Subversion Repositories DevTools

Rev

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

Rev Author Line No. Line
392 dpurdie 1
########################################################################
2
# Copyright (C) 1998-2012 Vix Technology, All rights reserved
3
#
4
# Module name   : cc2svn_importpackage.pl
5
# Module type   : Makefile system
6
# Compiler(s)   : Perl
7
# Environment(s): jats
8
#
9
# Description   : Get package information for a package name specified on the
10
#                 command line.
11
#
12
#                 Determine the package id
13
#                 Locate all packages that have the same package name
14
#                 Determine essential packages
15
#                 Prune uneeded packages
16
#
17
#                 Pump it into SVN
18
#
19
#                 Project Based Pumping, creating branches as needed
20
#
21
#......................................................................#
22
 
23
require 5.006_001;
24
use strict;
25
use warnings;
26
use JatsError;
27
use JatsRmApi;
28
use FileUtils;
29
use JatsSystem;
30
use HTTP::Date;
31
use JatsProperties;
32
use JatsEnv;
33
use ConfigurationFile;
34
use JatsSvn qw(:All);
35
 
36
 
37
#use Data::Dumper;
38
use Fcntl ':flock'; # import LOCK_* constants
39
use Cwd;
40
use DBI;
41
use Getopt::Long;
42
use Pod::Usage;                             # required for help support
43
 
44
#
45
#   Options
46
#
47
my $opt_help = 0;
48
my $opt_manual = 0;
49
my $opt_verbose = 0;
50
my $opt_repo_base = 'AUPERASVN01/';
51
my $opt_repo = '';
52
my $opt_flat;
53
my $opt_test;
54
my $opt_reuse;
55
my $opt_age;
56
my $opt_dump = 0;
57
my $opt_images = 0;
58
my $opt_retaincount = 2;
59
my $opt_pruneModeString;
60
my $opt_listTags;
61
my $opt_name;
62
my $opt_log = 0;
63
my @opt_tip;
64
my $opt_postimage = 1;
65
my $opt_workDir = '/work';
66
my $opt_vobMap;
67
 
68
################################################################################
69
#   List of Projects Suffixes and Branch Names to be used within SVN
70
#
71
#       Name        - Name of branch for the project
72
#       Trunk       - Can be a trunk project
73
#                     First one seen will be placed on the trunk
74
#                     Others will create project branches
75
#
76
my $ProjectTrunk;
77
my %ProjectsBaseCreated;
78
my %Projects = (
79
    '.sea'      => { Name => 'Seattle' },
80
    '.coct'     => { Name => 'CapeTown' },
81
    '.sls'      => { Name => 'Stockholm' },
82
    '.syd'      => { Name => 'Sydney' },
83
    '.vtk'      => { Name => 'Vasttrafik' },
84
    '.bei'      => { Name => 'Beijing' },
85
    '.bkk'      => { Name => 'Bangkok' },
86
    '.ndl'      => { Name => 'NewDelhi' },
87
    '.nzs'      => { Name => 'NewZealandStageCoach' },
88
    '.wdc'      => { Name => 'Washington' },
89
    '.oso'      => { Name => 'Oslo' },
90
    '.lvs'      => { Name => 'LasVegas' },
91
    '.mlc'      => { Name => 'BeijingMlc' },
92
    '.sfo'      => { Name => 'SanFrancisco' },
93
    '.sg'       => { Name => 'Singapore' },
94
    '.gmp'      => { Name => 'GmpteProject' },
95
    '.ssw'      => { Name => 'UkStageCoach' },
96
    '.uk'       => { Name => 'UkProject' },
97
    '.pmb'      => { Name => 'Pietermaritzburg' },
98
    '.vps'      => { Name => 'VixPayments' },
99
    '.ncc'      => { Name => 'NSWClubCard' },
100
    '.rm'       => { Name => 'Rome' },
101
    'unknown'   => { Name => 'UnknownProject' },
102
 
103
    '.ebr'      => { Name => 'eBrio' , Trunk => 1 },
104
    '.mas'      => { Name => 'Mass'  , Trunk => 1 },
105
    '.cr'       => { Name => 'Core'  , Trunk => 1 },
106
    '.cots'     => { Name => 'Cots'  , Trunk => 1 },
107
    '.tool'     => { Name => 'Tools' , Trunk => 1 },
108
);
109
 
110
my %suffixFixup = (
111
    '.sf'           => '.sfo',
112
    '.vt'           => '.vtk',
113
    '.lv'           => '.lvs',
114
    '.was'          => '.wdc',
115
    '.uk.1'         => '.uk',
116
    '.ssts.demo'    => '.ssts',
117
    '.u244.syd'     => '.syd',
118
    '.pxxx.sea'     => '.sea',
119
    '.pxxx.syd'     => '.syd',
120
    '.pxxx.sydddd'  => '.syd',
121
    '.oslo'         => '.oso',
122
);
123
 
124
my %specialPackages = (
125
#    'core_devl' =>  ',all,protected,',
126
    'core_devl' =>  ',all,',
127
    'daf_utils_mos' => ',flat,',
128
    'mos_packager'  => ',all,',
129
);
130
 
131
my %notCots = (
132
    'isl'       => 1,
133
);
134
 
135
################################################################################
136
#   Global data
137
#
138
my $VERSION = "1.0.0";
139
my $RM_DB;
140
my $last_pv_id;
141
my %pkg_ids;
142
my $first_pkg_id;
143
my %versions;
144
my %suffixes;
145
my @processOrder;
146
my @startPoints;
147
my @allStartPoints;
148
my @endPoints;
149
my $now = time();
150
my $logSummary;
151
my $firstVersionCreated;
152
my @EssentialPackages;
153
my $createBranch;
154
my $createSuffix;
155
my $currentBranchName;
156
my $singleProject;
157
my $pruneCount = 0;
158
my $trimCount = 0;
159
my $badVcsCount = 0;
160
my $ProjectCount = 0;
161
my $totalVersions = 0;
162
my $initialTrees = 0;
163
my $globalError;
164
my @unknownProjects;
165
my %knownProjects;
166
my $badSingletonCount = 0;
167
my @flatOrder;
168
my $pruneMode;
169
my $pruneModeString;
170
my $threadId = 0;
171
my $threadCount;
172
my %tipVersions;
173
my $allSvn;
174
my @multiplePaths;
175
my @badEssentials;
176
my %svnData;
177
my $cwd;
178
 
179
my $packageNames;
180
my @packageNames;
181
my $multiPackages = -1;
182
my $visitId = 0;
183
my $noTransfer;
184
my $rippleCount = 0;
185
my $svnRepo;
186
 
187
our $GBE_RM_URL;
188
my $UNIX = $ENV{'GBE_UNIX'};
189
 
190
my $result = GetOptions (
191
                "help+"         => \$opt_help,          # flag, multiple use allowed
192
                "manual:3"      => \$opt_help,
193
                "verbose:+"     => \$opt_verbose,       # Versose
194
                "repository:s"  => \$opt_repo,          # Name of repository
195
                "flat!"         => \$opt_flat,          # Flat structure
196
                "test!"         => \$opt_test,          # Test operations
197
                "reuse!"        => \$opt_reuse,         # Reuse ClearCase views
198
                "age:i"         => \$opt_age,           # Only recent versions
199
                "dump:1"        => \$opt_dump,          # Dump Data
200
                "images:1"      => \$opt_images,        # Create DOT images
201
                "retain:i"      => \$opt_retaincount,   # Retain N packages
202
                "pruneMode:s"   => \$opt_pruneModeString,
203
                "listtags:i"    => \$opt_listTags,
204
                "name:s"        => \$opt_name,          # Alternate output
205
                "tip:s"         => \@opt_tip,           # Force tip version(s)
206
                "log!"          => \$opt_log,
207
                "postimage!"    => \$opt_postimage,
208
                'workdir:s'     => \$opt_workDir,
209
                );
210
 
211
#
212
#   Process help and manual options
213
#
214
pod2usage(-verbose => 0, -message => "Version: $VERSION")  if ($opt_help == 1  || ! $result);
215
pod2usage(-verbose => 1)  if ($opt_help == 2 );
216
pod2usage(-verbose => 2)  if ($opt_manual || ($opt_help > 2));
217
 
218
#
219
#   Configure the error reporting process now that we have the user options
220
#
221
SystemConfig ('ExitOnError' => 1);
222
ErrorConfig( 'name'    =>'CC2SVN_IMPORT',
223
             'verbose' => $opt_verbose,
224
              );
225
 
226
Error("Workdir does not exist" ) unless ( -d $opt_workDir );
227
Error("Specify a package as 'name'" ) unless ( defined $ARGV[0] );
228
EnvImport('GBE_RM_URL');
229
$cwd = Getcwd();
230
 
231
#
232
#   Init the pruning mode
233
#
234
setPruneMode( $opt_pruneModeString || 'ripple');
235
 
236
#
237
#   Get data for all packages
238
#
239
foreach my $packageName ( @ARGV )
240
{
241
    next unless ( $packageName );
242
    Verbose( "Base Package: $packageName");
243
 
244
    my $pkg_id = GetPkgIdByName ( $packageName );
245
    GetData_by_pkg_id ( $pkg_id, $packageName  );
246
    $pkg_ids{$pkg_id} = 1;
247
    $first_pkg_id = $pkg_id unless ( $first_pkg_id );
248
    push @packageNames, $packageName;
249
    $multiPackages++;
250
}
251
 
252
{
253
    #
254
    #   Delete entries that have been created as we read in
255
    #   data, but don't exist in RM. They will not have a pvid.
256
    #
257
    foreach my $entry ( keys(%versions) )
258
    {
259
        delete $versions{$entry}
260
            unless ( exists $versions{$entry}{pvid} );
261
    }
262
}
263
 
264
$totalVersions = scalar keys %versions;
265
Error ("No packages specified") unless ( $multiPackages >= 0 );
266
Warning ("Multiple Packages being processed") if ( $multiPackages > 1 );
267
$packageNames = join ('_', @packageNames );
268
$packageNames = $opt_name if ( defined $opt_name );
269
Message ("PackageName: $packageNames" );
270
 
271
#
272
#   Save logging data
273
#
274
if ( $opt_log )
275
{
276
    my $opt_logfile = $packageNames . '.import';
277
    Message ("Logging outout: $opt_logfile" );
278
    open STDOUT, '>', $opt_logfile  or die "Can't redirect STDOUT: $!";
279
    open STDERR, ">&STDOUT"         or die "Can't dup STDOUT: $!";
280
}
281
 
282
#
283
#   Prepare tip version hash
284
#
285
$tipVersions{$_} = 1 foreach ( @opt_tip );
286
 
287
#
288
#   Read in external data and massage it all
289
#
290
getEssenialPackageVersions();
291
getVobMapping();
292
smartPackageType();                 # Determine special prune mode
293
ReportPathVariance();
294
massageData();
295
getSvnData();
296
smartPackageType();                 # Have another go
297
 
298
my @missedTips = keys %tipVersions;
299
Error ("Specified tip version not found: @missedTips") if ( @missedTips );
300
 
301
if ( $opt_flat )
302
{
303
#    @flatOrder = sort {$versions{$a}{version} cmp $versions{$b}{version}} keys(%versions);
304
#    @flatOrder = sort {$versions{$a}{created} cmp $versions{$b}{created}} keys(%versions);
305
    @flatOrder = sort {$a <=> $b} keys(%versions);
306
    my $tip = $flatOrder[-1];
307
    $versions{$tip}{Tip} = 1 if $tip;
308
}
309
 
310
#
311
#   Generate dumps and images
312
#
313
if ( $opt_images )
314
{
315
    createImages();
316
}
317
 
318
if ( $opt_dump )
319
{
320
    DebugDumpData ("Versions", \%versions );
321
    DebugDumpData ("Starts", \@startPoints );
322
    DebugDumpData ("Ends", \@endPoints );
323
    DebugDumpData ("Suffixes", \%suffixes );
324
}
325
 
326
 
327
#   Display VCS tags
328
#
329
if ( $opt_listTags )
330
{
331
    foreach my $entry (sort {$versions{$a}{version} cmp $versions{$b}{version}} keys(%versions) )
332
    {
333
        print $versions{$entry}{vcsTag} || '-' ,"\n";
334
    }
335
}
336
exit if ( ($opt_dump > 1) || ($opt_images > 1) );
337
 
338
transferPackageToSvn();
339
 
340
if ( $opt_postimage )
341
{
342
    getSvnData();
343
    createImages();
344
}
345
 
346
exit 0;
347
 
348
#-------------------------------------------------------------------------------
349
# Function        : transferPackageToSvn
350
#
351
# Description     : Transfer the package to SVN
352
#
353
# Inputs          : 
354
#
355
# Returns         : 
356
#
357
sub transferPackageToSvn
358
{
359
    Error ("Repository Path not setup")
360
        unless ( $svnRepo );
361
 
362
    #
363
    #   Going to do serious work
364
    #   Need to ensure we have more arguments
365
    #
366
    if ( $noTransfer )
367
    {
368
        Warning("Protected Package not transferred: $packageNames[0]");
369
        exit 0;
370
    }
371
 
372
    #
373
    #   Perform all the work in a package specific subdirectory
374
    #
375
    my $workDir = $opt_workDir . '/' . $packageNames;
376
    mkdir $workDir unless ( -d $workDir );
377
    chdir $workDir || Error ("Cannot cd to $workDir");
378
 
379
    #
380
    #   Process all packages
381
    #       Going to create versions based on RM structure
382
    #       May have several starting points: Process each
383
    #
384
    newPackage();
385
    if ( $opt_flat )
386
    {
387
        newProject();
388
        foreach my $entry (@flatOrder )
389
        {
390
            newPackageVersion( $entry, $versions{$entry}{suffix} );
391
        }
392
    }
393
    else
394
    {
395
        processBranch(@allStartPoints);
396
    }
397
    endPackage();
398
 
399
    chdir $cwd || Error ("Cannot cd back to $cwd");
400
    rmdir $workDir;
401
    Warning ("Work Directory still exists: $workDir");
402
    saveData();
403
}
404
 
