Subversion Repositories DevTools

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
6133 dpurdie 1
########################################################################
7300 dpurdie 2
# COPYRIGHT - VIX IP PTY LTD ("VIX"). ALL RIGHTS RESERVED.
6133 dpurdie 3
#
4
# Module name   : jats_generate_deployable.pl
5
# Module type   : Makefile system
6
# Compiler(s)   : Perl
7
# Environment(s): jats build system
8
#
9
# Description   : Extracts current package version list from release manager
10
#                 based on the 'IS_DEPOLYABLE' flag in a given Release
11
#                 and copies resultant packages to release specific
12
#                 directory.
13
#                 
14
#                 Based on jats_update_release.pl and jats_gen_bom.pl but it is 
15
#                 intended to be used by the PULSE digital distribution process
16
#......................................................................#
17
 
18
require 5.008_002;
19
use File::Basename;
20
use File::Copy;
21
use File::Path;
22
use strict;
23
use warnings;
24
use JatsEnv;
25
use JatsError;
26
use JatsRmApi;
27
use ArrayHashUtils;
28
use FileUtils;
29
use DBI;
30
use Getopt::Long;
31
use Pod::Usage;                             # required for help support
32
use JSON;
33
 
34
#
35
#   Config Options
36
#
37
my $VERSION = "1.0.0";                      # Update this
38
my $opt_help = 0;
39
my $opt_verbose = $ENV{'GBE_VERBOSE'};      # Allow global verbose
40
my $opt_rtagid;
41
my $opt_rootdir = '.';
42
my $opt_test;
43
my $opt_showFilters;
44
my @opt_addFilters;
45
my @opt_delFilters;
46
my $opt_showFiles;
47
my @opt_addFiles;
48
my @opt_delFiles;
7307 dpurdie 49
my $opt_symlinks;
6133 dpurdie 50
 
51
 
52
#
53
#   Constants
54
#
55
my $CONFFILE = '.bomGen';
7304 dpurdie 56
my $BOMFILE = '.bomCots';
6133 dpurdie 57
my $MANIFEST = 'MANIFEST.json';
58
my $TFVARS   = 'MANIFEST.tf';
59
 
60
#
61
#   Globals
62
#
63
my $DM_DB;              # Data Base Interface
64
my %bomList;            # All files in the BOM
65
my $bomInfo;            # Sbom meta data
7300 dpurdie 66
my %baseList;           # List of files in bin
6133 dpurdie 67
 
68
#
69
#   Configuration file vars
70
#
71
my @confFilters;
72
my @confFiles;
73
my %filtersUsed;
74
 
75
#-------------------------------------------------------------------------------
76
# Function        : Main
77
#
78
# Description     : Main entry point
79
#                   Parse user options
80
#
81
# Inputs          :
82
#
83
# Returns         :
84
#
85
 
86
my $result = GetOptions (
87
                "help:+"            => \$opt_help,              # flag, multiple use allowed
88
                "manual:3"          => \$opt_help,              # flag, multiple use allowed
89
                "verbose:+"         => \$opt_verbose,           # flag
90
                "rtagid|rtag_id=s"  => \$opt_rtagid,            # Number
91
                "rootdir=s"         => \$opt_rootdir,           # string
7307 dpurdie 92
                "symlinks!"         => \$opt_symlinks,          # Boolean
6133 dpurdie 93
 
94
                "addfilter=s"       => \@opt_addFilters,        # multiple strings
95
                "delfilter=s"       => \@opt_delFilters,        # multiple strings
96
                "showfilters"       => \$opt_showFilters,       # flag
97
 
98
                "addfiles=s"       => \@opt_addFiles,           # multiple strings
99
                "delfiles=s"       => \@opt_delFiles,           # multiple strings
100
                "showfiles"        => \$opt_showFiles,          # flag
101
 
102
                "test"              => \$opt_test,              # flag
103
                );
104
 
105
#
106
#   Process help and manual options
107
#
108
pod2usage(-verbose => 0, -message => "Version: $VERSION")  if ($opt_help == 1  || ! $result);
109
pod2usage(-verbose => 1)  if ($opt_help == 2 );
110
pod2usage(-verbose => 2)  if ($opt_help > 2);
111
 
112
ErrorConfig( 'name'    => 'GenDeploy',
113
             'verbose' => $opt_verbose );
114
 
115
#
116
#   Sanity tests
117
#
118
 
119
# Supplied rootdir must exists as a directory
120
Error("Root dir not specified") 
121
    unless defined $opt_rootdir;
122
Error("Root dir not a valid directory: ", $opt_rootdir )
123
    unless( -d $opt_rootdir );
124
 
125
    # Environment var GBE_DPKG must exists as a directory
126
Error("GBE_DPKG Environment var is not a directory")
127
    unless ( -d $ENV{GBE_DPKG} );
128
 
129
LoadFilterConfig();
130
ProcessFilterArgs();
131
 
132
#   Non Filter operations
133
#   Must supply an rtagid
134
Error("Need --rtagid", "Example: -rtagid=2362" )
135
    unless ($opt_rtagid);
136
 
7304 dpurdie 137
Error("No Filters defined.", "Add filters before creating BOM") 
138
    unless ( @confFilters );
