Subversion Repositories DevTools

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
227 dpurdie 1
########################################################################
2
# Copyright (C) 1998-2007 ERG Limited, All rights reserved
3
#
4
# Module name   : CCdiff.pl
5
# Module type   : Makefile system
6
# Compiler(s)   : n/a
7
# Environment(s): JATS. This script is designed to be run under JATS
8
#
9
# Description   : Make ClearCase difference report suitable for uploading
241 dpurdie 10
#                 to Code Striker.
227 dpurdie 11
#......................................................................#
12
 
13
require 5.6.1;
14
use strict;
15
use warnings;
16
use JatsError;
17
use JatsSystem;
18
use Pod::Usage;                             # required for help support
19
use Getopt::Long;
247 dpurdie 20
use FileUtils;
227 dpurdie 21
 
241 dpurdie 22
#-------------------------------------------------------------------------------
23
#
24
#  Function Prototypes
25
#
247 dpurdie 26
sub populateFilesArray($$$\%);
27
sub files_from_view($$$$\%);
28
sub generateOutputFilename(\$);
29
sub getTags();
30
sub parseTag(\$\$\$);
31
sub getClearToolFindOutput($$);
32
sub element0($);
33
sub getIds($@);
34
sub massage_path($\$$\$);
227 dpurdie 35
 
241 dpurdie 36
#-------------------------------------------------------------------------------
37
#
38
#  Global variables
39
#
227 dpurdie 40
 
247 dpurdie 41
#
42
# Update this:
43
#
44
my $VERSION = "1.0.3";                      
241 dpurdie 45
 
227 dpurdie 46
#
247 dpurdie 47
#  Globals that can be set immediately
227 dpurdie 48
#
247 dpurdie 49
my $ats = "@@";
50
my $UNIX = $ENV{'GBE_UNIX'};
51
my $UNIX_VOB_PREFIX = '/vobs';
52
my $VOB_SEP = $UNIX ? '/' : '\\';
227 dpurdie 53
 
54
#
55
#   Options
56
#
57
my $opt_debug   = $ENV{'GBE_DEBUG'};        # Allow global debug
58
my $opt_verbose = $ENV{'GBE_VERBOSE'};      # Allow global verbose
59
my $opt_help = 0;
60
my $opt_manual = 0;
61
my $opt_drive = $UNIX ? '/view' : 'o:';
62
my $opt_viewname = 'administration_view';
63
my $opt_outfile;
64
my @opt_vobs;
247 dpurdie 65
my $opt_new;
66
my $opt_old;
67
my $opt_massage = 1;
227 dpurdie 68
 
69
#
247 dpurdie 70
#  Globals that are set within the script
227 dpurdie 71
#
72
my @error_list;                             # ClearCmd detected errors
73
my $view_path;
74
my @view_tags;
75
my %files;
247 dpurdie 76
my %clearCaseInfos;
227 dpurdie 77
 
247 dpurdie 78
my $oldLabel;
79
my $newLabel;
80
my $oldDirectory;
81
my $newDirectory;
82
 
227 dpurdie 83
#
84
#   ROOT_VOBS is a list of VOBS too look in first
85
#   If a label is not found in these vobs, then the program will
86
#   look in all vobs. This list is a hint to speed up searching
87
#
88
my @ROOT_VOBS = qw( /LMOS /DPG_SWBase /DPG_SWCode /ProjectCD /MASS_Dev_Bus
89
                    /MASS_Dev_Infra /MOS /MASS_Dataman /MASS_Dev /MASS_Dev_Dataman
90
                    /COTS /GMPTE2005 /GMPTE2005_obe /MPR /MOS );
91
 
92
#-------------------------------------------------------------------------------
93
#
247 dpurdie 94
#  Mainline entry point
227 dpurdie 95
#
247 dpurdie 96
InitFileUtils();
227 dpurdie 97
 
98
#
99
#   Parse the user options
100
#
101
my $result = GetOptions (
247 dpurdie 102
    "help+"         => \$opt_help,              # flag, multiple use allowed
103
    "manual"        => sub{ $opt_help = 3},     # flag, multiple use allowed
104
    "verbose+"      => \$opt_verbose,           # flag, multiple use allowed
105
    "output=s"      => \$opt_outfile,           # String
106
    "new=s"         => \$opt_new,               # String
107
    "old=s"         => \$opt_old,               # String
108
    "drive=s"       => \$opt_drive,             # String
109
    "vob=s"         => \@opt_vobs,              # String
110
    "massage!"      => \$opt_massage,           # [no]flag
111
    );
227 dpurdie 112
 
247 dpurdie 113
#
114
#   UPDATE THE DOCUMENTATION AT THE END OF THIS FILE !!!
115
#
227 dpurdie 116
 
117
#
118
#   Process help and manual options
119
#
120
pod2usage(-verbose => 0, -message => "Version: $VERSION")  if ($opt_help == 1  || ! $result );
121
pod2usage(-verbose => 1)  if ($opt_help == 2);
122
pod2usage(-verbose => 2)  if ($opt_help > 2);
123
 
124
#
125
#   Configure the error reporting process now that we have the user options
126
#
127
ErrorConfig( 'name'    => 'CCDIFF',
128
             'verbose' => $opt_verbose );
129
 
130
#
247 dpurdie 131
#   Work out '$oldLabel', '$newLabel', '$oldDirectory', '$newDirectory' tags
227 dpurdie 132
#
247 dpurdie 133
getTags();
227 dpurdie 134
 