405
#-------------------------------------------------------------------------------
406
# Function        : setPruneMode
407
#
408
# Description     : Set the pruning mode
409
#
410
# Inputs          : mode                    - Text mode value
411
#
412
# Returns         : Nothing
413
#
414
sub setPruneMode
415
{
416
    my ($mode) = @_;
417
    my $value;
418
    if ( $mode )
419
    {
420
        if ( $mode =~ m/none/i) {
421
            $value = 0;
422
        } elsif ( $mode =~ m/ripple/i) {
423
            $value = 1;
424
        } elsif ( $mode =~ m/retain/i) {
425
            $value = 2;
426
        } elsif ( $mode =~ m/severe/i) {
427
            $value = 3;
428
        } else {
429
            Error ("Unknown pruning mode", "Use: none, ripple, retain or severe");
430
        }
431
 
432
        $pruneModeString = $mode;
433
        $pruneMode = $value;
434
    }
435
}
436
 
437
#-------------------------------------------------------------------------------
438
# Function        : smartPackageType
439
#
440
# Description     : Have a look at the projects in the package set and
441
#                   attempt to determine what sort of mechanism to use
442
#
443
# Inputs          : Uses %suffixes data
444
#
445
# Returns         : 
446
#
447
my $packageType = 'UNKNOWN';
448
sub smartPackageType
449
{
450
    #
451
    #   Rebuild suffixes hash based on  post massaged versions
452
    #
453
    my %suffixes;
454
    my @unknown;
455
    foreach my $entry ( keys %versions )
456
    {
457
        my $suffix = $versions{$entry}{suffix} || '';
458
        push (@unknown, $entry) if ($suffix eq 'unknown');
459
 
460
        next if ( exists $suffixes{$suffix} );
461
        next if ( $versions{$entry}{badSingleton} );
462
        next if ( $versions{$entry}{locked} eq 'N' || $versions{$entry}{isaWip} );
463
        $suffixes{$suffix} = 1;
464
        $knownProjects{$suffix}{seen} = 1;
465
 
466
    }
467
 
468
    #
469
    #   The 'unknown' suffix is really an 'empty' suffix
470
    #   Try to be clever
471
    #       Map unknown to 'cr' or 'mas' if present
472
    #
473
    #
474
    if ( exists $suffixes{'unknown'}  )
475
    {
476
        my $new_suffix;
477
        if ( exists $suffixes{'.cr'} ) {
478
            $new_suffix = '.cr';
479
        } elsif ( exists $suffixes{'.mas'} ) {
480
            $new_suffix = '.mas';
481
        }
482
 
483
        if ( $new_suffix )
484
        {
485
            foreach my $entry ( @unknown )
486
            {
487
                $versions{$entry}{suffix} = $new_suffix;
488
            }
489
            delete $suffixes{'unknown'};
490
            delete $knownProjects{'unknown'}{seen};
491
        }
492
    }
493
 
494
    if ( exists $suffixes{'.cots'} && !exists ($notCots{$packageNames}) ) {
495
        $packageType = 'COTS';
496
        $Projects{'.cots'}{Trunk} = 1;
497
        $singleProject = 1;
498
        $opt_flat = 1 unless defined $opt_flat;
499
        setPruneMode('none') unless (defined $opt_pruneModeString);
500
 
501
    } elsif ( exists $suffixes{'.tool'} ) {
502
        $packageType = 'TOOL';
503
        $Projects{'.tool'}{'Trunk'} = 1;
504
        $singleProject = 1;
505
        setPruneMode('none') unless (defined $opt_pruneModeString);
506
#        $opt_flat = 1;
507
 
508
    } elsif ( scalar (keys %suffixes ) == 1 ) {
509
        $packageType = 'SINGLE_PROJECT';
510
        $singleProject = 1;
511
 
512
    } else {
513
        $packageType = 'MULTIPLE_PROJECT';
514
    }
515
 
516
    #
517
    #   Some packages are special
518
    #
519
 
520
    if ( $packageNames[0] =~ m'^br_applet_' )
521
    {
522
        $opt_flat = 1 unless defined $opt_flat;
523
    }
524
 
525
    if ( exists $specialPackages{$packageNames[0]} )
526
    {
527
        my $data = $specialPackages{$packageNames[0]};
528
        if ( index( $data, ',all' ) >= 0) {
529
            setPruneMode('none') unless (defined $opt_pruneModeString);
530
        }
531
 
532
        if ( index( $data, 'protected,' ) >= 0) {
533
            $noTransfer = 1;
534
        }
535
 
536
        if ( index( $data, 'flat,' ) >= 0) {
537
            $opt_flat = 1;
538
        }
539
 
540
    }
541
 
542
    Message("Package Type: $packageType, $pruneModeString");
543
}
544
 
545
 
546
#-------------------------------------------------------------------------------
547
# Function        : massageData
548
#
549
# Description     : Massage all the data to create a tree of package versions
550
#                   that can be used to create images as well as an import order
551
#
552
# Inputs          : 
553
#
554
# Returns         : 
555
#
556
my $reprocess=0;
557
sub calcLinks
558
{
559
    #
560
    #   Process the 'versions' hash and:
561
    #   Add back references
562
    #   Find starts and ends
563
    #       Entry with no previous
564
    #       Entry with no next
565
    #
566
    $reprocess = 0;
567
    foreach my $entry ( keys(%versions) )
568
    {
569
        foreach ( @{ $versions{$entry}{next}} )
570
        {
571
            $versions{$_}{last} = $entry;
572
        }
573
    }
574
    @allStartPoints = ();
575
    @startPoints = ();
576
    @endPoints = ();
577
    foreach my $entry ( keys(%versions) )
578
    {
579
        push @startPoints, $entry
580
            unless ( exists $versions{$entry}{last} || $versions{$entry}{badSingleton} );
581
 
582
        push @allStartPoints, $entry
583
            unless ( exists $versions{$entry}{last} );
584
 
585
        push @endPoints, $entry
586
            unless ( @{$versions{$entry}{next}} > 0  )
587
    }
588
}
589
 
590
sub massageData
591
{
592
    #
593
    #   Report unknown suffixes
594
    #   Handle bad, or little known project suffixes by creating them
595
    #
596
    foreach my $suffix ( keys %suffixes )
597
    {
598
        if ( exists $Projects{$suffix} )
599
        {
600
            next;
601
        }
602
        Message ("Unknown project suffix: '$suffix'");
603
        push @unknownProjects, $suffix;
604
        my $cleanSuffix = ucfirst(lc(substr( $suffix, 1)));
605
        $Projects{$suffix}{Name} = 'Project_' . $cleanSuffix;
606
    }
607
 
608
    calcLinks();
609
 
610
    $initialTrees = scalar @allStartPoints;
611
    Message ('Total RM versions: ' . $totalVersions );
612
    Message ('Initial trees: ' . $initialTrees );
613
    #
614
    #   Attempt to glue all the start points into one chain.
615
    #   This should allow us to track projects that branch from each other
616
    #   in cases where the RM data is incorrect/incomplete
617
    #       Strays are those that have no next or last
618
    #
619
    #   Glue based on Name, then PVID (Creation Order)
620
    #
621
    {
622
        #
623
        #   Examine threads. If it is a single entry thats bad then drop it
624
        #   This is simple to do. Should examine all entries, but thats a
625
        #   bit harder. Perhaps later.
626
        #
627
        if (1) {
628
            Message ("Dropping Bad Singletons");
629
            my $badSingletons;
630
            foreach my $entry ( sort {$a <=> $b} @startPoints )
631
            {
632
                my $ep = $versions{$entry};
633
                unless ( $ep->{last} || $ep->{next}[0] )
634
                {
635
#                    if (  $ep->{isaWip}  )
636
                    if ( (exists $ep->{badVcsTag} && $ep->{badVcsTag}) || $ep->{isaWip}  )
637
                    {
638
                        $ep->{badSingleton} = 1;
639
                        $reprocess = 1;
640
                        $badSingletonCount++;
641
 
642
                        # Add to a list of its own.
643
                        if ( $badSingletons )
644
                        {
645
                            push @{$versions{$badSingletons}{next}}, $entry;
646
                        }
647
                        $badSingletons = $entry;
648
                    }
649
                }
650
            }
651
            calcLinks()
652
                if ( $reprocess );
653
        }
654
 
655
        #
656
        #   Create simple trees out of the chains
657
        #   Tree is based on suffix (project) and version
658
        #
659
        {
660
            my %trees;
661
            Message ("Entries into trees");
662
            foreach my $single ( @startPoints )
663
            {
664
                my $suffix = $versions{$single}{suffix} || '';
665
                push @{$trees{$suffix}}, $single;
666
            }
667
 
668
            foreach  ( keys %trees )
669
            {
670
                my $last;
671
                foreach my $entry ( sort { $versions{$a}{version} cmp $versions{$b}{version}  } @{$trees{$_}} )
672
                {
673
                    if ( $last )
674
                    {
675
                        $versions{$last}{MakeTree} = 1;
676
                        push @{$versions{$last}{next}}, $entry;
677
                        $reprocess = 1;
678
                    }
679
                    $last = $entry;
680
                }
681
            }
682
            calcLinks()
683
                if ( $reprocess );
684
        }
685
 
686
        #
687
        #   Have a number of trees that are project related
688
        #   Attempt to create a single tree by inserting
689
        #   Secondary trees into the main line at suitable points
690
        #
691
        my @AllVersions = sort { $a <=> $b } @startPoints;
692
        my $lastEntry = shift @AllVersions;
693
        Error ("Oldest entry has a previous version") if ( $versions{$lastEntry}{last}  );
694
#print "Oldest: $lastEntry\n";
695
        #
696
        #   Insert remaining entries into out list, which is now sorted
697
        #
698
        my @completeList;
699
        foreach my $base ( @AllVersions  )
700
        {
701
            push @completeList, recurseList($lastEntry);
702
            @completeList = sort {$a <=> $b} @completeList;
703
#            Message("Complete List: ", @completeList);
704
#            Message("Complete List($completeList[0]) Length: " . scalar @completeList);
705
            $lastEntry = $base;
706
 
707
            my $last;
708
            foreach my $entry ( @completeList )
709
            {
710
                if ( $entry > $base )
711
                {
712
                    Error ("Not expecting last to be empty. $base, $entry") unless ( $last );
713
                    last;
714
                }
715
                $last = $entry;
716
            }
717
 
718
            #
719
            #   Insert at end if point not yet found
720
            #
721
#print "Inserting $base at $last\n";
722
            push @{$versions{$last}{next}}, $base;
723
            $versions{$base}{GluedIn} = 1;
724
            $reprocess = 1;
725
        }
726
 
727
        #
728
        #   Recalc basic links if any processing done
729
        #
730
        calcLinks()
731
            if ( $reprocess );
732
 
733
    }
734
 
735
 
736
    #
737
    #   Remove Dead Ends
738
    #   Packages that were never released
739
    #       Not locked, unless essential or a branchpoint
740
    #   Won't consider these to be mainline path.
741
    #
742
    {
743
        Message ("Remove Dead Ends");
744
        foreach my $entry ( @endPoints )
745
        {
746
            my $deadWood;
747
            while ( $entry )
748
            {
749
                last if ( $versions{$entry}{Essential} );
750
 
751
                my @next = @{$versions{$entry}{next}};
752
                my $count = @next;
753
                last if ( $count > 1 );
754
 
755
                last unless ( $versions{$entry}{locked} eq 'N' || $versions{$entry}{isaWip} );
756
 
757
                $versions{$entry}{DeadWood} = 1;
758
                $trimCount++;
759
            } continue {
760
                $entry = $versions{$entry}{last};
761
            }
762
        }
763
    }
764
 
765
    #
766
    #   Walk each starting point list and determine new Projects
767
    #   branchpoints.
768
    #
769
    Message ("Locate Projects branch points");
770
    foreach my $bentry ( keys(%versions) )
771
    {
772
        my $baseSuffix = $versions{$bentry}{suffix};
773
        foreach my $entry ( @{$versions{$bentry}{next}} )
774
        {
775
            if ( $baseSuffix ne $versions{$entry}{suffix})
776
            {
777
                unless ( exists $versions{$entry}{DeadWood} || $versions{$entry}{badSingleton} )
778
                {
779
#print "--- Project Branch $versions{$entry}{vname}\n";
780
                    $versions{$entry}{branchPoint} = 1;
781
                    $versions{$entry}{newSuffix} = 1;
782
                }
783
            }
784
        }
785
    }
786
 
787
    #
788
    #   Prune
789
    #   Marks paths to root for all essential packages
790
    #   Marks the last-N from all essential packages
791
    #
792
    if ( $pruneMode )
793
    {
794
        Message ("Prune Tree: $pruneModeString");
795
        foreach ( @EssentialPackages )
796
        {
797
            #next unless ( exists $versions{$_} );      # Aleady deleted
798
 
799
            # Mark previous-N to be retained as well
800
            my $entry = $_;
801
            my $count = 0;
802
            while ( $entry )
803
            {
804
                last if ( $versions{$entry}{KeepMe} );
805
                unless ( $versions{$entry}{isaRipple} )
806
                {
807
                    my $keepFlag = ($count++ < $opt_retaincount);
808
                    last unless ( $keepFlag );
809
                    $versions{$entry}{KeepMe} = $keepFlag;
810
                }
811
                $entry = $versions{$entry}{last}
812
            }
813
        }
814
 
815
        #
816
        #   Keep versions that are common parents to Essential Versions
817
        #       Mark paths through the tree to essential versions
818
        #       Mark nodes with the number of essential versions that they sprout
819
        #   Don't do it if we are ripple pruning
820
        #
821
        Message ("Prune Tree keep common parents");
822
        if ( $pruneMode != 1 )
823
        {
824
            foreach my $entry ( @endPoints )
825
            {
826
                my $hasEssential = 0;
827
                $visitId++;
828
                while ( $entry )
829
                {
830
                    $hasEssential = 1 if ( exists ($versions{$entry}{Essential}) && $versions{$entry}{Essential} );
831
                    if ( $hasEssential )
832
                    {
833
                        if ( @{$versions{$entry}{next}} > 1 )
834
                        {
835
                            $versions{$entry}{EssentialSplitPoint}++;
836
                        }
837
                        last if ( exists $versions{$entry}{EssentialPath} );
838
                        $versions{$entry}{EssentialPath} = 1;
839
                    }
840
 
841
                    if ( ($versions{$entry}{visitId} || 0) == $visitId )
842
                    {
843
                        DebugDumpData ("Versions", \%versions );
844
                        Warning ("Circular dependency");
845
                        last;
846
                    }
847
                    $versions{$entry}{visitId} = $visitId;
848
 
849
                    $entry = $versions{$entry}{last};
850
                }
851
            }
852
        }
853
 
854
        #
855
        #   Keep first version of each ripple. Must keep first
856
        #   Group ripples together so that they can be proccessed at the same time
857
        #
858
        calcRippleGroups()
859
            if ( $pruneMode == 1);
860
 
861
        #
862
        #   Delete all nodes that are not marked for retention
863
        #   This is rough on the tree
864
        #
865
        Message ("Prune Tree Deleting");
866
 
867
        # 0 - Keep me
868
        # 1 - Prune me
869
        sub pruneMe
870
        {
871
            my ($entry) = @_;
872
 
873
            return 0 unless ( exists $versions{$entry} );
874
            return 0 unless ( $versions{$entry}{last} );
875
            return 0 if ( ($pruneMode == 2) && exists $versions{$entry}{KeepMe} );
876
            return 0 if ( exists $versions{$entry}{Essential} );
877
            return 0 if ( $versions{$entry}{newSuffix} );
878
            return 0 if ( $versions{$entry}{newSuffix} && (exists $versions{$entry}{EssentialPath}) );
879
#            return 1 if ( exists $versions{$entry}{DeadWood} );
880
            return 0 if ( exists $versions{$entry}{EssentialSplitPoint} && $versions{$entry}{EssentialSplitPoint} > 1 );
881
            return 0 if ( exists $versions{$entry}{keepLowestRipple} &&  $versions{$entry}{keepLowestRipple} );
882
            return 0 if ( ($pruneMode == 1) && ! $versions{$entry}{isaRipple} );
883
            return 1;
884
        }
885
 
886
        foreach my $entry ( keys(%versions) )
887
        {
888
#last;
889
            next unless ( pruneMe($entry) );
890
#print "--- Prune: $versions{$entry}{vname}\n";
891
 
892
            # Delete the current node
893
            #
894
            my @newNext;
895
            $pruneCount++;
896
            my $last = $versions{$entry}{last};
897
            foreach ( @{$versions{$last}{next}} )
898
            {
899
                next if ( $_ == $entry );
900
                push @newNext, $_;
901
            }
902
            foreach ( @{$versions{$entry}{next}} )
903
            {
904
                push @newNext, $_;
905
                $versions{$_}{last} = $last;
906
            }
907
 
908
            @{$versions{$last}{next}} = @newNext;
909
            delete $versions{$entry};
910
        }
911
 
912
        # Recalculate endpoints
913
        calcLinks();
914
    }
915
    else
916
    {
917
        #   No rippling happening
918
        #   Some process still need to happen
919
        #
920
        calcRippleGroups();
921
    }
922
 
923
    #
924
    #   Calculate best through-path for branches in the tree
925
    #   Attempt to keep that 'max' version on the mainline
926
    #   May be modified by -tip=nnnn
927
    #
928
    #   For each leaf (end point), walk backwards and mark each node with the
929
    #   max version see. If we get to a node which already has been marked then
930
    #   stop if our version is greater. We want the value to be the max version
931
    #   to a leaf
932
    #
933
    #   Account for 'suffix'. When suffix changes, then the 'max' version must
934
    #   be recalculated
935
    #
936
 
937
    Message ("Calculate Max Version");
938
    my $maxVersion;
939
 
940
    foreach my $entry ( @endPoints )
941
    {
942
        my $lastSuffix;
943
        my $forceTip;
944
        while ( $entry )
945
        {
946
            if (!defined($lastSuffix) || ($versions{$entry}{suffix} ne $lastSuffix) )
947
            {
948
                $maxVersion = '0';
949
                $visitId++;
950
                $forceTip = ( exists $tipVersions{$versions{$entry}{vname}} );
951
                delete $tipVersions{$versions{$entry}{vname}};
952
                $maxVersion = '999.999.999.999.zzz' if ( $forceTip );
953
                $lastSuffix = $versions{$entry}{suffix};
954
#print "---Tip Found\n" if $forceTip;
955
            }
956
 
957
            # Detect circular dependencies
958
            if ( ($versions{$entry}{visitId} || 0) == $visitId )
959
            {
960
                DebugDumpData ("Circular dependency: Versions", \%versions );
961
                Warning ("Circular dependency");
962
                last;
963
            }
964
            $versions{$entry}{visitId} = $visitId;
965
 
966
            my $thisVersion = $versions{$entry}{version} || '';
967
            if ( $thisVersion gt $maxVersion )
968
            {
969
                $maxVersion = $thisVersion;
970
            }
971
 
972
            if ( exists $versions{$entry}{maxVersion} )
973
            {
974
                if ( $versions{$entry}{maxVersion} gt $maxVersion )
975
                {
976
                    last;
977
                }
978
            }
979
 
980
            $versions{$entry}{maxVersion} = $maxVersion;
981
            $entry = $versions{$entry}{last};
982
        }
983
    }
984
 
985
 
986
    #
987
    #   Locate all instances where a package-version branches
988
    #   Determine the version that should be on the non-branching path
989
    #
990
    #   Reorder the 'next' list so that the first item is the non-branching
991
    #   path. This will be used in the data-insertion phase to simplify the
992
    #   processing.
993
    #
994
    Message ("Calculate package version branches");
995
    foreach my $entry ( sort {$a <=> $b} keys(%versions) )
996
    {
997
        calculateWalkOrder($entry);
998
    }
999
 
1000
    #
1001
    #   Mark Project Branch Tips as they will be in the Repository
1002
    #   Find each project head and walk primary entry to the end.
1003
    #
1004
    foreach my $entry ( keys(%versions) )
1005
    {
1006
        #
1007
        #   Root of each tree is 'new'
1008
        #
1009
        unless ( defined $versions{$entry}{last})
1010
        {
1011
            unless ( $versions{$entry}{badSingleton} )
1012
            {
1013
                $versions{$entry}{newSuffix} = 1;
1014
            }
1015
        }
1016
 
1017
        #
1018
        #   Update stats
1019
        #
1020
        $badVcsCount++ if ( $versions{$entry}{badVcsTag} );
1021
        $ProjectCount++ if ( $versions{$entry}{newSuffix} );
1022
        next if ( $opt_flat );
1023
 
1024
        next unless ($versions{$entry}{newSuffix} );
1025
#print "--- Project new Suffix $versions{$entry}{vname}\n";
1026
 
1027
 
1028
        my $suffix = $versions{$entry}{suffix};
1029
        $knownProjects{$suffix}{count}++;
1030
 
1031
        my $next = $versions{$entry}{next}[0];
1032
        my $tip;
1033
        while ( $next )
1034
        {
1035
            last if ( $suffix ne $versions{$next}{suffix} );
1036
            $tip = $next unless (exists ($versions{$next}{DeadWood}) || $versions{$next}{badSingleton});
1037
            $next = $versions{$next}{next}[0];
1038
        }
1039
 
1040
        $versions{$tip}{Tip} = 1 if $tip;
1041
    }
1042
 
1043
    unless ( $opt_flat )
1044
    {
1045
        my $finalTrees = scalar @startPoints;
1046
        Warning ("Still have multiple trees: $finalTrees") unless ( $finalTrees == 1 );
1047
    }
1048
 
1049
    #
1050
    #   Display warnings about multiple
1051
    #
1052
    foreach ( sort keys %knownProjects )
1053
    {
1054
        my $count = $knownProjects{$_}{count} || 0;
1055
        Warning ("Multiple Project Roots: $_ ($count)" )
1056
            if ( $count > 1 );
1057
    }
1058
 
1059
    #
1060
    #   Display warnings about Bad Essential Packages
1061
    #
1062
    $allSvn = 1;
1063
    foreach my $entry ( keys(%versions) )
1064
    {
1065
        $rippleCount++ if ( exists($versions{$entry}{isaRipple}) && $versions{$entry}{isaRipple} );
1066
        $allSvn = 0 unless ( $versions{$entry}{isSvn} );
1067
        next unless ( exists $versions{$entry}{Essential}  );
1068
        next unless ( $versions{$entry}{badVcsTag}  );
1069
        push @badEssentials, $entry;
1070
        Warning ("BadVCS Essential: " . GetVname($entry))
1071
    }
1072
 
1073
    #
1074
    #   All done
1075
    #
1076
    Message("Retained entries: " . (scalar keys %versions) );
1077
    Message("Pruned entries: $pruneCount");
1078
    Message("Deadwood entries: $trimCount");
1079
    Message("Bad Singletons: $badSingletonCount");
1080
    Message("Ripples: $rippleCount");
1081
}
1082
 