139
 
6133 dpurdie 140
#
141
#   This command is destined to be used in a directory where group permissions
142
#   are important. Ensure that the user is not killing group access
143
#
144
umask 0002;
145
 
146
#
147
#   Body of the processing
148
#       Save generation time into the meta data
149
my $now = time;
150
$bomInfo->{version} = "2.0.0";
151
$bomInfo->{timestamp}{epoch} = $now;
152
$bomInfo->{timestamp}{utc} = gmtime($now);
153
 
7307 dpurdie 154
Message("Copying packages from $ENV{GBE_DPKG} to $opt_rootdir") unless $opt_symlinks;
155
Message("Symlink packages from $opt_rootdir to $ENV{GBE_DPKG}") if $opt_symlinks;
6133 dpurdie 156
 
157
#
158
#   Processing
159
#
160
connectRM(\$DM_DB);
161
GetReleaseInfo();               # Get Release Metadata
162
GetPackageData();               # Get RM Data
163
RemoveDuplicates();             # Need P or D, but not both
164
CopyInNew();                    # Copy new files
165
RemoveExcess();                 # Remove files no longer required
166
GenFileData();                  # Generate file metadata
167
WriteManifest();                # Save out meta data
168
exit 0;
169
 
170
#-------------------------------------------------------------------------------
171
# Function        : GenFileData 
172
#
173
# Description     : Generate meta data on each file
174
#                   Much of this is a guess.
175
#                   Assume files look like:
176
#                   
177
#                       VIXcryptoKeyManager-1.0.2061.cr-WIN32.exe
178
#                       erg-pkgmnt_1.0.3010.cr_UBUNTU16_P.deb
179
#                       erg-pkgmnt_1.0.3010.cr_RHEL7_P.rpm
180
#                       xxxxxx.sh - bit trickier
181
#
182
# Inputs          : None
183
#
184
# Returns         : Populates $bomInfo
185
#
186
sub GenFileData
187
{
188
    my @elist;
189
    my @edup;
190
    foreach my $file (sort keys %bomList)
191
    {
192
        my $data;
193
        my $alias;
194
 
195
        $bomList{$file}{version} =~ m~(.*)\.([a-z]+)$~;
196
        my $pvfull = $1;
197
        my $proj = $2;
198
        my $pv = $pvfull;
199
        $pv =~ s~\.\d+$~~;
200
 
201
        if ($file =~ m~^(.*)-(.*)\.(.*)-(WIN.*)\.(exe)$~i)
202
        {
203
            $data->{name} = $1;
204
            $data->{version} = $2;
205
            $data->{prj} = $3;
206
            $data->{arch} = $4;
207
            $data->{type} = $5;
208
        }
209
        elsif ( $file =~ m~^(.*)_(.*)\.([^_]+)_(.*)\.(deb|tgz|rpm)$~i)
210
        {
211
            $data->{name} = $1;
212
            $data->{version} = $2;
213
            $data->{prj} = $3;
214
            $data->{arch} = $4;
215
            $data->{type} = $5;
216
            $data->{arch} =~ s~_[PD]~~;
7304 dpurdie 217
            $alias = join('.', $data->{name}, $data->{prj}, $data->{arch}, $data->{type} );
6133 dpurdie 218
        }
7306 dpurdie 219
        elsif ( $file =~ m~^(.*)-(.*)-(.*)\.(.*)\.(rpm)$~i)
220
        {
221
            $data->{name} = $1;
222
            $data->{version} = $2;
223
            $data->{release} = $3;
224
            $data->{arch} = $4;
225
            $data->{type} = $5;
226
            $alias = join('.', $data->{name}, $data->{arch}, $data->{type} );
227
        }
6133 dpurdie 228
        elsif ( $file =~ m~^(.*)-($pv)\.(.*)\.(rpm)$~i)
229
        {
230
            # COTS package
231
            $data->{name} = $1;
232
            $data->{version} = $2;
233
            $data->{arch} = $3;
234
            $data->{type} = $4;
235
            $data->{prj} = $proj;
236
        }
237
        elsif ( $file =~ m~^(.*)_($pv)\.(tgz)$~i)
238
        {
239
            # COTS package
240
            $data->{name} = $1;
241
            $data->{version} = $2;
242
            $data->{arch} = 'UNKNOWN';
243
            $data->{type} = $3;
244
            $data->{prj} = $proj;
245
        }
246
        elsif ( $file =~ m~^(.*)-($pv)\.(.*)\.(deb)$~i)
247
        {
248
            # COTS package
249
            $data->{name} = $1;
250
            $data->{version} = $2;
251
            $data->{arch} = $3;
252
            $data->{type} = $4;
253
            $data->{prj} = $proj;
254
        }
255
        elsif ( $file =~ m~^(.*)\.(sh|zip|msi|tar\.gz)$~i)
256
        {
257
            $data->{name} = $1;
258
            $data->{arch} = 'NOARCH';
259
            $data->{type} = $2;
260
 
261
            $data->{version} = $pvfull;
262
            $data->{prj} = $proj;
263
        }
264
 
7306 dpurdie 265
        unless (($data && $data->{name} && $data->{prj} && $data->{type}) || $alias) {
6133 dpurdie 266
            push @elist, $file;
267
            next;
268
        }
269
        $data->{fullname} = $file;
270
 
271
        #
272
        #   Create a nice alias
273
        #       ERG -> VIX  (not done)
274
        #       All lowercase
275
        #
7304 dpurdie 276
        $alias = join ('.', $data->{name}, $data->{prj}, $data->{type} ) unless defined $alias;
6133 dpurdie 277
        $alias = lc ($alias);
278
        #$alias =~ s~^erg~vix~;
279
        #$alias =~ s~^vix~vix-~;
280
        #$alias =~ s~^vix--~vix-~;
281
        push (@edup, join( ' : ', $alias, $file ,$bomInfo->{files}{$alias}{fullname})  ) if exists $bomInfo->{files}{$alias};
282
 
283
        delete $data->{type};
284
        $bomInfo->{files}{$alias} = $data;
7304 dpurdie 285
#Debug0("Alias: $file-> $alias");
6133 dpurdie 286
    }
287
 
288
    ReportError ("Cannot extract file metadata from:", @elist)  if (@elist);
289
    ReportError ("Duplicate aliases for:", @edup)  if (@edup);
290
    ErrorDoExit();
291
}
292
 
