changeset 19221:b54093acb8fe

ver.m: Overhaul function. Add ability to call "ver PKG_NAME". Add ability to call "pkg list PKG_NAME". * ver.m: Redo docstring. Rename output variable to retval rather than unnecessary use of varargout. Add ability to call "ver PKG_NAME" by passing PKG_NAME to 'pkg list' command. * pkg.m: Redo docstring for 'list' to explain new ability to supply a PKG_NAME. Use numel() rather than length() for clarity. Use isempty() rather than length() == 0 for clarity. * installed_packages.m: Add additional input argument pkgname. Use unique() rather than double for loop to uniquify package list. Add code to report only on package pkgname if given. Use numel() rather than length() for clarity. Replace for loops with cellfun calls to determine max length of string entries. * version.m: Add seealso reference to ver in docstring.
author Rik <rik@octave.org>
date Tue, 30 Sep 2014 08:29:16 -0700
parents 1111d2d5ff95
children c3611856cdd4
files scripts/miscellaneous/ver.m scripts/miscellaneous/version.m scripts/pkg/pkg.m scripts/pkg/private/installed_packages.m
diffstat 4 files changed, 170 insertions(+), 162 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/miscellaneous/ver.m	Mon Sep 29 19:52:14 2014 +0100
+++ b/scripts/miscellaneous/ver.m	Tue Sep 30 08:29:16 2014 -0700
@@ -17,19 +17,21 @@
 ## <http://www.gnu.org/licenses/>.
 
 ## -*- texinfo -*-
-## @deftypefn  {Function File} {} ver ()
-## @deftypefnx {Function File} {v =} ver ()
-## @deftypefnx {Function File} {v =} ver ("Octave")
-## @deftypefnx {Function File} {v =} ver (@var{package})
+## @deftypefn  {Function File} {} ver
+## @deftypefnx {Function File} {} ver Octave
+## @deftypefnx {Function File} {} ver @var{package}
+## @deftypefnx {Function File} {v =} ver (@dots{})
 ## 
 ## Display a header containing the current Octave version number, license
-## string, and operating system followed by a list of installed packages,
-## versions, and installation directories.
+## string, and operating system.  The header is followed by a list of installed
+## packages, versions, and installation directories.
 ##
-## @code{v = ver ()}
+## Use the package name @var{package} or Octave to limit the listing to a
+## desired component.
 ##
-## Return a vector of structures describing Octave and each installed package.
-## The structure includes the following fields.
+## When called with an output argument, return a vector of structures
+## describing Octave and each installed package.  The structure includes the
+## following fields.
 ##
 ## @table @code
 ## @item Name
@@ -45,71 +47,67 @@
 ## Date of the version/revision.
 ## @end table
 ##
-## @code{v = ver ("Octave")}
-##
-## Return version information for Octave only.
-##
-## @code{v = ver (@var{package})}
-##
-## Return version information for @var{package}.
-##
-## @seealso{version, octave_config_info}
+## @seealso{version, octave_config_info, pkg}
 ## @end deftypefn
 
 ## Author: William Poetra Yoga Hadisoeseno <williampoetra@gmail.com>
 
-function varargout = ver (package = "")
+function retval = ver (package = "")
 
   if (nargin > 1)
     print_usage ();
   endif
 
-  ## Start with the version info for Octave
-  ret = struct ("Name", "Octave", "Version", version,
-                "Release", [], "Date", []);
+  if (nargout == 0)
+    [unm, err] = uname ();
 
-  ## Add the installed packages
-  lst = pkg ("list");
-  for i = 1:length (lst)
-    ret(end+1) = struct ("Name", lst{i}.name, "Version", lst{i}.version,
-                         "Release", [], "Date", lst{i}.date);
-  endfor
-
-  if (nargout == 0)
-    octave_license = license ();
-
-    [unm, status] = uname ();
-
-    if (status < 0)
+    if (err)
       os_string = "unknown";
     else
