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
    #
1451
    $cc_path =~ s~/MASS_Dev_Bus/Cbp/~/MASS_Dev_Bus/CBP/~i;
1452
    $cc_path =~ s~/MREF_Package/ergpostmongui$~/MREF_Package/ergpostmongui~i;
1453
 
1454
#print "--- Path: $cc_path, Label: $cc_label\n";
1455
 
1456
    #
1457
    #   Create CC view
1458
    #   Import into Subversion View
1459
    #
1460
    $data->{ViewRoot} = $opt_name ? $opt_name : "$cc_label";
1461
    $data->{ViewPath} =  $data->{ViewRoot} . '/' . $cc_path;
1462
    $data->{ViewPath} =~  tr~/~/~s;
1463
 
1464
    if ( $opt_reuse && -d $data->{ViewPath}  )
1465
    {
1466
        Message ("Reusing view: $cc_label");
1467
    }
1468
    else
1469
    {
1470
        my @args;
1471
        push (@args, '-view', $opt_name ) if ( defined $opt_name );
1472
        $rv = JatsToolPrint ( 'jats_ccrelease', '-extractfiles', '-root=.' , '-noprefix',
1473
                    "-label=$cc_label" ,
1474
                    "-path=$cc_path",
1475
                    @args
1476
                    );
1477
 
1478
        unless ( -d $data->{ViewPath}  )
1479
        {
1480
            $data->{errStr} = 'Failed to extract files from CC';
1481
            return 2;
1482
        }
1483
    }
1484
 
1485
    #
1486
    #   Have a CC view
1487
    #   Now we can create the SVN package and branching point before we
1488
    #   import the CC data into SVN
1489
    #
1490
    my @args;
1491
 
1492
    #
1493
    #   Calculate args for functions
1494
    #
1495
    my $author = $versions{$entry}{created_id};
1496
    if ( $author )
1497
    {
1498
        push @args, '-author', $author;
1499
    }
1500
    my $created = $versions{$entry}{created};
1501
    if ( $created )
1502
    {
1503
        $created =~ s~ ~T~;
1504
        $created .= '00000Z';
1505
        push @args, '-date', $created;
1506
    }
1507
 
1508
    my $log = $versions{$entry}{comment};
1509
    if ( $log )
1510
    {
1511
        push @args, '-log', $log;
1512
    }
1513
 
1514
    #
1515
    #   Create package skeleton if needed
1516
    #
1517
    $rv = createPackage( $author, $created);
1518
    if ( $rv )
1519
    {
1520
        $data->{errStr} = 'Failed to create Package';
1521
        return 10;
1522
    }
1523
 
1524
    #
1525
    #   Calculate the label for the target package
1526
    #   Use format <packageName>_<PackageVersion>
1527
    #   Need to handle WIPs too.
1528
    #
1529
    my $import_label = saneLabel($entry);
1530
 
1531
    #
1532
    #   May need to create the branchpoint
1533
    #   The process is delayed until its needed so avoid creating unneeded
1534
    #   branch points
1535
    #
1536
    if ( $createBranch )
1537
    {
1538
        $rv = createBranchPoint ($entry, $author, $created);
1539
        $createBranch = 0;
1540
        $createSuffix = 0;
1541
        if ( $rv )
1542
        {
1543
            $data->{errStr} = 'Failed to create Branch Point';
1544
            return 11;
1545
        }
1546
    }
1547
    push @args, "-branch=$currentBranchName" if ( defined $currentBranchName );
1548
 
1549
    my $datafile = "importdata.$import_label.properties";
1550
    $rv = JatsToolPrint ( 'jats_svn', 'import', '-reuse' ,
1551
                    "-package=$svnRepo/$packageNames",
1552
                    "-dir=$data->{ViewPath}",
1553
                    "-label=$import_label",
1554
                    "-datafile=$datafile",
1555
                    @args,
1556
                     );
1557
 
1558
    if ( $rv )
1559
    {
1560
        $data->{errStr} = 'Failed to import to SVN';
1561
        return 12;
1562
    }
1563
 
1564
    $versions{$entry}{TagCreated} = 1;
1565
    $firstVersionCreated = $entry unless ( $firstVersionCreated );
1566
 
1567
    #
1568
    #   Read in the Rm Reference
1569
    #   Retain entries in a global file
1570
    #
1571
    if ( -f $datafile  )
1572
    {
1573
        my $rmData = JatsProperties::New($datafile);
1574
        $data->{rmRef} = 'SVN::' . $rmData->getProperty('subversion.tag');
1575
    }
1576
 
1577
    unless ( $data->{rmRef}  )
1578
    {
1579
        $data->{errStr} = 'Failed to determin Rm Reference';
1580
        return 13;
1581
    }
1582
 
1583
    Message ("RM Ref: $data->{rmRef}");
1584
    unlink $datafile;
1585
 
1586
    #
1587
    #   All is good
1588
    #
1589
    $data->{errStr} = '';
1590
    return 0;
1591
}
1592
 
1593
 
1594
#-------------------------------------------------------------------------------
1595
# Function        : newProject
1596
#
1597
# Description     : Start a new project within a package
1598
#
1599
# Inputs          : 
1600
#
1601
# Returns         : 
1602
#
1603
sub newProject
1604
{
1605
#    Message ("---- New Project");
1606
    $createSuffix = 0;
1607
 
1608
    #
1609
    #   New project
1610
    #   Kill the running import directory
1611
    #
1612
    RmDirTree ('SvnImportDir');
1613
}
1614
 
1615
#-------------------------------------------------------------------------------
1616
# Function        : newPackage
1617
#
1618
# Description     : Start processing a new package
1619
#
1620
# Inputs          : 
1621
#
1622
# Returns         : 
1623
#
1624
my $createPackageDone;
1625
sub newPackage
1626
{
1627
#    Message( "---- New Package");
1628
 
1629
    #
1630
    #   Create a package specific log file
1631
    #
1632
    $logSummary = $packageNames . ".summary.log";
1633
    unlink $logSummary;
1634
    Message( "PackageName: $packageNames");
1635
    $createPackageDone = 1;
1636
    $createBranch = 0;
1637
    $createSuffix = 0;
1638
 
1639
    #
1640
    #   First entry being created
1641
    #   Prime the work area
1642
    #
1643
    RmDirTree ('SvnImportDir');
1644
}
1645
 
1646
#-------------------------------------------------------------------------------
1647
# Function        : createPackage
1648
#
1649
# Description     : Create a new Package in SVN
1650
#                   Called before any serious SVN operation to ensure that the
1651
#                   package has been created. Don't create a package until
1652
#                   we expect to put something into it.
1653
#
1654
#                   Will only create a package once
1655
 
1656
#
1657
# Inputs          : $author         - Who done it
1658
#                   $date           - When
1659
#
1660
# Returns         : 
1661
#
1662
sub createPackage
1663
{
1664
    my ($author, $date) = @_;
1665
    my @opts;
1666
    push (@opts, '-date', $date) if ( $date );
1667
    push (@opts, '-author', $author) if ( $author );
1668
    #
1669
    #   Only do once
1670
    #
1671
    return unless ( $createPackageDone );
1672
    $createPackageDone = 0;
1673
 
1674
    Message ("Creating new SVN package: $packageNames");
1675
    JatsToolPrint ( 'jats_svn', 'delete-package', '-noerror',  "$svnRepo/$packageNames" );
1676
    JatsToolPrint ( 'jats_svn', 'create', "$svnRepo/$packageNames", @opts );
1677
}
1678
 
1679
 
