# HG changeset patch # User Carnë Draug # Date 1411946972 -3600 # Node ID 6dfce51a7b405a6b98d84018e8769218f74155ec # Parent 4871d0ecbfa74c5b9a6bddbb8c631e5133c4b96f license.m: update to treat packages as features (bug #43154). * miscellaneous/license.m: this function was originally written when the only feature was a monolithic installation of Octave Forge. This cset updates it to treat packages as features. It also disables the TOOGLE option which does not make any sense in the context of free software. diff -r 4871d0ecbfa7 -r 6dfce51a7b40 scripts/miscellaneous/license.m --- a/scripts/miscellaneous/license.m Fri Oct 03 07:35:20 2014 -0400 +++ b/scripts/miscellaneous/license.m Mon Sep 29 00:29:32 2014 +0100 @@ -1,4 +1,5 @@ ## Copyright (C) 2005-2013 William Poetra Yoga Hadisoeseno +## Copyright (C) 2014 Carnë Draug ## ## This file is part of Octave. ## @@ -18,181 +19,173 @@ ## -*- texinfo -*- ## @deftypefn {Command} {} license +## @deftypefnx {Command} {} license inuse +## @deftypefnx {Command} {} license inuse @var{feature} ## @deftypefnx {Function File} {} license ("inuse") ## @deftypefnx {Function File} {@var{retval} =} license ("inuse") ## @deftypefnx {Function File} {@var{retval} =} license ("test", @var{feature}) -## @deftypefnx {Function File} {} license ("test", @var{feature}, @var{toggle}) ## @deftypefnx {Function File} {@var{retval} =} license ("checkout", @var{feature}) -## -## Display the license of Octave. -## -## @code{license ("inuse")} -## -## Display a list of packages currently being used. -## -## @code{@var{retval} = license ("inuse")} +## @deftypefnx {Function File} {[@var{retval}, @var{errmsg}] =} license ("checkout", @var{feature}) +## Get license information for Octave and Octave packages. ## -## Return a structure containing the fields @code{feature} and @code{user}. -## -## @code{@var{retval} = license ("test", @var{feature})} +## GNU Octave is free software distributed under the GNU General Public +## License (GPL), and a license manager makes no sense. This function is +## provided only for @sc{Matlab} compatibility. ## -## Return 1 if a license exists for the product identified by the string -## @var{feature} and 0 otherwise. The argument @var{feature} is case -## insensitive and only the first 27 characters are checked. -## -## @code{license ("test", @var{feature}, @var{toggle})} -## -## Enable or disable license testing for @var{feature}, depending on -## @var{toggle}, which may be one of: +## When called with no extra input arguments, it returns the Octave license, +## otherwise the first input defines the operation mode and must be one of +## the following strings: @code{inuse}, @code{test}, and @code{checkout}. +## The optional @var{feature} argument can either be @qcode{"octave"} (core), +## or an Octave package. ## ## @table @asis -## @item @qcode{"enable"} -## Future tests for the specified license of @var{feature} are conducted -## as usual. +## @item @qcode{"inuse"} +## Returns a list of loaded features, i.e., octave and the list of loaded +## packages. If an output is requested, it returns a struct array with +## the fields @qcode{"feature"}, and @qcode{"user"}. +## +## @item @qcode{"test"} +## Return true if the specified @var{feature} is installed, false otherwise. ## -## @item @qcode{"disable"} -## Future tests for the specified license of @var{feature} return 0. +## An optional third argument @qcode{"enable"} or @qcode{"disable"} is +## accepted but ignored. +## +## @item @qcode{"checkout"} +## Return true if the specified @var{feature} is installed, false otherwise. +## An optional second output will have an error message if a package is not +## installed. +## ## @end table ## -## @code{@var{retval} = license ("checkout", @var{feature})} -## -## Check out a license for @var{feature}, returning 1 on success and 0 -## on failure. -## -## This function is provided for compatibility with @sc{matlab}. -## @seealso{ver, version} +## @seealso{pkg, ver, version} ## @end deftypefn ## Author: William Poetra Yoga Hadisoeseno -function retval = license (varargin) - - persistent __octave_licenses__; +function [retval, errmsg] = license (cmd, feature, toogle) - if (isempty (__octave_licenses__)) - __octave_licenses__ = cell (); - __octave_licenses__{1,1} = "Octave"; - __octave_licenses__{1,2} = "GNU General Public License"; - __octave_licenses__{1,3} = true; - if (exist ("OCTAVE_FORGE_VERSION")) - __octave_licenses__{2,1} = "octave-forge"; - __octave_licenses__{2,2} = ""; - __octave_licenses__{2,3} = true; - endif - endif - - nout = nargout; - nin = nargin; - nr_licenses = rows (__octave_licenses__); - - if (nout > 1 || nin > 3) + if (nargin > 3) print_usage (); endif - if (nin == 0) - - found = find (strcmp (__octave_licenses__(:,1), "Octave"), 1); - - if (! isempty (found)) - result = __octave_licenses__{found,2}; - else - result = "unknown"; - endif + ## Then only give information about Octave core + if (nargin == 0) + retval = "GNU General Public License"; + return + endif - if (nout == 0) - printf ("%s\n", result); - else - retval = result; - endif + [features, desc, flags] = get_all_features (); - elseif (nin == 1) - - if (nout == 0) - - if (! strcmp (varargin{1}, "inuse")) - usage ('license ("inuse")'); + switch tolower (cmd) + case "inuse" + if (nargin > 2) + print_usage (); endif - printf ("%s\n", __octave_licenses__{:,1}); + unloaded = cellfun (@(x) x.name, desc(strcmpi (flags, "Not loaded")), + "UniformOutput", false); + features(ismember (features, unloaded)) = []; - else - - if (! strcmp (varargin{1}, "inuse")) - usage ('retval = license ("inuse")'); + if (nargin > 1) + features = features(strcmp (features, feature)); + endif + if (nargout == 0) + printf ("%s\n", features{:}); + else + retval = struct ("feature", features, "user", get_username ()); endif - pw = getpwuid (getuid ()); - if (isstruct (pw)) - username = pw.name; - else - username = "octave_user"; + case "test" + if (nargin < 2) + print_usage (); endif - retval = struct ("feature", __octave_licenses__(:,1), "user", username); - - endif - - else - - feature = varargin{2}(1:(min ([(length (varargin{2})), 27]))); - - if (strcmp (varargin{1}, "test")) - - found = find (strcmpi (__octave_licenses__(:,1), feature), 1); - - if (nin == 2) - retval = ! isempty (found) && __octave_licenses__{found,3}; - else - if (! isempty (found)) - if (strcmp (varargin{3}, "enable")) - __octave_licenses__{found,3} = true; - elseif (strcmp (varargin{3}, "disable")) - __octave_licenses__{found,3} = false; - else - error ("license: TOGGLE must be either 'enable' or 'disable'"); - endif - else - error ("license: FEATURE '%s' not found", feature); - endif + if (nargin > 2) + ## We ignore the toogle argument because... what's the point? We + ## don't need a license management system on Octave. This function + ## will return true, even if anyone tries to disabled a license. + switch tolower (toogle) + case "enable", # do nothing + case "disable", # do nothing + otherwise, error ("license: TOOGLE must be enable or disable"); + endswitch endif - elseif (strcmp (varargin{1}, "checkout")) + retval = any (strcmp (features, feature)); - if (nin != 2) - usage ('retval = license ("checkout", feature)'); + case "checkout" + ## I guess we could have the checkout command load packages but it's not + ## really the same thing. The closest we have is simply to check if + ## there is a package with the feature name, and give an error if not. + + if (nargin != 2) + print_usage (); endif - found = find (strcmpi (__octave_licenses__(:,1), feature), 1); - - retval = ! isempty (found) && __octave_licenses__{found,3}; + retval = any (strcmp (features, feature)); + errmsg = ""; - else + if (! retval) + errmsg = ["No package named \"" feature "\" installed"]; + endif + + otherwise print_usage (); - endif - - endif + endswitch endfunction +function username = get_username () + pw = getpwuid (getuid ()); + if (isstruct (pw)) + username = pw.name; + else + username = "octave_user"; + endif +endfunction -%!assert (license(), "GNU General Public License") -%!assert ((license ("inuse")).feature, "Octave") +function [features, desc, loaded] = get_all_features () + [desc, loaded] = pkg ("describe", "all"); + pkg_names = cellfun (@(x) x.name, desc, "UniformOutput", false); + features = {"octave", pkg_names{:}}; +endfunction + +%!assert (license (), "GNU General Public License") +%!assert ((license ("inuse", "octave")).feature, "octave") %!test -%! lstate = license ("test", "Octave"); -%! license ("test", "Octave", "disable"); -%! assert (license ("test", "Octave"), false); -%! license ("test", "Octave", "enable"); -%! assert (license ("test", "Octave"), true); -%! if (lstate == false) -%! license ("test", "Octave", "disable"); -%! endif +%! [desc, flags] = pkg ("describe", "all"); +%! for idx = 1: numel (desc) +%! name = desc{idx}.name; +%! switch (flags{idx}) +%! case "Loaded" +%! assert ((license ("inuse", name)).feature, name); +%! case "Not loaded" +%! rv = license ("inuse", name); +%! assert (isstruct (rv)); +%! assert (all (ismember ({"feature", "user"}, fieldnames (rv)))); +%! otherwise +%! error ("code in license out of date"); +%! endswitch +%! endfor -%!assert (license ("checkout", "Octave"), true) +%!assert (license ("test", "octave"), true) +%!assert (license ("test", "not_a_valid package name"), false) + +%!test +%! desc = pkg ("describe", "all"); +%! for idx = 1: numel (desc) +%! assert (license ("test", desc{idx}.name), true) +%! endfor + +%!assert (license ("checkout", "octave"), true) + +%!test +%! [s, e] = license ("checkout", "NOT_A_PACKAGE"); +%! assert (e, "No package named \"NOT_A_PACKAGE\" installed"); %% Test input validation %!error license ("not_inuse") -%!error license ("test", "Octave", "not_enable") -%!error license ("test", "INVALID", "enable") -%!error license ("not_test", "Octave", "enable") +%!error license ("not_test", "octave", "enable") +%!error license ("test", "octave", "invalid_toogle")