-      os_string = sprintf ("%s %s %s %s", unm.sysname, unm.release,
-                           unm.version, unm.machine);
+      os_string = sprintf ("%s %s %s %s",
+                           unm.sysname, unm.release, unm.version, unm.machine);
     endif
 
     hbar(1:70) = "-";
-    ver_line1 = "GNU Octave Version ";
-    ver_line2 = "GNU Octave License: ";
-    ver_line3 = "Operating System: ";
+    desc = {hbar
+            ["GNU Octave Version: " OCTAVE_VERSION]
+            ["GNU Octave License: " license]
+            ["Operating System: " os_string]
+            hbar};
+
+    printf ("%s\n", desc{:});
 
-    ver_desc = sprintf ("%s\n%s%s\n%s%s\n%s%s\n%s\n", hbar, ver_line1, version,
-                        ver_line2, octave_license, ver_line3, os_string, hbar);
-
-    puts (ver_desc);
-
-    pkg ("list");
+    if (isempty (package))
+      pkg ("list");
+    elseif (strcmpi (package, "Octave"))
+      ## Nothing to do, Octave version was already reported
+    else
+      pkg ("list", package);
+    endif
   else
-    if (! isempty (package))
-      n = [];
-      for r = 1:numel (ret)
-        if (strcmpi (ret(r).Name, package))
-          n = r;
-          break;
-        endif
+    ## Get the installed packages
+    if (isempty (package))
+      lst = pkg ("list");
+      ## Start with the version info for Octave
+      retval = struct ("Name", "Octave", "Version", version,
+                       "Release", [], "Date", []);
+      for i = 1:numel (lst)
+        retval(end+1) = struct ("Name", lst{i}.name, "Version", lst{i}.version,
+                                "Release", [], "Date", lst{i}.date);
       endfor
-      ret = ret(n);
+    elseif (strcmpi (package, "Octave"))
+      retval = struct ("Name", "Octave", "Version", version,
+                       "Release", [], "Date", []);
+    else 
+      lst = pkg ("list", package);
+      if (isempty (lst))
+        retval = struct ("Name", "", "Version", [],
+                         "Release", [], "Date", []);
+      else
+        retval = struct ("Name", lst{1}.name, "Version", lst{1}.version,
+                         "Release", [], "Date", lst{1}.date);
+      endif
     endif
-    varargout{1} = ret;
   endif
 
 endfunction
--- a/scripts/miscellaneous/version.m	Mon Sep 29 19:52:14 2014 +0100
+++ b/scripts/miscellaneous/version.m	Tue Sep 30 08:29:16 2014 -0700
@@ -18,11 +18,11 @@
 
 ## -*- texinfo -*-
 ## @deftypefn {Function File} {} version ()
-## Return the version number of Octave, as a string.
+## Return the version number of Octave as a string.
 ##
 ## This is an alias for the function @w{@env{OCTAVE_VERSION}} provided for
 ## compatibility.
-## @seealso{OCTAVE_VERSION}
+## @seealso{OCTAVE_VERSION, ver}
 ## @end deftypefn
 
 ## Author: jwe
--- a/scripts/pkg/pkg.m	Mon Sep 29 19:52:14 2014 +0100
+++ b/scripts/pkg/pkg.m	Tue Sep 30 08:29:16 2014 -0700
@@ -21,8 +21,9 @@
 ## -*- texinfo -*-
 ## @deftypefn  {Command} {} pkg @var{command} @var{pkg_name}
 ## @deftypefnx {Command} {} pkg @var{command} @var{option} @var{pkg_name}
-## Manage packages (groups of add-on functions) for Octave.  Different actions
-## are available depending on the value of @var{command}.
+## Manage packages (groups of add-on functions) for Octave.
+##
+## Different actions are available depending on the value of @var{command}.
 ##
 ## Available commands:
 ##
@@ -123,11 +124,25 @@
 ## Show the list of currently installed packages.  For example,
 ##
 ## @example
-## installed_packages = pkg ("list")
+## pkg list
 ## @end example
 ##
 ## @noindent
