Subversion Repositories DevTools

Rev

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

Rev Author Line No. Line
227 dpurdie 1
########################################################################
2
# Copyright ( C ) 2007 ERG Limited, All rights reserved
3
#
4
# Module name   : jats.sh
5
# Module type   : Makefile system
6
# Compiler(s)   : n/a
7
# Environment(s): jats
8
#
9
# Description   : Determine packages from an SBOM for escrow purposes
10
#                 For a given bom_id determine all used packages
11
#                 Create various bits of useful information
12
#                   Extract commands
13
#                   Build Order
14
#                   Depenendency Info
15
#                   Bad Packages
16
#
17
#
18
#......................................................................#
19
 
20
require 5.6.1;
21
use strict;
22
use warnings;
23
use JatsEnv;
24
use JatsError;
25
use JatsSystem;
26
use JatsRmApi;
27
use DBI;
28
use Getopt::Long;
29
use Pod::Usage;                             # required for help support
30
use Storable qw (dclone);
31
 
32
 
33
#
34
#   Config Options
35
#
36
my $VERSION = "1.0.0";              # Update this
37
my $opt_help = 0;
38
my $opt_manual;
39
my $opt_verbose = $ENV{'GBE_VERBOSE'};      # Allow global verbose
40
my $opt_sbom_id;
41
my $opt_rtag_id;
42
my $opt_test = 0;
43
my $opt_patch = 1;
44
my $opt_extract;
233 dpurdie 45
my $opt_rootpkg;
227 dpurdie 46
 
47
#
48
#   Data Base Interface
49
#
50
my $RM_DB;
51
my $DM_DB;
52
 
53
#
54
#   Global variables
55
#
56
my %os_id_list;                 # os_id in the SBOM
57
my %os_env_list;                # OS Environments
58
my %pv_id;                      # Packages in the SBOM
59
my %Package;                    # Per Package information
60
my %Release;                    # Release information
61
my %Release_pvid;               # Release info
62
my @StrayPackages;              # Non-top level packages
63
my @create_list;                # List of files created
64
my $fpref = "sbom";             # Sbom Prefix
65
our $GBE_RM_URL;
66
our $GBE_DM_URL;
67
 
68
#
69
#   Constants, that should be variable
70
#
71
my $rm_base = "/dependencies.asp?pv_id=";
72
my $dm_base = "/OsDefault.asp?bom_id=BOMID&os_id=";
73
 
74
#
75
#   Build types. Should be populated from a table
76
#
77
my %BM_ID = (
78
    1 => "Solaris",
79
    2 => "Win32",
80
    3 => "Linux",
81
    4 => "Generic",
82
);
83
 
84
my %BSA_ID = (
85
    1 => "Jats Debug",
86
    2 => "Jats Prod",
87
    3 => "Jats Debug+Prod",
88
    4 => "Ant Java 1.4",
89
    5 => "Ant Java 1.5",
90
    6 => "Ant Java 1.6",
91
);
92
 
93
#
94
#   Packages to be ignored
95
#
96
my %ignore;
97
my %patch;
98
 
99
 
100
#-------------------------------------------------------------------------------
101
# Function        : Main
102
#
103
# Description     : Main entry point
104
#                   Parse user options
105
#
106
# Inputs          :
107
#
108
# Returns         :
109
#
110
 
111
my $result = GetOptions (
112
                "help+"         => \$opt_help,              # flag, multiple use allowed
113
                "manual"        => \$opt_manual,            # flag
114
                "verbose+"      => \$opt_verbose,           # flag
115
                "sbomid=s"      => \$opt_sbom_id,           # string
116
                "rtagid=s"      => \$opt_rtag_id,           # string
233 dpurdie 117
                "rootpackage=s" => \$opt_rootpkg,           # String
227 dpurdie 118
                "ignore=s",     => sub{my ($a,$i) = @_; $ignore{$i} = 0 },
119
                "test!"         => \$opt_test,              #[no]flag
120
                "patch!"        => \$opt_patch,             #[no]flag
121
                "extract=s"     => \$opt_extract,           # Name of file
122
                );
123
 
124
#
125
#   Process help and manual options
126
#
127
pod2usage(-verbose => 0, -message => "Version: $VERSION")  if ($opt_help == 1  || ! $result);
128
pod2usage(-verbose => 1)  if ($opt_help == 2 );
129
pod2usage(-verbose => 2)  if ($opt_manual || ($opt_help > 2));
130
 
131
ErrorConfig( 'name'    => 'ESCROW',
132
             'verbose' => $opt_verbose );
133
 
134
#
135
#   Sanity test
136
#
137
unless ( $opt_rtag_id || $opt_sbom_id || $opt_extract)
138
{
139
    Error ("Need sbomid and/or rtagid, or -extract",
140
           "Example: -sbomid=13543, for NZS Phase-1",
141
           "Example: -sbomid=13543 -rtagid=xxxx, for NZS Phase-1, comapred against given release",
142
           "Example: -rtagid=2362, for Sydney R1/R2",
233 dpurdie 143
           "Example: -rtagid=8384 -root=StockholmSBOM",
144
 
227 dpurdie 145
    )
146
}
147
 
148
#
149
#   The extract option is special
150
#   It places the progam in a different mode
151
#
152
if ( $opt_extract )
153
{
154
    Error ("Cannot mix -extract with sbomid or rtagid" )
155
        if ( $opt_rtag_id || $opt_sbom_id );
156
 
157
    extract_files();
158
    exit (0);
159
 
160
}
161
 
162
Warning ("No sbomid provided. Output based an a Release") unless ( $opt_sbom_id );
163
$dm_base =~ s~BOMID~$opt_sbom_id~ if ($opt_sbom_id);
164
$fpref = "release" unless ( $opt_sbom_id );
165
 
166
#
167
#   Import essential EnvVars
168
#
169
EnvImport('GBE_RM_URL');
170
EnvImport('GBE_DM_URL');
171
 
172
$rm_base = $GBE_RM_URL . $rm_base;
173
$dm_base = $::GBE_DM_URL . $dm_base;
174
 
