| 229 |
dpurdie |
1 |
#! /usr/bin/perl
|
|
|
2 |
########################################################################
|
|
|
3 |
# Copyright (C) 1998-2004 ERG Limited, All rights reserved
|
|
|
4 |
#
|
|
|
5 |
# Module name : jats_cbuilder.pl
|
|
|
6 |
# Module type : Makefile system
|
|
|
7 |
# Compiler(s) : n/a
|
|
|
8 |
# Environment(s):
|
|
|
9 |
#
|
|
|
10 |
# Description : Create two dynamic views and invoke Beyond Compare
|
|
|
11 |
# to view the differences.
|
|
|
12 |
#
|
|
|
13 |
# or
|
|
|
14 |
#
|
|
|
15 |
# Create one dynamic view and use the directory
|
|
|
16 |
#
|
|
|
17 |
#......................................................................#
|
|
|
18 |
|
| 255 |
dpurdie |
19 |
require 5.006_001;
|
| 229 |
dpurdie |
20 |
use strict;
|
|
|
21 |
use warnings;
|
|
|
22 |
use JatsError;
|
|
|
23 |
use JatsSystem;
|
|
|
24 |
use FileUtils;
|
|
|
25 |
|
|
|
26 |
use Pod::Usage; # required for help support
|
|
|
27 |
use Getopt::Long;
|
|
|
28 |
use Cwd;
|
|
|
29 |
use Sys::Hostname; # For hostname
|
|
|
30 |
|
|
|
31 |
my $VERSION = "1.1.0"; # Update this
|
|
|
32 |
|
|
|
33 |
#
|
|
|
34 |
# Options
|
|
|
35 |
#
|
|
|
36 |
my $opt_debug = $ENV{'GBE_DEBUG'}; # Allow global debug
|
|
|
37 |
my $opt_verbose = $ENV{'GBE_VERBOSE'}; # Allow global verbose
|
|
|
38 |
my $opt_help = 0;
|
|
|
39 |
my $opt_manual = 0;
|
|
|
40 |
my $opt_drive = 'o';
|
|
|
41 |
my $opt_tag = 'dynamic';
|
|
|
42 |
my $opt_new_label;
|
|
|
43 |
my $opt_old_label;
|
|
|
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 |
|
|
|
52 |
#
|
|
|
53 |
# Globals
|
|
|
54 |
#
|
|
|
55 |
my $MACHINENAME;
|
|
|
56 |
my @error_list; # ClearCmd detected errors
|
|
|
57 |
my $BC2 = 'c:/Program Files/Beyond Compare 2/BC2.exe';
|
|
|
58 |
my @view_tags;
|
|
|
59 |
|
|
|
60 |
|
|
|
61 |
#-------------------------------------------------------------------------------
|
|
|
62 |
# Function : Mainline Entry Point
|
|
|
63 |
#
|
|
|
64 |
# Description :
|
|
|
65 |
#
|
|
|
66 |
# Inputs :
|
|
|
67 |
#
|
|
|
68 |
|
|
|
69 |
#
|
|
|
70 |
# Parse the user options
|
|
|
71 |
#
|
|
|
72 |
my $result = GetOptions (
|
|
|
73 |
"help+" => \$opt_help, # flag, multiple use allowed
|
|
|
74 |
"manual" => \$opt_manual, # flag, multiple use allowed
|
|
|
75 |
"verbose+" => \$opt_verbose, # flag, multiple use allowed
|
|
|
76 |
"new=s" => \$opt_new_label, # String
|
|
|
77 |
"old=s" => \$opt_old_label, # String
|
|
|
78 |
"drive=s" => \$opt_drive, # String
|
|
|
79 |
);
|
|
|
80 |
|
|
|
81 |
#
|
|
|
82 |
# UPDATE THE DOCUMENTATION AT THE END OF THIS FILE !!!
|
|
|
83 |
#
|
|
|
84 |
|
|
|
85 |
#
|
|
|
86 |
# Process help and manual options
|
|
|
87 |
#
|
|
|
88 |
pod2usage(-verbose => 0, -message => "Version: $VERSION") if ($opt_help == 1 || ! $result );
|
|
|
89 |
pod2usage(-verbose => 1) if ($opt_help == 2 );
|
|
|
90 |
pod2usage(-verbose => 2) if ($opt_manual || ($opt_help > 2));
|
|
|
91 |
|
|
|
92 |
InitFileUtils();
|
|
|
93 |
|
|
|
94 |
#
|
|
|
95 |
# Configure the error reporting process now that we have the user options
|
|
|
96 |
#
|
|
|
97 |
ErrorConfig( 'name' => 'CC_BC2',
|
|
|
98 |
'verbose' => $opt_verbose );
|
|
|
99 |
|
|
|
100 |
#
|
|
|
101 |
# Only for windows
|
|
|
102 |
#
|
|
|
103 |
Error ("This program only works under Windows")
|
|
|
104 |
if ( $UNIX );
|
|
|
105 |
|
|
|
106 |
#
|
|
|
107 |
# Validate user options
|
|
|
108 |
#
|
|
|
109 |
# Be nice to the user
|
|
|
110 |
# If we have two options and no labels, then assign them
|
|
|
111 |
#
|
|
|
112 |
if ( ! $opt_new_label && ! $opt_old_label )
|
|
|
113 |
{
|
|
|
114 |
Error ("Must provide two labels on command line unless they are provided via -old and -new options")
|
|
|
115 |
if ( $#ARGV < 1 );
|
|
|
116 |
|
|
|
117 |
$opt_old_label = shift @ARGV;
|
|
|
118 |
$opt_new_label = shift @ARGV;
|
|
|
119 |
}
|
|
|
120 |
|
|
|
121 |
Error ("Need two labels on the command line, or via options")
|
|
|
122 |
unless ( $opt_old_label && $opt_new_label );
|
|
|
123 |
|
|
|
124 |
Error ("Too many command line arguments" )
|
|
|
125 |
unless ( $#ARGV < 0 );
|
|
|
126 |
|
|
|
127 |
#
|
|
|
128 |
# Determine the machine type
|
|
|
129 |
#
|
|
|
130 |
Verbose ("Machine Type: UNIX=$UNIX");
|
|
|
131 |
|
|
|
132 |
#
|
|
|
133 |
# Extract parameters that will be used to create a view that is
|
|
|
134 |
# unique. Will use hostname and user name
|
|
|
135 |
#
|
|
|
136 |
$MACHINENAME = hostname;
|
|
|
137 |
Error ("Machine Name not determined")
|
|
|
138 |
unless ( $MACHINENAME );
|
|
|
139 |
chomp( $MACHINENAME );
|
|
|
140 |
|
|
|
141 |
Error ("USER name not determined" )
|
|
|
142 |
unless ( $USER );
|
|
|
143 |
|
|
|
144 |
#
|
|
|
145 |
# Need a TMP working directory
|
|
|
146 |
# Used to create config files
|
|
|
147 |
#
|
|
|
148 |
Error ("TMP not found or not a directory")
|
|
|
149 |
unless ( $TMP && -d $TMP );
|
|
|
150 |
$TMP = "$TMP/$$";
|
|
|
151 |
|
|
|
152 |
#
|
| 231 |
dpurdie |
153 |
# Determine the path to BC2.EXE
|
|
|
154 |
# It maynot be installed inthe default place
|
| 229 |
dpurdie |
155 |
#
|
| 231 |
dpurdie |
156 |
if ( ! -x $BC2 )
|
|
|
157 |
{
|
|
|
158 |
$BC2 = GetBc2ExePath();
|
|
|
159 |
}
|
| 229 |
dpurdie |
160 |
|
|
|
161 |
#
|
|
|
162 |
# Ensure that the 'cleartool' program can be located
|
|
|
163 |
#
|
|
|
164 |
Verbose ("Locate clearcase utility in users path");
|
|
|
165 |
Error ("Cannot locate the 'cleartool' utility in the users PATH")
|
|
|
166 |
unless ( LocateProgInPath('cleartool', '--All') );
|
|
|
167 |
|
|
|
168 |
|
|
|
169 |
#
|
|
|
170 |
# Create dynamic views for the two views
|
|
|
171 |
# Verify that the view are present
|
|
|
172 |
#
|
|
|
173 |
Message ("Constructing dynamic views");
|
|
|
174 |
my $path1 = create_dynamic_view( $opt_old_label );
|
|
|
175 |
my $path2 = create_dynamic_view( $opt_new_label );
|
|
|
176 |
|
|
|
177 |
Error ("Cannot locate view directory: $path1" ) unless (-d $path1);
|
|
|
178 |
Error ("Cannot locate view directory: $path2" ) unless (-d $path2);
|
|
|
179 |
|
|
|
180 |
#
|
|
|
181 |
# If one of the paths is a dynamic view and the other is a local path
|
|
|
182 |
# then attempt to locate the common directories
|
|
|
183 |
#
|
|
|
184 |
if ( $#view_tags == 0 )
|
|
|
185 |
{
|
|
|
186 |
massage_paths();
|
|
|
187 |
}
|
|
|
188 |
|
|
|
189 |
|
|
|
190 |
Message ("Using Beyond Compare to compare two views",
|
|
|
191 |
"Wait for BC2 to exit so that we can delete the views" );
|
|
|
192 |
System ( $BC2, $path1, $path2 );
|
|
|
193 |
exit 0;
|
|
|
194 |
|
|
|
195 |
#-------------------------------------------------------------------------------
|
|
|
196 |
# Function : create_dynamic_view
|
|
|
197 |
#
|
|
|
198 |
# Description : Create a dynamic view, based on a label
|
|
|
199 |
#
|
|
|
200 |
# Inputs : $label - Base label
|
|
|
201 |
#
|
|
|
202 |
# Returns : Path to the view
|
|
|
203 |
#
|
|
|
204 |
sub create_dynamic_view
|
|
|
205 |
{
|
|
|
206 |
my ($label) = @_;
|
|
|
207 |
|
|
|
208 |
#
|
|
|
209 |
# Intercept and treat the special label 'current'
|
|
|
210 |
#
|
|
|
211 |
return create_path_view( $label )
|
|
|
212 |
if ( $label eq 'current' || $label =~ m~^dir=.+~ || $label =~ m~^current=.+~ );
|
|
|
213 |
|
|
|
214 |
my $config = "${TMP}.config_ccview.txt";
|
|
|
215 |
|
|
|
216 |
#
|
|
|
217 |
# Create a config spec
|
|
|
218 |
#
|
|
|
219 |
Verbose ("Create tmp file: $config");
|
|
|
220 |
open (CF, ">$config" ) || Error ("Cannot create temp config spec file");
|
|
|
221 |
print CF "element * CHECKEDOUT\n";
|
|
|
222 |
print CF "element .../lost+found -none\n";
|
|
|
223 |
print CF "element * $label\n";
|
|
|
224 |
close CF;
|
|
|
225 |
|
|
|
226 |
my $tag = "${USER}_${MACHINENAME}_${opt_tag}_${label}";
|
|
|
227 |
push @view_tags, $tag;
|
|
|
228 |
|
|
|
229 |
ClearCmd ( "rmview -tag $tag" );
|
|
|
230 |
ClearCmd ( "mkview -tag $tag -stgloc -auto" );
|
|
|
231 |
ClearCmd ( "setcs -tag $tag $config" );
|
|
|
232 |
|
|
|
233 |
unlink $config;
|
|
|
234 |
|
|
|
235 |
return "$opt_drive:/$tag";
|
|
|
236 |
}
|
|
|
237 |
|
|
|
238 |
#-------------------------------------------------------------------------------
|
|
|
239 |
# Function : create_path_view
|
|
|
240 |
#
|
|
|
241 |
# Description : Not using a view, using a path
|
|
|
242 |
# Return the path as requested
|
|
|
243 |
#
|
|
|
244 |
# Inputs : $label - with embedded path
|
|
|
245 |
#
|
|
|
246 |
# Returns : Path to the (dummy) view
|
|
|
247 |
#
|
|
|
248 |
sub create_path_view
|
|
|
249 |
{
|
|
|
250 |
my ($label) = @_;
|
|
|
251 |
my $path = '.';
|
|
|
252 |
|
|
|
253 |
$path = $1
|
|
|
254 |
if ( $label =~ m~.+=(.+)~ );
|
|
|
255 |
|
|
|
256 |
Error ("Directory not found: $path" )
|
|
|
257 |
unless ( -d $path );
|
|
|
258 |
|
|
|
259 |
$path = FullPath( $path );
|
|
|
260 |
return $path;
|
|
|
261 |
}
|
|
|
262 |
|
|
|
263 |
#-------------------------------------------------------------------------------
|
|
|
264 |
# Function : massage_paths
|
|
|
265 |
#
|
|
|
266 |
# Description : Used when one of the paths is a view and the the other
|
|
|
267 |
# is a local directory.
|
|
|
268 |
#
|
|
|
269 |
# Attempt to locate the common root
|
|
|
270 |
#
|
|
|
271 |
# Inputs : None
|
|
|
272 |
#
|
|
|
273 |
# Returns : Modifies $path1 and $path2
|
|
|
274 |
#
|
|
|
275 |
sub massage_paths
|
|
|
276 |
{
|
|
|
277 |
my $view_path = "$opt_drive:/" . $view_tags[0];
|
|
|
278 |
my $user_path = $path1;
|
|
|
279 |
$user_path = $path2 if ( $view_path eq $path1 );
|
|
|
280 |
|
|
|
281 |
#
|
|
|
282 |
# Split the user path into its component directory entries
|
|
|
283 |
# Start at the top and look for one of these in the view
|
|
|
284 |
#
|
|
|
285 |
my @user_path = split ('/', $user_path );
|
|
|
286 |
my $tpath = '';
|
|
|
287 |
foreach my $dir ( @user_path )
|
|
|
288 |
{
|
|
|
289 |
if ( -d "$view_path/$dir" )
|
|
|
290 |
{
|
|
|
291 |
#
|
|
|
292 |
# Common directory found
|
|
|
293 |
# Set the user path to the previous directory
|
|
|
294 |
#
|
|
|
295 |
$user_path = $tpath;
|
|
|
296 |
if ( $view_path eq $path1 )
|
|
|
297 |
{
|
|
|
298 |
$path2 = $user_path;
|
|
|
299 |
}
|
|
|
300 |
else
|
|
|
301 |
{
|
|
|
302 |
$path1 = $user_path;
|
|
|
303 |
}
|
|
|
304 |
|
|
|
305 |
#
|
|
|
306 |
# now add the common part
|
|
|
307 |
#
|
|
|
308 |
$path1 .= "/$dir";
|
|
|
309 |
$path2 .= "/$dir";
|
|
|
310 |
Message ("Setting common root path ($dir)", $path1, $path2);
|
|
|
311 |
last;
|
|
|
312 |
}
|
|
|
313 |
$tpath .= '/' if ( $tpath );
|
|
|
314 |
$tpath .= $dir;
|
|
|
315 |
}
|
|
|
316 |
}
|
|
|
317 |
|
| 231 |
dpurdie |
318 |
#-------------------------------------------------------------------------------
|
|
|
319 |
# Function : GetBc2ExePath
|
|
|
320 |
#
|
|
|
321 |
# Description : Determine the path to the BeyondCompare executable
|
|
|
322 |
# by looking in the Windows Registry
|
|
|
323 |
#
|
|
|
324 |
# Inputs : None
|
|
|
325 |
#
|
|
|
326 |
# Returns : Path to an executable
|
|
|
327 |
#
|
| 229 |
dpurdie |
328 |
|
| 231 |
dpurdie |
329 |
sub GetBc2ExePath
|
|
|
330 |
{
|
|
|
331 |
eval "require Win32::TieRegistry"
|
|
|
332 |
or Error ("Win32::TieRegistry not available");
|
|
|
333 |
|
|
|
334 |
my $userKey= Win32::TieRegistry->new("CUser")
|
|
|
335 |
or Error( "Can't access HKEY_CURRENT_USER key: $^E" );
|
|
|
336 |
|
|
|
337 |
my $bc2Key= $userKey->Open( "Software/Scooter Software/Beyond Compare", {Delimiter=>"/"} )
|
|
|
338 |
or Error "Can't access BC2 Keys: $^E";
|
|
|
339 |
|
|
|
340 |
my $bc2Data = $bc2Key->GetValue( 'ExePath' )
|
|
|
341 |
or Error( "Cannot locate BeyondCompare in Windows Registry");
|
|
|
342 |
|
|
|
343 |
Error ("BeyondCompare program not found", "Prog: $bc2Data") unless ( -x $bc2Data );
|
|
|
344 |
return $bc2Data;
|
|
|
345 |
}
|
|
|
346 |
|
| 229 |
dpurdie |
347 |
#-------------------------------------------------------------------------------
|
|
|
348 |
# Function : END
|
|
|
349 |
#
|
|
|
350 |
# Description : This function will be called as the program exits
|
|
|
351 |
# It will also be called under error conditions
|
|
|
352 |
# Close down stuff we created
|
|
|
353 |
#
|
|
|
354 |
# Inputs :
|
|
|
355 |
#
|
|
|
356 |
# Returns :
|
|
|
357 |
#
|
|
|
358 |
|
|
|
359 |
sub END
|
|
|
360 |
{
|
|
|
361 |
Message ("Cleaning up views - Please wait") if @view_tags;
|
|
|
362 |
foreach my $tag ( @view_tags )
|
|
|
363 |
{
|
|
|
364 |
# Message ("NOT Cleaning up views");
|
|
|
365 |
ClearCmd ( "rmview -tag $tag" );
|
|
|
366 |
}
|
|
|
367 |
}
|
|
|
368 |
|
|
|
369 |
#-------------------------------------------------------------------------------
|
|
|
370 |
# Function : ClearCmd
|
|
|
371 |
#
|
|
|
372 |
# Description : Execute a cleartool command
|
|
|
373 |
# Capture error messages only
|
|
|
374 |
#
|
|
|
375 |
# Inputs : Command to execute
|
|
|
376 |
#
|
|
|
377 |
# Returns : Exit code
|
|
|
378 |
# Also the global @error_list
|
|
|
379 |
#
|
|
|
380 |
sub ClearCmd
|
|
|
381 |
{
|
|
|
382 |
my( $cmd ) = @_;
|
|
|
383 |
Verbose2 "cleartool $cmd";
|
|
|
384 |
|
|
|
385 |
@error_list = ();
|
|
|
386 |
open(CMD, "cleartool $cmd 2>&1 |") || Error "can't run command: $!";
|
|
|
387 |
while (<CMD>)
|
|
|
388 |
{
|
|
|
389 |
chomp;
|
|
|
390 |
Verbose ($_);
|
|
|
391 |
push @error_list, $_ if ( m~Error:~ );
|
|
|
392 |
}
|
|
|
393 |
close(CMD);
|
|
|
394 |
|
|
|
395 |
Verbose2 "Exit Status: $?";
|
|
|
396 |
return $? / 256;
|
|
|
397 |
}
|
|
|
398 |
|
|
|
399 |
#-------------------------------------------------------------------------------
|
|
|
400 |
# Documentation
|
|
|
401 |
#
|
|
|
402 |
|
|
|
403 |
=pod
|
|
|
404 |
|
|
|
405 |
=head1 NAME
|
|
|
406 |
|
|
|
407 |
CCbc2 - ClearCase BeyondCompare Difference
|
|
|
408 |
|
|
|
409 |
=head1 SYNOPSIS
|
|
|
410 |
|
| 231 |
dpurdie |
411 |
jats CCbc2 [options] [old_label new_label]
|
| 229 |
dpurdie |
412 |
|
|
|
413 |
Options:
|
|
|
414 |
-help - brief help message
|
|
|
415 |
-help -help - Detailed help message
|
|
|
416 |
-man - Full documentation
|
|
|
417 |
-old=label - Old label (or dir=path)
|
|
|
418 |
-new=label - New label (or dir=path)
|
|
|
419 |
-drive=path - Alternate vob location
|
|
|
420 |
|
|
|
421 |
=head1 OPTIONS
|
|
|
422 |
|
|
|
423 |
=over 8
|
|
|
424 |
|
|
|
425 |
=item B<-help>
|
|
|
426 |
|
|
|
427 |
Print a brief help message and exits.
|
|
|
428 |
|
|
|
429 |
=item B<-help -help>
|
|
|
430 |
|
|
|
431 |
Print a detailed help message with an explanation for each option.
|
|
|
432 |
|
|
|
433 |
=item B<-man>
|
|
|
434 |
|
|
|
435 |
Prints the manual page and exits.
|
|
|
436 |
|
|
|
437 |
=item B<-old=label>
|
|
|
438 |
|
|
|
439 |
This option specifies the old, or base, label for the difference report. This
|
|
|
440 |
label is mandatory for the difference report.
|
|
|
441 |
|
|
|
442 |
The old and new labels may be provided on the command line, or via named
|
|
|
443 |
options, but not both.
|
|
|
444 |
|
|
|
445 |
The label may be of the form dir=path to force the utility to use a local
|
|
|
446 |
view or path.
|
|
|
447 |
|
|
|
448 |
=item B<-new=label>
|
|
|
449 |
|
|
|
450 |
This option specifies the new, or current, label for the difference report. This
|
|
|
451 |
label is mandatory for the difference report.
|
|
|
452 |
|
|
|
453 |
The old and new labels may be provided on the command line, or via named
|
|
|
454 |
options, but not both.
|
|
|
455 |
|
|
|
456 |
The label may be of the form dir=path to force the utility to use a local
|
|
|
457 |
view or path.
|
|
|
458 |
|
|
|
459 |
=item B<-drive=path>
|
|
|
460 |
|
|
|
461 |
This option allows the user to provide an alternate location for the
|
|
|
462 |
administration vob used by the program. The default location is:
|
|
|
463 |
|
|
|
464 |
=over 8
|
|
|
465 |
|
|
|
466 |
=item * Windows o:
|
|
|
467 |
|
|
|
468 |
=item * Unix /view
|
|
|
469 |
|
|
|
470 |
=back
|
|
|
471 |
|
|
|
472 |
=back
|
|
|
473 |
|
|
|
474 |
=head1 DESCRIPTION
|
|
|
475 |
|
|
|
476 |
This program simplifies the process of perform a code review between two ClearCase
|
|
|
477 |
labels by:
|
|
|
478 |
|
|
|
479 |
=over 8
|
|
|
480 |
|
|
|
481 |
=item # Creating a visual difference between two labels
|
|
|
482 |
|
|
|
483 |
=item # Creating a visual difference between a label and a directory
|
|
|
484 |
|
|
|
485 |
=item # Creating a visual difference between two directories.
|
|
|
486 |
|
|
|
487 |
=back
|
|
|
488 |
|
|
|
489 |
The program will:
|
|
|
490 |
|
|
|
491 |
=over 8
|
|
|
492 |
|
|
|
493 |
=item * Create two dynamic views based on the provided label
|
|
|
494 |
|
|
|
495 |
=item * Invoke BeyondCompare to allow visual inspection of the two software versions.
|
|
|
496 |
|
|
|
497 |
=item * Delete the views when the comparison is complete.
|
|
|
498 |
|
|
|
499 |
=back
|
|
|
500 |
|
|
|
501 |
If one of the labels is of the form:
|
|
|
502 |
|
|
|
503 |
=over 8
|
|
|
504 |
|
|
|
505 |
=item * current
|
|
|
506 |
|
|
|
507 |
=item * current=path
|
|
|
508 |
|
|
|
509 |
=item * dir=path
|
|
|
510 |
|
|
|
511 |
=back
|
|
|
512 |
|
|
|
513 |
Then the label will be treated as a directory and will be used for one side
|
|
|
514 |
of the comparison.
|
|
|
515 |
|
|
|
516 |
The program uses a global administration view for the purposes of determining
|
|
|
517 |
file versions.
|
|
|
518 |
|
|
|
519 |
Two dynamic views will be created. These should be deleted by this program,
|
|
|
520 |
but may remain if the command line program is terminated.
|
|
|
521 |
|
|
|
522 |
The user must have relevant VOBs mounted on there machine for this utility to
|
|
|
523 |
operate correctly.
|
|
|
524 |
|
|
|
525 |
=cut
|
|
|
526 |
|