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