Making forge-packages installation relocatable

View: New views
1 Messages — Rating Filter:   Alert me  

Making forge-packages installation relocatable

by Benjamin Lindner :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hello all,

One item on my personal todo list for octave has long been to make the
octave forge package installation via pkg.m relocatable, i.e. allowing
an installed octave directory structure to be moved elsewhere and having
everything work as before (thus making octave a truly portable application).

Currently this works for octave itself, but not if forge packages are
installed.

This is, because installed packages are referred to by their absolute
path at the time of installation.
My idea is to remove the absolute path and store only the package's
actual subdirectory and restore the absolute path at runtime based on
OCTAVE_HOME().

Thinking about it I realised that  this makes sense only for globally
installed packages - not locally installed ones.

I have attached a first attempt to achieve this.

I'm not entirely satisified by the solution, but it is a first attempt
and it does work for me for octave-3.2.3 on windows.

comments and suggestions are very welcome.

I see that the package list structure contains actually two directory paths:
  .dir
  .archprefix

In the attached patch I actually only deal with the .dir field, by
creating a new function getdir() (similar to getarchdir()) and replacing
all explicit references to the field .dir by a call to this new function.

The situation with .archprefix is different, as currently, this field is
not referenced directly, rather than through the function getsrchdir().
So I modified this function to generate the actual absolute path at runtime.

But actually the field .archprefix is redundant, because this directory
can be (and is) created from the package's description and version at
runtime, so couldn't it be removed anyway?

benjamin

diff -r d5ba49ddea77 scripts/pkg/pkg.m
--- a/scripts/pkg/pkg.m Sun Oct 25 19:31:34 2009 +0100
+++ b/scripts/pkg/pkg.m Tue Oct 27 21:50:50 2009 +0100
@@ -205,7 +205,7 @@
      "octave_packages");
   mlock ();
 
-  global_install = issuperuser ();
+  global_install = issuperuser ()
 
   if (prefix == -1)
     if (global_install)
@@ -370,7 +370,7 @@
     case "rebuild"
       if (global_install)
  global_packages = rebuild (prefix, archprefix, global_list, files,
-   auto, verbose);
+   auto, verbose, global_install);
  global_packages = save_order (global_packages);
  save (global_list, "global_packages");
  if (nargout > 0)
@@ -378,7 +378,7 @@
  endif
       else
  local_packages = rebuild (prefix, archprefix, local_list, files, auto,
-  verbose);
+  verbose, global_install);
  local_packages = save_order (local_packages);
  save (local_list, "local_packages");
  if (nargout == 0)
@@ -419,7 +419,7 @@
   endswitch
 endfunction
 
-function descriptions = rebuild (prefix, archprefix, list, files, auto, verbose)
+function descriptions = rebuild (prefix, archprefix, list, files, auto, verbose, global_install)
   if (isempty (files))
     [dirlist, err, msg] = readdir (prefix);
     if (err)
@@ -445,21 +445,27 @@
     endif
     if (exist (descfile, "file"))
       desc = get_description (descfile);
-      desc.dir = fullfile (prefix, dirlist{k});
+      if (global_install)
+ desc.dir = dirlist{k};
+ desc.dir_is_relative = true;
+      else
+ desc.dir = fullfile (prefix, dirlist{k});
+ desc.dir_is_relative = false;
+      endif
       desc.archprefix = fullfile (archprefix, cstrcat (desc.name, "-",
   desc.version));
       if (auto != 0)
- if (exist (fullfile (desc.dir, "packinfo", ".autoload"), "file"))
-  unlink (fullfile (desc.dir, "packinfo", ".autoload"));
+ if (exist (fullfile (getdir (desc), "packinfo", ".autoload"), "file"))
+  unlink (fullfile (getdir (desc), "packinfo", ".autoload"));
  endif
         if (auto < 0)
   desc.autoload = 0;
  elseif (auto > 0)
   desc.autoload = 1;
-  fclose (fopen (fullfile (desc.dir, "packinfo", ".autoload"), "wt"));
+  fclose (fopen (fullfile (getdir (desc), "packinfo", ".autoload"), "wt"));
  endif
       else
- if (exist (fullfile (desc.dir, "packinfo", ".autoload"), "file"))
+ if (exist (fullfile (getdir (desc), "packinfo", ".autoload"), "file"))
   desc.autoload = 1;
  else
   desc.autoload = 0;
@@ -632,7 +638,13 @@
  endif
 
  ## Set default installation directory.
