Subversion Repositories DevTools

Rev

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

Rev Author Line No. Line
5209 dpurdie 1
########################################################################
2
# Copyright (c) VIX TECHNOLOGY (AUST) LTD
3
#
4
# Module name   : jats_lxr.pl
5
# Module type   : JATS Utility
6
# Compiler(s)   : Perl
7
# Environment(s): jats
8
#
9
# Description   : Tiools to maintain LXR information
10
#
11
# Usage         : See POD at the end of this file
12
#
13
#......................................................................#
14
 
15
require 5.008_002;
16
use strict;
17
use warnings;
18
 
19
use Pod::Usage;
20
use Getopt::Long;
21
use File::Path;
22
use FindBin;
23
use Socket;
24
 
25
use JatsError;
26
use JatsRmApi;
27
use DBI;
28
use JatsSystem;
29
use FileUtils;
30
 
31
#
32
#   Config Options
33
#
34
my $VERSION = "1.0.0";                      # Update this
35
my $opt_help = 0;
36
my $opt_verbose = $ENV{'GBE_VERBOSE'};      # Allow global verbose
37
my $opt_createVersions = 1;
38
my $opt_index = 1;
39
my $opt_purge = 1;
40
my $opt_extract = 1;
41
my $opt_logfile = 1;
5211 dpurdie 42
my $opt_config;
5209 dpurdie 43
 
44
 
45
#
46
#   Globals
47
#
48
my $scriptDir;
49
my $RM_DB;
50
our $config;
51
my @addressList;
52
my %ReleaseData;
53
my %Packages;
54
my $PackageStore;
55
my $ReleaseStore;
56
my $stamptime = time;
57
 
58
#-------------------------------------------------------------------------------
59
# Function        : Main
60
#
61
# Description     : Main entry point
62
#                   Parse user options
63
#
64
# Inputs          :
65
#
66
# Returns         :
67
#
68
 
69
my $result = GetOptions (
70
                "help:+"            => \$opt_help,              # flag, multiple use allowed
71
                "manual:3"          => \$opt_help,              # flag, multiple use allowed
72
                "verbose:+"         => \$opt_verbose,           # flag
73
                "createVersions!"   => \$opt_createVersions,
74
                "purge!"            => \$opt_purge,
75
                "index!"            => \$opt_index,
76
                "extract!"          => \$opt_extract,
5211 dpurdie 77
                "logfile!"          => \$opt_logfile,
78
                "config:s"          => \$opt_config,
5209 dpurdie 79
                );
80
 
81
#
82
#   Process help and manual options
83
#
84
pod2usage(-verbose => 0, -message => "Version: $VERSION")  if ($opt_help == 1  || ! $result);
85
pod2usage(-verbose => 1)  if ($opt_help == 2 );
86
pod2usage(-verbose => 2)  if ($opt_help > 2);
87
 
88
#
89
#   Capture all logging to a file
90
#   Could be done by the jats wrapper, but this way we can control its location
91
#
92
ErrorConfig( 'name'    => 'LXR',
93
             'verbose' => $opt_verbose );
94
 
95
#
96
#   Sanity test
97
#
98
 
99
$scriptDir = $FindBin::Bin;
100
InitFileUtils();
101
 
102
#
103
#   Read the tool configuration
104
#
105
readConfig();
106
Error ("No LXR Data directory defined", $config->{lxrFiles}) unless( exists $config->{lxrFiles});
107
Error ("No LXR Data directory found", $config->{lxrFiles}) unless( -d $config->{lxrFiles});
108
Error ("No LXR Install directory defined",$config->{lxr}) unless( exists $config->{lxr});
109
Error ("No LXR Install directory found",$config->{lxr}) unless( -d $config->{lxr});
110
 
111
#
112
#   Start logging
113
#
114
startLogFile();
115
Message ("Start of LXR. " . localtime(time) ) if $opt_logfile;
116
Message("ScriptDir: $scriptDir");
117
 
118
#
119
#   Check required paths exist
120
#
121
$PackageStore = catdir($config->{lxrFiles}, 'Packages');
122
$ReleaseStore = catdir($config->{lxrFiles}, 'Releases');
123
mkpath($PackageStore);
124
mkpath($ReleaseStore);
125
Error ("Package Store not found ",$PackageStore) unless( -d $PackageStore);
126
Error ("Release Store not found ",$ReleaseStore) unless( -d $ReleaseStore);
127
 
128
#
5211 dpurdie 129
#   Default config
130
#
131
$config->{'releaseAge'} = 0 unless exists $config->{'releaseAge'};
132
$config->{'packageAge'} = 0 unless exists $config->{'packageAge'};
133
 
134
#
5209 dpurdie 135
#   Determine the various names for this machine
136
#   Include all the IP addresses too
137
#
138
my ($canonname, $aliases, $addrtype, $length, @addrs) = gethostbyname($ENV{GBE_HOSTNAME});
139
push @addressList, $canonname ;
140
push (@addressList, $aliases) if ($aliases) ;
141
push (@addressList, $ENV{GBE_HOSTNAME});
142
foreach ( @addrs) {
143
    push @addressList, inet_ntoa($_); 
144
}
145
Message("IpAddress: @addressList");
146
 
147
#
148
#   Perform the hard work
149
#
150
getReleaseData();
5212 dpurdie 151
extractPackages();
5209 dpurdie 152
createReleaseViews() if $opt_createVersions;
153
cleanReleaseViews();
154
rebuildLxrConfig();
155
buildIndexes() if $opt_index;
156
cleanPackageStore() if $opt_purge;
157
cleanupLogFiles() if $opt_purge;
158
 