1680
#-------------------------------------------------------------------------------
1681
# Function        : createBranchPoint
1682
#
1683
# Description     : Create a branch point for the current work
1684
#                   Perform the calculation to determine the details of
1685
#                   the branch point. The work will only be done when its
1686
#                   needed. This will avoid the creation of branchpoints
1687
#                   that are not used.
1688
#
1689
# Inputs          : $entry                  Entry being processed
1690
#                   $author         - Who done it
1691
#                   $date           - When
1692
#
1693
# Returns         : 
1694
#
1695
sub createBranchPoint
1696
{
1697
    my ($entry, $author, $date) = @_;
1698
    my $forceNewProject;
1699
 
1700
#    Message ("---- Create Branch Point");
1701
 
1702
    #
1703
    #   Find previous good tag
1704
    #   We are walking a tree so something should have been created, but
1705
    #   the one we want may have had an error
1706
    #
1707
    #   Walk backwards looking for one that has been created
1708
    #
1709
    my $last = $versions{$entry}{last};
1710
    while ( $last )
1711
    {
1712
        unless ( $versions{$last}{TagCreated} )
1713
        {
1714
            $last = $versions{$last}{last};
1715
        }
1716
        else
1717
        {
1718
            last;
1719
        }
1720
    }
1721
 
1722
    #
1723
    #   If we have walked back to the base of the tree
1724
    #   If we transferred any software at all, then use the first
1725
    #   version as the base for this disconnected version
1726
    #
1727
    #   Otherwise we create a new, and empty, view
1728
    #
1729
    unless ( $last )
1730
    {
1731
        if ( $firstVersionCreated )
1732
        {
1733
            Warning ("Cannot find previous version to branch. Use first version");
1734
            $last = $firstVersionCreated;
1735
        }
1736
        else
1737
        {
1738
            Warning ("Forcing First instance of a Project");
1739
            $forceNewProject = 1;
1740
        }
1741
    }
1742
 
1743
    #
1744
    #   Determine source name
1745
    #   This MUST have been created before we can branch
1746
    #
1747
    my $src_label;
1748
    $src_label = saneLabel($last) if $last;
1749
 
1750
    #
1751
    #   Create target name
1752
    #
1753
    my $tgt_label;
1754
    if ( $forceNewProject || $versions{$entry}{newSuffix} || $createSuffix || !defined $src_label )
1755
    {
1756
        #
1757
        #   Create target name based on project
1758
        #
1759
        return if ( $singleProject );
1760
 
1761
        my $suffix = $versions{$entry}{suffix};
1762
        if ( $suffix )
1763
        {
1764
            Error ("Unknown Project: $suffix") unless ( defined $Projects{$suffix} );
1765
 
1766
            #
1767
            #   If this project can be considered to be a truck, then 'claim' the
1768
            #   truck for the first created element.
1769
            #
1770
            if ( $Projects{$suffix}{Trunk} )
1771
            {
1772
                # This project can use the trunk, if it has not been allocated.
1773
                $ProjectTrunk = $suffix unless ( defined $ProjectTrunk );
1774
 
1775
                #
1776
                #   If this package has multiple instances of the potential
1777
                #   trunk, then don't place either of them on the trunk as it
1778
                #   may cause confusion
1779
                #
1780
                if ($knownProjects{$suffix}{count} < 2 )
1781
                {
1782
                    if ( $suffix eq $ProjectTrunk )
1783
                    {
1784
                        return unless $currentBranchName;
1785
                    }
1786
                }
1787
            }
1788
 
1789
            $tgt_label = $Projects{$suffix}{Name};
1790
            $tgt_label = $versions{$entry}{name} . '_' . $tgt_label if ($multiPackages);
1791
            if ( !exists $ProjectsBaseCreated{$tgt_label}  )
1792
            {
1793
                $ProjectsBaseCreated{$tgt_label} = 1;
1794
            }
1795
            else
1796
            {
1797
                #   Project Base Already taken
1798
                #   Have disjoint starting points
1799
                $tgt_label .= '.' . $ProjectsBaseCreated{$tgt_label} ++;
1800
            }
1801
        }
1802
        else
1803
        {
1804
            #
1805
            #   No suffix in use
1806
            #
1807
            #   Currently not handled
1808
            #   May have to force the use of the trunk
1809
            #
1810
            Error ("INTERNAL ERROR: No suffix present");
1811
        }
1812
    }
1813
    else
1814
    {
1815
        $tgt_label = saneLabel($entry, $src_label . '_for_');
1816
    }
1817
 
1818
    #
1819
    #   Save branch name for use when populating sandbox
1820
    #
1821
    $currentBranchName = $tgt_label;
1822
 
1823
    #
1824
    #   Perform the branch
1825
    #
1826
    if ( defined $src_label )
1827
    {
1828
        my @opts;
1829
        push (@opts, '-date', $date) if ( $date );
1830
        push (@opts, '-author', $author) if ( $author );
1831
 
1832
        JatsToolPrint ( 'jats_svnlabel',
1833
                        '-packagebase', "$svnRepo/$packageNames",
1834
                        'tags/' . $src_label,
1835
                        '-branch',
1836
                        '-clone', $tgt_label,
1837
                        @opts
1838
                      );
1839
    }
1840
}
1841
 
1842
 
1843
#-------------------------------------------------------------------------------
1844
# Function        : endPackage
1845
#
1846
# Description     : End of package processing
1847
#                   Clean up and display problems
1848
#
1849
# Inputs          : 
1850
#
1851
# Returns         : 
1852
#
1853
sub endPackage
1854
{
1855
    RmDirTree ('SvnImportDir');
1856
 
1857
    #
1858
    #   Display versions that did get captured
1859
    #
1860
    foreach my $entry ( @processOrder )
1861
    {
1862
        $versions{$entry}{Scanned} = 1;
1863
        next unless ( $versions{$entry}{TagCreated} );
1864
        Warning ("Processed: " . GetVname($entry) . ' :: ' . $versions{$entry}{rmRef} || $versions{$entry}{errStr} || '???' );
1865
    }
1866
 
1867
    #
1868
    #   Display versions that did not get created
1869
    #
1870
    foreach my $entry ( @processOrder )
1871
    {
1872
        $versions{$entry}{Scanned} = 1;
1873
        next if ( $versions{$entry}{TagCreated} );
1874
        Warning ("Not Processed: " . GetVname($entry) );
1875
    }
1876
 
1877
    foreach my $entry ( keys(%versions) )
1878
    {
1879
        next if ( $versions{$entry}{Scanned} );
1880
        Warning ("(E) INTERNAL ERROR. Package Not Processed: " . GetVname($entry) );
1881
    }
1882
 
1883
    Message ("All Done");
1884
}
1885
 
1886
sub JatsToolPrint
1887
{
1888
    Information ("Command: @_");
1889
    JatsTool @_;
1890
}
1891
 
1892
sub GetVname
1893
{
1894
    my ($entry) = @_;
1895
    my $me = 'NONE';
1896
    if ( $entry )
1897
        {
1898
        $me = $versions{$entry}{vname};
1899
        unless ( $me )
1900
        {
1901
            $me = 'Unknown-' . $entry;
1902
        }
1903
    }
1904
    return $me;
1905
}
1906
 
1907
sub saneLabel
1908
{
1909
    my ($entry, $pkgname) = @_;
1910
    my $me = $versions{$entry}{vname};
1911
    $pkgname = $versions{$entry}{name} unless ( defined $pkgname );
1912
 
1913
    Error ("Package does have a version string: pvid: $entry")
1914
        unless ( defined $me );
1915
 
1916
    #
1917
    #   Convert Wip format (xxxx) into a string that can be used for a label
1918
    #
1919
    if ( $me =~ m~^(.*)\((.*)\)(.*)$~ )
1920
    {
1921
        $me = $1 . '_' . $2 . '_' . $3 . '.WIP';
1922
        $me =~ s~_\.~.~;
1923
        $me =~ s~^_~~;
1924
    }
1925
 
1926
    #
1927
    #   Allow for WIPS
1928
    #   Get rid of multiple '_'
1929
    #   Replace space with -
1930
    #
1931
    $me = $pkgname . '_' . $me;
1932
    $me =~ tr~ ~-~s;
1933
    $me =~ tr~-~-~s;
1934
    $me =~ tr~_~_~s;
1935
 
1936
    return $me;
1937
}
1938
 
1939
 
1940
exit 0;
1941
 
1942
 
