Subversion Repositories DevTools

Rev

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

Rev Author Line No. Line
1119 dpurdie 1
########################################################################
6302 dpurdie 2
# COPYRIGHT - VIX IP PTY LTD ("VIX"). ALL RIGHTS RESERVED.
1119 dpurdie 3
#
6302 dpurdie 4
# Module name   : ManifestFiles.pm
1119 dpurdie 5
# Module type   : Makefile system
6302 dpurdie 6
# Environment(s): JATS Build System
5654 dpurdie 7
# Documents     : MASS-00232 Format of the Linux App Upgrade Manifest File
1119 dpurdie 8
#
9
# Description   : This package extends the JATS toolset at build time
10
#                 It provides additional directives to the JATS makefiles
11
#                 to simplify the directives.
12
#
13
#                 This directive does all its work at 'build' time
14
#                 It uses makefile.pl directives
15
#
16
# Operation     : This package adds the JATS directive ManifestFiles
17
#                 This is used to create linux manifest files
18
#
19
# Syntax        : ManifestFiles (<platforms>, Options+);
20
#                 See the function header for details
21
#
22
#......................................................................#
23
 
24
require 5.6.1;
25
use strict;
26
use warnings;
6306 dpurdie 27
use ArrayHashUtils;
1119 dpurdie 28
 
29
#
30
#   Globals
6932 dpurdie 31
#   These are exposed to all of JATS, so:
32
#       Limit the number (ideally none)
33
#       Be away of the potential name conflicts
1119 dpurdie 34
#
35
 
36
#-------------------------------------------------------------------------------
37
# Function        : BEGIN
38
#
39
# Description     : Setup directive hooks
40
#                   Register a function to be called just before we start to
41
#                   generate makefiles. This will be used to process the data
42
#                   collected in all the ManifestFiles directives
43
#
44
# Inputs          : None
45
#
46
# Returns         : None
47
#
48
BEGIN
49
{
6932 dpurdie 50
    RegisterMakefileGenerate (\&ManifestFiles::Generate);
1119 dpurdie 51
}
52
 
53
#-------------------------------------------------------------------------------
54
# Function        : ManifestFiles
55
#
56
# Description     : Create a ManifestFiles entry
57
#
58
# Inputs          : Platform             - Active Platform Selector
59
#                   Options              - One or more options
60
#                       --Name=Name             - Mandatory
61
#                       --Tier=Name             - Mandatory
62
#                       --Architecture=xxxx     - Default actitecture is the current target
63
#                       --Product=yyyy          - Product Family
64
#                       --Debian=BaseName[,--Prod,--Debug,--Arch=xxxx,--Product=yyyy]
6302 dpurdie 65
#                       --Apk=BaseName[,--Prod,--Debug,--Platform=pppp]
66
#                                                   Default platform = ANDROID
67
#                                                   Default type = Production
1119 dpurdie 68
#                       --MugPackage=Package[,--Subdir=subdir[,subdir]+]
69
#                       --SrcFile=xxx
1125 alewis 70
#                       --SrcFileNoCopy=xxx
1123 dpurdie 71
#                       --Comment=xxx           - Add comment to Manifst
1125 alewis 72
#                       --NoManifestVersion     - Create unversioned Manifest File
73
#                       --PkgSubdir=xxx         - Specifies packaging subdir
5105 dpurdie 74
#                       --ImportManifest=Package[,--Subdir=subdir,--ReWrite] - Import Manifest from package
5649 dpurdie 75
#                       --Md5                   - Add MD5 checksums to the Manifest File
5767 alewis 76
#                       --Dmf                   - Generate the Device Management Framework
77
#                                                 combined archive ZIP file.
78
#                       --DmfVersion=xxxx       - Generate the Device Management Framework
79
#                                                 combined archive ZIP using a modified
80
#                                                 version number; only for testing!
6364 dpurdie 81
#                       --LineLength=nnn        - Limit line length. Default is 79
82
#                       --SubManifest           - Create a sub-manifest (not installable). Manifest will have no version.
83
#                                                 Gives a default name, tier and subdir if not explicitly provided.
6932 dpurdie 84
#                       --NoSignatures          - Prevent the generation of .sig files
85
#                                                 Default is to generate .sigFiles
6978 dpurdie 86
#                       --ManifestInsertionPoint[,--All,--Name,--Name=xxxx,--Tier,--Tier=Name,--Current]
87
#                                                 Create template insertion hook
88
#                       --Template=Package[,--Subdir=subdir,File=name]                                                                           
6932 dpurdie 89
#                       --NoWarn                - Supress warnings about unused packages
90
#                                                 Will supress sanity test. Useful when generating multiple
91
#                                                 manifests.                          
92
#                                                 
93
# Notes: On sig file generation
94
#   This tool will use an internal key file to generate signatures
95
#   UNLESS the tool is being run on a special build machine with a controlled signature file
96
#   the generated signatures will not work on-target.
97
#   
1119 dpurdie 98
#
99
# Returns         : Nothing
100
#
101
sub ManifestFiles
102
{
103
    my( $platforms, @elements ) = @_;
104
    Debug2( "ManifestFiles($platforms, @elements)" );
105
    return if ( ! ActivePlatform($platforms) );
106
 
107
    my $name;
108
    my $tier;
109
    my @files;
6306 dpurdie 110
    my %fileVersions;
1119 dpurdie 111
    my $mug_dir;
112
    my $default_arch = $::ScmPlatform;
113
    my $default_prod = '';
1129 dpurdie 114
    my $imported_manifest = 0;
5649 dpurdie 115
    my $include_md5 = 0;
5767 alewis 116
    my $generate_dmf = 0;
5771 alewis 117
    my $dmf_version = $::ScmBuildVersionFull;
6314 dpurdie 118
    my $useDefaultLineWidth = 1;
6364 dpurdie 119
    my $is_sub_manifest = 0;
1119 dpurdie 120
 
121
    #
122
    #   Collect user options
123
    #
124
    foreach ( @elements )
125
    {
126
        if ( m~^--Name=(.+)~ ) {
6302 dpurdie 127
            if ( $name ) {
1119 dpurdie 128
                ReportError ("ManifestFiles:--Name option is only allowed once");
129
                next;
130
            }
131
            $name = $1;
132
 
133
        } elsif ( m~^--Tier=(.+)~ ) {
6302 dpurdie 134
            if ( $tier ) {
1119 dpurdie 135
                ReportError ("ManifestFiles:--Tier option is only allowed once");
136
                next;
137
            }
138
            $tier = $1;
139
 
1123 dpurdie 140
        } elsif ( m~^--Comment=~ ) {
141
            my $cmt = $_;
142
            $cmt =~ s~.+=~~;
143
            $cmt =~ s~\s*\n\s*~\n~g;
144
            push @files, {'cmt' => $cmt };
145
 
1119 dpurdie 146
        } elsif ( m~^--Debian=(.+)~ ) {
6932 dpurdie 147
            push @files, {'file' => ManifestFiles::_LocateDebianFile($1, $default_arch, $default_prod)};
1119 dpurdie 148
 
6302 dpurdie 149
        } elsif ( m~^--Apk=(.+)~ ) {
6932 dpurdie 150
            my $apkData = ManifestFiles::_LocateApkFile($1, $default_arch);
6306 dpurdie 151
            my ($fname, $fversion) = split($;, $apkData);
152
            $fileVersions{$fname} = $fversion;
153
            push @files, {'file' => $fname };
6314 dpurdie 154
            $useDefaultLineWidth = 0;
6302 dpurdie 155
 
1119 dpurdie 156
        } elsif ( m~^--SrcFile=(.+)~ ) {
1123 dpurdie 157
            push @files, {'file' => LocatePreReq($1)};
5649 dpurdie 158
 
1125 alewis 159
        } elsif ( m~^--SrcFileNoCopy=(.+)~ ) {
160
            push @files, {'filenocopy' => $1};
5649 dpurdie 161
 
1119 dpurdie 162
        } elsif ( m~^--MugPackage=(.+)~ ) {
6302 dpurdie 163
            if ( $mug_dir ) {
1119 dpurdie 164
                ReportError ("ManifestFiles:--MugPackage option is only allowed once");
165
                next;
5649 dpurdie 166
            }
6932 dpurdie 167
            $mug_dir = ManifestFiles::_LocateMugDir($1);
1119 dpurdie 168
 
169
        } elsif ( m/^--Arch(.*)=(.+)/ ) {
170
            $default_arch = $2;
171
 
172
        } elsif ( m/^--Product=(.+)/ ) {
173
            $default_prod = $1;
174
 
1125 alewis 175
        } elsif ( m/^--NoManifestVersion/i ) {
6932 dpurdie 176
            $ManifestFiles::Manifest_has_version = 0;
1125 alewis 177
 
178
        } elsif ( m/^--PkgSubdir=(.+)/i ) {
6932 dpurdie 179
            if ( $ManifestFiles::pkg_subdir ) {
1129 dpurdie 180
                ReportError ("ManifestFiles:--PkgSubdir option is only allowed once");
1125 alewis 181
                next;
182
            }
6932 dpurdie 183
            $ManifestFiles::pkg_subdir = $1;
1125 alewis 184
 
1129 dpurdie 185
        } elsif ( m/^--ImportManifest=(.+)/i ) {
6932 dpurdie 186
            my $import_info = ManifestFiles::_ImportManifest($1, $tier, $name);
1129 dpurdie 187
#DebugDumpData("ImportInfo", $import_info );
188
            push @files, {'manifest' => $import_info };
189
 
190
            #
191
            #   Fill in details unless already provided
192
            #
193
            $tier = $import_info->{'tier'} unless ( defined $tier );
194
            $name = $import_info->{'name'} unless ( defined $name );
195
            $imported_manifest = 1;
196
 
6978 dpurdie 197
        } elsif ( m/^--ManifestInsertionPoint(.*)/i ) {
198
            my $insert_info = ManifestFiles::_InsertPoint($1, $tier, $name);
199
#DebugDumpData("InsertPoint", $insert_info );
200
            push @files, {'insertPoint' => $insert_info };
201
 
202
        } elsif ( m/^--Template=(.+)/i ) {
203
            my $template_info = ManifestFiles::_Template($1, $tier, $name);
204
#DebugDumpData("TemplateInfo", $template_info );
205
            push @files, {'template' => $template_info };
206
 
5649 dpurdie 207
        } elsif (m/^--Md5/i) {
6314 dpurdie 208
            $include_md5 = 1;
209
            $useDefaultLineWidth = 0;
5649 dpurdie 210
 
5767 alewis 211
        } elsif (m/^--Dmf/i) {
212
            $generate_dmf = 1
213
 
214
        } elsif ( m/^--DmfVersion=(.+)/ ) {
215
            $generate_dmf = 1;
216
            $dmf_version = $1;
217
 
6314 dpurdie 218
        } elsif ( m/^--LineLength=(\d+)$/i ) {
6932 dpurdie 219
            $ManifestFiles::ManifestLineWidth = $1;
6314 dpurdie 220
            $useDefaultLineWidth = 0;
221
 
6364 dpurdie 222
        } elsif (m/^--SubManifest/i) {
223
            $is_sub_manifest = 1;
6932 dpurdie 224
            $ManifestFiles::Manifest_has_version = 0;
225
            $name = $::ScmPlatform unless $name;
226
            $ManifestFiles::pkg_subdir = $name unless $ManifestFiles::pkg_subdir;
227
            $tier = 0 unless defined($tier);
6364 dpurdie 228
 
6932 dpurdie 229
        } elsif (m/^--(No)?Signatures/i) {
230
           $ManifestFiles::noSigs = !! $1;
231
 
232
        } elsif (m/^--(No)?Warn/i) {
233
           $ManifestFiles::noWarn = !! $1;
234
 
1119 dpurdie 235
        } else {
236
            ReportError ("ManifestFiles: Unknown option or argument: $_");
237
 
238
        }
239
    }
240
 
241
    #
242
    #   Sanity test the user options
243
    #
244
    ReportError ("ManifestFiles: No name specified")
245
        unless $name;
246
    ReportError ("ManifestFiles: No tier specified")
1129 dpurdie 247
        unless defined ($tier);
6302 dpurdie 248
    ReportError ("ManifestFiles: Cannot mix --Debian/-Apk/--SrcFile with --MugPackage in one directive")
1129 dpurdie 249
        if ( $mug_dir && (@files || $imported_manifest) );
1119 dpurdie 250
    ReportError ("ManifestFiles: Must specify files to add to Manifest")
1129 dpurdie 251
        unless ( $mug_dir ||  @files || $imported_manifest);
1119 dpurdie 252
    ErrorDoExit();
253
 
254
    #
6314 dpurdie 255
    #   Set ManifestLineWidth
256
    #   The default is largely historical - for MOS
257
    #   
6932 dpurdie 258
    unless (defined $ManifestFiles::ManifestLineWidth) {
259
        $ManifestFiles::ManifestLineWidth = $useDefaultLineWidth ? 79 : 0;
6314 dpurdie 260
    }
6932 dpurdie 261
    Verbose("ManifestLineWidth:$ManifestFiles::ManifestLineWidth");
6314 dpurdie 262
 
263
    #
1119 dpurdie 264
    #   Save information for processing at the end of the parsing phase
265
    #   Data collected from ALL the ManifestFiles directives will be collected
266
    #   and processed into one Manifest file
267
    #
268
    my %data;
269
    $data{tier} = $tier;
270
    $data{name} = $name;
271
    $data{files} = \@files;
6306 dpurdie 272
    $data{fileVersions} = \%fileVersions;
1119 dpurdie 273
    $data{mugdir} = $mug_dir;
6932 dpurdie 274
    $data{pkgsubdir} = $ManifestFiles::pkg_subdir;
5649 dpurdie 275
    $data{md5} = $include_md5;
5767 alewis 276
    $data{dmf} = $generate_dmf;
277
    $data{arch} = $default_arch;
278
    $data{dmf_version} = $dmf_version;
6364 dpurdie 279
    $data{is_sub_manifest} = $is_sub_manifest;
5767 alewis 280
 
1129 dpurdie 281
#DebugDumpData("DirectiveData", \%data );
1119 dpurdie 282
 
6932 dpurdie 283
    push @ManifestFiles::Manifests, \%data;
6302 dpurdie 284
}
1119 dpurdie 285
 
