Subversion Repositories DevTools

Rev

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

Rev Author Line No. Line
383 dpurdie 1
########################################################################
2
# Copyright (C) 1998-2012 Vix Technology, All rights reserved
3
#
4
# Module name   : jats_vcsdiff.pl
5
# Module type   : Makefile system
6
# Compiler(s)   : Perl
7
# Environment(s): jats
8
#
9
# Description   : Create two views and DIFF them
10
#                 The views can be any type understood by JATS
11
#                 Can:
12
#                   - Compare with MD5SUms
13
#                   - Invoke BeyondCompare
14
#
15
#......................................................................#
16
 
17
require 5.008_002;
18
use strict;
19
use warnings;
20
 
21
use Pod::Usage;
22
use Getopt::Long;
23
 
24
use JatsError;
25
use JatsSystem;
26
use FileUtils;
27
use Cwd;
28
 
29
my $VERSION = "1.0.0";                      # Update this
30
 
31
#
32
#   Options
33
#
34
my $opt_debug   = $ENV{'GBE_DEBUG'};        # Allow global debug
35
my $opt_verbose = $ENV{'GBE_VERBOSE'};      # Allow global verbose
36
my $opt_help = 0;
37
my $opt_manual = 0;
38
my $opt_new_label;
39
my $opt_old_label;
40
my $opt_md5check;
41
my $opt_mode;
2931 dpurdie 42
my $opt_diff;
383 dpurdie 43
 
44
#
45
#   Globals - Provided by the JATS environment
46
#
47
my $USER            = $ENV{'USER'};
48
my $UNIX            = $ENV{'GBE_UNIX'};
49
my $TMP             = $UNIX ? "/tmp" : $ENV{'TMP'};
50
my $MACHINENAME     = $ENV{'GBE_HOSTNAME'};
51
 
52
#
53
#   Globals
54
#
2931 dpurdie 55
my $Name            = 'BeyondCompare';
3967 dpurdie 56
my $DiffProg;
2931 dpurdie 57
my @DiffArgs;
58
my $DiffWait;
383 dpurdie 59
my @view_tags;
60
my @view_commands;
61
my @cleanFiles;
62
 
63
 
64
#-------------------------------------------------------------------------------
65
# Function        : Mainline Entry Point
66
#
67
# Description     :
68
#
69
# Inputs          :
70
#
71
 
72
#
73
#   Parse the user options
74
#
75
my $result = GetOptions (
76
                "help+"         => \$opt_help,              # Help level
77
                "manual"        => \$opt_manual,            # Help level
78
                "verbose:+"     => \$opt_verbose,           # Verbosity
79
                "debug:+"       => \$opt_debug,             # Debug Verbosity
80
                "new=s"         => \$opt_new_label,         # Path1
81
                "old=s"         => \$opt_old_label,         # Path2
82
                'check'         => \$opt_md5check,          # Force MD5 Check
2931 dpurdie 83
                'diff!'         => \$opt_diff,              # Force use of diff
383 dpurdie 84
                );
85
 
86
                #
87
                #   UPDATE THE DOCUMENTATION AT THE END OF THIS FILE !!!
88
                #
89
 
90
#
91
#   Process help and manual options
92
#
93
pod2usage(-verbose => 0, -message => "Version: $VERSION")  if ($opt_help == 1  || ! $result );
94
pod2usage(-verbose => 1)  if ($opt_help == 2 );
95
pod2usage(-verbose => 2)  if ($opt_manual || ($opt_help > 2));
96
 
97
InitFileUtils();
98
 
99
#
100
#   Configure the error reporting process now that we have the user options
101
#
102
ErrorConfig( 'name'    => 'VCSDIFF',
103
             'verbose' => $opt_verbose,
104
             'debug'   => $opt_debug );
105
 
2931 dpurdie 106
Error ("Options -check and -diff cannot be combined")
107
    if ( $opt_md5check && $opt_diff );
108
 