- desc.dir = fullfile (prefix, cstrcat (desc.name, "-", desc.version));
+ if (global_install)
+    desc.dir = cstrcat (desc.name, "-", desc.version);
+    desc.dir_is_relative = true;
+ else
+    desc.dir = fullfile (prefix, cstrcat (desc.name, "-", desc.version));
+    desc.dir_is_relative = false;
+ endif
 
  ## Set default architectire dependent installation directory.
  desc.archprefix = fullfile (archprefix, cstrcat (desc.name, "-",
@@ -750,7 +762,7 @@
       rm_rf (tmpdirs{i});
     endfor
     for i = 1:length (descriptions)
-      rm_rf (descriptions{i}.dir);
+      rm_rf (getdir (descriptions{i}.dir));
       rm_rf (getarchdir (descriptions{i}));
     endfor
     rethrow (lasterror ());
@@ -759,10 +771,11 @@
   ## Check if the installed directory is empty. If it is remove it
   ## from the list.
   for i = length (descriptions):-1:1
-    if (dirempty (descriptions{i}.dir, {"packinfo", "doc"}) &&
+    descriptions{i}
+    if (dirempty (getdir (descriptions{i}), {"packinfo", "doc"}) &&
  dirempty (getarchdir (descriptions{i})))
       warning ("package %s is empty\n", descriptions{i}.name);
-      rm_rf (descriptions{i}.dir);
+      rm_rf (getdir (descriptions{i}));
       rm_rf (getarchdir (descriptions{i}));
       descriptions(i) = [];
     endif
@@ -771,8 +784,9 @@
   ## If the package requested that it is autoloaded, or the installer
   ## requested that it is, then mark the package as autoloaded.
   for i = length (descriptions):-1:1
+    disp(descriptions{i})
     if (autoload > 0 || (autoload == 0 && isautoload (descriptions(i))))
-      fclose (fopen (fullfile (descriptions{i}.dir, "packinfo",
+      fclose (fopen (fullfile (getdir (descriptions{i}), "packinfo",
        ".autoload"), "wt"));
       descriptions{i}.autoload = 1;
     endif
@@ -797,7 +811,7 @@
       rm_rf (tmpdirs{i});
     endfor
     for i = 1:length (descriptions)
-      rm_rf (descriptions{i}.dir);
+      rm_rf (getdir (descriptions{i}));
     endfor
     if (global_install)
       printf ("error: couldn't append to %s\n", global_list);
@@ -910,23 +924,23 @@
   for i = delete_idx
     desc = installed_pkgs_lst{i};
     ## If an 'on_uninstall.m' exist, call it!
-    if (exist (fullfile (desc.dir, "packinfo", "on_uninstall.m"), "file"))
+    if (exist (fullfile (getdir (desc), "packinfo", "on_uninstall.m"), "file"))
       wd = pwd ();
-      cd (fullfile (desc.dir, "packinfo"));
+      cd (fullfile (getdir (desc), "packinfo"));
       on_uninstall (desc);
       cd (wd);
     endif
     ## Do the actual deletion.
     if (desc.loaded)
-      rmpath (desc.dir);
+      rmpath (getdir (desc));
       if (exist (getarchdir (desc)))
  rmpath (getarchdir (desc));
       endif
     endif
-    if (exist (desc.dir, "dir"))
-      [status, msg] = rm_rf (desc.dir);
+    if (exist (getdir (desc), "dir"))
+      [status, msg] = rm_rf (getdir (desc));
       if (status != 1)
- error ("couldn't delete directory %s: %s", desc.dir, msg);
+ error ("couldn't delete directory %s: %s", getdir (desc), msg);
       endif
       [status, msg] = rm_rf (getarchdir (desc));
       if (status != 1)
@@ -936,7 +950,7 @@
  rm_rf (desc.archprefix);
       endif
     else
-      warning ("directory %s previously lost", desc.dir);
+      warning ("directory %s previously lost", getdir (desc));
     endif
   endfor
 
@@ -995,7 +1009,7 @@
       pkg_desc_list{name_pos}.name = installed_pkgs_lst{i}.name;
       pkg_desc_list{name_pos}.version = installed_pkgs_lst{i}.version;
       pkg_desc_list{name_pos}.description = installed_pkgs_lst{i}.description;
-      pkg_desc_list{name_pos}.provides = parse_pkg_idx (installed_pkgs_lst{i}.dir);
+      pkg_desc_list{name_pos}.provides = parse_pkg_idx (getdir (installed_pkgs_lst{i}));
 
     endif
   endfor
@@ -1207,7 +1221,7 @@
   if (! exist (inst_dir, "dir"))
     [status, msg] = mkdir (inst_dir);
     if (status != 1)
-      rm_rf (desc.dir);
+      rm_rf (getdir (desc));
       error ("the 'inst' directory did not exist and could not be created: %s",
      msg);
     endif
@@ -1236,9 +1250,9 @@
       flags = strcat( flags, " LDFLAGS=-L\"", fullfile(OCTAVE_HOME,"lib"), "\"" );
       flags = strcat( flags, " CPPFLAGS=-I\"", fullfile(OCTAVE_HOME,"include"), "\"" );
       [status, output] = shell (strcat ("cd '", src, "'; ./configure --prefix=\"",
-                                        desc.dir, "\"", flags));
+                                        getdir (desc), "\"", flags));
       if (status != 0)
- rm_rf (desc.dir);
+ rm_rf (getdir (desc));
  error ("the configure script returned the following error: %s", output);
       elseif (verbose)
  printf("%s", output);
@@ -1248,10 +1262,10 @@
 
     ## Make.
     if (exist (fullfile (src, "Makefile"), "file"))
-      [status, output] = shell (cstrcat ("export INSTALLDIR=\"", desc.dir,
+      [status, output] = shell (cstrcat ("export INSTALLDIR=\"", getdir (desc),
  "\"; make -C '", src, "'"));
       if (status != 0)
- rm_rf (desc.dir);
+ rm_rf (getdir (desc));
  error ("'make' returned the following error: %s", output);
       elseif (verbose)
  printf("%s", output);
@@ -1317,7 +1331,7 @@
   endif
   [status, output] = copyfile (archindependent, instdir);
   if (status != 1)
-    rm_rf (desc.dir);
+    rm_rf (getdir (desc));
     error ("Couldn't copy files from 'src' to 'inst': %s", output);
   endif
         endif
@@ -1332,7 +1346,7 @@
   endif
   [status, output] = copyfile (archdependent, archdir);
   if (status != 1)
-    rm_rf (desc.dir);
+    rm_rf (getdir (desc));
     error ("Couldn't copy files from 'src' to 'inst': %s", output);
   endif
         endif
@@ -1361,7 +1375,7 @@
 endfunction
 
 function create_pkgadddel (desc, packdir, nm, global_install)
-  instpkg = fullfile (desc.dir, nm);
+  instpkg = fullfile (getdir (desc), nm);
   instfid = fopen (instpkg, "wt");
   ## If it is exists, most of the  PKG_* file should go into the
   ## architecture dependent directory so that the autoload/mfilename
@@ -1427,11 +1441,11 @@
 
 function copy_files (desc, packdir, global_install)
   ## Create the installation directory.
-  if (! exist (desc.dir, "dir"))
-    [status, output] = mkdir (desc.dir);
+  if (! exist (getdir (desc), "dir"))
+    [status, output] = mkdir (getdir (desc));
     if (status != 1)
       error ("couldn't create installation directory %s : %s",
-      desc.dir, output);
+      getdir (desc), output);
     endif
   endif
 
@@ -1440,13 +1454,13 @@
   ## Copy the files from "inst" to installdir.
   instdir = fullfile (packdir, "inst");
   if (! dirempty (instdir))
-    [status, output] = copyfile (fullfile (instdir, "*"), desc.dir);
+    [status, output] = copyfile (fullfile (instdir, "*"), getdir (desc));
     if (status != 1)
-      rm_rf (desc.dir);
+      rm_rf (getdir (desc));
       error ("couldn't copy files to the installation directory");
     endif
-    if (exist (fullfile (desc.dir, getarch ()), "dir") &&
- ! strcmp (fullfile (desc.dir, getarch ()), octfiledir))
+    if (exist (fullfile (getdir (desc), getarch ()), "dir") &&
+ ! strcmp (fullfile (getdir (desc), getarch ()), octfiledir))
       if (! exist (octfiledir, "dir"))
         ## Can be required to create upto three levels of dirs.
         octm1 = fileparts (octfiledir);
@@ -1457,38 +1471,38 @@
             if (! exist (octm3, "dir"))
               [status, output] = mkdir (octm3);
               if (status != 1)
-                rm_rf (desc.dir);
+                rm_rf (getdir (desc));
                 error ("couldn't create installation directory %s : %s",
                        octm3, output);
               endif
             endif
             [status, output] = mkdir (octm2);
             if (status != 1)
-              rm_rf (desc.dir);
+              rm_rf (getdir (desc));
               error ("couldn't create installation directory %s : %s",
                      octm2, output);
             endif
           endif
           [status, output] = mkdir (octm1);
           if (status != 1)
-            rm_rf (desc.dir);
+            rm_rf (getdir (desc));
             error ("couldn't create installation directory %s : %s",
                    octm1, output);
           endif
         endif
         [status, output] = mkdir (octfiledir);
         if (status != 1)
-          rm_rf (desc.dir);
+          rm_rf (getdir (desc));
           error ("couldn't create installation directory %s : %s",
           octfiledir, output);
         endif
       endif
-      [status, output] = movefile (fullfile (desc.dir, getarch (), "*"),
+      [status, output] = movefile (fullfile (getdir (desc), getarch (), "*"),
    octfiledir);
-      rm_rf (fullfile (desc.dir, getarch ()));
+      rm_rf (fullfile (getdir (desc), getarch ()));
 
       if (status != 1)
-        rm_rf (desc.dir);
+        rm_rf (getdir (desc));
         rm_rf (octfiledir);
         error ("couldn't copy files to the installation directory");
       endif
@@ -1497,10 +1511,10 @@
   endif
 
   ## Create the "packinfo" directory.
-  packinfo = fullfile (desc.dir, "packinfo");
+  packinfo = fullfile (getdir (desc), "packinfo");
   [status, msg] = mkdir (packinfo);
   if (status != 1)
-    rm_rf (desc.dir);
+    rm_rf (getdir (desc));
     rm_rf (octfiledir);
     error ("couldn't create packinfo directory: %s", msg);
   endif
@@ -1508,7 +1522,7 @@
   ## Copy DESCRIPTION.
   [status, output] = copyfile (fullfile (packdir, "DESCRIPTION"), packinfo);
   if (status != 1)
-    rm_rf (desc.dir);
+    rm_rf (getdir (desc));
     rm_rf (octfiledir);
     error ("couldn't copy DESCRIPTION: %s", output);
   endif
@@ -1516,7 +1530,7 @@
   ## Copy COPYING.
   [status, output] = copyfile (fullfile (packdir, "COPYING"), packinfo);
   if (status != 1)
-    rm_rf (desc.dir);
+    rm_rf (getdir (desc));
     rm_rf (octfiledir);
     error ("couldn't copy COPYING: %s", output);
   endif
@@ -1526,7 +1540,7 @@
   if (exist (changelog_file, "file"))
     [status, output] = copyfile (changelog_file, packinfo);
     if (status != 1)
-      rm_rf (desc.dir);
+      rm_rf (getdir (desc));
       rm_rf (octfiledir);
       error ("couldn't copy ChangeLog file: %s", output);
     endif
@@ -1537,7 +1551,7 @@
   if (exist(index_file, "file"))
     [status, output] = copyfile (index_file, packinfo);
     if (status != 1)
-      rm_rf (desc.dir);
+      rm_rf (getdir (desc));
       rm_rf (octfiledir);
       error ("couldn't copy INDEX file: %s", output);
     endif
@@ -1546,7 +1560,7 @@
       write_index (desc, fullfile (packdir, "inst"),
    fullfile (packinfo, "INDEX"), global_install);
     catch
-      rm_rf (desc.dir);
+      rm_rf (getdir (desc));
       rm_rf (octfiledir);
       rethrow (lasterror ());
     end_try_catch
@@ -1557,7 +1571,7 @@
   if (exist (fon_uninstall, "file"))
     [status, output] = copyfile (fon_uninstall, packinfo);
     if (status != 1)
-      rm_rf (desc.dir);
+      rm_rf (getdir (desc));
       rm_rf (octfiledir);
       error ("couldn't copy on_uninstall.m: %s", output);
     endif
@@ -1566,14 +1580,14 @@
   ## Is there a doc/ directory that needs to be installed?
   docdir = fullfile (packdir, "doc");
   if (exist (docdir, "dir") && ! dirempty (docdir))
-    [status, output] = copyfile (docdir, desc.dir);
+    [status, output] = copyfile (docdir, getdir (desc));
   endif
 
   ## Is there a bin/ directory that needs to be installed?
   ## FIXME: Need to treat architecture dependent files in bin/
   bindir = fullfile (packdir, "bin");
   if (exist (bindir, "dir") && ! dirempty (bindir))
-    [status, output] = copyfile (bindir, desc.dir);
+    [status, output] = copyfile (bindir, getdir (desc));
   endif
 endfunction
 
@@ -1587,7 +1601,7 @@
       cd (wd);
     catch
       cd (wd);
-      rm_rf (desc.dir);
+      rm_rf (getdir (desc));
       rm_rf (getarchdir (desc), global_install);
       rethrow (lasterror ());
     end_try_catch
@@ -1595,7 +1609,7 @@
 endfunction
 
 function generate_lookfor_cache (desc)
-  dirs = split_by (genpath (desc.dir), pathsep ());
+  dirs = split_by (genpath (getdir (desc)), pathsep ());
   for i = 1 : length (dirs)
     gen_doc_cache (fullfile (dirs{i}, "doc-cache"), dirs{i});
   endfor
@@ -1880,21 +1894,21 @@
   ## Now check if the package is loaded.
   tmppath = strrep (path(), "\\", "/");
   for i = 1:length (installed_pkgs_lst)
-    if (findstr (tmppath, strrep (installed_pkgs_lst{i}.dir, "\\", "/")))
+    if (findstr (tmppath, strrep (getdir (installed_pkgs_lst{i}), "\\", "/")))
       installed_pkgs_lst{i}.loaded = true;
     else
       installed_pkgs_lst{i}.loaded = false;
     endif
   endfor
   for i = 1:length (local_packages)
-    if (findstr (tmppath, strrep (local_packages{i}.dir, "\\", "/")))
+    if (findstr (tmppath, strrep (getdir (local_packages{i}), "\\", "/")))
       local_packages{i}.loaded = true;
     else
       local_packages{i}.loaded = false;
     endif
   endfor
   for i = 1:length (global_packages)
-    if (findstr (tmppath, strrep (global_packages{i}.dir, "\\", "/")))
+    if (findstr (tmppath, strrep (getdir (global_packages{i}), "\\", "/")))
       global_packages{i}.loaded = true;
     else
       global_packages{i}.loaded = false;
@@ -1956,7 +1970,7 @@
   for i = 1:num_packages
     cur_name = installed_pkgs_lst{idx(i)}.name;
     cur_version = installed_pkgs_lst{idx(i)}.version;
-    cur_dir = installed_pkgs_lst{idx(i)}.dir;
+    cur_dir = getdir (installed_pkgs_lst{idx(i)});
     if (length (cur_dir) > max_dir_length)
       first_char = length (cur_dir) - max_dir_length + 4;
       first_filesep = strfind (cur_dir(first_char:end), filesep());
@@ -1984,7 +1998,7 @@
   pnames = pdirs = cell (1, num_packages);
   for i = 1:num_packages
     pnames{i} = installed_pkgs_lst{i}.name;
-    pdirs{i} = installed_pkgs_lst{i}.dir;
+    pdirs{i} = getdir (installed_pkgs_lst{i});
   endfor
 
   ## Load all.
@@ -2022,7 +2036,7 @@
   pnames = pdirs = cell (1, num_packages);
   for i = 1:num_packages
     pnames{i} = installed_pkgs_lst{i}.name;
-    pdirs{i} = installed_pkgs_lst{i}.dir;
+    pdirs{i} = getdir (installed_pkgs_lst{i});
     pdeps{i} = installed_pkgs_lst{i}.depends;
   endfor
 
@@ -2135,7 +2149,15 @@
 endfunction
 
 function archdir = getarchdir (desc)
-  archdir = fullfile (desc.archprefix, getarch());
+  archdir = fullfile (getarchprefix (desc), getarch());
+endfunction
+
+function d = getdir (desc)
+  if (isfield (desc, "dir_is_relative") && desc.dir_is_relative)
+     d = fullfile (OCTAVE_HOME(), "share", "octave", "packages", desc.dir);
+  else
+     d = desc.dir;
+  endif
 endfunction
 
 function s = issuperuser ()
@@ -2210,7 +2232,7 @@
   dirs = {};
   execpath = EXEC_PATH ();
   for i = idx;
-    ndir = installed_pkgs_lst{i}.dir;
+    ndir = getdir (installed_pkgs_lst{i});
     dirs{end+1} = ndir;
     if (exist (fullfile (dirs{end}, "bin"), "dir"))
       execpath = cstrcat (fullfile (dirs{end}, "bin"), ":", execpath);