Subversion Repositories DevTools

Rev

Blame | Last modification | View Log | RSS feed

###############################################################################
# CLASS Clearcase::FindCmd
# This class inherits from the CCCmpdProc and executes the cleartool command
# "find" with specified args
#
# It overrides the CCProcess member to process the resultant output from the find
# command and store information about all files/dirs in and below the pwd.
# 
# It uses the CCIgnore class to determine if a file should be ignored or included
# in the processing of the cmd output.
#
# It stores as a result of the command for each file/dir
# NAME      = The full path of the file (as defined by CCCmdProc)
# VERSION   = 
###############################################################################

package Clearcase::FindCmd;

use strict;
use Cwd qw/ abs_path /;
use DeployUtils::Logger;
use Clearcase::IgnoreList;
use Clearcase::CmdProc;

use vars qw( @ISA );

@ISA = qw( Clearcase::CmdProc );

my $StateCheckedIn  = "CHECKEDIN";
my $StateCheckedOut = "CHECKEDOUT";

#==============================================================================
#   Constructor
#==============================================================================
sub new
{
    my $obclass = shift;
    my $class = ref($obclass) || $obclass;
    my $dir = shift;
    my $args = shift;

    LogDebug("Clearcase::FindCmd::new Instantiating new object of class $class");
     
    # if no dir of dir is "." the get full absolute path, abs_path returns patch with "/" regardless of platform
    $dir = abs_path(".") if ( ! defined($dir) || $dir eq "." );    
    $args = "" if ( ! defined($args) );
    $args .= " -print" if ( $args !~ /-print/ );

    # Call base class's constructor
    my $self = $class->SUPER::new();

    # Add this class's data to the class object
    $self->{_FINDDIR} = $dir;
    $self->{_FINDARGS} = $args;

    bless($self, $class);

    # set Clearcase command and arg
    $self->CCcmd("find $dir");
    $self->CCargs("$args");

    return $self;
}   # new


#==============================================================================
#   CCprocess overrides base class's CCProcess to process result
#==============================================================================
sub CCprocess
{
    my $self = shift;
    my $line;
    my ($name, $version, $state ) = ( "", "", "" );
    my $dirRE = $self->{_FINDDIR};

    # if dirRE starts with a drive letter then its a dynamic view and the find reports file names without
    # the drive letter, so lets remove it from the RE
    #$dirRE =~ s|^[a-zA-Z]:||;

    # Change the search RE for the findDir so that all occurances of "/" in path are changed to "[/\\]" 
    # to match either type of path separator
    $dirRE =~ s|/|\[/\\\\\]|g;

NEXTLINE:
    while ( $line = $self->getline() )
    {
        chomp $line ;
        $line =~ s/\r//g;    # remove carraige returns
        
        # ignore blank lines
        next NEXTLINE if ( $line =~ /^\s*$/ );

        # Files Found can be above the supplied dir if -all is used so lets remove files that dont start with Dir
        if ( $line !~ m|^$dirRE| )
        {
            LogDebug("Clearcase::FindCmd::CCprocess Ignoring following Line as it is above current path");
            LogDebug("$line");
            next NEXTLINE;
        }

        # if line contains 2 sets of @@ then its probably a removed file that is traced back to a parent
        # its format is dir@@branch/filename@@branch/version
        if ( $line =~ /^(.*)\@\@(.*)\@\@(.*)$/ )
        {
            my $dir = $1;
            $name = $2;
            $version = $3;
            # get last part of name which is the file name with the dir separator 
            $name =~ s|^.*([/\\\\][^/\\\\])|$1|;
            # now prepend dir to name
            $name = $dir . $name;

            # See if Checked out state
            if ( $version =~ /CHECKEDOUT$/ )
            {
                $state = $StateCheckedOut;
            }
            else
            {
                $state = $StateCheckedIn;
            }
        }
        elsif ( $line =~ /^(.*)\@\@(.*)$/ )
        {
            # got the file name, & rest of line
            $name = $1;
            $version = $2;

            # See if Checked out state
            if ( $version =~ /CHECKEDOUT$/ )
            {
                $state = $StateCheckedOut;
            }
            else
            {
                $state = $StateCheckedIn;
            }
        }
        else
        {
            LogError("-x", "Clearcase::FindCmd::CCprocess Unknown Input Line as follows");
            LogError("$line");
        }

        # Remove findDir from path if find dir is same as pwd, makes it less clutered
        $name =~ s|$dirRE|\.| if ( $self->CCcwd() =~ m|^$dirRE| );

        # Add name to file list and set it as current element
        $self->addToFileList($name);
        # now add other elements, the index is remembered in the base class
        $self->updateCurrentFile("STATE", $state, "VERSION", $version);
    }
}   # process


#==============================================================================
#   printResult prints out the result of the ls command in a formatted output
#==============================================================================
sub printResult
{
}   # printResult



#==============================================================================
# getDiffListFrom
# Compares this objects file list to object passed into.  It assumes the object passed
# is the from object and this object is the to object and compares them.
# Any item in this and not in from is new and vice versa.
# it returns a reference to a hash that is keyed by name and contains hash elements
# NEW & OLD that contain the version strings from the comparison
#==============================================================================
sub getDiffListFrom
{
    my $self = shift;
    my $from = shift;
    my %diff;
    my ( $thisElement, $thatElement );
    my $name;

    LogError("FindCmd::getDiffFrom: Argument must be a FindCmd object") if ( ref($from) ne "Clearcase::FindCmd" );

    # loop through this objects elements and find them in from object.
    # if not found in from then its a new object, otherwise if versions are different then element has changed
    $thisElement = $self->getFirstElement();
    while( defined($thisElement) )
    {   
        $name = $thisElement->{NAME};
        $thatElement = $from->findName($name);
        if ( defined($thatElement) )
        {
            if ( $thisElement->{VERSION} ne $thatElement->{VERSION} )
            {
                $diff{$name}{NEW} = $thisElement->{VERSION};
                $diff{$name}{OLD} = $thatElement->{VERSION};
            }
        }
        else
        {
            $diff{$name}{NEW} = $thisElement->{VERSION};
            $diff{$name}{OLD} = "";
        }
        $thisElement = $self->getNextElement();
    }

    # loop through that objects elements and find them in this object.
    # Only want to find ones that dont exist in this one which means they have been removed
    $thatElement = $from->getFirstElement();
    while( defined($thatElement) )
    {   
        $name = $thatElement->{NAME};
        $thisElement = $self->findName($name);
        if ( !defined($thisElement) )
        {
            $diff{$name}{OLD} = $thatElement->{VERSION};
            $diff{$name}{NEW} = "";
        }
        $thatElement = $from->getNextElement();
    }
#print Data::Dumper->Dump([ \%diff ], [ "Diff" ]);
    return \%diff;
}   # getDiffListFrom


1;