1943
#-------------------------------------------------------------------------------
1944
# Function        : GetPkgIdByName
1945
#
1946
# Description     :
1947
#
1948
# Inputs          : pkg_name
1949
#
1950
# Returns         : pkg_id
1951
#
1952
sub GetPkgIdByName
1953
{
1954
    my ( $pkg_name ) = @_;
1955
    my (@row);
1956
    my $pv_id;
1957
    my $pkg_id;
1958
 
1959
    #
1960
    #   Establish a connection to Release Manager
1961
    #
1962
    connectRM(\$RM_DB) unless ( $RM_DB );
1963
 
1964
    #
1965
    #   Extract data from Release Manager
1966
    #
1967
    my $m_sqlstr = "SELECT pkg.PKG_NAME, pkg.PKG_ID" .
1968
                   " FROM RELEASE_MANAGER.PACKAGES pkg" .
1969
                   " WHERE pkg.PKG_NAME = \'$pkg_name\'";
1970
 
1971
    my $sth = $RM_DB->prepare($m_sqlstr);
1972
    if ( defined($sth) )
1973
    {
1974
        if ( $sth->execute( ) )
1975
        {
1976
            if ( $sth->rows )
1977
            {
1978
                while ( @row = $sth->fetchrow_array )
1979
                {
1980
                    Verbose( "DATA: " . join(',', @row) );
1981
                    $pkg_id = $row[1] || 0;
1982
                    last;
1983
                }
1984
            }
1985
            else
1986
            {
1987
                Error ("GetPkgIdByName:No Data for package: $pkg_name");
1988
            }
1989
            $sth->finish();
1990
        }
1991
    }
1992
    else
1993
    {
1994
        Error("GetPkgIdByName:Prepare failure" );
1995
    }
1996
 
1997
    return $pkg_id;
1998
}
1999
 
2000
#-------------------------------------------------------------------------------
2001
# Function        : GetData_by_pkg_id
2002
#
2003
# Description     :
2004
#
2005
# Inputs          : pv_id
2006
#
2007
# Returns         :
2008
#
2009
sub GetData_by_pkg_id
2010
{
2011
    my ( $pkg_id, $packageName ) = @_;
2012
    my (@row);
2013
 
2014
    #
2015
    #   Establish a connection to Release Manager
2016
    #
2017
    Message ("Extract package versions from Release Manager: $packageName");
2018
    connectRM(\$RM_DB) unless ( $RM_DB );
2019
 
2020
    #
2021
    #   Extract data from Release Manager
2022
    #
2023
    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 ".
2024
                   " FROM RELEASE_MANAGER.PACKAGES pkg, RELEASE_MANAGER.PACKAGE_VERSIONS pv, ACCESS_MANAGER.USERS amu" .
2025
                   " WHERE pv.PKG_ID = \'$pkg_id\' AND pkg.PKG_ID = pv.PKG_ID AND amu.USER_ID (+) = pv.CREATOR_ID";
2026
 
2027
 
2028
    my $sth = $RM_DB->prepare($m_sqlstr);
2029
    if ( defined($sth) )
2030
    {
2031
        if ( $sth->execute( ) )
2032
        {
2033
            if ( $sth->rows )
2034
            {
2035
                while ( @row = $sth->fetchrow_array )
2036
                {
2037
                    Verbose( "DATA: " . join(',', @row) );
2038
                    my $pkg_name = $row[0] || 'Unknown';
2039
                    my $pkg_ver = $row[1] || 'Unknown';
2040
                       $pkg_ver =~ s~\s+$~~;
2041
                       $pkg_ver =~ s~^\s+~~;
2042
                    my $pv_id = $row[3] || 'Unknown';
2043
                    my $last_pv_id = $row[4];
2044
                    my $created =  $row[5] || 'Unknown';
2045
                    my $vcstag =  $row[6] || 'Unknown';
2046
                       $vcstag =~ tr~\\/~/~s;
2047
 
2048
                    my $created_id =  $row[7] || ($row[10] ? "Userid_$row[10]" :'Unknown');
2049
                    my $comment =  $row[8] || '';
2050
                    my $locked =  $row[9] || 'N';
2051
 
2052
                    #
2053
                    #   Some developers have a 'special' package version
2054
                    #   We really need to ignore them
2055
                    #
2056
                    next if ( $pkg_ver eq '23.23.23.ssw' );
2057
 
2058
                    #
2059
                    #   Add data to the hash
2060
                    #       Remove entries that address themselves
2061
                    #
2062
                    push (@{$versions{$last_pv_id}{next}}, $pv_id) unless ($pv_id == $last_pv_id || $last_pv_id == 0) ;
2063
                    $versions{$pv_id}{name} = $pkg_name;
2064
                    $versions{$pv_id}{pvid} = $pv_id;
2065
                    $versions{$pv_id}{vname} = $pkg_ver;
2066
                    $versions{$pv_id}{vcsTag} = $vcstag;
2067
                    $versions{$pv_id}{created} = $created;
2068
                    $versions{$pv_id}{created_id} = $created_id;
2069
                    $versions{$pv_id}{comment} = $comment;
2070
                    $versions{$pv_id}{locked} = $locked;
2071
                    $versions{$pv_id}{TimeStamp} = str2time( $created );
2072
                    $versions{$pv_id}{Age} = ($now - $versions{$pv_id}{TimeStamp}) / (60 * 60 * 24);
2073
                    $versions{$pv_id}{TooOld} = 1 if ( $opt_age && $opt_age <= $versions{$pv_id}{Age} );
2074
                    examineVcsTag($pv_id);
2075
 
2076
                    #
2077
                    #   Process version number
2078
                    #
2079
                    my ($suffix, $version, $isaR, $isaWip, $buildVersion ) = massageVersion($pkg_ver, $pkg_name);
2080
 
2081
                    $versions{$pv_id}{version} = $version;
2082
                    $versions{$pv_id}{buildVersion} = $buildVersion;
2083
                    $versions{$pv_id}{isaRipple} = 1 if ( $isaR );
2084
                    $versions{$pv_id}{isaWip} = 1 if ( $isaWip );
2085
 
2086
                    #
2087
                    #   Process suffix
2088
                    #
2089
                    $suffix = 'Unknown' unless ( $suffix );
2090
                    $suffix = lc ($suffix);
2091
                    $versions{$pv_id}{suffix} = $suffix;
2092
                    push @{$suffixes{$suffix}}, $pv_id;
2093
 
2094
#                    print "$pkg_name, $pkg_ver, $pv_id, $last_pv_id, $locked, $created, $created_id, $suffix\n";
2095
                }
2096
            }
2097
            else
2098
            {
2099
                Error ("GetData_by_pkg_id: No Data: $m_sqlstr");
2100
            }
2101
            $sth->finish();
2102
        }
2103
        else
2104
        {
2105
                Error ("GetData_by_pkg_id: Execute: $m_sqlstr");
2106
        }
2107
    }
2108
    else
2109
    {
2110
        Error("GetData_by_pkg_id:Prepare failure" );
2111
    }
2112
}
2113
 
