The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

App::Framework::Feature::Run - Execute external commands

SYNOPSIS

  use App::Framework '+Run' ;

  $app->run("perl t/test/runtest.pl"); 
  $app->run('cmd' => "perl t/test/runtest.pl"); 
  $app->run('cmd' => "perl t/test/runtest.pl", 'progress' => \&progress);
  
  my $results_aref = $app->run('cmd' => "perl t/test/runtest.pl");
  
  my $run = $app->run() ;
  $run->run("perl t/test/runtest.pl");
  $run->run('cmd' => "perl t/test/runtest.pl", 'timeout' => $sleep);

DESCRIPTION

Provides for external command running from within an application.

An external conmmand may be run using this feature, and the output from the command may be returned for additional processing. The feature also provides timed execution (aborting after a certain time), exit code status, and callbacks that can be defined to be called during execution and/or after program completion.

Arguments

The access method for this feature (called as $app->run()) allows the complete run settings to be specified as a HASH. The call sets the object "FIELDS" from the values in this HASH, for example:

  $app->run(
    'cmd'   => "perl t/test/runtest.pl", 
    'progress' => \&progress,
  ) ;

which specifies the command to run along with the "progress" field (a callback).

A simpler alternative is allowed:

  $app->run("perl t/test/runtest.pl", "some args") ;

or:

  $app->run("perl t/test/runtest.pl some args") ;

The command arguments can be specified either as part of the "cmd" field definition, or separately in the "args" field. One benefit of using the "args" field is that the command need only be specified once - subsequent calls will use the same setting, for example:

  $app->run('cmd' => "perl t/test/runtest.pl"); 
  $app->run('progress' => \&progress);
  $app->run('progress' => \&progress);

Return code

When the external command completes, it's return code can be accessed by reading the "status" field:

  $app->run()->status ;
  

This value is set in the feature object to the result of the last run (i.e. you must save status values between runs if you want to keep track of the values).

The status value is entirely defined by the external command and the operating system.

Also, if you want your script to automatically abort on error (rather than write your own program error handler) then you can set the on_error field to 'fatal'.

Required Programs Check

It's a good idea to start your script with a check for all the external programs you're about to use. You can do this by specifying them in a HASH ref using the "required" method. This does the checking for you, returning the path of all the executables. You can also tell the object to abort the script if some programs are not found, for example:

  $app->run->set(
      'on_error'   => 'fatal',
      'required'   => {
          'lsvob'      => 1,
          'ffmpeg'     => 1,
          'transcode'  => 1,
          'vlc'        => 1,    
      },
  ) ;

NOTE: The values you specify along with the program names are not important when you set the required list - these values get updated with the actual executable path.

Command output

All output (both STDOUT and STDERR) is captured from the external command and can be accessed by reading the "results" field. This returns an ARRAY reference, where the ARRAY contains the lines of text output (one array entry per line).

NOTE: the lines have the original trailing newline removed.

  my $results_aref = $app->run()->results ;
  foreach my $line (@$results_aref)
  {
      print "$line\n";
  }

Timeout

If you specify a "timeout" then the command is executed as normal but will be aborted if it runs for longer than the specified time.

This can be useful, for example, for running commands that don't normally terminate (or run on much longer than is necessary).

Callbacks

There are 2 optional callback routines that may be specified:

progress

This subroutine is called for every line of output from the external command. This can be used in an application for monitoring progress, checking for errors etc.

check_results

This subroutine is called at the end of external command completion. It allows the application to process the results to determine whether the command passed or failed some additional criteria. The "status" field is then set to the results of this subroutine.

Examples

Run a command:

    $app->run(
        'cmd'         => "perl t/test/runtest.pl", 
    ) ;

Run a command and get a callback for each line of output:

    $app->run(
        'cmd'         => "perl t/test/runtest.pl", 
        'progress'    => \&progress,
    ) ;

Ping a machine for 10 seconds and use a callback routine to check the replies:

    my $run_for = 10 ;
    my $host = '192.168.0.1' ;
    my $run = $app->run() ;
    $run->run_cmd("ping", 
        'progress' => \&progress,
        'args'     => "$host",
        'timeout'  => $run_for,
    ) ;

Note the above example uses the run feature object to access it's methods directly.

Fields

cmd - command string (program name)

The program to run

args - any optional program arguments

String containing program arguments (may be specified as part of the 'cmd' string instead)

timeout - optional timeout time in secs.

When specified causes the program to be run as a forked child

nice - optional nice level

On operating systems that allow this, runs the external command at the specified "nice" level

on_error - what to do when a program fails

When this field is set to something other than 'status' it causes an error to be thrown. The default 'status' just returns with the error information stored in the object fields (i.e. 'status', 'results' etc). This field may be set to:

status - error information returned in fields
warning - throw a warning with the message string indicating the error
fatal - [default] throw a fatal error (and abort the script) with the message string indicating the error
required - required programs check

This is a HASH ref where the keys are the names of the required programs. When reading the field, the values are set to the path for that program. Where a program is not found then it's path is set to undef.

See "required" method.

check_results - optional results check subroutine

results check subroutine which should be of the form:

    check_results($results_aref)

Where:

$results_aref = ARRAY ref to all lines of text

Subroutine should return 0 = results ok; non-zero for program failed.

progress - optional progress subroutine

progress subroutine which should be in the form:

    progress($line, $linenum, $state_href)
                                           

Where:

$line = line of text
$linenum = line number (starting at 1)
$state_href = An empty HASH ref (allows progress routine to store variables between calls)
status - Program exit status

Reads as the program exit status

results - Program results

ARRAY ref of program output text lines

norun - Flag used for debug

Evaluates all parameters and prints out the command that would have been executed

CONSTRUCTOR

new([%args])

Create a new Run.

The %args are specified as they would be in the set method (see "Fields").

CLASS METHODS

init_class([%args])

Initialises the Run object class variables.

OBJECT DATA METHODS

required([$required_href])

Get/set the required programs list. If specified, $required_href is a HASH ref where the keys are the names of the required programs (the values are unimportant).

This method returns the $required_href HASH ref having set the values associated with the program name keys to the path for that program. Where a program is not found then it's path is set to undef.

Also, if the "on_error" field is set to 'warning' or 'fatal' then this method throws a warning or fatal error if one or more required programs are not found. Sets the message string to indicate which programs were not found.

OBJECT METHODS

run( [args] )

Execute a command if args are specified. Whether args are specified or not, always returns the run object.

This method has reasonably flexible arguments which can be one of:

(%args)

The args HASH contains the information needed to set the "FIELDS" and then run teh command for example:

  ('cmd' => 'ping', 'args' => $host) 
($cmd)

You can specify just the command string. This will be treated as if you had called the function with:

  ('cmd' => $cmd) 
($cmd, $args)

You can specify the command string and the arguments string. This will be treated as if you had called the function with:

  ('cmd' => $cmd, 'args' => $args) 

NOTE: Need to get run object from application to access this method. This can be done as one of:

  $app->run()->run(.....);
  
  or
  
  my $run = $app->run() ;
  $run->run(....) ;
Run([%args])

Alias to "run"

DIAGNOSTICS

Setting the debug flag to level 1 prints out (to STDOUT) some debug messages, setting it to level 2 prints out more verbose messages.

AUTHOR

Steve Price <sdprice at cpan.org>

BUGS

None that I know of!