1083
sub calculateWalkOrder
1084
{
1085
    my ($entry) = @_;
1086
    my @next = @{$versions{$entry}{next}};
1087
    my $count = @next;
1088
    my @ordered;
1089
    my $main;
1090
 
1091
    if ( $count > 1 )
1092
    {
1093
        # Array to hash to simplify removal
1094
        my %nexts = map { $_ => 1 } @next;
1095
        foreach my $e ( @next )
1096
        {
1097
 
1098
            #
1099
            #   Locate branch points that are not a part of a new project
1100
            #   These will not be preferred paths for walking
1101
            #
1102
            if ( !defined($versions{$e}{branchPoint}) && $versions{$entry}{suffix} ne $versions{$e}{suffix} )
1103
            {
1104
                unless ( exists $versions{$e}{DeadWood} || $versions{$e}{badSingleton}  )
1105
                {
1106
#print "--- Project Branch (1) $versions{$e}{vname}\n";
1107
                    $versions{$e}{branchPoint} = 1;
1108
                    $versions{$e}{newSuffix} = 1;
1109
                }
1110
            }
1111
 
1112
            #
1113
            #   Remove those that already have a branch,
1114
            #
1115
            if ( $versions{$e}{branchPoint} || $versions{$e}{newSuffix} || $versions{$e}{DeadWood}  )
1116
            {
1117
                push @ordered, $e;
1118
                delete $nexts{$e};
1119
            }
1120
        }
1121
        #
1122
        #   Select longest arm as the non-branching path
1123
        #   Note: Reverse sort order
1124
        #         Done so that 'newest' item is given preference
1125
        #         to the main trunk in cases where all subtrees are
1126
        #         the same length
1127
        #
1128
        my $maxData = '';
1129
        my $countEntry;
1130
        foreach my $e ( sort {$b <=> $a} keys %nexts )
1131
        {
1132
            if ( $versions{$e}{maxVersion} gt $maxData )
1133
            {
1134
                $maxData = $versions{$e}{maxVersion};
1135
                $countEntry = $e;
1136
            }
1137
        }
1138
        if ($countEntry)
1139
        {
1140
            $main = $countEntry;
1141
            delete $nexts{$countEntry};
1142
        }
1143
 
1144
        #
1145
        #   Append the remaining
1146
        #
1147
        push @ordered, keys %nexts;
1148
 
1149
        #
1150
        #   Re-order 'next' so that the main path is first
1151
        #   Sort (non main) by number
1152
        #
1153
        @ordered = sort {$a <=> $b} @ordered;
1154
        unshift @ordered, $main if ( $main );
1155
        @{$versions{$entry}{next}} = @ordered;
1156
 
1157
        #
1158
        #   Ensure all except the first are a branch point
1159
        #   First may still be a branch point
1160
        #
1161
        shift @ordered;
1162
        foreach my $e ( @ordered )
1163
        {
1164
            $versions{$e}{branchPoint} = 1;
1165
        }
1166
    }
1167
}
1168
 
1169
#-------------------------------------------------------------------------------
1170
# Function        : calcRippleGroups
1171
#
1172
# Description     : Locate and mark ripple groups
1173
#                   packages that are ripples fo each other
1174
#                       Keep first version of each ripple. Must keep first
1175
#                       Group ripples together so that they can be
1176
#                       proccessed at the same time
1177
#
1178
# Inputs          : 
1179
#
1180
# Returns         : 
1181
#
1182
sub calcRippleGroups
1183
{
1184
    my %rippleVersions;
1185
    foreach my $entry ( keys(%versions) )
1186
    {
1187
        my $ep = $versions{$entry};
1188
        if ( defined $ep->{buildVersion} )
1189
        {
1190
            my $suffix = $ep->{suffix};
1191
            my ($major, $minor, $patch, $build) = @{$ep->{buildVersion}};
1192
#print "--- $major, $minor, $patch, $build, $suffix\n";
1193
            $rippleVersions{$suffix}{"$major.$minor.$patch"}{count}++;
1194
            my $rp = $rippleVersions{$suffix}{"$major.$minor.$patch"};
1195
            $rp->{list}{$entry} = 1;
1196
 
1197
            next if ( $ep->{badVcsTag} );
1198
            next if ( $ep->{locked} eq 'N');
1199
            if (!defined ($rp->{min}) || $rp->{min} > $build )
1200
            {
1201
                $rp->{pvid} = $entry;
1202
                $rp->{min} = $build;
1203
            }
1204
        }
1205
    }
1206
#            DebugDumpData("rippleVersions", \%rippleVersions );
1207
 
1208
    while ( my($suffix, $e1) = each %rippleVersions )
1209
    {
1210
        while ( my( $mmp, $e2) = each %{$e1} )
1211
        {
1212
            next unless ( exists  $e2->{pvid} );
1213
            my $entry = $e2->{pvid};
1214
            if ( !exists $versions{$entry} )
1215
            {
1216
                Error ("Internal: Expected entry not found: $entry, $mmp");
1217
            }
1218
 
1219
            $versions{$entry}{keepLowestRipple} = 1;
1220
#print "--- Keep Riple $versions{$entry}{vname}\n";
1221
 
1222
            #
1223
            #   Update entry with list of associated ripples, removing lowest
1224
            #
1225
            delete $e2->{list}{$entry};
1226
            my @rippleList = sort keys %{$e2->{list}};
1227
            if ( @rippleList)
1228
            {
1229
#DebugDumpData("LIST: $entry", $e2->{list}, \@rippleList  );
1230
                @{$versions{$entry}{rippleList}} = @rippleList;
1231
            }
1232
        }
1233
    }
1234
}
1235
 
1236
#-------------------------------------------------------------------------------
1237
# Function        : processBranch
1238
#
1239
# Description     : Process one complete branch within the tree of versions
1240
#                   May be called recursivly to walk the tree
1241
#
1242
# Inputs          : Array of package-version ID to process
1243
#
1244
# Returns         : Nothing
1245
#
1246
 
