Subversion Repositories DevTools

Rev

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

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