293
#-------------------------------------------------------------------------------
294
# Function        : CopyInNew 
295
#
296
# Description     : Copy in new files
297
#                   Don't copy in files that already exist - assume that the
7307 dpurdie 298
#                   files don't change without a chnage to the file name
6133 dpurdie 299
#
300
# Inputs          : 
301
#
302
# Returns         : 
303
#
304
sub CopyInNew
305
{
306
    #
307
    #   Ensure the output directory exists
308
    #
309
    if ( ! -d $opt_rootdir )
310
    {
311
        if ( defined($opt_test) )
312
        {
313
            Message("mkdir $opt_rootdir");
314
        }
315
        else
316
        {
317
            eval { mkpath($opt_rootdir) };
318
            Error("Failed to make project directory tree $opt_rootdir") if ( $@ || ! -d $opt_rootdir );
319
        }
320
    }
321
 
322
    #
7300 dpurdie 323
    #   Generate a list of all files in the directory
324
    #
325
    foreach my $file ( glob("$opt_rootdir/*") ) {
326
        $baseList{$file}{data} = 1;
327
    }
328
 
329
    #
6133 dpurdie 330
    #   Determine the files to be transferred
331
    #
332
    my @filelist;
333
    foreach my $file ( keys %bomList)
334
    {
335
        push (@filelist, $file) unless ( -f "$opt_rootdir/$file" );
336
    }
337
 
338
    #
339
    #   Perform the actual copy
340
    #
341
    if ( @filelist )
342
    {
343
        #Message("Copying files for package $PKG_NAME version $PKG_VERSION");
344
        if ( defined($opt_test) )
345
        {
346
            Message( map("$_...", @filelist) );
347
        }
348
        else
349
        {
350
            eval { mkpath($opt_rootdir) };
351
            Error("Failed to make destination directory") if ( $@ || ! -d $opt_rootdir );
352
            foreach my $file ( @filelist )
353
            {
354
                my $srcFile = $bomList{$file}{path};
7307 dpurdie 355
                if ($opt_symlinks)
6133 dpurdie 356
                {
7307 dpurdie 357
                   Verbose("Symlink: $file");
358
                   my $fname = catdir( $opt_rootdir, StripDir($srcFile));
359
                    if ( ! symlink ($srcFile, $fname) )
360
                    {
361
                        Warning("Failed to symlink $file ($!)");
362
                    }
363
 
6133 dpurdie 364
                }
7307 dpurdie 365
                else
366
                {
367
                    Verbose("Copy: $file");
368
                    if ( ! copy($srcFile, $opt_rootdir) )
369
                    {
370
                        Warning("Failed to copy $file ($!)");
371
                    }
372
                }
6133 dpurdie 373
            }
374
        }
375
    }
376
}
377
 