1247
sub processBranch
1248
{
1249
    foreach my $entry ( @_ )
1250
    {
1251
        #
1252
        #   Do we need to create a branch before we can process this package
1253
        #
1254
        if ( $versions{$entry}{newSuffix} || $versions{$entry}{branchPoint} )
1255
        {
1256
            newProject();
1257
            $createBranch = 1;
1258
            $createSuffix = 1 if $versions{$entry}{newSuffix};
1259
        }
1260
 
1261
        newPackageVersion( $entry );
1262
no warnings "recursion";
1263
        processBranch (@{$versions{$entry}{next}});
1264
    }
1265
}
1266
 
1267
#-------------------------------------------------------------------------------
1268
# Function        : newPackageVersion
1269
#
1270
# Description     : Create a package version
1271
#
1272
# Inputs          : $entry              - Ref to entry being proccessed
1273
#
1274
# Returns         :
1275
#
1276
sub newPackageVersion
1277
{
1278
    my ($entry) = @_;
1279
    my %data;
1280
    my $flags = 'e';
1281
    my $rv = 1;
1282
    my $startTime = time();
1283
    my $timestamp = localtime;
1284
 
1285
    $data{rmRef} = 'ERROR';
1286
    $data{tag} = 'ERROR';
1287
 
1288
    #
1289
    #   If its been processed then fake that its been done
1290
    #   May have been a ripple that we processed
1291
    #
1292
    Message ("------------------------------------------------------------------" );
1293
    Message ("New package-version: " . GetVname($entry) . " Tag: " . $versions{$entry}{vcsTag} );
1294
    return if ($versions{$entry}{Processed});
1295
 
1296
 
1297
    #
1298
    #   If we have a global error,then we pretend to process, but we
1299
    #   report errors for the logging system
1300
    #
1301
    unless ( $globalError )
1302
    {
1303
        #
1304
        #   Call worker function
1305
        #   It will exist on any error so that it can be logged
1306
        #
1307
        $rv = newPackageVersionBody( \%data, @_ );
1308
        $globalError = 1 if ( $rv >= 10 );
1309
    }
1310
 
1311
    #
1312
    #   Highlight essential packages that failed to transfer
1313
    #
1314
    if ( $globalError ) {
1315
        $flags = 'e';
1316
    } elsif ( $rv && ( exists $versions{$entry}{Essential} ) ) {
1317
        $flags = 'X';
1318
    } elsif ( $rv ) {
1319
        $flags = 'E';
1320
    } else {
1321
        $flags = 'G';
1322
    }
1323
 
1324
    #
1325
    #   Always log results to a file
1326
    #   Flags:
1327
    #       e - Error: Global Fatal causes other versions to be ignored
1328
    #       X - Essential Package NOT proccessed
1329
    #       E - Error processing package
1330
    #       G - Good
1331
    #
1332
    my $duration = time() - $startTime;
1333
    my $line = join(';',
1334
            $flags,
1335
            $entry,
1336
            $packageNames,
1337
            $versions{$entry}{vname},
1338
            $data{rmRef},
1339
            $data{tag},
1340
            $timestamp,
1341
            $duration,
1342
            $data{errStr} || ''
1343
            );
1344
    logToFile( $cwd . '/importsummary.txt', ";$line;");
1345
 
1346
    #
1347
    #   Sava data
1348
    #
1349
    $versions{$entry}{rmRef} = $data{rmRef};
1350
    $versions{$entry}{errStr} = $data{errStr};
1351
    $versions{$entry}{errFlags} = $flags;
1352
 
1353
    #
1354
    #   Delete the created view
1355
    #   Its just a directory, so delete it
1356
    #
1357
    if ( $data{ViewRoot} && -d $data{ViewRoot})
1358
    {
1359
        RmDirTree ($data{ViewRoot} ) if ( !$opt_reuse || $rv );
1360
    }
1361
 
1362
 
1363
    #
1364
    #   If this version has any 'ripples' then process them while we have the
1365
    #   main view. Note the ripple list may contain entries that do not
1366
    #   exist - they will have been pruned.
1367
    #
1368
    foreach my $rentry ( @{$versions{$entry}{rippleList}} )
1369
    {
1370
        next unless( exists $versions{$rentry} );
1371
 
1372
        if ($versions{$rentry}{Processed})
1373
        {
1374
            Warning ("Ripple Processed before main entry");
1375
            $versions{$rentry}{rippleProcessed} = 1;
1376
        }
1377
 
1378
        Message ("Proccessing associated Ripple: " . GetVname($rentry));
1379
        newPackageVersion($rentry);
1380
    }
1381
}
1382
 
1383
#-------------------------------------------------------------------------------
1384
# Function        : newPackageVersionBody
1385
#
1386
# Description     : Perform the bulk of the work in creating a new PackageVersion
1387
#                   Designed to return on error and have error processing
1388
#                   performed by caller
1389
#
1390
# Inputs          : $data               - Shared data
1391
#                   $entry              - Package entry to process
1392
#
1393
# Returns         : Error Code
1394
#                         0 - All is well
1395
#                       <10 - Recoveralble error
1396
#                       >10 - Fatal error
1397
#
1398
sub newPackageVersionBody
1399
{
1400
    my ($data, $entry) = @_;
1401
    my $rv;
1402
    my $cc_label;
1403
    my $cc_path;
1404
 
1405
    #
1406
    #   Init Data
1407
    #
1408
    $data->{rmRef} = 'ERROR';
1409
    $data->{tag} = '';
1410
    $data->{ViewRoot} = undef;
1411
    $data->{ViewPath} = undef;
1412
    $data->{flags} = undef;
1413
    $data->{errStr} = '';
1414
    $versions{$entry}{Processed} = 1;
1415
 
1416
 
1417
    SystemConfig ('ExitOnError' => 0);
1418
 
1419
    push @processOrder, $entry;
1420
    return 0 if ( $opt_test );
1421
 
1422
#   Keep DeadWood. May be a WIP
1423
#    if ( exists $versions{$entry}{DeadWood} && $versions{$entry}{DeadWood} )
1424
#    {
1425
#        $data->{errStr} = 'Package is DeadWood';
1426
#        return 3;
1427
#    }
1428
 
1429
    #
1430
    #   Determine version information
1431
    #
1432
    $data->{tag} = $versions{$entry}{vcsTag} || '';
1433
    if ( $versions{$entry}{badVcsTag} )
1434
    {
1435
        Warning ("Error: Bad VcsTag for: " . GetVname($entry),
1436
                 "Tag: $data->{tag}" );
1437
        $data->{errStr} = 'VCS Tag Marked as Bad';
1438
        return 1;
1439
    }
1440
 
1441
 
1442
    $data->{tag} =~ m~^(.+?)::(.*?)(::(.+))?$~;
1443
    $cc_label = $4;
1444
    $cc_path = $2;
1445
    $cc_path = '/' . $cc_path;
1446
    $cc_path =~ tr~\\/~/~s;
1447
 
1448
    #
1449
    #   Correct well known path mistakes
1450
    #
394 dpurdie 1451
    $cc_path =~ s~/MASS_Dev/Bus/~/MASS_Dev_Bus/~i;
392 dpurdie 1452
    $cc_path =~ s~/MASS_Dev_Bus/Cbp/~/MASS_Dev_Bus/CBP/~i;
1453
    $cc_path =~ s~/MREF_Package/ergpostmongui$~/MREF_Package/ergpostmongui~i;
1454
 
1455
#print "--- Path: $cc_path, Label: $cc_label\n";
1456
 
1457
    #
1458
    #   Create CC view
1459
    #   Import into Subversion View
1460
    #
1461
    $data->{ViewRoot} = $opt_name ? $opt_name : "$cc_label";
1462
    $data->{ViewPath} =  $data->{ViewRoot} . '/' . $cc_path;
1463
    $data->{ViewPath} =~  tr~/~/~s;
1464
 
1465
    if ( $opt_reuse && -d $data->{ViewPath}  )
1466
    {
1467
        Message ("Reusing view: $cc_label");
1468
    }
1469
    else
1470
    {
1471
        my @args;
1472
        push (@args, '-view', $opt_name ) if ( defined $opt_name );
1473
        $rv = JatsToolPrint ( 'jats_ccrelease', '-extractfiles', '-root=.' , '-noprefix',
1474
                    "-label=$cc_label" ,
1475
                    "-path=$cc_path",
1476
                    @args
1477
                    );
1478
 
1479
        unless ( -d $data->{ViewPath}  )
1480
        {
1481
            $data->{errStr} = 'Failed to extract files from CC';
1482
            return 2;
1483
        }
1484
    }
1485
 
1486
    #
1487
    #   Have a CC view
1488
    #   Now we can create the SVN package and branching point before we
1489
    #   import the CC data into SVN
1490
    #
1491
    my @args;
1492
 
1493
    #
1494
    #   Calculate args for functions
1495
    #
1496
    my $author = $versions{$entry}{created_id};
1497
    if ( $author )
1498
    {
1499
        push @args, '-author', $author;
1500
    }
1501
    my $created = $versions{$entry}{created};
1502
    if ( $created )
1503
    {
1504
        $created =~ s~ ~T~;
1505
        $created .= '00000Z';
1506
        push @args, '-date', $created;
1507
    }
1508
 
1509
    my $log = $versions{$entry}{comment};
1510
    if ( $log )
1511
    {
1512
        push @args, '-log', $log;
1513
    }
1514
 
1515
    #
1516
    #   Create package skeleton if needed
1517
    #
1518
    $rv = createPackage( $author, $created);
1519
    if ( $rv )
1520
    {
1521
        $data->{errStr} = 'Failed to create Package';
1522
        return 10;
1523
    }
1524
 
1525
    #
1526
    #   Calculate the label for the target package
1527
    #   Use format <packageName>_<PackageVersion>
1528
    #   Need to handle WIPs too.
1529
    #
1530
    my $import_label = saneLabel($entry);
1531
 
1532
    #
1533
    #   May need to create the branchpoint
1534
    #   The process is delayed until its needed so avoid creating unneeded
1535
    #   branch points
1536
    #
1537
    if ( $createBranch )
1538
    {
1539
        $rv = createBranchPoint ($entry, $author, $created);
1540
        $createBranch = 0;
1541
        $createSuffix = 0;
1542
        if ( $rv )
1543
        {
1544
            $data->{errStr} = 'Failed to create Branch Point';
1545
            return 11;
1546
        }
1547
    }
1548
    push @args, "-branch=$currentBranchName" if ( defined $currentBranchName );
1549
 
1550
    my $datafile = "importdata.$import_label.properties";
1551
    $rv = JatsToolPrint ( 'jats_svn', 'import', '-reuse' ,
1552
                    "-package=$svnRepo/$packageNames",
1553
                    "-dir=$data->{ViewPath}",
1554
                    "-label=$import_label",
1555
                    "-datafile=$datafile",
1556
                    @args,
1557
                     );
1558
 
1559
    if ( $rv )
1560
    {
1561
        $data->{errStr} = 'Failed to import to SVN';
1562
        return 12;
1563
    }
1564
 
1565
    $versions{$entry}{TagCreated} = 1;
1566
    $firstVersionCreated = $entry unless ( $firstVersionCreated );
1567
 
1568
    #
1569
    #   Read in the Rm Reference
1570
    #   Retain entries in a global file
1571
    #
1572
    if ( -f $datafile  )
1573
    {
1574
        my $rmData = JatsProperties::New($datafile);
1575
        $data->{rmRef} = 'SVN::' . $rmData->getProperty('subversion.tag');
1576
    }
1577
 
1578
    unless ( $data->{rmRef}  )
1579
    {
1580
        $data->{errStr} = 'Failed to determin Rm Reference';
1581
        return 13;
1582
    }
1583
 
1584
    Message ("RM Ref: $data->{rmRef}");
1585
    unlink $datafile;
1586
 
1587
    #
1588
    #   All is good
1589
    #
1590
    $data->{errStr} = '';
1591
    return 0;
1592
}
1593
 
1594
 
1595
#-------------------------------------------------------------------------------
1596
# Function        : newProject
1597
#
1598
# Description     : Start a new project within a package
1599
#
1600
# Inputs          : 
1601
#
1602
# Returns         : 
1603
#
1604
sub newProject
1605
{
1606
#    Message ("---- New Project");
1607
    $createSuffix = 0;
1608
 
1609
    #
1610
    #   New project
1611
    #   Kill the running import directory
1612
    #
1613
    RmDirTree ('SvnImportDir');
1614
}
1615
 
1616
#-------------------------------------------------------------------------------
1617
# Function        : newPackage
1618
#
1619
# Description     : Start processing a new package
1620
#
1621
# Inputs          : 
1622
#
1623
# Returns         : 
1624
#
1625
my $createPackageDone;
1626
sub newPackage
1627
{
1628
#    Message( "---- New Package");
1629
 
1630
    #
1631
    #   Create a package specific log file
1632
    #
1633
    $logSummary = $packageNames . ".summary.log";
1634
    unlink $logSummary;
1635
    Message( "PackageName: $packageNames");
1636
    $createPackageDone = 1;
1637
    $createBranch = 0;
1638
    $createSuffix = 0;
1639
 
1640
    #
1641
    #   First entry being created
1642
    #   Prime the work area
1643
    #
1644
    RmDirTree ('SvnImportDir');
1645
}
1646
 
1647
#-------------------------------------------------------------------------------
1648
# Function        : createPackage
1649
#
1650
# Description     : Create a new Package in SVN
1651
#                   Called before any serious SVN operation to ensure that the
1652
#                   package has been created. Don't create a package until
1653
#                   we expect to put something into it.
1654
#
1655
#                   Will only create a package once
1656
 
1657
#
1658
# Inputs          : $author         - Who done it
1659
#                   $date           - When
1660
#
1661
# Returns         : 
1662
#
1663
sub createPackage
1664
{
1665
    my ($author, $date) = @_;
1666
    my @opts;
1667
    push (@opts, '-date', $date) if ( $date );
1668
    push (@opts, '-author', $author) if ( $author );
1669
    #
1670
    #   Only do once
1671
    #
1672
    return unless ( $createPackageDone );
1673
    $createPackageDone = 0;
1674
 
1675
    Message ("Creating new SVN package: $packageNames");
1676
    JatsToolPrint ( 'jats_svn', 'delete-package', '-noerror',  "$svnRepo/$packageNames" );
1677
    JatsToolPrint ( 'jats_svn', 'create', "$svnRepo/$packageNames", @opts );
1678
}
1679
 
1680
 