2114
#-------------------------------------------------------------------------------
2115
# Function        : massageVersion
2116
#
2117
# Description     : Process a version number and return usful bits
2118
#
2119
# Inputs          : Version Number
2120
#                   Package Name - debug only
2121
#
2122
# Returns         : An array
2123
#                       suffix
2124
#                       multipart version string useful for text comparisons
2125
#
2126
sub massageVersion
2127
{
2128
    my ($version, $name) = @_;
2129
    my ($major, $minor, $patch, $build, $suffix);
2130
    my $result;
2131
    my $buildVersion;
2132
    my $isaRipple;
2133
    my $isaWIP;
2134
    $build = 0;
2135
 
2136
#print "--- $name, $version\n";
2137
    $version =~ s~^_~~;
2138
    $version =~ s~^${name}_~~;
2139
 
2140
    #
2141
    #   xxxxxxxxx.nnnn.cots
2142
    #
2143
    if ( $version =~ m~(.*)\.cots$~ ) {
2144
        my $cots_base = $1;
2145
        $suffix = '.cots';
2146
        if ( $version =~ m~(.*?)\.([0-9]{4})\.cots$~ )
2147
        {
2148
            $result = $1 . sprintf (".%4.4d", $2) . $suffix;
2149
        }
2150
        else
2151
        {
2152
            $result = $cots_base . '.0000.cots';
2153
        }
2154
    }
2155
    #
2156
    #   Convert version into full form for comparisions
2157
    #       nnn.nnn.nnn.[p]nnn.xxx
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
    #   Don't flag as ripples - they are patches
2163
    #
2164
    elsif ( $version =~ m~^(\d+)\.(\d+)\.(\d+)[-.p][p]?(\d+)([-.](.*))?$~ ) {
2165
        $major = $1;
2166
        $minor = $2;
2167
        $patch = $3;
2168
        $build = $4;
2169
        $suffix = defined $6 ? ".$6" : '';
2170
        $isaRipple = 0;
2171
    }
2172
    #
2173
    #       nn.nnn.nnnnn.xxx
2174
    #       nn.nnn.nnnnn-xxx
2175
    #       nnn.nnn.nnnx.xxx
2176
    #   Don't flag as ripples - they are patches
2177
    #
2178
    elsif ( $version =~ m~^(\d+)\.(\d+)\.(\d+)\w?([-.](.*))?$~ ) {
2179
        $major = $1;
2180
        $minor = $2;
2181
        $patch = $3;
2182
        if ( length( $patch) >= 4 )
2183
        {
2184
            $build = substr( $patch, -3 ,3);
2185
            $patch = substr( $patch,  0 ,length($patch)-3);
2186
        }
2187
        $suffix = defined $5 ? ".$5" : '';
2188
    }
2189
 
2190
    #
2191
    #       nnn.nnn.nnn
2192
    #       nnn.nnn-nnn
2193
    #       nnn.nnn_nnn
2194
    #
2195
    elsif ( $version =~ m~^(\d+)\.(\d+)[-._](\d+)$~ ) {
2196
        $major = $1;
2197
        $minor = $2;
2198
        $patch = $3;
2199
        $suffix = '';
2200
    }
2201
 
2202
    #
2203
    #       nnn.nnn.nnn.nnn
2204
    #       nnn.nnn.nnn-nnn
2205
    #       nnn.nnn.nnn_nnn
2206
    #
2207
    elsif ( $version =~ m~^(\d+)\.(\d+)\.(\d+)[-._](\d+)$~ ) {
2208
        $major = $1;
2209
        $minor = $2;
2210
        $patch = $3;
2211
        $build = $4;
2212
        $suffix = '';
2213
        $isaRipple = 0;
2214
    }
2215
 
2216
 
2217
    #
2218
    #       nnn.nnn
2219
    #
2220
    elsif ( $version =~ m~^(\d+)\.(\d+)$~ ) {
2221
        $major = $1;
2222
        $minor = $2;
2223
        $patch = 0;
2224
        $suffix = '';
2225
    }
2226
    #
2227
    #       nnn.nnn.xxx
2228
    #
2229
    elsif ( $version =~ m~^(\d+)\.(\d+)(\.\w+)$~ ) {
2230
        $major = $1;
2231
        $minor = $2;
2232
        $patch = 0;
2233
        $suffix = $3;
2234
    }
2235
 
2236
    #
2237
    #       nnn.nnn.nnnz
2238
    #
2239
    elsif ( $version =~ m~^(\d+)\.(\d+)\.(\d+)([a-z])$~ ) {
2240
        $major = $1;
2241
        $minor = $2;
2242
        $patch = $3;
2243
        $build = ord($4) - ord('a');
2244
        $suffix = '.cots';
2245
        $isaRipple = 0;
2246
    }
2247
    #
2248
    #       ???REV=???
2249
    #
2250
    elsif ( $version =~ m~REV=~ ) {
2251
        $suffix = '.cots';
2252
        $result = $version . '.0000.cots';
2253
    }
2254
 
2255
    #
2256
    #   Wip Packages
2257
    #   (nnnnnn).xxx
2258
    #   Should be essential, but want to sort very low
2259
    #
2260
    elsif ($version =~ m~\((.*)\)(\..*)?~) {
2261
        $suffix = $2 || '';
2262
        $result = "000.000.000.000$suffix";
2263
        $isaWIP = 1;
2264
    }
2265
 
2266
    #
2267
    #   !current
2268
    #
2269
    elsif ($version eq '!current' || $version eq 'current_$USER' || $version eq 'current' || $version eq 'beta' || $version eq 'latest' || $version eq 'beta.cr' || $version eq 'CREATE') {
2270
        $suffix = '';
2271
        $result = "000.000.000.000$suffix";
2272
        $isaWIP = 1;
2273
    }
2274
 
2275
    #
2276
    #   Also WIP: FINRUN.103649.BEI.WIP
2277
    elsif ($version =~ m~(\.[a-zA-Z]+)\.WIP$~) {
2278
        $suffix = lc($1);
2279
        $result = "000.000.000.000$suffix";
2280
        $isaWIP = 1;
2281
    }
2282
 
2283
    #
2284
    #   Also ERGOFSSLS190100_015
2285
    #   Don't flag as a ripple
2286
    elsif ($version =~ m~^ERG[A-Z]+(\d\d)(\d\d)(\d\d)[-_](\d+)(\.\w+)?$~) {
2287
        $major = $1;
2288
        $minor = $2;
2289
        $patch = $3;
2290
        $build = $4;
2291
        $suffix = $5 || '.sls';
2292
        $isaRipple = 0;
2293
    }
2294
 
2295
    #
2296
    #   Stuff we don't yet handle
2297
    #
2298
    else  {
2299
        Warning ("Unknown version number: $name,$version");
2300
        $version =~ m~(\.\w+)$~;
2301
        $suffix = $1 || '';
2302
        $result = $version;
2303
    }
2304
 
2305
    $isaRipple = ($build > 0) unless defined $isaRipple;
2306
    unless ( $result )
2307
    {
2308
        # Major and minor of 99.99 are normally funy versions
2309
        # Don't make important desicions on them
2310
        #
2311
        if ( $major == 99 && $minor == 99 )
2312
        {
2313
            $major = 0;
2314
            $minor = 0;
2315
            $patch = 0;
2316
        }
2317
 
2318
        $result = sprintf("%3.3d.%3.3d.%3.3d.%3.3d%s", $major,$minor,$patch,$build,$suffix || '.0000');
2319
        $buildVersion = [ $major, $minor, $patch, $build ];
2320
    }
2321
 
2322
    $suffix = lc( $suffix );
2323
    if ( exists $suffixFixup{$suffix} )
2324
    {
2325
        $suffix = $suffixFixup{$suffix} ;
2326
    }
2327
 
2328
    return ($suffix, $result, $isaRipple, $isaWIP, $buildVersion );
2329
}
2330
 