383 dpurdie 109
#
110
#   Determine mode
111
#   Not all modes work on all machines
112
#
113
Verbose ("Machine Type: UNIX=$UNIX");
114
if ( $opt_md5check )
115
{
116
    $opt_mode = 'md5';
117
}
2931 dpurdie 118
elsif ( $UNIX || $opt_diff )
119
{
120
    $opt_mode = 'diff';
121
    $Name = 'diff';
122
    push @DiffArgs, '-r';
123
    $Name = 'gdiff';
124
    $DiffProg = LocateProgInPath( $Name, '--All');
125
    unless ( $DiffProg =~ m~/~ )
126
    {
127
        $Name = 'diff';
128
        $DiffProg = LocateProgInPath( $Name, '--All');
129
    }
130
 
131
    Error ("Cannot locate a 'diff' utility in the users PATH")
132
        unless ( $DiffProg =~ m~/~ );
133
}
383 dpurdie 134
else
135
{
136
    $opt_mode = 'bc2';
2931 dpurdie 137
    $DiffWait = 1;
383 dpurdie 138
 
139
    #
3967 dpurdie 140
    #   Determine the path to Beyond Compare Exe
141
    #       It may not be installed in the default place, but the Windows
142
    #       registry will know where it is
383 dpurdie 143
    #
3967 dpurdie 144
    GetBeyondCompareExePath();
383 dpurdie 145
}
146
 