378
#-------------------------------------------------------------------------------
379
# Function        : RemoveExcess 
380
#
381
# Description     : Remove excess files from the output directory 
382
#
383
# Inputs          : 
384
#
385
# Returns         : 
386
#
387
sub RemoveExcess
388
{
389
    my @filelist;
390
    my %keepList = map { $_ => 1 } @confFiles;
391
 
392
    #
393
    #   Find all files in the output directory
394
    #   Use the 'keepList' so that we don't pickup files that should
395
    #   be in the directory. README.md, MANIFEST ...
396
    #
397
    foreach my $srcPath ( glob("$opt_rootdir/*") )
398
    {
399
        my $dstFile = basename($srcPath);
400
        next if exists $keepList{$dstFile};
401
        next unless ( -f $srcPath );
402
 
403
        push (@filelist, $dstFile) unless (exists $bomList{$dstFile} );
404
    }
405
 
406
    if ( @filelist)
407
    {
7304 dpurdie 408
        Verbose ("Delete execess files", @filelist );
6133 dpurdie 409
        unless ( defined($opt_test) )
410
        {
411
            foreach my $file ( @filelist )
412
            {
7304 dpurdie 413
                Verbose2("Delete: $file...");
6133 dpurdie 414
                if ( unlink("$opt_rootdir/$file") ne 1 )
415
                {
416
                    Warning("Failed to delete: $file. ($!)");
417
                }
418
            }
419
        }
420
    }
7300 dpurdie 421
 
422
    #
423
    #   Report changed files
424
    #   Generate a list of all files in the directory
425
    #
426
    foreach my $file ( glob("$opt_rootdir/*") ) {
427
        $baseList{$file}{data} |= 2;
428
    }
429
 
430
    #
431
    #   Determined added, removed and replaced
432
    #       
433
    #
434
    my (@replaced, @added, @removed, @unchanged, %newList);
435
    foreach my $entry ( keys %baseList )
436
    {
437
        (my $key = $entry) =~ s~\d+~z~g;
438
        $baseList{$entry}{key} = $key;
439
 
440
        (my $name = $entry) =~ s~^\./~~;
441
        $newList{$key}{$baseList{$entry}{data}} = $entry;
442
    }
443
 
444
    foreach my $key ( sort keys %newList )
445
    {
446
        if (exists $newList{$key}{1} && exists $newList{$key}{2}  ) {
447
            push @replaced, "$newList{$key}{1}   =>   $newList{$key}{2}";
448
        } elsif (exists $newList{$key}{1}) {
449
            push @removed, $newList{$key}{1};
450
        } elsif (exists $newList{$key}{2}) {
451
            push @added, $newList{$key}{2};
452
        } elsif (exists $newList{$key}{3}) {
453
            push @unchanged, $newList{$key}{3};
454
        }
455
    }
456
 
457
    Message ("Unchanged: " .(@unchanged ? scalar(@unchanged ) : 'None') );
458
    Message ("Replaced: " . (@replaced ?  scalar(@replaced )  : 'None'), @replaced);
459
    Message ("Added: " .    (@added    ?  scalar(@added )     : 'None'), @added);
460
    Message ("Removed: " .  (@removed  ?  scalar(@removed )   : 'None'), @removed);
6133 dpurdie 461
}
462
 
463
#-------------------------------------------------------------------------------
464
# Function        : RemoveDuplicates 
465
#
466
# Description     : Scan the BOM file list and remove duplicate installers
467
#                   Duplicate installers are that that have both a P and a D
468
#                   flavor of the installer
469
#                   
470
#                   This test has some nasty built-in knowledge (assumtions)
471
#                   It assumes that:
472
#                       Windows installers are only created for one flavor
473
#                           Don't need to worry about windoes installers
474
#                       Non windows installers are of the form:
475
#                           Name_Architecture_Type.deb    
476
#
477
# Inputs          : 
478
#
479
# Returns         : 
480
#
481
sub RemoveDuplicates
482
{
483
    my %baseNames;
484
    foreach my $file ( keys %bomList)
485
    {
486
        #
487
        #   Only process files that are of the expected form
488
        #       ie: erg-udcrypt_1.0.3043.vss_UBUNTU16_P.deb
489
        #
490
        if( $file =~ m~(.*)_([PD])(\.(deb|rpm|tgz))$~ )
491
        {
492
            my $base=$1;
493
            my $type=$2;
494
            my $suf=$3;
495
 
496
            if (exists $baseNames{$base} )
497
            {
498
                my $debugName = $base . '_D' . $suf;  
499
                Verbose("Remove debug installer: $file. Kill: $debugName");
500
                delete $bomList{$debugName};
501
            }
502
 
503
            $baseNames{$base} = $type;
504
        }
505
    }
506
}
507
 
508
#-------------------------------------------------------------------------------
509
# Function        : LoadFilterConfig  
510
#
511
# Description     : Load Filter Config
512
#                   Retain filter config for future reference 
513
#
514
# Inputs          : 
515
#
516
# Returns         : 
517
#
518
sub LoadFilterConfig
519
{
520
    if ( -f "$opt_rootdir/$CONFFILE" )
521
    {
522
        Message("Loading Config File");
7304 dpurdie 523
        my $perl_scalar = ReadJsonFile("$opt_rootdir/$CONFFILE");
6133 dpurdie 524
        Error ("Invalid format in Config file")
525
            unless (ref($perl_scalar->{filters}) eq 'ARRAY');
526
 
527
        push (@confFilters, @{$perl_scalar->{filters}});
528
        push (@confFiles, @{$perl_scalar->{keptfiles}}) if exists ($perl_scalar->{keptfiles});
529
    }
530
}
531
 
532
#-------------------------------------------------------------------------------
7304 dpurdie 533
# Function        : ReadJsonFile 
534
#
535
# Description     : Read a JSON file and return the data 
536
#
537
# Inputs          : $fname  - Name of the file to read 
538
#
539
# Returns         : Ref to the JSON 
540
#
541
sub ReadJsonFile
542
{
543
    my ($fname) = @_;
544
    local $/;
545
    open(my $fh, $fname ) || Error("Failed to open $fname. $!");
546
    my $json_text = <$fh>;
547
    my $perl_scalar = decode_json( $json_text );
548
    close($fh);
549
 
550
    return $perl_scalar;
551
}
552
 
