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
 
5264 dpurdie 396
    Win32::TieRegistry::import(qw( REG_SZ REG_EXPAND_SZ REG_DWORD REG_BINARY REG_MULTI_SZ KEY_READ KEY_WRITE KEY_ALL_ACCESS ));
397
 
398
    my $userKey= Win32::TieRegistry->new("CUser", {Access=>KEY_READ(),Delimiter=>"/"})
383 dpurdie 399
        or  Error( "Can't access HKEY_CURRENT_USER key: $^E" );
400
 
5264 dpurdie 401
    my $localKey= Win32::TieRegistry->new("LMachine", {Access=>KEY_READ(),Delimiter=>"/"})
5240 dpurdie 402
        or  Error( "Can't access HKEY_LOCAL_MACHINE key: $^E" );
403
 
404
    sub checkKeys
405
    {
406
        my ($userKey, $localKey, $key) = @_;
407
        my ($bcKey, $DiffProg);
5264 dpurdie 408
        $bcKey = $userKey->Open( $key );
5240 dpurdie 409
        if ($bcKey && ($DiffProg = $bcKey->GetValue( 'ExePath' )) )
410
        {
411
            return $DiffProg;
412
        }
5264 dpurdie 413
        $bcKey = $localKey->Open( $key );
5240 dpurdie 414
        if ($bcKey && ($DiffProg = $bcKey->GetValue( 'ExePath' )) )
415
        {
416
            return $DiffProg;
417
        }
418
        return undef;
419
    }
420
 
3967 dpurdie 421
    my $bcKey;
5240 dpurdie 422
    if ($DiffProg = checkKeys( $userKey, $localKey,"Software/Scooter Software/Beyond Compare 4" ))
3967 dpurdie 423
    {
5100 dpurdie 424
        Verbose("Using BC4");
425
        push @DiffArgs, '/solo';
426
    }
5240 dpurdie 427
    elsif ($DiffProg = checkKeys( $userKey, $localKey,"Software/Scooter Software/Beyond Compare 3"))
5100 dpurdie 428
    {
3967 dpurdie 429
        Verbose("Using BC3");
430
        push @DiffArgs, '/solo';
431
    }
5240 dpurdie 432
    elsif ($DiffProg = checkKeys( $userKey, $localKey,"Software/Scooter Software/Beyond Compare"))
3967 dpurdie 433
    {
434
        Verbose("Using BC2");
435
    }
436
    else
437
    {
5100 dpurdie 438
        Error "Can't access BC2, BC3 or BC4 Keys: $^E";
3967 dpurdie 439
    }
383 dpurdie 440
 
3967 dpurdie 441
    Error ("BeyondCompare program not found", "Prog: $DiffProg")
442
        unless ( -x $DiffProg );
383 dpurdie 443
}
444
 
445
#-------------------------------------------------------------------------------
446
# Function        : END
447
#
448
# Description     : This function will be called as the program exits
449
#                   It will also be called under error conditions
450
#                   Close down stuff we created
451
#
452
# Inputs          : 
453
#
454
# Returns         : 
455
#
456
 
457
sub END
458
{
459
    my $exitCode = $?;
460
 
461
    if ( $opt_debug )
462
    {
463
        Message ("NOT Cleaning up views");
464
        return;
465
    }
466
 
467
    Message ("Cleaning up views") if @view_tags;
468
    foreach my $cmds ( @view_commands )
469
    {
470
        JatsTool( @{$cmds}, '-delete' );
471
    }
472
 
473
    foreach my $file ( @cleanFiles )
474
    {
475
        unlink $file;
476
    }
477
 
478
    #
479
    #   The exit code may get modified by the JatsTool
480
    #   Preserve any error indication
481
    #
482
    $? = $exitCode;
483
}
484
 
485
#-------------------------------------------------------------------------------
486
#   Documentation
487
#
488
 
489
=pod
490
 
491
=head1 NAME
492
 
493
jats_vcsdiff - Difference two views
494
 
495
=head1 SYNOPSIS
496
 
497
  jats vcsdiff [options] [old_label new_label]
498
 
499
 Options:
500
    -help              - brief help message
501
    -help -help        - Detailed help message
502
    -man               - Full documentation
503
    -check             - Perform MD5SUM over both views
2931 dpurdie 504
    -[no]diff          - Force the use of a 'diff' utility
383 dpurdie 505
    -old=tag           - Old VcsTag (or dir=path)