147
#
148
#   Validate user options
149
#
150
#   Be nice to the user
151
#   If we have two options and no labels, then assign them
152
#
153
if ( ! $opt_new_label && ! $opt_old_label )
154
{
155
    Error ("Must provide two labels on command line unless they are provided via -old and -new options")
156
         if ( $#ARGV < 1 );
157
 
158
    $opt_old_label = shift @ARGV;
159
    $opt_new_label = shift @ARGV;
160
}
161
 
162
Error ("Need two labels on the command line, or via options")
163
    unless ( $opt_old_label && $opt_new_label );
164
 
165
Error ("Too many command line arguments" )
166
    unless ( $#ARGV < 0 );
167
 
168
#
169
#   Extract parameters that will be used to create a view that is
170
#   unique. Will use hostname and user name
171
#
172
Error ("Machine Name not determined")
173
    unless ( $MACHINENAME );
174
 
175
Error ("USER name not determined" )
176
    unless ( $USER );
177
 
178
#
179
#   Need a TMP working directory
180
#   Used to create config files
181
#
182
Error ("TMP not found or not a directory")
183
    unless ( $TMP && -d $TMP );
184
$TMP = "$TMP/$$";
185
 
186
#
187
#   Create views for the two views
188
#   Verify that the view are present
189
#
190
Message ("Constructing views");
191
my $path1 = create_view( $opt_old_label, 1 );
192
my $path2 = create_view( $opt_new_label, 2 );
193
 
194
Error ("Cannot locate view directory: $path1" ) unless (-d $path1);
195
Error ("Cannot locate view directory: $path2" ) unless (-d $path2);
196
 
197
#
198
#   If one of the paths is a dynamic view and the other is a local path
199
#   then attempt to locate the common directories
200
#
201
if ( $#view_tags == 0 )
202
{
203
    massage_paths();
204
}
205
 
206
if ( $opt_md5check )
207
{
208
    Verbose ("Performing MD5 Check");
209
    my $checkfile = 'vcsdiff_md5.txt';
210
    my $rv;
211
    push @cleanFiles, $checkfile;
212
    $rv = JatsTool ('jats_manifest', '-quiet',
213
                '-manifest', $checkfile,
214
                '-rootdir', $path1 );
215
 
216
    $rv = JatsTool ('jats_manifest', '-quiet', '-check',
217
                '-manifest', $checkfile,
218
                '-rootdir', $path2 ) unless $rv;
219
 
220
    exit $rv;
221
}
222
 
2931 dpurdie 223
#
224
#   Diffing the paths
225
#   Will use BeyondCompare under Windows
226
#   Will use diff under unix
227
#
228
Message ("Using '$Name' to compare two views",
229
         "Wait for utility to exit so that we can delete the views" ) if ($DiffWait);
383 dpurdie 230
 
2931 dpurdie 231
Verbose ("Diff Utility: $DiffProg");
232
System ( $DiffProg, @DiffArgs, $path1, $path2 );
383 dpurdie 233
exit 0;
234
 
235
#-------------------------------------------------------------------------------
236
# Function        : create_view
237
#
238
# Description     : Create dynamic view, based on a Vcs Tag
239
#
240
# Inputs          : $vcstag
241
#
242
# Returns         : Path to the view
243
#
244
sub create_view
245
{
246
    my ($vcstag, $num) = @_;
247
 
248
    #
249
    #   Intercept and treat the special label 'current'
250
    #
251
    return create_path_view( $vcstag )
252
        if ( $vcstag eq 'current'  || $vcstag =~ m~^dir=.+~ || $vcstag =~ m~^current=.+~ );
253
 
254
    my $tag = "${USER}_${MACHINENAME}_vcsdiff_${num}";
255
    push @view_tags, $tag;
256
 
257
    #
258
    #   Use vcsrelease to do the hard work
259
    #
260
    my @command = ( 'jats_vcsrelease',
261
                        '-extractfiles',
262
                        '-root=.' ,
263
                        '-noprefix',
1403 dpurdie 264
                        '-devmode=escrow',
383 dpurdie 265
                        '-view', $tag ,
266
                        '-label', $vcstag,
267
                   );
268
    push @view_commands, \@command;
269
 
270
    if ( $opt_debug && -d $tag )
271
    {
272
        Message ("Using existing view");
273
    }
274
    else
275
    {
276
        JatsTool( @command );
277
    }
278
 
279
    #
280
    #   Minor Kludge
281
    #       Should be in a library
282
    #   Iff CC::, then process path info too
283
    #
284
    if ( $vcstag =~ m~^CC::(.*?)(::(.+))?$~ )
285
    {
286
        my $path = $1;
287
        if ( $path )
288
        {
289
            my $try = $tag . '/' . $path;
290
            if ( -d  $try )
291
            {
292
                $tag = $try;
293
            }
294
        }
295
    }
296
 
297
    return $tag;
298
}
299
 
300
#-------------------------------------------------------------------------------
301
# Function        : create_path_view
302
#
303
# Description     : Not using a view, using a path
304
#                   Return the path as requested
305
#
306
# Inputs          : $label                  - with embedded path
307
#
308
# Returns         : Path to the (dummy) view
309
#
310
sub create_path_view
311
{
312
    my ($label) = @_;
313
    my $path  = '.';
314
 
315
    $path = $1
316
        if ( $label =~ m~.+=(.+)~ );
317
 
318
    Error ("Directory not found: $path" )
319
        unless ( -d $path );
320
 
321
    $path = FullPath( $path );
322
    return $path;
323
}
324
 
325
#-------------------------------------------------------------------------------
326
# Function        : massage_paths
327
#
328
# Description     : Used when one of the paths is a view and the the other
329
#                   is a local directory.
330
#
331
#                   Attempt to locate the common root
332
#
333
# Inputs          : None
334
#
335
# Returns         : Modifies $path1 and $path2
336
#
337
sub massage_paths
338
{
339
    my $view_path = $view_tags[0];
340
    my $user_path = $path1;
341
    $user_path = $path2 if ( $view_path eq $path1 );
342
 
343
    #
344
    #   Split the user path into its component directory entries
345
    #   Start at the top and look for one of these in the view
346
    #
347
    my @user_path = split ('/', $user_path );
348
    my $tpath = '';
349
    foreach my $dir ( @user_path )
350
    {
351
        if ( -d "$view_path/$dir" )
352
        {
353
            #
354
            #   Common directory found
355
            #   Set the user path to the previous directory
356
            #
357
            $user_path = $tpath;
358
            if ( $view_path eq $path1   )
359
            {
360
                $path2 = $user_path;
361
            }
362
            else
363
            {
364
                $path1 = $user_path;
365
            }
366
 
367
            #
368
            #   now add the common part
369
            #
370
            $path1 .= "/$dir";
371
            $path2 .= "/$dir";
372
            Message ("Setting common root path ($dir)", $path1, $path2);
373
            last;
374
        }
375
        $tpath .= '/' if ( $tpath );
376
        $tpath .= $dir;
377
    }
378
}
379
 
380
#-------------------------------------------------------------------------------
3967 dpurdie 381
# Function        : GetBeyondCompareExePath
383 dpurdie 382
#
383
# Description     : Determine the path to the BeyondCompare executable
384
#                   by looking in the Windows Registry
385
#
386
# Inputs          : None
387
#
388
# Returns         : Path to an executable
389
#
390
 
3967 dpurdie 391
sub GetBeyondCompareExePath
383 dpurdie 392
{
393
    eval "require Win32::TieRegistry"
394
        or Error ("Win32::TieRegistry not available");
395
 
396
    my $userKey= Win32::TieRegistry->new("CUser")
397
        or  Error( "Can't access HKEY_CURRENT_USER key: $^E" );
398
 
5240 dpurdie 399
    my $localKey= Win32::TieRegistry->new("LMachine")
400
        or  Error( "Can't access HKEY_LOCAL_MACHINE key: $^E" );
401
 
402
    sub checkKeys
403
    {
404
        my ($userKey, $localKey, $key) = @_;
405
        my ($bcKey, $DiffProg);
406
        $bcKey = $userKey->Open( $key, {Delimiter=>"/"} );
407
        if ($bcKey && ($DiffProg = $bcKey->GetValue( 'ExePath' )) )
408
        {
409
            return $DiffProg;
410
        }
411
        $bcKey = $localKey->Open( $key, {Delimiter=>"/"} );
412
        if ($bcKey && ($DiffProg = $bcKey->GetValue( 'ExePath' )) )
413
        {
414
            return $DiffProg;
415
        }
416
        return undef;
417
    }
418
 
3967 dpurdie 419
    my $bcKey;
5240 dpurdie 420
    if ($DiffProg = checkKeys( $userKey, $localKey,"Software/Scooter Software/Beyond Compare 4" ))
3967 dpurdie 421
    {
5100 dpurdie 422
        Verbose("Using BC4");
423
        push @DiffArgs, '/solo';
424
    }
5240 dpurdie 425
    elsif ($DiffProg = checkKeys( $userKey, $localKey,"Software/Scooter Software/Beyond Compare 3"))
5100 dpurdie 426
    {
3967 dpurdie 427
        Verbose("Using BC3");
428
        push @DiffArgs, '/solo';
429
    }
5240 dpurdie 430
    elsif ($DiffProg = checkKeys( $userKey, $localKey,"Software/Scooter Software/Beyond Compare"))
3967 dpurdie 431
    {
432
        Verbose("Using BC2");
433
    }
434
    else
435
    {
5100 dpurdie 436
        Error "Can't access BC2, BC3 or BC4 Keys: $^E";
3967 dpurdie 437
    }
383 dpurdie 438
 
3967 dpurdie 439
    Error ("BeyondCompare program not found", "Prog: $DiffProg")
440
        unless ( -x $DiffProg );
383 dpurdie 441
}
442
 
443
#-------------------------------------------------------------------------------
444
# Function        : END
445
#
446
# Description     : This function will be called as the program exits
447
#                   It will also be called under error conditions
448
#                   Close down stuff we created
449
#
450
# Inputs          : 
451
#
452
# Returns         : 
453
#
454
 
455
sub END
456
{
457
    my $exitCode = $?;
458
 
459
    if ( $opt_debug )
460
    {
461
        Message ("NOT Cleaning up views");
462
        return;
463
    }
464
 
465
    Message ("Cleaning up views") if @view_tags;
466
    foreach my $cmds ( @view_commands )
467
    {
468
        JatsTool( @{$cmds}, '-delete' );
469
    }
470
 
471
    foreach my $file ( @cleanFiles )
472
    {
473
        unlink $file;
474
    }
475
 
476
    #
477
    #   The exit code may get modified by the JatsTool
478
    #   Preserve any error indication
479
    #
480
    $? = $exitCode;
481
}
482
 
483
#-------------------------------------------------------------------------------
484
#   Documentation
485
#
486
 
487
=pod
488
 
489
=head1 NAME
490
 
491
jats_vcsdiff - Difference two views
492
 
493
=head1 SYNOPSIS
494
 
495
  jats vcsdiff [options] [old_label new_label]
496
 
497
 Options:
498
    -help              - brief help message
499
    -help -help        - Detailed help message
500
    -man               - Full documentation
501
    -check             - Perform MD5SUM over both views
2931 dpurdie 502
    -[no]diff          - Force the use of a 'diff' utility
383 dpurdie 503
    -old=tag           - Old VcsTag (or dir=path)
504
    -new=tag           - New VcsTag (or dir=path)
505
 
506
=head1 OPTIONS
507
 
508
=over 8
509
 
510
=item B<-help>
511
 
512
Print a brief help message and exits.
513
 
514
=item B<-help -help>
515
 
516
Print a detailed help message with an explanation for each option.
517
 
518
=item B<-man>
519
 
520
Prints the manual page and exits.
521
 
522
=item B<-check>
523
 
524
This option controls the mode in which the program will operate.
525
 
2931 dpurdie 526
If enabled the program will perform an MD5 Cheksum over the files in the first
383 dpurdie 527
view and compare that with files in the second view.
528
 
2931 dpurdie 529
This option cannot be used in conjunction with the '-diff' option'.
383 dpurdie 530
 
2931 dpurdie 531
=item B<-diff>
532
 
533
This option controls the mode in which the program will operate.
534
 
535
By default the program is Operating System dependent. It will:
536
 
537
=over 4
538
 
539
=item * Windows - Use Beyond Compare
540
 
541
=item * Unix - Use gdiff or diff
542
 
543
=back
544
 
545
This option will force the use of a 'diff' utility on both Windows and
546
Unix.
547
 
548
This option cannot be used in conjunction with the '-check' option'.
549
 
383 dpurdie 550
=item B<-old=tag>
551
 
552
This option specifies the old, or base, VcsTag for the difference report. This
553
tag is mandatory.
554
 
555
The old and new tags may be provided on the command line, or via named
556
options, but not both.
557
 
558
The tag may be of the form dir=path to force the utility to use a local
559
view or path.
560
 
561
=item B<-new=tag>
562
 
563
This option specifies the new, or current, VcsTag for the difference report. This
564
tag is mandatory.
565
 
566
The old and new tags may be provided on the command line, or via named
567
options, but not both.
568
 
569
The tag may be of the form dir=path to force the utility to use a local
570
view or path.
571
 
572
=back
573
 
574
=head1 DESCRIPTION
575
 
576
This program has two modes of operation:
577
 
578
=over 4
579
 
580
=item 1 MD5Sum of the two views
581
 
2931 dpurdie 582
=item 2 Invoke a differencing program.
383 dpurdie 583
 
2931 dpurdie 584
The program that is invoked is, by default, Operating System dependent. It will:
585
 
586
=over 4
587
 
588
=item * Windows - Use Beyond Compare to perform a visual diff.
589
 
383 dpurdie 590
This mode simplifies the process of perform a code review between two
591
VCS Tags by:
592
 
593
=over 8
594
 
595
=item *
596
 
597
Creating a visual difference between two labels
598
 
599
=item *
600
 
601
Creating a visual difference between a label and a directory
602
 
603
=item *
604
 
605
Creating a visual difference between two directories.
606
 
607
=back
608
 
2931 dpurdie 609
=item * Unix - Use gdiff or diff
610
 
383 dpurdie 611
=back
612
 
2931 dpurdie 613
=back
614
 
383 dpurdie 615
The program will:
616
 
617
=over 8
618
 
619
=item *
620
 
621
Create two 'extract only' views based on the VCS Tags provided. The resultant
622
views are not connected to any version control system.
623
 
624
=item *
625
 
2931 dpurdie 626
Perform the desired operation: MD5Sum or Difference.
383 dpurdie 627
 
628
=item *
629
 
630
Delete the created directories the comparison is complete.
631
 
632
=back
633
 
634
If one of the Vcs Tags is of the form:
635
 
636
=over 8
637
 
638
=item *
639
 
640
current
641
 
642
=item *
643
 
644
current=path
645
 
646
=item *
647
 
648
dir=path
649
 
650
=back
651
 
652
Then the tag will be treated as a directory and will be used for one side
653
of the comparison.
654
 
655
Two directories views will be created. These should be deleted by this program,
656
but may remain if the command line program is terminated.
657
 
658
=head1 EXAMPLE
659
 
660
The following command will compare a Subversion view with a ClearCase view.
661
 
662
    jats vcsdiff SVN::AUPERASVN02/COTS/crc/tags/crc_26.4.0007.cr@18587 CC::/MASS_Dev_Infra/crc::crc_26.4.0006.cr -check
663
 
664
The following command will compare a Subversion View with a local directory
665
 
666
    jats vcsdiff SVN::AUPERASVN02/COTS/crc/tags/crc_26.4.0000.cr dir=crc
667
 
668
=cut
669