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