Subversion Repositories DevTools

Rev

Rev 6085 | Rev 7300 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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