159
#
160
#   All done
161
#
162
Message ("End of LXR. " . localtime(time) ) if $opt_logfile;
163
exit 0;
164
 
165
#-------------------------------------------------------------------------------
5212 dpurdie 166
# Function        : extractPackages 
5209 dpurdie 167
#
5212 dpurdie 168
# Description     : Extract Packages from VCS
5209 dpurdie 169
#                   Don't extract them if they already exist
5212 dpurdie 170
#   
171
#                   Kludge: Prevent extraction from MASS_Dev_Crypto Repo
5209 dpurdie 172
#
173
# Inputs          : 
174
#
175
# Returns         : 
176
#
5212 dpurdie 177
sub extractPackages
5209 dpurdie 178
{
179
    foreach my $pvid ( keys{%Packages})
180
    {
181
        my $entry = $Packages{$pvid};
182
        #DebugDumpData("Entry", \$entry);
183
        my $fullName = join('_', $entry->{name}, $entry->{ver});
184
        my $fullPath = catfile($PackageStore , $fullName);
185
        next unless defined $entry->{vcs};
186
        next if ( $entry->{vcs} ) =~ m~^UC::~;
5211 dpurdie 187
        unless (-d $fullPath ) 
188
        {
5209 dpurdie 189
            Message("Need to extract: $entry->{name}, $entry->{ver}");
190
            if ($opt_extract)
191
            {
192
                Verbose0("Extracting into: $fullPath");
5212 dpurdie 193
                if ($entry->{vcs} =~ m~/MASS_Dev_Crypto/~)
5211 dpurdie 194
                {
195
                    print "$fullName : SUPPRESSED\n";
196
                }
197
                else
198
                {
199
                    my $rv = JatsCmd ('jats_vcsrelease', '-devmode=escrow', '-extractfiles', "-view=$fullName", "-label=$entry->{vcs}", "-root=$PackageStore", "-noprefix");
200
                    print "$fullName : SUCCESS\n" unless $rv;
201
                    print "$fullName : ERROR\n" if $rv;
202
                    $entry->{bad} = 1;
203
                }
5209 dpurdie 204
            }
205
        }
5211 dpurdie 206
        else
207
        {
208
            #   Package already extracted
209
            #   Ensure that it does not get aged out
210
            deleteAgeMarker($fullPath);
211
        }
5209 dpurdie 212
    }
213
}
214
 
215
#-------------------------------------------------------------------------------
216
# Function        : createReleaseViews 
217
#
218
# Description     : Create a new view for each Release
219
#                   Each view is basically a bunch of symlinks
220
#
221
# Inputs          : 
222
#
223
# Returns         : 
224
#
225
sub createReleaseViews
226
{
5212 dpurdie 227
    my $latestView;
228
    my $needNewView;
229
 
5209 dpurdie 230
    #
231
    #   Create a name for the releases - based on a date-time
232
    #   Will be unqiue(ish)
233
    #
234
    my $dateTag = localtime($stamptime);
235
 
236
    foreach my $rtagid (keys \%ReleaseData)
237
    {
5212 dpurdie 238
        $latestView = undef;
239
        $needNewView = 0;
240
 
5209 dpurdie 241
        my $entry = $ReleaseData{$rtagid};
5212 dpurdie 242
        if ($entry->{data} )
243
        {
244
            $latestView = getLatestVersion(catdir($ReleaseStore, $rtagid));
245
            $needNewView = 1;
246
        }
5209 dpurdie 247
 
248
        #
249
        #   Check to see if we really need to create a new view
5212 dpurdie 250
        #   If the LATEST view contains all the package-versions that we need then
5209 dpurdie 251
        #   don't create a new one.
252
        #
253
        #   Scan each entry within the Last View
254
        #
255
        if ($latestView)
256
        {
257
            my %pkgsUsed;
258
            opendir (my $ldir, $latestView) || Warning ("Cannot open directory: $latestView", $!);
259
            while (my $ldirEntry = readdir($ldir))
260
            {
261
                #   Skip hidden files
262
                next if ($ldirEntry =~ m~^\.~);
263
                my $dirName = catdir($latestView, $ldirEntry );
264
 
265
                #
266
                #   Process each entry within the Version
267
                #
268
                my $pkgName = $ldirEntry;
269
                if (-l $dirName)
270
                {
271
                    $pkgName = readlink($dirName);
272
                    $pkgName =~ s~.*/~~;
273
                }
274
                $pkgsUsed{$pkgName} = 2;
275
            }
276
            close ($ldir);
277
 
278
            #
279
            #   Compare Package-Versions against those we need
280
            # 
281
            foreach my $pvid (keys $entry->{data})
282
            {
283
                my $entry = $Packages{$pvid};
284
                my $fullName = join('_', $entry->{name}, $entry->{ver});
285
                $pkgsUsed{$fullName}++;
286
            }
287
 
288
            #
289
            #   Scan the pkgUsed
290
            #   A value of 1 indicates that it is used only in the New Version
291
            #   A value of 2 indicates that it is only used on the Last Version
292
            #   A value of 3 indicates that its used in both
293
            #   Detect those that are not a 3
294
            #
295
            $needNewView = 0;
296
            foreach ( keys %pkgsUsed)
297
            {
298
                if ($pkgsUsed{$_} != 3)
299
                {
300
                    $needNewView = 1;
301
                    last;
302
                }
303
            }
304
            #DebugDumpData("pkgsUsed",\%pkgsUsed);
305
        }
306
 
307
        unless ($needNewView)
308
        {
309
            Message("No Changes to LXR View: $rtagid");
310
        }
311
        else
312
        {
313
            Message("Creating LXR View: $rtagid, $dateTag");
314
            my $releaseDir = catdir($ReleaseStore, $rtagid, $dateTag);
315
            mkpath($releaseDir);
316
            if (-d $releaseDir)
317
            {
318
                foreach my $pvid (keys $entry->{data})
319
                {
320
                    my $entry = $Packages{$pvid};
321
                    my $alias = join('', $entry->{name}, $entry->{ext});
322
                    my $fullName = join('_', $entry->{name}, $entry->{ver});
323
                    my $PackageStore = catdir($PackageStore , $fullName);
324
                    my $releaseDir = catdir($releaseDir, $alias );
325
                    next if -l $releaseDir;
326
 
327
                    Verbose("Symlink $PackageStore, $releaseDir");
328
                    my $rv = symlink ($PackageStore, $releaseDir);
329
                    unless ($rv)
330
                    {
331
                        Warning("Could not link $PackageStore, $releaseDir")
332
                    }
333
                }
334
            }
335
        }
336
    }
337
}
338
 
