############################################################################### # CLASS Clearcase::Cmd # Base Class for executing clearcase commands and allowing results to be proceesed. # # The class should be instantiated, the Clearcase Command and Arguements set and # then the CCexecute should be called to execute the command. By default this # class will then simply just print the result to the console if no derived class # overrides the CCProcess method. # Dereived Classes should override the CCProcess member, which is called by CCexecute # after the Clearcase command has been executed, to process the output of the # command as required. # # By convention all members/methods that begin with an '_' are private. # ############################################################################### package Clearcase::Cmd; use strict; use Cwd; use DeployUtils::Logger; use IO::File; use File::Temp qw /mktemp/; use File::Spec qw /tmpdir/; #============================================================================== # Constructor #============================================================================== sub new { my $obclass = shift; my $class = ref($obclass) || $obclass; LogDebug("ClearCase::Cmd::new Instantiating new object of class $class"); bless my $self = { _CWD => Cwd::cwd, _CLEARTOOL => ( $^O eq "solaris" ) ? "/usr/atria/bin/cleartool" : "cleartool", _CMD => "", _ARGS => "", _TMPNAME => "", _CMDOUTPUT => new IO::File, _PROCESSOUTPUT => 1, _ABORTONERROR => 1 } => ( $class ); return($self); } # new #============================================================================== # DESTROY ( Desctructor ) #============================================================================== sub DESTROY { my $self = shift; $self->reset(); } # DESTROY #============================================================================== # reset # Closes the filehandle and removes the temp file if any #============================================================================== sub reset { my $self = shift; $self->{_CMDOUTPUT}->close if ( defined($self->{_CMDOUTPUT}) && defined($self->{_CMDOUTPUT}->fileno()) ); unlink($self->{_TMPNAME}) if ( $self->{_TMPNAME} ne "" && -f $self->{_TMPNAME} ); } # reset ############################################################################### # Set/Get member methods. # The following functions allow callers to set/get internal members. ############################################################################### #============================================================================== # CCcwd accessor method returns CWD #============================================================================== sub CCcwd { my $self = shift; return $self->{_CWD}; } # CCcwd #============================================================================== # CCcmd accessor sets & returns the Clearcase command #============================================================================== sub CCcmd { my $self = shift; if ( @_ ) { # if we are setting the command then we need to make sure the object is reset in case its a new cmd $self->reset(); $self->{_CMD} = shift; $self->{_ARGS} = ""; LogDebug("ClearCase::Cmd::CCcmd Set CC Command to $self->{_CMD}"); } return $self->{_CMD}; } # cc_cmd #============================================================================== # CCargs accessor sets & returns the Clearcase command arguements #============================================================================== sub CCargs { my $self = shift; if ( @_ ) { $self->{_ARGS} = shift; LogDebug("ClearCase::Cmd::CCargs Set CC Args to $self->{_ARGS}"); } return $self->{_ARGS}; } # cc_args #============================================================================== # CCaddArgs accessor appends arsg to existing args list #============================================================================== sub CCaddArgs { my $self = shift; foreach my $i ( @_ ) { $self->{_ARGS} .= " " . $i; } LogDebug("ClearCase::Cmd::CCaddArgs Set CC Args to $self->{_ARGS}"); return $self->{_ARGS}; } # cc_args #============================================================================== # processOutput # Sets the processOutput flag to 1 or 0. If 1 clearcase commands are redirected # to a file for processing by CCProcess, otherwise 0 does not redirection or processing. #============================================================================== sub processOutput { my $self = shift; if ( @_ ) { my $val = shift; $self->{_PROCESSOUTPUT} = ( $val == 0 ) ? 0 : 1; LogDebug("ClearCase::Cmd::processOutput Set to $self->{_PROCESSOUTPUT}"); } return $self->{_PROCESSOUTPUT}; } # processOutput #============================================================================== # abortOnError # Sets the abortOnError flag to 1 or 0. If 0 then CCexecute ignores errors and # returns the error code, if 1 then errors are reported & script terminates #============================================================================== sub abortOnError { my $self = shift; if ( @_ ) { my $val = shift; $self->{_ABORTONERROR} = ( $val == 0 ) ? 0 : 1; LogDebug("ClearCase::Cmd::abortOnError Set to $self->{_ABORTONERROR}"); } return $self->{_ABORTONERROR}; } # abortOnError #============================================================================== # CCexecute executes cleartool cmd with args and stores resulting output in # IO::File handle in self #============================================================================== sub CCexecute { my $self = shift; my $retval; if ( $self->{_CMD} eq "" ) { LogError("ClearCase::Cmd::CCexecute No Command to execute"); } if ( $self->{_PROCESSOUTPUT} ) { $self->{_TMPNAME} = File::Spec->tmpdir() . "/" . mktemp("CCCmdXXXXX"); LogDebug("ClearCase::Cmd::CCexecute Executing cmd \"$self->{_CLEARTOOL} $self->{_CMD} $self->{_ARGS} > $self->{_TMPNAME}\"."); $retval = system("$self->{_CLEARTOOL} $self->{_CMD} $self->{_ARGS} > $self->{_TMPNAME}") >> 8; } else { LogDebug("ClearCase::Cmd::CCexecute Executing cmd \"$self->{_CLEARTOOL} $self->{_CMD} $self->{_ARGS}\"."); $retval = system("$self->{_CLEARTOOL} $self->{_CMD} $self->{_ARGS}") >> 8; } if ( $retval != 0 ) { unlink($self->{_TMPNAME}) if ( $self->{_TMPNAME} ne "" && -f $self->{_TMPNAME} ); LogError("ClearCase::Cmd::CCexecute Cmd Execution Failed with error $retval") if ( $self->{_ABORTONERROR} ); LogError("-x", "ClearCase::Cmd::CCexecute Cmd Execution Failed with error $retval"); } if ( $self->{_PROCESSOUTPUT} ) { $self->{_CMDOUTPUT}->open("<$self->{_TMPNAME}") || LogError("ClearCase::Cmd::CCexecute Cannot open clearcase command results file"); # Calls processData member to process result. # default version in this class simply prints the result to std out. $self->CCprocess(); } return $retval; } # cc_exec #============================================================================== # CCprocess processes the output from the execute command. # This is the default version that just simply dumps the output from the # clearcase command executed to console # Any Derived classes can override this and either do nothing or process output # as required. # It is a function called by the CCexecute method and should not be # called externally #============================================================================== sub CCprocess { my $self = shift; my $line; while ( $line = $self->{_CMDOUTPUT}->getline() ) { print $line; } } # CCprocess #============================================================================== # getline retunrs the next line from the IO File class using its getline method #============================================================================== sub getline { my $self = shift; return $self->{_CMDOUTPUT}->getline(); } # getline #============================================================================== # dumpSelf, debugging member to dump selfs hash #============================================================================== sub dumpSelf { use Data::Dumper; my $self = shift; print Data::Dumper->Dump([$self], [ref($self)]); } # dumpSelf 1;