506
    -new=tag           - New VcsTag (or dir=path)
507
 
508
=head1 OPTIONS
509
 
510
=over 8
511
 
512
=item B<-help>
513
 
514
Print a brief help message and exits.
515
 
516
=item B<-help -help>
517
 
518
Print a detailed help message with an explanation for each option.
519
 
520
=item B<-man>
521
 
522
Prints the manual page and exits.
523
 
524
=item B<-check>
525
 
526
This option controls the mode in which the program will operate.
527
 
2931 dpurdie 528
If enabled the program will perform an MD5 Cheksum over the files in the first
383 dpurdie 529
view and compare that with files in the second view.
530
 
2931 dpurdie 531
This option cannot be used in conjunction with the '-diff' option'.
383 dpurdie 532
 
2931 dpurdie 533
=item B<-diff>
534
 
535
This option controls the mode in which the program will operate.
536
 
537
By default the program is Operating System dependent. It will:
538
 
539
=over 4
540
 
541
=item * Windows - Use Beyond Compare
542
 
543
=item * Unix - Use gdiff or diff
544
 
545
=back
546
 
547
This option will force the use of a 'diff' utility on both Windows and
548
Unix.
549
 
550
This option cannot be used in conjunction with the '-check' option'.
551
 
383 dpurdie 552
=item B<-old=tag>
553
 
554
This option specifies the old, or base, VcsTag for the difference report. This
555
tag is mandatory.
556
 
557
The old and new tags may be provided on the command line, or via named
558
options, but not both.
559
 
560
The tag may be of the form dir=path to force the utility to use a local
561
view or path.
562
 
563
=item B<-new=tag>
564
 
565
This option specifies the new, or current, VcsTag for the difference report. This
566
tag is mandatory.
567
 
568
The old and new tags may be provided on the command line, or via named
569
options, but not both.
570
 
571
The tag may be of the form dir=path to force the utility to use a local
572
view or path.
573
 
574
=back
575
 
576
=head1 DESCRIPTION
577
 
578
This program has two modes of operation:
579
 
580
=over 4
581
 
582
=item 1 MD5Sum of the two views
583
 
2931 dpurdie 584
=item 2 Invoke a differencing program.
383 dpurdie 585
 
2931 dpurdie 586
The program that is invoked is, by default, Operating System dependent. It will:
587
 
588
=over 4
589
 
590
=item * Windows - Use Beyond Compare to perform a visual diff.
591
 
383 dpurdie 592
This mode simplifies the process of perform a code review between two
593
VCS Tags by:
594
 
595
=over 8
596
 
597
=item *
598
 
599
Creating a visual difference between two labels
600
 
601
=item *
602
 
603
Creating a visual difference between a label and a directory
604
 
605
=item *
606
 
607
Creating a visual difference between two directories.
608
 
609
=back
610
 
2931 dpurdie 611
=item * Unix - Use gdiff or diff
612
 
383 dpurdie 613
=back
614
 
2931 dpurdie 615
=back
616
 
383 dpurdie 617
The program will:
618
 
619
=over 8
620
 
621
=item *
622
 
623
Create two 'extract only' views based on the VCS Tags provided. The resultant
624
views are not connected to any version control system.
625
 
626
=item *
627
 
2931 dpurdie 628
Perform the desired operation: MD5Sum or Difference.
383 dpurdie 629
 
630
=item *
631
 
632
Delete the created directories the comparison is complete.
633
 
634
=back
635
 
636
If one of the Vcs Tags is of the form:
637
 
638
=over 8
639
 
640
=item *
641
 
642
current
643
 
644
=item *
645
 
646
current=path
647
 
648
=item *
649
 
650
dir=path
651
 
652
=back
653
 
654
Then the tag will be treated as a directory and will be used for one side
655
of the comparison.
656
 
657
Two directories views will be created. These should be deleted by this program,
658
but may remain if the command line program is terminated.
659
 
660
=head1 EXAMPLE
661
 
662
The following command will compare a Subversion view with a ClearCase view.
663
 
664
    jats vcsdiff SVN::AUPERASVN02/COTS/crc/tags/crc_26.4.0007.cr@18587 CC::/MASS_Dev_Infra/crc::crc_26.4.0006.cr -check
665
 
666
The following command will compare a Subversion View with a local directory
667
 
668
    jats vcsdiff SVN::AUPERASVN02/COTS/crc/tags/crc_26.4.0000.cr dir=crc
669
 
670
=cut
671