553
#-------------------------------------------------------------------------------
554
# Function        : WriteJsonFile 
555
#
556
# Description     : Write data into a file as JSON
557
#
558
# Inputs          : $fname  - Name of file to write
559
#                   $data   - Ref to data to write 
560
#
561
# Returns         : Will not return on error
562
#
563
sub WriteJsonFile
564
{
565
    my ($fname, $data) = @_;
566
    FileCreate ($fname, to_json( $data, { ascii => 1, pretty => 1 }));
567
}
568
 
569
 
570
#-------------------------------------------------------------------------------
6133 dpurdie 571
# Function        : ProcessFilterArgs
572
#
573
# Description     : Process the filter based arguments 
574
#
575
# Inputs          : 
576
#
577
# Returns         : 
578
#
579
sub ProcessFilterArgs
580
{
581
    my $filterArgSeen;
582
    my $writeConf;
583
 
584
 
585
 
586
    if ( @opt_addFilters )
587
    {
588
        Message ("Adding command line filters to the release config file");
589
        foreach my $element (@opt_addFilters) {
590
            UniquePush (\@confFilters, $_ ) foreach  ( split(/,/, $element));
591
        }
592
        $writeConf = 1;
593
    }
594
 
595
    if ( @opt_delFilters )
596
    {
597
        Message ("Deleting command line filters to the release config file");
598
        foreach my $element (@opt_delFilters) {
599
            ArrayDelete (\@confFilters, $_ ) foreach  ( split(/,/, $element));
600
        }
601
        $writeConf = 1;
602
    }
603
 
604
    if ( @opt_addFiles )
605
    {
606
        Message ("Adding command line files to the release config file");
607
        foreach my $element (@opt_addFiles) {
608
            UniquePush (\@confFiles, $_ ) foreach  ( split(/,/, $element));
609
        }
610
        $writeConf = 1;
611
    }
612
 
613
    if ( @opt_delFiles )
614
    {
615
        Message ("Deleting command line files to the release config file");
616
        foreach my $element (@opt_delFiles) {
617
            ArrayDelete (\@confFiles, $_ ) foreach  ( split(/,/, $element));
618
        }
619
        $writeConf = 1;
620
    }
621
 
622
    #
623
    #   Save filter information
624
    #
625
    if ( $writeConf && ! defined($opt_test) )
626
    {
627
        Verbose ("Write config file");
628
 
629
        #
630
        #   Add known files
631
        #
7304 dpurdie 632
        UniquePush (\@confFiles, $CONFFILE, $BOMFILE, $MANIFEST, $TFVARS);
6133 dpurdie 633
 
634
        my $config;
635
        push @{$config->{filters}},@confFilters;
636
        push @{$config->{keptfiles}},@confFiles;
7304 dpurdie 637
        WriteJsonFile("$opt_rootdir/$CONFFILE",$config);
6133 dpurdie 638
    }
639
 
640
    #
641
    #   Display information to the user
642
    #
643
    if ($opt_showFilters)
644
    {
645
        Message ("Configured Filters",@confFilters );
646
        $filterArgSeen = 1;
647
    }
648
 
649
    if ($opt_showFiles)
650
    {
651
        Message ("Configured Files. Keep:",@confFiles );
652
        $filterArgSeen = 1;
653
    }
654
 
655
 
656
    #
657
    #   Terminate program on any filter operations
658
    #
659
    exit 0 if ( $writeConf || $filterArgSeen);
660
}
661
 
662
#-------------------------------------------------------------------------------
663
# Function        : WriteManifest 
664
#
665
# Description     : Save the filter config file if required
666
#
667
# Inputs          : 
668
#
669
# Returns         : 
670
#
671
sub WriteManifest
672
{
673
    return if defined($opt_test);
674
 
675
    #
676
    #   Create JSON metadata
677
    #
678
    Verbose ("Write JSON Manifest");
679
    my $jsonString = to_json( $bomInfo, { ascii => 1, pretty => 1, canonical => 1 } ); 
680
    FileCreate ($opt_rootdir . '/' . $MANIFEST, $jsonString);
681
 
682
    #
683
    #   Create Terraform data
684
    #       Note: Terraform variable cannot have a '.' in them
685
    #   
686
    my @tfData2;
687
 
688
    push @tfData2, "// Terraform variable definitions to map clean package name to full file name";
689
    push @tfData2, "variable vixFileName {";
690
    push @tfData2, "    type = \"map\"";
691
    push @tfData2, "    default = {" ;
692
 
7300 dpurdie 693
    foreach my $item ( sort keys %{$bomInfo->{files}} )
6133 dpurdie 694
    {
695
        push @tfData2, "        \"". $item  ."\" = \"" .$bomInfo->{files}{$item}{fullname} ."\"";
696
    }
697
 
698
    push @tfData2, "    }" ;
699
    push @tfData2, "}" ;
700
 
701
    FileCreate ($opt_rootdir . '/' . $TFVARS, @tfData2);
702
 
703
 
704
}
705
 