2331
#-------------------------------------------------------------------------------
2332
# Function        : examineVcsTag
2333
#
2334
# Description     : Examine a VCS Tag and determine if it looks like rubbish
2335
#
2336
# Inputs          : $entry
2337
#
2338
# Returns         : Will add Data to the $entry
2339
#
2340
sub examineVcsTag
2341
{
2342
    my ($entry) = @_;
2343
    my $bad = 0;
2344
    my $vcstag = $versions{$entry}{vcsTag};
2345
    if ( $vcstag =~ m~^SVN::~ ) {
2346
        $versions{$entry}{isSvn} = 1;
2347
 
2348
    } elsif ( $vcstag =~ m~^CC::(.*?)(::(.+))?$~ ) {
2349
        my $path = $1  || '';
2350
        my $label = $2 || '';
2351
        $bad = 1 unless ( $label );
2352
        $bad = 1 if ( $label =~ m~^N/A$~i || $label  =~ m~^na$~i );
2353
 
2354
        $bad = 1 unless ( $path );
2355
        $bad = 1 if ( $path =~ m~^N/A$~i || $path  =~ m~^na$~i );
2356
        $bad = 1 if ( $path =~ m~^/dpkg_archive~ || $path  =~ m~^dpkg_archive~ );
2357
        $bad = 1 if ( $path =~ m~^/devl/~ || $path  =~ m~^devl/~ );
2358
        $bad = 1 if ( $path =~ m~^http:~i );
2359
        $bad = 1 if ( $path =~ m~^[A-Za-z]\:~ );
2360
        $bad = 1 if ( $path =~ m~^//~ );
2361
        $bad = 1 if ( $path =~ m~^cvsserver:~ );
2362
        $bad = 1 if ( $path =~ m~,\s*module:~ );
2363
#        $bad = 1 unless ( $path =~ m~^/~ );
2364
    }
2365
    else
2366
    {
2367
        $bad = 1;
2368
    }
2369
    $versions{$entry}{badVcsTag} = 1 if ( $bad );
2370
}
2371
 
2372
#-------------------------------------------------------------------------------
2373
# Function        : logToFile
2374
#
2375
# Description     : Log some data to a named file
2376
#                   Use file locking to allow multiple process to log
2377
#
2378
# Inputs          : $filename           - Name of file to log
2379
#                   ...                 - Data to log
2380
#
2381
# Returns         : Nothing
2382
#
2383
sub logToFile
2384
{
2385
    my ($file, @data) = @_;
2386
 
2387
    open  (LOGFILE, '>>', $file);
2388
    flock (LOGFILE, LOCK_EX);
2389
    print  LOGFILE "@data\n";
2390
    flock (LOGFILE, LOCK_UN);
2391
    close (LOGFILE);
2392
}
2393
 
2394
#-------------------------------------------------------------------------------
2395
# Function        : createImages
2396
#
2397
# Description     : Create nice images of the RM version tree
2398
#
2399
# Inputs          : 
2400
#
2401
# Returns         : 
2402
#
2403
sub createImages
2404
{
2405
 
2406
    my $filebase = "${packageNames}";
2407
    open (FH, '>', "$filebase.dot" ) or die "Cannot open output";
2408
    print FH "digraph \"${packageNames}\" {\n";
2409
    #print FH "rankdir=LR;\n";
2410
    print FH "node[fontsize=16];\n";
2411
    print FH "node[target=_graphviz];\n";
2412
#    print FH "subgraph cluster_A {\n";
2413
#    print FH "node[fontsize=12];\n";
2414
 
2415
    {
2416
        my @text;
2417
        push @text, $packageNames;
2418
        push @text, 'HyperLinked to Release Manager';
2419
        push @text, 'Created:' . localtime();
2420
        push @text, '|';
2421
 
2422
        push @text, 'Total RM versions: ' . $totalVersions;
2423
        push @text, 'Essential Entries: ' . scalar @EssentialPackages;
2424
        push @text, 'Initial trees: ' . $initialTrees;
2425
 
2426
        push @text, 'Number of Entries: ' . scalar keys %versions;
2427
        push @text, 'Type : ' . $packageType;
2428
        push @text, 'All versions in Subversion' if ( $allSvn );
2429
 
2430
        push @text, '|';
2431
        push @text, 'Total Project Branches: ' . $ProjectCount;
2432
        foreach ( sort keys %knownProjects )
2433
        {
2434
            my $count = $knownProjects{$_}{count} || 0;
2435
            if ( $count )
2436
            {
2437
                my $text = 'Project Branch: ' . $_;
2438
                $text .= " (" . $count . ")" if ( $count > 1 );
2439
                push @text, $text;
2440
            }
2441
        }
2442
 
2443
        push @text, '|';
2444
        push @text, 'Bad VCS : ' . $badVcsCount;
2445
        push @text, 'Bad Singletions : ' . $badSingletonCount;
2446
        push @text, 'Deadwood entries : ' . $trimCount;
2447
        push @text, 'Walking Mode : Flat' if ($opt_flat);
2448
        push @text, 'Pruned Mode : ' . $pruneModeString;
2449
        push @text, 'Pruned entries : ' . $pruneCount;
2450
 
2451
        if ( @unknownProjects )
2452
        {
2453
            push @text, '|';
2454
            push @text, 'Unknown Projects';
2455
            push @text, 'Unknown Project: ' . $_ foreach (sort @unknownProjects );
2456
        }
2457
 
2458
        #
2459
        #   Multiple Paths
2460
        #
2461
        if ( scalar @multiplePaths > 1 )
2462
        {
2463
            push @text, '|';
2464
            push @text, 'Multiple Paths';
2465
            push @text, @multiplePaths;
2466
        }
2467
 
2468
        #
2469
        #   Bad essentials
2470
        #
2471
        if ( @badEssentials  )
2472
        {
2473
            push @text, '|';
2474
            push @text, 'Bad Essential Versions';
2475
            push @text, GetVname($_) foreach ( @badEssentials );
2476
        }
2477
 
2478
        #
2479
        #   Subversion Data
2480
        #
2481
        if ( %svnData )
2482
        {
2483
            push @text, '|';
2484
            push @text, 'Subversion';
2485
            push @text, 'Trunk used' if exists $svnData{branches}{trunk} ;
2486
            push @text, 'Labels: ' . scalar keys %{$svnData{tags}} ;
2487
            push @text, 'Branches: ' . scalar keys %{$svnData{branches}} ;
2488
        }
2489
 
2490
        push @text, '';
2491
        my $text = join '\l', @text;
2492
        $text =~ s~\|\\l~|~g;
2493
 
2494
        my @attributes;
2495
        push @attributes, "shape=record";
2496
        push @attributes, "label=\"{$text}\"";
2497
        push @attributes, "tooltip=\"$packageNames\"";
2498
        push @attributes, "URL=\"" . $GBE_RM_URL . "/view_by_version.asp?pkg_id=$first_pkg_id" . "\"";
2499
        push @attributes, "color=red";
2500
        my $attr = join( ' ', @attributes);
2501
 
2502
        my $tld_done = 'TitleBlock';
2503
        print FH "$tld_done [$attr]\n";
2504
    }
2505
 
2506
    #
2507
    #   Generate Legend
2508
    #
2509
    {
2510
        my @text;
2511
        push @text, 'Legend';
2512
        push @text, '|';
2513
        push @text, 'Node Content';
2514
        push @text, 'Package Version';
2515
#        push @text, 'Release Manager Ref (pvid)';
2516
        push @text, 'Creation Date: yyyy-mm-dd';
2517
        push @text, '(Coded information)';
2518
        push @text, '|{Code';
2519
        push @text, '|{N: Not Locked';
2520
        push @text, 'b: Bad Singleton';
2521
        push @text, 'B: Bad VCS Tag';
2522
        push @text, 'D: DeadWood';
2523
        push @text, 'E: Essential Version';
2524
        push @text, 'G: Glued into Version Tree';
2525
        push @text, 'S: Splitpoint';
2526
        push @text, 't: Glued into Project Tree';
2527
        push @text, 'T: Tip version';
2528
        push @text, 'V: In SVN';
2529
        push @text, '+: In Subversion';
2530
        push @text, '}}';
2531
 
2532
        push @text, '|';
2533
        push @text, 'Outline';
2534
        push @text, 'Red: Dead or Bad VCS Tag';
2535
        push @text, 'Orange: Project Branch Root';
2536
        push @text, 'Green: Ripple Build Version';
2537
        push @text, 'Blue: Essential Version';
2538
        push @text, 'Darkmagenta: Entry Glued into tree';
2539
        push @text, 'Magenta: Entry added to project tree';
2540
 
2541
 
2542
        push @text, '|';
2543
        push @text, 'Fill';
2544
        push @text, 'PowderBlue: Essential Version';
2545
        push @text, 'Red: Bad Essential Version';
2546
        push @text, 'Light Green: Migrated to SVN';
2547
#        push @text, 'Red: Entry Glued into tree';
2548
#        push @text, 'Green: Entry added to project tree';
2549
 
2550
        push @text, '|';
2551
        push @text, 'Shape';
2552
        push @text, 'Oval: Normal Package Version';
2553
        push @text, 'Invhouse: Project Branch Root';
2554
        push @text, 'Octagon: Branch Point';
2555
        push @text, 'Box: Bad Single version with no history';
2556
        push @text, 'Doublecircle: Tip of a Project Branch';
2557
 
2558
        push @text, '';
2559
        my $text = join '\l', @text;
2560
        $text =~ s~\|\\l~|~g;
2561
        $text =~ s~\}\\l~}~g;
2562
 
2563
        my @attributes;
2564
        push @attributes, "shape=record";
2565
        push @attributes, "label=\"{$text}\"";
2566
        push @attributes, "color=red";
2567
        my $attr = join( ' ', @attributes);
2568
 
2569
        my $tld_done = 'LegendBlock';
2570
        print FH "$tld_done [$attr]\n";
2571
    }
2572
 
2573
#    print FH "\n}\n";
2574
    print FH "TitleBlock -> LegendBlock [style=invis]\n";
2575
 