-## returns a cell array containing a structure for each installed package.
+## will produce a short report with the package name, version, and installation
+## directory for each installed package.  Supply a package name to limit 
+## reporting to a particular package.  For example:
+##
+## @example
+## pkg list image
+## @end example
+##
+## If a single return argument is requested then @code{pkg} returns a cell
+## array where each element is a structure with information on a single
+## package.
+##
+## @example
+## installed_packages = pkg ("list")
+## @end example
 ##
 ## If two output arguments are requested @code{pkg} splits the list of
 ## installed packages into those which were installed by the current user,
@@ -137,7 +152,7 @@
 ## [user_packages, system_packages] = pkg ("list")
 ## @end example
 ##
-## The option @qcode{"-forge"} lists packages available at the Octave-Forge
+## The @qcode{"-forge"} option lists packages available at the Octave-Forge
 ## repository.  This requires an internet connection and the cURL library. 
 ## For example:
 ##
@@ -164,7 +179,7 @@
 ## @end example
 ##
 ## @noindent
-## If any of the requested packages is not installed, pkg returns an
+## If any of the requested packages is not installed, @code{pkg} returns an
 ## error, unless a second output is requested:
 ##
 ## @example
@@ -263,6 +278,7 @@
 ## @end deftypefn
 
 function [local_packages, global_packages] = pkg (varargin)
+
   ## Installation prefix (FIXME: what should these be on windows?)
   persistent user_prefix = false;
   persistent prefix = false;
@@ -271,10 +287,6 @@
   persistent global_list = fullfile (OCTAVE_HOME (), "share", "octave",
                                      "octave_packages");
 
-  confirm_recursive_rmdir (false, "local");
-
-  mlock ();
-
   ## If user is superuser set global_istall to true
   ## FIXME: is it OK to set this always true on windows?
   global_install = ((ispc () && ! isunix ()) || (geteuid () == 0));
@@ -285,12 +297,17 @@
     archprefix = tilde_expand (archprefix);
   endif
 
+  mlock ();
+
+  confirm_recursive_rmdir (false, "local");
+
   available_actions = {"list", "install", "uninstall", "load", ...
                        "unload", "prefix", "local_list", ...
                        "global_list", "rebuild", "build", ...
                        "describe", "update"};
-  ## Handle input
-  if (length (varargin) == 0 || ! iscellstr (varargin))
+
+  ## Parse input arguments
+  if (isempty (varargin) || ! iscellstr (varargin))
     print_usage ();
   endif
   files = {};
@@ -299,7 +316,7 @@
   action = "none";
   verbose = false;
   octave_forge = false;
-  for i = 1:length (varargin)
+  for i = 1:numel (varargin)
     switch (varargin{i})
       case "-nodeps"
         deps = false;
@@ -327,11 +344,10 @@
           [prefix, archprefix] = default_prefix (global_install);
         endif
       case available_actions
-        if (strcmp (action, "none"))
-          action = varargin{i};
-        else
+        if (! strcmp (action, "none"))
           error ("more than one action specified");
         endif
+        action = varargin{i};
       otherwise
         files{end+1} = varargin{i};
     endswitch
@@ -352,19 +368,20 @@
         endif
       else
         if (nargout == 0)
-          installed_packages (local_list, global_list);
+          installed_packages (local_list, global_list, files);
         elseif (nargout == 1)
-          local_packages = installed_packages (local_list, global_list);
+          local_packages = installed_packages (local_list, global_list, files);
         elseif (nargout == 2)
           [local_packages, global_packages] = installed_packages (local_list,
-                                                                  global_list);
+                                                                  global_list,
+                                                                  files);
         else
           error ("too many output arguments requested");
         endif
       endif
 
     case "install"
-      if (length (files) == 0)
+      if (isempty (files))
         error ("you must specify at least one filename when calling 'pkg install'");
       endif
 
@@ -389,48 +406,47 @@
       end_unwind_protect
 
     case "uninstall"
-      if (length (files) == 0)
+      if (isempty (files))
         error ("you must specify at least one package when calling 'pkg uninstall'");
       endif
-      uninstall (files, deps, verbose, local_list,
-                 global_list, global_install);
+      uninstall (files, deps, verbose, local_list, global_list, global_install);
 
     case "load"
