Subversion Repositories DevTools

Rev

Rev 361 | Blame | Compare with Previous | Last modification | View Log | RSS feed

########################################################################
# Copyright (C) 2008 ERG Limited, All rights reserved
#
# Module name   : CCbc2.pl
# Module type   : JATS Utility
# Compiler(s)   : Perl
# Environment(s): JATS
#
# Description   : Create two dynamic views and invoke Beyond Compare
#                 to view the differences.
#
#                 or
#
#                 Create one dynamic view and use the directory
#
#......................................................................#

require 5.006_001;
use strict;
use warnings;
use JatsError;
use JatsSystem;
use FileUtils;

use Pod::Usage;                             # required for help support
use Getopt::Long;
use Cwd;

my $VERSION = "1.1.0";                      # Update this

#
#   Options
#
my $opt_debug   = $ENV{'GBE_DEBUG'};        # Allow global debug
my $opt_verbose = $ENV{'GBE_VERBOSE'};      # Allow global verbose
my $opt_help = 0;
my $opt_manual = 0;
my $opt_drive = 'o';
my $opt_tag = 'dynamic';
my $opt_new_label;
my $opt_old_label;

#
#   Globals - Provided by the JATS environment
#
my $USER            = $ENV{'USER'};
my $UNIX            = $ENV{'GBE_UNIX'};
my $TMP             = $UNIX ? "/tmp" : $ENV{'TMP'};
my $MACHINENAME     = $ENV{'GBE_HOSTNAME'};

#
#   Globals
#
my @error_list;                             # ClearCmd detected errors
my $BC2             = 'c:/Program Files/Beyond Compare 2/BC2.exe';
my @view_tags;


#-------------------------------------------------------------------------------
# Function        : Mainline Entry Point
#
# Description     :
#
# Inputs          :
#

#
#   Parse the user options
#
my $result = GetOptions (
                "help+"         => \$opt_help,              # flag, multiple use allowed
                "manual"        => \$opt_manual,            # flag, multiple use allowed
                "verbose+"      => \$opt_verbose,           # flag, multiple use allowed
                "new=s"         => \$opt_new_label,         # String
                "old=s"         => \$opt_old_label,         # String
                "drive=s"       => \$opt_drive,             # String
                );

                #
                #   UPDATE THE DOCUMENTATION AT THE END OF THIS FILE !!!
                #

#
#   Process help and manual options
#
pod2usage(-verbose => 0, -message => "Version: $VERSION")  if ($opt_help == 1  || ! $result );
pod2usage(-verbose => 1)  if ($opt_help == 2 );
pod2usage(-verbose => 2)  if ($opt_manual || ($opt_help > 2));

InitFileUtils();

#
#   Configure the error reporting process now that we have the user options
#
ErrorConfig( 'name'    => 'CC_BC2',
             'verbose' => $opt_verbose );

#
#   Only for windows
#
Error ("This program only works under Windows")
    if ( $UNIX );