339
#-------------------------------------------------------------------------------
340
# Function        : rebuildLxrConfig 
341
#
342
# Description     : Rebuild the LXR Configuration file
343
#                   This MAY be a bit LXR version specific, but since LXR doesn't
344
#                   provide a scriptable way to update configuration
345
#
346
#                   Uses template files that have been handcrafted after taken from
5211 dpurdie 347
#                   LXR. Basically we to a text replace and a glue together
5209 dpurdie 348
#
349
#                   For each release we need
350
#                       Long Release Name
351
#                       Short Release Name
352
#                       List of Versions
353
#
354
#
355
# Inputs          : Assumes Data has been added to %ReleaseData by other subroutines
356
#
357
# Returns         : 
358
#
359
sub rebuildLxrConfig
360
{
361
    my @lxrTreeText;
5211 dpurdie 362
 
5209 dpurdie 363
    #
5211 dpurdie 364
    #   Sort Sub
365
    #   Sort ReleaseData by Project and Name
366
    #   $a and $b are special to the sort
367
    #
368
    sub ReleaseDataSort
369
    {
370
        my $rv = lc($ReleaseData{$a}{release}{Project}) cmp lc($ReleaseData{$b}{release}{Project});
371
        if ($rv == 0)
372
        {
373
            $rv = lc($ReleaseData{$a}{release}{Name}) cmp lc($ReleaseData{$b}{release}{Name});
374
        }
375
        return $rv;
376
    }
377
 
378
    #
5209 dpurdie 379
    #   Process configured releases
5212 dpurdie 380
    #   Generate in the order we wish to display the Releases
5209 dpurdie 381
    #
382
    #DebugDumpData("ReleaseData", \%ReleaseData);
5211 dpurdie 383
    foreach my $rtagid ( sort ReleaseDataSort keys %ReleaseData )
5209 dpurdie 384
    {
385
        my $entry = $ReleaseData{$rtagid};
5211 dpurdie 386
        Information("Entry: $entry->{release}{Project}, $entry->{release}{Name}, $rtagid");
5209 dpurdie 387
        $entry->{release}{VersionsString} = join( ',', map { '"' . $_ .'"'} @{$entry->{Versions}} );
388
        $entry->{release}{dbName} = genDatabaseName($rtagid);
389
        #DebugDumpData("ENTRY", \$entry);
390
 
391
        my $tfileName = 'lxr.tree.template';
392
        open( my $tf, '<', $tfileName) || Error ("Cannot open $tfileName. $!");
393
        while (my $line = <$tf>)
394
        {
395
            # Chomp trailing write space
396
            $line =~ s~\s+$~~;
397
 
398
            #   Replace known bits in the template
399
            $line =~ s~\@CAPTION\@~$entry->{release}{Project}::$entry->{release}{Name}~g;
400
            $line =~ s~\@SHORT_NAME\@~$rtagid~g;
401
            $line =~ s~\@RELEASE_ROOT\@~$entry->{release}{root}~g;
402
            $line =~ s~\@VERSIONS_LIST\@~$entry->{release}{VersionsString}~g;
403
            $line =~ s~\@DBNAME\@~$entry->{release}{dbName}~g;
404
            push @lxrTreeText, $line
405
        }
406
        close $tf;
407
    }
408
 
409
    #
410
    #   Insert tree sections into the main config file template
411
    #
412
    my $hostList = join( ',', map { '\'http://' . $_ .'\''} @addressList );
413
 
414
    my $tfileName = catfile($scriptDir, 'lxr.template');
415
    my $lxrFileName = catfile($config->{lxr}, 'lxr.new.conf');
416
    unlink $lxrFileName;
417
    open( my $tf, '<', $tfileName) || Error ("Cannot open $tfileName. $!");
418
    open( my $to, '>', $lxrFileName) || Error ("Cannot open $lxrFileName. $!");
419
    while (my $line = <$tf>)
420
    {
421
        # Chomp trailing write space
422
        $line =~ s~\s+$~~;
423
 
424
        #   Replace known bits in the template
425
        if ($line =~ m~\@TREE_SECTIONS\@~)
426
        {
427
            foreach (@lxrTreeText)
428
            {
429
                print $to $_, "\n";
430
            }
431
        }
432
        else
433
        {
434
            $line =~ s~\@HOSTLIST\@~$hostList~g;
435
            print $to $line, "\n";
436
        }
437
    }
438
    close $tf;
439
    close $to;
440
 
441
    #
442
    #   Install the new config files
443
    #
444
    my $lxrLive = catfile($config->{lxr}, 'lxr.conf');
445
    my $lxrBackup = catfile($config->{lxr}, 'lxr.conf.bak');
446
    unlink $lxrBackup;
447
    rename ($lxrLive, $lxrBackup) || Warning("Renaming $lxrLive, $lxrBackup", $!);
448
    rename ($lxrFileName, $lxrLive) || Warning("Renaming $lxrFileName, $lxrLive", $!);
449
 
450
    #
451
    #   Create new database tables if required
452
    #   Use a customized shell script to do the hard work
453
    #
454
    foreach my $rtagid ( keys %ReleaseData )
455
    {
456
        my $entry = $ReleaseData{$rtagid};
457
        Information("Database:$entry->{release}{Name}, $entry->{release}{dbName} ");
458
        System('--NoExit', '--NoShell', catfile($scriptDir, 'lxr.initdb.sh'), $entry->{release}{dbName});
459
    }
460
}
461
 