1681
#-------------------------------------------------------------------------------
1682
# Function        : createBranchPoint
1683
#
1684
# Description     : Create a branch point for the current work
1685
#                   Perform the calculation to determine the details of
1686
#                   the branch point. The work will only be done when its
1687
#                   needed. This will avoid the creation of branchpoints
1688
#                   that are not used.
1689
#
1690
# Inputs          : $entry                  Entry being processed
1691
#                   $author         - Who done it
1692
#                   $date           - When
1693
#
1694
# Returns         : 
1695
#
1696
sub createBranchPoint
1697
{
1698
    my ($entry, $author, $date) = @_;
1699
    my $forceNewProject;
1700
 
1701
#    Message ("---- Create Branch Point");
1702
 
1703
    #
1704
    #   Find previous good tag
1705
    #   We are walking a tree so something should have been created, but
1706
    #   the one we want may have had an error
1707
    #
1708
    #   Walk backwards looking for one that has been created
1709
    #
1710
    my $last = $versions{$entry}{last};
1711
    while ( $last )
1712
    {
1713
        unless ( $versions{$last}{TagCreated} )
1714
        {
1715
            $last = $versions{$last}{last};
1716
        }
1717
        else
1718
        {
1719
            last;
1720
        }
1721
    }
1722
 
1723
    #
1724
    #   If we have walked back to the base of the tree
1725
    #   If we transferred any software at all, then use the first
1726
    #   version as the base for this disconnected version
1727
    #
1728
    #   Otherwise we create a new, and empty, view
1729
    #
1730
    unless ( $last )
1731
    {
1732
        if ( $firstVersionCreated )
1733
        {
1734
            Warning ("Cannot find previous version to branch. Use first version");
1735
            $last = $firstVersionCreated;
1736
        }
1737
        else
1738
        {
1739
            Warning ("Forcing First instance of a Project");
1740
            $forceNewProject = 1;
1741
        }
1742
    }
1743
 
1744
    #
1745
    #   Determine source name
1746
    #   This MUST have been created before we can branch
1747
    #
1748
    my $src_label;
1749
    $src_label = saneLabel($last) if $last;
1750
 
1751
    #
1752
    #   Create target name
1753
    #
1754
    my $tgt_label;
1755
    if ( $forceNewProject || $versions{$entry}{newSuffix} || $createSuffix || !defined $src_label )
1756
    {
1757
        #
1758
        #   Create target name based on project
1759
        #
1760
        return if ( $singleProject );
1761
 
1762
        my $suffix = $versions{$entry}{suffix};
1763
        if ( $suffix )
1764
        {
1765
            Error ("Unknown Project: $suffix") unless ( defined $Projects{$suffix} );
1766
 
1767
            #
1768
            #   If this project can be considered to be a truck, then 'claim' the
1769
            #   truck for the first created element.
1770
            #
1771
            if ( $Projects{$suffix}{Trunk} )
1772
            {
1773
                # This project can use the trunk, if it has not been allocated.
1774
                $ProjectTrunk = $suffix unless ( defined $ProjectTrunk );
1775
 
1776
                #
1777
                #   If this package has multiple instances of the potential
1778
                #   trunk, then don't place either of them on the trunk as it
1779
                #   may cause confusion
1780
                #
1781
                if ($knownProjects{$suffix}{count} < 2 )
1782
                {
1783
                    if ( $suffix eq $ProjectTrunk )
1784
                    {
1785
                        return unless $currentBranchName;
1786
                    }
1787
                }
1788
            }
1789
 
1790
            $tgt_label = $Projects{$suffix}{Name};
1791
            $tgt_label = $versions{$entry}{name} . '_' . $tgt_label if ($multiPackages);
1792
            if ( !exists $ProjectsBaseCreated{$tgt_label}  )
1793
            {
1794
                $ProjectsBaseCreated{$tgt_label} = 1;
1795
            }
1796
            else
1797
            {
1798
                #   Project Base Already taken
1799
                #   Have disjoint starting points
1800
                $tgt_label .= '.' . $ProjectsBaseCreated{$tgt_label} ++;
1801
            }
1802
        }
1803
        else
1804
        {
1805
            #
1806
            #   No suffix in use
1807
            #
1808
            #   Currently not handled
1809
            #   May have to force the use of the trunk
1810
            #
1811
            Error ("INTERNAL ERROR: No suffix present");
1812
        }
1813
    }
1814
    else
1815
    {
1816
        $tgt_label = saneLabel($entry, $src_label . '_for_');
1817
    }
1818
 
1819
    #
1820
    #   Save branch name for use when populating sandbox
1821
    #
1822
    $currentBranchName = $tgt_label;
1823
 
1824
    #
1825
    #   Perform the branch
1826
    #
1827
    if ( defined $src_label )
1828
    {
1829
        my @opts;
1830
        push (@opts, '-date', $date) if ( $date );
1831
        push (@opts, '-author', $author) if ( $author );
1832
 
1833
        JatsToolPrint ( 'jats_svnlabel',
1834
                        '-packagebase', "$svnRepo/$packageNames",
1835
                        'tags/' . $src_label,
1836
                        '-branch',
1837
                        '-clone', $tgt_label,
1838
                        @opts
1839
                      );
1840
    }
1841
}
1842
 
1843
 
1844
#-------------------------------------------------------------------------------
1845
# Function        : endPackage
1846
#
1847
# Description     : End of package processing
1848
#                   Clean up and display problems
1849
#
1850
# Inputs          : 
1851
#
1852
# Returns         : 
1853
#
1854
sub endPackage
1855
{
1856
    RmDirTree ('SvnImportDir');
1857
 
1858
    #
1859
    #   Display versions that did get captured
1860
    #
1861
    foreach my $entry ( @processOrder )
1862
    {
1863
        $versions{$entry}{Scanned} = 1;
1864
        next unless ( $versions{$entry}{TagCreated} );
1865
        Warning ("Processed: " . GetVname($entry) . ' :: ' . $versions{$entry}{rmRef} || $versions{$entry}{errStr} || '???' );
1866
    }
1867
 
1868
    #
1869
    #   Display versions that did not get created
1870
    #
1871
    foreach my $entry ( @processOrder )
1872
    {
1873
        $versions{$entry}{Scanned} = 1;
1874
        next if ( $versions{$entry}{TagCreated} );
1875
        Warning ("Not Processed: " . GetVname($entry) );
1876
    }
1877
 
1878
    foreach my $entry ( keys(%versions) )
1879
    {
1880
        next if ( $versions{$entry}{Scanned} );
1881
        Warning ("(E) INTERNAL ERROR. Package Not Processed: " . GetVname($entry) );
1882
    }
1883
 
1884
    Message ("All Done");
1885
}
1886
 
1887
sub JatsToolPrint
1888
{
1889
    Information ("Command: @_");
1890
    JatsTool @_;
1891
}
1892
 
1893
sub GetVname
1894
{
1895
    my ($entry) = @_;
1896
    my $me = 'NONE';
1897
    if ( $entry )
1898
        {
1899
        $me = $versions{$entry}{vname};
1900
        unless ( $me )
1901
        {
1902
            $me = 'Unknown-' . $entry;
1903
        }
1904
    }
1905
    return $me;
1906
}
1907
 
1908
sub saneLabel
1909
{
1910
    my ($entry, $pkgname) = @_;
1911
    my $me = $versions{$entry}{vname};
1912
    $pkgname = $versions{$entry}{name} unless ( defined $pkgname );
1913
 
1914
    Error ("Package does have a version string: pvid: $entry")
1915
        unless ( defined $me );
1916
 
1917
    #
1918
    #   Convert Wip format (xxxx) into a string that can be used for a label
1919
    #
1920
    if ( $me =~ m~^(.*)\((.*)\)(.*)$~ )
1921
    {
1922
        $me = $1 . '_' . $2 . '_' . $3 . '.WIP';
1923
        $me =~ s~_\.~.~;
1924
        $me =~ s~^_~~;
1925
    }
1926
 
1927
    #
1928
    #   Allow for WIPS
1929
    #   Get rid of multiple '_'
1930
    #   Replace space with -
1931
    #
1932
    $me = $pkgname . '_' . $me;
1933
    $me =~ tr~ ~-~s;
1934
    $me =~ tr~-~-~s;
1935
    $me =~ tr~_~_~s;
1936
 
1937
    return $me;
1938
}
1939
 
1940
 
1941
exit 0;
1942
 
1943
 
1944
#-------------------------------------------------------------------------------
1945
# Function        : GetPkgIdByName
1946
#
1947
# Description     :
1948
#
1949
# Inputs          : pkg_name
1950
#
1951
# Returns         : pkg_id
1952
#
1953
sub GetPkgIdByName
1954
{
1955
    my ( $pkg_name ) = @_;
1956
    my (@row);
1957
    my $pv_id;
1958
    my $pkg_id;
1959
 
1960
    #
1961
    #   Establish a connection to Release Manager
1962
    #
1963
    connectRM(\$RM_DB) unless ( $RM_DB );
1964
 
1965
    #
1966
    #   Extract data from Release Manager
1967
    #
1968
    my $m_sqlstr = "SELECT pkg.PKG_NAME, pkg.PKG_ID" .
1969
                   " FROM RELEASE_MANAGER.PACKAGES pkg" .
1970
                   " WHERE pkg.PKG_NAME = \'$pkg_name\'";
1971
 
1972
    my $sth = $RM_DB->prepare($m_sqlstr);
1973
    if ( defined($sth) )
1974
    {
1975
        if ( $sth->execute( ) )
1976
        {
1977
            if ( $sth->rows )
1978
            {
1979
                while ( @row = $sth->fetchrow_array )
1980
                {
1981
                    Verbose( "DATA: " . join(',', @row) );
1982
                    $pkg_id = $row[1] || 0;
1983
                    last;
1984
                }
1985
            }
1986
            else
1987
            {
1988
                Error ("GetPkgIdByName:No Data for package: $pkg_name");
1989
            }
1990
            $sth->finish();
1991
        }
1992
    }
1993
    else
1994
    {
1995
        Error("GetPkgIdByName:Prepare failure" );
1996
    }
1997
 
1998
    return $pkg_id;
1999
}
2000
 
2001
#-------------------------------------------------------------------------------
2002
# Function        : GetData_by_pkg_id
2003
#
2004
# Description     :
2005
#
2006
# Inputs          : pv_id
2007
#
2008
# Returns         :
2009
#
2010
sub GetData_by_pkg_id
2011
{
2012
    my ( $pkg_id, $packageName ) = @_;
2013
    my (@row);
2014
 
2015
    #
2016
    #   Establish a connection to Release Manager
2017
    #
2018
    Message ("Extract package versions from Release Manager: $packageName");
2019
    connectRM(\$RM_DB) unless ( $RM_DB );
2020
 
2021
    #
2022
    #   Extract data from Release Manager
2023
    #
2024
    my $m_sqlstr = "SELECT pkg.PKG_NAME, pv.PKG_VERSION, pkg.PKG_ID, pv.PV_ID, pv.LAST_PV_ID, pv.MODIFIED_STAMP, release_manager.PK_RMAPI.return_vcs_tag(pv.PV_ID), amu.USER_NAME, pv.COMMENTS, pv.DLOCKED, pv.CREATOR_ID ".
2025
                   " FROM RELEASE_MANAGER.PACKAGES pkg, RELEASE_MANAGER.PACKAGE_VERSIONS pv, ACCESS_MANAGER.USERS amu" .
2026
                   " WHERE pv.PKG_ID = \'$pkg_id\' AND pkg.PKG_ID = pv.PKG_ID AND amu.USER_ID (+) = pv.CREATOR_ID";
2027
 
2028
 
2029
    my $sth = $RM_DB->prepare($m_sqlstr);
2030
    if ( defined($sth) )
2031
    {
2032
        if ( $sth->execute( ) )
2033
        {
2034
            if ( $sth->rows )
2035
            {
2036
                while ( @row = $sth->fetchrow_array )
2037
                {
2038
                    Verbose( "DATA: " . join(',', @row) );
2039
                    my $pkg_name = $row[0] || 'Unknown';
2040
                    my $pkg_ver = $row[1] || 'Unknown';
2041
                       $pkg_ver =~ s~\s+$~~;
2042
                       $pkg_ver =~ s~^\s+~~;
2043
                    my $pv_id = $row[3] || 'Unknown';
2044
                    my $last_pv_id = $row[4];
2045
                    my $created =  $row[5] || 'Unknown';
2046
                    my $vcstag =  $row[6] || 'Unknown';
2047
                       $vcstag =~ tr~\\/~/~s;
2048
 
2049
                    my $created_id =  $row[7] || ($row[10] ? "Userid_$row[10]" :'Unknown');
2050
                    my $comment =  $row[8] || '';
2051
                    my $locked =  $row[9] || 'N';
2052
 
2053
                    #
2054
                    #   Some developers have a 'special' package version
2055
                    #   We really need to ignore them
2056
                    #
2057
                    next if ( $pkg_ver eq '23.23.23.ssw' );
2058
 
2059
                    #
2060
                    #   Add data to the hash
2061
                    #       Remove entries that address themselves
2062
                    #
2063
                    push (@{$versions{$last_pv_id}{next}}, $pv_id) unless ($pv_id == $last_pv_id || $last_pv_id == 0) ;
2064
                    $versions{$pv_id}{name} = $pkg_name;
2065
                    $versions{$pv_id}{pvid} = $pv_id;
2066
                    $versions{$pv_id}{vname} = $pkg_ver;
2067
                    $versions{$pv_id}{vcsTag} = $vcstag;
2068
                    $versions{$pv_id}{created} = $created;
2069
                    $versions{$pv_id}{created_id} = $created_id;
2070
                    $versions{$pv_id}{comment} = $comment;
2071
                    $versions{$pv_id}{locked} = $locked;
2072
                    $versions{$pv_id}{TimeStamp} = str2time( $created );
2073
                    $versions{$pv_id}{Age} = ($now - $versions{$pv_id}{TimeStamp}) / (60 * 60 * 24);
2074
                    $versions{$pv_id}{TooOld} = 1 if ( $opt_age && $opt_age <= $versions{$pv_id}{Age} );
2075
                    examineVcsTag($pv_id);
2076
 
2077
                    #
2078
                    #   Process version number
2079
                    #
2080
                    my ($suffix, $version, $isaR, $isaWip, $buildVersion ) = massageVersion($pkg_ver, $pkg_name);
2081
 
2082
                    $versions{$pv_id}{version} = $version;
2083
                    $versions{$pv_id}{buildVersion} = $buildVersion;
2084
                    $versions{$pv_id}{isaRipple} = 1 if ( $isaR );
2085
                    $versions{$pv_id}{isaWip} = 1 if ( $isaWip );
2086
 
2087
                    #
2088
                    #   Process suffix
2089
                    #
2090
                    $suffix = 'Unknown' unless ( $suffix );
2091
                    $suffix = lc ($suffix);
2092
                    $versions{$pv_id}{suffix} = $suffix;
2093
                    push @{$suffixes{$suffix}}, $pv_id;
2094
 
2095
#                    print "$pkg_name, $pkg_ver, $pv_id, $last_pv_id, $locked, $created, $created_id, $suffix\n";
2096
                }
2097
            }
2098
            else
2099
            {
2100
                Error ("GetData_by_pkg_id: No Data: $m_sqlstr");
2101
            }
2102
            $sth->finish();
2103
        }
2104
        else
2105
        {
2106
                Error ("GetData_by_pkg_id: Execute: $m_sqlstr");
2107
        }
2108
    }
2109
    else
2110
    {
2111
        Error("GetData_by_pkg_id:Prepare failure" );
2112
    }
2113
}
2114
 