6932 dpurdie 286
#==================================================================================================
287
#   End of externally exposed methods
6933 dpurdie 288
#       The remainder is package-internal
6932 dpurdie 289
#
290
package ManifestFiles;
291
 
292
use strict;
293
use warnings;
294
use Digest::file qw(digest_file_hex);
295
use Digest::file qw(digest_file_base64);
296
use File::Spec::Functions qw(rel2abs);
297
use File::Basename qw(dirname);
298
 
299
use JatsError;
300
use FileUtils;
301
use ReadBuildConfig;
302
use ArrayHashUtils;
303
use JatsSystem;
304
 
305
#
306
#   Variables
307
#   Config - must be 'our'
308
#
309
our @Manifests;                     # Manifest entries
310
our $Manifest_has_version = 1;      # Create Manifest_xxxx by default
311
our $pkg_subdir;                    # Alternate packaging
312
our $ManifestLineWidth;             # Max length of lines
313
 
314
our %package_dirs;                  # Package dirs discovered and used
315
our $ManifestFiles;                 # Files in the Manifest
316
our $noWarn = 0;                    # Control unused package warnings
317
our $pkgBase;                       # Where the package is being sourced from
6933 dpurdie 318
our $noSigs = 1;                    # Control signature generation (Force noSigs. could use use undef)
6978 dpurdie 319
our $templateMode;                  # In templating mode
6932 dpurdie 320
 
321
#
322
#   Internal
6962 dpurdie 323
#   Used while generating a manifest
6932 dpurdie 324
#
325
my $certName;                       # Signing Cert Name
326
my $certFile;                       # Path to the certificate
327
my $keyFile;                        # Path to the keyfile
328
my $opensslProg;                    # Path to openssl program
329
my $opensslConf;                    # Path to openssl config
6962 dpurdie 330
my $manifestName;                   # Name of the current manifest file
6932 dpurdie 331
 
332
BEGIN {
333
    my $path = rel2abs( __FILE__ );
334
    $pkgBase = dirname( $path );
335
}
336
 
6302 dpurdie 337
#-------------------------------------------------------------------------------
6932 dpurdie 338
# Bring in the DMF build requirements.
339
use lib $pkgBase;
340
use Archive::Zip qw( :ERROR_CODES :CONSTANTS );
341
use JSON;
342
 