2576
    sub genLabelText
2577
    {
2578
        my ($entry) = @_;
2579
        my @label;
2580
        push @label, $versions{$entry}{name} if ( $multiPackages );
2581
        push @label, $versions{$entry}{vname};
2582
#        push @label, $entry;       # Add PVID
2583
        push @label, substr( $versions{$entry}{created}, 0, 10); #  2008-02-19
2584
#        push @label, 'V=' . $versions{$entry}{maxVersion};
2585
#        push @label, 'B=' . $versions{$entry}{svnBranchTip} if ( exists $versions{$entry}{svnBranchTip} );
2586
 
2587
 
2588
        my $stateText = '';
2589
        $stateText .= 'N' if ($versions{$entry}{locked} eq 'N');
2590
        $stateText .= 'b' if (exists $versions{$entry}{badSingleton});
2591
        $stateText .= 'B' if (exists $versions{$entry}{badVcsTag});
2592
        $stateText .= 'G' if (exists $versions{$entry}{GluedIn});
2593
        $stateText .= 't' if (exists $versions{$entry}{MakeTree});
2594
        $stateText .= 'E' if (exists $versions{$entry}{Essential});
2595
        $stateText .= 'D' if (exists $versions{$entry}{DeadWood});
2596
        $stateText .= 'S' if (exists $versions{$entry}{EssentialSplitPoint} && $versions{$entry}{EssentialSplitPoint} > 1 );
2597
        $stateText .= 'T' if (exists $versions{$entry}{Tip} );
2598
        $stateText .= 'V' if (exists $versions{$entry}{isSvn} );
2599
        $stateText .= '+' if (exists $versions{$entry}{svnVersion} );
2600
#        $stateText .= 's' if (exists $versions{$entry}{branchPoint} );
2601
#        $stateText .= ' T='. $versions{$entry}{threadId} if (exists $versions{$entry}{threadId});
2602
#        $stateText .= ' EssentalPath' if (exists $versions{$entry}{EssentialPath});
2603
#        $stateText .= ' Count='. $versions{$entry}{EssentialSplitPoint} if (exists $versions{$entry}{EssentialSplitPoint});
2604
#        $stateText .= ' M='. $versions{$entry}{maxVersion} if (exists $versions{$entry}{maxVersion});
2605
 
2606
        push @label, "(${stateText})" if ( $stateText );
2607
 
2608
        return join ('\n', @label );
2609
    }
2610
 
2611
    sub genAttributes
2612
    {
2613
        my ($entry) = @_;
2614
        my @attributes;
2615
        push @attributes, 'label="' . genLabelText($entry) . '"';
2616
        push @attributes, 'URL="' . dotUrl($entry) . '"';
2617
        push @attributes, 'tooltip="' . "Goto: $versions{$entry}{vname}, PVID=$entry" ,'"';
2618
        my $shape;
2619
            $shape = 'box' if ($versions{$entry}{badSingleton});
2620
            $shape = 'octagon'  if ($versions{$entry}{branchPoint});
2621
            $shape = 'invhouse' if ($versions{$entry}{newSuffix});
2622
            $shape = 'doublecircle' if ($versions{$entry}{Tip});
2623
 
2624
 
2625
        push @attributes, 'shape=' . $shape if ( $shape );
2626
 
2627
        my $color;
2628
        my $fill;
2629
           $color = 'color=green style=bold' if ( $versions{$entry}{isaRipple} );
2630
           $color = 'color=orange style=bold' if ( $versions{$entry}{newSuffix} );
2631
           $color = 'color=red style=bold' if ( $versions{$entry}{DeadWood} || $versions{$entry}{badVcsTag} );
2632
           $color = 'color=blue style=bold' if ( $versions{$entry}{Essential} );
2633
           $color = 'color=darkmagenta style=bold' if ( $versions{$entry}{GluedIn} );
2634
           $color = 'color=magenta style=bold' if ( $versions{$entry}{MakeTree} );
2635
 
2636
           $fill = 'style=filled fillcolor=powderblue' if ( $versions{$entry}{Essential} );
2637
           $fill = 'style=filled fillcolor=red' if ( $versions{$entry}{Essential} && $versions{$entry}{badVcsTag} );
2638
           $fill = 'style=filled fillcolor="#99FF99"' if ( exists $versions{$entry}{svnVersion} );
2639
 
2640
 
2641
        push @attributes, $color if ( $color );
2642
        push @attributes, $fill if ( $fill );
2643
 
2644
        return '[' . join( ' ', @attributes) . ']';
2645
    }
2646
 
2647
    sub genArrowAttributes
2648
    {
2649
        my ($not_first, $entry) = @_;
2650
        my @attributes;
2651
 
2652
        push @attributes, 'arrowhead=empty' if ( $not_first );
2653
        push ( @attributes, 'label="' . $versions{$entry}{svnBranchTip} .'"' ) if ( exists $versions{$entry}{svnBranchTip} );
2654
 
2655
        return ('[' . join( ' ', @attributes) . ']') if ( @attributes ) ;
2656
        return '';
2657
    }
2658
 
2659
    #
2660
    #   Flat
2661
    #
2662
    if ( $opt_flat )
2663
    {
2664
        my $last = 0;
2665
        foreach my $entry (@flatOrder )
2666
        {
2667
            if ( $last )
2668
            {
2669
                my $me = dotTag($last);
2670
 
2671
                print FH pentry($me)  ,' -> ', pentry(dotTag($entry)), genArrowAttributes(0, $entry) ,";\n";
2672
                print FH pentry($me)  ,genAttributes($last) . ";\n";
2673
            }
2674
            $last = $entry;
2675
        }
2676
        print FH pentry(dotTag($last))  ,genAttributes($last) . ";\n";
2677
 
2678
    }
2679
    else
2680
    {
2681
        foreach my $entry ( sort {$a <=> $b} keys(%versions) )
2682
        {
2683
            my $me = dotTag($entry);
2684
            my @versions = @{ $versions{$entry}{next}};
2685
            my $ii = 0;
2686
            foreach ( @versions )
2687
            {
2688
                print FH pentry($me)  ," -> ",pentry(dotTag($_)), genArrowAttributes($ii++, $_), ";\n";
2689
            }
2690
 
2691
            print FH pentry($me)  ,genAttributes($entry) . ";\n";
2692
        }
2693
    }
2694
 
2695
    print FH "\n};\n";
2696
    close FH;
2697
 
2698
    #
2699
    #   Convert DOT to a SVG
2700
    #
2701
    unless ( $UNIX )
2702
    {
2703
    print "Generating graphical images\n";
2704
#    system( "dot $filebase.dot -Tjpg -o$filebase.jpg" );  # -v
2705
    system( "dot $filebase.dot -Tsvg -o$filebase.svg" );  # -v
2706
#    unlink("$filebase.dot");
2707
 
2708
    #
2709
    #   Display a list of terminal packages
2710
    #   These are packages that are not used by any other package
2711
    #
2712
    print "\n";
2713
#    print "Generated: $filebase.dot\n";
2714
#    print "Generated: $filebase.jpg\n";
2715
    print "Generated: $filebase.svg\n";
2716
    }
2717
    else
2718
    {
2719
        print "Generated: $filebase.dot\n";
2720
    }
2721
}
2722
 
2723
sub dotTag
2724
{
2725
    my ($entry) = @_;
2726
 
2727
    my $label = '';
2728
    $label .= $versions{$entry}{name} if $multiPackages;
2729
    $label .= $versions{$entry}{vname};
2730
    $label =~ s~[-() ]~_~g;
2731
    return $label;
2732
}
2733
 
2734
sub dotUrl
2735
{
2736
    my ($entry) = @_;
2737
 
2738
    my $pv_base = $GBE_RM_URL . "/fixed_issues.asp?pv_id=$entry";
2739
}
2740
 
2741
#-------------------------------------------------------------------------------
2742
# Function        : pentry
2743
#
2744
# Description     : Generate an entry list as text
2745
#                   Replace "." with "_" since DOT doesn't like .'s
2746
#                   Seperate the arguments
2747
#
2748
# Inputs          : @_          - An array of entries to process
2749
#
2750
# Returns         : A string
2751
#
2752
sub pentry
2753
{
2754
    my ($data) = @_;
2755
    $data =~ s~\.~_~g;
2756
    $result = '"' . $data . '"' ;
2757
    return $result;
2758
}
2759
 