135
Error ("Too many command line arguments" )
136
    unless ( $#ARGV < 0 );
137
 
247 dpurdie 138
generateOutputFilename($opt_outfile);
241 dpurdie 139
 
140
#
227 dpurdie 141
#   Determine the machine type
142
#
143
Verbose ("Machine Type: UNIX=$UNIX");
144
 
145
#
146
#   Ensure that the 'cleartool' program can be located
147
#
148
Verbose ("Locate clearcase utility in users path");
149
Error ("Cannot locate the 'cleartool' utility in the users PATH")
150
    unless ( LocateProgInPath('cleartool', '--All') );
151
 
152
#
247 dpurdie 153
#   Ensure that the 'administration_view' is available
227 dpurdie 154
#   Then start the view, before checking its availability
155
#
241 dpurdie 156
if( ClearCmd('lsview', $opt_viewname) )
227 dpurdie 157
{
158
    Error ("Required view not found: $opt_viewname",
247 dpurdie 159
           "This is a dynamic view that should exist as it is used by the build system");
227 dpurdie 160
}
161
 
241 dpurdie 162
if( ClearCmd( 'startview', $opt_viewname) )
227 dpurdie 163
{
164
    Error ("Cannot start the required view: $opt_viewname");
165
}
166
 
167
$view_path = "$opt_drive/$opt_viewname";
168
$view_path .= $UNIX_VOB_PREFIX if ( $UNIX );
247 dpurdie 169
Error ("Cannot locate the required dynamic view: $view_path",
170
       "The view exits and has been started. It cannot be found")
171
    if ( ! -d $view_path  );
227 dpurdie 172
 
173
#
247 dpurdie 174
#   Determine the list of VOBs to scan for a label
175
#   This may be user specified or all the known vobs
227 dpurdie 176
#
177
if ( @opt_vobs )
178
{
247 dpurdie 179
    #
180
    #   User has provided a list of vobs to search
181
    #   Use this list
182
    #
227 dpurdie 183
    @ROOT_VOBS = ();
184
    foreach my $vob ( @opt_vobs )
185
    {
186
        $vob = '/' . $vob;
187
        $vob =~ s~^$UNIX_VOB_PREFIX~~ if ($UNIX);
241 dpurdie 188
        $vob =~ tr{\\/}{/}s;
227 dpurdie 189
        push @ROOT_VOBS, $vob;
190
    }
191
}
192
else
193
{
247 dpurdie 194
    #
195
    #   Extend the list of ROOT_VOBS with all the known vobs
196
    #   The initial ROOT_VOBS are treated as a "hint" to assist searching
197
    #
227 dpurdie 198
    my $cmd = "cleartool lsvob -short";
199
    open(CMD, "$cmd 2>&1 |") || Error( "can't run command: $!");
200
    while (<CMD>)
201
    {
202
        #
203
        #   Filter output from the user
204
        #
241 dpurdie 205
        s~[\n\r]+$~~;
227 dpurdie 206
        s~^$UNIX_VOB_PREFIX~~ if ($UNIX);
207
        Verbose2("lsvob: $_");
241 dpurdie 208
        tr{\\/}{/}s;
227 dpurdie 209
        push @ROOT_VOBS, $_;
210
    }
211
    close(CMD);
212
}
213
 
214
#
215
#   Ensure the two labels are present - determine the VOB root
216
#
247 dpurdie 217
my $oldLabelVob = $oldLabel ? LocateLabel( $oldLabel ) : "";
218
my $newLabelVob = $newLabel ? LocateLabel( $newLabel ) : "";
227 dpurdie 219
 
220
#
247 dpurdie 221
#   Massage the directory path
222
#   If the user has provided a directory, then we will compare the
223
#   entire contents of the directory against the label
227 dpurdie 224
#
247 dpurdie 225
massage_path( $oldLabelVob, $oldDirectory, $newLabelVob, $newDirectory  )
226
    if ( $opt_massage );
227 dpurdie 227
 
228
#
247 dpurdie 229
#   Locate all files for the two areas
227 dpurdie 230
#
231
{
247 dpurdie 232
    my %initialFilePaths;
233
 
234
    files_from_view( $oldLabelVob, $oldLabel, 1, $oldDirectory, %initialFilePaths );
235
    files_from_view( $newLabelVob, $newLabel, 2, $newDirectory, %initialFilePaths );
236
    #DebugDumpData ("initialFilePaths", \%initialFilePaths );
237
 
238
    populateFilesArray( $oldLabel, 1, $oldDirectory, %initialFilePaths);
239
    populateFilesArray( $newLabel, 2, $newDirectory, %initialFilePaths);
240
    #DebugDumpData ("Files", \%files );
227 dpurdie 241
}
242
 
247 dpurdie 243
 
227 dpurdie 244
#
247 dpurdie 245
#   Have a structure that contains files for both the old and new labels
246
#   Scan the list locating files that are different
227 dpurdie 247
#
248
my @no_text;
249
my $added = 0;
250
my $deleted = 0;
247 dpurdie 251
my $ndiffs = 0;
241 dpurdie 252
my $ifile = 0;
253
 
247 dpurdie 254
Verbose ("Opening file in current directory", $opt_outfile, Getcwd() );
255
open (FO, ">$opt_outfile") || Error ("Cannot open file: $opt_outfile", "Reason: $!");
241 dpurdie 256
 
247 dpurdie 257
foreach my $id ( sort keys %files )
227 dpurdie 258
{
241 dpurdie 259
    $ifile ++;
260
 
247 dpurdie 261
    Verbose("Computing differences for file $ifile/" . scalar(keys %files));
241 dpurdie 262
 
247 dpurdie 263
    my ($hs, $aid);
264
 
265
    if ( $files{$id}{1} && $files{$id}{2} ) #  File exists in both areas:
227 dpurdie 266
    {
247 dpurdie 267
        #
268
        #   Test for files existing in both tags and being identical
269
        #
270
        next if( $files{$id}{1} eq $files{$id}{2} );
271
 
272
        #
273
        #   Files are in both areas, but are different
274
        #   Perform diff. There may be cases where they are really the same text
275
        #   or the only change is in white space.
276
        #
277
        ($hs, $aid) = ClearDiff("-serial_format", "-blank_ignore", $files{$id}{1}, $files{$id}{2});
278
        $ndiffs++ if ( $hs );
227 dpurdie 279
    }
247 dpurdie 280
    elsif( $files{$id}{1} ) # File doesn't exist in 'new' area:
227 dpurdie 281
    {
247 dpurdie 282
        ($hs, $aid) = ClearDiff("-serial_format", $files{$id}{1}, element0($files{$id}{1}) );
283
        $deleted++ if ( $hs );
227 dpurdie 284
    }
247 dpurdie 285
    elsif( $files{$id}{2} ) # File doesn't exist in 'old' area:
227 dpurdie 286
    {
247 dpurdie 287
        ($hs, $aid) = ClearDiff("-serial_format", element0($files{$id}{2}), $files{$id}{2} );
288
        $added++ if ( $hs );
227 dpurdie 289
    }
247 dpurdie 290
    else # bug!
291
    {
292
        Error("Internal BUG in main line!  Please report!",
293
              "id='$id' ifile=$ifile neither has a 1 nor a 2 tag");
294
    }
227 dpurdie 295
 
247 dpurdie 296
    push @no_text, $files{$id}{1} if ( $files{$id}{1} && ! $hs && ! $aid );
297
    push @no_text, $files{$id}{2} if ( $files{$id}{2} && ! $hs && ! $aid );
241 dpurdie 298
}
227 dpurdie 299
 
247 dpurdie 300
close FO;
241 dpurdie 301
 
227 dpurdie 302
#
303
#   Warn about problem files
304
#
305
if ( @no_text )
306
{
307
    Warning ("The following files did not generate any difference report, although",
308
             "they are different. They may be binary files:", @no_text);
309
}
310
 
311
#
312
#   Summary information
313
#
314
Information ("Summary Information",
247 dpurdie 315
             "Old:               : " . $oldLabel ? $oldLabel : $oldDirectory,
316
             "New:               : " . $newLabel ? $newLabel : $newDirectory,
317
             "Files different    : $ndiffs",
227 dpurdie 318
             "Files added        : $added",
319
             "Files deleted      : $deleted",
241 dpurdie 320
             "Files not in report: " . scalar(@no_text),
247 dpurdie 321
             "Output file        : $opt_outfile"
227 dpurdie 322
             );
323
 
247 dpurdie 324
exit (0);
227 dpurdie 325
 
326
 
327
#-------------------------------------------------------------------------------
247 dpurdie 328
# Function        : generateOutputFilename
227 dpurdie 329
#
247 dpurdie 330
# Description     : Works out what the output diff filename should be
241 dpurdie 331
#
247 dpurdie 332
# Inputs          : $oldLabel, $newLabel
241 dpurdie 333
#
247 dpurdie 334
# Input/Output    : reference to $opt_outfile
241 dpurdie 335
#
247 dpurdie 336
# Returns         : 
241 dpurdie 337
#
247 dpurdie 338
sub generateOutputFilename(\$)
241 dpurdie 339
{
247 dpurdie 340
    my $refOpt_outfile = shift;
241 dpurdie 341
 
247 dpurdie 342
    unless( $$refOpt_outfile )
241 dpurdie 343
    {
247 dpurdie 344
        $$refOpt_outfile = "${oldLabel}-${newLabel}-diff.txt" if(  $oldLabel &&  $newLabel );
345
        $$refOpt_outfile = "${oldLabel}-diff.txt"             if(  $oldLabel && !$newLabel );
346
        $$refOpt_outfile = "${newLabel}-diff.txt"             if( !$oldLabel &&  $newLabel );
347
        $$refOpt_outfile = "directoryDifferences-diff.txt"    if( !$oldLabel && !$newLabel );
241 dpurdie 348
 
247 dpurdie 349
        #
350
        #   If the label has ugly characaters in it then we won't be able to create
351
        #   a nice file name. Sanitise the filename
352
        #
353
        $$refOpt_outfile =~ s{[\\/:]+}{_}g;
354
        $$refOpt_outfile =~ s{_+}{_}g;
241 dpurdie 355
    }
356
 
247 dpurdie 357
    #
358
    # Do an early check that output file can be written to
359
    #
360
    open( Z, ">$$refOpt_outfile") or Error("Could not open '$$refOpt_outfile' for writing");
361
    close( Z );
362
    unlink $$refOpt_outfile;
363
}
241 dpurdie 364
 
365
 
247 dpurdie 366
#-------------------------------------------------------------------------------
367
# Function        : getTags
368
#
369
# Description     : Works out whether using labels or directories, and fills in
370
#                   $oldLabel or $oldDirectory
371
#                   $newLabel or $newDirectory
372
#                   Function works with $opt_new, $opt_old, @ARGV
373
#
374
# Inputs          : 
375
#
376
# Returns         : 
377
#
378
sub getTags()
379
{
380
    # If we have two options and no labels, then assign them
381
    if ( ! $opt_new && ! $opt_old )
382
    {
383
        Error ("Must provide two labels on command line unless they are provided " .
384
               "via -old and -new options") if ( $#ARGV < 1 );
241 dpurdie 385
 
247 dpurdie 386
        $opt_old = shift @ARGV;
387
        $opt_new = shift @ARGV;
388
    }
241 dpurdie 389
 
247 dpurdie 390
    Error ("Need to provide the 'new' label/directory") unless ( $opt_new );
391
    Error ("Need to provide the 'old' label/directory") unless ( $opt_old );
392
 
393
    parseTag($opt_old, $oldLabel, $oldDirectory);
394
    parseTag($opt_new, $newLabel, $newDirectory);
395
 
396
    Error("Cannot compare two directories") if( $oldDirectory && $newDirectory );
241 dpurdie 397
}
398
 
399
 
400
#-------------------------------------------------------------------------------
247 dpurdie 401
# Function        : parseTags
241 dpurdie 402
#
247 dpurdie 403
# Description     : Worker function for getTags() - parses a "-new"/"-old" option
241 dpurdie 404
#
247 dpurdie 405
# Inputs          : $retOpt - reference to the command line argument
406
#                   $refLabel - reference to the label variable that may be initialised
407
#                   $refDirectory - reference to the directory variable that may be initialised
241 dpurdie 408
#
247 dpurdie 409
# Returns         : 
241 dpurdie 410
#
247 dpurdie 411
sub parseTag(\$\$\$)
412
{
413
    my ($refOpt,$refLabel,$refDirectory) = @_;
414
 
415
    if( $$refOpt =~ m/^dir=(.*)/ )
416
    {
417
        $$refLabel = "";
418
        $$refDirectory = ($1 eq "current") ? "." : $1;
419
        $$refDirectory =~ tr{\\/}{/}s;
420
        $$refDirectory =~ s~/$~~;
421
    }
422
    elsif( $$refOpt =~ m/^current/ )
423
    {
424
        $$refLabel = "";
425
        $$refDirectory = ".";
426
    }
427
    else
428
    {
429
        $$refLabel = $$refOpt;
430
        $$refDirectory = "";
431
 
432
        #
433
        #   Sanity check
434
        #   Labels shouldn't have directory seperator characters in them
435
        #   The user may have mis-used the command
436
        #
437
        if ( $$refOpt =~ m~[/\\]~  )
438
        {
439
            Warning("Label has slashes in it. Looks like a directory",
440
            "Did you mean 'dir=$$refOpt'?",
441
            "Continuing anyway...");
442
        }
443
    }
444
}
445
 
446
#-------------------------------------------------------------------------------
447
# Function        : populateFilesArray
241 dpurdie 448
#
247 dpurdie 449
# Description     : Populates the global '%files' hash array.  It does this
450
#                   by taking as input a hash array that is the output of cleartool
451
#                   find/ls, and, for files that did not come up identical for both
452
#                   old and new labels, calling cleartool dump to get the info
453
#                   to put into the '%files' hash.
454
#
455
# Inputs          : $label          - Label (not set if $directory defined)
456
#                   $tag            - File tag (1 for 'old' or 2 for 'new')
457
#                   $directory      - Directory name (not set if $label defined)
458
#                   $refInitialFilePaths - reference to the hash array that stores the
459
#                                          output of previous calls to cleartool find/ls.
460
#
461
# Returns         : Nothing
462
#                   Populates the %files array
463
#
464
sub populateFilesArray($$$\%)
241 dpurdie 465
{
247 dpurdie 466
    my ($label, $tag, $directory, $refInitialFilePaths) = @_;
241 dpurdie 467
 
247 dpurdie 468
    #######################
469
    # Step 1: Get an array of filenames
470
    my @initialFilePaths;
241 dpurdie 471
 
247 dpurdie 472
    foreach my $initialFilePath (sort keys %$refInitialFilePaths)
473
    {
474
        # If a file exists in both labels and has the same initial file path
475
        # we just assume that the ids are identical and that 
476
        # cleartool dump does not need to be called
477
        # This saves execution time.
478
        # Instead - we just use the file path as the id
479
        #
480
        if( $$refInitialFilePaths{$initialFilePath}{1} && 
481
            $$refInitialFilePaths{$initialFilePath}{2} )
482
        {
483
            $files{$initialFilePath}{$tag} = $initialFilePath;
484
            next;
485
        }
241 dpurdie 486
 
247 dpurdie 487
        push @initialFilePaths, $initialFilePath 
488
            if( $$refInitialFilePaths{$initialFilePath}{$tag} );
489
    }
241 dpurdie 490
 
247 dpurdie 491
    #######################
492
    # Step 2: Call cleartool dump on each of these initial filenames and get the ids
493
    # Then populate the %files array
494
    #
495
    #   In practice this will only be used when one side of the comarison
496
    #   is a directory. Should be able to use this knowledge
497
    #
498
    my @ids = getIds( $tag, @initialFilePaths );
499
#DebugDumpData ("IDS", \@ids);
500
 
501
    #
502
    #   Populate the 'files' hash
503
    #   Keys are: element number and tag
504
    #   This groups files that are the same element together
505
    #   They may be different versions of the element
506
    #
507
    #   The value is the vob extended pathname within the admin vob
508
    #   This can be used to extract the file in any view
509
    #
510
    foreach my $datap ( @ids )
241 dpurdie 511
    {
247 dpurdie 512
        my $pname = $datap->{pname};
513
        my $element = $datap->{element};
514
        $files{$element}{$tag} = $pname;
241 dpurdie 515
    }
516
}
517
 
247 dpurdie 518
 
241 dpurdie 519
#-------------------------------------------------------------------------------
247 dpurdie 520
# Function        : files_from_view
241 dpurdie 521
#
247 dpurdie 522
# Description     : Fills in the hash array 'initialFilePaths' with filename paths
523
#                   If a label, uses cleartool find
524
#                   If a directory, then cleartool ls is used
241 dpurdie 525
#
247 dpurdie 526
# Inputs          : $vpath          - Path to the view
527
#                   $label          - Label (not set if $directory defined)
528
#                   $tag            - File tag (1 for 'old' or 2 for 'new')
529
#                   $directory      - Directory name (not set if $label defined)
530
#                   $refInitialFilePaths - reference to hash array of filename paths
241 dpurdie 531
#
247 dpurdie 532
# Returns         : Nothing
241 dpurdie 533
#
247 dpurdie 534
sub files_from_view($$$$\%)
241 dpurdie 535
{
247 dpurdie 536
    my ($vpath, $label, $tag, $directory, $refInitialFilePaths) = @_;
241 dpurdie 537
 
247 dpurdie 538
    if( $label )
241 dpurdie 539
    {
247 dpurdie 540
        #
541
        #   Ensure that the VOB is mounted
542
        #   The mount command MUST have the correct vob format
543
        #
544
        my $vob_name = $vpath;
545
        $vob_name =~ s~^/+~~;
546
        ClearCmd ('mount', $VOB_SEP . $vob_name);
241 dpurdie 547
 
247 dpurdie 548
        my @initialFilePaths = getClearToolFindOutput( $vpath, $label );
241 dpurdie 549
 
247 dpurdie 550
        foreach my $initialFilePath (@initialFilePaths)
551
        {
552
            $$refInitialFilePaths{$initialFilePath}{$tag} = 1;
553
        }
554
    }    
555
    else
556
    {
557
        my $nfilesStartedWith = scalar(keys %$refInitialFilePaths);
558
        my @checkedout;
241 dpurdie 559
 
247 dpurdie 560
        #
561
        #   Locate files in the specified directory
562
        #   Use an absolute directory to simplify location of files
563
        #   Will cause output of the 'ls' to have absolute paths, which is good
564
        #
565
        $directory = FullPath( $directory );
566
        my $cmd = QuoteCommand( 'cleartool', 'ls', '-recurse', $directory);
241 dpurdie 567
 
247 dpurdie 568
        Message("Cleartool: searching for clearcase elements in '$directory'");
241 dpurdie 569
 
247 dpurdie 570
        open( CMD, "$cmd 2>& 1 |") or Error("can't run command: $!");
571
        while( <CMD> )
572
        {
573
            # Each line will be of the form (e.g.):
574
            # ./LIB/JatsMakeConfig.pm@@/main/4         Rule: core_devl_2.73.2000.cr
241 dpurdie 575
 
247 dpurdie 576
            s~[\n\r]+$~~;
241 dpurdie 577
 
247 dpurdie 578
            #
579
            #   Only want the files known to ClearCase
580
            #   These will have a 'Rule:'
581
            #
582
            #   If the user has checkedout files, then all of this will
583
            #   not work
584
            #
585
            if ( m{(.+?)\s+Rule:(.+)} )
586
            {
587
                my $files = $1;
588
                my $rule = $2;
241 dpurdie 589
 
247 dpurdie 590
                $files =~ tr{\\/}{/}s;  # Replace \ and / with /
591
                (my $actualFilePath = $files) =~ s~${ats}.*~~;
241 dpurdie 592
 
247 dpurdie 593
                if ( $rule =~ m/CHECKEDOUT/ )
594
                {
595
                    push @checkedout, $actualFilePath;
596
                }
241 dpurdie 597
 
247 dpurdie 598
                #
599
                #   Don't want to know about directories
600
                #
601
                next if( -d $actualFilePath );
241 dpurdie 602
 
247 dpurdie 603
                #
604
                #   Save files name, with embedded version
605
                #
606
                $$refInitialFilePaths{$files}{$tag} = 1;
607
            }
608
        }
609
        close( CMD );
610
 
611
        Message ("There are " . (scalar(keys %$refInitialFilePaths) - $nfilesStartedWith) . 
612
             " files in directory $directory");
613
 
614
        #
615
        #   Files that are checked otu are bad news. They cannot be reproduced
616
        #   on demand. Generate an error
617
        #
618
        if ( @checkedout )
619
        {
620
            Error ("Processed directory contains checked out files",
621
                   "Not supported by this tool. Files are:", @checkedout );
622
        }
241 dpurdie 623
    }
624
}
625
 
247 dpurdie 626
 
241 dpurdie 627
#-------------------------------------------------------------------------------
247 dpurdie 628
# Function        : getClearToolFindOutput
241 dpurdie 629
#
247 dpurdie 630
# Description     : Runs cleartool find on a label
631
#                   Runs in the adbinistration view so that the paths that
632
#                   are provided are vob extended.
241 dpurdie 633
#
247 dpurdie 634
# Inputs          : $vpath, $label
241 dpurdie 635
#
247 dpurdie 636
# Returns         : An array of the output lines of cleartool find
241 dpurdie 637
#
247 dpurdie 638
sub getClearToolFindOutput($$)
241 dpurdie 639
{
247 dpurdie 640
    my ($vpath,$label) = @_;
641
 
642
    my $cmd = qq(cleartool find "$opt_drive/$opt_viewname/$vpath" -all -follow -type f -element "lbtype_sub($label)" -version "lbtype_sub($label)" -print);
241 dpurdie 643
 
247 dpurdie 644
    Message ("Cleartool: searching for files with label '$label'");
241 dpurdie 645
 
247 dpurdie 646
    my @outputLines;
647
 
648
    # A typical line of output:
649
    #/view/administration_view/vobs/MASS_Dev_Infra/core_devl@@/main/mass_dev/1/BIN.win32/main/mass_dev/1/printenv.exe@@/main/mass_dev/1
650
 
651
    open(CMD, "$cmd 2>&1 |") || Error "Can't run command: $!";
652
    while (<CMD>)
241 dpurdie 653
    {
247 dpurdie 654
        s~\s+$~~;           # Remove white space including newline/returns
655
        tr{\\/}{/}s;        # Replace \ and / with /
656
        next if( -d $_ );   # -d tests if file is a directory
657
        Verbose2 ("ctf: $_");
658
        push @outputLines, $_;
241 dpurdie 659
    }
247 dpurdie 660
    close(CMD);
241 dpurdie 661
 
247 dpurdie 662
    Message("There are " . scalar(@outputLines) . " files in $opt_drive/$opt_viewname/$vpath");
663
 
664
    return @outputLines;
241 dpurdie 665
}
666
 
667
 
668
#-------------------------------------------------------------------------------
247 dpurdie 669
# Function        : getIds
241 dpurdie 670
#
247 dpurdie 671
# Description     : Calls cleartool dump to retrieve the unique identifer
672
#                   for each of a list of files.
227 dpurdie 673
#
247 dpurdie 674
# Inputs          : $tag
675
#                   @initialFilePaths - a list of filenames with @@'s in them.
227 dpurdie 676
#
247 dpurdie 677
# Returns         : An array of unique identifier strings.  This array has the same
678
#                   size as the input @initialFilePaths - each element is the unique
679
#                   identifier for the corresponding element of that array.
227 dpurdie 680
#
247 dpurdie 681
sub getIds($@)
227 dpurdie 682
{
247 dpurdie 683
    my ($tag,@initialFilePaths) = @_;
684
    my @ids;
685
    my $nfilesPerCallToDump = 20;
227 dpurdie 686
 
687
    #
247 dpurdie 688
    #   Change to the directory that contains the admin view
689
    #   This will ensure that the 2nd line of the dump comamnd contains
690
    #   the vob extended pathname within that view. This will be used
691
    #   to simplify the pairing of files
227 dpurdie 692
    #
247 dpurdie 693
    chdir ($view_path) || Error ("Did not chdir to $view_path" );
694
 
695
    while( @initialFilePaths )
696
    {
697
        #
698
        #   Limit the number of files to be processed in one call to the
699
        #   clearcase dump. Iff too many, then the command line will be long.
700
        #   If short ( ie 1 ), then the call overhead is very high
701
        #
702
        my @filesToDump = splice( @initialFilePaths, 0, $nfilesPerCallToDump);
227 dpurdie 703
 
247 dpurdie 704
        #
705
        #   The dump command provides two useful bits of information
706
        #       1) Line1: The vob extended pathname of the files as
707
        #                 seen in the current view, together with some junk
708
        #                 The line contains two @@ which is used by codestriker
709
        #                 Line2 would be better, but doesn't work with
710
        #                 Codestriker
711
        #
712
        #       2) element number
713
        #           This will be the same for all versions of an element
714
        #           This allows files from two views to be correlated
715
        #
716
        #
227 dpurdie 717
 
247 dpurdie 718
        my $cmd2 = QuoteCommand( "cleartool", "dump", @filesToDump);
719
        my @newids;
720
        my %data;
721
        my $line = 0;
722
 
723
        Verbose2("Cleartool: getting unique identifiers for " . scalar(@filesToDump) . " files");
724
 
725
        open(CCI, "$cmd2 2>&1 |") || Error "Can't run command: $!";
726
        while( <CCI> )
727
        {
728
            s~[\n\r]+$~~;
729
 
730
            #
731
            #   Blank entry signals new package
732
            #
733
            unless ( $_ )
734
            {
735
                $line = 0;
736
                %data = ();
737
                next;
738
            }
739
            $line++;
740
 
741
            #
742
            #   Line-1:
743
            #   Path to package as seen from current view
744
            #
249 dpurdie 745
            if ( $line == 1 )
247 dpurdie 746
            {
747
                s{\\}{/}g;
748
                s{\s+\(.+\)$}{};
749
                $data{pname} = $_;
750
                Verbose2 ("ctd: pname: $_");
751
                next;
752
            }
753
 
754
            #
755
            #   Extract the element number
756
            #   This will be common for each file, independent of the version of the
757
            #   file. This allows files from different views to be correlated
758
            #   Line is of the form:
759
            #   elem=596638  branch=596639  ver num=3  line count=526
760
            #
761
            if ( m{^(elem=\d+)} )
762
            {
763
                $data{element} = $1;
764
                Verbose2 ("ctd: elem: $1");
765
                push @newids, {%data};
766
            }
767
        }
768
        close(CCI);
769
 
770
        Error("Internal error in getIds(): Only retrieved " . scalar(@newids) . 
771
              " IDs from a cleartool dump command for " . scalar(@filesToDump) . " files")
772
            if( scalar(@newids) != scalar(@filesToDump) );
773
 
774
        push @ids, @newids;
227 dpurdie 775
    }
241 dpurdie 776
 
247 dpurdie 777
    chdir ($FileUtils::CwdFull) || Error ("Did not chdir to $FileUtils::CwdFull") ;
778
    return @ids;
227 dpurdie 779
}
780
 
247 dpurdie 781
 
227 dpurdie 782
#-------------------------------------------------------------------------------
783
# Function        : ClearDiff
784
#
785
# Description     : Issue a cleartool command
786
#                   Filter out many of the stupid messages
787
#
788
# Inputs          : Options and Command line
789
#
247 dpurdie 790
# Returns         : header_seen         - Bool. Header has been seen
791
#                   identical           - Bool. Files are really the same
227 dpurdie 792
#
793
sub ClearDiff
794
{
795
    my $header_seen = 0;
796
    my $identical = 0;
241 dpurdie 797
    my $cmd = QuoteCommand("cleardiff", @_);
227 dpurdie 798
 
247 dpurdie 799
    Verbose("ClearDiff cmd: $cmd");
227 dpurdie 800
    open(CMD, "$cmd 2>&1 |") || Error "can't run command: $!";
241 dpurdie 801
 
227 dpurdie 802
    while (<CMD>)
803
    {
247 dpurdie 804
        Verbose2("ClearDiff: $_");
227 dpurdie 805
        $header_seen = 1
806
            if ( m~^[*]{32}~ );
807
        unless ( $header_seen )
808
        {
247 dpurdie 809
            $identical = 1 if ( m~^Files are identical~ );
227 dpurdie 810
            next;
811
        }
812
 
813
        #
814
        #   Filter output from the user
815
        #
816
        s~(file [12]: )$view_path/~$1/~i;
817
        print FO $_;
818
    }
819
    close(CMD);
820
 
821
    #
822
    #   Ensure the section ends with a complete line
823
    #   An extra line doesn't affect CS parsing, but without it any file
824
    #   without a trailing \n will kill the header parsing
825
    #
826
    print FO "\n" if($header_seen);
827
 
828
    return $header_seen, $identical;
829
}
830
 
247 dpurdie 831
 
227 dpurdie 832
#-------------------------------------------------------------------------------
833
# Function        : ClearCmd
834
#
835
# Description     : Execute a cleartool command
836
#                   Capture error messages only
837
#
838
# Inputs          : Command to execute
839
#
840
# Returns         : Exit code
841
#                   Also the global @error_list
842
#
843
sub ClearCmd
844
{
241 dpurdie 845
    my $cmd = QuoteCommand( @_ );
846
 
847
    @error_list = ();    
848
    open(CMD, "cleartool $cmd  2>&1 |")    || Error "can't run command: $!";
849
    while (<CMD>)
850
    {
247 dpurdie 851
        s~[\n\r]+$~~;
852
        Verbose2 ($_);
853
        push @error_list, $_ if ( m~Error:~ );
241 dpurdie 854
    }
855
    close(CMD);
227 dpurdie 856
 
247 dpurdie 857
    Verbose2 ("ClearCmd: Exit Status: $?");
858
 
241 dpurdie 859
    return ($?) / 256;
227 dpurdie 860
}
861
 
247 dpurdie 862
 
227 dpurdie 863
#-------------------------------------------------------------------------------
864
# Function        : LocateLabel
865
#
241 dpurdie 866
# Description     : Determine the VOBs that contains the specified label
227 dpurdie 867
#
868
# Inputs          : $label  - Label to locate
869
#
241 dpurdie 870
# Returns         : First VOB that contains the label
227 dpurdie 871
#
872
sub LocateLabel
873
{
874
    my ($label) = @_;
875
 
876
    Message ("Locate label in VOB: $label" );
247 dpurdie 877
 
227 dpurdie 878
    my $found = 0;
879
    foreach my $vob ( @ROOT_VOBS )
880
    {
241 dpurdie 881
        $vob = $UNIX_VOB_PREFIX . $vob if ( $UNIX && $vob !~ m~^${UNIX_VOB_PREFIX}~ );
227 dpurdie 882
        (my $vob_name = $vob) =~ s~/~$VOB_SEP~g;
883
 
247 dpurdie 884
        Verbose ("Examine label $label in vob: $vob" );
227 dpurdie 885
 
886
        my $cmd = "cleartool lstype \"lbtype:$label\@$vob_name\"";
247 dpurdie 887
 
227 dpurdie 888
        open(CMD, "$cmd 2>&1 |") || Error( "can't run command: $!");
889
        while (<CMD>)
890
        {
891
            #
892
            #   Filter output from the user
893
            #
247 dpurdie 894
            s~[\n\r]+$~~;
241 dpurdie 895
            Verbose2 ("lstype: $_");
227 dpurdie 896
            next if ( m~Error~ );
897
            next unless ( m~label type~ );
898
            $found = $vob;
247 dpurdie 899
 
227 dpurdie 900
            last;
901
        }
247 dpurdie 902
        while( <CMD> ){} # Get rid of broken pipe messages
227 dpurdie 903
        close(CMD);
904
        last if ( $found );
905
    }
906
 
907
    Error ("Label $label not found in @ROOT_VOBS")
908
        unless ( $found );
909
 
910
    Verbose ("Label $label found in $found");
911
    return $found;
912
}
913
 
914
 
915
#-------------------------------------------------------------------------------
916
# Function        : element0
917
#
918
# Description     : Given a branch version, this function will return the
919
#                   zero-th element on the branch
920
#
921
#                   ie: /DPG_SWBase/file@@some_branch/12
922
#                   ->  /DPG_SWBase/file@@some_branch/0
923
#
924
# Inputs          : $element
925
#
926
# Returns         : as described
927
#
247 dpurdie 928
sub element0($)
227 dpurdie 929
{
930
    my ($element) = @_;
247 dpurdie 931
    $element =~ s~/\d+$~/0~;
227 dpurdie 932
    return $element;
933
}
934
 
247 dpurdie 935
 
227 dpurdie 936
#-------------------------------------------------------------------------------
247 dpurdie 937
# Function        : massage_path
227 dpurdie 938
#
247 dpurdie 939
# Description     : Massage the user directory, if specified, such that
940
#                   it describes the root of the vob.
227 dpurdie 941
#
247 dpurdie 942
# Inputs          : $oldLabelVob
943
#                   $oldDirectory
944
#                 : $newLabelVob
945
#                   $newDirectory
227 dpurdie 946
#
247 dpurdie 947
# Returns         : Modifies $newDirectory or $oldDirectory
227 dpurdie 948
#
247 dpurdie 949
#
950
sub massage_path($\$$\$)
227 dpurdie 951
{
247 dpurdie 952
    my ($oldLabelVob, $oldDirectory, $newLabelVob, $newDirectory ) = @_;
227 dpurdie 953
 
954
    #
247 dpurdie 955
    #   If the user is comparing two labels, then there is nothing to do
227 dpurdie 956
    #
247 dpurdie 957
    return unless ( $$newDirectory || $$oldDirectory );
958
 
959
    #
960
    #   Figure out which ones to use
961
    #
962
    my $vob = $$newDirectory ? $oldLabelVob : $newLabelVob;
963
    my $directory = $$newDirectory ? $newDirectory : $oldDirectory;
964
 
965
    #
966
    #   Walk up the directory until we find the vob root
967
    #   The vob has a leading /
968
    #
969
    my $dir = $$directory;
970
    while ( $$directory )
227 dpurdie 971
    {
247 dpurdie 972
        if ( $$directory =~ m{(.*)\Q$vob\E$} )
973
        {
974
            Verbose ("Massaged path to: $$directory");
975
            return;
976
        }
977
        last unless ($$directory =~ s{/[^/]+$}{});
227 dpurdie 978
    }
247 dpurdie 979
    Error ("Could not find vob root in user directory",
980
           "Vob Root: $vob",
981
           "Path : $dir");
227 dpurdie 982
 
983
}
984
 
985
#-------------------------------------------------------------------------------
986
#   Documentation
987
#
988
 
989
=pod
990
 
991
=head1 NAME
992
 
993
CCdiff - ClearCase Difference Report
994
 
995
=head1 SYNOPSIS
996
 
247 dpurdie 997
jats CCdiff [options] [old-label new-label]
227 dpurdie 998
 
247 dpurdie 999
Options:
227 dpurdie 1000
 
247 dpurdie 1001
  -help              - brief help message
1002
  -help -help        - Detailed help message
1003
  -man               - Full documentation
1004
  -old=label         - Old label (or dir=path)
1005
  -new=label         - New label (or dir=path)
1006
  -output=file       - Output filename
1007
  -vob=name          - Vob for labels
1008
  -drive=path        - Alternate vob location
1009
  -[no]massage       - Massage the user path [default]
1010
 
227 dpurdie 1011
=head1 OPTIONS
1012
 
1013
=over 8
1014
 
1015
=item B<-help>
1016
 
1017
Print a brief help message and exits.
1018
 
1019
=item B<-help -help>
1020
 
1021
Print a detailed help message with an explanation for each option.
1022
 
1023
=item B<-man>
1024
 
1025
Prints the manual page and exits.
1026
 
1027
=item B<-old=label>
1028
 
1029
This option specifies the old, or base, label for the difference report. This
247 dpurdie 1030
label is mandatory for the difference report.
227 dpurdie 1031
 
247 dpurdie 1032
The old and new labels may be provided on the command line, or via named
1033
options, but not both.
1034
 
1035
The label may be of the form dir=path to force the utility to use a local
1036
view or path, within a cleacsae view.
1037
 
227 dpurdie 1038
=item B<-new=label>
1039
 
1040
This option specifies the new, or current, label for the difference report. This
1041
label is mandatory for the difference report.
1042
 
1043
The old and new labels may be provided on the command line, or via named
1044
options, but not both.
1045
 
247 dpurdie 1046
The label may be of the form dir=path to force the utility to use a local
1047
clearcase view. The utility understands:
1048
 
1049
=over 8
1050
 
1051
=item *-new=dir=some_path  and dir=some_path
1052
 
1053
=item *-new=dir=current and dir=current
1054
 
1055
=item *-new=current and current
1056
 
1057
=back
1058
 
1059
The utiliity cannot compare two directories. It can only compare a directory
1060
against a labeled version. It will adjust the user-provided path to backtrack
1061
to the root of the view. The comparision is not limited to the specified
1062
sub-tree; it will always be the complete view.
1063
 
1064
All files within the view directory must be checked in. The utility will not
1065
process the directory if any files or directories are checkedout. The utility
1066
will ignore files that are not version controlled.
1067
 
227 dpurdie 1068
=item B<-vob=name>
1069
 
1070
This option limits the label search to the specified VOB. This option may be
1071
needed if the labels are to be found in multiple VOBs.
1072
 
1073
This option may be used multiple times. All specified vobs will be searched and
1074
the first one containing the label will be used.
1075
 
1076
=item B<-output=file>
1077
 
1078
This option specifies the output filename. The program will generate an output
1079
file based on the two source labels.
1080
 
1081
=item B<-drive=path>
1082
 
1083
This option allows the user to provide an alternate location for the
1084
administration vob used by the program. The default location is:
1085
 
247 dpurdie 1086
=item B<-[no]massage>
1087
 
1088
If the user has provided a directory path, then it will be massaged such that
1089
the comparison will include the entire VOB.
1090
 
1091
The default operation is to massage the path. This can be suppressed if required.
1092
 
227 dpurdie 1093
=over 8
1094
 
1095
=item * Windows o:
1096
 
1097
=item * Unix /view
1098
 
1099
=back
1100
 
247 dpurdie 1101
=back
1102
 
227 dpurdie 1103
=head1 DESCRIPTION
1104
 
1105
This program is the primary tool for creating 'diff' reports to be uploaded to
1106
Code Striker.
1107
 
1108
The program will determine the files that are different between the two specified
1109
labels. It will determine full pathnames for the files and create a difference
1110
report that is suitable for Code Striker.
1111
 
1112
The program uses a global administration view for the purposes of determining
1113
file versions. The path names that are generated are full vob-extended pathnames.
1114
These may be very long and may not be directly usable under windows.
1115
 
1116
=cut
1117