2115
#-------------------------------------------------------------------------------
2116
# Function        : massageVersion
2117
#
2118
# Description     : Process a version number and return usful bits
2119
#
2120
# Inputs          : Version Number
2121
#                   Package Name - debug only
2122
#
2123
# Returns         : An array
2124
#                       suffix
2125
#                       multipart version string useful for text comparisons
2126
#
2127
sub massageVersion
2128
{
2129
    my ($version, $name) = @_;
2130
    my ($major, $minor, $patch, $build, $suffix);
2131
    my $result;
2132
    my $buildVersion;
2133
    my $isaRipple;
2134
    my $isaWIP;
2135
    $build = 0;
2136
 
2137
#print "--- $name, $version\n";
2138
    $version =~ s~^_~~;
2139
    $version =~ s~^${name}_~~;
2140
 
2141
    #
2142
    #   xxxxxxxxx.nnnn.cots
2143
    #
2144
    if ( $version =~ m~(.*)\.cots$~ ) {
2145
        my $cots_base = $1;
2146
        $suffix = '.cots';
2147
        if ( $version =~ m~(.*?)\.([0-9]{4})\.cots$~ )
2148
        {
2149
            $result = $1 . sprintf (".%4.4d", $2) . $suffix;
2150
        }
2151
        else
2152
        {
2153
            $result = $cots_base . '.0000.cots';
2154
        }
2155
    }
2156
    #
2157
    #   Convert version into full form for comparisions
2158
    #       nnn.nnn.nnn.[p]nnn.xxx
2159
    #       nnn.nnn.nnn.[p]nnn-xxx
2160
    #       nnn.nnn.nnn-[p]nnn.xxx
2161
    #       nnn.nnn.nnn-[p]nnn-xxx
2162
    #       nnn.nnn.nnn[p]nnn-xxx
2163
    #   Don't flag as ripples - they are patches
2164
    #
2165
    elsif ( $version =~ m~^(\d+)\.(\d+)\.(\d+)[-.p][p]?(\d+)([-.](.*))?$~ ) {
2166
        $major = $1;
2167
        $minor = $2;
2168
        $patch = $3;
2169
        $build = $4;
2170
        $suffix = defined $6 ? ".$6" : '';
2171
        $isaRipple = 0;
2172
    }
2173
    #
2174
    #       nn.nnn.nnnnn.xxx
2175
    #       nn.nnn.nnnnn-xxx
2176
    #       nnn.nnn.nnnx.xxx
2177
    #   Don't flag as ripples - they are patches
2178
    #
2179
    elsif ( $version =~ m~^(\d+)\.(\d+)\.(\d+)\w?([-.](.*))?$~ ) {
2180
        $major = $1;
2181
        $minor = $2;
2182
        $patch = $3;
2183
        if ( length( $patch) >= 4 )
2184
        {
2185
            $build = substr( $patch, -3 ,3);
2186
            $patch = substr( $patch,  0 ,length($patch)-3);
2187
        }
2188
        $suffix = defined $5 ? ".$5" : '';
2189
    }
2190
 
2191
    #
2192
    #       nnn.nnn.nnn
2193
    #       nnn.nnn-nnn
2194
    #       nnn.nnn_nnn
2195
    #
2196
    elsif ( $version =~ m~^(\d+)\.(\d+)[-._](\d+)$~ ) {
2197
        $major = $1;
2198
        $minor = $2;
2199
        $patch = $3;
2200
        $suffix = '';
2201
    }
2202
 
2203
    #
2204
    #       nnn.nnn.nnn.nnn
2205
    #       nnn.nnn.nnn-nnn
2206
    #       nnn.nnn.nnn_nnn
2207
    #
2208
    elsif ( $version =~ m~^(\d+)\.(\d+)\.(\d+)[-._](\d+)$~ ) {
2209
        $major = $1;
2210
        $minor = $2;
2211
        $patch = $3;
2212
        $build = $4;
2213
        $suffix = '';
2214
        $isaRipple = 0;
2215
    }
2216
 
2217
 
2218
    #
2219
    #       nnn.nnn
2220
    #
2221
    elsif ( $version =~ m~^(\d+)\.(\d+)$~ ) {
2222
        $major = $1;
2223
        $minor = $2;
2224
        $patch = 0;
2225
        $suffix = '';
2226
    }
2227
    #
2228
    #       nnn.nnn.xxx
2229
    #
2230
    elsif ( $version =~ m~^(\d+)\.(\d+)(\.\w+)$~ ) {
2231
        $major = $1;
2232
        $minor = $2;
2233
        $patch = 0;
2234
        $suffix = $3;
2235
    }
2236
 
2237
    #
2238
    #       nnn.nnn.nnnz
2239
    #
2240
    elsif ( $version =~ m~^(\d+)\.(\d+)\.(\d+)([a-z])$~ ) {
2241
        $major = $1;
2242
        $minor = $2;
2243
        $patch = $3;
2244
        $build = ord($4) - ord('a');
2245
        $suffix = '.cots';
2246
        $isaRipple = 0;
2247
    }
2248
    #
2249
    #       ???REV=???
2250
    #
2251
    elsif ( $version =~ m~REV=~ ) {
2252
        $suffix = '.cots';
2253
        $result = $version . '.0000.cots';
2254
    }
2255
 
2256
    #
2257
    #   Wip Packages
2258
    #   (nnnnnn).xxx
2259
    #   Should be essential, but want to sort very low
2260
    #
2261
    elsif ($version =~ m~\((.*)\)(\..*)?~) {
2262
        $suffix = $2 || '';
2263
        $result = "000.000.000.000$suffix";
2264
        $isaWIP = 1;
2265
    }
2266
 
2267
    #
2268
    #   !current
2269
    #
2270
    elsif ($version eq '!current' || $version eq 'current_$USER' || $version eq 'current' || $version eq 'beta' || $version eq 'latest' || $version eq 'beta.cr' || $version eq 'CREATE') {
2271
        $suffix = '';
2272
        $result = "000.000.000.000$suffix";
2273
        $isaWIP = 1;
2274
    }
2275
 
2276
    #
2277
    #   Also WIP: FINRUN.103649.BEI.WIP
2278
    elsif ($version =~ m~(\.[a-zA-Z]+)\.WIP$~) {
2279
        $suffix = lc($1);
2280
        $result = "000.000.000.000$suffix";
2281
        $isaWIP = 1;
2282
    }
2283
 
2284
    #
2285
    #   Also ERGOFSSLS190100_015
2286
    #   Don't flag as a ripple
2287
    elsif ($version =~ m~^ERG[A-Z]+(\d\d)(\d\d)(\d\d)[-_](\d+)(\.\w+)?$~) {
2288
        $major = $1;
2289
        $minor = $2;
2290
        $patch = $3;
2291
        $build = $4;
2292
        $suffix = $5 || '.sls';
2293
        $isaRipple = 0;
2294
    }
2295
 
2296
    #
2297
    #   Stuff we don't yet handle
2298
    #
2299
    else  {
2300
        Warning ("Unknown version number: $name,$version");
2301
        $version =~ m~(\.\w+)$~;
2302
        $suffix = $1 || '';
2303
        $result = $version;
2304
    }
2305
 
2306
    $isaRipple = ($build > 0) unless defined $isaRipple;
2307
    unless ( $result )
2308
    {
2309
        # Major and minor of 99.99 are normally funy versions
2310
        # Don't make important desicions on them
2311
        #
2312
        if ( $major == 99 && $minor == 99 )
2313
        {
2314
            $major = 0;
2315
            $minor = 0;
2316
            $patch = 0;
2317
        }
2318
 
2319
        $result = sprintf("%3.3d.%3.3d.%3.3d.%3.3d%s", $major,$minor,$patch,$build,$suffix || '.0000');
2320
        $buildVersion = [ $major, $minor, $patch, $build ];
2321
    }
2322
 
2323
    $suffix = lc( $suffix );
2324
    if ( exists $suffixFixup{$suffix} )
2325
    {
2326
        $suffix = $suffixFixup{$suffix} ;
2327
    }
2328
 
2329
    return ($suffix, $result, $isaRipple, $isaWIP, $buildVersion );
2330
}
2331
 
2332
#-------------------------------------------------------------------------------
2333
# Function        : examineVcsTag
2334
#
2335
# Description     : Examine a VCS Tag and determine if it looks like rubbish
2336
#
2337
# Inputs          : $entry
2338
#
2339
# Returns         : Will add Data to the $entry
2340
#
2341
sub examineVcsTag
2342
{
2343
    my ($entry) = @_;
2344
    my $bad = 0;
2345
    my $vcstag = $versions{$entry}{vcsTag};
2346
    if ( $vcstag =~ m~^SVN::~ ) {
2347
        $versions{$entry}{isSvn} = 1;
2348
 
2349
    } elsif ( $vcstag =~ m~^CC::(.*?)(::(.+))?$~ ) {
2350
        my $path = $1  || '';
2351
        my $label = $2 || '';
2352
        $bad = 1 unless ( $label );
2353
        $bad = 1 if ( $label =~ m~^N/A$~i || $label  =~ m~^na$~i );
2354
 
2355
        $bad = 1 unless ( $path );
2356
        $bad = 1 if ( $path =~ m~^N/A$~i || $path  =~ m~^na$~i );
2357
        $bad = 1 if ( $path =~ m~^/dpkg_archive~ || $path  =~ m~^dpkg_archive~ );
2358
        $bad = 1 if ( $path =~ m~^/devl/~ || $path  =~ m~^devl/~ );
2359
        $bad = 1 if ( $path =~ m~^http:~i );
2360
        $bad = 1 if ( $path =~ m~^[A-Za-z]\:~ );
2361
        $bad = 1 if ( $path =~ m~^//~ );
2362
        $bad = 1 if ( $path =~ m~^cvsserver:~ );
2363
        $bad = 1 if ( $path =~ m~,\s*module:~ );
2364
#        $bad = 1 unless ( $path =~ m~^/~ );
2365
    }
2366
    else
2367
    {
2368
        $bad = 1;
2369
    }
2370
    $versions{$entry}{badVcsTag} = 1 if ( $bad );
2371
}
2372
 
2373
#-------------------------------------------------------------------------------
2374
# Function        : logToFile
2375
#
2376
# Description     : Log some data to a named file
2377
#                   Use file locking to allow multiple process to log
2378
#
2379
# Inputs          : $filename           - Name of file to log
2380
#                   ...                 - Data to log
2381
#
2382
# Returns         : Nothing
2383
#
2384
sub logToFile
2385
{
2386
    my ($file, @data) = @_;
2387
 
2388
    open  (LOGFILE, '>>', $file);
2389
    flock (LOGFILE, LOCK_EX);
2390
    print  LOGFILE "@data\n";
2391
    flock (LOGFILE, LOCK_UN);
2392
    close (LOGFILE);
2393
}
2394
 
2395
#-------------------------------------------------------------------------------
2396
# Function        : createImages
2397
#
2398
# Description     : Create nice images of the RM version tree
2399
#
2400
# Inputs          : 
2401
#
2402
# Returns         : 
2403
#
2404
sub createImages
2405
{
2406
 
2407
    my $filebase = "${packageNames}";
2408
    open (FH, '>', "$filebase.dot" ) or die "Cannot open output";
2409
    print FH "digraph \"${packageNames}\" {\n";
2410
    #print FH "rankdir=LR;\n";
2411
    print FH "node[fontsize=16];\n";
2412
    print FH "node[target=_graphviz];\n";
2413
#    print FH "subgraph cluster_A {\n";
2414
#    print FH "node[fontsize=12];\n";
2415
 
2416
    {
2417
        my @text;
2418
        push @text, $packageNames;
2419
        push @text, 'HyperLinked to Release Manager';
2420
        push @text, 'Created:' . localtime();
2421
        push @text, '|';
2422
 
2423
        push @text, 'Total RM versions: ' . $totalVersions;
2424
        push @text, 'Essential Entries: ' . scalar @EssentialPackages;
2425
        push @text, 'Initial trees: ' . $initialTrees;
2426
 
2427
        push @text, 'Number of Entries: ' . scalar keys %versions;
2428
        push @text, 'Type : ' . $packageType;
2429
        push @text, 'All versions in Subversion' if ( $allSvn );
2430
 
2431
        push @text, '|';
2432
        push @text, 'Total Project Branches: ' . $ProjectCount;
2433
        foreach ( sort keys %knownProjects )
2434
        {
2435
            my $count = $knownProjects{$_}{count} || 0;
2436
            if ( $count )
2437
            {
2438
                my $text = 'Project Branch: ' . $_;
2439
                $text .= " (" . $count . ")" if ( $count > 1 );
2440
                push @text, $text;
2441
            }
2442
        }
2443
 
2444
        push @text, '|';
2445
        push @text, 'Bad VCS : ' . $badVcsCount;
2446
        push @text, 'Bad Singletions : ' . $badSingletonCount;
2447
        push @text, 'Deadwood entries : ' . $trimCount;
2448
        push @text, 'Walking Mode : Flat' if ($opt_flat);
2449
        push @text, 'Pruned Mode : ' . $pruneModeString;
2450
        push @text, 'Pruned entries : ' . $pruneCount;
2451
 
2452
        if ( @unknownProjects )
2453
        {
2454
            push @text, '|';
2455
            push @text, 'Unknown Projects';
2456
            push @text, 'Unknown Project: ' . $_ foreach (sort @unknownProjects );
2457
        }
2458
 
2459
        #
2460
        #   Multiple Paths
2461
        #
2462
        if ( scalar @multiplePaths > 1 )
2463
        {
2464
            push @text, '|';
2465
            push @text, 'Multiple Paths';
2466
            push @text, @multiplePaths;
2467
        }
2468
 
2469
        #
2470
        #   Bad essentials
2471
        #
2472
        if ( @badEssentials  )
2473
        {
2474
            push @text, '|';
2475
            push @text, 'Bad Essential Versions';
2476
            push @text, GetVname($_) foreach ( @badEssentials );
2477
        }
2478
 
2479
        #
2480
        #   Subversion Data
2481
        #
2482
        if ( %svnData )
2483
        {
2484
            push @text, '|';
2485
            push @text, 'Subversion';
2486
            push @text, 'Trunk used' if exists $svnData{branches}{trunk} ;
2487
            push @text, 'Labels: ' . scalar keys %{$svnData{tags}} ;
2488
            push @text, 'Branches: ' . scalar keys %{$svnData{branches}} ;
2489
        }
2490
 
2491
        push @text, '';
2492
        my $text = join '\l', @text;
2493
        $text =~ s~\|\\l~|~g;
2494
 
2495
        my @attributes;
2496
        push @attributes, "shape=record";
2497
        push @attributes, "label=\"{$text}\"";
2498
        push @attributes, "tooltip=\"$packageNames\"";
2499
        push @attributes, "URL=\"" . $GBE_RM_URL . "/view_by_version.asp?pkg_id=$first_pkg_id" . "\"";
2500
        push @attributes, "color=red";
2501
        my $attr = join( ' ', @attributes);
2502
 
2503
        my $tld_done = 'TitleBlock';
2504
        print FH "$tld_done [$attr]\n";
2505
    }
2506
 
2507
    #
2508
    #   Generate Legend
2509
    #
2510
    {
2511
        my @text;
2512
        push @text, 'Legend';
2513
        push @text, '|';
2514
        push @text, 'Node Content';
2515
        push @text, 'Package Version';
2516
#        push @text, 'Release Manager Ref (pvid)';
2517
        push @text, 'Creation Date: yyyy-mm-dd';
2518
        push @text, '(Coded information)';
2519
        push @text, '|{Code';
2520
        push @text, '|{N: Not Locked';
2521
        push @text, 'b: Bad Singleton';
2522
        push @text, 'B: Bad VCS Tag';
2523
        push @text, 'D: DeadWood';
2524
        push @text, 'E: Essential Version';
2525
        push @text, 'G: Glued into Version Tree';
2526
        push @text, 'S: Splitpoint';
2527
        push @text, 't: Glued into Project Tree';
2528
        push @text, 'T: Tip version';
2529
        push @text, 'V: In SVN';
2530
        push @text, '+: In Subversion';
2531
        push @text, '}}';
2532
 
2533
        push @text, '|';
2534
        push @text, 'Outline';
2535
        push @text, 'Red: Dead or Bad VCS Tag';
2536
        push @text, 'Orange: Project Branch Root';
2537
        push @text, 'Green: Ripple Build Version';
2538
        push @text, 'Blue: Essential Version';
2539
        push @text, 'Darkmagenta: Entry Glued into tree';
2540
        push @text, 'Magenta: Entry added to project tree';
2541
 
2542
 
2543
        push @text, '|';
2544
        push @text, 'Fill';
2545
        push @text, 'PowderBlue: Essential Version';
2546
        push @text, 'Red: Bad Essential Version';
2547
        push @text, 'Light Green: Migrated to SVN';
2548
#        push @text, 'Red: Entry Glued into tree';
2549
#        push @text, 'Green: Entry added to project tree';
2550
 
2551
        push @text, '|';
2552
        push @text, 'Shape';
2553
        push @text, 'Oval: Normal Package Version';
2554
        push @text, 'Invhouse: Project Branch Root';
2555
        push @text, 'Octagon: Branch Point';
2556
        push @text, 'Box: Bad Single version with no history';
2557
        push @text, 'Doublecircle: Tip of a Project Branch';
2558
 
2559
        push @text, '';
2560
        my $text = join '\l', @text;
2561
        $text =~ s~\|\\l~|~g;
2562
        $text =~ s~\}\\l~}~g;
2563
 
2564
        my @attributes;
2565
        push @attributes, "shape=record";
2566
        push @attributes, "label=\"{$text}\"";
2567
        push @attributes, "color=red";
2568
        my $attr = join( ' ', @attributes);
2569
 
2570
        my $tld_done = 'LegendBlock';
2571
        print FH "$tld_done [$attr]\n";
2572
    }