2760
#-------------------------------------------------------------------------------
2761
# Function        : getVobMapping
2762
#
2763
# Description     : Read in Package to Repository Mapping
2764
#
2765
# Inputs          : 
2766
#
2767
# Returns         : Populates %VobMapping
2768
#                             Mapping of PackageName to RepoName[/Subdir]
2769
#
2770
our %ScmRepoMap;
2771
sub getVobMapping
2772
{
2773
    Message ("Read in Vob Mapping");
2774
 
2775
    my $fname = 'cc2svn.repo.dat';
2776
    Error "Cannot locate $fname" unless ( -f $fname );
2777
    require $fname;
2778
 
2779
    Error "Data in $fname is not valid\n"
2780
        unless ( keys(%ScmRepoMap) >= 0 );
2781
 
2782
    $opt_vobMap = $ScmRepoMap{$packageNames}{repo}
2783
        if (exists $ScmRepoMap{$packageNames});
2784
 
2785
    #
2786
    #   Free the memory
2787
    #
2788
    %ScmRepoMap = ();
2789
 
2790
    #
2791
    #   Calculate Target Repo
2792
    #
2793
    Warning ("No VOB Mapping found")
2794
        unless ($opt_vobMap);
2795
    Error("No repository specified. ie -repo=DevTools or -repo=COTS")
2796
        unless ( $opt_repo || $opt_vobMap );
2797
 
2798
    my $r1 = ($opt_repo || '') . '/' . ($opt_vobMap || '');
2799
    $r1 =~ s~^/~~;
2800
    $r1 =~ s~/$~~;
2801
    $svnRepo = $opt_repo_base . $r1;
2802
 
2803
    Verbose( "Repo URL: $svnRepo");
2804
}
2805
 
2806
 
2807
#-------------------------------------------------------------------------------
2808
# Function        : getEssenialPackageVersions
2809
#
2810
# Description     : Determine the 'Essental' Package Versions
2811
#                   Read the data in from an external file
2812
#
2813
# Inputs          : 
2814
#
2815
# Returns         : Populates @EssentialPackages
2816
#
2817
 
2818
our %ScmReleases;
2819
our %ScmPackages;
2820
our %ScmSuffixes;
2821
sub getEssenialPackageVersions
2822
{
2823
    Message ("Read in Essential Package Versions");
2824
 
2825
    my $fname = 'cc2svn.raw.txt';
2826
    Error "Cannot locate $fname" unless ( -f $fname );
2827
    require $fname;
2828
 
2829
    Error "Data in $fname is not valid\n"
2830
        unless ( keys(%ScmReleases) >= 0 );
2831
 
2832
#    DebugDumpData("ScmReleases", \%ScmReleases );
2833
#    DebugDumpData("ScmPackages", \%ScmPackages );
2834
#    DebugDumpData("ScmSuffixes", \%ScmSuffixes );
2835
 
2836
    #
2837
    #   Create a list of essential packages
2838
    #   Retain packages-versions used in this program
2839
    #
2840
    foreach ( keys %ScmPackages )
2841
    {
2842
        next unless ( exists  $pkg_ids{ $ScmPackages{$_}{pkgid} } );
2843
        push @EssentialPackages, $_;
2844
        Error ("Essential Package Version not in extracted Release Manager Data: $_")
2845
            unless ( exists $versions{$_} );
2846
        $versions{$_}{Essential} = 1;
2847
        #print "ESSENTIAL: $versions{$_}{name} $versions{$_}{vname}\n";
2848
    }
2849
 
2850
    #
2851
    #   Free memory
2852
    #
2853
    %ScmReleases = ();
2854
    %ScmPackages = ();
2855
    %ScmSuffixes = ();
2856
 
2857
#    DebugDumpData("Essential", \@EssentialPackages );
2858
    Message ("Essential Versions: " . scalar @EssentialPackages );
2859
}
2860
 
2861
#-------------------------------------------------------------------------------
2862
# Function        : ReportPathVariance
2863
#
2864
# Description     : Report variance in paths used by the versions
2865
#
2866
# Inputs          : 
2867
#
2868
# Returns         : 
2869
#
2870
my %VobPaths;
2871
sub ReportPathVariance
2872
{
2873
    Message ("Detect Multiple Paths");
2874
    foreach my $entry ( keys(%versions) )
2875
    {
2876
        my $e = $versions{$entry};
2877
        next if ( isSet ($e, 'DeadWood' ) );
2878
        next if ( isSet ($e, 'badVcsTag') );
2879
        next if ( isSet ($e, 'isSvn') );
2880
        my $tag = $e->{vcsTag};
2881
        next unless ( $tag );
2882
 
2883
        $tag =~ m~^(.+?)::(.*?)(::(.+))?$~;
2884
        my $vcsType = $1;
2885
        my $cc_label = $4;
2886
        my $cc_path = $2;
2887
        $cc_path = '/' . $cc_path;
2888
        $cc_path =~ tr~\\/~/~s;
2889
 
2890
        $VobPaths{$cc_path}++;
2891
    }
2892
 
2893
    @multiplePaths = sort keys %VobPaths;
2894
    if ( scalar @multiplePaths > 1 )
2895
    {
2896
        Warning ("Multiple Paths:" . $_ ) foreach (@multiplePaths);
2897
    }
2898
}
2899
 
2900
sub isSet
2901
{
2902
    my ($base, $element) = @_;
2903
    return 0 unless ( exists $base->{$element} );
2904
    return $base->{$element};
2905
}
2906
 
2907
 
2908
#-------------------------------------------------------------------------------
2909
# Function        : recurseList
2910
#
2911
# Description     : Return a list of all element below a given head element
2912
#
2913
# Inputs          : $head               - Head element
2914
#
2915
# Returns         : A list, not in any particular order
2916
#
2917
 
2918
our @recurseList;
2919
sub recurseList
2920
{
2921
    @recurseList = ();
2922
    recurseListBody (@_);
2923
    return @recurseList;
2924
}
2925
sub recurseListBody
2926
{
2927
    foreach my $entry ( @_ )
2928
    {
2929
        push @recurseList, $entry;
2930
no warnings "recursion";
2931
        recurseListBody (@{$versions{$entry}{next}});
2932
    }
2933
}
2934
 
2935
#-------------------------------------------------------------------------------
2936
# Function        : getSvnData
2937
#
2938
# Description     : Read the SVN tree and see what we have
2939
#
2940
# Inputs          : 
2941
#
2942
# Returns         : 
2943
#
2944
my @svnDataItems;
2945
sub getSvnData
2946
{
2947
    Message ("Examine Subversion Tree");
2948
 
2949
    #
2950
    #   Re-init data
2951
    #
2952
    @svnDataItems = ();
2953
    %svnData = ();
2954
 
2955
    #
2956
    #   Create an SVN session
2957
    #
2958
    return unless ( $svnRepo );
2959
    my $svn = NewSessionByUrl ( "$svnRepo/$packageNames" );
2960
    return unless ( $svn );
2961
 
2962
    #
2963
    #   extract data
2964
    #
2965
#    DebugDumpData("SVN", $svn );
2966
    $svn->SvnCmd ( 'log', '-v', '--xml', '--stop-on-copy', $svn->Full()
2967
                    , { 'credentials' => 1,
2968
                        'process' => \&ProcessSvnLog,
2969
                         }
2970
                        );
2971
 
2972
    #
2973
    #   Process data
2974
    foreach my $entry ( @svnDataItems )
2975
    {
2976
        my $name;
2977
        my $isaBranch;
2978
        my $target = $entry->{target};
2979
        if ( $target =~ m~/tags/(.*)~ ) {
2980
            $name = $1;
2981
            $svnData{tags}{$name} = 1;
2982
        } elsif ( $target =~ m~/branches/(.*)~ )  {
2983
            $name = $1;
2984
    #        $branches{$1} = 1;
2985
        } else {
2986
            $svnData{nonTag}{$target} = 1;
2987
        }
2988
 
2989
        my $fromBranch;
2990
        if ( $entry->{fromPath} =~ m~/trunk$~  ) {
2991
            $fromBranch = 'trunk';
2992
        } elsif ( $entry->{fromPath} =~ m~/branches/(.*)~ ) {
2993
            $fromBranch = $1;
2994
        }
2995
 
2996
        if ( defined($fromBranch) && ! exists $svnData{branches}{$fromBranch} )
2997
        {
2998
            unless ( $name eq $fromBranch )
2999
            {
3000
                $svnData{branches}{$fromBranch} = $name;
3001
                $svnData{tips}{$name} = $fromBranch;
3002
            }
3003
        }
3004
    }
3005
#    DebugDumpData("SvnData", \%svnData);
3006
 
3007
    foreach my $entry ( keys(%versions) )
3008
    {
3009
        my $import_label = saneLabel($entry);
3010
        delete $versions{$entry}{svnVersion};
3011
        delete $versions{$entry}{svnBranchTip};
3012
 
3013
        if ( exists $svnData{tags}{$import_label} )
3014
        {
3015
            $versions{$entry}{svnVersion} = 1;
3016
        }
3017
 
3018
        if ( exists $svnData{tips}{$import_label} )
3019
        {
3020
            $versions{$entry}{svnBranchTip} = $svnData{tips}{$import_label};
3021
        }
3022
    }
3023
 
3024
    Message ( 'Trunk used: ' . (exists $svnData{branches}{trunk} ? 'Yes' : 'No') );
3025
    Message ( 'Labels    : ' . scalar keys %{$svnData{tags}} );
3026
    Message ( 'Branches  : ' . scalar keys %{$svnData{branches}} );
3027
}
3028
 