-      if (length (files) == 0)
-        error ("you must specify at least one package, 'all' or 'auto' when calling 'pkg load'");
+      if (isempty (files))
+        error ("you must specify at least one package, 'all', or 'auto' when calling 'pkg load'");
       endif
       load_packages (files, deps, local_list, global_list);
 
     case "unload"
-      if (length (files) == 0)
+      if (isempty (files))
         error ("you must specify at least one package or 'all' when calling 'pkg unload'");
       endif
       unload_packages (files, deps, local_list, global_list);
 
     case "prefix"
-      if (length (files) == 0 && nargout == 0)
+      if (isempty (files) && nargout == 0)
         printf ("Installation prefix:             %s\n", prefix);
         printf ("Architecture dependent prefix:   %s\n", archprefix);
-      elseif (length (files) == 0 && nargout >= 1)
+      elseif (isempty (files) && nargout >= 1)
         local_packages = prefix;
         global_packages = archprefix;
-      elseif (length (files) >= 1 && nargout <= 2 && ischar (files{1}))
+      elseif (numel (files) >= 1 && nargout <= 2 && ischar (files{1}))
         prefix = tilde_expand (files{1});
         if (! exist (prefix, "dir"))
-          [status, msg, msgid] = mkdir (prefix);
+          [status, msg] = mkdir (prefix);
           if (status == 0)
-            error("cannot create prefix %s: %s", prefix, msg);
+            error ("cannot create prefix %s: %s", prefix, msg);
           endif
           warning ("creating the directory %s\n", prefix);
         endif
         local_packages = prefix = canonicalize_file_name (prefix);
         user_prefix = true;
-        if (length (files) >= 2 && ischar (files{2}))
+        if (numel (files) >= 2 && ischar (files{2}))
           archprefix = tilde_expand (files{2});
           if (! exist (archprefix, "dir"))
-            [status, msg, msgid] = mkdir (archprefix);
+            [status, msg] = mkdir (archprefix);
             if (status == 0)
-              error("cannot create archprefix %s: %s", archprefix, msg);
+              error ("cannot create archprefix %s: %s", archprefix, msg);
             endif
             warning ("creating the directory %s\n", archprefix);
             global_packages = archprefix = canonicalize_file_name (archprefix);
@@ -441,11 +457,11 @@
       endif
       
     case "local_list"
-      if (length (files) == 0 && nargout == 0)
+      if (isempty (files) && nargout == 0)
         disp (local_list);
-      elseif (length (files) == 0 && nargout == 1)
+      elseif (isempty (files) && nargout == 1)
         local_packages = local_list;
-      elseif (length (files) == 1 && nargout == 0 && ischar (files{1}))
+      elseif (numel (files) == 1 && nargout == 0 && ischar (files{1}))
         local_list = files{1};
         if (! exist (local_list, "file"))          
           try
@@ -461,11 +477,11 @@
       endif
 
     case "global_list"
-      if (length (files) == 0 && nargout == 0)
-        disp(global_list);
-      elseif (length (files) == 0 && nargout == 1)
+      if (isempty (files) && nargout == 0)
+        disp (global_list);
+      elseif (isempty (files) && nargout == 1)
         local_packages = global_list;
-      elseif (length (files) == 1 && nargout == 0 && ischar (files{1}))
+      elseif (numel (files) == 1 && nargout == 0 && ischar (files{1}))
         global_list = files{1};
         if (! exist (global_list, "file"))  
           try
@@ -490,8 +506,8 @@
           local_packages = global_packages;
         endif
       else
-        local_packages = rebuild (prefix, archprefix, local_list, files, auto,
-                                  verbose);
+        local_packages = rebuild (prefix, archprefix, local_list, files,
+                                  auto, verbose);
         local_packages = save_order (local_packages);
         save (local_list, "local_packages");
         if (nargout == 0)
@@ -500,23 +516,21 @@
       endif
 
     case "build"
-      if (length (files) < 2)
+      if (numel (files) < 2)
         error ("you must specify at least the build directory and one filename\nwhen calling 'pkg build'");
       endif
       build (files, deps, auto, verbose);
 
     case "describe"