2573
 
2574
#    print FH "\n}\n";
2575
    print FH "TitleBlock -> LegendBlock [style=invis]\n";
2576
 
2577
    sub genLabelText
2578
    {
2579
        my ($entry) = @_;
2580
        my @label;
2581
        push @label, $versions{$entry}{name} if ( $multiPackages );
2582
        push @label, $versions{$entry}{vname};
2583
#        push @label, $entry;       # Add PVID
2584
        push @label, substr( $versions{$entry}{created}, 0, 10); #  2008-02-19
2585
#        push @label, 'V=' . $versions{$entry}{maxVersion};
2586
#        push @label, 'B=' . $versions{$entry}{svnBranchTip} if ( exists $versions{$entry}{svnBranchTip} );
2587
 
2588
 
2589
        my $stateText = '';
2590
        $stateText .= 'N' if ($versions{$entry}{locked} eq 'N');
2591
        $stateText .= 'b' if (exists $versions{$entry}{badSingleton});
2592
        $stateText .= 'B' if (exists $versions{$entry}{badVcsTag});
2593
        $stateText .= 'G' if (exists $versions{$entry}{GluedIn});
2594
        $stateText .= 't' if (exists $versions{$entry}{MakeTree});
2595
        $stateText .= 'E' if (exists $versions{$entry}{Essential});
2596
        $stateText .= 'D' if (exists $versions{$entry}{DeadWood});
2597
        $stateText .= 'S' if (exists $versions{$entry}{EssentialSplitPoint} && $versions{$entry}{EssentialSplitPoint} > 1 );
2598
        $stateText .= 'T' if (exists $versions{$entry}{Tip} );
2599
        $stateText .= 'V' if (exists $versions{$entry}{isSvn} );
2600
        $stateText .= '+' if (exists $versions{$entry}{svnVersion} );
2601
#        $stateText .= 's' if (exists $versions{$entry}{branchPoint} );
2602
#        $stateText .= ' T='. $versions{$entry}{threadId} if (exists $versions{$entry}{threadId});
2603
#        $stateText .= ' EssentalPath' if (exists $versions{$entry}{EssentialPath});
2604
#        $stateText .= ' Count='. $versions{$entry}{EssentialSplitPoint} if (exists $versions{$entry}{EssentialSplitPoint});
2605
#        $stateText .= ' M='. $versions{$entry}{maxVersion} if (exists $versions{$entry}{maxVersion});
2606
 
2607
        push @label, "(${stateText})" if ( $stateText );
2608
 
2609
        return join ('\n', @label );
2610
    }
2611
 
2612
    sub genAttributes
2613
    {
2614
        my ($entry) = @_;
2615
        my @attributes;
2616
        push @attributes, 'label="' . genLabelText($entry) . '"';
2617
        push @attributes, 'URL="' . dotUrl($entry) . '"';
2618
        push @attributes, 'tooltip="' . "Goto: $versions{$entry}{vname}, PVID=$entry" ,'"';
2619
        my $shape;
2620
            $shape = 'box' if ($versions{$entry}{badSingleton});
2621
            $shape = 'octagon'  if ($versions{$entry}{branchPoint});
2622
            $shape = 'invhouse' if ($versions{$entry}{newSuffix});
2623
            $shape = 'doublecircle' if ($versions{$entry}{Tip});
2624
 
2625
 
2626
        push @attributes, 'shape=' . $shape if ( $shape );
2627
 
2628
        my $color;
2629
        my $fill;
2630
           $color = 'color=green style=bold' if ( $versions{$entry}{isaRipple} );
2631
           $color = 'color=orange style=bold' if ( $versions{$entry}{newSuffix} );
2632
           $color = 'color=red style=bold' if ( $versions{$entry}{DeadWood} || $versions{$entry}{badVcsTag} );
2633
           $color = 'color=blue style=bold' if ( $versions{$entry}{Essential} );
2634
           $color = 'color=darkmagenta style=bold' if ( $versions{$entry}{GluedIn} );
2635
           $color = 'color=magenta style=bold' if ( $versions{$entry}{MakeTree} );
2636
 
2637
           $fill = 'style=filled fillcolor=powderblue' if ( $versions{$entry}{Essential} );
2638
           $fill = 'style=filled fillcolor=red' if ( $versions{$entry}{Essential} && $versions{$entry}{badVcsTag} );
2639
           $fill = 'style=filled fillcolor="#99FF99"' if ( exists $versions{$entry}{svnVersion} );
2640
 
2641
 
2642
        push @attributes, $color if ( $color );
2643
        push @attributes, $fill if ( $fill );
2644
 
2645
        return '[' . join( ' ', @attributes) . ']';
2646
    }
2647
 
2648
    sub genArrowAttributes
2649
    {
2650
        my ($not_first, $entry) = @_;
2651
        my @attributes;
2652
 
2653
        push @attributes, 'arrowhead=empty' if ( $not_first );
2654
        push ( @attributes, 'label="' . $versions{$entry}{svnBranchTip} .'"' ) if ( exists $versions{$entry}{svnBranchTip} );
2655
 
2656
        return ('[' . join( ' ', @attributes) . ']') if ( @attributes ) ;
2657
        return '';
2658
    }
2659
 
2660
    #
2661
    #   Flat
2662
    #
2663
    if ( $opt_flat )
2664
    {
2665
        my $last = 0;
2666
        foreach my $entry (@flatOrder )
2667
        {
2668
            if ( $last )
2669
            {
2670
                my $me = dotTag($last);
2671
 
2672
                print FH pentry($me)  ,' -> ', pentry(dotTag($entry)), genArrowAttributes(0, $entry) ,";\n";
2673
                print FH pentry($me)  ,genAttributes($last) . ";\n";
2674
            }
2675
            $last = $entry;
2676
        }
2677
        print FH pentry(dotTag($last))  ,genAttributes($last) . ";\n";
2678
 
2679
    }
2680
    else
2681
    {
2682
        foreach my $entry ( sort {$a <=> $b} keys(%versions) )
2683
        {
2684
            my $me = dotTag($entry);
2685
            my @versions = @{ $versions{$entry}{next}};
2686
            my $ii = 0;
2687
            foreach ( @versions )
2688
            {
2689
                print FH pentry($me)  ," -> ",pentry(dotTag($_)), genArrowAttributes($ii++, $_), ";\n";
2690
            }
2691
 
2692
            print FH pentry($me)  ,genAttributes($entry) . ";\n";
2693
        }
2694
    }
2695
 
2696
    print FH "\n};\n";
2697
    close FH;
2698
 
2699
    #
2700
    #   Convert DOT to a SVG
2701
    #
2702
    unless ( $UNIX )
2703
    {
2704
    print "Generating graphical images\n";
2705
#    system( "dot $filebase.dot -Tjpg -o$filebase.jpg" );  # -v
2706
    system( "dot $filebase.dot -Tsvg -o$filebase.svg" );  # -v
2707
#    unlink("$filebase.dot");
2708
 
2709
    #
2710
    #   Display a list of terminal packages
2711
    #   These are packages that are not used by any other package
2712
    #
2713
    print "\n";
2714
#    print "Generated: $filebase.dot\n";
2715
#    print "Generated: $filebase.jpg\n";
2716
    print "Generated: $filebase.svg\n";
2717
    }
2718
    else
2719
    {
2720
        print "Generated: $filebase.dot\n";
2721
    }
2722
}
2723
 
2724
sub dotTag
2725
{
2726
    my ($entry) = @_;
2727
 
2728
    my $label = '';
2729
    $label .= $versions{$entry}{name} if $multiPackages;
2730
    $label .= $versions{$entry}{vname};
2731
    $label =~ s~[-() ]~_~g;
2732
    return $label;
2733
}
2734
 
2735
sub dotUrl
2736
{
2737
    my ($entry) = @_;
2738
 
2739
    my $pv_base = $GBE_RM_URL . "/fixed_issues.asp?pv_id=$entry";
2740
}
2741
 
2742
#-------------------------------------------------------------------------------
2743
# Function        : pentry
2744
#
2745
# Description     : Generate an entry list as text
2746
#                   Replace "." with "_" since DOT doesn't like .'s
2747
#                   Seperate the arguments
2748
#
2749
# Inputs          : @_          - An array of entries to process
2750
#
2751
# Returns         : A string
2752
#
2753
sub pentry
2754
{
2755
    my ($data) = @_;
2756
    $data =~ s~\.~_~g;
2757
    $result = '"' . $data . '"' ;
2758
    return $result;
2759
}
2760
 
2761
#-------------------------------------------------------------------------------
2762
# Function        : getVobMapping
2763
#
2764
# Description     : Read in Package to Repository Mapping
2765
#
2766
# Inputs          : 
2767
#
2768
# Returns         : Populates %VobMapping
2769
#                             Mapping of PackageName to RepoName[/Subdir]
2770
#
2771
our %ScmRepoMap;
2772
sub getVobMapping
2773
{
2774
    Message ("Read in Vob Mapping");
2775
 
2776
    my $fname = 'cc2svn.repo.dat';
2777
    Error "Cannot locate $fname" unless ( -f $fname );
2778
    require $fname;
2779
 
2780
    Error "Data in $fname is not valid\n"
2781
        unless ( keys(%ScmRepoMap) >= 0 );
2782
 
2783
    $opt_vobMap = $ScmRepoMap{$packageNames}{repo}
2784
        if (exists $ScmRepoMap{$packageNames});
2785
 
2786
    #
2787
    #   Free the memory
2788
    #
2789
    %ScmRepoMap = ();
2790
 
2791
    #
2792
    #   Calculate Target Repo
2793
    #
2794
    Warning ("No VOB Mapping found")
2795
        unless ($opt_vobMap);
2796
    Error("No repository specified. ie -repo=DevTools or -repo=COTS")
2797
        unless ( $opt_repo || $opt_vobMap );
2798
 
2799
    my $r1 = ($opt_repo || '') . '/' . ($opt_vobMap || '');
2800
    $r1 =~ s~^/~~;
2801
    $r1 =~ s~/$~~;
2802
    $svnRepo = $opt_repo_base . $r1;
2803
 
2804
    Verbose( "Repo URL: $svnRepo");
2805
}
2806
 