343
#-------------------------------------------------------------------------------
6302 dpurdie 344
# Function        : _LocateDebianFile
345
#
346
# Description     : Locate a debian file
347
#                   Internal Function
348
#
349
#                   Scan packages for the Debian package specified
350
#                   The user provides the base name of the package
351
#                   A Debian Package name has several fields
352
#                   These are:
353
#                       1) Base Name - Provided by the user
6730 dpurdie 354
#                       2) Version - Default Version will be wildcarded if it hadn't been provided by user
6302 dpurdie 355
#                       3) Architecture - Wildcarded. Uses bin/arch directory
356
#
357
#                   Expect to find Debian Packages in the bin/PLATFORM subdir
358
#
359
# Inputs          : Debian base name, complete with suboptions
360
#
361
# Returns         : Full path of the file
362
#
363
sub _LocateDebianFile
364
{
365
    my ($arg, $arch, $product) = @_;
366
    Verbose("LocateDebianFile: Processing: $arg");
367
 
368
    my @type = qw( P D );
369
    my @debian_file_path;
6306 dpurdie 370
    my @searchPath;
6730 dpurdie 371
    my $version='*';
6302 dpurdie 372
 
1119 dpurdie 373
    #
6302 dpurdie 374
    #   Extract sub-options
375
    #       --Prod[uction]
376
    #       --Debug
377
    #       --Arch[itecture]=yyy
378
    #       --Product=yyy
6730 dpurdie 379
    #       --Version=yy.yy.yyyyy  default value is wildcard 
1119 dpurdie 380
    #
6302 dpurdie 381
    my ($base_name, @opts) = split( ',', $arg );
382
    foreach ( @opts )
383
    {
384
        if ( m/^--Arch(.*)=(.+)/ ) {
385
            $arch=$2;
386
        } elsif ( m/^--Product=(.+)/ ) {
387
            $product=$1;
388
        } elsif ( m/^--Prod/ ) {
389
            @type = 'P';
390
        } elsif ( m/^--Debug/ ) {
391
            @type = 'D';
6730 dpurdie 392
        } elsif ( m/^--Version=(.+)/ ) {
393
            $version=$1;
6302 dpurdie 394
        } else {
395
            Warning ('--Debian: Unknown Option: ' . $_);
396
        }
397
    }
398
 
5649 dpurdie 399
    #
6302 dpurdie 400
    #   Create a list of products
401
    #   ie: PRODUCT_ARCH
1119 dpurdie 402
    #
6302 dpurdie 403
    my @products;
404
    push @products, $product . '_' . $arch if ( $product );
405
    push @products, $arch;
406
 
1119 dpurdie 407
    #
6302 dpurdie 408
    #   Scan all packages for the specified debian package
1119 dpurdie 409
    #
6302 dpurdie 410
    foreach my $package_dir ( getPackagePaths ('--All') )
1119 dpurdie 411
    {
6302 dpurdie 412
        foreach my $type ( @type )
1119 dpurdie 413
        {
6302 dpurdie 414
            foreach my $prd ( @products )
1119 dpurdie 415
            {
6302 dpurdie 416
                foreach my $joiner ( qw(/ .) )
1119 dpurdie 417
                {
6302 dpurdie 418
                    my $dir = "$package_dir/bin$joiner$prd$type";
6306 dpurdie 419
                    UniquePush(\@searchPath, $dir);
5873 acammell 420
                    next unless ( -d $dir );
6734 dpurdie 421
                    my @files = glob ( "$dir/${base_name}_${version}*.deb" );
5873 acammell 422
                    next unless ( @files );
423
                    push @debian_file_path, @files;
424
                    $package_dirs{$package_dir}{used} = 1;
425
                }
426
            }
1119 dpurdie 427
        }
6302 dpurdie 428
        foreach my $type ( @type )
429
        {
430
            foreach my $prd ( @products )
431
            {
432
                my $dir = "$package_dir";
6306 dpurdie 433
                UniquePush(\@searchPath, $dir);
6730 dpurdie 434
                next unless ( -d $dir ); 
435
                if ( $version eq "*" ){
436
                    my @files = glob ( "$dir/${base_name}_${version}_${prd}_${type}.deb" );
437
                    if ( @files ){
438
                        push @debian_file_path, @files;
439
                        $package_dirs{$package_dir}{used} = 1;
440
                    }
441
                }
442
                else{
443
                    if( -e "$dir/${base_name}_${version}_${prd}_${type}.deb" ) {
444
                        my $file = "$dir/${base_name}_${version}_${prd}_${type}.deb";
445
                        push(@debian_file_path, $file);
446
                        $package_dirs{$package_dir}{used} = 1;
447
                    } elsif ( -e "$dir/${base_name}_${version}_${prd}.deb") {
448
                        my $file = "$dir/${base_name}_${version}_${prd}.deb";
449
                        push(@debian_file_path, $file);
450
                        $package_dirs{$package_dir}{used} = 1;
6734 dpurdie 451
                    }
6730 dpurdie 452
                }
6302 dpurdie 453
            }
454
        }
1119 dpurdie 455
    }
456
 
6306 dpurdie 457
    #
458
    #   Keep user informed
459
    #   Report errors and provide useful information
460
    #
461
    if (IsVerbose(1) || IsDebug(1) || $#debian_file_path != 0)
462
    {
463
        Message ("Search for ($base_name). In search Path", @searchPath);
464
    }
6730 dpurdie 465
 
6302 dpurdie 466
    ReportError ("Required Debian package not found: $base_name") unless @debian_file_path;
467
    ReportError ("Multiple matching Debian Packages located: $base_name", @debian_file_path ) if ( $#debian_file_path > 0 );
468
    return $debian_file_path[0];
469
}
470
 
471
#-------------------------------------------------------------------------------
472
# Function        : _LocateApkFile
473
#
474
# Description     : Locate a APK file
475
#                   Internal Function
476
#
477
#                   Scan packages for the APK package specified
478
#                   The user provides the base name of the package
479
#                   APK ( Android Packages )
480
#                   Expect to have a '-release' or '-debug' suffix, except those provided via a
481
#                   3rd party SDK.
482
#                   Expect to find APK Packages in the bin/PLATFORM(P/D) subdir
483
#                   Expect to find -debug in the <PLATFORM>D directory
484
#                   Expect to find -release' in the <PLATFORM>P directory
485
#                   
486
#                   Allow for:
487
#                       Full path to .apk file
488
#                       .apk in package root directory
489
#
490
# Inputs          : Apk base name, complete with suboptions
491
#
6306 dpurdie 492
# Returns         : Full path of the file $; PackageVersion
493
#                   apk packages do not appear to have version numbers in the file name
494
#                   Retain package version number for later processing
6302 dpurdie 495
#
496
sub _LocateApkFile
497
{
498
    my ($arg, $arch) = @_;
499
    Verbose("LocateApkFile: Processing: $arg");
500
 
501
    my @type = qw( P );
502
    my @apk_file_path;
503
    my %type = ('P' => '-release', 'D' => '-debug' );
6306 dpurdie 504
    my @searchPath;
6302 dpurdie 505
 
1119 dpurdie 506
    #
6302 dpurdie 507
    #   Extract sub-options
508
    #       --Prod[uction]
509
    #       --Debug
510
    #       --Architecture=yyy
1119 dpurdie 511
    #
6302 dpurdie 512
    my ($base_name, @opts) = split( ',', $arg );
513
    foreach ( @opts )
1119 dpurdie 514
    {
6302 dpurdie 515
        if ( m/^--Arch(.*)=(.+)/ ) {
516
            $arch=$2;
517
        } elsif ( m/^--Prod/ ) {
518
            @type = 'P';
519
        } elsif ( m/^--Debug/ ) {
520
            @type = 'D';
521
        } else {
522
            Warning ('--Apk: Unknown Option: ' . $_);
1119 dpurdie 523
        }
6302 dpurdie 524
    }
1119 dpurdie 525
 
6302 dpurdie 526
    #
527
    #   Scan all packages for the specified APK package
528
    #   Try:
529
    #       Raw name - for apks from the SDK or 3rd parties
530
    #       PLATFORM(P|D)/baseName-(release|debug) - Expected
531
    #       baseName-(release|debug) - Repackaged badly
6306 dpurdie 532
    # 
533
    foreach my $pkgEntry ( getPackageList() )
6302 dpurdie 534
    {
6306 dpurdie 535
        next if ($pkgEntry->getType() eq 'interface');
536
        my $pkgVersion = $pkgEntry->getVersion();
537
 
538
        my $pkgLocal = $pkgEntry->getBase(2);
539
        my $pkgRoot = $pkgEntry->getDir();
1119 dpurdie 540
 
6306 dpurdie 541
        #
542
        #   Helper function
543
        #   Uses closure
544
        #   Notes: Test the package in dpkg_archive so that we can retain the package-version
545
        #          Use the version in the interface directory if BuildPkgArchive
546
        #   $pkgLocal - Local base of the package. May in the interface directory
547
        #   $pkgRoot  - Directory in dpkg_achive. Will have version info
548
        #   $subdir   - subdir within the package
549
        #   $fname    - File to look for
550
        #   
551
        #   Returns: Nothing
552
        #   Maintains: apk_file_path. Tupple: filename, PackageVersion
553
        #
554
        my $testOneFile = sub {
555
            my ( $subdir, $fname) = @_;
556
            my $testFile = "$pkgRoot/$subdir";
557
            $testFile =~ s~//~/~g;
558
            $testFile =~ s~/$~~;
559
            UniquePush(\@searchPath, $testFile);
560
            return unless (-d $testFile);
6302 dpurdie 561
 
6306 dpurdie 562
            $testFile .= '/' . $fname;
563
            if (-f $testFile ) {
564
                if ($pkgLocal ne $pkgRoot) {
565
                    my $testFile2 = "$pkgLocal/$subdir/$fname";
566
                    $testFile2 =~ s~//~/~g;
567
                    if ( -f $testFile2 ) {
568
                        $testFile = $testFile2;
569
                    }
570
                }
571
 
572
             $testFile = join($;, $testFile, $pkgVersion);
573
             push @apk_file_path, $testFile;
574
            }
575
        };
576
 
577
        #
578
        #   Test for the specified file in the package root
579
        #
580
        $testOneFile->("", "${base_name}.apk");
581
 
582
        #
583
        #   Test for BIN/PLATFORM
584
        #   
6302 dpurdie 585
        foreach my $type ( @type )
1119 dpurdie 586
        {
6302 dpurdie 587
            my $typeSuffix = $type{$type};
6306 dpurdie 588
            foreach my $joiner ( qw(/ .) ) {
589
                $testOneFile->("bin$joiner$arch$type","${base_name}${typeSuffix}.apk");
1119 dpurdie 590
            }
591
        }
6306 dpurdie 592
 
6302 dpurdie 593
        foreach my $type ( @type )
594
        {
595
            my $typeSuffix = $type{$type};
6306 dpurdie 596
            $testOneFile->("","${base_name}${typeSuffix}.apk");
6302 dpurdie 597
        }
6306 dpurdie 598
        $package_dirs{$pkgRoot}{used} = 1 if (@apk_file_path) ;
1119 dpurdie 599
    }
1129 dpurdie 600
 
6306 dpurdie 601
    #
602
    #   Keep user informed
603
    #   Report errors and provide useful information
604
    #
605
    if (IsVerbose(1) || IsDebug(1) || $#apk_file_path != 0)
606
    {
607
        Message ("Search for ($base_name). In search Path", @searchPath);
608
    }
609
 
6302 dpurdie 610
    ReportError ("Required APK package not found: $base_name") unless @apk_file_path;
611
    ReportError ("Multiple matching APK Packages located: $base_name", @apk_file_path ) if ( $#apk_file_path > 0 );
6306 dpurdie 612
 
613
#DebugDumpData("apk_file_path", \@apk_file_path);
6302 dpurdie 614
    return $apk_file_path[0];
615
}
616
 
617
#-------------------------------------------------------------------------------
618
# Function        : _LocateMugDir
619
#
620
# Description     : Locate the directory containing the mugfiles
621
#                   Internal Function
622
#
623
# Inputs          : Mufile package, with embedded options
624
#
625
# Returns         : Full path
626
#
627
sub _LocateMugDir
628
{
629
    my ($mug_package) = @_;
630
 
1129 dpurdie 631
    #
6302 dpurdie 632
    #   Locate the mugfile subdir
1129 dpurdie 633
    #
6302 dpurdie 634
    my $package_name = $mug_package;
635
    my @dirs = 'mug';
636
    my $mug_dir;
637
 
1129 dpurdie 638
    #
6302 dpurdie 639
    #   Extract sub options
640
    #       --Subdir=xxxx,yyyy,zzzz
1129 dpurdie 641
    #
6302 dpurdie 642
    if ( $package_name =~ m/(.*?),--Subdir=(.*)/ )
1129 dpurdie 643
    {
6302 dpurdie 644
        $package_name = $1;
645
        @dirs = split( ',', $2 );
646
    }
1129 dpurdie 647
 
6978 dpurdie 648
    my $package = ::GetPackageEntry( $package_name );
6302 dpurdie 649
    unless ( $package )
650
    {
651
        ReportError ("ManifestFiles: Package not known to build: $package_name");
652
        return undef;
653
    }
1129 dpurdie 654
 
6302 dpurdie 655
    foreach my $subdir ( @dirs )
656
    {
657
        my $dir = "$package->{'ROOT'}/$subdir";
658
        if ( -d $dir )
1129 dpurdie 659
        {
6302 dpurdie 660
            Warning ("Multiple Mugfile directories located. Only the first will be used",
661
                     "Ignoring: $subdir" )if ( $mug_dir );
662
            $mug_dir = $dir;
663
        }
664
    }
665
    ReportError ("Mugfile directory not found in package: $package_name")
666
        unless $mug_dir;
5105 dpurdie 667
 
6302 dpurdie 668
    return $mug_dir;
669
}
5105 dpurdie 670
 
1129 dpurdie 671
 
6302 dpurdie 672
#-------------------------------------------------------------------------------
673
# Function        : _ImportManifest
674
#
675
# Description     : Import an existing manifest
676
#
677
# Inputs          : Args    - PackageName[,Subdir=name,--ReWrite]
678
#                   tier    - May be null
679
#                   name    - May be null
680
#
681
# Returns         : A hash of data to be used later
682
#
683
sub _ImportManifest
684
{
685
    my ($args, $tier, $name) = @_;
686
    my @file_contents;
6364 dpurdie 687
    my @item_list;
1129 dpurdie 688
 
6302 dpurdie 689
    #
690
    #   Locate the mugfile subdir
691
    #
692
    my $package_name = $args;
693
    my @dirs = 'mug';
694
    my $pkg_dir;
695
    my $pkg_root;
696
    my $manifest;
697
    my $first_tier;
698
    my $first_name;
699
    my $rewrite;
700
 
701
    #
702
    #   Extract sub options
703
    #       --Subdir=xxxx,yyyy,zzzz
704
    #       --ReWrite
705
    #
706
    if ( $package_name =~ m/(.*?)(,.*)/ )
707
    {
708
        $package_name = $1;
709
        my @subargs = split(',--', $2);
710
        foreach ( @subargs)
5105 dpurdie 711
        {
6302 dpurdie 712
            next unless (length($_) > 0);
713
            if (m~^Subdir=(.*)~i){
714
                @dirs = split( ',', $1 );
5105 dpurdie 715
 
6302 dpurdie 716
            } elsif (m~^ReWrite~i) {
717
                $rewrite = 1;
718
 
719
            } else {
720
                ReportError("ManifestFiles: Unknown suboption to ImportManifest:" . $_);
1129 dpurdie 721
            }
722
        }
6302 dpurdie 723
    }
1129 dpurdie 724
 
6978 dpurdie 725
    my $package = ::GetPackageEntry( $package_name );
6302 dpurdie 726
    unless ( $package )
727
    {
728
        ReportError ("ManifestFiles: Package not known to build: $package_name");
729
        return undef;
730
    }
5105 dpurdie 731
 
6302 dpurdie 732
    if (defined ($rewrite) && ( !defined($tier) || !defined($name)))
733
    {
734
        ReportError ("ManifestFiles: ImportManifest. --ReWrite cannot be used unless tier and name are specified");
735
        return undef;
736
    }
1129 dpurdie 737
 
6302 dpurdie 738
    foreach my $subdir ( @dirs )
739
    {
740
        my $dir = "$package->{'ROOT'}/$subdir";
741
        my $root = $package->{'ROOT'};
742
        if ( -d $dir )
5105 dpurdie 743
        {
6302 dpurdie 744
            Warning ("Multiple Package directories located. Only the first will be used",
745
                     "Ignoring: $subdir" )if ( $pkg_dir );
746
            $pkg_dir = $dir;
747
            $pkg_root = $root;
5105 dpurdie 748
        }
6302 dpurdie 749
    }
1129 dpurdie 750
 
6302 dpurdie 751
    unless ($pkg_dir)
752
    {
753
        ReportError ("Package directory not found in package: $package_name");
754
        return undef;
755
    }
5105 dpurdie 756
 
6302 dpurdie 757
    #
758
    #   Determine Manifest File name
759
    #
760
    foreach my $file ( glob ($pkg_dir . '/Manifest*' ) )
761
    {
762
            next unless ( -f $file );
763
            Warning ("Multiple Manifest Files find. Only the first will be used",
764
                     "Using: $manifest",
765
                     "Ignoring: $file" ) if ( $manifest );
766
            $manifest = $file;
767
    }
768
 
769
    unless ($manifest)
770
    {
771
        ReportError ("ImportManifest. No Manifest found: $package_name");
772
        return undef;
773
    }
774
 
775
 
776
    #
777
    #
778
    #
779
    open (MF, '<', $manifest ) || Error ("Cannot open the Manifest file: $manifest", $!);
780
    while ( <MF> )
781
    {
1129 dpurdie 782
        #
6302 dpurdie 783
        #   Clean trailing whitespace ( line-feed and new lines )
784
        #   Comment out [Version] data
1129 dpurdie 785
        #
6302 dpurdie 786
        s~\s+$~~;
787
        s~(\s*\[Version])~#$1~;
788
 
5649 dpurdie 789
        #
6302 dpurdie 790
        #   Part lines and determine files
791
        #
792
        next unless ( $_ );
6364 dpurdie 793
        if (( m~\s*#~ ) || ( m~\s*\[~ )) {
794
            push @item_list, { 'comment' => $_ };
795
            next;
796
        }
797
        my( $aname, $atier, $afile, @additionnal_info) = split(/\s*\,\s*/, $_);
1129 dpurdie 798
#            print "---------- $_\n";
799
#            print "T: $atier, N:$aname, F:$afile\n";
6364 dpurdie 800
        my $file =  { 'file_name' => $afile
801
                    , 'file_info' => \@additionnal_info
802
                    };
803
        push @item_list, $file;
1129 dpurdie 804
 
6302 dpurdie 805
        #
806
        #   Rewrite the name and tier
807
        #
808
        if ($rewrite)
809
        {
810
            $_ = join(',', $name, $tier, $afile);
811
            $first_tier = $tier;
812
            $first_name = $name;
813
        }
814
        else
815
        {
1129 dpurdie 816
            #
6302 dpurdie 817
            #   Capture first tier and name
1129 dpurdie 818
            #
6302 dpurdie 819
            $first_tier = $atier unless ( defined $first_tier );
820
            $first_name = $aname unless ( defined $first_name );
1129 dpurdie 821
        }
6302 dpurdie 822
    }
823
    continue
824
    {
825
        push @file_contents, $_;
826
    }
827
    close MF;
1129 dpurdie 828
 
6302 dpurdie 829
    #
830
    #   Create a hash of data that describes the manifest that has
831
    #   just been read in.
832
    #
833
    $package_dirs{$pkg_root}{used} = 1;
834
    $manifest =~ s~.*/~~;
835
    return { 'contents' => \@file_contents,
6364 dpurdie 836
              'items' => \@item_list,
6302 dpurdie 837
              'file_base' => $pkg_dir,
838
              'manifest' => $manifest,
839
              'pkg_dir' => $pkg_root,
840
              'tier' => $first_tier,
841
              'name' => $first_name,
842
              'rewrite' => $rewrite,
843
            };
1119 dpurdie 844
}
845
 
846
#-------------------------------------------------------------------------------
6978 dpurdie 847
# Function        : _InsertPoint
848
#
849
# Description     : Create a Manifest Insertion Point
850
#
851
# Inputs          : Args    - [,--All,--Name,--Name=xxxx,--Tier,--Tier=Name, --Current]
852
#                   tier    - May be null
853
#                   name    - May be null
854
#
855
# Returns         : A hash of data to be used later
856
#
857
sub _InsertPoint
858
{
859
    my ($args, $tier, $name) = @_;
860
    my @item_list;
861
 
862
    ReportError("ManifestFiles: ManifestInsertionPoint. Name not yet specified") unless defined $name;
863
    ReportError("ManifestFiles: ManifestInsertionPoint. Tier not yet specified") unless defined $tier;
864
 
865
    my $argName = $name;
866
    my $argTier = $tier;
867
 
868
    #
869
    #   Extract sub options
870
    #
871
    my @subargs = split(',--', $args);
872
    foreach ( @subargs)
873
    {
874
        next unless (length($_) > 0);
875
        if (m~^All$~i){
876
            $argName = '*';
877
            $argTier = '*';
878
 
879
        } elsif (m~^Name(=(.*))?~i){
880
            if ( $1 ){
881
                $argName = $2;
882
            } else {
883
                $argName = $name;
884
            }
885
 
886
        } elsif (m~^Tier(=(.*))?~i){
887
            if ( $1 ){
888
                $argTier = $2;
889
            } else {
890
                $argTier = $tier;
891
            }
892
 
893
        } elsif (m~^Current$~i){
894
            $argName = $name;
895
            $argTier = $tier;
896
 
897
        } else {
898
            ReportError("ManifestFiles: Unknown suboption to ManifestInsertionPoint:" . $_);
899
        }
900
    }
901
 
902
    return { 'tier' => $argTier,
903
             'name' => $argName,
904
           };
905
}
906
 
907
#-------------------------------------------------------------------------------
908
# Function        : _Template
909
#
910
# Description     : Capture templating information
911
#
912
# Inputs          : --Template=Package[,--Subdir=subdir,File=name] 
913
#                   tier    - May be null
914
#                   name    - May be null
915
#
916
# Returns         : A hash of data to be used later
917
#
918
sub _Template
919
{
920
    my ($args, $tier, $name) = @_;
921
    my $subdir = 'mug';
922
    my $manifest;
923
 
924
    #
925
    #   Can only use the Template directive once
926
    #   
927
    if ($templateMode) {
928
        ReportError ("ManifestFiles:--Template option is only allowed once");
929
        return undef;
930
    }
931
    $templateMode = 1;
932
 
933
 
934
    #
935
    #   Locate the mugfile subdir
936
    #
937
    my $package_name = $args;
938
 
939
    #
940
    #   Extract sub options
941
    #       --Subdir=xxxx
942
    #       --File=name
943
    #       
944
    if ( $package_name =~ m/(.*?)(,.*)/ )
945
    {
946
        $package_name = $1;
947
        my @subargs = split(',--', $2);
948
        foreach ( @subargs)
949
        {
950
            next unless (length($_) > 0);
951
            if (m~^Subdir=(.*)~i){
952
                $subdir = $1;
953
 
954
            } elsif (m~^File=(.*)~i) {
955
                $manifest = $1;
956
 
957
            } else {
958
                ReportError("ManifestFiles: Unknown suboption to Template:" . $_);
959
            }
960
        }
961
    }
962
 
963
    my $package = ::GetPackageEntry( $package_name );
964
    unless ( $package )
965
    {
966
        ReportError ("ManifestFiles: Package not known to build: $package_name");
967
        return undef;
968
    }
969
 
970
    my $pkg_root = $package->{'ROOT'};
971
    my $pkgDir = CatPaths( $pkg_root, $subdir);
972
    unless (-d $pkgDir) {
973
        ReportError ("ManifestFiles: Template subdir not found in $package_name: $subdir");
974
        return undef;
975
    }
976
 
977
    #
978
    #   Determine Manifest File name, unless specified by user
979
    #
980
    unless ($manifest) {
981
        foreach my $file ( glob ($pkgDir . '/Manifest*' ) )
982
        {
983
                next unless ( -f $file );
984
                if ( $manifest ) {
985
                    Warning ("Multiple Manifest Files find. Only the first will be used",
986
                             "Using: $manifest",
987
                             "Ignoring: $file" ) ;
988
                    next;
989
                }
990
                $manifest = $file;
991
        }
992
        unless ($manifest)
993
        {
994
            ReportError ("ImportManifest. No Manifest template found: $package_name");
995
            return undef;
996
        }
997
    } else { 
998
        $manifest = CatPaths($pkgDir, $manifest);
999
    }
1000
 
1001
    unless (-f $manifest) {
1002
        ReportError ("ImportManifest. No Manifest template found: $package_name, $subdir, $manifest");
1003
        return undef;
1004
    }
1005
 
1006
    #
1007
    #   Return paramters for later processing
1008
    #
1009
 
1010
    $package_dirs{$pkg_root}{used} = 1;
1011
    return { 'manifest' => $manifest,
1012
             'pkg_dir' => $pkg_root,
1013
             'subdir' => $subdir,
1014
             'manifest_dir' => $pkgDir,
1015
             'package' => $package_name,
1016
    }; 
1017
}
1018
 
1019
 
1020
#-------------------------------------------------------------------------------
6932 dpurdie 1021
# Function        : Generate
1119 dpurdie 1022
#
1023
# Description     : Internal Function
1024
#                   Process all the collected data and create directives
1025
#                   for the creation of the manifest
1026
#
1027
#                   This function will be called, just before the Makefile
1028
#                   is created. The function will:
1029
#                       1) Create the Manifest File
1030
#                       2) Package the Manifest File
1031
#                       3) Package the manifest file contents
1032
#
1033
#                   using (mostly) normal makefile.pl directives.
1034
#
1035
# Inputs          : None
1036
#
1037
# Returns         : Nothing
1038
#
6932 dpurdie 1039
sub Generate
1119 dpurdie 1040
{
6932 dpurdie 1041
    Debug ("Generate");
1119 dpurdie 1042
    Message ("Generating Manifest File");
1123 dpurdie 1043
 
1044
    #
1045
    #   Need at least one Manifest Entry
1046
    #
6932 dpurdie 1047
#DebugDumpData ( "Manifests", \@Manifests );
1123 dpurdie 1048
    return unless ( @Manifests );
1119 dpurdie 1049
 
1050
    #
6932 dpurdie 1051
    #   Init the signing subsystem
1052
    # 
1053
    GenSigInit();
1054
 
1055
    #
1125 alewis 1056
    #   Determine the target packaging directory
1057
    #   Default is .../mug
1058
    #
6962 dpurdie 1059
    $pkg_subdir = 'mug';
1129 dpurdie 1060
    if ( exists $Manifests[0]->{pkgsubdir} && defined $Manifests[0]->{pkgsubdir} )
1125 alewis 1061
    {
1062
        my $subdir = $Manifests[0]->{pkgsubdir};
6962 dpurdie 1063
        $pkg_subdir .= '/' . $subdir;
1064
        $pkg_subdir =~ s~^mug/mug~mug~;
1125 alewis 1065
    }
1066
 
1067
    #
1119 dpurdie 1068
    #   Create the Manifest File as we process the lists
1125 alewis 1069
    #   Place this in the 'lib' directory:
1119 dpurdie 1070
    #       - So that it will be deleted on clobber
1123 dpurdie 1071
    #       - So that it can be placed in a target-specific subdir
1125 alewis 1072
    #       - So that we can have one per makefile.pl
1119 dpurdie 1073
    #
1074
    Error ("ManifestFiles: Needs local directory specified in build.pl") unless ( $::ScmLocal );
1075
 
1125 alewis 1076
    my $manifest_dir = "$::ScmPlatform.LIB";
1119 dpurdie 1077
    System( "$::GBE_BIN/mkdir -p $manifest_dir" );
1078
 
6962 dpurdie 1079
    $manifestName = $manifest_dir . '/Manifest';
1080
    $manifestName .= '_' . $::ScmBuildVersion if ( $Manifest_has_version );
1081
    ::PackageFile ('*', $manifestName, '--Subdir=' . $pkg_subdir, '--Strip' );
1082
    ::ToolsetGenerate( $manifestName );
5649 dpurdie 1083
 
6962 dpurdie 1084
    Verbose ("Generate: File: $manifestName");
1119 dpurdie 1085
 
6962 dpurdie 1086
    open (MF, '>', $manifestName ) || Error ("Cannot create the Manifest file: $manifestName");
5711 kspencer 1087
    binmode (MF);
5767 alewis 1088
 
6364 dpurdie 1089
    if ($Manifests[0]->{is_sub_manifest} == 1) {
1090
        print_mf ("# Package $::ScmBuildPackage $::ScmBuildVersion built: $::CurrentTime");
1091
    } else {
1092
        print_mf ("# PackageName: $::ScmBuildPackage");
1093
        print_mf ("# PackageVersion: $::ScmBuildVersion");
1094
        print_mf ("# BuildDate: $::CurrentTime");
1095
        print_mf ("#");
1096
        print_mf ("[Version],$::ScmBuildVersion");
1097
        print_mf ("#");
1098
    }
1119 dpurdie 1099
 
1100
    #
6932 dpurdie 1101
    #   Insert the certificate used to verify the files
1102
    #       Currently we only handle one certificate
1103
    #       Certificate name must end in .crt
1104
    #   In production the .crt file MUST be signed by the VixManifestRoot-CA
1105
    #   The assumtion is that the public key for VixManifestRoot-CA is on the device
1106
    #
1107
    unless (($Manifests[0]->{is_sub_manifest} == 1) || $noSigs) {
1108
        print_mf ("");
1109
        print_mf ("#");
1110
        print_mf ("# Signing Certificate");
1111
        print_mf ("[Certificate],$certName");
1112
 
6962 dpurdie 1113
        ::PackageFile ('*', $certFile, '--Subdir=' . $pkg_subdir, '--Strip' );
6932 dpurdie 1114
    }
1115
 
1116
    #
1125 alewis 1117
    #   Process each tier in the order presented in the source file
1119 dpurdie 1118
    #
1123 dpurdie 1119
    my $last_was_comment = 0;
6978 dpurdie 1120
    my $last_was_insert = 0;
1119 dpurdie 1121
    foreach my $entry ( @Manifests )
1122
    {
1123
 
1124
#DebugDumpData ( "Manifest Entry", $entry );
1125
 
1126
        my $tier = $entry->{tier};
1127
        my $name = $entry->{name};
5649 dpurdie 1128
        my $include_md5 = $entry->{md5};
1119 dpurdie 1129
 
5767 alewis 1130
        if ( $entry->{dmf} )
1131
        {
6302 dpurdie 1132
            DmfGenerate($entry);
5767 alewis 1133
        }
1134
 
1119 dpurdie 1135
        #
1136
        #   Insert all the files that have been specified
1137
        #   The user specified order is preserved
1138
        #
1123 dpurdie 1139
        #   Entries may be either a file or a comment
1140
        #   Comments: Merge multiple comments and create blocks
1141
        #
1142
        #
1119 dpurdie 1143
        my @files = @{ $entry->{files} };
1123 dpurdie 1144
        foreach my $fentry ( @files )
1119 dpurdie 1145
        {
1123 dpurdie 1146
            if ( my $cmt = $fentry->{'cmt'} )
1147
            {
1148
                print_mf ('') unless ( $last_was_comment ) ;
1149
                print_mf ( map (('# ' . $_) , split ("\n", $cmt) ));
1150
                $last_was_comment = 1;
1151
                next;
1152
            }
1153
 
6978 dpurdie 1154
            print_mf ('#') if ( $last_was_comment);
1155
            $last_was_comment = 0;
1156
 
1157
            if ( my $ip = $fentry->{'insertPoint'} ) {
1158
               #
1159
               #   Create an insertion point
1160
               #   Looks like a comment for the purposes of backward compatability
1161
               #
1162
 
1163
               print_mf ('') unless $last_was_insert;
1164
               print_mf ("##INSERT POINT [Name:$ip->{name}] [Tier:$ip->{tier}]");
1165
               $last_was_insert = 1;
1166
               next;
1167
            }
1168
            print_mf ('#') if ( $last_was_insert);
1169
            $last_was_insert = 0;
1170
 
1123 dpurdie 1171
            if ( my $file = $fentry->{'file'} )
1172
            {
1173
                my $base_file = StripDir( $file );
6314 dpurdie 1174
                my @items = ($name, $tier, $base_file);
5649 dpurdie 1175
                if ($include_md5) {
1176
                    my $md5 = digest_file_hex($file, 'MD5');
6314 dpurdie 1177
                    push @items, "MD5=$md5" ;
6306 dpurdie 1178
                }
1179
                if (exists $entry->{fileVersions} && exists $entry->{fileVersions}{$file} ) {
6314 dpurdie 1180
                    push @items, "VERSION=" . $entry->{fileVersions}{$file};
6306 dpurdie 1181
                }
6314 dpurdie 1182
                print_mf (join (',', @items));
6962 dpurdie 1183
                PackageManifestFile ($name, $tier, $file );
1123 dpurdie 1184
            }
1125 alewis 1185
 
1186
            if ( my $file = $fentry->{'filenocopy'} )
1187
            {
1188
                print_mf ("$name,$tier,$file");
1189
            }
1129 dpurdie 1190
 
1191
            if ( my $emf = $fentry->{'manifest'} )
1192
            {
1193
                #
1194
                #   Insert the entire manifest
1195
                #   Items are:
1196
                #        contents
6364 dpurdie 1197
                #        items:
1198
                #               file_name + arrays of file_info
1199
                #           or  comment line to copy
1129 dpurdie 1200
                #        file_base
1201
                #        manifest
1202
                #
1203
#DebugDumpData ( "Embedded Manifest Entry", $emf );
6364 dpurdie 1204
                if ($emf->{'rewrite'}) {
1205
                    foreach my $item ( @{$emf->{'items'}}) {
1206
                        if (defined($item->{'file_name'}))
1207
                        {
1208
                            my @items = ($name, $tier, $item->{'file_name'});
1209
                            my $md5_added = 0;
1210
                            foreach my $info (@{$item->{'file_info'}}) {
1211
                                push @items, $info;
1212
                                $md5_added = 1 if ($info =~ m~^MD5=~i);
1213
                            }
1214
                            if ($include_md5 && $md5_added == 0) { # add md5 if requested and not already added from submanifest
1215
                                my $md5 = digest_file_hex($emf->{'file_base'} . '/' . $item->{'file_name'}, 'MD5');
1216
                                push @items, "MD5=$md5";
1217
                            }
1218
                            print_mf (join (',', @items));
6962 dpurdie 1219
                            PackageManifestFile ( $name, $tier, $emf->{'file_base'} . '/' . $item->{'file_name'} );
6364 dpurdie 1220
                        }
1221
                        elsif (defined($item->{'comment'})) {
1222
                            print_mf($item->{'comment'});
1223
                        }
1224
                    }
1225
                    print_mf('#');
1226
                }
1227
                else {
1228
                    print_mf ($_) foreach  ( @{$emf->{'contents'}} );
1229
                    foreach my $item ( @{$emf->{'items'}}) {
6932 dpurdie 1230
                        if (defined($item->{'file_name'})) {
6962 dpurdie 1231
                            PackageManifestFile ( $name, $tier, $emf->{'file_base'} . '/' . $item->{'file_name'} );
6932 dpurdie 1232
                        }
6364 dpurdie 1233
                    }
1234
                    print_mf('#');
1235
                }
1129 dpurdie 1236
            }
1119 dpurdie 1237
        }
1238
 
1239
        #
1240
        #   Expand out the entire MUG directory
1241
        #   All .mug files in the MUG directory will be added to the manifest
1242
        #   The assumption is that the MUG directory has been created by
1243
        #   something that knows what its doing
1244
        #
1245
        if ( my $mugdir = $entry->{mugdir} )
1246
        {
1247
            foreach my $file ( glob ($mugdir . '/*.mug' ) )
1248
            {
1249
                next unless ( -f $file );
1250
                my $base_file = StripDir($file);
6314 dpurdie 1251
 
1252
                my @items = ($name, $tier, $base_file);
1253
 
5654 dpurdie 1254
                if ($include_md5) {
1255
                    my $md5 = digest_file_hex($file, 'MD5');
6314 dpurdie 1256
                    push @items, "MD5=$md5" ;
5654 dpurdie 1257
                }
6314 dpurdie 1258
                print_mf (join (',', @items));
6962 dpurdie 1259
                PackageManifestFile ($name, $tier, $file );
1119 dpurdie 1260
            }
1261
        }
1262
    }
1263
 
1264
    #
1265
    #   Complete the creation of the Manifest File
1266
    #
6364 dpurdie 1267
    print_mf ("# end of $::ScmBuildPackage");
1119 dpurdie 1268
    close MF;
1269
    ErrorDoExit();
1121 dpurdie 1270
 
1271
    #
6932 dpurdie 1272
    #   Post process files from the manifest
1273
    #   May include signature generation
1274
    GenSignatures();
1275
 
1276
    #
1121 dpurdie 1277
    #   Sanity test of packages that did not provide a debian file
1278
    #   Just a hint that something may have been missed
1279
    #
6932 dpurdie 1280
    unless ($noWarn) {
1281
        my @not_used_packages;
1282
        foreach my $package_dir ( getPackagePaths ('--All') )
1121 dpurdie 1283
        {
6932 dpurdie 1284
            next if ( $package_dir =~ m~/manifest-tool/~ );
1285
            unless ( exists $package_dirs{$package_dir}{used} )
1286
            {
1287
                push @not_used_packages, $package_dir;
1288
            }
1121 dpurdie 1289
        }
6932 dpurdie 1290
        if ( @not_used_packages )
1291
        {
1292
            Warning ("Packages that did not contribute packages to the manifest:",
1293
                      @not_used_packages );
1294
        }
1121 dpurdie 1295
    }
6932 dpurdie 1296
}
1297
 
1298
#-------------------------------------------------------------------------------
1299
# Function        : print_mf
1300
#
1301
# Description     : Internal Function
1302
#                   Print one line to the Manifest File
1303
#                   Checks the length of the line being created
1304
#
1305
# Inputs          : $line
1306
#
1307
# Returns         :
1308
#
1309
 
1310
sub print_mf
1311
{
1312
    foreach  ( @_ )
1121 dpurdie 1313
    {
6932 dpurdie 1314
        my $ll = length ($_);
1315
        ReportError ( "Manifest line too long: $ll. Max is $ManifestLineWidth.",
1316
                "Line: $_" ) if ( $ManifestLineWidth && $ll > $ManifestLineWidth);
1317
        print MF $_ . "\n";
1121 dpurdie 1318
    }
6932 dpurdie 1319
}
1121 dpurdie 1320
 
6932 dpurdie 1321
#-------------------------------------------------------------------------------
1322
# Function        : PackageManifestFile  
1323
#
1324
# Description     : Process and package a manifest file
6978 dpurdie 1325
#                       Retain a list of files in the manifest to allow postprocessing
6932 dpurdie 1326
#                       such as signature generation
1327
#                   
1328
#
6962 dpurdie 1329
# Inputs          : $name           - Target platform name
1330
#                   $tier           - Target tier
1331
#                   $srcFile        - Full path to the source file
6932 dpurdie 1332
#
1333
# Returns         : Nothing
1334
#
1335
sub PackageManifestFile {
6962 dpurdie 1336
    my ($name, $tier, $srcFile ) = @_;
1337
    push @{$ManifestFiles}, ({srcFile => $srcFile, name =>$name, tier => $tier});
1119 dpurdie 1338
 
6962 dpurdie 1339
    ::PackageFile ('*', $srcFile, '--Subdir=' . $pkg_subdir, '--Strip' );
6932 dpurdie 1340
}
1341
 
1342
#-------------------------------------------------------------------------------
1343
# Function        : GenSigInit 
1344
#
1345
# Description     : Initialise the Siganture Generation process
1346
#                   Populate some globals for use in creating the manifest
1347
#                   Bail if there are errors
1348
#
1349
# Inputs          : 
1350
#
1351
# Returns         : 
1352
#
1353
sub GenSigInit
1354
{
6933 dpurdie 1355
    Debug("GenSigInit:", $noSigs);
6932 dpurdie 1356
    return if $noSigs;
1357
 
1358
    my @warnings;
1359
 
1119 dpurdie 1360
    #
6933 dpurdie 1361
    #   Locate and setup openssl
1362
    #   Should be provided by a package
1363
    #   set OPENSSL_CONF=...../openssl.cfg 
1364
    #   
1365
    $opensslProg = ::ToolExtensionProgram( 'openssl', '', '.exe');
1366
 
1367
    #   Generate  a dummy openssl.cnf - to keep the uitility happy (quiet)
1368
    $opensslConf = FullPath(CatPaths( $::ScmRoot, $::ScmInterface, 'openssl.cfg'));
1369
    TouchFile($opensslConf);
1370
    ::ToolsetGenerate($opensslConf);
1371
    $ENV{OPENSSL_CONF}= $opensslConf;
1372
 
1373
    #
1374
    #   Figure out default operation if openssl cannot be found
1375
    #       If --signature - then report error
1376
    #       If not specified, then default is -NoSig
1377
    #
1378
    unless ($opensslProg) {
1379
        if (defined $noSigs) {
1380
            ReportError ("The openssl utility is not available. Must be provided by a package") unless $opensslProg;  
1381
        } else {
1382
            Verbose("openssl not found in a package. Default to no signature");
1383
            $noSigs = 1;
1384
            return;
1385
        }
1386
    }
1387
 
1388
    #
6932 dpurdie 1389
    #   Signatures 'should' be generated for a target paltform of 'MANSIG'
1390
    #       In the automated build system this will be a controlled machine
1391
    #   Warn if attemting to create signatures for a different target    
1119 dpurdie 1392
    #
6932 dpurdie 1393
    push @warnings, "# Package build for platform other than MANSIG - will generate test signatures" if ($::ScmPlatform ne 'MANSIG');
1394
 
1395
 
1119 dpurdie 1396
    #
6932 dpurdie 1397
    #   Locate the signature file
1398
    #   Use an internal key that unless being run on a controlled build machine
1399
    #   The controlled build machine will have
1400
    #       GBE_MANIFEST_KEY set to a path that contains the keyfile
1401
    #           Yes, a user can fudge this, but not with the real file
1402
    #          
1403
    #  Internal cert created with:
1404
    #  openssl req -nodes -x509 -sha256 -newkey rsa:4096 -keyout VixPulseManifestTest.key -out VixPulseManifestTest.crt -days 10000 -subj "/C=AU/CN=Vix.Pulse.Manifest.Test"
1119 dpurdie 1405
    #
6932 dpurdie 1406
    $keyFile = CatPaths( $pkgBase, 'VixPulseManifestTest.key');
1407
    my $localKey = 1;
1408
    if (exists $ENV{GBE_MANIFEST_KEY} ) {
1409
        $keyFile = $ENV{GBE_MANIFEST_KEY};
1410
        $localKey = 0;
1411
    }
1412
    $certFile = $keyFile;
1413
    $certFile =~ s~\.key$~.crt~;
1414
    $certName = $certFile;
1415
    $certName =~ s~.*[\\/]~~;
1119 dpurdie 1416
 
6932 dpurdie 1417
    ReportError ("Manifest signing key not found", $keyFile) unless -f $keyFile;
1418
    ReportError ("Manifest signing key not found", $certFile) unless -f $certFile;
1419
 
1420
    push @warnings, "#  Using uncontrolled test key to sign the manifest" if ($localKey);
1421
    Warning("#############################################################", "#",
1422
             @warnings,
1423
            "#", "#############################################################") if (@warnings);
1424
 
1425
    ErrorDoExit();
1426
    Message("OpenSsl Prog: $opensslProg");
1427
    Message("OpenSsl Conf: $opensslConf");
1428
    Message("Signing with: $keyFile");
1429
 
1119 dpurdie 1430
}
1431
 
6932 dpurdie 1432
#-------------------------------------------------------------------------------
1433
# Function        : GenSignatures 
1434
#
1435
# Description     : Generate signatures on all packages
1436
#
1437
# Inputs          : Used the array of files in $ManifestFiles 
1438
#
1439
# Returns         : Nothing 
1440
#
1441
sub GenSignatures
1442
{
6933 dpurdie 1443
    Debug("GenSignatures:", $noSigs);
6932 dpurdie 1444
    return if $noSigs;
5767 alewis 1445
 
6962 dpurdie 1446
    my %sigManifest;
1447
 
6932 dpurdie 1448
    foreach my $entry ( @{$ManifestFiles}) {
6962 dpurdie 1449
        Verbose("PostProcess: $entry->{srcFile}");
6932 dpurdie 1450
 
1451
        #
1452
        #   Generate the name of the signature file
1453
        #   Generate Packaging directives for the signature
1454
        #   
1455
        my $sigFileName = CatPaths( "$::ScmPlatform.LIB", StripDir($entry->{srcFile}) . '.sig' );
6962 dpurdie 1456
        ::PackageFile ('*', $sigFileName, '--Subdir=' . $pkg_subdir, '--Strip' );
6932 dpurdie 1457
        ::ToolsetGenerate($sigFileName);
1458
 
1459
        #
6962 dpurdie 1460
        #   Generate the name/tier for the manifest signature
1461
        #       ie: Manifest_<name>_<tier>.sig
1462
        #   Generate the name for the manifest signature
1463
        #       ie: Manifest_<name>.sig
1464
        #   Will generate signature of signatures
6932 dpurdie 1465
        #
6962 dpurdie 1466
        my $sigManifest =  join('_', $entry->{name}, $entry->{tier});
1467
        push @{$sigManifest{$sigManifest}}, $sigFileName;
1468
        push @{$sigManifest{$entry->{name}}}, $sigFileName;
6932 dpurdie 1469
 
1470
 
6962 dpurdie 1471
        # Generate the signature over the file
1472
        genSigForFile($entry->{srcFile}, $sigFileName);
1473
    }
1474
 
1475
    #
1476
    #   Create a file of signatures
1477
    #   Create one for each platform/tier
1478
    #
1479
    foreach my $nameTier ( keys %sigManifest)
1480
    {
1481
        Verbose("PostProcessSig: $nameTier");
1482
        my $sigSigTemp = $manifestName . '_' . $nameTier . '.sig';
1483
        my $sigSigTempCat = $sigSigTemp . '.content';
1484
        ::ToolsetGenerate($sigSigTemp, $sigSigTempCat);
1485
        ::PackageFile ('*', $sigSigTemp, '--Subdir=' . $pkg_subdir, '--Strip' );
1486
 
6932 dpurdie 1487
        #
6962 dpurdie 1488
        #   Concatenate the contents of the required .sig files
1489
        #   Treat them as binary files. 
1490
        #
1491
        open  (my $ofh, '>', $sigSigTempCat ) || Error( "Cannot create file: $sigSigTempCat", "Reason: $!" );
1492
        binmode ($ofh);
1493
        foreach my $entry (@{$sigManifest{$nameTier}}) {
1494
            Verbose("PostProcessSig: $entry");
1495
            open( my $file, '<', $entry ) || Error("Cannot open '$entry'. $!");
1496
            binmode ($file);
1497
            my @lines = <$file>;
1498
            close $file;
6932 dpurdie 1499
 
6962 dpurdie 1500
            foreach my $entry ( @lines ) {
1501
                print $ofh $entry;
1502
            }
6932 dpurdie 1503
        }
6962 dpurdie 1504
        close $ofh;
6932 dpurdie 1505
 
6962 dpurdie 1506
        #
1507
        #   Generate a signature over the file
1508
        #
1509
        genSigForFile($sigSigTempCat, $sigSigTemp);
1510
        #unlink $sigSigTempCat;
6932 dpurdie 1511
    }
6962 dpurdie 1512
 
6932 dpurdie 1513
    unlink $opensslConf;
5767 alewis 1514
}
1515
 
6962 dpurdie 1516
#-------------------------------------------------------------------------------
1517
# Function        : genSigForFile 
1518
#
1519
# Description     : Generate a .sig file for a named file (internal)
1520
#                   Will be smart and only 'touch' the output file if the input has chnaged
1521
#                       It will maintain a fingerprint file to do this.
1522
#                   
1523
#                   Generate package signature
1524
#                   The required custom(vix) 'sig' file has the format:
1525
#                       line-1 : name of the certificate to decode
1526
#                                Assume its the keyname with .key -> .crt - with no path elements
1527
#                       line-2 : Text representation of the signature (base64)
1528
#                                The openssl dgst command generates a binary output by default
1529
#                                This is then converted into base64 with -A option
1530
#                   
1531
# Inputs          : $srcFile        - Source file to process
1532
#                   $tgtFile        - Output file name
1533
#
1534
# Returns         : 
1535
#
1536
sub genSigForFile
1537
{
1538
    my ($srcFile, $tgtFile) = @_;
5767 alewis 1539
 
6962 dpurdie 1540
    my $tmp1 = CatPaths( "$::ScmPlatform.LIB", 'temp1');
1541
    my $tmp2 = CatPaths( "$::ScmPlatform.LIB", 'temp2');
1542
    ::ToolsetGenerate($tmp1, $tmp2);
1543
 
1544
    Verbose("Signing: " . StripDir($srcFile));
1545
    System( '--Exit', '--NoShell', $opensslProg, 'dgst', '-sha256', '-sign', $keyFile, '-out', $tmp1, $srcFile );
1546
    System( '--Exit', '--NoShell', $opensslProg, 'base64', '-A', '-in', $tmp1, '-out', $tmp2 );
1547
    my $base64 = TagFileRead($tmp2);
1548
 
1549
    #
1550
    #   In a development environment we don't want to create the signature file every time we run. Its noisy. 
1551
    #   Solution: Only generate a signature file if:
1552
    #               It doesn't exist
1553
    #               A copy of the signed digest doesn't exist (.fpp)
1554
    #               The signed digest has changed
1555
    #   
1556
    my $fppFileName = CatPaths( "$::ScmPlatform.LIB", StripDir($srcFile) . '.fpp' );
1557
    ::ToolsetGenerate($fppFileName);
1558
    my $genSig = 0;
1559
    $genSig = 1 unless ( -e $tgtFile &&  -e $fppFileName);
1560
    unless ($genSig) {
1561
        my $ffp = TagFileRead($fppFileName);
1562
        $genSig = ($ffp ne $base64);
1563
    }
1564
 
1565
    if ($genSig) {
1566
        FileCreate($tgtFile, $certName, $base64);
1567
        rename $tmp2, $fppFileName ;
1568
    }
1569
 
1570
    unlink $tmp1;
1571
    unlink $tmp2;
1572
}
1573
 
5767 alewis 1574
#-------------------------------------------------------------------------------
1575
# Function        : DmfGenerate
1576
#
1577
# Description     : Import an existing manifest
1578
#
1579
# Inputs          : entry   - The manifest that is being processed.
1580
#
1581
# Returns         : Nothing
1582
#
1583
sub DmfGenerate
1584
{
1585
    my ($entry) = @_;
1586
 
1587
    # Get the generation time.
1588
    my $gen_time = time();
1589
 
1590
    my $work_dir = "$::ScmPlatform.BIN/";
1591
    System( "$::GBE_BIN/mkdir -p $work_dir" );
1592
 
1593
    my $name = $entry->{name};
1594
    my $version = $entry->{dmf_version};
1595
 
1596
    # Configure base manifest information.
1597
    my %manifest;
5771 alewis 1598
    $manifest{'mugsetId'} = $name . '_' . $version;
5767 alewis 1599
    $manifest{'name'} = $name;
1600
    $manifest{'version'} = $version;
5771 alewis 1601
    $manifest{'packageName'} = $::ScmBuildPackage;
1602
    $manifest{'packageVersion'} = $::ScmBuildVersionFull;
5767 alewis 1603
    $manifest{'datetime'} = localtime($gen_time);
1604
    $gen_time *= 1000;  # Make to milliseconds
1605
    $manifest{'timestamp'} = $gen_time;
1606
    $manifest{'tier'} = $entry->{tier};
1607
 
1608
    # Process each file.
1609
    my @files = @{ $entry->{files} };
1610
    my $zip = Archive::Zip->new();
1611
    my $i = 0;
1612
    foreach my $fentry ( @files )
1613
    {
1614
        if ( my $file = $fentry->{'file'} )
1615
        {
6302 dpurdie 1616
            my $order = $i + 1;
5767 alewis 1617
            my $base_file = StripDir( $file );
1618
            my $publish_file = $name . '_' . $version . '_' . $order . '.aup';
1619
            my $aup_file = $work_dir . $publish_file;
1620
 
1621
            GenerateCesFile($file, $aup_file, 0x3, $gen_time, $publish_file);
1622
 
1623
            my $file_member = $zip->addFile( $aup_file, $publish_file );
1624
 
1625
            $manifest{'tasks'}[$i]{'order'} = 1 * $order;
1626
            $manifest{'tasks'}[$i]{'filename'} = $base_file;
1627
            $manifest{'tasks'}[$i]{'download'} = $publish_file;
5771 alewis 1628
            $manifest{'tasks'}[$i]{'sha256'} = digest_file_base64($file, 'SHA-256');
1629
            $manifest{'tasks'}[$i]{'size'} = -s $file;
1630
 
5767 alewis 1631
            if ($base_file =~ /\.sh$/)
1632
            {
1633
                $manifest{'tasks'}[$i]{'action'} = 'exec-shell';
1634
            }
1635
            elsif ($base_file =~ /\.deb$/)
1636
            {
1637
                $manifest{'tasks'}[$i]{'action'} = 'dpkg-install';
5771 alewis 1638
 
1639
                my ($pkg_name, $pkg_version, $pkg_arch) = ($base_file =~ /([^_]*)_([^_]*)_(.*)/);
1640
                $manifest{'tasks'}[$i]{'arch'} = $pkg_arch;
1641
                $manifest{'tasks'}[$i]{'name'} = $pkg_name;
1642
                $manifest{'tasks'}[$i]{'version'} = $pkg_version;
5767 alewis 1643
            }
1644
            else
1645
            {
1646
                ReportError ("Manifest entry $base_file does not have a supported DMF install action");
1647
            }
1648
 
1649
            $i = $i + 1;
1650
        }
1651
    }
1652
 
1653
    # Encode and commit the JSON.
1654
    my $json_encoder = JSON->new->allow_nonref;
1655
    my $json = $json_encoder->pretty->encode( \%manifest );
1656
 
1657
    my $manifest_filename = $name . '_' . $version;
1658
    my $aum_filename = $manifest_filename . '_0.aum';
1659
    my $manifest_file = $work_dir . $manifest_filename . '.json';
1660
    my $aum_file = $work_dir . $aum_filename;
1661
 
1662
    # Save our manifest.
1663
    open (J, '>', $manifest_file ) || Error ("Cannot create the DMF Manifest file");
1664
    binmode (J);
1665
    print J $json;
1666
    close J;
1667
 
1668
    GenerateCesFile($manifest_file, $aum_file, 0x2, $gen_time, $aum_filename);
1669
 
1670
    $zip->addFile($aum_file, $aum_filename);
1671
 
1672
    my $zip_filename = $work_dir . $name . '_' . $version . '.zip';
1673
    if ( $zip->writeToFileNamed($zip_filename) != AZ_OK )
1674
    {
1675
        ReportError("DMF ZIP file creation failed");
1676
    }
6943 dpurdie 1677
    ::PackageFile('*', $zip_filename, '--Strip');
1678
    ::PackageFile('*', $manifest_file, '--Strip');
5767 alewis 1679
 
1680
}
1681
 
1682
#-------------------------------------------------------------------------------
6932 dpurdie 1683
# Function        : GenerateCesFile
5767 alewis 1684
#
1685
# Description     : Import an existing manifest
1686
#
1687
# Inputs          : src_file     - The input file.
1688
#                   dst_file     - The output CES file.
1689
#                   content_type - The content type to report.
1690
#                   gen_time     - The generation time for the file.
1691
#                   filename     - The filename to embed in the CES file.
1692
#
1693
#
1694
# Returns         : Nothing
1695
#
1696
sub GenerateCesFile
1697
{
1698
    my ($src_file, $dst_file, $content_type, $gen_time, $filename) = @_;
1699
 
1700
    open (INF, '<', $src_file ) || Error ("Cannot open file $src_file for reading");
1701
    binmode (INF);
1702
 
1703
    open (OUTF, '>', $dst_file ) || Error ("Cannot open file $dst_file for writing");
1704
    binmode (OUTF);
1705
 
1706
    my $signing_key_name = "";
1707
    my $signature_size = 0;
1708
    my $format_version = 0xCE500000;
1709
    my $compression_method = 0;
1710
    my $encryption_method = 0;
1711
    my $kek_name = "";
1712
    my $encryption_key_size = 0;
1713
    my $filename_size = length($filename);
1714
 
1715
    print OUTF pack("Z32", $signing_key_name);
1716
    print OUTF pack("n", $signature_size);
1717
    print OUTF pack("N", $format_version);
1718
    print OUTF pack("N", $content_type);
1719
    print OUTF pack("Q>", $gen_time);
1720
    print OUTF pack("N", $compression_method);
1721
    print OUTF pack("N", $encryption_method);
1722
    print OUTF pack("Z32", $kek_name);
1723
    print OUTF pack("n", $encryption_key_size);
1724
    print OUTF pack("n", $filename_size);
1725
    # Encryption key HERE
1726
    print OUTF pack("A$filename_size", $filename);
1727
 
1728
    my $buf;
1729
    while (read(INF,$buf,65536))
1730
    {
1731
        print OUTF $buf;
1732
    }
1733
    print OUTF $buf;
1734
    close INF;
1735
 
1736
    # Signature HERE
1737
 
1738
    # Finish with file.
1739
    close OUTF;
1740
}
1741
 
1119 dpurdie 1742
1;