462
#-------------------------------------------------------------------------------
463
# Function        : buildIndexes 
464
#
465
# Description     : Build (Generate) indexes for all versions of all releases
466
#                   that don't have an index
467
#                   
468
#                   Place a marker file in the 'version' directory when the
469
#                   index has been created
470
#
471
#                   Notes:
472
#                   The 'genxref' program needs to be run from the lxr insatll directory
473
#                   chdir to that directory for each invocation
474
#
475
#                   genxref uses DBI - and must find the proper PERL DBI and not the one
476
#                   within JATS.. Solution:
477
#                       Kill the PERL5LIB EnvVar
478
#
479
#
480
#
481
# Inputs          : 
482
#
483
# Returns         : 
484
#
485
sub buildIndexes
486
{
487
    #
488
    #   Prep envonment for calling genxref
489
    #   See notes above
490
    #
491
    chdir ($config->{lxr}) || Error ("Cannot chnage directory:$config->{lxr}, $!");
492
    delete $ENV{PERL5LIB};
493
 
494
    #
495
    #   Examine each Version in each Release
496
    #   Generate command line like:
497
    #   genxref --tree RTAGID --url http://HOSTNAME/lxr --version 'VERSION'
498
    foreach my $rtagid ( keys %ReleaseData )
499
    {
500
        my $entry = $ReleaseData{$rtagid};
501
        foreach my $version (@{$entry->{Versions}})
502
        {
503
            my $markerFile = catfile($entry->{release}{root}, $version, '.lxrIndexed');
504
            unless (-f $markerFile) {
505
                Message("Must index: $rtagid, $version");
506
                my $rv = System('--NoExit', 
507
                       '--NoShell', 
508
                       catfile($config->{lxr}, 'genxref'),
509
                       '--url', 'http://' . $ENV{GBE_HOSTNAME} . '/lxr',
510
                       '--tree', $rtagid,
511
                       '--version', $version
512
                       );
513
               Verbose("genxref exit: $rv");
514
               unless ($rv) {
515
                   TouchFile($markerFile);
516
               }
517
            }
518
            else
519
            {
520
                Verbose("Already indexed: $rtagid, $version");
521
            }
522
        }
523
    }
524
    #
525
    #   Restore current directory
526
    #
527
    chdir($FileUtils::CwdFull);
528
}
529
 
530
 
531
#-------------------------------------------------------------------------------
532
# Function        : cleanReleaseViews 
533
#
534
# Description     : Clean up unused Releases and Release Views
535
#                   Maintain the list of retained versions
536
#
537
#                   Two classes
538
#                   Active - Marked as having LXR support
539
#                       Retain the last 5 Versions
540
#
541
#                  InActive - Not having LXR support
542
#                       Retain for 10 days then delete all versions
543
#
544
# Inputs          : 
545
#
546
# Returns         : 
547
#
548
sub cleanReleaseViews
549
{
550
    #
551
    #   Scan Releases and delete all that are not currently configured
552
    #
553
    opendir (my $rdir, $ReleaseStore) || Error ("Cannot open directory: $ReleaseStore", $!);
554
    while (my $rdirEntry = readdir($rdir))
555
    {
556
        #   Skip hidden files and directories
557
        next if ($rdirEntry =~ m~^\.~);
558
        my $vdirName = catdir($ReleaseStore, $rdirEntry );
559
        next unless ( -d $vdirName );
5212 dpurdie 560
        unless(exists $ReleaseData{$rdirEntry} && $ReleaseData{$rdirEntry}{release}{ACTIVE} )
5209 dpurdie 561
        {
5211 dpurdie 562
            #   Release is no longer configured - age it out
5209 dpurdie 563
            #   Assume $rdirEntry is an rtag_id
5211 dpurdie 564
            if (processAgeMarker($vdirName, $config->{'releaseAge'} ))
565
            {
566
                Message("Delete Release: $rdirEntry");
567
                RmDirTree($vdirName);
568
                System('--NoExit', '--NoShell', catfile($scriptDir, 'lxr.dropdb.sh'), genDatabaseName($rdirEntry));
569
            }
5209 dpurdie 570
        }
571
        else
572
        {
5211 dpurdie 573
            deleteAgeMarker($vdirName);
5209 dpurdie 574
 
575
            #   Release is configured
576
            #   Keep the last x created
577
            #   Note: Create time is a kludge
578
            #
579
            #   Process each version within the Release
580
            #
581
            my @versionData;
582
            opendir (my $vdir, $vdirName) || Warning ("Cannot open directory: $vdirName", $!);
583
            while (my $vdirEntry = readdir($vdir))
584
            {
585
                #   Skip hidden files and directories
586
                next if ($vdirEntry =~ m~^\.~);
587
                my $ldirName = catdir($vdirName, $vdirEntry );
588
                next unless ( -d $ldirName );
589
                my $data;
590
                $data->{name} = $vdirEntry; 
591
                $data->{path} = $ldirName; 
592
                $data->{ctime} = (stat $ldirName)[9];
593
                push @versionData  , $data;
594
            }
595
            close ($vdir);
596
            #DebugDumpData("versionData",\@versionData);
597
 
598
            my $keepCount = 0;
599
            foreach my $entry ( sort { $b->{ctime} <=> $a->{ctime}} @versionData )
600
            {
601
                #DebugDumpData("Entry", $entry);
602
                $keepCount++;
603
                if ($keepCount > 5)
604
                {
605
                    #   Version is no longer needed - remove it
606
                    Message("Delete Version: $rdirEntry, $entry->{name}, $entry->{ctime}");
607
                    RmDirTree($entry->{path});
608
                }
609
                else
610
                {
611
                    #   Note which versions we have
612
                    push @{$ReleaseData{$rdirEntry}{Versions}}, $entry->{name};
613
                }
614
            }
615
        }
616
    }
617
    close ($rdir);
618
}
619
 
