Mercurial > emacs
comparison test/indent/octave.m @ 110038:6939db1ee97b
Use SMIE for octave-mode.
* test/indent/octave.m: New file.
* lisp/progmodes/octave-mod.el (octave-font-lock-keywords): Use regexp-opt.
(octave-mode-map): Remove special bindings for forward/backward-block
and octave-backward-up-block. Use smie-close-block.
(octave-continuation-marker-regexp): New var.
(octave-continuation-regexp): Use it.
(octave-operator-table, octave-smie-op-levels)
(octave-operator-regexp, octave-smie-indent-rules): New vars.
(octave-smie-backward-token, octave-smie-forward-token): New funs.
(octave-mode): Use SMIE.
(octave-close-block): Delete.
author | Stefan Monnier <monnier@iro.umontreal.ca> |
---|---|
date | Mon, 30 Aug 2010 22:34:52 +0200 |
parents | |
children | b10051866f51 |
comparison
equal
deleted
inserted
replaced
110037:314f04d4d276 | 110038:6939db1ee97b |
---|---|
1 ## -*- octave -*- | |
2 | |
3 function res = tcomp (fn) | |
4 %% res = tcomp (fn) | |
5 %% imports components and rearranges them. | |
6 | |
7 if nargin ~= 1 | |
8 print_usage() | |
9 endif | |
10 | |
11 data = dlmread(fn, 3, 0); | |
12 | |
13 x = data(:,2:end); | |
14 y = 'hello'; | |
15 z = y'; | |
16 | |
17 cnty = repmat(x(:,1)(:), 10, 1); | |
18 | |
19 pop = x(:,1:10)(:); | |
20 bir = x(:,11:20)(:); | |
21 dth = x(:,21:30)(:); | |
22 imig = x(:,31:40)(:); | |
23 dmig = x(:,41:50)(:); | |
24 gq = x(:,51:60)(:); | |
25 | |
26 yrs = repmat(2000:2009, 39, 1)(:); | |
27 | |
28 res = [yrs, cnty, pop, bir, dth, imig, dmig, gq]; | |
29 | |
30 endfunction | |
31 | |
32 ## Copyright (C) 2005, 2006, 2007, 2008, 2009 S�ren Hauberg | |
33 ## | |
34 ## This file is part of Octave. | |
35 ## | |
36 ## Octave is free software; you can redistribute it and/or modify it | |
37 ## under the terms of the GNU General Public License as published by | |
38 ## the Free Software Foundation; either version 3 of the License, or (at | |
39 ## your option) any later version. | |
40 ## | |
41 ## Octave is distributed in the hope that it will be useful, but | |
42 ## WITHOUT ANY WARRANTY; without even the implied warranty of | |
43 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
44 ## General Public License for more details. | |
45 ## | |
46 ## You should have received a copy of the GNU General Public License | |
47 ## along with Octave; see the file COPYING. If not, see | |
48 ## <http://www.gnu.org/licenses/>. | |
49 | |
50 ## -*- texinfo -*- | |
51 ## @deftypefn {Command} pkg @var{command} @var{pkg_name} | |
52 ## @deftypefnx {Command} pkg @var{command} @var{option} @var{pkg_name} | |
53 ## This command interacts with the package manager. Different actions will | |
54 ## be taken depending on the value of @var{command}. | |
55 ## | |
56 ## @table @samp | |
57 ## @item install | |
58 ## Install named packages. For example, | |
59 ## @example | |
60 ## pkg install image-1.0.0.tar.gz | |
61 ## @end example | |
62 ## @noindent | |
63 ## installs the package found in the file @file{image-1.0.0.tar.gz}. | |
64 ## | |
65 ## The @var{option} variable can contain options that affect the manner | |
66 ## in which a package is installed. These options can be one or more of | |
67 ## | |
68 ## @table @code | |
69 ## @item -nodeps | |
70 ## The package manager will disable the dependency checking. That way it | |
71 ## is possible to install a package even if it depends on another package | |
72 ## that's not installed on the system. @strong{Use this option with care.} | |
73 ## | |
74 ## @item -noauto | |
75 ## The package manager will not automatically load the installed package | |
76 ## when starting Octave, even if the package requests that it is. | |
77 ## | |
78 ## @item -auto | |
79 ## The package manager will automatically load the installed package when | |
80 ## starting Octave, even if the package requests that it isn't. | |
81 ## | |
82 ## @item -local | |
83 ## A local installation is forced, even if the user has system privileges. | |
84 ## | |
85 ## @item -global | |
86 ## A global installation is forced, even if the user doesn't normally have | |
87 ## system privileges | |
88 ## | |
89 ## @item -verbose | |
90 ## The package manager will print the output of all of the commands that are | |
91 ## performed. | |
92 ## @end table | |
93 ## | |
94 ## @item uninstall | |
95 ## Uninstall named packages. For example, | |
96 ## @example | |
97 ## pkg uninstall image | |
98 ## @end example | |
99 ## @noindent | |
100 ## removes the @code{image} package from the system. If another installed | |
101 ## package depends on the @code{image} package an error will be issued. | |
102 ## The package can be uninstalled anyway by using the @code{-nodeps} option. | |
103 ## @item load | |
104 ## Add named packages to the path. After loading a package it is | |
105 ## possible to use the functions provided by the package. For example, | |
106 ## @example | |
107 ## pkg load image | |
108 ## @end example | |
109 ## @noindent | |
110 ## adds the @code{image} package to the path. It is possible to load all | |
111 ## installed packages at once with the command | |
112 ## @example | |
113 ## pkg load all | |
114 ## @end example | |
115 ## @item unload | |
116 ## Removes named packages from the path. After unloading a package it is | |
117 ## no longer possible to use the functions provided by the package. | |
118 ## This command behaves like the @code{load} command. | |
119 ## @item list | |
120 ## Show a list of the currently installed packages. By requesting one or two | |
121 ## output argument it is possible to get a list of the currently installed | |
122 ## packages. For example, | |
123 ## @example | |
124 ## installed_packages = pkg list; | |
125 ## @end example | |
126 ## @noindent | |
127 ## returns a cell array containing a structure for each installed package. | |
128 ## The command | |
129 ## @example | |
130 ## [@var{user_packages}, @var{system_packages}] = pkg list | |
131 ## @end example | |
132 ## @noindent | |
133 ## splits the list of installed packages into those who are installed by | |
134 ## the current user, and those installed by the system administrator. | |
135 ## @item describe | |
136 ## Show a short description of the named installed packages, with the option | |
137 ## '-verbose' also list functions provided by the package, e.g.: | |
138 ## @example | |
139 ## pkg describe -verbose all | |
140 ## @end example | |
141 ## @noindent | |
142 ## will describe all installed packages and the functions they provide. | |
143 ## If one output is requested a cell of structure containing the | |
144 ## description and list of functions of each package is returned as | |
145 ## output rather than printed on screen: | |
146 ## @example | |
147 ## desc = pkg ("describe", "secs1d", "image") | |
148 ## @end example | |
149 ## @noindent | |
150 ## If any of the requested packages is not installed, pkg returns an | |
151 ## error, unless a second output is requested: | |
152 ## @example | |
153 ## [ desc, flag] = pkg ("describe", "secs1d", "image") | |
154 ## @end example | |
155 ## @noindent | |
156 ## @var{flag} will take one of the values "Not installed", "Loaded" or | |
157 ## "Not loaded" for each of the named packages. | |
158 ## @item prefix | |
159 ## Set the installation prefix directory. For example, | |
160 ## @example | |
161 ## pkg prefix ~/my_octave_packages | |
162 ## @end example | |
163 ## @noindent | |
164 ## sets the installation prefix to @file{~/my_octave_packages}. | |
165 ## Packages will be installed in this directory. | |
166 ## | |
167 ## It is possible to get the current installation prefix by requesting an | |
168 ## output argument. For example, | |
169 ## @example | |
170 ## p = pkg prefix | |
171 ## @end example | |
172 ## | |
173 ## The location in which to install the architecture dependent files can be | |
174 ## independent specified with an addition argument. For example | |
175 ## | |
176 ## @example | |
177 ## pkg prefix ~/my_octave_packages ~/my_arch_dep_pkgs | |
178 ## @end example | |
179 ## @item local_list | |
180 ## Set the file in which to look for information on the locally | |
181 ## installed packages. Locally installed packages are those that are | |
182 ## typically available only to the current user. For example | |
183 ## @example | |
184 ## pkg local_list ~/.octave_packages | |
185 ## @end example | |
186 ## It is possible to get the current value of local_list with the following | |
187 ## @example | |
188 ## pkg local_list | |
189 ## @end example | |
190 ## @item global_list | |
191 ## Set the file in which to look for, for information on the globally | |
192 ## installed packages. Globally installed packages are those that are | |
193 ## typically available to all users. For example | |
194 ## @example | |
195 ## pkg global_list /usr/share/octave/octave_packages | |
196 ## @end example | |
197 ## It is possible to get the current value of global_list with the following | |
198 ## @example | |
199 ## pkg global_list | |
200 ## @end example | |
201 ## @item rebuild | |
202 ## Rebuilds the package database from the installed directories. This can | |
203 ## be used in cases where for some reason the package database is corrupted. | |
204 ## It can also take the @code{-auto} and @code{-noauto} options to allow the | |
205 ## autoloading state of a package to be changed. For example | |
206 ## | |
207 ## @example | |
208 ## pkg rebuild -noauto image | |
209 ## @end example | |
210 ## | |
211 ## will remove the autoloading status of the image package. | |
212 ## @item build | |
213 ## Builds a binary form of a package or packages. The binary file produced | |
214 ## will itself be an Octave package that can be installed normally with | |
215 ## @code{pkg}. The form of the command to build a binary package is | |
216 ## | |
217 ## @example | |
218 ## pkg build builddir image-1.0.0.tar.gz @dots{} | |
219 ## @end example | |
220 ## | |
221 ## @noindent | |
222 ## where @code{builddir} is the name of a directory where the temporary | |
223 ## installation will be produced and the binary packages will be found. | |
224 ## The options @code{-verbose} and @code{-nodeps} are respected, while | |
225 ## the other options are ignored. | |
226 ## @end table | |
227 ## @end deftypefn | |
228 | |
229 function [local_packages, global_packages] = pkg (varargin) | |
230 ## Installation prefix (FIXME: what should these be on windows?) | |
231 persistent user_prefix = false; | |
232 persistent prefix = -1; | |
233 persistent archprefix = -1; | |
234 persistent local_list = tilde_expand (fullfile ("~", ".octave_packages")); | |
235 persistent global_list = fullfile (OCTAVE_HOME (), "share", "octave", | |
236 "octave_packages"); | |
237 mlock (); | |
238 | |
239 global_install = issuperuser (); | |
240 | |
241 if (prefix == -1) | |
242 if (global_install) | |
243 prefix = fullfile (OCTAVE_HOME (), "share", "octave", "packages"); | |
244 archprefix = fullfile (octave_config_info ("libexecdir"), | |
245 "octave", "packages"); | |
246 else | |
247 prefix = fullfile ("~", "octave"); | |
248 archprefix = prefix; | |
249 endif | |
250 prefix = tilde_expand (prefix); | |
251 archprefix = tilde_expand (archprefix); | |
252 endif | |
253 | |
254 available_actions = {"list", "install", "uninstall", "load", ... | |
255 "unload", "prefix", "local_list", ... | |
256 "global_list", "rebuild", "build","describe"}; | |
257 ## Handle input | |
258 if (length (varargin) == 0 || ! iscellstr (varargin)) | |
259 print_usage (); | |
260 endif | |
261 files = {}; | |
262 deps = true; | |
263 auto = 0; | |
264 action = "none"; | |
265 verbose = false; | |
266 for i = 1:length (varargin) | |
267 switch (varargin{i}) | |
268 case "-nodeps" | |
269 deps = false; | |
270 case "-noauto" | |
271 auto = -1; | |
272 case "-auto" | |
273 auto = 1; | |
274 case "-verbose" | |
275 verbose = true; | |
276 case "-local" | |
277 global_install = false; | |
278 if (! user_prefix) | |
279 prefix = tilde_expand (fullfile ("~", "octave")); | |
280 archprefix = prefix; | |
281 endif | |
282 case "-global" | |
283 global_install = true; | |
284 if (! user_prefix) | |
285 prefix = fullfile (OCTAVE_HOME (), "share", "octave", "packages"); | |
286 archprefix = fullfile (octave_config_info ("libexecdir"), | |
287 "octave", "packages"); | |
288 endif | |
289 case available_actions | |
290 if (strcmp (action, "none")) | |
291 action = varargin{i}; | |
292 else | |
293 error ("more than one action specified"); | |
294 endif | |
295 otherwise | |
296 files{end+1} = varargin{i}; | |
297 endswitch | |
298 endfor | |
299 | |
300 ## Take action | |
301 switch (action) | |
302 case "list" | |
303 if (nargout == 0) | |
304 installed_packages (local_list, global_list); | |
305 elseif (nargout == 1) | |
306 local_packages = installed_packages (local_list, global_list); | |
307 elseif (nargout == 2) | |
308 [local_packages, global_packages] = installed_packages (local_list, | |
309 global_list); | |
310 else | |
311 error ("too many output arguments requested"); | |
312 endif | |
313 | |
314 case "install" | |
315 if (length (files) == 0) | |
316 error ("you must specify at least one filename when calling 'pkg install'"); | |
317 endif | |
318 install (files, deps, auto, prefix, archprefix, verbose, local_list, | |
319 global_list, global_install); | |
320 | |
321 case "uninstall" | |
322 if (length (files) == 0) | |
323 error ("you must specify at least one package when calling 'pkg uninstall'"); | |
324 endif | |
325 uninstall (files, deps, verbose, local_list, | |
326 global_list, global_install); | |
327 | |
328 case "load" | |
329 if (length (files) == 0) | |
330 error ("you must specify at least one package, 'all' or 'auto' when calling 'pkg load'"); | |
331 endif | |
332 load_packages (files, deps, local_list, global_list); | |
333 | |
334 case "unload" | |
335 if (length (files) == 0) | |
336 error ("you must specify at least one package or 'all' when calling 'pkg unload'"); | |
337 endif | |
338 unload_packages (files, deps, local_list, global_list); | |
339 | |
340 case "prefix" | |
341 if (length (files) == 0 && nargout == 0) | |
342 printf ("Installation prefix: %s\n", prefix); | |
343 printf ("Architecture dependent prefix: %s\n", archprefix); | |
344 elseif (length (files) == 0 && nargout >= 1) | |
345 local_packages = prefix; | |
346 global_packages = archprefix; | |
347 elseif (length (files) >= 1 && nargout <= 2 && ischar (files{1})) | |
348 prefix = files{1}; | |
349 prefix = absolute_pathname (prefix); | |
350 local_packages = prefix; | |
351 user_prefix = true; | |
352 if (length (files) >= 2 && ischar (files{2})) | |
353 archprefix = files{2}; | |
354 try | |
355 archprefix = absolute_pathname (archprefix); | |
356 catch | |
357 mkdir (archprefix); | |
358 warning ("creating the directory %s\n", archprefix); | |
359 archprefix = absolute_pathname (archprefix); | |
360 end_try_catch | |
361 global_packages = archprefix; | |
362 endif | |
363 else | |
364 error ("you must specify a prefix directory, or request an output argument"); | |
365 endif | |
366 | |
367 case "local_list" | |
368 if (length (files) == 0 && nargout == 0) | |
369 disp (local_list); | |
370 elseif (length (files) == 0 && nargout == 1) | |
371 local_packages = local_list; | |
372 elseif (length (files) == 1 && nargout == 0 && ischar (files{1})) | |
373 try | |
374 local_list = absolute_pathname (files{1}); | |
375 catch | |
376 ## Force file to be created | |
377 fclose (fopen (files{1}, "wt")); | |
378 local_list = absolute_pathname (files{1}); | |
379 end_try_catch | |
380 else | |
381 error ("you must specify a local_list file, or request an output argument"); | |
382 endif | |
383 | |
384 case "global_list" | |
385 if (length (files) == 0 && nargout == 0) | |
386 disp(global_list); | |
387 elseif (length (files) == 0 && nargout == 1) | |
388 local_packages = global_list; | |
389 elseif (length (files) == 1 && nargout == 0 && ischar (files{1})) | |
390 try | |
391 global_list = absolute_pathname (files{1}); | |
392 catch | |
393 ## Force file to be created | |
394 fclose (fopen (files{1}, "wt")); | |
395 global_list = absolute_pathname (files{1}); | |
396 end_try_catch | |
397 else | |
398 error ("you must specify a global_list file, or request an output argument"); | |
399 endif | |
400 | |
401 case "rebuild" | |
402 if (global_install) | |
403 global_packages = rebuild (prefix, archprefix, global_list, files, | |
404 auto, verbose); | |
405 global_packages = save_order (global_packages); | |
406 save (global_list, "global_packages"); | |
407 if (nargout > 0) | |
408 local_packages = global_packages; | |
409 endif | |
410 else | |
411 local_packages = rebuild (prefix, archprefix, local_list, files, auto, | |
412 verbose); | |
413 local_packages = save_order (local_packages); | |
414 save (local_list, "local_packages"); | |
415 if (nargout == 0) | |
416 clear ("local_packages"); | |
417 endif | |
418 endif | |
419 | |
420 case "build" | |
421 if (length (files) < 2) | |
422 error ("you must specify at least the build directory and one filename\nwhen calling 'pkg build'"); | |
423 endif | |
424 build (files, deps, auto, verbose); | |
425 | |
426 case "describe" | |
427 if (length (files) == 0) | |
428 error ("you must specify at least one package or 'all' when calling 'pkg describe'"); | |
429 endif | |
430 ## FIXME: the name of the output variables is inconsistent | |
431 ## with their content | |
432 switch (nargout) | |
433 case 0 | |
434 describe (files, verbose, local_list, global_list); | |
435 case 1 | |
436 pkg_desc_list = describe (files, verbose, local_list, ... | |
437 global_list); | |
438 local_packages = pkg_desc_list; | |
439 case 2 | |
440 [pkg_desc_list, flag] = describe (files, verbose, local_list, ... | |
441 global_list); | |
442 local_packages = pkg_desc_list; | |
443 global_packages = flag; | |
444 otherwise | |
445 error ("you can request at most two outputs when calling 'pkg describe'"); | |
446 endswitch | |
447 | |
448 otherwise | |
449 error ("you must specify a valid action for 'pkg'. See 'help pkg' for details"); | |
450 endswitch | |
451 endfunction | |
452 | |
453 function descriptions = rebuild (prefix, archprefix, list, files, auto, verbose) | |
454 if (isempty (files)) | |
455 [dirlist, err, msg] = readdir (prefix); | |
456 if (err) | |
457 error ("couldn't read directory %s: %s", prefix, msg); | |
458 endif | |
459 ## the two first entries of dirlist are "." and ".." | |
460 dirlist([1,2]) = []; | |
461 else | |
462 old_descriptions = installed_packages (list, list); | |
463 wd = pwd (); | |
464 unwind_protect | |
465 cd (prefix); | |
466 dirlist = glob (cellfun(@(x) cstrcat(x, '-*'), files, 'UniformOutput', 0)); | |
467 unwind_protect_cleanup | |
468 cd (wd); | |
469 end_unwind_protect | |
470 endif | |
471 descriptions = {}; | |
472 for k = 1:length (dirlist) | |
473 descfile = fullfile (prefix, dirlist{k}, "packinfo", "DESCRIPTION"); | |
474 if (verbose) | |
475 printf ("recreating package description from %s\n", dirlist{k}); | |
476 endif | |
477 if (exist (descfile, "file")) | |
478 desc = get_description (descfile); | |
479 desc.dir = fullfile (prefix, dirlist{k}); | |
480 desc.archprefix = fullfile (archprefix, cstrcat (desc.name, "-", | |
481 desc.version)); | |
482 if (auto != 0) | |
483 if (exist (fullfile (desc.dir, "packinfo", ".autoload"), "file")) | |
484 unlink (fullfile (desc.dir, "packinfo", ".autoload")); | |
485 endif | |
486 if (auto < 0) | |
487 desc.autoload = 0; | |
488 elseif (auto > 0) | |
489 desc.autoload = 1; | |
490 fclose (fopen (fullfile (desc.dir, "packinfo", ".autoload"), "wt")); | |
491 endif | |
492 else | |
493 if (exist (fullfile (desc.dir, "packinfo", ".autoload"), "file")) | |
494 desc.autoload = 1; | |
495 else | |
496 desc.autoload = 0; | |
497 endif | |
498 endif | |
499 descriptions{end + 1} = desc; | |
500 elseif (verbose) | |
501 warning ("directory %s is not a valid package", dirlist{k}); | |
502 endif | |
503 endfor | |
504 | |
505 if (! isempty (files)) | |
506 ## We are rebuilding for a particular package(s) so we should take | |
507 ## care to keep the other untouched packages in the descriptions | |
508 descriptions = {descriptions{:}, old_descriptions{:}}; | |
509 | |
510 dup = []; | |
511 for i = 1:length (descriptions) | |
512 if (find (dup, i)) | |
513 continue; | |
514 endif | |
515 for j = (i+1):length (descriptions) | |
516 if (find (dup, j)) | |
517 continue; | |
518 endif | |
519 if (strcmp (descriptions{i}.name, descriptions{j}.name)) | |
520 dup = [dup, j]; | |
521 endif | |
522 endfor | |
523 endfor | |
524 if (! isempty (dup)) | |
525 descriptions (dup) = []; | |
526 endif | |
527 endif | |
528 endfunction | |
529 | |
530 function build (files, handle_deps, autoload, verbose) | |
531 if (length (files) < 1) | |
532 error ("insufficient number of files"); | |
533 endif | |
534 builddir = files{1}; | |
535 if (! exist (builddir, "dir")) | |
536 warning ("creating build directory %s", builddir); | |
537 [status, msg] = mkdir (builddir); | |
538 if (status != 1) | |
539 error ("could not create installation directory: %s", msg); | |
540 endif | |
541 endif | |
542 builddir = absolute_pathname (builddir); | |
543 installdir = fullfile (builddir, "install"); | |
544 if (! exist (installdir, "dir")) | |
545 [status, msg] = mkdir (installdir); | |
546 if (status != 1) | |
547 error ("could not create installation directory: %s", msg); | |
548 endif | |
549 endif | |
550 files(1) = []; | |
551 buildlist = fullfile (builddir, "octave_packages"); | |
552 install (files, handle_deps, autoload, installdir, installdir, verbose, | |
553 buildlist, "", false); | |
554 unwind_protect | |
555 repackage (builddir, buildlist); | |
556 unwind_protect_cleanup | |
557 unload_packages ({"all"}, handle_deps, buildlist, ""); | |
558 if (exist (installdir, "dir")) | |
559 rm_rf (installdir); | |
560 endif | |
561 if (exist (buildlist, "file")) | |
562 unlink (buildlist); | |
563 endif | |
564 end_unwind_protect | |
565 endfunction | |
566 | |
567 function install (files, handle_deps, autoload, prefix, archprefix, verbose, | |
568 local_list, global_list, global_install) | |
569 | |
570 ## Check that the directory in prefix exist. If it doesn't: create it! | |
571 if (! exist (prefix, "dir")) | |
572 warning ("creating installation directory %s", prefix); | |
573 [status, msg] = mkdir (prefix); | |
574 if (status != 1) | |
575 error ("could not create installation directory: %s", msg); | |
576 endif | |
577 endif | |
578 | |
579 ## Get the list of installed packages. | |
580 [local_packages, global_packages] = installed_packages (local_list, | |
581 global_list); | |
582 | |
583 installed_pkgs_lst = {local_packages{:}, global_packages{:}}; | |
584 | |
585 if (global_install) | |
586 packages = global_packages; | |
587 else | |
588 packages = local_packages; | |
589 endif | |
590 | |
591 ## Uncompress the packages and read the DESCRIPTION files. | |
592 tmpdirs = packdirs = descriptions = {}; | |
593 try | |
594 ## Warn about non existent files. | |
595 for i = 1:length (files) | |
596 if (isempty (glob(files{i}))) | |
597 warning ("file %s does not exist", files{i}); | |
598 endif | |
599 endfor | |
600 | |
601 ## Unpack the package files and read the DESCRIPTION files. | |
602 files = glob (files); | |
603 packages_to_uninstall = []; | |
604 for i = 1:length (files) | |
605 tgz = files{i}; | |
606 | |
607 if (exist (tgz, "file")) | |
608 ## Create a temporary directory. | |
609 tmpdir = tmpnam (); | |
610 tmpdirs{end+1} = tmpdir; | |
611 if (verbose) | |
612 printf ("mkdir (%s)\n", tmpdir); | |
613 endif | |
614 [status, msg] = mkdir (tmpdir); | |
615 if (status != 1) | |
616 error ("couldn't create temporary directory: %s", msg); | |
617 endif | |
618 | |
619 ## Uncompress the package. | |
620 if (verbose) | |
621 printf ("untar (%s, %s)\n", tgz, tmpdir); | |
622 endif | |
623 untar (tgz, tmpdir); | |
624 | |
625 ## Get the name of the directories produced by tar. | |
626 [dirlist, err, msg] = readdir (tmpdir); | |
627 if (err) | |
628 error ("couldn't read directory produced by tar: %s", msg); | |
629 endif | |
630 | |
631 if (length (dirlist) > 3) | |
632 error ("bundles of packages are not allowed") | |
633 endif | |
634 endif | |
635 | |
636 ## The filename pointed to an uncompressed package to begin with. | |
637 if (exist (tgz, "dir")) | |
638 dirlist = {".", "..", tgz}; | |
639 endif | |
640 | |
641 if (exist (tgz, "file") || exist (tgz, "dir")) | |
642 ## The two first entries of dirlist are "." and "..". | |
643 if (exist (tgz, "file")) | |
644 packdir = fullfile (tmpdir, dirlist{3}); | |
645 else | |
646 packdir = fullfile (pwd(), dirlist{3}); | |
647 endif | |
648 packdirs{end+1} = packdir; | |
649 | |
650 ## Make sure the package contains necessary files. | |
651 verify_directory (packdir); | |
652 | |
653 ## Read the DESCRIPTION file. | |
654 filename = fullfile (packdir, "DESCRIPTION"); | |
655 desc = get_description (filename); | |
656 | |
657 ## Verify that package name corresponds with filename. | |
658 [dummy, nm] = fileparts (tgz); | |
659 if ((length (nm) >= length (desc.name)) | |
660 && ! strcmp (desc.name, nm(1:length(desc.name)))) | |
661 error ("package name '%s' doesn't correspond to its filename '%s'", | |
662 desc.name, nm); | |
663 endif | |
664 | |
665 ## Set default installation directory. | |
666 desc.dir = fullfile (prefix, cstrcat (desc.name, "-", desc.version)); | |
667 | |
668 ## Set default architectire dependent installation directory. | |
669 desc.archprefix = fullfile (archprefix, cstrcat (desc.name, "-", | |
670 desc.version)); | |
671 | |
672 ## Save desc. | |
673 descriptions{end+1} = desc; | |
674 | |
675 ## Are any of the new packages already installed? | |
676 ## If so we'll remove the old version. | |
677 for j = 1:length (packages) | |
678 if (strcmp (packages{j}.name, desc.name)) | |
679 packages_to_uninstall(end+1) = j; | |
680 endif | |
681 endfor | |
682 endif | |
683 endfor | |
684 catch | |
685 ## Something went wrong, delete tmpdirs. | |
686 for i = 1:length (tmpdirs) | |
687 rm_rf (tmpdirs{i}); | |
688 endfor | |
689 rethrow (lasterror ()); | |
690 end_try_catch | |
691 | |
692 ## Check dependencies. | |
693 if (handle_deps) | |
694 ok = true; | |
695 error_text = ""; | |
696 for i = 1:length (descriptions) | |
697 desc = descriptions{i}; | |
698 idx2 = complement (i, 1:length(descriptions)); | |
699 if (global_install) | |
700 ## Global installation is not allowed to have dependencies on locally | |
701 ## installed packages. | |
702 idx1 = complement (packages_to_uninstall, | |
703 1:length(global_packages)); | |
704 pseudo_installed_packages = {global_packages{idx1}, ... | |
705 descriptions{idx2}}; | |
706 else | |
707 idx1 = complement (packages_to_uninstall, | |
708 1:length(local_packages)); | |
709 pseudo_installed_packages = {local_packages{idx1}, ... | |
710 global_packages{:}, ... | |
711 descriptions{idx2}}; | |
712 endif | |
713 bad_deps = get_unsatisfied_deps (desc, pseudo_installed_packages); | |
714 ## Are there any unsatisfied dependencies? | |
715 if (! isempty (bad_deps)) | |
716 ok = false; | |
717 for i = 1:length (bad_deps) | |
718 dep = bad_deps{i}; | |
719 error_text = cstrcat (error_text, " ", desc.name, " needs ", | |
720 dep.package, " ", dep.operator, " ", | |
721 dep.version, "\n"); | |
722 endfor | |
723 endif | |
724 endfor | |
725 | |
726 ## Did we find any unsatisfied dependencies? | |
727 if (! ok) | |
728 error ("the following dependencies where unsatisfied:\n %s", error_text); | |
729 endif | |
730 endif | |
731 | |
732 ## Prepare each package for installation. | |
733 try | |
734 for i = 1:length (descriptions) | |
735 desc = descriptions{i}; | |
736 pdir = packdirs{i}; | |
737 prepare_installation (desc, pdir); | |
738 configure_make (desc, pdir, verbose); | |
739 endfor | |
740 catch | |
741 ## Something went wrong, delete tmpdirs. | |
742 for i = 1:length (tmpdirs) | |
743 rm_rf (tmpdirs{i}); | |
744 endfor | |
745 rethrow (lasterror ()); | |
746 end_try_catch | |
747 | |
748 ## Uninstall the packages that will be replaced. | |
749 try | |
750 for i = packages_to_uninstall | |
751 if (global_install) | |
752 uninstall ({global_packages{i}.name}, false, verbose, local_list, | |
753 global_list, global_install); | |
754 else | |
755 uninstall ({local_packages{i}.name}, false, verbose, local_list, | |
756 global_list, global_install); | |
757 endif | |
758 endfor | |
759 catch | |
760 ## Something went wrong, delete tmpdirs. | |
761 for i = 1:length (tmpdirs) | |
762 rm_rf (tmpdirs{i}); | |
763 endfor | |
764 rethrow (lasterror ()); | |
765 end_try_catch | |
766 | |
767 ## Install each package. | |
768 try | |
769 for i = 1:length (descriptions) | |
770 desc = descriptions{i}; | |
771 pdir = packdirs{i}; | |
772 copy_files (desc, pdir, global_install); | |
773 create_pkgadddel (desc, pdir, "PKG_ADD", global_install); | |
774 create_pkgadddel (desc, pdir, "PKG_DEL", global_install); | |
775 finish_installation (desc, pdir, global_install); | |
776 generate_lookfor_cache (desc); | |
777 endfor | |
778 catch | |
779 ## Something went wrong, delete tmpdirs. | |
780 for i = 1:length (tmpdirs) | |
781 rm_rf (tmpdirs{i}); | |
782 endfor | |
783 for i = 1:length (descriptions) | |
784 rm_rf (descriptions{i}.dir); | |
785 rm_rf (getarchdir (descriptions{i})); | |
786 endfor | |
787 rethrow (lasterror ()); | |
788 end_try_catch | |
789 | |
790 ## Check if the installed directory is empty. If it is remove it | |
791 ## from the list. | |
792 for i = length (descriptions):-1:1 | |
793 if (dirempty (descriptions{i}.dir, {"packinfo", "doc"}) && | |
794 dirempty (getarchdir (descriptions{i}))) | |
795 warning ("package %s is empty\n", descriptions{i}.name); | |
796 rm_rf (descriptions{i}.dir); | |
797 rm_rf (getarchdir (descriptions{i})); | |
798 descriptions(i) = []; | |
799 endif | |
800 endfor | |
801 | |
802 ## If the package requested that it is autoloaded, or the installer | |
803 ## requested that it is, then mark the package as autoloaded. | |
804 for i = length (descriptions):-1:1 | |
805 if (autoload > 0 || (autoload == 0 && isautoload (descriptions(i)))) | |
806 fclose (fopen (fullfile (descriptions{i}.dir, "packinfo", | |
807 ".autoload"), "wt")); | |
808 descriptions{i}.autoload = 1; | |
809 endif | |
810 endfor | |
811 | |
812 ## Add the packages to the package list. | |
813 try | |
814 if (global_install) | |
815 idx = complement (packages_to_uninstall, 1:length(global_packages)); | |
816 global_packages = save_order ({global_packages{idx}, descriptions{:}}); | |
817 save (global_list, "global_packages"); | |
818 installed_pkgs_lst = {local_packages{:}, global_packages{:}}; | |
819 else | |
820 idx = complement (packages_to_uninstall, 1:length(local_packages)); | |
821 local_packages = save_order ({local_packages{idx}, descriptions{:}}); | |
822 save (local_list, "local_packages"); | |
823 installed_pkgs_lst = {local_packages{:}, global_packages{:}}; | |
824 endif | |
825 catch | |
826 ## Something went wrong, delete tmpdirs. | |
827 for i = 1:length (tmpdirs) | |
828 rm_rf (tmpdirs{i}); | |
829 endfor | |
830 for i = 1:length (descriptions) | |
831 rm_rf (descriptions{i}.dir); | |
832 endfor | |
833 if (global_install) | |
834 printf ("error: couldn't append to %s\n", global_list); | |
835 else | |
836 printf ("error: couldn't append to %s\n", local_list); | |
837 endif | |
838 rethrow (lasterror ()); | |
839 end_try_catch | |
840 | |
841 ## All is well, let's clean up. | |
842 for i = 1:length (tmpdirs) | |
843 [status, msg] = rm_rf (tmpdirs{i}); | |
844 if (status != 1) | |
845 warning ("couldn't clean up after my self: %s\n", msg); | |
846 endif | |
847 endfor | |
848 | |
849 ## Add the newly installed packages to the path, so the user | |
850 ## can begin using them. Only load them if they are marked autoload. | |
851 if (length (descriptions) > 0) | |
852 idx = []; | |
853 for i = 1:length (descriptions) | |
854 if (isautoload (descriptions(i))) | |
855 nm = descriptions{i}.name; | |
856 for j = 1:length (installed_pkgs_lst) | |
857 if (strcmp (nm, installed_pkgs_lst{j}.name)) | |
858 idx (end + 1) = j; | |
859 break; | |
860 endif | |
861 endfor | |
862 endif | |
863 endfor | |
864 load_packages_and_dependencies (idx, handle_deps, installed_pkgs_lst, | |
865 global_install); | |
866 endif | |
867 endfunction | |
868 | |
869 function uninstall (pkgnames, handle_deps, verbose, local_list, | |
870 global_list, global_install) | |
871 ## Get the list of installed packages. | |
872 [local_packages, global_packages] = installed_packages(local_list, | |
873 global_list); | |
874 if (global_install) | |
875 installed_pkgs_lst = {local_packages{:}, global_packages{:}}; | |
876 else | |
877 installed_pkgs_lst = local_packages; | |
878 endif | |
879 | |
880 num_packages = length (installed_pkgs_lst); | |
881 delete_idx = []; | |
882 for i = 1:num_packages | |
883 cur_name = installed_pkgs_lst{i}.name; | |
884 if (any (strcmp (cur_name, pkgnames))) | |
885 delete_idx(end+1) = i; | |
886 endif | |
887 endfor | |
888 | |
889 ## Are all the packages that should be uninstalled already installed? | |
890 if (length (delete_idx) != length (pkgnames)) | |
891 if (global_install) | |
892 ## Try again for a locally installed package. | |
893 installed_pkgs_lst = local_packages; | |
894 | |
895 num_packages = length (installed_pkgs_lst); | |
896 delete_idx = []; | |
897 for i = 1:num_packages | |
898 cur_name = installed_pkgs_lst{i}.name; | |
899 if (any (strcmp (cur_name, pkgnames))) | |
900 delete_idx(end+1) = i; | |
901 endif | |
902 endfor | |
903 if (length (delete_idx) != length (pkgnames)) | |
904 ## FIXME: We should have a better error message. | |
905 warning ("some of the packages you want to uninstall are not installed"); | |
906 endif | |
907 else | |
908 ## FIXME: We should have a better error message. | |
909 warning ("some of the packages you want to uninstall are not installed"); | |
910 endif | |
911 endif | |
912 | |
913 ## Compute the packages that will remain installed. | |
914 idx = complement (delete_idx, 1:num_packages); | |
915 remaining_packages = {installed_pkgs_lst{idx}}; | |
916 | |
917 ## Check dependencies. | |
918 if (handle_deps) | |
919 error_text = ""; | |
920 for i = 1:length (remaining_packages) | |
921 desc = remaining_packages{i}; | |
922 bad_deps = get_unsatisfied_deps (desc, remaining_packages); | |
923 | |
924 ## Will the uninstallation break any dependencies? | |
925 if (! isempty (bad_deps)) | |
926 for i = 1:length (bad_deps) | |
927 dep = bad_deps{i}; | |
928 error_text = cstrcat (error_text, " ", desc.name, " needs ", | |
929 dep.package, " ", dep.operator, " ", | |
930 dep.version, "\n"); | |
931 endfor | |
932 endif | |
933 endfor | |
934 | |
935 if (! isempty (error_text)) | |
936 error ("the following dependencies where unsatisfied:\n %s", error_text); | |
937 endif | |
938 endif | |
939 | |
940 ## Delete the directories containing the packages. | |
941 for i = delete_idx | |
942 desc = installed_pkgs_lst{i}; | |
943 ## If an 'on_uninstall.m' exist, call it! | |
944 if (exist (fullfile (desc.dir, "packinfo", "on_uninstall.m"), "file")) | |
945 wd = pwd (); | |
946 cd (fullfile (desc.dir, "packinfo")); | |
947 on_uninstall (desc); | |
948 cd (wd); | |
949 endif | |
950 ## Do the actual deletion. | |
951 if (desc.loaded) | |
952 rmpath (desc.dir); | |
953 if (exist (getarchdir (desc))) | |
954 rmpath (getarchdir (desc)); | |
955 endif | |
956 endif | |
957 if (exist (desc.dir, "dir")) | |
958 [status, msg] = rm_rf (desc.dir); | |
959 if (status != 1) | |
960 error ("couldn't delete directory %s: %s", desc.dir, msg); | |
961 endif | |
962 [status, msg] = rm_rf (getarchdir (desc)); | |
963 if (status != 1) | |
964 error ("couldn't delete directory %s: %s", getarchdir (desc), msg); | |
965 endif | |
966 if (dirempty (desc.archprefix)) | |
967 rm_rf (desc.archprefix); | |
968 endif | |
969 else | |
970 warning ("directory %s previously lost", desc.dir); | |
971 endif | |
972 endfor | |
973 | |
974 ## Write a new ~/.octave_packages. | |
975 if (global_install) | |
976 if (length (remaining_packages) == 0) | |
977 unlink (global_list); | |
978 else | |
979 global_packages = save_order (remaining_packages); | |
980 save (global_list, "global_packages"); | |
981 endif | |
982 else | |
983 if (length (remaining_packages) == 0) | |
984 unlink (local_list); | |
985 else | |
986 local_packages = save_order (remaining_packages); | |
987 save (local_list, "local_packages"); | |
988 endif | |
989 endif | |
990 | |
991 endfunction | |
992 | |
993 function [pkg_desc_list, flag] = describe (pkgnames, verbose, | |
994 local_list, global_list) | |
995 | |
996 ## Get the list of installed packages. | |
997 installed_pkgs_lst = installed_packages(local_list, global_list); | |
998 num_packages = length (installed_pkgs_lst); | |
999 | |
1000 | |
1001 describe_all = false; | |
1002 if (any (strcmp ("all", pkgnames))) | |
1003 describe_all = true; | |
1004 flag(1:num_packages) = {"Not Loaded"}; | |
1005 num_pkgnames = num_packages; | |
1006 else | |
1007 num_pkgnames = length (pkgnames); | |
1008 flag(1:num_pkgnames) = {"Not installed"}; | |
1009 endif | |
1010 | |
1011 for i = 1:num_packages | |
1012 curr_name = installed_pkgs_lst{i}.name; | |
1013 if (describe_all) | |
1014 name_pos = i; | |
1015 else | |
1016 name_pos = find(strcmp (curr_name, pkgnames)); | |
1017 endif | |
1018 | |
1019 if (! isempty (name_pos)) | |
1020 if (installed_pkgs_lst{i}.loaded) | |
1021 flag{name_pos} = "Loaded"; | |
1022 else | |
1023 flag{name_pos} = "Not loaded"; | |
1024 endif | |
1025 | |
1026 pkg_desc_list{name_pos}.name = installed_pkgs_lst{i}.name; | |
1027 pkg_desc_list{name_pos}.version = installed_pkgs_lst{i}.version; | |
1028 pkg_desc_list{name_pos}.description = installed_pkgs_lst{i}.description; | |
1029 pkg_desc_list{name_pos}.provides = parse_pkg_idx (installed_pkgs_lst{i}.dir); | |
1030 | |
1031 endif | |
1032 endfor | |
1033 | |
1034 non_inst = find (strcmp (flag, "Not installed")); | |
1035 if (! isempty (non_inst)) | |
1036 if (nargout < 2) | |
1037 non_inst_str = sprintf (" %s ", pkgnames{non_inst}); | |
1038 error ("some packages are not installed: %s", non_inst_str); | |
1039 else | |
1040 pkg_desc_list{non_inst} = struct ("name", {}, "description", | |
1041 {}, "provides", {}); | |
1042 endif | |
1043 endif | |
1044 | |
1045 if (nargout == 0) | |
1046 for i = 1:num_pkgnames | |
1047 print_package_description (pkg_desc_list{i}.name, | |
1048 pkg_desc_list{i}.version, | |
1049 pkg_desc_list{i}.provides, | |
1050 pkg_desc_list{i}.description, | |
1051 flag{i}, verbose); | |
1052 endfor | |
1053 endif | |
1054 | |
1055 endfunction | |
1056 | |
1057 ## AUXILIARY FUNCTIONS | |
1058 | |
1059 ## Read an INDEX file. | |
1060 function [pkg_idx_struct] = parse_pkg_idx (packdir) | |
1061 | |
1062 index_file = fullfile (packdir, "packinfo", "INDEX"); | |
1063 | |
1064 if (! exist (index_file, "file")) | |
1065 error ("could not find any INDEX file in directory %s, try 'pkg rebuild all' to generate missing INDEX files", packdir); | |
1066 endif | |
1067 | |
1068 | |
1069 [fid, msg] = fopen (index_file, "r"); | |
1070 if (fid == -1) | |
1071 error ("the INDEX file %s could not be read: %s", | |
1072 index_file, msg); | |
1073 endif | |
1074 | |
1075 cat_num = 1; | |
1076 pkg_idx_struct{1}.category = "Uncategorized"; | |
1077 pkg_idx_struct{1}.functions = {}; | |
1078 | |
1079 line = fgetl (fid); | |
1080 while (isempty (strfind (line, ">>")) && ! feof (fid)) | |
1081 line = fgetl (fid); | |
1082 endwhile | |
1083 | |
1084 while (! feof (fid) || line != -1) | |
1085 if (! any (! isspace (line)) || line(1) == "#" || any (line == "=")) | |
1086 ## Comments, blank lines or comments about unimplemented | |
1087 ## functions: do nothing | |
1088 ## FIXME: probably comments and pointers to external functions | |
1089 ## could be treated better when printing to screen? | |
1090 elseif (! isempty (strfind (line, ">>"))) | |
1091 ## Skip package name and description as they are in DESCRIPTION | |
1092 ## already. | |
1093 elseif (! isspace (line(1))) | |
1094 ## Category. | |
1095 if (! isempty (pkg_idx_struct{cat_num}.functions)) | |
1096 pkg_idx_struct{++cat_num}.functions = {}; | |
1097 endif | |
1098 pkg_idx_struct{cat_num}.category = deblank (line); | |
1099 else | |
1100 ## Function names. | |
1101 while (any (! isspace (line))) | |
1102 [fun_name, line] = strtok (line); | |
1103 pkg_idx_struct{cat_num}.functions{end+1} = deblank (fun_name); | |
1104 endwhile | |
1105 endif | |
1106 line = fgetl (fid); | |
1107 endwhile | |
1108 fclose (fid); | |
1109 endfunction | |
1110 | |
1111 function print_package_description (pkg_name, pkg_ver, pkg_idx_struct, | |
1112 pkg_desc, status, verbose) | |
1113 | |
1114 printf ("---\nPackage name:\n\t%s\n", pkg_name); | |
1115 printf ("Version:\n\t%s\n", pkg_ver); | |
1116 printf ("Short description:\n\t%s\n", pkg_desc); | |
1117 printf ("Status:\n\t%s\n", status); | |
1118 if (verbose) | |
1119 printf ("---\nProvides:\n"); | |
1120 for i = 1:length(pkg_idx_struct) | |
1121 if (! isempty (pkg_idx_struct{i}.functions)) | |
1122 printf ("%s\n", pkg_idx_struct{i}.category); | |
1123 for j = 1:length(pkg_idx_struct{i}.functions) | |
1124 printf ("\t%s\n", pkg_idx_struct{i}.functions{j}); | |
1125 endfor | |
1126 endif | |
1127 endfor | |
1128 endif | |
1129 | |
1130 endfunction | |
1131 | |
1132 | |
1133 function pth = absolute_pathname (pth) | |
1134 [status, msg, msgid] = fileattrib (pth); | |
1135 if (status != 1) | |
1136 error ("could not find the file or path %s", pth); | |
1137 else | |
1138 pth = msg.Name; | |
1139 endif | |
1140 endfunction | |
1141 | |
1142 function repackage (builddir, buildlist) | |
1143 packages = installed_packages (buildlist, buildlist); | |
1144 | |
1145 wd = pwd(); | |
1146 for i = 1 : length(packages) | |
1147 pack = packages{i}; | |
1148 unwind_protect | |
1149 cd (builddir); | |
1150 mkdir (pack.name); | |
1151 mkdir (fullfile (pack.name, "inst")); | |
1152 copyfile (fullfile (pack.dir, "*"), fullfile (pack.name, "inst")); | |
1153 movefile (fullfile (pack.name, "inst","packinfo", "*"), pack.name); | |
1154 if (exist (fullfile (pack.name, "inst","packinfo", ".autoload"), "file")) | |
1155 unlink (fullfile (pack.name, "inst","packinfo", ".autoload")); | |
1156 endif | |
1157 rmdir (fullfile (pack.name, "inst", "packinfo")); | |
1158 if (exist (fullfile (pack.name, "inst", "doc"), "dir")) | |
1159 movefile (fullfile (pack.name, "inst", "doc"), pack.name); | |
1160 endif | |
1161 if (exist (fullfile (pack.name, "inst", "bin"), "dir")) | |
1162 movefile (fullfile (pack.name, "inst", "bin"), pack.name); | |
1163 endif | |
1164 archdir = fullfile (pack.archprefix, cstrcat (pack.name, "-", | |
1165 pack.version), getarch ()); | |
1166 if (exist (archdir, "dir")) | |
1167 if (exist (fullfile (pack.name, "inst", "PKG_ADD"), "file")) | |
1168 unlink (fullfile (pack.name, "inst", "PKG_ADD")); | |
1169 endif | |
1170 if (exist (fullfile (pack.name, "inst", "PKG_DEL"), "file")) | |
1171 unlink (fullfile (pack.name, "inst", "PKG_DEL")); | |
1172 endif | |
1173 if (exist (fullfile (archdir, "PKG_ADD"), "file")) | |
1174 movefile (fullfile (archdir, "PKG_ADD"), | |
1175 fullfile (pack.name, "PKG_ADD")); | |
1176 endif | |
1177 if (exist (fullfile (archdir, "PKG_DEL"), "file")) | |
1178 movefile (fullfile (archdir, "PKG_DEL"), | |
1179 fullfile (pack.name, "PKG_DEL")); | |
1180 endif | |
1181 else | |
1182 if (exist (fullfile (pack.name, "inst", "PKG_ADD"), "file")) | |
1183 movefile (fullfile (pack.name, "inst", "PKG_ADD"), | |
1184 fullfile (pack.name, "PKG_ADD")); | |
1185 endif | |
1186 if (exist (fullfile (pack.name, "inst", "PKG_DEL"), "file")) | |
1187 movefile (fullfile (pack.name, "inst", "PKG_DEL"), | |
1188 fullfile (pack.name, "PKG_DEL")); | |
1189 endif | |
1190 endif | |
1191 tfile = cstrcat (pack.name, "-", pack.version, ".tar"); | |
1192 tar (tfile, pack.name); | |
1193 try | |
1194 gzip (tfile); | |
1195 unlink (tfile); | |
1196 catch | |
1197 warning ("failed to compress %s", tfile); | |
1198 end_try_catch | |
1199 unwind_protect_cleanup | |
1200 if (exist (pack.name, "dir")) | |
1201 rm_rf (pack.name); | |
1202 endif | |
1203 cd (wd); | |
1204 end_unwind_protect | |
1205 endfor | |
1206 endfunction | |
1207 | |
1208 function auto = isautoload (desc) | |
1209 auto = false; | |
1210 if (isfield (desc{1}, "autoload")) | |
1211 a = desc{1}.autoload; | |
1212 if ((isnumeric (a) && a > 0) | |
1213 || (ischar (a) && (strcmpi (a, "true") | |
1214 || strcmpi (a, "on") | |
1215 || strcmpi (a, "yes") | |
1216 || strcmpi (a, "1")))) | |
1217 auto = true; | |
1218 endif | |
1219 endif | |
1220 endfunction | |
1221 | |
1222 function prepare_installation (desc, packdir) | |
1223 ## Is there a pre_install to call? | |
1224 if (exist (fullfile (packdir, "pre_install.m"), "file")) | |
1225 wd = pwd (); | |
1226 try | |
1227 cd (packdir); | |
1228 pre_install (desc); | |
1229 cd (wd); | |
1230 catch | |
1231 cd (wd); | |
1232 rethrow (lasterror ()); | |
1233 end_try_catch | |
1234 endif | |
1235 | |
1236 ## If the directory "inst" doesn't exist, we create it. | |
1237 inst_dir = fullfile (packdir, "inst"); | |
1238 if (! exist (inst_dir, "dir")) | |
1239 [status, msg] = mkdir (inst_dir); | |
1240 if (status != 1) | |
1241 rm_rf (desc.dir); | |
1242 error ("the 'inst' directory did not exist and could not be created: %s", | |
1243 msg); | |
1244 endif | |
1245 endif | |
1246 endfunction | |
1247 | |
1248 function configure_make (desc, packdir, verbose) | |
1249 ## Perform ./configure, make, make install in "src". | |
1250 if (exist (fullfile (packdir, "src"), "dir")) | |
1251 src = fullfile (packdir, "src"); | |
1252 ## Configure. | |
1253 if (exist (fullfile (src, "configure"), "file")) | |
1254 flags = ""; | |
1255 if (isempty (getenv ("CC"))) | |
1256 flags = cstrcat (flags, " CC=\"", octave_config_info ("CC"), "\""); | |
1257 endif | |
1258 if (isempty (getenv ("CXX"))) | |
1259 flags = cstrcat (flags, " CXX=\"", octave_config_info ("CXX"), "\""); | |
1260 endif | |
1261 if (isempty (getenv ("AR"))) | |
1262 flags = cstrcat (flags, " AR=\"", octave_config_info ("AR"), "\""); | |
1263 endif | |
1264 if (isempty (getenv ("RANLIB"))) | |
1265 flags = cstrcat (flags, " RANLIB=\"", octave_config_info ("RANLIB"), "\""); | |
1266 endif | |
1267 [status, output] = shell (strcat ("cd '", src, "'; ./configure --prefix=\"", | |
1268 desc.dir, "\"", flags)); | |
1269 if (status != 0) | |
1270 rm_rf (desc.dir); | |
1271 error ("the configure script returned the following error: %s", output); | |
1272 elseif (verbose) | |
1273 printf("%s", output); | |
1274 endif | |
1275 | |
1276 endif | |
1277 | |
1278 ## Make. | |
1279 if (exist (fullfile (src, "Makefile"), "file")) | |
1280 [status, output] = shell (cstrcat ("export INSTALLDIR=\"", desc.dir, | |
1281 "\"; make -C '", src, "'")); | |
1282 if (status != 0) | |
1283 rm_rf (desc.dir); | |
1284 error ("'make' returned the following error: %s", output); | |
1285 elseif (verbose) | |
1286 printf("%s", output); | |
1287 endif | |
1288 endif | |
1289 | |
1290 ## Copy files to "inst" and "inst/arch" (this is instead of 'make | |
1291 ## install'). | |
1292 files = fullfile (src, "FILES"); | |
1293 instdir = fullfile (packdir, "inst"); | |
1294 archdir = fullfile (packdir, "inst", getarch ()); | |
1295 | |
1296 ## Get file names. | |
1297 if (exist (files, "file")) | |
1298 [fid, msg] = fopen (files, "r"); | |
1299 if (fid < 0) | |
1300 error ("couldn't open %s: %s", files, msg); | |
1301 endif | |
1302 filenames = char (fread (fid))'; | |
1303 fclose (fid); | |
1304 if (filenames(end) == "\n") | |
1305 filenames(end) = []; | |
1306 endif | |
1307 filenames = split_by (filenames, "\n"); | |
1308 delete_idx = []; | |
1309 for i = 1:length (filenames) | |
1310 if (! all (isspace (filenames{i}))) | |
1311 filenames{i} = fullfile (src, filenames{i}); | |
1312 else | |
1313 delete_idx(end+1) = i; | |
1314 endif | |
1315 endfor | |
1316 filenames(delete_idx) = []; | |
1317 else | |
1318 m = dir (fullfile (src, "*.m")); | |
1319 oct = dir (fullfile (src, "*.oct")); | |
1320 mex = dir (fullfile (src, "*.mex")); | |
1321 | |
1322 filenames = cellfun (@(x) fullfile (src, x), | |
1323 {m.name, oct.name, mex.name}, | |
1324 "UniformOutput", false); | |
1325 endif | |
1326 | |
1327 ## Split into architecture dependent and independent files. | |
1328 if (isempty (filenames)) | |
1329 idx = []; | |
1330 else | |
1331 idx = cellfun (@is_architecture_dependent, filenames); | |
1332 endif | |
1333 archdependent = filenames (idx); | |
1334 archindependent = filenames (!idx); | |
1335 | |
1336 ## Copy the files. | |
1337 if (! all (isspace ([filenames{:}]))) | |
1338 if (! exist (instdir, "dir")) # fixindent | |
1339 mkdir (instdir); | |
1340 endif | |
1341 if (! all (isspace ([archindependent{:}]))) | |
1342 if (verbose) | |
1343 printf ("copyfile"); | |
1344 printf (" %s", archindependent{:}); | |
1345 printf ("%s\n", instdir); | |
1346 endif | |
1347 [status, output] = copyfile (archindependent, instdir); | |
1348 if (status != 1) | |
1349 rm_rf (desc.dir); | |
1350 error ("Couldn't copy files from 'src' to 'inst': %s", output); | |
1351 endif | |
1352 endif | |
1353 if (! all (isspace ([archdependent{:}]))) | |
1354 if (verbose) | |
1355 printf ("copyfile"); | |
1356 printf (" %s", archdependent{:}); | |
1357 printf (" %s\n", archdir); | |
1358 endif | |
1359 if (! exist (archdir, "dir")) | |
1360 mkdir (archdir); | |
1361 endif | |
1362 [status, output] = copyfile (archdependent, archdir); | |
1363 if (status != 1) | |
1364 rm_rf (desc.dir); | |
1365 error ("Couldn't copy files from 'src' to 'inst': %s", output); | |
1366 endif | |
1367 endif | |
1368 endif | |
1369 endif | |
1370 endfunction | |
1371 | |
1372 function pkg = extract_pkg (nm, pat) | |
1373 fid = fopen (nm, "rt"); | |
1374 pkg = ""; | |
1375 if (fid >= 0) | |
1376 while (! feof (fid)) | |
1377 ln = fgetl (fid); | |
1378 if (ln > 0) | |
1379 t = regexp (ln, pat, "tokens"); | |
1380 if (! isempty (t)) | |
1381 pkg = cstrcat (pkg, "\n", t{1}{1}); | |
1382 endif | |
1383 endif | |
1384 endwhile | |
1385 if (! isempty (pkg)) | |
1386 pkg = cstrcat (pkg, "\n"); | |
1387 endif | |
1388 fclose (fid); | |
1389 endif | |
1390 endfunction | |
1391 | |
1392 function create_pkgadddel (desc, packdir, nm, global_install) | |
1393 instpkg = fullfile (desc.dir, nm); | |
1394 instfid = fopen (instpkg, "wt"); | |
1395 ## If it is exists, most of the PKG_* file should go into the | |
1396 ## architecture dependent directory so that the autoload/mfilename | |
1397 ## commands work as expected. The only part that doesn't is the | |
1398 ## part in the main directory. | |
1399 archdir = fullfile (getarchprefix (desc), cstrcat (desc.name, "-", | |
1400 desc.version), getarch ()); | |
1401 if (exist (getarchdir (desc, global_install), "dir")) | |
1402 archpkg = fullfile (getarchdir (desc, global_install), nm); | |
1403 archfid = fopen (archpkg, "at"); | |
1404 else | |
1405 archpkg = instpkg; | |
1406 archfid = instfid; | |
1407 endif | |
1408 | |
1409 if (archfid >= 0 && instfid >= 0) | |
1410 ## Search all dot-m files for PKG commands. | |
1411 lst = dir (fullfile (packdir, "inst", "*.m")); | |
1412 for i = 1:length (lst) | |
1413 nam = fullfile (packdir, "inst", lst(i).name); | |
1414 fwrite (instfid, extract_pkg (nam, ['^[#%][#%]* *' nm ': *(.*)$'])); | |
1415 endfor # fixindent | |
1416 | |
1417 ## Search all C++ source files for PKG commands. | |
1418 lst = dir (fullfile (packdir, "src", "*.cc")); # fixindent | |
1419 for i = 1:length (lst) | |
1420 nam = fullfile (packdir, "src", lst(i).name); | |
1421 fwrite (archfid, extract_pkg (nam, ['^//* *' nm ': *(.*)$'])); | |
1422 fwrite (archfid, extract_pkg (nam, ['^/\** *' nm ': *(.*) *\*/$'])); | |
1423 endfor | |
1424 | |
1425 ## Add developer included PKG commands. | |
1426 packdirnm = fullfile (packdir, nm); | |
1427 if (exist (packdirnm, "file")) | |
1428 fid = fopen (packdirnm, "rt"); | |
1429 if (fid >= 0) | |
1430 while (! feof (fid)) | |
1431 ln = fgets (fid); | |
1432 if (ln > 0) | |
1433 fwrite (archfid, ln); | |
1434 endif | |
1435 endwhile | |
1436 fclose (fid); | |
1437 endif | |
1438 endif | |
1439 | |
1440 ## If the files is empty remove it. | |
1441 fclose (instfid); | |
1442 t = dir (instpkg); | |
1443 if (t.bytes <= 0) | |
1444 unlink (instpkg); | |
1445 endif | |
1446 | |
1447 if (instfid != archfid) | |
1448 fclose (archfid); | |
1449 t = dir (archpkg); | |
1450 if (t.bytes <= 0) | |
1451 unlink (archpkg); | |
1452 endif | |
1453 endif | |
1454 endif # fixindent | |
1455 endfunction # fixindent | |
1456 | |
1457 function copy_files (desc, packdir, global_install) # fixindent | |
1458 ## Create the installation directory. | |
1459 if (! exist (desc.dir, "dir")) | |
1460 [status, output] = mkdir (desc.dir); | |
1461 if (status != 1) | |
1462 error ("couldn't create installation directory %s : %s", | |
1463 desc.dir, output); | |
1464 endif | |
1465 endif | |
1466 | |
1467 octfiledir = getarchdir (desc); | |
1468 | |
1469 ## Copy the files from "inst" to installdir. | |
1470 instdir = fullfile (packdir, "inst"); | |
1471 if (! dirempty (instdir)) | |
1472 [status, output] = copyfile (fullfile (instdir, "*"), desc.dir); | |
1473 if (status != 1) | |
1474 rm_rf (desc.dir); | |
1475 error ("couldn't copy files to the installation directory"); | |
1476 endif | |
1477 if (exist (fullfile (desc.dir, getarch ()), "dir") && | |
1478 ! strcmp (fullfile (desc.dir, getarch ()), octfiledir)) | |
1479 if (! exist (octfiledir, "dir")) | |
1480 ## Can be required to create upto three levels of dirs. | |
1481 octm1 = fileparts (octfiledir); | |
1482 if (! exist (octm1, "dir")) | |
1483 octm2 = fileparts (octm1); | |
1484 if (! exist (octm2, "dir")) | |
1485 octm3 = fileparts (octm2); | |
1486 if (! exist (octm3, "dir")) | |
1487 [status, output] = mkdir (octm3); | |
1488 if (status != 1) | |
1489 rm_rf (desc.dir); | |
1490 error ("couldn't create installation directory %s : %s", | |
1491 octm3, output); | |
1492 endif | |
1493 endif | |
1494 [status, output] = mkdir (octm2); | |
1495 if (status != 1) | |
1496 rm_rf (desc.dir); | |
1497 error ("couldn't create installation directory %s : %s", | |
1498 octm2, output); | |
1499 endif | |
1500 endif | |
1501 [status, output] = mkdir (octm1); | |
1502 if (status != 1) | |
1503 rm_rf (desc.dir); | |
1504 error ("couldn't create installation directory %s : %s", | |
1505 octm1, output); | |
1506 endif | |
1507 endif | |
1508 [status, output] = mkdir (octfiledir); | |
1509 if (status != 1) | |
1510 rm_rf (desc.dir); | |
1511 error ("couldn't create installation directory %s : %s", | |
1512 octfiledir, output); | |
1513 endif | |
1514 endif | |
1515 [status, output] = movefile (fullfile (desc.dir, getarch (), "*"), | |
1516 octfiledir); | |
1517 rm_rf (fullfile (desc.dir, getarch ())); | |
1518 | |
1519 if (status != 1) | |
1520 rm_rf (desc.dir); | |
1521 rm_rf (octfiledir); | |
1522 error ("couldn't copy files to the installation directory"); | |
1523 endif | |
1524 endif | |
1525 | |
1526 endif | |
1527 | |
1528 ## Create the "packinfo" directory. | |
1529 packinfo = fullfile (desc.dir, "packinfo"); | |
1530 [status, msg] = mkdir (packinfo); | |
1531 if (status != 1) | |
1532 rm_rf (desc.dir); | |
1533 rm_rf (octfiledir); | |
1534 error ("couldn't create packinfo directory: %s", msg); | |
1535 endif | |
1536 | |
1537 ## Copy DESCRIPTION. | |
1538 [status, output] = copyfile (fullfile (packdir, "DESCRIPTION"), packinfo); | |
1539 if (status != 1) | |
1540 rm_rf (desc.dir); | |
1541 rm_rf (octfiledir); | |
1542 error ("couldn't copy DESCRIPTION: %s", output); | |
1543 endif | |
1544 | |
1545 ## Copy COPYING. | |
1546 [status, output] = copyfile (fullfile (packdir, "COPYING"), packinfo); | |
1547 if (status != 1) | |
1548 rm_rf (desc.dir); | |
1549 rm_rf (octfiledir); | |
1550 error ("couldn't copy COPYING: %s", output); | |
1551 endif | |
1552 | |
1553 ## If the file ChangeLog exists, copy it. | |
1554 changelog_file = fullfile (packdir, "ChangeLog"); | |
1555 if (exist (changelog_file, "file")) | |
1556 [status, output] = copyfile (changelog_file, packinfo); | |
1557 if (status != 1) | |
1558 rm_rf (desc.dir); | |
1559 rm_rf (octfiledir); | |
1560 error ("couldn't copy ChangeLog file: %s", output); | |
1561 endif | |
1562 endif | |
1563 | |
1564 ## Is there an INDEX file to copy or should we generate one? | |
1565 index_file = fullfile (packdir, "INDEX"); | |
1566 if (exist(index_file, "file")) | |
1567 [status, output] = copyfile (index_file, packinfo); | |
1568 if (status != 1) | |
1569 rm_rf (desc.dir); | |
1570 rm_rf (octfiledir); | |
1571 error ("couldn't copy INDEX file: %s", output); | |
1572 endif | |
1573 else | |
1574 try | |
1575 write_index (desc, fullfile (packdir, "inst"), | |
1576 fullfile (packinfo, "INDEX"), global_install); | |
1577 catch | |
1578 rm_rf (desc.dir); | |
1579 rm_rf (octfiledir); | |
1580 rethrow (lasterror ()); | |
1581 end_try_catch | |
1582 endif | |
1583 | |
1584 ## Is there an 'on_uninstall.m' to install? | |
1585 fon_uninstall = fullfile (packdir, "on_uninstall.m"); | |
1586 if (exist (fon_uninstall, "file")) | |
1587 [status, output] = copyfile (fon_uninstall, packinfo); | |
1588 if (status != 1) | |
1589 rm_rf (desc.dir); | |
1590 rm_rf (octfiledir); | |
1591 error ("couldn't copy on_uninstall.m: %s", output); | |
1592 endif | |
1593 endif | |
1594 | |
1595 ## Is there a doc/ directory that needs to be installed? | |
1596 docdir = fullfile (packdir, "doc"); | |
1597 if (exist (docdir, "dir") && ! dirempty (docdir)) | |
1598 [status, output] = copyfile (docdir, desc.dir); | |
1599 endif | |
1600 | |
1601 ## Is there a bin/ directory that needs to be installed? | |
1602 ## FIXME: Need to treat architecture dependent files in bin/ | |
1603 bindir = fullfile (packdir, "bin"); | |
1604 if (exist (bindir, "dir") && ! dirempty (bindir)) | |
1605 [status, output] = copyfile (bindir, desc.dir); | |
1606 endif | |
1607 endfunction | |
1608 | |
1609 function finish_installation (desc, packdir, global_install) | |
1610 ## Is there a post-install to call? | |
1611 if (exist (fullfile (packdir, "post_install.m"), "file")) | |
1612 wd = pwd (); | |
1613 try | |
1614 cd (packdir); | |
1615 post_install (desc); | |
1616 cd (wd); | |
1617 catch | |
1618 cd (wd); | |
1619 rm_rf (desc.dir); | |
1620 rm_rf (getarchdir (desc), global_install); | |
1621 rethrow (lasterror ()); | |
1622 end_try_catch | |
1623 endif | |
1624 endfunction | |
1625 | |
1626 function generate_lookfor_cache (desc) | |
1627 dirs = split_by (genpath (desc.dir), pathsep ()); | |
1628 for i = 1 : length (dirs) | |
1629 gen_doc_cache (fullfile (dirs{i}, "doc-cache"), dirs{i}); | |
1630 endfor | |
1631 endfunction | |
1632 | |
1633 ## Make sure the package contains the essential files. | |
1634 function verify_directory (dir) | |
1635 needed_files = {"COPYING", "DESCRIPTION"}; | |
1636 for f = needed_files | |
1637 if (! exist (fullfile (dir, f{1}), "file")) | |
1638 error ("package is missing file: %s", f{1}); | |
1639 endif | |
1640 endfor | |
1641 endfunction | |
1642 | |
1643 ## Parse the DESCRIPTION file. | |
1644 function desc = get_description (filename) | |
1645 [fid, msg] = fopen (filename, "r"); | |
1646 if (fid == -1) | |
1647 error ("the DESCRIPTION file %s could not be read: %s", filename, msg); | |
1648 endif | |
1649 | |
1650 desc = struct (); | |
1651 | |
1652 line = fgetl (fid); | |
1653 while (line != -1) | |
1654 if (line(1) == "#") | |
1655 ## Comments, do nothing. | |
1656 elseif (isspace(line(1))) | |
1657 ## Continuation lines | |
1658 if (exist ("keyword", "var") && isfield (desc, keyword)) | |
1659 desc.(keyword) = cstrcat (desc.(keyword), " ", rstrip(line)); | |
1660 endif | |
1661 else | |
1662 ## Keyword/value pair | |
1663 colon = find (line == ":"); | |
1664 if (length (colon) == 0) | |
1665 disp ("skipping line"); | |
1666 else | |
1667 colon = colon(1); | |
1668 keyword = tolower (strip (line(1:colon-1))); | |
1669 value = strip (line (colon+1:end)); | |
1670 if (length (value) == 0) | |
1671 fclose (fid); | |
1672 error ("the keyword %s has an empty value", desc.keywords{end}); | |
1673 endif | |
1674 desc.(keyword) = value; | |
1675 endif | |
1676 endif | |
1677 line = fgetl (fid); | |
1678 endwhile | |
1679 fclose (fid); | |
1680 | |
1681 ## Make sure all is okay. | |
1682 needed_fields = {"name", "version", "date", "title", ... | |
1683 "author", "maintainer", "description"}; | |
1684 for f = needed_fields | |
1685 if (! isfield (desc, f{1})) | |
1686 error ("description is missing needed field %s", f{1}); | |
1687 endif | |
1688 endfor | |
1689 desc.version = fix_version (desc.version); | |
1690 if (isfield (desc, "depends")) | |
1691 desc.depends = fix_depends (desc.depends); | |
1692 else | |
1693 desc.depends = ""; | |
1694 endif | |
1695 desc.name = tolower (desc.name); | |
1696 endfunction | |
1697 | |
1698 ## Make sure the version string v is a valid x.y.z version string | |
1699 ## Examples: "0.1" => "0.1.0", "monkey" => error(...). | |
1700 function out = fix_version (v) | |
1701 dots = find (v == "."); | |
1702 if (length (dots) == 1) | |
1703 major = str2num (v(1:dots-1)); | |
1704 minor = str2num (v(dots+1:end)); | |
1705 if (length (major) != 0 && length (minor) != 0) | |
1706 out = sprintf ("%d.%d.0", major, minor); | |
1707 return; | |
1708 endif | |
1709 elseif (length (dots) == 2) | |
1710 major = str2num (v(1:dots(1)-1)); | |
1711 minor = str2num (v(dots(1)+1:dots(2)-1)); | |
1712 rev = str2num (v(dots(2)+1:end)); | |
1713 if (length (major) != 0 && length (minor) != 0 && length (rev) != 0) | |
1714 out = sprintf ("%d.%d.%d", major, minor, rev); | |
1715 return; | |
1716 endif | |
1717 endif | |
1718 error ("bad version string: %s", v); | |
1719 endfunction | |
1720 | |
1721 ## Make sure the depends field is of the right format. | |
1722 ## This function returns a cell of structures with the following fields: | |
1723 ## package, version, operator | |
1724 function deps_cell = fix_depends (depends) | |
1725 deps = split_by (tolower (depends), ","); | |
1726 deps_cell = cell (1, length (deps)); | |
1727 | |
1728 ## For each dependency. | |
1729 for i = 1:length (deps) | |
1730 dep = deps{i}; | |
1731 lpar = find (dep == "("); | |
1732 rpar = find (dep == ")"); | |
1733 ## Does the dependency specify a version | |
1734 ## Example: package(>= version). | |
1735 if (length (lpar) == 1 && length (rpar) == 1) | |
1736 package = tolower (strip (dep(1:lpar-1))); | |
1737 sub = dep(lpar(1)+1:rpar(1)-1); | |
1738 parts = strsplit (sub, " ", true); | |
1739 if (length (parts) != 2) | |
1740 error ("incorrect syntax for dependency `%s' in the DESCRIPTION file\n", | |
1741 dep); | |
1742 endif | |
1743 operator = parts{1}; | |
1744 if (! any (strcmp (operator, {">", ">=", "<=", "<", "=="}))) | |
1745 error ("unsupported operator: %s", operator); | |
1746 endif | |
1747 version = fix_version (parts{2}); | |
1748 | |
1749 ## If no version is specified for the dependency | |
1750 ## we say that the version should be greater than | |
1751 ## or equal to "0.0.0". | |
1752 else | |
1753 package = tolower (strip (dep)); | |
1754 operator = ">="; | |
1755 version = "0.0.0"; | |
1756 endif | |
1757 deps_cell{i} = struct ("package", package, "operator", operator, | |
1758 "version", version); | |
1759 endfor | |
1760 endfunction | |
1761 | |
1762 ## Strip the text of spaces from the right | |
1763 ## Example: " hello world " => " hello world" | |
1764 ## FIXME -- is this the same as deblank? | |
1765 function text = rstrip (text) | |
1766 chars = find (! isspace (text)); | |
1767 if (length (chars) > 0) | |
1768 ## FIXME: shouldn't it be text = text(1:chars(end)); | |
1769 text = text (chars(1):end); | |
1770 else | |
1771 text = ""; | |
1772 endif | |
1773 endfunction | |
1774 | |
1775 ## Strip the text of spaces from the left and the right. | |
1776 ## Example: " hello world " => "hello world" | |
1777 function text = strip (text) | |
1778 chars = find (! isspace (text)); | |
1779 if (length (chars) > 0) | |
1780 text = text(chars(1):chars(end)); | |
1781 else | |
1782 text = ""; | |
1783 endif | |
1784 endfunction | |
1785 | |
1786 ## Split the text into a cell array of strings by sep. | |
1787 ## Example: "A, B" => {"A", "B"} (with sep = ",") | |
1788 function out = split_by (text, sep) | |
1789 out = strtrim (strsplit (text, sep)); | |
1790 endfunction | |
1791 | |
1792 ## Create an INDEX file for a package that doesn't provide one. | |
1793 ## 'desc' describes the package. | |
1794 ## 'dir' is the 'inst' directory in temporary directory. | |
1795 ## 'index_file' is the name (including path) of resulting INDEX file. | |
1796 function write_index (desc, dir, index_file, global_install) | |
1797 ## Get names of functions in dir | |
1798 [files, err, msg] = readdir (dir); | |
1799 if (err) | |
1800 error ("couldn't read directory %s: %s", dir, msg); | |
1801 endif | |
1802 | |
1803 ## Check for architecture dependent files. | |
1804 tmpdir = getarchdir (desc); | |
1805 if (exist (tmpdir, "dir")) | |
1806 [files2, err, msg] = readdir (tmpdir); | |
1807 if (err) | |
1808 error ("couldn't read directory %s: %s", tmpdir, msg); | |
1809 endif | |
1810 files = [files; files2]; | |
1811 endif | |
1812 | |
1813 functions = {}; | |
1814 for i = 1:length (files) | |
1815 file = files{i}; | |
1816 lf = length (file); | |
1817 if (lf > 2 && strcmp (file(end-1:end), ".m")) | |
1818 functions{end+1} = file(1:end-2); | |
1819 elseif (lf > 4 && strcmp (file(end-3:end), ".oct")) | |
1820 functions{end+1} = file(1:end-4); | |
1821 endif | |
1822 endfor | |
1823 | |
1824 ## Does desc have a categories field? | |
1825 if (! isfield (desc, "categories")) | |
1826 error ("the DESCRIPTION file must have a Categories field, when no INDEX file is given"); | |
1827 endif | |
1828 categories = split_by (desc.categories, ","); | |
1829 if (length (categories) < 1) | |
1830 error ("the Category field is empty"); | |
1831 endif | |
1832 | |
1833 ## Write INDEX. | |
1834 fid = fopen (index_file, "w"); | |
1835 if (fid == -1) | |
1836 error ("couldn't open %s for writing.", index_file); | |
1837 endif | |
1838 fprintf (fid, "%s >> %s\n", desc.name, desc.title); | |
1839 fprintf (fid, "%s\n", categories{1}); | |
1840 fprintf (fid, " %s\n", functions{:}); | |
1841 fclose (fid); | |
1842 endfunction | |
1843 | |
1844 function bad_deps = get_unsatisfied_deps (desc, installed_pkgs_lst) | |
1845 bad_deps = {}; | |
1846 | |
1847 ## For each dependency. | |
1848 for i = 1:length (desc.depends) | |
1849 dep = desc.depends{i}; | |
1850 | |
1851 ## Is the current dependency Octave? | |
1852 if (strcmp (dep.package, "octave")) | |
1853 if (! compare_versions (OCTAVE_VERSION, dep.version, dep.operator)) | |
1854 bad_deps{end+1} = dep; | |
1855 endif | |
1856 ## Is the current dependency not Octave? | |
1857 else | |
1858 ok = false; | |
1859 for i = 1:length (installed_pkgs_lst) | |
1860 cur_name = installed_pkgs_lst{i}.name; | |
1861 cur_version = installed_pkgs_lst{i}.version; | |
1862 if (strcmp (dep.package, cur_name) | |
1863 && compare_versions (cur_version, dep.version, dep.operator)) | |
1864 ok = true; | |
1865 break; | |
1866 endif | |
1867 endfor | |
1868 if (! ok) | |
1869 bad_deps{end+1} = dep; | |
1870 endif | |
1871 endif | |
1872 endfor | |
1873 endfunction | |
1874 | |
1875 function [out1, out2] = installed_packages (local_list, global_list) | |
1876 ## Get the list of installed packages. | |
1877 try | |
1878 local_packages = load (local_list).local_packages; | |
1879 catch | |
1880 local_packages = {}; | |
1881 end_try_catch | |
1882 try | |
1883 global_packages = load (global_list).global_packages; | |
1884 catch | |
1885 global_packages = {}; | |
1886 end_try_catch | |
1887 installed_pkgs_lst = {local_packages{:}, global_packages{:}}; | |
1888 | |
1889 ## Eliminate duplicates in the installed package list. | |
1890 ## Locally installed packages take precedence. | |
1891 dup = []; | |
1892 for i = 1:length (installed_pkgs_lst) | |
1893 if (find (dup, i)) | |
1894 continue; | |
1895 endif | |
1896 for j = (i+1):length (installed_pkgs_lst) | |
1897 if (find (dup, j)) | |
1898 continue; | |
1899 endif | |
1900 if (strcmp (installed_pkgs_lst{i}.name, installed_pkgs_lst{j}.name)) | |
1901 dup = [dup, j]; | |
1902 endif | |
1903 endfor | |
1904 endfor | |
1905 if (! isempty(dup)) | |
1906 installed_pkgs_lst(dup) = []; | |
1907 endif | |
1908 | |
1909 ## Now check if the package is loaded. | |
1910 tmppath = strrep (path(), "\\", "/"); | |
1911 for i = 1:length (installed_pkgs_lst) | |
1912 if (findstr (tmppath, strrep (installed_pkgs_lst{i}.dir, "\\", "/"))) | |
1913 installed_pkgs_lst{i}.loaded = true; | |
1914 else | |
1915 installed_pkgs_lst{i}.loaded = false; | |
1916 endif | |
1917 endfor | |
1918 for i = 1:length (local_packages) | |
1919 if (findstr (tmppath, strrep (local_packages{i}.dir, "\\", "/"))) | |
1920 local_packages{i}.loaded = true; | |
1921 else | |
1922 local_packages{i}.loaded = false; | |
1923 endif | |
1924 endfor | |
1925 for i = 1:length (global_packages) | |
1926 if (findstr (tmppath, strrep (global_packages{i}.dir, "\\", "/"))) | |
1927 global_packages{i}.loaded = true; | |
1928 else | |
1929 global_packages{i}.loaded = false; | |
1930 endif | |
1931 endfor | |
1932 | |
1933 ## Should we return something? | |
1934 if (nargout == 2) | |
1935 out1 = local_packages; | |
1936 out2 = global_packages; | |
1937 return; | |
1938 elseif (nargout == 1) | |
1939 out1 = installed_pkgs_lst; | |
1940 return; | |
1941 endif | |
1942 | |
1943 ## We shouldn't return something, so we'll print something. | |
1944 num_packages = length (installed_pkgs_lst); | |
1945 if (num_packages == 0) | |
1946 printf ("no packages installed.\n"); | |
1947 return; | |
1948 endif | |
1949 | |
1950 ## Compute the maximal lengths of name, version, and dir. | |
1951 h1 = "Package Name"; | |
1952 h2 = "Version"; | |
1953 h3 = "Installation directory"; | |
1954 max_name_length = length (h1); | |
1955 max_version_length = length (h2); | |
1956 names = cell (num_packages, 1); | |
1957 for i = 1:num_packages | |
1958 max_name_length = max (max_name_length, | |
1959 length (installed_pkgs_lst{i}.name)); | |
1960 max_version_length = max (max_version_length, | |
1961 length (installed_pkgs_lst{i}.version)); | |
1962 names{i} = installed_pkgs_lst{i}.name; | |
1963 endfor | |
1964 max_dir_length = terminal_size()(2) - max_name_length - ... | |
1965 max_version_length - 7; | |
1966 if (max_dir_length < 20) | |
1967 max_dir_length = Inf; | |
1968 endif | |
1969 | |
1970 h1 = postpad (h1, max_name_length + 1, " "); | |
1971 h2 = postpad (h2, max_version_length, " ");; | |
1972 | |
1973 ## Print a header. | |
1974 header = sprintf("%s | %s | %s\n", h1, h2, h3); | |
1975 printf (header); | |
1976 tmp = sprintf (repmat ("-", 1, length(header)-1)); | |
1977 tmp(length(h1)+2) = "+"; | |
1978 tmp(length(h1)+length(h2)+5) = "+"; | |
1979 printf ("%s\n", tmp); | |
1980 | |
1981 ## Print the packages. | |
1982 format = sprintf ("%%%ds %%1s| %%%ds | %%s\n", max_name_length, | |
1983 max_version_length); | |
1984 [dummy, idx] = sort (names); | |
1985 for i = 1:num_packages | |
1986 cur_name = installed_pkgs_lst{idx(i)}.name; | |
1987 cur_version = installed_pkgs_lst{idx(i)}.version; | |
1988 cur_dir = installed_pkgs_lst{idx(i)}.dir; | |
1989 if (length (cur_dir) > max_dir_length) | |
1990 first_char = length (cur_dir) - max_dir_length + 4; | |
1991 first_filesep = strfind (cur_dir(first_char:end), filesep()); | |
1992 if (! isempty (first_filesep)) | |
1993 cur_dir = cstrcat ("...", | |
1994 cur_dir((first_char + first_filesep(1) - 1):end)); | |
1995 else | |
1996 cur_dir = cstrcat ("...", cur_dir(first_char:end)); | |
1997 endif | |
1998 endif | |
1999 if (installed_pkgs_lst{idx(i)}.loaded) | |
2000 cur_loaded = "*"; | |
2001 else | |
2002 cur_loaded = " "; | |
2003 endif | |
2004 printf (format, cur_name, cur_loaded, cur_version, cur_dir); | |
2005 endfor | |
2006 endfunction | |
2007 | |
2008 function load_packages (files, handle_deps, local_list, global_list) | |
2009 installed_pkgs_lst = installed_packages (local_list, global_list); | |
2010 num_packages = length (installed_pkgs_lst); | |
2011 | |
2012 ## Read package names and installdirs into a more convenient format. | |
2013 pnames = pdirs = cell (1, num_packages); | |
2014 for i = 1:num_packages | |
2015 pnames{i} = installed_pkgs_lst{i}.name; | |
2016 pdirs{i} = installed_pkgs_lst{i}.dir; | |
2017 endfor | |
2018 | |
2019 ## Load all. | |
2020 if (length (files) == 1 && strcmp (files{1}, "all")) | |
2021 idx = [1:length(installed_pkgs_lst)]; | |
2022 ## Load auto. | |
2023 elseif (length (files) == 1 && strcmp (files{1}, "auto")) | |
2024 idx = []; | |
2025 for i = 1:length (installed_pkgs_lst) | |
2026 if (exist (fullfile (pdirs{i}, "packinfo", ".autoload"), "file")) | |
2027 idx (end + 1) = i; | |
2028 endif | |
2029 endfor | |
2030 ## Load package_name1 ... | |
2031 else | |
2032 idx = []; | |
2033 for i = 1:length (files) | |
2034 idx2 = find (strcmp (pnames, files{i})); | |
2035 if (! any (idx2)) | |
2036 error ("package %s is not installed", files{i}); | |
2037 endif | |
2038 idx (end + 1) = idx2; | |
2039 endfor | |
2040 endif | |
2041 | |
2042 ## Load the packages, but take care of the ordering of dependencies. | |
2043 load_packages_and_dependencies (idx, handle_deps, installed_pkgs_lst, true); | |
2044 endfunction | |
2045 | |
2046 function unload_packages (files, handle_deps, local_list, global_list) | |
2047 installed_pkgs_lst = installed_packages (local_list, global_list); | |
2048 num_packages = length (installed_pkgs_lst); | |
2049 | |
2050 ## Read package names and installdirs into a more convenient format. | |
2051 pnames = pdirs = cell (1, num_packages); | |
2052 for i = 1:num_packages | |
2053 pnames{i} = installed_pkgs_lst{i}.name; | |
2054 pdirs{i} = installed_pkgs_lst{i}.dir; | |
2055 pdeps{i} = installed_pkgs_lst{i}.depends; | |
2056 endfor | |
2057 | |
2058 ## Get the current octave path. | |
2059 p = split_by (path(), pathsep ()); | |
2060 | |
2061 if (length (files) == 1 && strcmp (files{1}, "all")) | |
2062 ## Unload all. | |
2063 dirs = pdirs; | |
2064 desc = installed_pkgs_lst; | |
2065 else | |
2066 ## Unload package_name1 ... | |
2067 dirs = {}; | |
2068 desc = {}; | |
2069 for i = 1:length (files) | |
2070 idx = strcmp (pnames, files{i}); | |
2071 if (! any (idx)) | |
2072 error ("package %s is not installed", files{i}); | |
2073 endif | |
2074 dirs{end+1} = pdirs{idx}; | |
2075 desc{end+1} = installed_pkgs_lst{idx}; | |
2076 endfor | |
2077 endif | |
2078 | |
2079 ## Check for architecture dependent directories. | |
2080 archdirs = {}; | |
2081 for i = 1:length (dirs) | |
2082 tmpdir = getarchdir (desc{i}); | |
2083 if (exist (tmpdir, "dir")) | |
2084 archdirs{end+1} = dirs{i}; | |
2085 archdirs{end+1} = tmpdir; | |
2086 else | |
2087 archdirs{end+1} = dirs{i}; | |
2088 endif | |
2089 endfor | |
2090 | |
2091 ## Unload the packages. | |
2092 for i = 1:length (archdirs) | |
2093 d = archdirs{i}; | |
2094 idx = strcmp (p, d); | |
2095 if (any (idx)) | |
2096 rmpath (d); | |
2097 ## FIXME: We should also check if we need to remove items from | |
2098 ## EXEC_PATH. | |
2099 endif | |
2100 endfor | |
2101 endfunction | |
2102 | |
2103 function [status_out, msg_out] = rm_rf (dir) | |
2104 if (exist (dir)) | |
2105 crr = confirm_recursive_rmdir (); | |
2106 unwind_protect | |
2107 confirm_recursive_rmdir (false); | |
2108 [status, msg] = rmdir (dir, "s"); | |
2109 unwind_protect_cleanup | |
2110 confirm_recursive_rmdir (crr); | |
2111 end_unwind_protect | |
2112 else | |
2113 status = 1; | |
2114 msg = ""; | |
2115 endif | |
2116 if (nargout > 0) | |
2117 status_out = status; | |
2118 endif | |
2119 if (nargout > 1) | |
2120 msg_out = msg; | |
2121 endif | |
2122 endfunction | |
2123 | |
2124 function emp = dirempty (nm, ign) | |
2125 if (exist (nm, "dir")) | |
2126 if (nargin < 2) | |
2127 ign = {".", ".."}; | |
2128 else | |
2129 ign = [{".", ".."}, ign]; | |
2130 endif | |
2131 l = dir (nm); | |
2132 for i = 1:length (l) | |
2133 found = false; | |
2134 for j = 1:length (ign) | |
2135 if (strcmp (l(i).name, ign{j})) | |
2136 found = true; | |
2137 break; | |
2138 endif | |
2139 endfor | |
2140 if (! found) | |
2141 emp = false; | |
2142 return | |
2143 endif | |
2144 endfor | |
2145 emp = true; | |
2146 else | |
2147 emp = true; | |
2148 endif | |
2149 endfunction | |
2150 | |
2151 function arch = getarch () | |
2152 persistent _arch = cstrcat (octave_config_info("canonical_host_type"), ... | |
2153 "-", octave_config_info("api_version")); | |
2154 arch = _arch; | |
2155 endfunction | |
2156 | |
2157 function archprefix = getarchprefix (desc, global_install) | |
2158 if ((nargin == 2 && global_install) || (nargin < 2 && issuperuser ())) | |
2159 archprefix = fullfile (octave_config_info ("libexecdir"), "octave", | |
2160 "packages", cstrcat(desc.name, "-", desc.version)); | |
2161 else | |
2162 archprefix = desc.dir; | |
2163 endif | |
2164 endfunction | |
2165 | |
2166 function archdir = getarchdir (desc) | |
2167 archdir = fullfile (desc.archprefix, getarch()); | |
2168 endfunction | |
2169 | |
2170 function s = issuperuser () | |
2171 if ((ispc () && ! isunix ()) || (geteuid() == 0)) | |
2172 s = true; | |
2173 else | |
2174 s = false; | |
2175 endif | |
2176 endfunction | |
2177 | |
2178 function [status, output] = shell (cmd) | |
2179 persistent have_sh; | |
2180 | |
2181 cmd = strrep (cmd, "\\", "/"); | |
2182 if (ispc () && ! isunix ()) | |
2183 if (isempty(have_sh)) | |
2184 if (system("sh.exe -c \"exit\"")) | |
2185 have_sh = false; | |
2186 else | |
2187 have_sh = true; | |
2188 endif | |
2189 endif | |
2190 if (have_sh) | |
2191 [status, output] = system (cstrcat ("sh.exe -c \"", cmd, "\"")); | |
2192 else | |
2193 error ("Can not find the command shell") | |
2194 endif | |
2195 else | |
2196 [status, output] = system (cmd); | |
2197 endif | |
2198 endfunction | |
2199 | |
2200 function newdesc = save_order (desc) | |
2201 newdesc = {}; | |
2202 for i = 1 : length(desc) | |
2203 deps = desc{i}.depends; | |
2204 if (isempty (deps) || (length (deps) == 1 && | |
2205 strcmp(deps{1}.package, "octave"))) | |
2206 newdesc {end + 1} = desc{i}; | |
2207 else | |
2208 tmpdesc = {}; | |
2209 for k = 1 : length (deps) | |
2210 for j = 1 : length (desc) | |
2211 if (strcmp (desc{j}.name, deps{k}.package)) | |
2212 tmpdesc{end+1} = desc{j}; | |
2213 break; | |
2214 endif | |
2215 endfor | |
2216 endfor | |
2217 if (! isempty (tmpdesc)) | |
2218 newdesc = {newdesc{:}, save_order(tmpdesc){:}, desc{i}}; | |
2219 else | |
2220 newdesc{end+1} = desc{i}; | |
2221 endif | |
2222 endif | |
2223 endfor | |
2224 ## Eliminate the duplicates. | |
2225 idx = []; | |
2226 for i = 1 : length (newdesc) | |
2227 for j = (i + 1) : length (newdesc) | |
2228 if (strcmp (newdesc{i}.name, newdesc{j}.name)) | |
2229 idx (end + 1) = j; | |
2230 endif | |
2231 endfor | |
2232 endfor | |
2233 newdesc(idx) = []; | |
2234 endfunction | |
2235 | |
2236 function load_packages_and_dependencies (idx, handle_deps, installed_pkgs_lst, | |
2237 global_install) | |
2238 idx = load_package_dirs (idx, [], handle_deps, installed_pkgs_lst); | |
2239 dirs = {}; | |
2240 execpath = EXEC_PATH (); | |
2241 for i = idx; | |
2242 ndir = installed_pkgs_lst{i}.dir; | |
2243 dirs{end+1} = ndir; | |
2244 if (exist (fullfile (dirs{end}, "bin"), "dir")) | |
2245 execpath = cstrcat (fullfile (dirs{end}, "bin"), ":", execpath); | |
2246 endif | |
2247 tmpdir = getarchdir (installed_pkgs_lst{i}); | |
2248 if (exist (tmpdir, "dir")) | |
2249 dirs{end + 1} = tmpdir; | |
2250 if (exist (fullfile (dirs{end}, "bin"), "dir")) | |
2251 execpath = cstrcat (fullfile (dirs{end}, "bin"), ":", execpath); | |
2252 endif | |
2253 endif | |
2254 endfor | |
2255 | |
2256 ## Load the packages. | |
2257 if (length (dirs) > 0) | |
2258 addpath (dirs{:}); | |
2259 endif | |
2260 | |
2261 ## Add the binaries to exec_path. | |
2262 if (! strcmp (EXEC_PATH, execpath)) | |
2263 EXEC_PATH (execpath); | |
2264 endif | |
2265 endfunction | |
2266 | |
2267 function idx = load_package_dirs (lidx, idx, handle_deps, installed_pkgs_lst) | |
2268 for i = lidx | |
2269 if (isfield (installed_pkgs_lst{i}, "loaded") && | |
2270 installed_pkgs_lst{i}.loaded) | |
2271 continue; | |
2272 else | |
2273 if (handle_deps) | |
2274 deps = installed_pkgs_lst{i}.depends; | |
2275 if ((length (deps) > 1) || (length (deps) == 1 && | |
2276 ! strcmp(deps{1}.package, "octave"))) | |
2277 tmplidx = []; | |
2278 for k = 1 : length (deps) | |
2279 for j = 1 : length (installed_pkgs_lst) | |
2280 if (strcmp (installed_pkgs_lst{j}.name, deps{k}.package)) | |
2281 tmplidx (end + 1) = j; | |
2282 break; | |
2283 endif | |
2284 endfor | |
2285 endfor | |
2286 idx = load_package_dirs (tmplidx, idx, handle_deps, | |
2287 installed_pkgs_lst); | |
2288 endif | |
2289 endif | |
2290 if (isempty (find(idx == i))) | |
2291 idx (end + 1) = i; | |
2292 endif | |
2293 endif | |
2294 endfor | |
2295 endfunction | |
2296 | |
2297 function dep = is_architecture_dependent (nm) | |
2298 persistent archdepsuffix = {".oct",".mex",".a",".lib",".so",".so.*",".dll","dylib"}; | |
2299 | |
2300 dep = false; | |
2301 for i = 1 : length (archdepsuffix) | |
2302 ext = archdepsuffix{i}; | |
2303 if (ext(end) == "*") | |
2304 isglob = true; | |
2305 ext(end) = []; | |
2306 else | |
2307 isglob = false; | |
2308 endif | |
2309 pos = findstr (nm, ext); | |
2310 if (pos) | |
2311 if (! isglob && (length(nm) - pos(end) != length(ext) - 1)) | |
2312 continue; | |
2313 endif | |
2314 dep = true; | |
2315 break; | |
2316 endif | |
2317 endfor | |
2318 endfunction |