#
#   Validate user options
#
#   Be nice to the user
#   If we have two options and no labels, then assign them
#
if ( ! $opt_new_label && ! $opt_old_label )
{
    Error ("Must provide two labels on command line unless they are provided via -old and -new options")
         if ( $#ARGV < 1 );

    $opt_old_label = shift @ARGV;
    $opt_new_label = shift @ARGV;
}

Error ("Need two labels on the command line, or via options")
    unless ( $opt_old_label && $opt_new_label );

Error ("Too many command line arguments" )
    unless ( $#ARGV < 0 );

#
#   Determine the machine type
#
Verbose ("Machine Type: UNIX=$UNIX");

#
#   Extract parameters that will be used to create a view that is
#   unique. Will use hostname and user name
#
Error ("Machine Name not determined")
    unless ( $MACHINENAME );

Error ("USER name not determined" )
    unless ( $USER );

#
#   Need a TMP working directory
#   Used to create config files
#
Error ("TMP not found or not a directory")
    unless ( $TMP && -d $TMP );
$TMP = "$TMP/$$";

#
#   Determine the path to BC2.EXE
#   It maynot be installed inthe default place
#
if ( ! -x $BC2 )
{
    $BC2 = GetBc2ExePath();
}

#
#   Ensure that the 'cleartool' program can be located
#
Verbose ("Locate clearcase utility in users path");
Error ("Cannot locate the 'cleartool' utility in the users PATH")
    unless ( LocateProgInPath('cleartool', '--All') );


#
#   Create dynamic views for the two views
#   Verify that the view are present
#
Message ("Constructing dynamic views");
my $path1 = create_dynamic_view( $opt_old_label );
my $path2 = create_dynamic_view( $opt_new_label );

Error ("Cannot locate view directory: $path1" ) unless (-d $path1);
Error ("Cannot locate view directory: $path2" ) unless (-d $path2);

#
#   If one of the paths is a dynamic view and the other is a local path
#   then attempt to locate the common directories
#
if ( $#view_tags == 0 )
{
    massage_paths();
}


Message ("Using Beyond Compare to compare two views",
         "Wait for BC2 to exit so that we can delete the views" );
System ( $BC2, $path1, $path2 );
exit 0;

#-------------------------------------------------------------------------------
# Function        : create_dynamic_view
#
# Description     : Create a dynamic view, based on a label
#
# Inputs          : $label          - Base label
#
# Returns         : Path to the view
#
sub create_dynamic_view
{
    my ($label) = @_;

    #
    #   Intercept and treat the special label 'current'
    #
    return create_path_view( $label )
        if ( $label eq 'current'  || $label =~ m~^dir=.+~ || $label =~ m~^current=.+~ );

    my $config = "${TMP}.config_ccview.txt";

    #
    #   Create a config spec
    #
    Verbose ("Create tmp file: $config");
    FileCreate ( $config,
                 "element * CHECKEDOUT",
                 "element .../lost+found -none",
                 "element * $label",
                );

    my $tag = "${USER}_${MACHINENAME}_${opt_tag}_${label}";
    push @view_tags, $tag;

    ClearCmd ( "rmview -tag $tag" );
    ClearCmd ( "mkview -tag $tag -stgloc -auto" );
    ClearCmd ( "setcs  -tag $tag $config" );

    unlink $config;

    return "$opt_drive:/$tag";
}

#-------------------------------------------------------------------------------
# Function        : create_path_view
#
# Description     : Not using a view, using a path
#                   Return the path as requested
#
# Inputs          : $label                  - with embedded path
#
# Returns         : Path to the (dummy) view
#
sub create_path_view
{
    my ($label) = @_;
    my $path  = '.';

    $path = $1
        if ( $label =~ m~.+=(.+)~ );

    Error ("Directory not found: $path" )
        unless ( -d $path );

    $path = FullPath( $path );
    return $path;
}

#-------------------------------------------------------------------------------
# Function        : massage_paths
#
# Description     : Used when one of the paths is a view and the the other
#                   is a local directory.
#
#                   Attempt to locate the common root
#
# Inputs          : None
#
# Returns         : Modifies $path1 and $path2
#
sub massage_paths
{
    my $view_path = "$opt_drive:/" . $view_tags[0];
    my $user_path = $path1;
    $user_path = $path2 if ( $view_path eq $path1 );

    #
    #   Split the user path into its component directory entries
    #   Start at the top and look for one of these in the view
    #
    my @user_path = split ('/', $user_path );
    my $tpath = '';
    foreach my $dir ( @user_path )
    {
        if ( -d "$view_path/$dir" )
        {
            #
            #   Common directory found
            #   Set the user path to the previous directory
            #
            $user_path = $tpath;
            if ( $view_path eq $path1   )
            {
                $path2 = $user_path;
            }
            else
            {
                $path1 = $user_path;
            }

            #
            #   now add the common part
            #
            $path1 .= "/$dir";
            $path2 .= "/$dir";
            Message ("Setting common root path ($dir)", $path1, $path2);
            last;
        }
        $tpath .= '/' if ( $tpath );
        $tpath .= $dir;
    }
}

#-------------------------------------------------------------------------------
# Function        : GetBc2ExePath
#
# Description     : Determine the path to the BeyondCompare executable
#                   by looking in the Windows Registry
#
# Inputs          : None
#
# Returns         : Path to an executable
#

sub GetBc2ExePath
{
    eval "require Win32::TieRegistry"
        or Error ("Win32::TieRegistry not available");

    my $userKey= Win32::TieRegistry->new("CUser")
        or  Error( "Can't access HKEY_CURRENT_USER key: $^E" );

    my $bc2Key= $userKey->Open( "Software/Scooter Software/Beyond Compare", {Delimiter=>"/"} )
        or  Error "Can't access BC2 Keys: $^E";

    my $bc2Data = $bc2Key->GetValue( 'ExePath' )
        or Error( "Cannot locate BeyondCompare in Windows Registry");

    Error ("BeyondCompare program not found", "Prog: $bc2Data") unless ( -x $bc2Data );
    return $bc2Data;
}

#-------------------------------------------------------------------------------
# Function        : END
#
# Description     : This function will be called as the program exits
#                   It will also be called under error conditions
#                   Close down stuff we created
#
# Inputs          : 
#
# Returns         : 
#

sub END
{
    Message ("Cleaning up views - Please wait") if @view_tags;
    foreach my $tag ( @view_tags )
    {
#        Message ("NOT Cleaning up views");
        ClearCmd ( "rmview -tag $tag" );
    }
}

#-------------------------------------------------------------------------------
# Function        : ClearCmd
#
# Description     : Execute a cleartool command
#                   Capture error messages only
#
# Inputs          : Command to execute
#
# Returns         : Exit code
#                   Also the global @error_list
#
sub ClearCmd
{
    my( $cmd ) = @_;
    Verbose2 "cleartool $cmd";

        @error_list = ();
        open(CMD, "cleartool $cmd  2>&1 |")    || Error "can't run command: $!";
        while (<CMD>)
        {
            chomp;
            Verbose ($_);
            push @error_list, $_ if ( m~Error:~ );
        }
        close(CMD);

    Verbose2 "Exit Status: $?";
    return $? / 256;
}

#-------------------------------------------------------------------------------
#   Documentation
#

=pod

=for htmltoc    GENERAL::ClearCase::

=head1 NAME

CCbc2 - ClearCase BeyondCompare Difference

=head1 SYNOPSIS

  jats CCbc2 [options] [old_label new_label]

 Options:
    -help              - brief help message
    -help -help        - Detailed help message
    -man               - Full documentation
    -old=label         - Old label (or dir=path)
    -new=label         - New label (or dir=path)
    -drive=path        - Alternate vob location

=head1 OPTIONS

=over 8

=item B<-help>

Print a brief help message and exits.

=item B<-help -help>

Print a detailed help message with an explanation for each option.

=item B<-man>

Prints the manual page and exits.

=item B<-old=label>

This option specifies the old, or base, label for the difference report. This
label is mandatory for the difference report.

The old and new labels may be provided on the command line, or via named
options, but not both.

The label may be of the form dir=path to force the utility to use a local
view or path.

=item B<-new=label>

This option specifies the new, or current, label for the difference report. This
label is mandatory for the difference report.

The old and new labels may be provided on the command line, or via named
options, but not both.

The label may be of the form dir=path to force the utility to use a local
view or path.

=item B<-drive=path>

This option allows the user to provide an alternate location for the
administration vob used by the program. The default location is:

=over 8

=item *

Windows o:

=item *

Unix /view

=back

=back

=head1 DESCRIPTION

This program simplifies the process of perform a code review between two ClearCase
labels by:

=over 8

=item *

Creating a visual difference between two labels

=item *

Creating a visual difference between a label and a directory

=item *

Creating a visual difference between two directories.

=back

The program will:

=over 8

=item *

Create two dynamic views based on the provided label

=item *

Invoke BeyondCompare to allow visual inspection of the two software versions.

=item *

Delete the views when the comparison is complete.

=back

If one of the labels is of the form:

=over 8

=item *

current

=item *

current=path

=item *

dir=path

=back

Then the label will be treated as a directory and will be used for one side
of the comparison.

The program uses a global administration view for the purposes of determining
file versions.

Two dynamic views will be created. These should be deleted by this program,
but may remain if the command line program is terminated.

The user must have relevant VOBs mounted on there machine for this utility to
operate correctly.

=cut