620
#-------------------------------------------------------------------------------
621
# Function        : getLatestVersion 
622
#
623
# Description     : For a specified directory return the newest subdir
624
#
625
#                   Used to determine the most recent version
626
#
5212 dpurdie 627
# Inputs          : $vdirName - Dir to process - expecting a Release directory
5209 dpurdie 628
#
629
# Returns         : 
630
#
631
sub getLatestVersion
632
{
633
    my  ($vdirName) = @_;
634
    my $latestName;
635
    my $latestAge = 0;
636
 
637
    opendir (my $vdir, $vdirName) || Warning ("Cannot open directory: $vdirName", $!);
638
    while (my $vdirEntry = readdir($vdir))
639
    {
640
        #   Skip hidden files and directories
641
        next if ($vdirEntry =~ m~^\.~);
642
 
643
        my $ldirName = catdir($vdirName, $vdirEntry );
644
        next unless ( -d $ldirName );
645
 
646
        my $age = (stat $ldirName)[9];
647
        Verbose3("Age: $ldirName, $age");
648
 
649
        if  ($age > $latestAge )
650
        {
651
            $latestAge = $age;
652
            $latestName = $ldirName;
653
        }
654
    }
655
    close ($vdir);
656
 
657
    Verbose("Latest: $latestName, $latestAge");
658
    #DebugDumpData("versionDataSorted",\@versionDataSorted);
659
    return $latestName;
660
}
661
 
662
 
663
#-------------------------------------------------------------------------------
664
# Function        : cleanPackageStore 
665
#
666
# Description     : Delete unused PAckages fromthe package store
667
#
668
# Inputs          : 
669
#
670
# Returns         : 
671
#
672
sub cleanPackageStore
673
{
674
    my %pkgsUsed;
675
    #
676
    #   Examime ALL versions in ALL Releases and build up a hash of
677
    #   Package Versions used
678
    #
679
    opendir (my $rdir, $ReleaseStore) || Error ("Cannot open directory: $ReleaseStore", $!);
680
    while (my $rdirEntry = readdir($rdir))
681
    {
682
        #   Skip hidden files and directories
683
        next if ($rdirEntry =~ m~^\.~);
684
        my $vdirName = catdir($ReleaseStore, $rdirEntry );
685
        next unless ( -d $vdirName );
686
 
687
        #
688
        #   Process each version within the Release
689
        #
690
        opendir (my $vdir, $vdirName) || Warning ("Cannot open directory: $vdirName", $!);
691
        while (my $vdirEntry = readdir($vdir))
692
        {
693
            #   Skip hidden files and directories
694
            next if ($vdirEntry =~ m~^\.~);
695
            my $ldirName = catdir($vdirName, $vdirEntry );
696
            next unless ( -d $ldirName );
697
 
698
            #
699
            #   Process each entry within the Version
700
            #
701
            opendir (my $ldir, $ldirName) || Warning ("Cannot open directory: $ldirName", $!);
702
            while (my $ldirEntry = readdir($ldir))
703
            {
704
                #   Skip hidden files and directories (also borken symlinks )
705
                next if ($ldirEntry =~ m~^\.~);
706
                my $dirName = catdir($ldirName, $ldirEntry );
707
                next unless ( -d $dirName );
708
 
709
                #
710
                #   Process each entry within the Version
711
                #
712
                my $pkgName = $ldirEntry;
713
                if (-l $dirName)
714
                {
715
                    $pkgName = readlink($dirName);
716
                    $pkgName =~ s~.*/~~;
717
                }
718
                $pkgsUsed{$pkgName}++;
719
            }
720
            close ($ldir);
721
        }
722
        close ($vdir);
723
    }
724
    close ($rdir);
725
 
726
    #
727
    #   Process the Packages directory and remove those not currently used
728
    #
729
    #
730
    #   Process each entry within the Version
731
    #
732
    opendir (my $pdir, $PackageStore) || Error ("Cannot open directory: $PackageStore", $!);
733
    while (my $pdirEntry = readdir($pdir))
734
    {
735
        #   Skip hidden files and directories
736
        next if ($pdirEntry =~ m~^\.~);
737
        my $pdirName = catdir($PackageStore, $pdirEntry );
738
        next unless ( -d $pdirName );
739
        next if (exists $pkgsUsed{$pdirEntry} );
740
 
5211 dpurdie 741
        if (processAgeMarker($pdirName, $config->{packageAge})) 
742
        {
743
            Message("Purge Package: $pdirEntry");
744
            RmDirTree($pdirName);
745
        }
5209 dpurdie 746
    }
747
    close ($pdir);
748
 
749
    #DebugDumpData("pkgsUsed", \%pkgsUsed);
750
}
751
 
752
 
