BASIS  r3148
Utilities.pm
Go to the documentation of this file.
00001 ##############################################################################
00002 # @file  Utilities.pm
00003 # @brief Main module of project-independent BASIS utilities.
00004 #
00005 # This module defines the BASIS utility functions. It uses the BASIS::Sub::Exporter
00006 # module to enable the generation of these functions customized to the request
00007 # of the particular project they are used in. This is, for example, used by
00008 # the BASIS::Basis module. The default utility functions defined by
00009 # this module, i.e., without any customizaton are intended for use in Perl
00010 # scripts that are not build as part of a particular package. In case of a
00011 # BASIS package, the already customized project-specific implementations should
00012 # be used instead, i.e., those defined by the BASIS::Basis module of
00013 # the project.
00014 #
00015 # @note This module exports also all other BASIS utility functions that are
00016 #       defined in other Perl modules. Therefore, only this or the
00017 #       BASIS::Basis module should be used.
00018 #
00019 # Copyright (c) 2011, 2012 University of Pennsylvania. All rights reserved.<br />
00020 # See https://www.cbica.upenn.edu/sbia/software/license.html or COPYING file.
00021 #
00022 # Contact: SBIA Group <sbia-software at uphs.upenn.edu>
00023 #
00024 # @ingroup BasisPerlUtilities
00025 ##############################################################################
00026 
00027 use strict;
00028 use warnings;
00029 
00030 package BASIS::Utilities;
00031 {
00032     $BASIS::Utilities::VERSION = 0.00_00;
00033 }
00034 
00035 
00036 use Cwd                   qw(realpath);
00037 use File::Basename        qw(dirname basename);
00038 use File::Spec::Functions qw(catfile);
00039 use BASIS::File::Which    qw(which);
00040 
00041 
00042 ## @addtogroup BasisPerlUtilities
00043 # @{
00044 
00045 
00046 # ============================================================================
00047 # constants
00048 # ============================================================================
00049 
00050 ## @brief Default copyright of executables.
00051 use constant COPYRIGHT => "2011, 2012, 2013 University of Pennsylvania";
00052 ## @brief Default license of executables.
00053 use constant LICENSE   => "See https://www.cbica.upenn.edu/sbia/software/license.html or COPYING file.";
00054 ## @brief Default contact to use for help output of executables.
00055 use constant CONTACT   => "SBIA Group <sbia-software at uphs.upenn.edu>";
00056 
00057 # ============================================================================
00058 # exports
00059 # ============================================================================
00060 
00061 # Note: The generators are defined at the end of this file.
00062 
00063 use BASIS::Sub::Exporter -setup => {
00064     exports => [
00065         qw(tostring qsplit),
00066         print_contact => \&_build_print_contact,
00067         print_version => \&_build_print_version,
00068         targetuid     => \&_build_executabletargetinfo_function,
00069         istarget      => \&_build_executabletargetinfo_function,
00070         exepath       => \&_build_executabletargetinfo_function,
00071         exename       => \&_build_executabletargetinfo_function,
00072         exedir        => \&_build_executabletargetinfo_function,
00073         execute       => \&_build_execute],
00074     groups => {
00075         default    => [qw(print_contact print_version exepath exename exedir execute)],
00076         everything => [qw(print_contact print_version targetuid istarget exepath
00077                           exename exedir tostring qsplit execute)]
00078     }
00079 };
00080 
00081 # ============================================================================
00082 # executable information
00083 # ============================================================================
00084 
00085 # ----------------------------------------------------------------------------
00086 ## @brief Print contact information.
00087 #
00088 # @param [in] $contact Name of contact. If @c undef, the default contact is used.
00089 sub print_contact
00090 {
00091     my $contact = shift;
00092     $contact = CONTACT unless $contact;
00093     print "Contact:\n  $contact\n";
00094 }
00095 
00096 # ----------------------------------------------------------------------------
00097 ## @brief Print version information including copyright and license notices.
00098 #
00099 # @note This function can be customized when importing it in order to set
00100 #       default values for its parameters, which is in particular done by
00101 #       the Basis module.
00102 #
00103 # Example:
00104 # @code
00105 # use BASIS::Utilities qw(print_version);
00106 # print_version('foo', '1.0');
00107 # print_version('foo', version => '1.0');
00108 # print_version(name => 'foo', version => '1.0');
00109 # @endcode
00110 #
00111 # Example:
00112 # @code
00113 # use BASIS::Utilities
00114 #     print_version => {project   => 'FooBar',
00115 #                       version   => '1.0',
00116 #                       copyright => '2012 Andreas Schuh',
00117 #                       license   => 'Licensed under the Apache License, Version 2.0'};
00118 # print_version('foo');
00119 # @endcode
00120 # which results in the output
00121 # @verbatim
00122 # foo (FooBar) 1.0
00123 # Copyright (c) 2012 Andreas Schuh. All rights reserved.
00124 # Licensed under the Apache License, Version 2.0
00125 # @endverbatim
00126 #
00127 # @param [in] $name      Name of executable. Should not be set programmatically
00128 #                        to the first argument of the main script, but a string
00129 #                        literal instead. This argument is required if no default
00130 #                        has been set during customization. The argument can be
00131 #                        either given as first argument or as keyword argument
00132 #                        as in "name => 'foo'".
00133 # @param [in] $version   Version of executable, e.g., release of project this
00134 #                        executable belongs to. This argument is required if no
00135 #                        default has been set during customization. The argument
00136 #                        can be either given as second argument or as keyword
00137 #                        argument as in "version => '1.0'".
00138 # @param [in] $project   Name of project this executable belongs to.
00139 #                        If @c undef or an empty string is given, no project
00140 #                        information is included in output.
00141 # @param [in] $copyright The copyright notice. If @c undef, the default copyright
00142 #                        is used. If an empty string is given, no copyright notice
00143 #                        is printed.
00144 # @param [in] $license   Information regarding licensing. If @c undef, the default
00145 #                        software license is used. If an empty string is given,
00146 #                        no license information is printed.
00147 sub print_version
00148 {
00149     my $name    = undef;
00150     my $version = undef;
00151     if (@_ != 0 and (not defined $_[0] or $_[0] !~ /^(name|version|project|copyright|license)$/)) {
00152         $name = $_[0];
00153         shift;
00154     }
00155     if (@_ != 0 and (not defined $_[0] or $_[0] !~ /^(name|version|project|copyright|license)$/)) {
00156         $version = $_[0];
00157         shift;
00158     }
00159     die "print_version(): Invalid number of arguments" if scalar(@_) % 2 == 1;
00160     my %defaults = (name => undef, version => undef, project => undef, copyright => COPYRIGHT, license => LICENSE);
00161     my %options  = (%defaults, @_);
00162     die "print_version(): Name argument given twice"    if defined $options{'name'}    and defined $name;
00163     die "print_version(): Version argument given twice" if defined $options{'version'} and defined $version;
00164     $name    = $options{'name'}    unless $name;
00165     $version = $options{'version'} unless $version;
00166     die "print_version(): Missing name argument"    unless $name;
00167     die "print_version(): Missing version argument" unless $version;
00168     # program identification
00169     print $name;
00170     print " ($options{'project'})" if $options{'project'};
00171     print " ", $version, "\n";
00172     # copyright notice
00173     print "Copyright (c) ", $options{'copyright'}, ". All rights reserved.\n" if $options{'copyright'};
00174     # license information
00175     print $options{'license'}, "\n" if $options{'license'};
00176 }
00177 
00178 # ----------------------------------------------------------------------------
00179 ## @brief Get UID of build target.
00180 #
00181 # @note This function can be customized when importing it in order to set
00182 #       default values for @p prefix and @p targets, which is in particular
00183 #       done by the Basis module.
00184 #
00185 # This function prepends the default namespace used for targets build as
00186 # part of the project this module belongs to if the given target name is yet
00187 # neither known nor fully-qualified, i.e., in the form "<namespace>::<target>".
00188 #
00189 # @param [in] $target   Name of build target.
00190 # @param [in] $prefix   Common target name prefix. If @c undef, the given
00191 #                       target name must match excactly. Otherwise, targets
00192 #                       within the specified namespace are considered.
00193 # @param [in] %$targets Reference to hash which maps known build targets to
00194 #                       executable file paths. If not specified, this function
00195 #                       always returns the input target name unchanged.
00196 #
00197 # @returns Fully-qualified build target name or @c undef if @p target is
00198 #          @c undef or an empty string.
00199 sub targetuid
00200 {
00201     my $target  = shift;
00202     my $prefix  = shift;
00203     my $targets = shift;
00204     # handle invalid arguments
00205     return undef unless defined $target and length($target) > 0;
00206     # in case of a leading namespace separator or if no lookup table
00207     # of executable build target is provided, do not modify target name
00208     return $target if $target =~ /^\./ or not defined $targets;
00209     # project namespace
00210     $prefix = '' unless defined $prefix;
00211     $prefix = $prefix . '.DUMMY'; # simplifies while loop
00212     # try prepending namespace or parts of it until target is known
00213     while ($prefix =~ s/(.*)\.[^.]*/$1/) {
00214         if (exists $targets->{$prefix . '.' . $target}) {
00215             return $prefix . '.' . $target;
00216         }
00217     }
00218     # otherwise, return target name unchanged
00219     return $target;
00220 }
00221 
00222 # ----------------------------------------------------------------------------
00223 ## @brief Determine whether a given target is known.
00224 #
00225 # @note This function can be customized when importing it in order to set
00226 #       default values for @p prefix and @p targets, which is in particular
00227 #       done by the Basis module.
00228 #
00229 # @param [in] $target   Name of build target.
00230 # @param [in] $prefix   Common target name prefix. If @c undef, the given
00231 #                       target name must match excactly. Otherwise, targets
00232 #                       within the specified namespace are considered.
00233 # @param [in] %$targets Reference to hash which maps known build targets to
00234 #                       executable file paths. If not specified, this function
00235 #                       always returns false.
00236 #
00237 # @returns Whether the given build target is known by this module.
00238 sub istarget
00239 {
00240     my $target  = shift;
00241     my $prefix  = shift;
00242     my $targets = shift;
00243     if (defined $targets) {
00244         my $uid = targetuid($target, $prefix, $targets);
00245         defined $uid or return 0;
00246         $uid =~ s/^[.]?(.*)/$1/;
00247         exists $targets->{$uid};
00248     } else {
00249         return 0;
00250     }
00251 }
00252 
00253 # ----------------------------------------------------------------------------
00254 ## @brief Get absolute path of executable file.
00255 #
00256 # @note This function can be customized when importing it in order to set
00257 #       default values for @p prefix and @p targets, which is in particular
00258 #       done by the Basis module.
00259 #
00260 # This function determines the absolute file path of an executable. If no
00261 # arguments are given, the absolute path of this executable is returned.
00262 # Otherwise, the named command is searched in the system PATH and its
00263 # absolute path returned if found. If the executable is not found, @c undef
00264 # is returned.
00265 #
00266 # @param [in] $name     Name of command or @c undef.
00267 # @param [in] $prefix   Common target name prefix. If @c undef, the given
00268 #                       target name must match excactly. Otherwise, targets
00269 #                       within the specified namespace are considered.
00270 # @param [in] %$targets Reference to hash which maps known build targets to
00271 #                       executable file paths. If not specified, this function
00272 #                       always returns false.
00273 # @param [in] $base     Base directory used for relative paths in @p %$targets.
00274 #
00275 # @returns Absolute path of executable or @c undef if not found.
00276 #          If @p name is @c undef, the path of this executable is returned.
00277 sub exepath
00278 {
00279     my $name    = shift;
00280     my $prefix  = shift;
00281     my $targets = shift;
00282     my $base    = shift || '.';
00283     my $path    = undef;
00284     if (not defined $name) {
00285         $path = realpath($0);
00286     } elsif (defined $targets) {
00287         my $uid = targetuid($name, $prefix, $targets);
00288         defined $uid and $uid =~ s/^[.]?(.*)/$1/;
00289         if (defined $uid and exists $targets->{$uid}) {
00290             $path = $targets->{$uid};
00291             if ($path =~ m/\$\(IntDir\)/) {
00292                 my $tmppath = '';
00293                 my $intdir = '';
00294                 foreach $intdir ('Release', 'Debug', 'RelWithDebInfo', 'MinSizeRel') {
00295                     $tmppath = $path;
00296                     $tmppath =~ s/\$\(IntDir\)/$intdir/g;
00297                     if (-e $tmppath) {
00298                         $path = $tmppath;
00299                         last;
00300                     }
00301                 }
00302                 $path =~ s/\$\(IntDir\)//g;
00303             }
00304             $path = File::Spec->rel2abs($path, File::Spec->rel2abs($base, dirname(__FILE__)));
00305             # the realpath() function only works for existing paths
00306             $path = realpath($path) if -e $path;
00307         }
00308     }
00309     $path = which($name) unless defined $path;
00310     return $path;
00311 }
00312 
00313 # ----------------------------------------------------------------------------
00314 ## @brief Get name of executable file.
00315 #
00316 # @note This function can be customized when importing it in order to set
00317 #       default values for @p prefix and @p targets, which is in particular
00318 #       done by the Basis module.
00319 #
00320 # @param [in] $name     Name of command or @c undef.
00321 # @param [in] $prefix   Common target name prefix. If @c undef, the given
00322 #                       target name must match excactly. Otherwise, targets
00323 #                       within the specified namespace are considered.
00324 # @param [in] %$targets Reference to hash which maps known build targets to
00325 #                       executable file paths. If not specified, this function
00326 #                       always returns false.
00327 # @param [in] $base     Base directory used for relative paths in @p %$targets.
00328 #
00329 # @returns Name of executable file or @c undef if not found.
00330 #          If @p name is @c undef, the path of this executable is returned.
00331 sub exename
00332 {
00333     my $path = exepath(@_);
00334     defined $path or return undef;
00335     return basename($path);
00336 }
00337 
00338 # ----------------------------------------------------------------------------
00339 ## @brief Get directory of executable file.
00340 #
00341 # @note This function can be customized when importing it in order to set
00342 #       default values for @p prefix and @p targets, which is in particular
00343 #       done by the Basis module.
00344 #
00345 # @param [in] $name     Name of command or @c undef.
00346 # @param [in] $prefix   Common target name prefix. If @c undef, the given
00347 #                       target name must match excactly. Otherwise, targets
00348 #                       within the specified namespace are considered.
00349 # @param [in] %$targets Reference to hash which maps known build targets to
00350 #                       executable file paths. If not specified, this function
00351 #                       always returns false.
00352 # @param [in] $base     Base directory used for relative paths in @p %$targets.
00353 #
00354 # @returns Absolute path of directory containing executable or @c undef if not found.
00355 #          If @p name is @c undef, the directory of this executable is returned.
00356 sub exedir
00357 {
00358     my $path = exepath(@_);
00359     defined $path or return undef;
00360     return dirname($path);
00361 }
00362 
00363 # ============================================================================
00364 # command execution
00365 # ============================================================================
00366 
00367 # ----------------------------------------------------------------------------
00368 ## @brief Convert list to double quoted string.
00369 #
00370 # @param [in] @$args Array of arguments.
00371 #
00372 # @returns Double quoted string, i.e., string where array elements are separated
00373 #          by a space character and surrounded by double quotes if necessary.
00374 #          Double quotes within an array element are escaped with a backslash.
00375 sub tostring
00376 {
00377     my $str = '';
00378     if (ref($_[0]) eq 'ARRAY') {
00379         foreach my $arg (@{$_[0]}) {
00380             $arg =~ s/"/\\"/g;                             # escape double quotes
00381             $arg = '"' . $arg . '"' if $arg =~ m/'|\s|^$/; # quote if necessary
00382             $str .= ' ' if $str ne '';
00383             $str .= $arg;
00384         }
00385     } else {
00386         $str = $_[0];
00387         $str =~ s/"/\\"/g;                             # escape double quotes
00388         $str = '"' . $str . '"' if $str =~ m/'|\s|^$/; # quote if necessary
00389     }
00390     return $str;
00391 }
00392 
00393 # ----------------------------------------------------------------------------
00394 ## @brief Split quoted string.
00395 #
00396 # @param [in] $str Quoted string.
00397 sub qsplit
00398 {
00399     my $str  = shift;
00400     my $max  = shift;
00401     my $arg  = '';
00402     my @args = ();
00403     LOOP: {
00404         while ($str =~ /[ ]*('([^']|\\\')*[^\\]'|\"([^\"]|\\\")*[^\\]\"|[^ ]+)(.*)/) {
00405             $arg = $1;                           # matched element including quotes
00406             $str = $4;                           # continue with residual command-line
00407             $arg =~ s/^['\"]|(^|[^\\])['\"]$//g; # remove quotes
00408             $arg =~ s/[\\]('|\")/$1/g;           # unescape quotes
00409             push @args, $arg;                    # add to resulting array
00410             last LOOP if defined $max and scalar(@args) >= $max;
00411         }
00412     }
00413     if (defined $max) {
00414         if ($max eq 1) { return ($args[0], $str); }
00415         else           { return (@args, $str); }
00416     } else             { return @args; }
00417 }
00418 
00419 # ----------------------------------------------------------------------------
00420 # @brief Split/Convert quoted string or array of arguments into command name
00421 #        and quoted string of command arguments.
00422 #
00423 # @param [in] @$args Array of command name and arguments or quoted string.
00424 #
00425 # @returns Tuple of command name and quoted string of command arguments.
00426 sub _split_command_and_arguments
00427 {
00428     my $args      = $_[0];
00429     my $command   = '';
00430     my $arguments = '';
00431     if (ref($args) eq 'ARRAY') {
00432         my @argv = @$args; # otherwise input is modified
00433         $command   = shift @argv or die "execute(): No command specified for execution";
00434         $arguments = tostring(\@argv);
00435     } elsif (ref($args) eq '') {
00436         ($command, $arguments) = qsplit($args, 1);
00437     } else {
00438         die "Argument must be either array reference or string";
00439     }
00440     return ($command, $arguments);
00441 }
00442 
00443 # ----------------------------------------------------------------------------
00444 ## @brief Execute command as subprocess.
00445 #
00446 # @note This function can be customized when importing it in order to set
00447 #       default values for @p prefix and @p targets, which is in particular
00448 #       done by the Basis module.
00449 #
00450 # This command takes either an array reference or a string as first argument.
00451 # All other arguments are keyword arguments using hash notation.
00452 #
00453 # Example:
00454 # @code
00455 # # only returns exit code of command but does not output anything
00456 # my $status = execute(['ls', '/'], quiet => 1);
00457 # # returns exit code of command and returns command output w/o printing to stdout
00458 # my ($status, $stdout) = execute('ls /', quiet => 1, stdout => 1);
00459 # @endcode
00460 #
00461 # @param [in] $args        Command with arguments given either as single quoted
00462 #                          string or array of command name and arguments.
00463 # @param [in] $quiet       Turns off output of @c stdout of child process to
00464 #                          @c stdout of parent process.
00465 # @param [in] $stdout      Whether to return the command output.
00466 # @param [in] $allow_fail  If true, does not raise an exception if return
00467 #                          value is non-zero. Otherwise, an exception is
00468 #                          raised by this function using die.
00469 # @param [in] $verbose     Verbosity of output messages.
00470 #                          Does not affect verbosity of executed command.
00471 # @param [in] $simulate    Whether to simulate command execution only.
00472 # @param [in] $prefix      Common target name prefix. If @c undef, the given
00473 #                          target name must match excactly. Otherwise, targets
00474 #                          within the specified namespace are considered.
00475 # @param [in] %$targets    Reference to hash which maps known build targets to
00476 #                          executable file paths. If not specified, this function
00477 #                          always returns false.
00478 # @param [in] $base        Base directory used for relative paths in @p %$targets.
00479 #
00480 # @returns The exit code of the subprocess if @p stdout is false (the default).
00481 #          Otherwise, if @p stdout is true, a tuple consisting of exit code
00482 #          command output is returned. Note that if @p allow_fail is false,
00483 #          the returned exit code will always be 0.
00484 #
00485 # @throws die If command execution failed. This exception is not raised
00486 #             if the command executed with non-zero exit code but
00487 #             @p allow_fail is true.
00488 sub execute
00489 {
00490     # arguments
00491     my $args = shift or die "execute(): No command specified for execution";
00492     if ($args =~ m/^(quiet|stdout|allow_fail|verbose|simulate|prefix|targets|base)$/) {
00493         warn "First argument matches option name. Missing args argument?";
00494     }
00495     my %defaults = (quiet   => 0,  stdout   => 0, allow_fail => 0,
00496                     verbose => 0,  simulate => 0,
00497                     prefix  => undef, targets => undef, base => '.');
00498     my %options  = (%defaults, @_);
00499     # get absolute path of executable
00500     my ($command, $arguments) = _split_command_and_arguments($args);
00501     my $exec_path = exepath($command, $options{'prefix'}, $options{'targets'}, $options{'base'});
00502     defined $exec_path or die "$command: Command not found";
00503     $exec_path = '"' . $exec_path . '"' if $exec_path =~ m/'|\s/; # quote if necessary
00504     $args = "$exec_path $arguments";
00505     # some verbose output
00506     if ($options{'verbose'} gt 0 or $options{'simulate'}) {
00507         print "\$ ", $args;
00508         $options{'simulate'} and print " (simulated)";
00509         print "\n";
00510     }
00511     # execute command
00512     my $status = 0;
00513     my $output = '';
00514     if (not $options{'simulate'}) {
00515         open CMD, "$args |" or die "$command: Failed to open subprocess";
00516         my $ofh = select STDOUT;
00517         $|++;
00518         while (<CMD>) {
00519             print $_ unless $options{'quiet'};
00520             $output .= $_ if $options{'stdout'};
00521         }
00522         $|--;
00523         select $ofh;
00524         close CMD;
00525         $status = $?;
00526     }
00527     # if command failed, throw an exception
00528     if ($status != 0 and not $options{'allow_fail'}) {
00529         die "Command $args failed";
00530     }
00531     # return
00532     if ($options{'stdout'}) { return ($status, $output); }
00533     else                    { return $status; }
00534 }
00535 
00536 
00537 ## @}
00538 # end of Doxygen group
00539 
00540 
00541 # ============================================================================
00542 # exports
00543 # ============================================================================
00544 
00545 # ----------------------------------------------------------------------------
00546 # builder of customized print_contact()
00547 sub _build_print_contact
00548 {
00549     my ($class, $fn, $args) = @_;
00550     return sub {
00551         my $contact = shift || $args->{contact};
00552         print_contact($contact);
00553     }
00554 }
00555 
00556 # ----------------------------------------------------------------------------
00557 # builder of customized print_version()
00558 sub _build_print_version
00559 {
00560     my ($class, $fn, $args) = @_;
00561     return sub {
00562         my $name    = undef || $args->{name};
00563         my $version = undef || $args->{version};
00564         if (@_ != 0 and (not defined $_[0] or $_[0] !~ /^(name|version|project|copyright|license)$/)) {
00565             $name = $_[0];
00566             shift;
00567         }
00568         if (@_ != 0 and (not defined $_[0] or $_[0] !~ /^(name|version|project|copyright|license)$/)) {
00569             $version = $_[0];
00570             shift;
00571         }
00572         die "print_version(): Invalid number of arguments" if scalar(@_) % 2 == 1;
00573         my %defaults = (name      => $args->{name},
00574                         version   => $args->{version},
00575                         project   => $args->{project},
00576                         copyright => $args->{copyright},
00577                         license   => $args->{license});
00578         my %options  = (%defaults, @_);
00579         die "print_version(): Name argument given twice"    if defined $options{'name'}    and defined $name;
00580         die "print_version(): Version argument given twice" if defined $options{'version'} and defined $version;
00581         $options{'name'}    = $name    if $name;
00582         $options{'version'} = $version if $version;
00583         print_version(%options);
00584     }
00585 }
00586 
00587 # ----------------------------------------------------------------------------
00588 # builder of customized functions related to executable target information
00589 sub _build_executabletargetinfo_function
00590 {
00591     my ($class, $fn, $args) = @_;
00592     return sub {
00593         my $target  = shift;
00594         my $prefix  = shift || $args->{prefix};
00595         my $targets = shift || $args->{targets};
00596         my $base    = shift || $args->{base};
00597         eval "$fn(\$target, \$prefix, \$targets, \$base)";
00598     }
00599 }
00600 
00601 # ----------------------------------------------------------------------------
00602 # builder of customized execute()
00603 sub _build_execute
00604 {
00605     my ($class, $fn, $args) = @_;
00606     return sub {
00607         my $argv     = shift;
00608         my %defaults = (quiet      => $args->{quiet}      || 0,
00609                         stdout     => $args->{stdout}     || 0,
00610                         allow_fail => $args->{allow_fail} || 0,
00611                         verbose    => $args->{verbose}    || 0,
00612                         simulate   => $args->{simulate}   || 0,
00613                         prefix     => $args->{prefix},
00614                         targets    => $args->{targets},
00615                         base       => $args->{base});
00616         my %options  = (%defaults, @_);
00617         execute($argv, %options);
00618     }
00619 }
00620 
00621 
00622 1; # indicate success of module loading