706
#-------------------------------------------------------------------------------
707
# Function        : GetReleaseInfo 
708
#
709
# Description     : Get Release Meta Data
710
#
711
# Inputs          : 
712
#
713
# Returns         : Will exit on error 
714
#
715
sub GetReleaseInfo
716
{
717
    my $m_sqlstr = "SELECT p.PROJ_ID, rt.rtag_id, p.PROJ_NAME, rt.RTAG_NAME" .
718
                    " FROM release_tags rt, PROJECTS p" .
719
                    " WHERE p.PROJ_ID = rt.PROJ_ID" .
720
                    " and rt.RTAG_ID = " . $opt_rtagid;
721
 
722
    my $sth = $DM_DB->prepare($m_sqlstr);
723
    if ( defined($sth) )
724
    {
725
        if ( $sth->execute( ) )
726
        {
727
            if ( $sth->rows )
728
            {
729
                while ( my ( $proj_id, $xx, $pname, $rname ) = $sth->fetchrow_array )
730
                {
731
                    my $data;
732
                    $data->{product_id} = $proj_id;
733
                    $data->{product_name} = $pname;
734
                    $data->{release_rtagid} = $opt_rtagid;
735
                    $data->{release_name} = $rname;
736
                    push @{$bomInfo->{release}}, $data;
737
                }
738
            }
739
            else
740
            {
741
                Error("GetReleaseInfo: No rtagid found for " . $opt_rtagid);
742
            }
743
            $sth->finish();
744
        }
745
        else
746
        {
747
            Error("GetReleaseInfo: Execute failure", $sth->errstr(), $m_sqlstr );
748
        }
749
    }
750
    else
751
    {
752
        Error("GetReleaseInfo: Prepare failure", $sth->errstr(), $m_sqlstr );
753
    }
754
}
755
 
756
#-------------------------------------------------------------------------------
757
# Function        : GetPackageData 
758
#
759
# Description     : Extract data from RM based on the provided rtag_id
760
#
761
# Inputs          : 
762
#
763
# Returns         : 
764
#
765
sub GetPackageData
766
{
7304 dpurdie 767
    my $m_sqlstr =  "SELECT p.PKG_NAME, " .
768
                    " pv.PKG_VERSION, " .
769
                    " l.name " .
770
                    "FROM package_versions pv, " .
771
                    " RELEASE_MANAGER.RELEASE_CONTENT rc, " .
772
                    " RELEASE_MANAGER.PACKAGES p, " .
773
                    " RELEASE_MANAGER.LICENCING pl, " .
774
                    " RELEASE_MANAGER.LICENCES l " .
775
                    "WHERE rc.rtag_id     = $opt_rtagid " .
776
                    " AND rc.pv_id         = pv.pv_id " .
777
                    " AND p.PKG_ID         = pv.pkg_id " .
778
                    " AND pv.IS_DEPLOYABLE = 'Y' " .
779
                    " AND pl.PV_ID(+)      = pv.pv_id " .
780
                    " AND pl.LICENCE       = l.LICENCE(+)" ;
6133 dpurdie 781
#                    " and ( pv.IS_DEPLOYABLE = 'Y' or upper( p.PKG_NAME) like 'ERG%' or upper( p.PKG_NAME) like 'VIX%' )";
782
 
7304 dpurdie 783
 
784
 
785
    my ( $PKG_NAME, $PKG_VERSION, $LICENSE );
6133 dpurdie 786
    my $sth = $DM_DB->prepare($m_sqlstr);
787
    if ( defined($sth) )
788
    {
789
        if ( $sth->execute( ) )
790
        {
791
            if ( $sth->rows )
792
            {
7304 dpurdie 793
                while ( ( $PKG_NAME, $PKG_VERSION, $LICENSE ) = $sth->fetchrow_array )
6133 dpurdie 794
                {
795
                    Verbose ("Deployable: $PKG_NAME, $PKG_VERSION");
796
                    my $pkgDir = "$ENV{GBE_DPKG}/$PKG_NAME";
797
                    my $srcDir = "$ENV{GBE_DPKG}/$PKG_NAME/$PKG_VERSION";
798
                    my $dstDir = $opt_rootdir;
799
 
800
                    if ( -d "$srcDir" )
801
                    {
802
                        my $foundFiltered = 0;
803
 
804
                        # for each of the filter rules we glob the rule in the src pkg/version dir
805
                        # and if any of the globbed files dont exist in the dst dir add it to the 
806
                        # the filelist array of files to copy
807
                        foreach my $filter ( @confFilters )
808
                        {
7307 dpurdie 809
                            next if ( $filter =~ m~^--~ );
6133 dpurdie 810
                            foreach my $srcPath ( glob("$srcDir/$filter") )
811
                            {
812
                                next unless ( -f $srcPath );
7307 dpurdie 813
                                next unless testExcluded ($srcPath);
6133 dpurdie 814
                                $foundFiltered = 1;
815
                                $filtersUsed{$filter} = 1;
816
                                my $dstFile = basename($srcPath);
817
                                my $srcFile = $srcPath;
7304 dpurdie 818
                                ReportError("File provided by multiple packages: $dstFile") if exists ($bomList{$dstFile});
819
                                $bomList{$dstFile}{path} = $srcPath;
820
                                $bomList{$dstFile}{package} = $PKG_NAME;
821
                                $bomList{$dstFile}{version} = $PKG_VERSION;
822
                                $bomList{$dstFile}{license} = $LICENSE || '';
6133 dpurdie 823
                            }
824
                        }
825
 
826
                        # if no files found using filters then issue warning
827
                        Warning("No Files found for Package Version $PKG_NAME/$PKG_VERSION using supplied filters") 
828
                            unless ( $foundFiltered );
829
 
830
                        if ($foundFiltered)
831
                        {
832
                            $bomInfo->{packages}{$PKG_NAME} = $PKG_VERSION;
833
                        }
834
                    }
835
                    elsif ( ! -d "$pkgDir" )
836
                    {
837
                        # if srcDir and pkgDir dont exist then package is not in dpkg_archive so display message
838
                        Warning("Skipping Package $PKG_NAME/$PKG_VERSION as it does not exist in dpkg_archive");
839
                    }
840
                    else
841
                    {
842
                        # However if srcDir does not exist but pkgDir does exist then the package version is missing which maybe an issue
843
                        Warning("Missing Version $PKG_VERSION for Package $PKG_NAME in dpkg_archive");
844
                    }
845
                }
846
 
847
                #
848
                #   Report filter elements that where not used.
849
                #
850
                my @notUsed;
851
                foreach my $filter ( @confFilters )
852
                {
853
                    next if ( exists $filtersUsed{$filter} );
854
                    push @notUsed, $filter
855
                }
856
                Warning ("Unused filter rules:", @notUsed )
857
                    if ( @notUsed );
858
 
859
            }
860
            else
861
            {
862
                Error("No Packages for rtagid: $opt_rtagid");
863
            }
864
            $sth->finish();
865
        }
866
        else
867
        {
868
            Error("Execute failure", $sth->errstr(), $m_sqlstr );
869
        }
870
    }
871
    else
872
    {
873
        Error("Prepare failure", $sth->errstr(), $m_sqlstr );
874
    }
7304 dpurdie 875
 
876
    #
877
    #   Report Commercial packages
878
    #   Write out a file to contain the list of COTS files
879
    #
880
    my @Commercial;
881
    foreach my $file (sort keys %bomList)
882
    {
883
        next unless ($bomList{$file}{license} =~ m ~^Commercial~);
884
        $bomList{$file}{cots} = 1;
885
        push @Commercial, $file;
886
    }
887
    Message ("Commercial software packages:", @Commercial);
888
    my $data;
889
    $data->{COTS} = \@Commercial;
890
    WriteJsonFile ("$opt_rootdir/$BOMFILE", $data);
891
 
892
    ErrorDoExit();
6133 dpurdie 893
}
894
 