753
#-------------------------------------------------------------------------------
754
# Function        : getReleaseData 
755
#
756
# Description     : Get all the required Release Data 
757
#
758
# Inputs          :  
759
#
760
# Returns         : 
761
#
762
sub getReleaseData
763
{
764
    my ($rtagid) = @_;
765
    my (@row);
5212 dpurdie 766
    my @releaseList;
767
    my $partSql = '';
5209 dpurdie 768
 
769
    Information("getReleaseData");
770
    connectRM(\$RM_DB) unless $RM_DB;
771
 
5212 dpurdie 772
    #
773
    #   Determine list of existing Releases
774
    #   Build up a Clause for the extraction SQL
775
    #   This is used to get data for Releases that exist in the Store but may have been
776
    #   deconfigured.
777
    #
778
    if ( opendir (my $rdir, $ReleaseStore) )
779
    {
780
        while (my $rdirEntry = readdir($rdir))
781
        {
782
            #   Skip hidden files and directories
783
            next if ($rdirEntry =~ m~^\.~);
784
            my $vdirName = catdir($ReleaseStore, $rdirEntry );
785
            next unless ( -d $vdirName );
786
            push @releaseList, $rdirEntry;
787
        }
788
        close $rdir;
789
    }
5209 dpurdie 790
 
5212 dpurdie 791
    if (@releaseList)
792
    {
793
        $partSql = ' OR rt.rtag_id in (' . join(',', @releaseList ) . ')' 
794
    }
795
 
796
 
5209 dpurdie 797
    #
798
    # Determine which Releases need LXR support
799
    #
800
    my $m_sqlstr = 
801
        "SELECT rtag_id, " .
802
        "  rt.proj_id, " .
803
        "  p.PROJ_NAME, " .
804
        "  rtag_name, " .
805
        "  official, " .
5212 dpurdie 806
        "  NVL(TRUNC (SYSDATE - rt.official_stamp),0) AS OFFICIAL_STAMP_DAYS, " .
807
        "  rt.lxr " .
5209 dpurdie 808
        "FROM release_tags rt, " .
809
        "  projects p " .
5212 dpurdie 810
        "WHERE ( rt.lxr  = 'Y'" . $partSql . ")" .
811
        " AND p.PROJ_ID = rt.proj_id ";
5209 dpurdie 812
 
813
    my $sth = $RM_DB->prepare($m_sqlstr);
814
    if ( defined($sth) )
815
    {
816
        if ( $sth->execute( ) )
817
        {
818
            if ( $sth->rows )
819
            {
820
                while ( @row = $sth->fetchrow_array )
821
                {
822
                    my $rtagid = $row[0];
823
                    my $data;
824
                    $data->{Project} = $row[2];
825
                    $data->{Name} = $row[3];
826
                    $data->{official} = substr($row[4],0,1);
827
                    $data->{official_stamp_days} = $row[5];
5212 dpurdie 828
                    $data->{lxr} = $row[6];
5209 dpurdie 829
 
830
                    #
831
                    #   Determine if this request for an LXR release is OK
832
                    #   Ok If the release is Open, CCB or Restricted
5212 dpurdie 833
                    #   Ok If closed and has been closed to < 10 days
5209 dpurdie 834
                    #
5212 dpurdie 835
                    if ($data->{lxr} eq 'Y')
5209 dpurdie 836
                    {
5212 dpurdie 837
                        if (index('NRC', $data->{official}) >= 0)
838
                        {
839
                            $data->{ACTIVE} = 1;
840
                        }
841
                        elsif ($data->{official} eq 'Y' && $data->{official_stamp_days} < 10 )
842
                        {
843
                            $data->{ACTIVE} = 2;
844
                        }
5209 dpurdie 845
                    }
846
 
5212 dpurdie 847
                    $data->{root} = catdir($ReleaseStore, $rtagid );
5209 dpurdie 848
                    $ReleaseData{$rtagid}{release} = $data;
849
                }
850
            }
851
            $sth->finish();
852
        }
853
    }
854
    else
855
    {
856
        Error("getReleaseData:Prepare failure" );
857
    }
858
 
5212 dpurdie 859
 
5209 dpurdie 860
    DebugDumpData("ReleaseData", \%ReleaseData);
861
    foreach my $rtagid ( keys %ReleaseData)
862
    {
5212 dpurdie 863
        next unless $ReleaseData{$rtagid}{release}{ACTIVE};
864
        Information("Active Release: RtagId $rtagid");
5209 dpurdie 865
        getOneRelease($rtagid);
866
    }
867
}
868
 
869
#-------------------------------------------------------------------------------
870
# Function        : getOneRelease
871
#
5212 dpurdie 872
# Description     : Get PackgeVersion information for one Release
5209 dpurdie 873
#
874
# Inputs          : rtagid
875
#
876
# Returns         : 
877
#
878
sub getOneRelease
879
{
880
    my ($rtagid) = @_;
881
    my (@row);
882
 
883
    connectRM(\$RM_DB) unless $RM_DB;
884
 
885
 
886
    # Get details for each package in the Release
887
    #   Don't worry about dependent packages
888
    #
889
    my $m_sqlstr = "SELECT pv.PV_ID, pkg.PKG_NAME, pv.PKG_VERSION, pv.V_EXT, release_manager.PK_RMAPI.return_vcs_tag(pv.PV_ID)".
890
                   " FROM RELEASE_MANAGER.RELEASE_CONTENT rc, RELEASE_MANAGER.PACKAGE_VERSIONS pv, RELEASE_MANAGER.PACKAGES pkg" .
891
                   " WHERE rc.RTAG_ID = $rtagid AND rc.PV_ID = pv.PV_ID AND pv.PKG_ID = pkg.PKG_ID";
892
    my $sth = $RM_DB->prepare($m_sqlstr);
893
    if ( defined($sth) )
894
    {
895
        if ( $sth->execute( ) )
896
        {
897
            if ( $sth->rows )
898
            {
899
                while ( @row = $sth->fetchrow_array )
900
                {
901
                    my $data;
902
                    my $pvid = $row[0];
903
                    unless (exists $Packages{$pvid}) {
904
                        $data->{pv_id} = $row[0];
905
                        $data->{name} = $row[1];
906
                        $data->{ver} = $row[2];
907
                        $data->{ext} = $row[3] || '';
908
                        $data->{vcs} = $row[4] || '';
909
                        $Packages{$pvid} = $data;
910
                    }
5212 dpurdie 911
                    $ReleaseData{$rtagid}{data}{$pvid} = 1;
5209 dpurdie 912
                }
913
            }
914
            $sth->finish();
915
        }
916
    }
917
    else
918
    {
919
        Error("getOneRelease:Prepare failure" );
920
    }
921
}
922
 
