Subversion Repositories DevTools

Rev

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