895
#-------------------------------------------------------------------------------
7307 dpurdie 896
# Function        : testExcluded 
897
#
898
# Description     : Test a filename against the list of exclusion list 
899
#
900
# Inputs          : filename 
901
#
902
# Returns         : true - not excluded
903
#
904
sub testExcluded
905
{
906
    my ($filename) = @_;
907
    foreach my $ufilter ( @confFilters )
908
    {
909
        next unless ( $ufilter =~ m~^--(.*)~ );
910
        my $filter = glob2pat($1);
911
        if ( $filename =~ m~$filter~)
912
        {
913
            $filtersUsed{$ufilter} = 1;
914
            return 0;
915
        }
916
    }
917
 
918
    return 1;
919
}
920
 
921
#-------------------------------------------------------------------------------
922
# Function        : glob2pat
923
#
924
# Description     : Convert four shell wildcard characters into their equivalent
925
#                   regular expression; all other characters are quoted to
926
#                   render them literals.
927
#
928
# Inputs          : Shell style wildcard pattern
929
#
930
# Returns         : Perl RE
931
#
932
 
933
sub glob2pat
934
{
935
    my $globstr = shift;
936
    $globstr =~ s~^/~~;
937
    my %patmap = (
938
        '*' => '[^/]*',
939
        '?' => '[^/]',
940
        '[' => '[',
941
        ']' => ']',
942
        '-' => '-',
943
    );
944
    $globstr =~ s{(.)} { $patmap{$1} || "\Q$1" }ge;
945
    return '/' . $globstr . '$';
946
}
947
 
948
 
949
#-------------------------------------------------------------------------------
6133 dpurdie 950
#   Documentation
951
#
952
 
953
=pod
954
 
955
=for htmltoc    DEPLOY::generate_deployable
956
 
957
=head1 NAME
958
 
959
jats_generate_deployable - Extracts current package version list from Release Manager RtagId
960
                and copy resultant packages to a specific directory.
961
 
962
=head1 SYNOPSIS
963
 
964
  jats generate_deployable [options]
965
 
966
 Options:
967
    -help                   - Brief help message
968
    -help -help             - Detailed help message
969
    -man                    - Full documentation
970
    -rtagid=xxx             - Specify the Release Manager RtagId to process
971
    -rootdir=xxx            - Specifies the root of the releases directory
7307 dpurdie 972
    -[no]symlinks           - Use symlinks to dpkg_archive
6133 dpurdie 973
 
974
    -showfilters            - Display current filter set and exit
975
    -addfilter=xxx[,yyy]    - Add a new filter to the existing filter set
976
    -delfilter=xxx[,yyy]    - Delete a filter from the existing filter set