923
#-------------------------------------------------------------------------------
924
# Function        : genDatabaseName 
925
#
926
# Description     : Genertate the name of a database
927
#
928
# Inputs          : rtag_id 
929
#
930
# Returns         : Text Name of the database
931
#
932
 
933
sub genDatabaseName
934
{
935
    my ($rtag_id) = @_;
936
    return 'LXR_' . $rtag_id;
937
}
938
 
939
#-------------------------------------------------------------------------------
940
# Function        : readConfig 
941
#
942
# Description     : Read the basic LXR config
943
#                   This is held in a Perl structure 
944
#
945
# Inputs          : None 
946
#
947
# Returns         : Populate Global Data
948
#
949
sub readConfig
950
{
951
    my $cfile = catfile($scriptDir,'jats_lxr.conf');
5211 dpurdie 952
    if ($opt_config)
953
    {
954
        Message ("Using alternate config: $opt_config");
955
        $cfile = $opt_config;
956
    }
5209 dpurdie 957
    Error ("Expected config file not found: $cfile") unless ( -f $cfile );
958
    require $cfile;
959
 
960
#   #
961
#   #   Create data
962
#   #
963
#   my %hash = (
964
#   number => 42,
965
#   string => 'This is a string',
966
#   array  => [ 1 .. 10 ],
967
#   hash   => { apple => 'red', banana => 'yellow' },
968
#   );
969
#
970
#   # Print structure to file
971
#   open (my $out, '>', $cfile) || Error("Can't create $cfile. $!");
972
#   DebugDumpData("Hash", \%hash);
973
#   print {$out} Data::Dumper->Dump([\%hash], ['$config']);
974
#   close $out;
975
 
976
    #DebugDumpData("config", \$config);
977
 
978
}
979
 
980
#-------------------------------------------------------------------------------
981
# Function        : startLogFile 
982
#
983
# Description     : Start logging to a log file
984
#                   Generate a nice name for the log file
985
#
986
# Inputs          : 
987
#
988
# Returns         : 
989
#
990
sub startLogFile
991
{
992
    if ( $opt_logfile )
993
    {
994
        if (exists $config->{lxrLogDir})
995
        {
996
            my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime($stamptime);
997
            my $name = sprintf("jats-lxr-%4.4d%2.2d%2.2d.%2.2d%2.2d%2.2d.log", 1900+$year, 1+$mon, $mday, $hour, $min, $sec);
998
            $name = catdir($config->{lxrLogDir}, $name);
999
 
1000
            mkpath($config->{lxrLogDir}); 
1001
            if (-d $config->{lxrLogDir} )
1002
            {
1003
                open STDOUT, '>', $name  or die "Can't redirect STDOUT: $!";
1004
                open STDERR, ">&STDOUT"  or die "Can't dup STDOUT: $!";
1005
            }
1006
            else
1007
            {
1008
                Warning("Can't create log dir: $config->{lxrLogDir}. $!");
1009
            }
1010
        }
1011
    }
1012
}
1013
 
1014
#-------------------------------------------------------------------------------
1015
# Function        : cleanupLogFiles 
1016
#
1017
# Description     : Remove old log files
1018
#
1019
# Inputs          : 
1020
#
1021
# Returns         : 
1022
#
1023
sub cleanupLogFiles
1024
{
1025
    if (exists $config->{lxrLogDir} && exists $config->{logAge}  && $config->{logAge} > 0 )
1026
    {
1027
        Verbose("cleanupLogFiles:$config->{lxrLogDir}, $config->{logAge}");
1028
        if ( opendir my $logDir, $config->{lxrLogDir} )
1029
        {
1030
            foreach my $fileName (readdir $logDir)
1031
            {
1032
                my $file = catfile($config->{lxrLogDir}, $fileName);
1033
                next unless -f $file;
1034
                next unless -M $file > $config->{logAge};
1035
                Verbose("Purge logfile: $fileName");
1036
                unlink $file;
1037
            }
1038
            closedir $logDir;
1039
        }
1040
    }
1041
}
1042
 
