package Cmd; #============================================================================== # Copyright and license info is available in the LICENSE file included with # the Server Deployment Package (SDP), and also available online: # https://swarm.workshop.perforce.com/projects/perforce-software-sdp/view/main/LICENSE #------------------------------------------------------------------------------ =head1 NAME Cmd.pm - Execute system calls, honoring globals $Cmd::Verbosity and $Cmd::NoOp. =head1 VERSION 2.6.2 =head1 DESCRIPTION This modules provides the Cmd::Run() function, which executes system calls. It honors $Cmd::NoOp ("no operation"). By default, commands are displayed rather than executed if $Cmd::NoOp is set. The caller can determine the verbosity level at which a descriptive comment is displayed, and the verbosity level at which the output of the command (both stdout and stderr) are displayed. Whether or not it is displayed, the $Cmd::Output variable contains the output (both stdout and stderr) of the command executed. The exit code of the system call is available as $Cmd::ExitCode. =head1 PUBLIC DATA =head2 $Cmd::NoOp: If $Cmd::NoOp is set to 1, then Cmd::Run() will display commands rather than executing them. This provides script developers with a standard way to provide users a way to show commands that would be run before actually running them. This variable is exported and is global. =head2 $Cmd::Verbosity: This determines the amount of output, in the form of a numeric value from 1 (quiet, fatal errors only) to 6 (high debugging). See Msg.pm for more detail. This variable is exported and is global. =head2 $Cmd::ExitCode: Contains exit code returned from the last command executed by Cmd::Run(). =head2 $Cmd::Output: The $Cmd::Output string contains the the output of a command executed with the Cmd::Run() routine. =head1 PUBLIC FUNCTIONS =cut require Exporter; use strict; use File::Temp; use POSIX qw(uname); use Msg; use Misc; # The next line avoids problems with 'use strict'. use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); use vars qw($ExitCode $NoOp $Output $Verbosity $IGNORE_NO_OP $HONOR_NO_OP); # Initialization processing occurs in the BEGIN block. BEGIN { # Keep $VERSION value the same as at the top of this file. $VERSION = "2.6.2"; # Exported variable initialization. $ExitCode = 0; $NoOp = 0; $Output = ""; $Verbosity = $INFO; # Exported constants for readability. $HONOR_NO_OP = 0; $IGNORE_NO_OP = 1; } # Package interface standards. By default, any export can be blocked. @ISA = qw(Exporter); @EXPORT = qw( Run $NoOp $Verbosity $IGNORE_NO_OP $HONOR_NO_OP ); @EXPORT_OK = qw( $ExitCode $Output ); # Prototypes for public functions. sub Run($;$$$$); #============================================================================== # Internal Functions #============================================================================== #============================================================================== # Public Functions #============================================================================== #------------------------------------------------------------------------------ =head2 Run() Cmd($I; $I, $I, $I, $I) returns exit code from $I =head3 Description-Cmd This runs a command, and interacts with $I and $I in a standard fashion. See descriptions of $I and $I in Misc.pm. It also sets $I and $I. =head3 Parameters-Cmd $I - Command to run in the system shell. "2E&1" will be appended to the command, redirecting standard error to standard out. Note that the command can contain an input redirect, a 'E' character. It may I contain output redirection ('2E' or '2E&1'). This parameter is required; all others are optional. $I - Description of the command to run (optional). $I - If set to 1, command is executed even if $Cmd::NoOp is set. If this optional parameter is omitted, the default behavior is to honor the NoOp flag (i.e. not execute the command if $Cmd::NoOp is Set). This flag should only be used for commands that do not affect data, to honor the spirit of the $Cmd::NoOp flag. For example, it is appropriate to ignore the $Cmd::NoOp setting for a directory listing command, but not one that removes a directory tree. For readability, $IGNORE_NO_OP and $HONOR_NO_OP constants can be passed in. $I - The verbostiy level at or above which the description is displayed (optional). The default is $INFO. See Msg.pm for verbosity levels. $I - The verbostiy level at or above which the command output is displayed (optional). The default is $DEBUG. See Msg.pm for verbosity levels. =head3 Output-Cmd Output depends on the verbosity setting: =over 4 =item 1 None =item 2 Commmand description only (typical). =item 3 Command description and the actual command to run. =item 4 Command description, actual command to run, and output of the command. =back =head3 Returns-Cmd The return value of the system call is returned. The output of the executed command is displayed if $I E 3, and is also available in the calling environment via the global variable $Cmd::Output. The $I contains the exit status of the return command. This should be checked instead of $?, since $? is not set in NoOp mode. =head3 Examples-Cmd =head4 List *.cfg files in a directory tree: C C =head4 Run quietly at normal verbosity, showing the description only at DEBUG or higher verobsity level, and executing the command even if in NoOp mode, and showing output only at the maximum TRACE debug level. C =cut #------------------------------------------------------------------------------ sub Run($;$$$$) { $Msg->trace("Cmd::Run(@_)"); my ($cmd, $desc, $ignoreNoOpFlag, $desc_v, $out_v) = @_; $desc_v = $INFO unless ($desc_v); $out_v = $DEBUG unless ($out_v); if ($desc && ($desc ne "")) { print "$Msg::MsgLevelText{$desc_v}: $desc\n" if ($Verbosity >= $desc_v); } $Msg->debug("Executing command: [$cmd]."); $Output = ""; $ExitCode = 0; if ($NoOp && ( ! $ignoreNoOpFlag)) { $Msg->info("NO-OP: Would run: [$cmd]."); return $ExitCode; } else { $Output = `$cmd 2>&1`; $ExitCode = $?; print $Output if ($Output && ($Output ne "") && ($Verbosity >= $out_v)); return $ExitCode; } } # Return package load success. 1;