977
 
978
    -showfiles              - Display current kept file set and exit
979
    -addfiles=xxx[,yyy]     - Add a new file to the kept file set
980
    -delfiles=xxx[,yyy]     - Delete a file from the kept file set
981
 
982
    -test                   - Just log actions without copying files.
983
    -verbose                - Enable verbose output
984
 
985
=head1 OPTIONS
986
 
987
=over 8
988
 
989
=item B<-help>
990
 
991
Print a brief help message and exits.
992
 
993
=item B<-help -help>
994
 
995
Print a detailed help message with an explanation for each option.
996
 
997
=item B<-man>
998
 
999
Prints the manual page and exits.
1000
 
1001
=item B<-rtagid=xxx>
1002
 
1003
This option specifies one or more RTAG_ID's to use as the source of packages that will be copied.
1004
The ID will be used to get a unique list of package/versions that can be copied from dpkg_archive.
1005
 
1006
This option is Mandatory, for non-filter command.
1007
 
1008
=item B<-rootdir=xxx>
1009
 
1010
This option specifies the root directory where the packages will be copied to.
1011
 
1012
The specified directory must exist.
1013
 
1014
The default value is the current directory.
1015
 
7307 dpurdie 1016
=item B<[no]symlinks>
1017
 
1018
This option will cause symlinks to packages to be used in place of actual packages
1019
 
6133 dpurdie 1020
=item B<-showfilters>
1021
 
1022
This option will display the current filter set. If it is combined with another filter operation 
1023
then the other operations will be performed before the display.
1024
 
1025
=item B<-addFilter=xxx[,yyy]>
1026
 
1027
This option allows new filters to be added to the set of filters. This
1028
option can be specified multiple times.
1029
 
1030
This option specifies a comma separated list of shell wildcard filter rule that
1031
will be used to determine which files are copied from package version directory in
1032
GBE_DPKG to the release directory. This can be supplied multiple times to
1033
specify rules for copying.
1034
 
1035
Filters must be added the first time this command is run against a release 
1036
and packages are copied to the project/release directory.  These values are then written to a 
1037
config file in the release directory so the same values can be used on subsequent runs.  
1038
In these subsequent runs this option need not be specified as the config items will be used, however
1039
they can be changed by specifying them again on the command line and the config will be re-written.
1040
 
7307 dpurdie 1041
A filter that begins with a '--' will exclude files. The filter may contain shell wildcards. It is not a reguar expression.
1042
 
6133 dpurdie 1043
The values of these will depend on what builds are required for each project.  Some examples are
7307 dpurdie 1044
    --filter='*-WIN32.exe,*.deb,--*COBRA.deb'
6133 dpurdie 1045
 
1046
=item B<-delFilter=xxx[,yyy]>
1047
 
1048
This option deletes one or more filter rules from an existing set of filters. This
1049
option can be specified multiple times.
1050
 
1051
=item B<-showfiles>
1052
 
1053
This option will display the current file set. If it is combined with another file operations
1054
then the other operations will be performed before the display.
1055
 
1056
=item B<-addFile=xxx[,yyy]>
1057
 
1058
This option allows new files to be added to the set of kept files. This
1059
option can be specified multiple times.
1060
 
1061
This option specifies a comma separated list of file names (No wild cards) that
1062
will be used to specify a list of files that shold be kept in the directory. These
1063
files do not form a part of the manifest, but are not deleted by the tool.
1064
 
1065
=item B<-delFile=xxx[,yyy]>
1066
 
1067
This option deletes one or more files from the set of kept files. This
1068
option can be specified multiple times.
1069
 
1070
=item B<-test>
1071
 
1072
This option will display what would be copied without actually copying anything
1073
 
1074
=item B<-verbose>
1075
 
1076
This option will display progress information as the program executes.
1077
 
1078
=back
1079
 
1080
=head1 DESCRIPTION
1081
 
1082
This program is used to update a Distribution 'bin' directory with the versions of
1083
packages as indicated by the specified Deployment Manager SBoms.
1084
 
1085
There are two modes of operation: Filter modification operations and BOM creation.
1086
 
1087
In 'Filter modification' mode the current filter set will be updated and the program will
1088
exit.
1089
 
1090
In BOM creation mode an sbomid must be provided.
1091
 
1092
The rtagid is used to get all the required information from Release Manager about
1093
which package version are required, as well as the project name and release name.
1094
 
1095
 
1096
In addition to using Release Manager information to determine which Package/Versions are
1097
required to be copied this script also uses a set of shell wildcard filters that are
1098
used to determine which files are actually copied when invoked.
1099
 
1100
The filter rules can be supplied on the command line if available read from a 
1101
configuration file saved in the output diretory the last time the script was run
1102
on this release directory.
1103
 
1104
One or more filter rules must be specified on the command line the first time this command 
1105
is run against a project release directory.  These filter values are then written to a config
1106
file in the output directory so the same values can be used on subsequent runs.  
1107
In subsequent runs the filter rules will be loaded from the config file and need not be specified 
1108
on the command line, however the filter rules in the config file can be changed by specifying 
1109
them again on the command line and the config will be re-written.
1110
 
1111
=cut
1112