5211 dpurdie 1043
#-------------------------------------------------------------------------------
1044
# Function        : processAgeMarker 
1045
#
1046
# Description     : Age out directories
1047
#                   Will create age markers as required
1048
#
1049
# Inputs          : $tdir       - Target Directory
1050
#                   $age        - Configured age 
1051
#
1052
# Returns         : true        - Directory has reached age
1053
#
1054
sub processAgeMarker
1055
{
1056
    my ($tdir, $age) = @_;
1057
 
1058
    unless (-d $tdir) {
1059
        Warning ("Expected directory not found: $tdir");
1060
        return 0; 
1061
    }
5209 dpurdie 1062
 
5211 dpurdie 1063
    #   A configured age of 0 implies delete immediatly
1064
    if ($age == 0)
1065
    {
1066
        return 1;
1067
    }
1068
 
1069
    #
1070
    #   Create the file ONCE
1071
    #
1072
    my $markerfile = catfile($tdir, '.lxrAge');
1073
    unless (-f $markerfile)
1074
    {
1075
        TouchFile($markerfile);
1076
    }
1077
    else
1078
    {
1079
        if (-M $markerfile > $age)
1080
        {
1081
            return 1
1082
        }
1083
    }
1084
    return 0;
1085
}
1086
 
1087
 
5209 dpurdie 1088
#-------------------------------------------------------------------------------
5211 dpurdie 1089
# Function        : deleteAgeMarker 
1090
#
1091
# Description     : Delete any age marker
1092
#                   Used when a (potentially) agable directory is used to remove
1093
#                   the aging marker
1094
#
1095
# Inputs          :  $tdir      - Directory
1096
#
1097
# Returns         : 
1098
#
1099
sub deleteAgeMarker
1100
{
1101
    my ($tdir) = @_;
1102
 
1103
    unless (-d $tdir) {
1104
        Warning ("Expected directory not found: $tdir");
1105
        return 0; 
1106
    }
1107
 
1108
    #
1109
    #   Use same file name as in processAgeMarker
1110
    #
1111
    my $markerfile = catfile($tdir, '.lxrAge');
1112
    unlink $markerfile;
1113
}
1114
 
1115
 
1116
#-------------------------------------------------------------------------------
5209 dpurdie 1117
#   Documentation
1118
#
1119
 
1120
=pod
1121
 
1122
=head1 NAME
1123
 
1124
jats_lxr - Maintain LXR Releases
1125
 
1126
=head1 SYNOPSIS
1127
 
1128
  jats jats_lxr [options]
1129
 
1130
 Options:
1131
    -help               - brief help message
1132
    -help -help         - Detailed help message
1133
    -man                - Full documentation
1134
    -[no]createVersions - Create new versions. Default:Create
1135
    -[no]extract        - Extract source code. Default:Extract
1136
    -[no]index          - Index new LXR versions. Default:Index
1137
    -[no]purge          - Purge unused packages. Default:Purge
1138
    -[no]logfile        - Capture out to a log file. Default:Log
5211 dpurdie 1139
    -config=file        - Alternate config file
5209 dpurdie 1140
 
1141
=head1 OPTIONS
1142
 
1143
=over 8
1144
 
1145
=item B<-help>
1146
 
1147
Print a brief help message and exits.
1148
 
1149
=item B<-help -help>
1150
 
1151
Print a detailed help message with an explanation for each option.
1152
 
1153
=item B<-man>
1154
 
1155
Prints the manual page and exits.
1156
 
1157
=item B<-verbose>
1158
 
1159
This option will display progress information as the program executes.
1160
 
1161
=item B<-[no]createVersions>
1162
 
1163
This option can be used to suppress the creation of new views.
1164
 
1165
=item B<-[no]extract>
1166
 
1167
This option can be used to suppress the extraction of source.
1168
 
1169
=item B<-[no]index>
1170
 
1171
This option can be used to suppress the indexing of newly created views.
1172
 
1173
=item B<-[no]purge>
1174
 
1175
This option can be used to suppress purging of packages that are no longer used by any of the LXR Trees.
1176
 
5211 dpurdie 1177
=item B<-config=file>
1178
 
1179
This option can be used to override the standard config file. Used in testing.
1180
 
5209 dpurdie 1181
=back
1182
 
1183
=head1 DESCRIPTION
1184
 
1185
This program is a tool for creating and maintaining an LXR instance within the VIX Build System.
1186
 
1187
The program can:
1188
 
1189
=over 8
1190
 
1191
=item * 
1192
 
1193
Examine the Release Manager Database and determine which Releases are a part of the set to have LXR Views created.
1194
 
1195
Releases that are Open (or Restricted or in CCB Mode) or that have been closed for less than 10 days will be processed.
1196
 
1197
=item *
1198
 
1199
Examine the Release Manager Database and determine the package-versions that are a part of the LXR Release Set.
1200
 
1201
The process will only examine the contents of a Release. It will not descend the version dependency tree.
1202
 
1203
The program will then extract new package-versions into it's Package Store. Multiple LXR Tree's will share the one 
1204
instance of the extracted source code.
1205
 
1206
=item *
1207
 
1208
Create a new 'Version' for each Release.
1209
 
1210
The Version Name is based on the date-time at which the process is run.
1211
 
1212
Each Version is a symlink to the required package-version held in the Package Store.
1213
 
1214
This step can be suppressed though a command line option.
1215
 
1216
=item *
1217
 
1218
Remove unused LXR Trees (Releases no longer being processed) and unused Versions within each Tree.
1219
 
1220
Releases that are no longer eligable for processing will be retained for 10 days and then deleted. 
1221
During this time the existing versions will not be aged out.
1222
 
1223
At the moment this tool simply retains the last 5 Versions of each Release. If the tool 
1224
is run nightly then this will translate into  5 days.
1225
 
1226
=item *
1227
 
1228
Regenerate the LXR Configuration file
1229
 
1230
Create new database tables for new Releases
1231
 
1232
=item *
1233
 
1234
Run the LXR indexer for each LXR Version that has not been processed. Once processed the Version will 
1235
be tagged to prevent further indexing.
1236
 
1237
=item *
1238
 
1239
Remove unused Package-Versions from the Package Store.
1240
 
1241
=back
1242
 
1243
=cut
1244