-      if (length (files) == 0)
+      if (isempty (files))
         error ("you must specify at least one package or 'all' when calling 'pkg describe'");
       endif
-      ## FIXME: the name of the output variables is inconsistent
-      ##            with their content
+      ## FIXME: name of the output variables is inconsistent with their content
       switch (nargout)
         case 0
           describe (files, verbose, local_list, global_list);
         case 1
-          pkg_desc_list = describe (files, verbose, local_list, ...
-                                    global_list);
+          pkg_desc_list = describe (files, verbose, local_list, global_list);
           local_packages = pkg_desc_list;
         case 2
           [pkg_desc_list, flag] = describe (files, verbose, local_list, ...
@@ -530,24 +544,20 @@
     case "update"
       if (nargout == 0)
         installed_pkgs_lst = installed_packages (local_list, global_list);
-        if (length (files) > 0)
+        if (numel (files) > 0)
            update_lst = {}; 
-           for i = 1:length (files)
-             is_installed = false;
-             for j = 1:length (installed_pkgs_lst)
-               if (strcmp (files{i}, installed_pkgs_lst{j}.name))
-                 update_lst = { update_lst{:}, installed_pkgs_lst{j} };
-                 is_installed = true;
-               endif
-             endfor
-             if (is_installed == false)
-               s = sprintf ("Package %s is not installed - not updating this package", files{i});
-               warning (s);
+           installed_names = {installed_pkgs_list.name}';
+           for i = 1:numel (files)
+             idx = find (strcmp (files{i}, installed_names), 1);
+             if (isempty (idx))
+               warning ("Package %s is not installed - not updating this package", files{i});
+             else
+               update_lst = { update_lst, installed_pkgs_lst{idx} };
              endif
            endfor
            installed_pkgs_lst = update_lst;
         endif
-        for i = 1:length (installed_pkgs_lst)
+        for i = 1:numel (installed_pkgs_lst)
           installed_pkg_name = installed_pkgs_lst{i}.name;
           installed_pkg_version = installed_pkgs_lst{i}.version;
           forge_pkg_version = get_forge_pkg (installed_pkg_name);
@@ -560,7 +570,8 @@
       endif
 
     otherwise
-      error ("you must specify a valid action for 'pkg'. See 'help pkg' for details");
+      error ("you must specify a valid action for 'pkg'.  See 'help pkg' for details");
   endswitch
+
 endfunction
 
--- a/scripts/pkg/private/installed_packages.m	Mon Sep 29 19:52:14 2014 +0100
+++ b/scripts/pkg/private/installed_packages.m	Tue Sep 30 08:29:16 2014 -0700
@@ -22,7 +22,8 @@
 ## Undocumented internal function.
 ## @end deftypefn
 
-function [out1, out2] = installed_packages (local_list, global_list)
+function [out1, out2] = installed_packages (local_list, global_list, pkgname = {})
+
   ## Get the list of installed packages.
   try
     local_packages = load (local_list).local_packages;
@@ -38,41 +39,42 @@
 
   ## Eliminate duplicates in the installed package list.
   ## Locally installed packages take precedence.
-  dup = [];
-  for i = 1:length (installed_pkgs_lst)
-    if (any (dup == i))
-      continue;
+  installed_names = cellfun (@(x) x.name, installed_pkgs_lst,
+                             "uniformoutput", false);
+  [~, idx] = unique (installed_names, "first");
+  installed_names = installed_names(idx);
+  installed_pkgs_lst = installed_pkgs_lst(idx);
+
+  ## Check whether info on a particular package was requested
+  if (! isempty (pkgname))
+    idx = find (strcmp (pkgname{1}, installed_names));
+    if (isempty (idx))
+      installed_names = {};
+      installed_pkgs_lst = {};
+    else
+      installed_names = installed_names(idx);
+      installed_pkgs_lst = installed_pkgs_lst(idx);
     endif
-    for j = (i+1):length (installed_pkgs_lst)
-      if (any (dup == j))
-        continue;
-      endif
-      if (strcmp (installed_pkgs_lst{i}.name, installed_pkgs_lst{j}.name))
-        dup = [dup, j];
-      endif
-    endfor
-  endfor
-  if (! isempty (dup))
-    installed_pkgs_lst(dup) = [];
   endif
 
   ## Now check if the package is loaded.
+  ## FIXME: couldn't dir_in_loadpath() be used here?
   tmppath = strrep (path (), "\\", "/");
-  for i = 1:length (installed_pkgs_lst)
+  for i = 1:numel (installed_pkgs_lst)
     if (strfind (tmppath, strrep (installed_pkgs_lst{i}.dir, '\', '/')))
       installed_pkgs_lst{i}.loaded = true;
     else
       installed_pkgs_lst{i}.loaded = false;
     endif
   endfor
-  for i = 1:length (local_packages)
+  for i = 1:numel (local_packages)
     if (strfind (tmppath, strrep (local_packages{i}.dir, '\', '/')))
       local_packages{i}.loaded = true;
     else
       local_packages{i}.loaded = false;
     endif
   endfor
-  for i = 1:length (global_packages)
+  for i = 1:numel (global_packages)
     if (strfind (tmppath, strrep (global_packages{i}.dir, '\', '/')))
       global_packages{i}.loaded = true;
     else
@@ -90,10 +92,14 @@
     return;
   endif
 
-  ## We shouldn't return something, so we'll print something.
-  num_packages = length (installed_pkgs_lst);
+  ## Don't return anything, instead we'll print something.
+  num_packages = numel (installed_pkgs_lst);
   if (num_packages == 0)
-    printf ("no packages installed.\n");
+    if (isempty (pkgname))
+      printf ("no packages installed.\n");
+    else
+      printf ("package %s is not installed.\n", pkgname{1});
+    endif
     return;
   endif
 
@@ -101,20 +107,13 @@
   h1 = "Package Name";
   h2 = "Version";
   h3 = "Installation directory";
-  max_name_length = length (h1);
-  max_version_length = length (h2);
-  names = cell (num_packages, 1);
-  for i = 1:num_packages
-    max_name_length = max (max_name_length,
-                           length (installed_pkgs_lst{i}.name));
-    max_version_length = max (max_version_length,
-                              length (installed_pkgs_lst{i}.version));
-    names{i} = installed_pkgs_lst{i}.name;
-  endfor
-  max_dir_length = terminal_size ()(2) - max_name_length - ...
-                                             max_version_length - 7;
+  max_name_length = max ([length(h1), cellfun(@length, installed_names)]);
+  version_lengths = cellfun (@(x) length (x.version), installed_pkgs_lst); 
+  max_version_length = max ([length(h2), version_lengths]);
+  ncols = terminal_size ()(2);
+  max_dir_length = ncols - max_name_length - max_version_length - 7;
   if (max_dir_length < 20)
-     max_dir_length = Inf;
+    max_dir_length = Inf;
   endif
 
   h1 = postpad (h1, max_name_length + 1, " ");
@@ -129,13 +128,12 @@
   printf ("%s\n", tmp);
 
   ## Print the packages.
-  format = sprintf ("%%%ds %%1s| %%%ds | %%s\n", max_name_length,
-                    max_version_length);
-  [dummy, idx] = sort (names);
+  format = sprintf ("%%%ds %%1s| %%%ds | %%s\n",
+                    max_name_length, max_version_length);
   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_name = installed_pkgs_lst{i}.name;
+    cur_version = installed_pkgs_lst{i}.version;
+    cur_dir = installed_pkgs_lst{i}.dir;
     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 ());
@@ -145,12 +143,13 @@
         cur_dir = ["..." cur_dir(first_char:end)];
       endif
     endif
-    if (installed_pkgs_lst{idx(i)}.loaded)
+    if (installed_pkgs_lst{i}.loaded)
       cur_loaded = "*";
     else
       cur_loaded = " ";
     endif
     printf (format, cur_name, cur_loaded, cur_version, cur_dir);
   endfor
+
 endfunction