3029
#-------------------------------------------------------------------------------
3030
# Function        : ProcessSvnLog
3031
#
3032
# Description     :
3033
#                   Parse
3034
#                       <logentry
3035
#                          revision="24272">
3036
#                       <author>bivey</author>
3037
#                       <date>2005-07-25T15:45:35.000000Z</date>
3038
#                       <paths>
3039
#                       <path
3040
#                          prop-mods="false"
3041
#                          text-mods="false"
3042
#                          kind="dir"
3043
#                          copyfrom-path="/enqdef/branches/Stockholm"
3044
#                          copyfrom-rev="24271"
3045
#                          action="A">/enqdef/tags/enqdef_24.0.1.sls</path>
3046
#                       </paths>
3047
#                       <msg>COTS/enqdef: Tagged by Jats Svn Import</msg>
3048
#                       </logentry>
3049
#
3050
# Inputs          : 
3051
#
3052
# Returns         : 
3053
#
3054
my $entryData;
3055
sub  ProcessSvnLog
3056
{
3057
    my ($self, $line ) = @_;
3058
#print "----- $line\n";
3059
    if ( $line =~ m~^<logentry~ ) {
3060
        $entryData = ();
3061
 
3062
    } elsif ( $line =~ m~^\s+revision="(\d+)"~ ) {
3063
        $entryData->{Rev} = $1;
3064
 
3065
    } elsif ( $line =~ m~^\s+copyfrom-path="(.*)"~ ) {
3066
        $entryData->{fromPath} = $1;
3067
 
3068
    } elsif ( $line =~ m~^\s+copyfrom-rev="(\d+)"~ ) {
3069
        $entryData->{fromRev} = $1;
3070
 
3071
    } elsif ( $line =~ m~\s+action=.*?>(.*)</path~ ) {
3072
        $entryData->{target} = $1;
3073
 
3074
    } elsif ( $line =~ m~</logentry~ ) {
3075
        if ( exists $entryData->{fromPath} )
3076
        {
3077
#            DebugDumpData("Data", $entryData);
3078
            push @svnDataItems, $entryData;
3079
        }
3080
    }
3081
 
3082
    #
3083
    #   Return 0 to keep on going
3084
    return 0;
3085
}
3086
 
3087
 
3088
 
3089
#-------------------------------------------------------------------------------
3090
# Function        : saveData
3091
#
3092
# Description     : Save essential data
3093
#
3094
# Inputs          : 
3095
#
3096
# Returns         : 
3097
#
3098
sub saveData
3099
{
3100
    my $file = $cwd . "/${packageNames}.data";
3101
 
3102
    Message ("Create: $file");
3103
    my $fh = ConfigurationFile::New( $file );
3104
 
3105
    $fh->DumpData(
3106
        "\n# ScmVersions.\n#\n",
3107
        "ScmVersions", \%versions );
3108
 
3109
    #
3110
    #   Close out the file
3111
    #
3112
    $fh->Close();
3113
}
3114
 
3115
 
3116
#-------------------------------------------------------------------------------
3117
#   Documentation
3118
#
3119
 
3120
=pod
3121
 
3122
=for htmltoc    SYSUTIL::cc2svn::
3123
 
3124
=head1 NAME
3125
 
3126
cc2svn_gendata - CC2SVN tool to import an entire package into SVN
3127
 
3128
=head1 SYNOPSIS
3129
 
3130
  jats cc2svn_importpackage [options] package_name
3131
 
3132
 Options:
3133
    -help              - brief help message
3134
    -help -help        - Detailed help message
3135
    -man               - Full documentation
3136
    -repository=name   - Specify target repository
3137
    -[no]flat          - Do not create project tree. Def: -noflat
3138
    -prunemode=mode    - Mode: none, ripple, retain, severe, Def=ripple
3139
    -retain=N          - Specify retain count for pruning. Def=2
3140
    -[no]test          - Do not create packages. Def:-notest
3141
    -[no]reuse         - Keep and reuse ClearCase views
3142
    -age=nnDays        - Only keep recent package
3143
    -dump[=n]          - Dump raw data. N=0,1,2
3144
    -images[=n]        - Create SVG of version tree. N=0,1,2
3145
    -name=aaa          - Alternate output package name. Test Only
3146
    -[no]log           - Write output to log file. Def: -nolog
3147
    -[no]postimage     - Create image after transger: Def: -post
3148
    -workdir=path      - Use for temp storage (def:/work)
3149
 
3150
=head1 OPTIONS
3151
 
3152
=over 8
3153
 
3154
=item B<-help>
3155
 
3156
Print a brief help message and exits.
3157
 
3158
=item B<-help -help>
3159
 
3160
Print a detailed help message with an explanation for each option.
3161
 
3162
=item B<-man>
3163
 
3164
Prints the manual page and exits.
3165
 
3166
=item B<-prunemode=mode>
3167
 
3168
This option control the manner in which excess versions will be pruned. Valid
3169
modes are:
3170
 
3171
=over 8
3172
 
3173
=item   none
3174
 
3175
No pruning will be performed
3176
 
3177
=item   ripple
3178
 
3179
Non-Essential packages that are ripple builds will be removed.
3180
 
3181
=item   retain
3182
 
3183
Versions that preceed an Essential version will be retained.
3184
 
3185
=item   severe
3186
 
3187
Only Essential Versions, and Branching points will be retained.
3188
 
3189
=back
3190
 
3191
=back
3192
 
3193
=head1 DESCRIPTION
3194
 
3195
This program is a tool used in the conversion of ClearCase VOBS to subversion.
3196
It will take a complete package and all relevent versions from ClearCase and
3197
insert them into subversion in a sessible manner. It will attempt to retain
3198
file change order and history.
3199
 
3200
It will:
3201
 
3202
=over 8
3203
 
3204
=item *
3205
 
3206
Read in the Essential Package Version list.
3207
 
3208
=item *
3209
 
3210
Extract, from Release Manager, all known versions of the specified package.
3211
 
3212
=item *
3213
 
3214
It will attempt to determine the type of package: COTS, TOOL, CORE, PROJECT
3215
and alter the processing accordingly.
3216
 
3217
=item *
3218
 
3219
It will create a version dependency tree and determine 'new' project branch
3220
points. It will remove (prune) versions that are excess to requirements.
3221
 
3222
=item *
3223
 
3224
It will extract source from ClearCase and insert it into SVN, creating
3225
branches and tags as it goes.
3226
 
3227
=back
3228
 
3229
The program can also be used to create a SVG image of the version dependency
3230
tree. This does not work on Linux; only Windows with 'dot' installed.
3231
 
3232
=cut
3233