Subversion Repositories DevTools

Rev

Blame | Last modification | View Log | RSS feed

###############################################################################
# CLASS Clearcase::LsCmd
# This class inherits from the CCCmpdProc and executes the cleartool command
# "ls" with args "-recurse -long" to list all files in cwd.
#
# It overrider the CCProcess member to process the resultant output from the ls
# 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)
# STATE     = File NAME State (CHECKEDOUT, CHECKIN, PRIVATE)
# VERSION   = If state=CHECKEDIN Then current version of NAME in view 
#             If state=CHECKEDOUT Then version of NAME that the checkout was from
# ANNOTATION= Any Special Annotations returned by ls on NAME
###############################################################################

package Clearcase::LsCmd;

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

use vars qw( @ISA );

@ISA = qw( Clearcase::CmdProc );

# Globally defined states
our $StateCheckedIn  = "CHECKEDIN";
our $StateCheckedOut = "CHECKEDOUT";
our $StatePrivate    = "PRIVATE";

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

    LogDebug("Clearcase::LsCmd::new Instantiating new object of class $class");
    
    # if no dir of dir is "." the get full absolute path, abs_path returns path with "/" regardless of platform
    $dir = abs_path(".") if ( ! defined($dir) || $dir eq "." );    
    # however if passed in make sure we change \ to /
    $dir =~ s|\\|/|g;

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

    # Add this class's data to the class object
    $self->{_FINDDIR} = $dir;
    $self->{_IGNOREFILES} = 1;
    $self->{_IGNORECOUNT} = 0;

    #indexes used
    # State index is a hash of hashes of arrays.  The contents of _STATE are hashes keyed on global states
    # These hashes contain an array of element numbers into the FILEINFO array
    # The branch & annotation are similar but keyed on branches and annotations
    $self->{_STATE}      = {};
    $self->{_BRANCH}     = {};
    $self->{_ANNOTATION} = {};
    
    bless($self, $class);

    # set Clearcase command and arg
    $self->CCcmd("ls");
    $self->CCargs("-long");

    return $self;
}   # new


#==============================================================================
#   ignoreFiles
# Sets & returns the ignore files variable that determines whether to use the 
# IgnoreFiles class for files to ignore
#==============================================================================
sub ignoreFiles
{
    my $self = shift;

    if ( @_ )
    {
        $self->{_IGNOREFILES} = shift;
        LogDebug("ClearCase::LsCmd::ignoreFiles Set to $self->{_IGNOREFILES}");
    }
    return $self->{_IGNOREFILES};
}   # ignoreFiles