2807
 
2808
#-------------------------------------------------------------------------------
2809
# Function        : getEssenialPackageVersions
2810
#
2811
# Description     : Determine the 'Essental' Package Versions
2812
#                   Read the data in from an external file
2813
#
2814
# Inputs          : 
2815
#
2816
# Returns         : Populates @EssentialPackages
2817
#
2818
 
2819
our %ScmReleases;
2820
our %ScmPackages;
2821
our %ScmSuffixes;
2822
sub getEssenialPackageVersions
2823
{
2824
    Message ("Read in Essential Package Versions");
2825
 
2826
    my $fname = 'cc2svn.raw.txt';
2827
    Error "Cannot locate $fname" unless ( -f $fname );
2828
    require $fname;
2829
 
2830
    Error "Data in $fname is not valid\n"
2831
        unless ( keys(%ScmReleases) >= 0 );
2832
 
2833
#    DebugDumpData("ScmReleases", \%ScmReleases );
2834
#    DebugDumpData("ScmPackages", \%ScmPackages );
2835
#    DebugDumpData("ScmSuffixes", \%ScmSuffixes );
2836
 
2837
    #
2838
    #   Create a list of essential packages
2839
    #   Retain packages-versions used in this program
2840
    #
2841
    foreach ( keys %ScmPackages )
2842
    {
2843
        next unless ( exists  $pkg_ids{ $ScmPackages{$_}{pkgid} } );
2844
        push @EssentialPackages, $_;
2845
        Error ("Essential Package Version not in extracted Release Manager Data: $_")
2846
            unless ( exists $versions{$_} );
2847
        $versions{$_}{Essential} = 1;
2848
        #print "ESSENTIAL: $versions{$_}{name} $versions{$_}{vname}\n";
2849
    }
2850
 
2851
    #
2852
    #   Free memory
2853
    #
2854
    %ScmReleases = ();
2855
    %ScmPackages = ();
2856
    %ScmSuffixes = ();
2857
 
2858
#    DebugDumpData("Essential", \@EssentialPackages );
2859
    Message ("Essential Versions: " . scalar @EssentialPackages );
2860
}
2861
 
2862
#-------------------------------------------------------------------------------
2863
# Function        : ReportPathVariance
2864
#
2865
# Description     : Report variance in paths used by the versions
2866
#
2867
# Inputs          : 
2868
#
2869
# Returns         : 
2870
#
2871
my %VobPaths;
2872
sub ReportPathVariance
2873
{
2874
    Message ("Detect Multiple Paths");
2875
    foreach my $entry ( keys(%versions) )
2876
    {
2877
        my $e = $versions{$entry};
2878
        next if ( isSet ($e, 'DeadWood' ) );
2879
        next if ( isSet ($e, 'badVcsTag') );
2880
        next if ( isSet ($e, 'isSvn') );
2881
        my $tag = $e->{vcsTag};
2882
        next unless ( $tag );
2883
 
2884
        $tag =~ m~^(.+?)::(.*?)(::(.+))?$~;
2885
        my $vcsType = $1;
2886
        my $cc_label = $4;
2887
        my $cc_path = $2;
2888
        $cc_path = '/' . $cc_path;
2889
        $cc_path =~ tr~\\/~/~s;
2890
 
2891
        $VobPaths{$cc_path}++;
2892
    }
2893
 
2894
    @multiplePaths = sort keys %VobPaths;
2895
    if ( scalar @multiplePaths > 1 )
2896
    {
2897
        Warning ("Multiple Paths:" . $_ ) foreach (@multiplePaths);
2898
    }
2899
}
2900
 
2901
sub isSet
2902
{
2903
    my ($base, $element) = @_;
2904
    return 0 unless ( exists $base->{$element} );
2905
    return $base->{$element};
2906
}
2907
 
2908
 
2909
#-------------------------------------------------------------------------------
2910
# Function        : recurseList
2911
#
2912
# Description     : Return a list of all element below a given head element
2913
#
2914
# Inputs          : $head               - Head element
2915
#
2916
# Returns         : A list, not in any particular order
2917
#
2918
 
2919
our @recurseList;
2920
sub recurseList
2921
{
2922
    @recurseList = ();
2923
    recurseListBody (@_);
2924
    return @recurseList;
2925
}
2926
sub recurseListBody
2927
{
2928
    foreach my $entry ( @_ )
2929
    {
2930
        push @recurseList, $entry;
2931
no warnings "recursion";
2932
        recurseListBody (@{$versions{$entry}{next}});
2933
    }
2934
}
2935
 
2936
#-------------------------------------------------------------------------------
2937
# Function        : getSvnData
2938
#
2939
# Description     : Read the SVN tree and see what we have
2940
#
2941
# Inputs          : 
2942
#
2943
# Returns         : 
2944
#
2945
my @svnDataItems;
2946
sub getSvnData
2947
{
2948
    Message ("Examine Subversion Tree");
2949
 
2950
    #
2951
    #   Re-init data
2952
    #
2953
    @svnDataItems = ();
2954
    %svnData = ();
2955
 
2956
    #
2957
    #   Create an SVN session
2958
    #
2959
    return unless ( $svnRepo );
2960
    my $svn = NewSessionByUrl ( "$svnRepo/$packageNames" );
2961
    return unless ( $svn );
2962
 
2963
    #
2964
    #   extract data
2965
    #
2966
#    DebugDumpData("SVN", $svn );
2967
    $svn->SvnCmd ( 'log', '-v', '--xml', '--stop-on-copy', $svn->Full()
2968
                    , { 'credentials' => 1,
2969
                        'process' => \&ProcessSvnLog,
2970
                         }
2971
                        );
2972
 
2973
    #
2974
    #   Process data
2975
    foreach my $entry ( @svnDataItems )
2976
    {
2977
        my $name;
2978
        my $isaBranch;
2979
        my $target = $entry->{target};
2980
        if ( $target =~ m~/tags/(.*)~ ) {
2981
            $name = $1;
2982
            $svnData{tags}{$name} = 1;
2983
        } elsif ( $target =~ m~/branches/(.*)~ )  {
2984
            $name = $1;
2985
    #        $branches{$1} = 1;
2986
        } else {
2987
            $svnData{nonTag}{$target} = 1;
2988
        }
2989
 
2990
        my $fromBranch;
2991
        if ( $entry->{fromPath} =~ m~/trunk$~  ) {
2992
            $fromBranch = 'trunk';
2993
        } elsif ( $entry->{fromPath} =~ m~/branches/(.*)~ ) {
2994
            $fromBranch = $1;
2995
        }
2996
 
2997
        if ( defined($fromBranch) && ! exists $svnData{branches}{$fromBranch} )
2998
        {
2999
            unless ( $name eq $fromBranch )
3000
            {
3001
                $svnData{branches}{$fromBranch} = $name;
3002
                $svnData{tips}{$name} = $fromBranch;
3003
            }
3004
        }
3005
    }
3006
#    DebugDumpData("SvnData", \%svnData);
3007
 
3008
    foreach my $entry ( keys(%versions) )
3009
    {
3010
        my $import_label = saneLabel($entry);
3011
        delete $versions{$entry}{svnVersion};
3012
        delete $versions{$entry}{svnBranchTip};
3013
 
3014
        if ( exists $svnData{tags}{$import_label} )
3015
        {
3016
            $versions{$entry}{svnVersion} = 1;
3017
        }
3018
 
3019
        if ( exists $svnData{tips}{$import_label} )
3020
        {
3021
            $versions{$entry}{svnBranchTip} = $svnData{tips}{$import_label};
3022
        }
3023
    }
3024
 
3025
    Message ( 'Trunk used: ' . (exists $svnData{branches}{trunk} ? 'Yes' : 'No') );
3026
    Message ( 'Labels    : ' . scalar keys %{$svnData{tags}} );
3027
    Message ( 'Branches  : ' . scalar keys %{$svnData{branches}} );
3028
}
3029
 
3030
#-------------------------------------------------------------------------------
3031
# Function        : ProcessSvnLog
3032
#
3033
# Description     :
3034
#                   Parse
3035
#                       <logentry
3036
#                          revision="24272">
3037
#                       <author>bivey</author>
3038
#                       <date>2005-07-25T15:45:35.000000Z</date>
3039
#                       <paths>
3040
#                       <path
3041
#                          prop-mods="false"
3042
#                          text-mods="false"
3043
#                          kind="dir"
3044
#                          copyfrom-path="/enqdef/branches/Stockholm"
3045
#                          copyfrom-rev="24271"
3046
#                          action="A">/enqdef/tags/enqdef_24.0.1.sls</path>
3047
#                       </paths>
3048
#                       <msg>COTS/enqdef: Tagged by Jats Svn Import</msg>
3049
#                       </logentry>
3050
#
3051
# Inputs          : 
3052
#
3053
# Returns         : 
3054
#
3055
my $entryData;
3056
sub  ProcessSvnLog
3057
{
3058
    my ($self, $line ) = @_;
3059
#print "----- $line\n";
3060
    if ( $line =~ m~^<logentry~ ) {
3061
        $entryData = ();
3062
 
3063
    } elsif ( $line =~ m~^\s+revision="(\d+)"~ ) {
3064
        $entryData->{Rev} = $1;
3065
 
3066
    } elsif ( $line =~ m~^\s+copyfrom-path="(.*)"~ ) {
3067
        $entryData->{fromPath} = $1;
3068
 
3069
    } elsif ( $line =~ m~^\s+copyfrom-rev="(\d+)"~ ) {
3070
        $entryData->{fromRev} = $1;
3071
 
3072
    } elsif ( $line =~ m~\s+action=.*?>(.*)</path~ ) {
3073
        $entryData->{target} = $1;
3074
 
3075
    } elsif ( $line =~ m~</logentry~ ) {
3076
        if ( exists $entryData->{fromPath} )
3077
        {
3078
#            DebugDumpData("Data", $entryData);
3079
            push @svnDataItems, $entryData;
3080
        }
3081
    }
3082
 
3083
    #
3084
    #   Return 0 to keep on going
3085
    return 0;
3086
}
3087
 
3088
 
3089
 
3090
#-------------------------------------------------------------------------------
3091
# Function        : saveData
3092
#
3093
# Description     : Save essential data
3094
#
3095
# Inputs          : 
3096
#
3097
# Returns         : 
3098
#
3099
sub saveData
3100
{
3101
    my $file = $cwd . "/${packageNames}.data";
3102
 
3103
    Message ("Create: $file");
3104
    my $fh = ConfigurationFile::New( $file );
3105
 
3106
    $fh->DumpData(
3107
        "\n# ScmVersions.\n#\n",
3108
        "ScmVersions", \%versions );
3109
 
3110
    #
3111
    #   Close out the file
3112
    #
3113
    $fh->Close();
3114
}
3115
 
3116
 
3117
#-------------------------------------------------------------------------------
3118
#   Documentation
3119
#
3120
 
3121
=pod
3122
 
3123
=for htmltoc    SYSUTIL::cc2svn::
3124
 
3125
=head1 NAME
3126
 
3127
cc2svn_gendata - CC2SVN tool to import an entire package into SVN
3128
 
3129
=head1 SYNOPSIS
3130
 
3131
  jats cc2svn_importpackage [options] package_name
3132
 
3133
 Options:
3134
    -help              - brief help message
3135
    -help -help        - Detailed help message
3136
    -man               - Full documentation
3137
    -repository=name   - Specify target repository
3138
    -[no]flat          - Do not create project tree. Def: -noflat
3139
    -prunemode=mode    - Mode: none, ripple, retain, severe, Def=ripple
3140
    -retain=N          - Specify retain count for pruning. Def=2
3141
    -[no]test          - Do not create packages. Def:-notest
3142
    -[no]reuse         - Keep and reuse ClearCase views
3143
    -age=nnDays        - Only keep recent package
3144
    -dump[=n]          - Dump raw data. N=0,1,2
3145
    -images[=n]        - Create SVG of version tree. N=0,1,2
3146
    -name=aaa          - Alternate output package name. Test Only
3147
    -[no]log           - Write output to log file. Def: -nolog
3148
    -[no]postimage     - Create image after transger: Def: -post
3149
    -workdir=path      - Use for temp storage (def:/work)
3150
 
3151
=head1 OPTIONS
3152
 
3153
=over 8
3154
 
3155
=item B<-help>
3156
 
3157
Print a brief help message and exits.
3158
 
3159
=item B<-help -help>
3160
 
3161
Print a detailed help message with an explanation for each option.
3162
 
3163
=item B<-man>
3164
 
3165
Prints the manual page and exits.
3166
 
3167
=item B<-prunemode=mode>
3168
 
3169
This option control the manner in which excess versions will be pruned. Valid
3170
modes are:
3171
 
3172
=over 8
3173
 
3174
=item   none
3175
 
3176
No pruning will be performed
3177
 
3178
=item   ripple
3179
 
3180
Non-Essential packages that are ripple builds will be removed.
3181
 
3182
=item   retain
3183
 
3184
Versions that preceed an Essential version will be retained.
3185
 
3186
=item   severe
3187
 
3188
Only Essential Versions, and Branching points will be retained.
3189
 
3190
=back
3191
 
3192
=back
3193
 
3194
=head1 DESCRIPTION
3195
 
3196
This program is a tool used in the conversion of ClearCase VOBS to subversion.
3197
It will take a complete package and all relevent versions from ClearCase and
3198
insert them into subversion in a sessible manner. It will attempt to retain
3199
file change order and history.
3200
 
3201
It will:
3202
 
3203
=over 8
3204
 
3205
=item *
3206
 
3207
Read in the Essential Package Version list.
3208
 
3209
=item *
3210
 
3211
Extract, from Release Manager, all known versions of the specified package.
3212
 
3213
=item *
3214
 
3215
It will attempt to determine the type of package: COTS, TOOL, CORE, PROJECT
3216
and alter the processing accordingly.
3217
 
3218
=item *
3219
 
3220
It will create a version dependency tree and determine 'new' project branch
3221
points. It will remove (prune) versions that are excess to requirements.
3222
 
3223
=item *
3224
 
3225
It will extract source from ClearCase and insert it into SVN, creating
3226
branches and tags as it goes.
3227
 
3228
=back
3229
 
3230
The program can also be used to create a SVG image of the version dependency
3231
tree. This does not work on Linux; only Windows with 'dot' installed.
3232
 
3233
=cut
3234