175
if ( $opt_sbom_id )
176
{
177
    #
178
    #   Determines the OS_ID's for the bom
179
    #
180
    getOSIDforBOMID($opt_sbom_id);
181
 
182
    #
183
    #   Locate packages associated with the base install for each os
184
    #
185
    foreach my $base_env_id ( sort keys %os_env_list )
186
    {
187
        getPackagesforBaseInstall( $base_env_id );
188
    }
189
 
190
    #
191
    #   Determine all the top level packages in the BOM
192
    #
193
    foreach my $os_id ( sort keys %os_id_list )
194
    {
195
        getPackages_by_osid( $os_id );
196
    }
197
 
198
    #
199
    #   For each Top Level Package determine the dependent packages
200
    #
201
    foreach my $pv_id ( keys %pv_id )
202
    {
203
        getPkgDetailsByPV_ID( $pv_id);
204
    }
205
    LocateStrays();
206
 
207
    #
208
    #   Determine packages in a given Release
209
    #
210
    if ( $opt_rtag_id )
211
    {
212
        getPkgDetailsByRTAG_ID( $opt_rtag_id );
213
    }
214
}
215
else
216
{
217
    getPkgDetailsByRTAG_ID( $opt_rtag_id );
233 dpurdie 218
    if ( $opt_rootpkg )
227 dpurdie 219
    {
233 dpurdie 220
        #
221
        #   Base the report on a single package in a release
222
        #   Determine the package
223
        #
224
        Error ("Root Package not found: $opt_rootpkg") unless ( exists $Release{$opt_rootpkg} );
225
        my @root_vers = keys %{$Release{$opt_rootpkg}};
226
        Error ("Multiple versions of Root Package: $opt_rootpkg", @root_vers ) if ( $#root_vers > 0 );
227
        Message("Root Package: $opt_rootpkg, " . $root_vers[0]);
228
 
229
        getPkgDetailsByPV_ID( $Release{$opt_rootpkg}{$root_vers[0]}{pv_id} );
227 dpurdie 230
    }
233 dpurdie 231
    else
232
    {
233
my $count = 0;
234
        foreach my $pv_id ( keys %Release_pvid )
235
        {
236
            next if ( $opt_test && ++$count > 2 );
237
            getPkgDetailsByPV_ID( $pv_id);
238
        }
239
    }
240
    LocateStrays(1);
227 dpurdie 241
}
242
 
243
 
244
#
245
#   Remove packages to be ignored
246
#
247
foreach my $pkg ( keys %ignore )
248
{
249
    delete $Package{$pkg};
250
}
251
 
252
##
253
##   Display a list of all packages found so far
254
##
255
#foreach my $name ( sort keys %Package )
256
#{
257
#    foreach my $ver ( sort keys %{$Package{$name}} )
258
#    {
259
#
260
#        my $label = $Package{$name}{$ver}{label} || '';
261
#        my $path = $Package{$name}{$ver}{path} || '';
262
#
263
#        printf ("%30s %15s %45s %s\n", $name, $ver, $label, $path );
264
#    }
265
#}
266
 
267
#
268
#   Generate output files
269
#       1) Jats extract commands
270
#       2) Error list
271
my $file;
272
$file = "${fpref}_extract.txt";
273
push @create_list, $file;
274
open (JE, ">$file" ) || Error ("Cannot create $file");
275
 
276
$file = "${fpref}_status.txt";
277
push @create_list, $file;
278
 
279
open (ST, ">$file" ) || Error("Cannot create $file");
280
print ST "Cannot build:\n";
281
 
282
foreach my $name ( sort keys %Package )
283
{
284
    foreach my $ver ( sort keys %{$Package{$name}} )
285
    {
286
 
287
        my $label = $Package{$name}{$ver}{label} || '';
288
        my $path = $Package{$name}{$ver}{path} || '';
289
        my $mtest = exists ($Package{$name}{$ver}{build} ) || '0';
290
        my @reason1;            # can't extract files
291
        my @reason2;            # Others
292
 
293
        push @reason1, 'No Label' unless ( $label );
294
        push @reason1, 'Bad Label, N/A' if ( $label =~ s~^N/A$~~i || $label  =~ s~^na$~~i );
295
 
296
        push @reason1, 'No Source Path' unless ( $path );
297
        push @reason1, 'Bad Path, N/A' if ( $path =~ m~^N/A$~i || $path  =~ m~^na$~i );
298
        push @reason1, 'Bad Path, dpkg' if ( $path =~ m~^/dpkg_archive~ || $path  =~ m~^dpkg_archive~ );
299
        push @reason1, 'Bad Path, http' if ( $path =~ m~^http:~i );
300
        push @reason1, 'Bad Path, Drive' if ( $path =~ m~^[A-Za-z]\:~ );
301
        push @reason1, 'Bad Path, UNC' if ( $path =~ m~^//~ );
302
        push @reason1, 'Bad Path, Relative' unless ( $path =~ m~^/~ );
303
 
304
 
305
        push @reason2, 'No Build System' unless ( exists ($Package{$name}{$ver}{build} ) );
306
 
307
        unless ( @reason1 )
308
        {
309
            my $vname = "$name $ver";
310
            $vname =~ s~ ~_~g;
311
            $vname =~ s~__~~g;
312
 
233 dpurdie 313
            print JE "jats extract -extractfiles -view=$vname -label=$label -path=\"$path\" -root=. -noprefix\n";
227 dpurdie 314
        }
315
 
316
        if ( @reason1 || @reason2 )
317
        {
318
            $Package{$name}{$ver}{bad_extract} = [@reason1, @reason2];
319
            printf ST "%40s %20s %50s (%s) %s\n", $name, $ver, $label, $mtest, $path ;
320
        }
321
    }
322
}
323
 
324
close (JE);
325
close (ST);
326
 
327
#
328
#   Generate build order info
329
#
330
BuildOrder();
331
 
332
#
333
#   Generate HTML depenedancy information and other useful stuff
334
#
335
GenerateHTML();
336
 
337
 
338
#
339
#   Display names of files created
340
#
341
foreach my $file ( sort @create_list )
342
{
343
    Message ("Created: $file");
344
}
345
exit;
346
 
347
 
348
#-------------------------------------------------------------------------------
349
# Function        : getOSIDforBOMID
350
#
351
# Description     : Get all the os_id's associated with a BOMID
352
#
353
# Inputs          : $bom_id             - BOM to process
354
#
355
# Returns         :
356
#
357
 
358
sub getOSIDforBOMID
359
{
360
    my ($bom_id) = @_;
361
    my $foundDetails = 0;
362
    my (@row);
233 dpurdie 363
Verbose ("getOSIDforBOMID");
227 dpurdie 364
    connectDM(\$DM_DB) unless ($DM_DB);
365
 
366
    my $m_sqlstr = "SELECT distinct os.OS_ID, os.OS_NAME, nn.NODE_NAME, obe.BASE_ENV_ID " .
367
                   " FROM OPERATING_SYSTEMS os, BOM_CONTENTS bc, NETWORK_NODES nn, OS_BASE_ENV obe" .
368
                   " WHERE bc.BOM_ID = $bom_id AND bc.NODE_ID = os.NODE_ID AND nn.NODE_ID = os.NODE_ID AND obe.OS_ID = os.OS_ID ";
369
 
370
    my $sth = $DM_DB->prepare($m_sqlstr);
371
    if ( defined($sth) )
372
    {
373
        if ( $sth->execute( ) )
374
        {
375
            if ( $sth->rows )
376
            {
377
                while ( @row = $sth->fetchrow_array )
378
                {
379
                    Verbose ("OS_ID: ".join (',',@row) );
380
                    $os_id_list{$row[0]}{os_name} = $row[1];
381
                    $os_id_list{$row[0]}{node_name} = $row[2];
382
 
383
                    $os_env_list{$row[3]}{needed} = 1;
384
                    $os_env_list{$row[3]}{os_id}{$row[0]} = 1;
233 dpurdie 385
 
386
                    $foundDetails = 1;
227 dpurdie 387
                }
388
            }
389
            $sth->finish();
390
        }
233 dpurdie 391
        else
392
        {
393
            Error("getOSIDforBOMID:Execute failure" );
394
        }
227 dpurdie 395
    }
396
    else
397
    {
398
        Error("getOSIDforBOMID:Prepare failure" );
399
    }
233 dpurdie 400
 
401
    Error("getOSIDforBOMID:No OS Information Found" ) unless $foundDetails;
402
 
227 dpurdie 403
}
404
 
405
#-------------------------------------------------------------------------------
406
# Function        : getPackagesforBaseInstall
407
#
408
# Description     : Get all the packages for a given base install
409
#
410
# Inputs          :
411
#
412
# Returns         :
413
#
414
 
415
sub getPackagesforBaseInstall
416
{
417
    my ($base_env_id) =@_;
418
    my $foundDetails = 0;
419
    my (@row);
420
 
421
    connectDM(\$DM_DB) unless ($DM_DB);
422
 
423
    # First get details from pv_id
424
 
425
    my $m_sqlstr = "SELECT DISTINCT bec.PROD_ID, pkg.pkg_name, pv.pkg_version, pkg.pkg_id, pv.pv_id" .
426
                " FROM PACKAGES pkg, PACKAGE_VERSIONS pv,PRODUCT_DETAILS pd, BASE_ENV_CONTENTS bec".
427
                " WHERE bec.BASE_ENV_ID = $base_env_id AND bec.PROD_ID (+)= pv.PV_ID AND pv.pkg_id = pkg.pkg_id";
428
 
429
    my $sth = $DM_DB->prepare($m_sqlstr);
430
    if ( defined($sth) )
431
    {
432
        if ( $sth->execute( ) )
433
        {
434
            if ( $sth->rows )
435
            {
436
                while ( @row = $sth->fetchrow_array )
437
                {
438
                    Verbose ("OS ENV Package($base_env_id}:" . join (',',@row) );
439
 
440
                    my $pv_id =     $row[0];
441
                    my $name =      $row[1]  || 'BadName';
442
                    my $ver =       $row[2]  || 'BadVer';
443
 
444
                    $pv_id{$pv_id}{pkg_name} =$name;
445
                    $pv_id{$pv_id}{pkg_ver} = $ver;
446
                    foreach my $os_id ( keys %{$os_env_list{$base_env_id}{os_id}} )
447
                    {
448
                        $pv_id{$pv_id}{os_id}{$os_id} = 2;
449
                    }
450
                }
451
            }
452
            $sth->finish();
453
        }
454
        else
455
        {
456
            Error ("getPackagesforBaseInstall: Execute error");
457
        }
458
    }
459
    else
460
    {
461
        Error("getPackagesforBaseInstall:Prepare failure" );
462
    }
463
 
464
}
465
 
466
 
467
#-------------------------------------------------------------------------------
468
# Function        : getPackages_by_osid
469
#
470
# Description     : Get all the packages used by a given os_id
471
#
472
# Inputs          :
473
#
474
# Returns         :
475
#
476
 
477
my $count = 0;
478
sub getPackages_by_osid
479
{
480
    my ($os_id) =@_;
481
    my $foundDetails = 0;
482
    my (@row);
483
 
484
    connectDM(\$DM_DB) unless ($DM_DB);
485
 
486
    # First get details from pv_id
487
 
488
    my $m_sqlstr = "SELECT osc.*, pkg.pkg_name, pv.pkg_version, pd.IS_REJECTED, pv.IS_PATCH,pv.IS_OBSOLETE, pkg.pkg_id, pv.pv_id" .
489
                " FROM PACKAGES pkg, PACKAGE_VERSIONS pv,PRODUCT_DETAILS pd,".
490
	            "(" .
491
		        " SELECT osc.seq_num, osc.prod_id".
492
		        " FROM os_contents osc".
493
		        " WHERE osc.os_id = $os_id" .
494
	            " ) osc" .
495
                " WHERE pd.PROD_ID (+)= pv.PV_ID" .
496
                "   AND pv.pkg_id = pkg.pkg_id" .
497
                "   AND osc.PROD_ID = pv.pv_id" .
498
                " ORDER BY osc.SEQ_NUM desc" ;
499
 
500
    my $sth = $DM_DB->prepare($m_sqlstr);
501
    if ( defined($sth) )
502
    {
503
        if ( $sth->execute( ) )
504
        {
505
            if ( $sth->rows )
506
            {
507
                while ( @row = $sth->fetchrow_array )
508
                {
509
next if ( $opt_test && ++$count > 2 );
510
                    Verbose ("SBOM Package:".join (',',@row) );
511
                    my $pv_id =     $row[8];
512
                    my $name =      $row[2]  || 'BadName';
513
                    my $ver =       $row[3]  || 'BadVer';
514
 
515
                    $pv_id{$pv_id}{pkg_name} =$name;
516
                    $pv_id{$pv_id}{pkg_ver} = $ver;
517
                    $pv_id{$pv_id}{os_id}{$os_id} = 1;
518
                }
519
            }
520
            $sth->finish();
521
        }
522
    }
523
    else
524
    {
525
        Error("getPackages_by_osid:Prepare failure" );
526
    }
527
}
528
 
529
#-------------------------------------------------------------------------------
530
# Function        : getPkgDetailsByPV_ID
531
#
532
# Description     : Populate the Packages structure given a PV_ID
533
#                   Called for each package in the SBOM
534
#
535
# Inputs          : PV_ID           - Package Unique Identifier
536
#
537
# Returns         : Populates Package
538
#
539
sub getPkgDetailsByPV_ID
540
{
541
    my ($PV_ID) = @_;
542
    my $foundDetails = 0;
543
    my (@row);
544
 
545
    connectRM(\$RM_DB) unless ($RM_DB);
546
 
547
    # First get details from pv_id
548
 
549
    my $m_sqlstr = "SELECT pv.PV_ID, pkg.PKG_NAME, pv.PKG_VERSION, pv.PKG_LABEL, pv.SRC_PATH, pv.IS_DEPLOYABLE, pbi.BSA_ID, pbi.BM_ID" .
550
                    " FROM PACKAGE_VERSIONS pv, PACKAGES pkg, PACKAGE_BUILD_INFO pbi" .
551
                    " WHERE pv.PV_ID = \'$PV_ID\' AND pv.PKG_ID = pkg.PKG_ID AND pv.PV_ID = pbi.PV_ID (+) ";
552
 
553
    my $sth = $RM_DB->prepare($m_sqlstr);
554
    if ( defined($sth) )
555
    {
556
        if ( $sth->execute( ) )
557
        {
558
            if ( $sth->rows )
559
            {
560
                while ( @row = $sth->fetchrow_array )
561
                {
562
                    my $pv_id       = $row[0];
563
                    my $name        = $row[1];
564
                    my $ver         = $row[2];
565
                    my $label       = $row[3] || '';
566
                    my $path        = $row[4] || '';
567
                    my $deployable  = $row[5];
568
                    my $build_info  = $row[6] || '';
569
                    my $build_mach  = $row[7] || '';
570
 
571
                    #
572
                    #   BSA_ID: 1:debug, 2:prod, 3:debug+prod, 4:Java1.4 5: Java 1.5
573
                    #   BM_ID : 1:solaris, 2:win32, 3: linux, 4:generic
574
                    #
575
 
576
 
577
                    #
578
                    #   Does it look like a patch
579
                    #   We may want to ignore it.
580
                    #
581
                    my $patch = "";
582
                    unless ( $opt_patch )
583
                    {
584
                        if ( $ver =~ m~\.p\d+.\w+$~ )
585
                        {
586
                            $patch = "Patch";
587
                            $patch{$name} = 0
588
                                unless (  exists $patch{$name} );
589
                            $patch{$name}++;
590
                        }
591
                    }
592
                    Verbose ("getPkgDetailsByPV_ID: $PV_ID, $name, $ver, $build_mach ,$build_info, $patch");
593
                    next if ( $patch );
594
 
595
 
596
                    if ( exists $ignore{$name} )
597
                    {
598
                        Verbose2( "    Ignoring: $PV_ID, $name, $ver, $build_mach ,$build_info, $patch\n");
599
                        $ignore{$name}++;
600
                        last;
601
                    }
602
 
229 dpurdie 603
                    $path =~ tr~\\/~/~;
227 dpurdie 604
 
605
                    $Package{$name}{$ver}{pvid} = $PV_ID;
606
                    $Package{$name}{$ver}{done} = 1;
607
                    $Package{$name}{$ver}{base} = 1;
608
                    $Package{$name}{$ver}{deployable} = 1 if ($deployable);
609
                    $Package{$name}{$ver}{label} = $label;
610
                    $Package{$name}{$ver}{path} = $path;
611
                    $Package{$name}{$ver}{build}{$build_mach} = $build_info if $build_mach;
612
 
613
                    GetDepends( $pv_id, $name, $ver );
614
 
615
                }
616
            }
617
            else
618
            {
619
                Warning ("No Package details for: PVID: $PV_ID");
620
            }
621
            $sth->finish();
622
        }
623
        else
624
        {
625
            Error("getPkgDetailsByPV_ID: Execute failure", $m_sqlstr );
626
        }
627
    }
628
    else
629
    {
630
        Error("Prepare failure" );
631
    }
632
}
633
 
634
#-------------------------------------------------------------------------------
635
# Function        : GetDepends
636
#
637
# Description     : Extract the dependancies for a given package version
638
#
639
# Inputs          : $pvid
640
#
641
# Returns         :
642
#
643
sub GetDepends
644
{
645
    my ($pv_id, $pname, $pver ) = @_;
646
 
647
    connectRM(\$RM_DB) unless ($RM_DB);
648
 
649
    #
650
    #   Now extract the package dependacies
651
    #
652
    my $m_sqlstr = "SELECT pkg.PKG_NAME, pv.PKG_VERSION, pd.DPV_ID" .
653
                   " FROM PACKAGE_DEPENDENCIES pd, PACKAGE_VERSIONS pv, PACKAGES pkg" .
654
                   " WHERE pd.PV_ID = \'$pv_id\' AND pd.DPV_ID = pv.PV_ID AND pv.PKG_ID = pkg.PKG_ID";
655
    my $sth = $RM_DB->prepare($m_sqlstr);
656
    if ( defined($sth) )
657
    {
658
        if ( $sth->execute( ) )
659
        {
660
            if ( $sth->rows )
661
            {
662
                my %depends;
663
                while ( my @row = $sth->fetchrow_array )
664
                {
665
#print "$pname $pver ===== @row\n";
666
                    my $name = $row[0];
667
                    my $ver = $row[1];
668
 
669
                    Verbose2( "       Depends: $name, $ver");
670
 
671
                    $depends{$name,$ver} = 1;
672
                    $Package{$name}{$ver}{usedby}{$pname,$pver} = 1;
673
 
674
                    unless ( exists $Package{$name}{$ver}{done} )
675
                    {
676
                        my @DATA = ($name, $ver, $row[2]);
677
                        push @StrayPackages, \@DATA;
678
                    }
679
                }
680
                $Package{$pname}{$pver}{depends} = \%depends;
681
            }
682
            $sth->finish();
683
        }
684
    }
685
    else
686
    {
687
        Error("GetDepends:Prepare failure" );
688
    }
689
}
690
 
691
#-------------------------------------------------------------------------------
692
# Function        : getPkgDetailsByRTAG_ID
693
#
233 dpurdie 694
# Description     : Extract all the packages for a given rtag_id
227 dpurdie 695
#
696
# Inputs          : RTAG_ID
697
#
698
# Returns         : 
699
#
700
 
701
sub getPkgDetailsByRTAG_ID
702
{
233 dpurdie 703
    my ($RTAG_ID) = @_;
227 dpurdie 704
    my $foundDetails = 0;
705
    my (@row);
706
 
707
    connectRM(\$RM_DB);
708
 
709
    # First get details from pv_id
710
 
711
    my $m_sqlstr = "SELECT pv.PV_ID, pkg.PKG_NAME, pv.PKG_VERSION".
712
                   " FROM RELEASE_CONTENT rc, PACKAGE_VERSIONS pv, PACKAGES pkg" .
713
                   " WHERE rc.RTAG_ID = $RTAG_ID AND rc.PV_ID = pv.PV_ID AND pv.PKG_ID = pkg.PKG_ID";
714
    my $sth = $RM_DB->prepare($m_sqlstr);
715
    if ( defined($sth) )
716
    {
717
        if ( $sth->execute( ) )
718
        {
719
            if ( $sth->rows )
720
            {
721
                while ( @row = $sth->fetchrow_array )
722
                {
723
                    my $pv_id   = $row[0];
724
                    my $name    = $row[1];
725
                    my $ver     = $row[2];
726
                    Verbose ("getPkgDetailsByRTAG_ID: $RTAG_ID, $name, $ver, $pv_id");
727
 
728
                    $Release{$name}{$ver}{pv_id} = $pv_id;
729
                    $Release_pvid{$pv_id} = 1;
730
                }
731
            }
732
            $sth->finish();
733
        }
734
    }
735
    else
736
    {
737
        Error("getPkgDetailsByRTAG_ID:Prepare failure" );
738
    }
739
}
740
 
741
 
742
#-------------------------------------------------------------------------------
743
# Function        : LocateStrays
744
#
745
# Description     : Locate stray packages
746
#                   These are packages that have not been defined by the
747
#                   top level SBOM. These are not really stray
748
#
749
# Inputs          :
750
#
751
# Returns         :
752
#
753
sub LocateStrays
754
{
233 dpurdie 755
    my ($mode) = @_;
227 dpurdie 756
    while ( $#StrayPackages >= 0 )
757
    {
758
        my $DATA = pop @StrayPackages;
759
        my $name = $DATA->[0];
760
        my $ver = $DATA->[1];
761
        my $pv_id = $DATA->[2];
762
 
763
        next if ( exists $Package{$name}{$ver}{done} );
764
        getPkgDetailsByPV_ID ( $pv_id );
233 dpurdie 765
        if ( $mode )
766
        {
767
            next if ( exists $Release{$name}{$ver} );
768
        }
227 dpurdie 769
        $Package{$name}{$ver}{stray} = 1;
233 dpurdie 770
#print "Stray: $pv_id, $name, $ver\n";
227 dpurdie 771
    }
772
}
773
 
774
#-------------------------------------------------------------------------------
775
# Function        : BuildOrder
776
#
777
# Description     : Determine the order to build packages
778
#
779
# Inputs          :
780
#
781
# Returns         :
782
#
783
sub BuildOrder
784
{
785
    foreach my $name ( keys %Package )
786
    {
787
        foreach my $ver ( keys %{$Package{$name}} )
788
        {
789
            AddToBuildList( $name, $ver, $Package{$name}{$ver}{depends} );
790
        }
791
    }
792
 
793
    DetermineBuildOrder();
794
}
795
 
796
#-------------------------------------------------------------------------------
797
# Function        : AddToBuildList
798
#
799
# Description     : Add packages to a build list
800
#
801
# Inputs          : PackageName
802
#                   PackageVersion
803
#                   Hash of dependancies
804
#
805
# Returns         :
806
#
807
my %BuildList;
808
sub AddToBuildList
809
{
810
    my ($name, $ver, $pdepends ) = @_;
811
 
812
    Warning ("Duplicate Package to build: $name, $ver") if exists $BuildList{$name,$ver};
813
 
814
    #
815
    #   Clone dependancies as we will destroy the list as we process data
816
    #
817
    my $ref;
818
    $ref = dclone ($pdepends ) if $pdepends;
819
    $BuildList{$name,$ver}{depends} = $ref;
820
}
821
 
822
#-------------------------------------------------------------------------------
823
# Function        : DetermineBuildOrder
824
#
825
# Description     : Determine the build order
826
#
827
# Inputs          :
828
#
829
# Returns         :
830
#
831
sub DetermineBuildOrder
832
{
833
 
834
    my $file = "${fpref}_buildinfo.txt";
835
    push @create_list, $file;
836
 
837
    open (BI, ">$file" )  || Error ("Cannot create $file");
838
 
839
#    DebugDumpData ("BuildList", \%BuildList); exit 1;
840
 
841
    my $more = 1;
842
    my $level = 0;
843
    while ( $more )
844
    {
845
        my @build;
846
        $level ++;
847
        $more = 0;
848
        foreach my $key ( keys %BuildList )
849
        {
850
            #
851
            #   Locate packges with no dependencies left
852
            #
853
            next if ( keys %{$BuildList{$key}{depends}} );
854
            push @build, $key;
855
        }
856
 
857
        foreach my $build ( @build )
858
        {
859
            $more = 1;
860
            delete $BuildList{$build};
861
            my ($name, $ver) = split $;, $build;
862
 
863
            my $label = $Package{$name}{$ver}{label} || '';
864
            my $path  = $Package{$name}{$ver}{path} || '';
865
            $Package{$name}{$ver}{buildorder}  = $level;
866
 
867
            printf BI "Build(%2d): %40s %15s %-55s %s\n", $level, $name, $ver, $label, $path;
868
        }
869
 
870
        #
871
        #   Delete dependencies
872
        #
873
        foreach my $key ( keys %BuildList )
874
        {
875
            foreach my $build ( @build )
876
            {
877
                delete $BuildList{$key}{depends}->{$build};
878
            }
879
        }
880
    }
881
    close BI;
882
}
883
 
884
#-------------------------------------------------------------------------------
885
# Function        : GenerateHTML
886
#
887
# Description     : Generate Dependency information
888
#                   Generate a nive HTML dependancy table
889
#                   Shows DependOn and UsedBy
890
# Inputs          :
891
#
892
# Returns         :
893
#
894
 
895
sub GenerateHTML
896
{
897
    my $td = '<td style="vertical-align: top;">' . "\n";
898
    my $td3 = '<td style="vertical-align: top;" colspan="3">' . "\n";
899
    my $tdr = '<td style="text-align: right;">';
900
 
901
    my $file = "${fpref}_depends.html";
902
    push @create_list, $file;
903
    open (DP, ">$file" )  || Error ("Cannot create $file");
904
 
905
    #
906
    #   Generate an index
907
    #
908
    print DP "<dl><dt><h1>Index</h1></dt>\n";
909
    print DP "<dd><a href=\"#Ignore\">Ignored Packages</a></dd>\n";
910
    print DP "<dd><a href=\"#Depend\">Dependency Info</a></dd>\n";
911
    print DP "<dd><a href=\"#Multi\">Multiple Package Version</a></dd>\n";
233 dpurdie 912
    print DP "<dd><a href=\"#Leaf\">Packages that have no parents</a></dd>\n";
227 dpurdie 913
    print DP "<dd><a href=\"#NoBuild\">Packages that cannot be built</a></dd>\n";
914
    print DP "<dd><a href=\"#Excess\">Excess Packages from Release: $opt_rtag_id</a></dd>\n" if ( $opt_rtag_id && $opt_sbom_id );
915
    print DP "<dd><a href=\"#Stray\">Required Packages, not part of the release</a></dd>\n" if ( $opt_rtag_id && !$opt_sbom_id );
916
    print DP "<dd><a href=\"#Inconsistent\">Packages in the Release, with inconsistent dependencies</a></dd>\n" if ( $opt_rtag_id && !$opt_sbom_id );
917
 
918
    print DP "</dl>\n";
919
 
920
    #
921
    #   Ignored Packages
922
    #
923
    print DP "<h1><a name=\"Ignore\">Ignored Packages</a></h1>\n";
924
 
925
    print DP "The following package, and all dependents, have been ignored.<br><br>\n";
926
 
927
    foreach my $name ( sort keys %ignore )
928
    {
929
        print DP "$name: $ignore{$name} versions<br>\n";
930
    }
931
 
932
    unless ( $opt_patch )
933
    {
934
        print DP "The following package have patches that have been ignored.<br><br>\n";
935
        foreach my $name ( sort keys %patch )
936
        {
937
            print DP "$name: $patch{$name} patches<br>\n";
938
        }
939
    }
940
 
941
    #
942
    #   Dependency Information
943
    #
944
    print DP "<h1><a name=\"Depend\">Dependency Info</a></h1>\n";
945
 
946
    print DP "<table border=\"1\"><tbody>\n";
947
    print DP "<tr>\n";
948
    print DP "<th>Package Dependency</th>\n";
949
    print DP "<th>Package Used by</th>\n";
950
    print DP "<th>Build Info</th>\n";
951
    print DP "</tr>\n";
952
 
953
    foreach my $name ( sort keys %Package )
954
    {
955
        foreach my $ver ( sort keys %{$Package{$name}} )
956
        {
957
            print DP "<tr>\n";
958
            #
959
            #   Depends On info
960
            #
961
 
962
            print DP $td;
963
            my $anchor= "${name}_${ver}";
964
            my $tag = "usedby_${name}_${ver}";
965
            printf  DP "<dl><dt><a name=\"$anchor\"></a><a href=\"#$tag\">%s&nbsp;%s</a> Depends on:</dt>\n", $name, $ver;
966
            foreach my $depend ( sort keys %{$Package{$name}{$ver}{depends}} )
967
            {
968
                my ($dname, $dver) = split $;, $depend;
969
                my $tag = "${dname}_${dver}";
970
                printf  DP "    <dd><a href=\"#$tag\">%s&nbsp;%s</a></dd>\n", $dname, $dver;
971
            }
972
            print DP "</dl>\n";
973
            print DP "</td>\n";
974
 
975
 
976
            #
977
            #   Used By information
978
            #
979
            print DP $td;
980
            $anchor= "usedby_${name}_${ver}";
981
            $tag = "${name}_${ver}";
982
            printf  DP "<dl><dt><a name=\"$anchor\"></a><a href=\"#$tag\">%s&nbsp;%s</a> Used by:</dt>\n", $name, $ver;
983
            foreach my $depend ( sort keys %{$Package{$name}{$ver}{usedby}} )
984
            {
985
                my ($dname, $dver) = split $;, $depend;
986
                my $tag = "usedby_${dname}_${dver}";
987
                printf  DP "    <dd><a href=\"#$tag\">%s&nbsp;%s</a></dd>\n", $dname, $dver;
988
            }
989
            print DP "</dl>\n";
990
            print DP "</td>\n";
991
 
992
            #
993
            #   Build Info
994
            #
995
            print DP $td;
996
            print DP "<table>";
997
            my $stray = ( exists ($Package{$name}{$ver}{stray}) && $Package{$name}{$ver}{stray} );
998
 
999
            my $pv_id = $Package{$name}{$ver}{pvid} || 'No PVID';
1000
            my $pv_id_ref = $rm_base . $pv_id;
1001
               $pv_id_ref .= "&rtag_id=" . $opt_rtag_id if ($opt_rtag_id && !$stray);
233 dpurdie 1002
            my $pv_id_str = "<a href=\"$pv_id_ref\" TARGET=\"_blank\">$pv_id</a>";
227 dpurdie 1003
 
1004
            printf DP "<tr>${tdr}Pvid:</td><td>%s</td></tr>\n", $pv_id_str;
1005
            printf DP "<tr>${tdr}Label:</td><td>%s</td></tr>\n", $Package{$name}{$ver}{label} || 'NoneProvided';
1006
            printf DP "<tr>${tdr}Path:</td><td>%s</td></tr>\n", $Package{$name}{$ver}{path}  || 'NoneProvided';
1007
 
1008
            my $order = 'Not Built';
1009
            my @machs;
1010
 
1011
            if ( exists($Package{$name}{$ver}{build}) )
1012
            {
1013
                $order = $Package{$name}{$ver}{buildorder};
1014
                @machs = sort keys %{$Package{$name}{$ver}{build}};
1015
            }
1016
            else
1017
            {
1018
                my $tag = "notbuilt_${name}_${ver}";
1019
                $order = "<a href=\"#$tag\">Not Built</a>"
1020
            }
1021
 
1022
            printf DP "<tr>${tdr}Build Order:</td><td>%s</td></tr>\n", $order;
1023
 
1024
            my $text = "Build:";
1025
            foreach my $mach ( @machs )
1026
            {
1027
                my $type = $Package{$name}{$ver}{build}{$mach};
1028
                printf DP "<tr>${tdr}$text</td><td>%s&nbsp;%s</td></tr>\n", $BM_ID{$mach} || "Unknown, $mach", $BSA_ID{$type} || 'Unknown';
1029
                $text = '';
1030
            }
1031
 
1032
            my $pvid = $Package{$name}{$ver}{pvid};
1033
            $text = "Deployed:";
1034
            foreach my $osid ( sort keys %{ $pv_id{$pvid}{os_id}  } )
1035
            {
1036
                my $os_name = $os_id_list{$osid}{os_name};
1037
                my $node =    $os_id_list{$osid}{node_name};
1038
 
1039
                my $ref = $dm_base . $osid;
1040
                my $str = "<a href=\"$ref\">$node,($os_name)</a>";
1041
 
1042
 
1043
                printf DP "<tr>${tdr}$text</td><td>$str</td></tr>\n";
1044
                $text = '';
1045
            }
1046
 
1047
            if ( $stray )
1048
            {
1049
                printf DP "<tr>${tdr}Stray:</td><td>Package included indirectly</td></tr>\n";
1050
            }
1051
 
1052
 
1053
 
1054
            print DP "</table>";
1055
            print DP "</td>\n";
1056
 
1057
            #
1058
            #   End of Row
1059
            #
1060
            print DP "</tr>\n";
1061
        }
1062
    }
1063
    print DP "</tbody></table>\n";
1064
 
1065
 
1066
    #
1067
    #   Multiple versions of a package
1068
    #
1069
    print DP "<h1><a name=\"Multi\">Multiple Package Versions</a></h1>\n";
1070
    print DP "<table border=\"1\"><tbody>\n";
1071
    print DP "<tr>\n";
1072
    print DP "<th>Multiple Versions</th>\n";
1073
    print DP "</tr>\n";
1074
 
1075
    foreach my $name ( sort keys %Package )
1076
    {
1077
        my @versions = keys %{$Package{$name}};
1078
        next unless ( $#versions > 0 );
1079
        print DP "<tr>\n";
1080
        print DP $td;
1081
        printf  DP "<dl><dt>$name</a> Versions:<dt>\n";
1082
 
1083
        foreach my $ver ( sort @versions )
1084
        {
1085
            my $tag = "${name}_${ver}";
1086
            printf  DP "    <dd>";
1087
            printf  DP "<a href=\"#$tag\">%s&nbsp;%s</a>\n", $name, $ver;
1088
            print   DP " - Not in Release" if ($opt_rtag_id && $Package{$name}{$ver}{stray});
1089
            printf  DP "</dd>\n", $name, $ver;
1090
        }
1091
        print DP "</dl>\n";
1092
        print DP "</td>\n";
1093
        print DP "</tr>\n";
1094
    }
1095
    print DP "</tbody></table>\n";
1096
 
1097
 
1098
    #
233 dpurdie 1099
    #   Leaf Packages
1100
    #
1101
    print DP "<h1><a name=\"Leaf\">Packages that have no parents</a></h1>\n";
1102
    print DP "<table border=\"1\"><tbody>\n";
1103
    print DP "<tr>\n";
1104
    print DP "<th>Leaf Packages</th>\n";
1105
    print DP "</tr>\n";
1106
 
1107
    foreach my $name ( sort keys %Package )
1108
    {
1109
        foreach my $ver ( sort keys %{$Package{$name}} )
1110
        {
1111
            my @usedby = keys %{$Package{$name}{$ver}{usedby}};
1112
            next if ( @usedby );
1113
 
1114
            print DP "<tr>\n";
1115
            print DP $td;
1116
 
1117
            my $tag = "${name}_${ver}";
1118
 
1119
            printf  DP "<dt><a href=\"#$tag\">%s&nbsp;%s</a>\n", $name, $ver;
1120
 
1121
            print DP "</td>\n";
1122
            print DP "</tr>\n";
1123
        }
1124
    }
1125
    print DP "</tbody></table>\n";
1126
 
1127
 
1128
 
1129
    #
227 dpurdie 1130
    #   Packages that cannot be built
1131
    #
1132
    print DP "<h1><a name=\"NoBuild\">Packages that cannot be built</a></h1>\n";
1133
    print DP "<table border=\"1\"><tbody>\n";
1134
    print DP "<tr>\n";
1135
    print DP "<th>Not Built</th>\n";
1136
    print DP "</tr>\n";
233 dpurdie 1137
    my $no_build_count = 0;
227 dpurdie 1138
 
1139
    foreach my $name ( sort keys %Package )
1140
    {
1141
        my @versions = keys %{$Package{$name}};
1142
        foreach my $ver ( sort @versions )
1143
        {
1144
            next unless exists($Package{$name}{$ver}{bad_extract});
233 dpurdie 1145
            $no_build_count++;
227 dpurdie 1146
            my @reasons = @{$Package{$name}{$ver}{bad_extract}};
1147
 
1148
            print DP "<tr><dl>\n";
1149
            print DP $td;
1150
 
1151
            my $tag = "${name}_${ver}";
1152
            my $anchor = "notbuilt_${name}_${ver}";
1153
 
1154
            printf  DP "<dt><a name=\"$anchor\"></a><a href=\"#$tag\">%s&nbsp;%s</a></dt>\n", $name, $ver;
1155
            foreach my $reason ( @reasons )
1156
            {
1157
                print  DP "<dd>$reason</dd>\n";
1158
            }
1159
 
1160
 
1161
            print DP "</dl>\n";
1162
            print DP "</td>\n";
1163
            print DP "</tr>\n";
1164
 
1165
        }
1166
    }
233 dpurdie 1167
    print DP "<tr>\n";
1168
    print DP "<th>Total Count: $no_build_count</th>\n";
1169
    print DP "</tr>\n";
1170
 
227 dpurdie 1171
    print DP "</tbody></table>\n";
1172
 
1173
    #
1174
    #   Packages that are in a specified release, but not described by the SBOM
1175
    #
1176
    if ( $opt_rtag_id && $opt_sbom_id )
1177
    {
1178
        print DP "<h1><a name=\"Excess\">Excess Packages from Release: $opt_rtag_id</a></h1>\n";
1179
        print DP "<table border=\"1\"><tbody>\n";
1180
        print DP "<tr>\n";
1181
        print DP '<th colspan="3">Excess Packages</th>';
1182
        print DP "</tr>\n";
1183
 
1184
        print DP "<tr>\n";
1185
        print DP '<th>Package</th>';
1186
        print DP '<th>PVID</th>';
1187
        print DP '<th>Used Package</th>';
1188
        print DP "</tr>\n";
1189
 
1190
        my $were_found = 0;
1191
        my $not_found = 0;
1192
        foreach my $name ( sort keys %Release )
1193
        {
1194
            my @versions = keys %{$Release{$name}};
1195
            foreach my $ver ( sort @versions )
1196
            {
1197
                if (exists($Package{$name}{$ver}))
1198
                {
1199
                    $were_found++;
1200
                    next;
1201
                }
1202
                $not_found++;
1203
 
1204
                print DP "<tr>\n";
1205
                print DP $td;
1206
 
1207
                my $pv_id = $Release{$name}{$ver}{pv_id} || 'No PVID';
1208
                my $pv_id_ref = $rm_base . $pv_id . "&rtag_id=" . $opt_rtag_id;
233 dpurdie 1209
                my $pv_id_str = "<a href=\"$pv_id_ref\" TARGET=\"_blank\">$pv_id</a>";
227 dpurdie 1210
 
1211
                printf  DP "$name $ver ", $name, $ver;
1212
                print DP "</td>\n";
1213
 
1214
                print DP $td;
1215
                printf DP "Pvid: %s\n", $pv_id_str;
1216
                print DP "</td>\n";
1217
 
1218
                print DP $td;
1219
                my @pver = keys %{$Package{$name}};
1220
                if (@pver)
1221
                {
1222
                    printf  DP "<dl><dt> Uses Versions:<dt>\n";
1223
                    foreach my $ver ( sort @pver  )
1224
                    {
1225
                        my $tag = "${name}_${ver}";
1226
                        printf  DP "    <dd><a href=\"#$tag\">%s&nbsp;%s</a></dd>\n", $name, $ver;
1227
                    }
1228
                    print DP "</dl>\n";
1229
                }
1230
                else
1231
                {
1232
                    printf DP "No Versions of this package used\n"
1233
                }
1234
                print DP "</td>\n";
1235
 
1236
 
1237
                print DP "</tr>\n";
1238
            }
1239
        }
1240
 
1241
        print DP "<tr>\n";
1242
        print DP $td3;
1243
        print DP "Packages found in SBOM: $were_found";
1244
        print DP "</td>\n";
1245
        print DP "</tr>\n";
1246
 
1247
        print DP "<tr>\n";
1248
        print DP $td3;
1249
        print DP "Packages NOT found in SBOM: $not_found";
1250
        print DP "</td>\n";
1251
        print DP "</tr>\n";
1252
 
1253
        print DP "</tbody></table>\n";
1254
    }
1255
 
1256
    #
1257
    #   Packages that are strays
1258
    #   They are not top level packages in the release
1259
    #
1260
    if ( $opt_rtag_id && !$opt_sbom_id )
1261
    {
1262
        print DP "<h1><a name=\"Stray\">Required Packages, not part of the release</a></h1>\n";
1263
        print DP "<table border=\"1\"><tbody>\n";
1264
        print DP "<tr>\n";
1265
        print DP '<th colspan="3">Stray Packages</th>';
1266
        print DP "</tr>\n";
1267
 
1268
        print DP "<tr>\n";
1269
        print DP '<th>Inconsisient Package</th>';
1270
        print DP '<th>PVID</th>';
1271
        print DP '<th>Preferred Package</th>';
1272
        print DP "</tr>\n";
1273
 
1274
        foreach my $name ( sort keys %Package )
1275
        {
1276
 
1277
            my @versions = keys %{$Package{$name}};
1278
            foreach my $ver ( sort @versions )
1279
            {
1280
                unless (exists($Package{$name}{$ver}{stray}) && $Package{$name}{$ver}{stray} )
1281
                {
1282
                    next;
1283
                }
1284
 
1285
                #
1286
                #   Determine preferred package version(s)
1287
                #   These will be those without a 'stray' tag
1288
                #
1289
                my @preferred = ();
1290
                foreach my $pver ( keys %{$Package{$name}} )
1291
                {
1292
                    next if (exists($Package{$name}{$pver}{stray} ) && $Package{$name}{$pver}{stray} );
1293
                    push @preferred, $pver;
1294
                }
1295
 
1296
                print DP "<tr>\n";
1297
 
1298
                #
1299
                #  Package name and Used By information
1300
                #
1301
                print DP $td;
1302
                my $anchor= "usedby_${name}_${ver}";
1303
                my $tag = "${name}_${ver}";
1304
                printf  DP "<dl><dt><a name=\"$anchor\"></a><a href=\"#$tag\">%s&nbsp;%s</a> Used by:</dt>\n", $name, $ver;
1305
                foreach my $depend ( sort keys %{$Package{$name}{$ver}{usedby}} )
1306
                {
1307
                    my ($dname, $dver) = split $;, $depend;
1308
                    my $tag = "usedby_${dname}_${dver}";
1309
                    printf  DP "    <dd><a href=\"#$tag\">%s&nbsp;%s</a></dd>\n", $dname, $dver;
1310
                }
1311
                print DP "</dl>\n";
1312
                print DP "</td>\n";
1313
 
1314
 
1315
                my $pv_id = $Package{$name}{$ver}{pvid} || 'No PVID';
1316
 
1317
                my $pv_id_ref = $rm_base . $pv_id;
233 dpurdie 1318
                my $pv_id_str = "<a href=\"$pv_id_ref\" TARGET=\"_blank\">$pv_id</a>";
227 dpurdie 1319
 
1320
                print DP $td;
1321
                printf DP "Pvid: %s\n", $pv_id_str;
1322
                print DP "</td>\n";
1323
 
1324
                #
1325
                #   Insert Preferred package(s)
1326
                #
1327
                print DP $td;
1328
                print DP "<table>\n";
1329
                foreach my $pver ( sort @preferred )
1330
                {
1331
                    my $tag = "${name}_${pver}";
1332
                    printf  DP "<tr><td><a href=\"#$tag\">%s&nbsp;%s</a></td></tr>\n", $name, $pver;
1333
                }
1334
 
1335
                print DP "</table>\n";
1336
                print DP "</tr>\n";
1337
 
1338
            }
1339
        }
1340
 
1341
        print DP "</tbody></table>\n";
1342
    }
1343
 
1344
    #
1345
    #   Packages that have components not in the release
1346
    #   They are not top level packages in the release
1347
    #
1348
    if ( $opt_rtag_id && !$opt_sbom_id )
1349
    {
1350
        print DP "<h1><a name=\"Inconsistent\">Packages in the Release, with inconsistent dependencies</a></h1>\n";
1351
        print DP "<table border=\"1\"><tbody>\n";
1352
 
1353
        print DP "<tr>\n";
1354
        print DP '<th>Inconsisient Package</th>';
1355
        print DP "</tr>\n";
1356
 
1357
        foreach my $name ( sort keys %Package )
1358
        {
1359
 
1360
            my @versions = keys %{$Package{$name}};
1361
            foreach my $ver ( sort @versions )
1362
            {
1363
                #
1364
                #   Ignore 'stray' packages
1365
                #
1366
                next if (exists($Package{$name}{$ver}{stray}) && $Package{$name}{$ver}{stray} );
1367
 
1368
                #
1369
                #   Is it inconsitient
1370
                #
1371
                my $ok = 1;
1372
                foreach my $depend ( sort keys %{$Package{$name}{$ver}{depends}} )
1373
                {
1374
                    my ($dname, $dver) = split $;, $depend;
1375
                    if (exists($Package{$dname}{$dver}{stray}) && $Package{$dname}{$dver}{stray} )
1376
                    {
1377
                        $ok = 0;
1378
                        last;
1379
                    }
1380
                }
1381
 
1382
                next if ( $ok );
1383
 
1384
 
1385
                #
1386
                #   Depends On info
1387
                #
1388
 
1389
                print DP "<tr>\n";
1390
                print DP $td;
1391
                my $anchor= "${name}_${ver}";
1392
                my $tag = "usedby_${name}_${ver}";
1393
                printf  DP "<dl><dt><a name=\"$anchor\"></a><a href=\"#$tag\">%s&nbsp;%s</a> Inconsistent::</dt>\n", $name, $ver;
1394
                foreach my $depend ( sort keys %{$Package{$name}{$ver}{depends}} )
1395
                {
1396
                    my ($dname, $dver) = split $;, $depend;
1397
                    next unless (exists($Package{$dname}{$dver}{stray}) && $Package{$dname}{$dver}{stray} );
1398
 
1399
                    my $tag = "${dname}_${dver}";
1400
                    printf  DP "    <dd><a href=\"#$tag\">%s&nbsp;%s</a></dd>\n", $dname, $dver;
1401
                }
1402
                print DP "</dl>\n";
1403
                print DP "</td>\n";
1404
                print DP "<tr>\n";
1405
 
1406
            }
1407
        }
1408
 
1409
        print DP "</tbody></table>\n";
1410
    }
1411
 
1412
 
1413
 
1414
 
1415
    close DP;
1416
}
1417
 
1418
#-------------------------------------------------------------------------------
1419
# Function        : extract_files
1420
#
1421
# Description     : Alternate mode of operation
1422
#                   Extract files from the generated list. This is intended to
1423
#                   be run as a sperate phase taking the 'extract' file
1424
#
1425
# Inputs          :
1426
#
1427
# Returns         : 
1428
#
1429
sub extract_files
1430
{
1431
    my @extract_order;
1432
    my %extract;
1433
    ErrorConfig( 'name'    => 'ESCROW-EXTRACT' );
1434
 
1435
    #
1436
    #   Open the file and read in data in one hit
1437
    #   This will detect file errors early
1438
    #
1439
    Error ("Cannot find specified file: $opt_extract")
1440
        unless ( -f $opt_extract );
1441
 
1442
    open (FH, "<$opt_extract" ) || Error ("Cannot open file");
1443
    while ( <FH> )
1444
    {
1445
        s~[\r\n]+$~~;
1446
        next unless ( $_ );
1447
 
1448
        my ($view, $label, $path);
1449
        foreach ( split ' ', $_ )
1450
        {
1451
            if ( m~^-view=(.+)~ ) {
1452
                $view = $1;
1453
            } elsif ( m~^-label=(.+)~ ) {
1454
                $label = $1;
1455
            } elsif ( m~^-path=(.+)~ ) {
1456
                $path = $1;
233 dpurdie 1457
                $path =~ s~\"~~g
227 dpurdie 1458
            }
1459
        }
1460
 
1461
        Error "Duplicate view name: $view" if ( exists $extract{$view} );
1462
        Error "Bad file format in line: $_" unless ( $view && $label );
1463
        push @extract_order, $view;
1464
        $extract{$view}{label} = $label;
1465
        $extract{$view}{path} = $path;
1466
    }
1467
    close FH;
1468
 
1469
    #
1470
    #   Log the file processing
1471
    #
1472
    my $lfile = "${opt_extract}.log";
1473
    open (FH, ">$lfile" ) || Error ("Cannot open log file: $lfile");
1474
 
1475
    #
1476
    #   Process each entry
1477
    #
1478
    foreach my $view ( @extract_order )
1479
    {
1480
        my $label = $extract{$view}{label};
1481
        my $path = $extract{$view}{path};
1482
        my $rv = JatsCmd ("extract -extractfiles -view=$view -label=$label -path=$path -root=. -noprefix");
1483
        print FH "$view : SUCCESS\n" unless $rv;
1484
        print FH "$view : ERROR\n" if $rv;
1485
    }
1486
    close FH;
1487
 
1488
}
1489
 
1490
 
1491
#-------------------------------------------------------------------------------
1492
#   Documentation
1493
#
1494
 
1495
=pod
1496
 
1497
=head1 NAME
1498
 
1499
escrow - Extract Escrow Build Information
1500
 
1501
=head1 SYNOPSIS
1502
 
1503
  jats escrow [options]
1504
 
1505
 Options:
1506
    -help              - brief help message
1507
    -help -help        - Detailed help message
1508
    -man               - Full documentation
1509
    -sbomid=xxx        - Specify the SBOM to process
1510
    -rtagid=xxx        - Specify the Release to process (Optional)
1511
    -ignore=name       - Ignore packages with the specified name
1512
    -extract=fname     - Extract files from a previous run
1513
    -verbose           - Enable verbose output
1514
    -[no]patch         - Ignore/Include patches. Default:Include
1515
    -[no]test          - Reduced package scanning for test
1516
 
1517
=head1 OPTIONS
1518
 
1519
=over 8
1520
 
1521
=item B<-help>
1522
 
1523
Print a brief help message and exits.
1524
 
1525
=item B<-help -help>
1526
 
1527
Print a detailed help message with an explanation for each option.
1528
 
1529
=item B<-man>
1530
 
1531
Prints the manual page and exits.
1532
 
1533
=item B<-sbomid=xxx>
1534
 
1535
This option is mandatory. It specifies the SBOM to process. The sbomid must be
1536
determined from Deployment Manager.
1537
 
1538
=item B<-rtagid=xxx>
1539
 
1540
If provided, this option specifies an RTAG_ID to process in conjunction with the SBOM.
1541
The RTAG_ID must be determined from Release Manager. The program will determine
1542
packages that are in th Release, but not in the SBOM.
1543
 
1544
=item B<-ignore=name>
1545
 
1546
All versions of the named package will be ignored. This parameter is options.
1547
It may be used multiple times.
1548
 
1549
=item B<-extract=name>
1550
 
1551
This option will process the 'extract' file created in a previous run of this
1552
program and extract source files for the package-versions found in the file.
1553
 
1554
The command will then create a log file recording packages that could ne be
1555
extracted.
1556
 
1557
This option cannot be used in conjunction wit the -rtagid or -sbomid.
1558
 
1559
=item B<-[no]patch>
1560
 
1561
This option is used ignore patches. If -nopatch is selected, then packages
1562
versions that look like a patch will be added to the ignore list.
1563
 
1564
=item B<-[no]test>
1565
 
1566
This option is used for testing. It will only process the first two OS entries
1567
in the SBOM. This speeds up processing. It does not generate a complete list of
1568
packages.
1569
 
1570
=item B<verbose>
1571
 
1572
This option will display progress information as the program executes.
1573
 
1574
=back
1575
 
1576
=head1 DESCRIPTION
1577
 
1578
This program is a tool for extracting Escrow build information.
1579
 
1580
Given an SBOM_ID this program will:
1581
 
1582
=over 8
1583
 
1584
=item * Determine all the NODES in the SBOM
1585
 
1586
=item * Determine all the Base Packages for each NODE
1587
 
1588
=item * Determine all the Packages for each NODE
1589
 
1590
=item * Determine all the dependent packages for all packages encountered
1591
 
1592
=item * Generate a list of jats commands to extract the package source
1593
 
1594
=item * Generate a file describing the build order
1595
 
1596
=item * Generate a file describing the packages that cannot be built
1597
 
1598
=item * Generate an HTML file with extensive cross reference information
1599
 
1600
=over 8
1601
 
1602
=item * List of all packages with references into Release Manager
1603
 
1604
=item * List of all packages showing dependent packages
1605
 
1606
=item * List of all packages showing consumer packages
1607
 
1608
=item * List of all packages for which multiple versions are required
1609
 
1610
=item * Details of packages that are not built.
1611
 
1612
=item * Build order
1613
 
1614
=item * Build machines and built types
1615
 
1616
=item * Deployed target nodes, with references into deployment manager
1617
 
1618
=back
1619
 
1620
=back
1621
 
1622
This may take some time, as a typical escrow build may contain many hundreds of packages.
1623
 
1624
The program will display a list of files that have been created.
1625
 
1626
Given an 'extract' file from a previous run of this program the program will:
1627
 
1628
=over 8
1629
 
1630
=item * Parse the 'extract' file
1631
 
1632
=item * Create subdirectoroes for each package version within the file. This is done
1633
in such a way that no views are left in place.
1634
 
1635
=item * Create a log file showing packages that could not be extracted.
1636
 
1637
 
1638
=back
1639
 
1640
=cut
1641