#==============================================================================
#   CCexecute
# simply adds dir to args and runs base class CCexecute
#==============================================================================
sub CCexecute
{
    my $self = shift;
    my $args = $self->CCargs();

    # search directory first
    $self->CCargs("$args -directory $self->{_FINDDIR}");
    $self->SUPER::CCexecute();
    # now serach the contents
    $self->CCargs("$args -recurse $self->{_FINDDIR}");
    $self->SUPER::CCexecute();

}   # CCexecute

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

    # 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 or lines with directory ".*" with quotes
        next NEXTLINE if ( $line =~ /^\s*$/ || $line =~ /directory\s*\".*\":/ );

        if ( $line =~ /^view private object\s*(.*)\s*$/ )
        {
            $name       = $1;
            $state      = $StatePrivate;
            $version    = "";
            $branch     = "";
            $annotation = "";
            if ( $self->{_IGNOREFILES} && Clearcase::IgnoreList->ignoreFile($name) )
            {
                LogDebug("Clearcase::LsCmd::CCProcess Ignoring Private file $name");
                $self->{_IGNORECOUNT}++;
                next NEXTLINE;
            }
        }
        elsif ( $line =~ /^(?:directory |)version\s*(.*)\@\@(.*)$/ )
        {
            # got the file name, & rest of line
            $name = $1;
            $line = $2;

            # remove the Rule: from the end of the line as we dont need it
            $line =~ s/\s*Rule: .*$//;

            # Check for annotations & store, removing from line
            $line =~ s/\s*\[(.*)\]\s*$//;
            if ( defined($1) )
            {   $annotation = $1; }
            else
            {   $annotation = ""; }

            # See if Checked out state
            if ( $line =~ /^.*CHECKEDOUT from (.*)$/ )
            {
                $state = $StateCheckedOut;
                $version = $1;  # version is version checked out from
            }
            else
            {
                $state = $StateCheckedIn;
                $version = $line;
            }
            $branch = $version;
            # remove version number and dir separator from version to get branch
            $branch =~ s|[/\\]\d*$||;
        }
        else
        {
            LogError("-x", "Clearcase::LsCmd::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
        $index = $self->addToFileList($name);
        # now add other elements, the index is remembered in the base class
        $self->updateCurrentFile("STATE", $state, "VERSION", $version, "ANNOTATION", $annotation);

        # update indexes
        push(@{$self->{_STATE}{$state}}, $index);
        push(@{$self->{_BRANCH}{$branch}}, $index) if ( $branch ne "" );
        push(@{$self->{_ANNOTATION}{$annotation}}, $index) if ( $annotation ne "" );
    }
}   # process


#==============================================================================
#   getNumByState - Returns the number of items found by state
#==============================================================================
sub getNumByState
{
    my $self = shift;
    my $state = shift;
    my $retval;

    if ( $state eq $StateCheckedIn )
    {
        $retval = $#{$self->{_STATE}{$StateCheckedIn}} + 1;
    }
    elsif ( $state eq $StateCheckedOut )
    {
        $retval = $#{$self->{_STATE}{$StateCheckedOut}} + 1;
    }
    elsif ( $state eq $StatePrivate )
    {
        $retval = $#{$self->{_STATE}{$StatePrivate}} + 1;
    }
    else
    {
        LogError("Clearcase::LsCmd::getNumByState Invalid State supplied");
    }
    return $retval;
}   # getNumByState


#==============================================================================
#   getListByState - Returns a reference to an array of files by state
#==============================================================================
sub getListByState
{
    my $self = shift;
    my $state = shift;
    my @retval;

    if ( $state eq $StateCheckedIn )
    {
        foreach my $index ( @{$self->{_STATE}{$StateCheckedIn}} )
        {
            push(@retval, $self->getElement($index)->{NAME});
        }
    }
    elsif ( $state eq $StateCheckedOut )
    {
        foreach my $index ( @{$self->{_STATE}{$StateCheckedOut}} )
        {
            push(@retval, $self->getElement($index)->{NAME});
        }
    }
    elsif ( $state eq $StatePrivate )
    {
        foreach my $index ( @{$self->{_STATE}{$StatePrivate}} )
        {
            push(@retval, $self->getElement($index)->{NAME});
        }
    }
    else
    {
        LogError("Clearcase::LsCmd::getListByState Invalid State supplied");
    }
    return \@retval;
}   # getListByState


#==============================================================================
#   getNumBranches - Returns number of branches found
#==============================================================================
sub getNumBranches
{
    my $self = shift;
    return scalar keys %{$self->{_BRANCH}};
}   # getNumBranches


#==============================================================================
#   getListBranches - Returns a reference to an array of branches found
#==============================================================================
sub getListBranches
{
    my $self = shift;
    my @retval;

    @retval = keys %{$self->{_BRANCH}};
    return \@retval;
}   # getListBranches


#==============================================================================
#   getNumFilesByBranch - Returns the number of files associated to the supplied branch
#==============================================================================
sub getNumFilesByBranch
{
    my $self = shift;
    my $branch = shift;
    my $retval = undef;

    if ( defined($branch) && defined($self->{_BRANCH}{$branch}) )
    {
        $retval = $#{$self->{_BRANCH}{$branch}} + 1;
    }
    return $retval;
}   # getNumFilesByBranch


#==============================================================================
#   getListFilesByBranch - Returns a reference to an array of files found in the
# supplied branch
#==============================================================================
sub getListFilesByBranch
{
    my $self = shift;
    my $branch = shift;
    my @retval;

    if ( defined($branch) && defined($self->{_BRANCH}{$branch}) )
    {
        foreach my $index ( @{$self->{_BRANCH}{$branch}} )
        {
            push(@retval, $self->getElement($index)->{NAME});
        }
    }
    return \@retval;
}   # getListFilesByBranch


#==============================================================================
#   getNumAnnotations - Returns number of Annotations found
#==============================================================================
sub getNumAnnotations
{
    my $self = shift;
    return scalar keys %{$self->{_ANNOTATION}};
}   # getNumAnnotations


#==============================================================================
#   getListAnnotations - Returns a reference to an array of Annotations found
#==============================================================================
sub getListAnnotations
{
    my $self = shift;
    my @retval;

    @retval = keys %{$self->{_ANNOTATION}};
    return \@retval;
}   # getListAnnotations


#==============================================================================
#   getNumFilesByAnnotation - Returns the number of files associated to the supplied Annotation
# If supplied is all then it returns the total number of files with annotations
#==============================================================================
sub getNumFilesByAnnotation
{
    my $self = shift;
    my $annotation = shift;
    my $retval = undef;

    if ( defined($annotation) )
    {
        if ( $annotation =~ /all/i )
        {
            $retval = 0;
            foreach my $annot ( keys %{$self->{_ANNOTATION}} )
            {
                $retval += $#{$self->{_ANNOTATION}{$annot}} + 1
            }
        }
        if ( defined($self->{_ANNOTATION}{$annotation}) )
        {
            $retval = $#{$self->{_ANNOTATION}{$annotation}} + 1;
        }
    }
    return $retval;
}   # getNumFilesByAnnotation


#==============================================================================
#   getListFilesByAnnotation - Returns a reference to an array of files found 
# with the supplied Annotation
#==============================================================================
sub getListFilesByAnnotation
{
    my $self = shift;
    my $annotation = shift;
    my @retval;

    if ( defined($annotation) && defined($self->{_ANNOTATION}{$annotation}) )
    {
        foreach my $index ( @{$self->{_ANNOTATION}{$annotation}} )
        {
            push(@retval, $self->getElement($index)->{NAME});
        }
    }
    return \@retval;
}   # getListFilesByAnnotation


#==============================================================================
# getNumIgnored
# Returns the number of files ignored.
#==============================================================================
sub getNumIgnored
{
    my $self = shift;

    return $self->{_IGNORECOUNT};
}   # getNumIgnored
1;