Subversion Repositories DevTools

Rev

Rev 6302 | Rev 6314 | 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;
5649 dpurdie 27
use Digest::file qw(digest_file_hex);
5771 alewis 28
use Digest::file qw(digest_file_base64);
6306 dpurdie 29
use ArrayHashUtils;
1119 dpurdie 30
 
31
#
32
#   Globals
33
#
34
my @Manifests;                      # Manifest entries
1125 alewis 35
my $Manifest_has_version = 1;       # Create Manifest_xxxx by default
1121 dpurdie 36
my %package_dirs;                   # Package dirs discovered and used
1125 alewis 37
my $pkg_subdir;                     # Alternate packaging
1119 dpurdie 38
 
39
#-------------------------------------------------------------------------------
40
# Function        : BEGIN
41
#
42
# Description     : Setup directive hooks
43
#                   Register a function to be called just before we start to
44
#                   generate makefiles. This will be used to process the data
45
#                   collected in all the ManifestFiles directives
46
#
47
# Inputs          : None
48
#
49
# Returns         : None
50
#
51
BEGIN
52
{
53
    RegisterMakefileGenerate (\&ManifestFiles_Generate);
54
}
55
 
56
#-------------------------------------------------------------------------------
57
# Function        : ManifestFiles
58
#
59
# Description     : Create a ManifestFiles entry
60
#
61
# Inputs          : Platform             - Active Platform Selector
62
#                   Options              - One or more options
63
#                       --Name=Name             - Mandatory
64
#                       --Tier=Name             - Mandatory
65
#                       --Architecture=xxxx     - Default actitecture is the current target
66
#                       --Product=yyyy          - Product Family
67
#                       --Debian=BaseName[,--Prod,--Debug,--Arch=xxxx,--Product=yyyy]
6302 dpurdie 68
#                       --Apk=BaseName[,--Prod,--Debug,--Platform=pppp]
69
#                                                   Default platform = ANDROID
70
#                                                   Default type = Production
1119 dpurdie 71
#                       --MugPackage=Package[,--Subdir=subdir[,subdir]+]
72
#                       --SrcFile=xxx
1125 alewis 73
#                       --SrcFileNoCopy=xxx
1123 dpurdie 74
#                       --Comment=xxx           - Add comment to Manifst
1125 alewis 75
#                       --NoManifestVersion     - Create unversioned Manifest File
76
#                       --PkgSubdir=xxx         - Specifies packaging subdir
5105 dpurdie 77
#                       --ImportManifest=Package[,--Subdir=subdir,--ReWrite] - Import Manifest from package
5649 dpurdie 78
#                       --Md5                   - Add MD5 checksums to the Manifest File
5767 alewis 79
#                       --Dmf                   - Generate the Device Management Framework
80
#                                                 combined archive ZIP file.
81
#                       --DmfVersion=xxxx       - Generate the Device Management Framework
82
#                                                 combined archive ZIP using a modified
83
#                                                 version number; only for testing!
1119 dpurdie 84
#
85
# Returns         : Nothing
86
#
87
sub ManifestFiles
88
{
89
    my( $platforms, @elements ) = @_;
90
    Debug2( "ManifestFiles($platforms, @elements)" );
91
    return if ( ! ActivePlatform($platforms) );
92
 
93
    my $name;
94
    my $tier;
95
    my @files;
6306 dpurdie 96
    my %fileVersions;
1119 dpurdie 97
    my $mug_dir;
98
    my $default_arch = $::ScmPlatform;
99
    my $default_prod = '';
1129 dpurdie 100
    my $imported_manifest = 0;
5649 dpurdie 101
    my $include_md5 = 0;
5767 alewis 102
    my $generate_dmf = 0;
5771 alewis 103
    my $dmf_version = $::ScmBuildVersionFull;
1119 dpurdie 104
 
105
    #
106
    #   Collect user options
107
    #
108
    foreach ( @elements )
109
    {
110
        if ( m~^--Name=(.+)~ ) {
6302 dpurdie 111
            if ( $name ) {
1119 dpurdie 112
                ReportError ("ManifestFiles:--Name option is only allowed once");
113
                next;
114
            }
115
            $name = $1;
116
 
117
        } elsif ( m~^--Tier=(.+)~ ) {
6302 dpurdie 118
            if ( $tier ) {
1119 dpurdie 119
                ReportError ("ManifestFiles:--Tier option is only allowed once");
120
                next;
121
            }
122
            $tier = $1;
123
 
1123 dpurdie 124
        } elsif ( m~^--Comment=~ ) {
125
            my $cmt = $_;
126
            $cmt =~ s~.+=~~;
127
            $cmt =~ s~\s*\n\s*~\n~g;
128
            push @files, {'cmt' => $cmt };
129
 
1119 dpurdie 130
        } elsif ( m~^--Debian=(.+)~ ) {
6302 dpurdie 131
            push @files, {'file' => _LocateDebianFile($1, $default_arch, $default_prod)};
1119 dpurdie 132
 
6302 dpurdie 133
        } elsif ( m~^--Apk=(.+)~ ) {
6306 dpurdie 134
            my $apkData = _LocateApkFile($1, $default_arch);
135
            my ($fname, $fversion) = split($;, $apkData);
136
            $fileVersions{$fname} = $fversion;
137
            push @files, {'file' => $fname };
6302 dpurdie 138
 
1119 dpurdie 139
        } elsif ( m~^--SrcFile=(.+)~ ) {
1123 dpurdie 140
            push @files, {'file' => LocatePreReq($1)};
5649 dpurdie 141
 
1125 alewis 142
        } elsif ( m~^--SrcFileNoCopy=(.+)~ ) {
143
            push @files, {'filenocopy' => $1};
5649 dpurdie 144
 
1119 dpurdie 145
        } elsif ( m~^--MugPackage=(.+)~ ) {
6302 dpurdie 146
            if ( $mug_dir ) {
1119 dpurdie 147
                ReportError ("ManifestFiles:--MugPackage option is only allowed once");
148
                next;
5649 dpurdie 149
            }
6302 dpurdie 150
            $mug_dir = _LocateMugDir($1);
1119 dpurdie 151
 
152
        } elsif ( m/^--Arch(.*)=(.+)/ ) {
153
            $default_arch = $2;
154
 
155
        } elsif ( m/^--Product=(.+)/ ) {
156
            $default_prod = $1;
157
 
1125 alewis 158
        } elsif ( m/^--NoManifestVersion/i ) {
159
            $Manifest_has_version = 0;
160
 
161
        } elsif ( m/^--PkgSubdir=(.+)/i ) {
6302 dpurdie 162
            if ( $pkg_subdir ) {
1129 dpurdie 163
                ReportError ("ManifestFiles:--PkgSubdir option is only allowed once");
1125 alewis 164
                next;
165
            }
166
            $pkg_subdir = $1;
167
 
1129 dpurdie 168
        } elsif ( m/^--ImportManifest=(.+)/i ) {
6302 dpurdie 169
            my $import_info = _ImportManifest($1, $tier, $name);
1129 dpurdie 170
#DebugDumpData("ImportInfo", $import_info );
171
            push @files, {'manifest' => $import_info };
172
 
173
            #
174
            #   Fill in details unless already provided
175
            #
176
            $tier = $import_info->{'tier'} unless ( defined $tier );
177
            $name = $import_info->{'name'} unless ( defined $name );
178
            $imported_manifest = 1;
179
 
5649 dpurdie 180
        } elsif (m/^--Md5/i) {
181
            $include_md5 = 1
182
 
5767 alewis 183
        } elsif (m/^--Dmf/i) {
184
            $generate_dmf = 1
185
 
186
        } elsif ( m/^--DmfVersion=(.+)/ ) {
187
            $generate_dmf = 1;
188
            $dmf_version = $1;
189
 
1119 dpurdie 190
        } else {
191
            ReportError ("ManifestFiles: Unknown option or argument: $_");
192
 
193
        }
194
    }
195
 
196
    #
197
    #   Sanity test the user options
198
    #
199
    ReportError ("ManifestFiles: No name specified")
200
        unless $name;
201
    ReportError ("ManifestFiles: No tier specified")
1129 dpurdie 202
        unless defined ($tier);
6302 dpurdie 203
    ReportError ("ManifestFiles: Cannot mix --Debian/-Apk/--SrcFile with --MugPackage in one directive")
1129 dpurdie 204
        if ( $mug_dir && (@files || $imported_manifest) );
1119 dpurdie 205
    ReportError ("ManifestFiles: Must specify files to add to Manifest")
1129 dpurdie 206
        unless ( $mug_dir ||  @files || $imported_manifest);
1119 dpurdie 207
    ErrorDoExit();
208
 
209
    #
210
    #   Save information for processing at the end of the parsing phase
211
    #   Data collected from ALL the ManifestFiles directives will be collected
212
    #   and processed into one Manifest file
213
    #
214
    my %data;
215
    $data{tier} = $tier;
216
    $data{name} = $name;
217
    $data{files} = \@files;
6306 dpurdie 218
    $data{fileVersions} = \%fileVersions;
1119 dpurdie 219
    $data{mugdir} = $mug_dir;
1125 alewis 220
    $data{pkgsubdir} = $pkg_subdir;
5649 dpurdie 221
    $data{md5} = $include_md5;
5767 alewis 222
    $data{dmf} = $generate_dmf;
223
    $data{arch} = $default_arch;
224
    $data{dmf_version} = $dmf_version;
225
 
1129 dpurdie 226
#DebugDumpData("DirectiveData", \%data );
1119 dpurdie 227
 
228
    push @Manifests, \%data;
229
    return;
6302 dpurdie 230
}
1119 dpurdie 231
 
6302 dpurdie 232
#-------------------------------------------------------------------------------
233
# Function        : _LocateDebianFile
234
#
235
# Description     : Locate a debian file
236
#                   Internal Function
237
#
238
#                   Scan packages for the Debian package specified
239
#                   The user provides the base name of the package
240
#                   A Debian Package name has several fields
241
#                   These are:
242
#                       1) Base Name - Provided by the user
243
#                       2) Version - Version will be wildcarded
244
#                       3) Architecture - Wildcarded. Uses bin/arch directory
245
#
246
#                   Expect to find Debian Packages in the bin/PLATFORM subdir
247
#
248
# Inputs          : Debian base name, complete with suboptions
249
#
250
# Returns         : Full path of the file
251
#
252
sub _LocateDebianFile
253
{
254
    my ($arg, $arch, $product) = @_;
255
    Verbose("LocateDebianFile: Processing: $arg");
256
 
257
    my @type = qw( P D );
258
    my @debian_file_path;
6306 dpurdie 259
    my @searchPath;
6302 dpurdie 260
 
1119 dpurdie 261
    #
6302 dpurdie 262
    #   Extract sub-options
263
    #       --Prod[uction]
264
    #       --Debug
265
    #       --Arch[itecture]=yyy
266
    #       --Product=yyy
1119 dpurdie 267
    #
6302 dpurdie 268
    my ($base_name, @opts) = split( ',', $arg );
269
    foreach ( @opts )
270
    {
271
        if ( m/^--Arch(.*)=(.+)/ ) {
272
            $arch=$2;
273
        } elsif ( m/^--Product=(.+)/ ) {
274
            $product=$1;
275
        } elsif ( m/^--Prod/ ) {
276
            @type = 'P';
277
        } elsif ( m/^--Debug/ ) {
278
            @type = 'D';
279
        } else {
280
            Warning ('--Debian: Unknown Option: ' . $_);
281
        }
282
    }
283
 
5649 dpurdie 284
    #
6302 dpurdie 285
    #   Create a list of products
286
    #   ie: PRODUCT_ARCH
1119 dpurdie 287
    #
6302 dpurdie 288
    my @products;
289
    push @products, $product . '_' . $arch if ( $product );
290
    push @products, $arch;
291
 
1119 dpurdie 292
    #
6302 dpurdie 293
    #   Scan all packages for the specified debian package
1119 dpurdie 294
    #
6302 dpurdie 295
    foreach my $package_dir ( getPackagePaths ('--All') )
1119 dpurdie 296
    {
6302 dpurdie 297
        foreach my $type ( @type )
1119 dpurdie 298
        {
6302 dpurdie 299
            foreach my $prd ( @products )
1119 dpurdie 300
            {
6302 dpurdie 301
                foreach my $joiner ( qw(/ .) )
1119 dpurdie 302
                {
6302 dpurdie 303
                    my $dir = "$package_dir/bin$joiner$prd$type";
6306 dpurdie 304
                    UniquePush(\@searchPath, $dir);
5873 acammell 305
                    next unless ( -d $dir );
6302 dpurdie 306
                    my @files = glob ( "$dir/${base_name}_*.deb" );
5873 acammell 307
                    next unless ( @files );
308
                    push @debian_file_path, @files;
309
                    $package_dirs{$package_dir}{used} = 1;
310
                }
311
            }
1119 dpurdie 312
        }
6302 dpurdie 313
        foreach my $type ( @type )
314
        {
315
            foreach my $prd ( @products )
316
            {
317
                my $dir = "$package_dir";
6306 dpurdie 318
                UniquePush(\@searchPath, $dir);
6302 dpurdie 319
                next unless ( -d $dir );
320
                my @files = glob ( "$dir/${base_name}_*_${prd}_${type}.deb" );
321
                next unless ( @files );
322
                push @debian_file_path, @files;
323
                $package_dirs{$package_dir}{used} = 1;
324
            }
325
        }
1119 dpurdie 326
    }
327
 
6306 dpurdie 328
    #
329
    #   Keep user informed
330
    #   Report errors and provide useful information
331
    #
332
    if (IsVerbose(1) || IsDebug(1) || $#debian_file_path != 0)
333
    {
334
        Message ("Search for ($base_name). In search Path", @searchPath);
335
    }
336
 
6302 dpurdie 337
    ReportError ("Required Debian package not found: $base_name") unless @debian_file_path;
338
    ReportError ("Multiple matching Debian Packages located: $base_name", @debian_file_path ) if ( $#debian_file_path > 0 );
339
    return $debian_file_path[0];
340
}
341
 
342
#-------------------------------------------------------------------------------
343
# Function        : _LocateApkFile
344
#
345
# Description     : Locate a APK file
346
#                   Internal Function
347
#
348
#                   Scan packages for the APK package specified
349
#                   The user provides the base name of the package
350
#                   APK ( Android Packages )
351
#                   Expect to have a '-release' or '-debug' suffix, except those provided via a
352
#                   3rd party SDK.
353
#                   Expect to find APK Packages in the bin/PLATFORM(P/D) subdir
354
#                   Expect to find -debug in the <PLATFORM>D directory
355
#                   Expect to find -release' in the <PLATFORM>P directory
356
#                   
357
#                   Allow for:
358
#                       Full path to .apk file
359
#                       .apk in package root directory
360
#
361
# Inputs          : Apk base name, complete with suboptions
362
#
6306 dpurdie 363
# Returns         : Full path of the file $; PackageVersion
364
#                   apk packages do not appear to have version numbers in the file name
365
#                   Retain package version number for later processing
6302 dpurdie 366
#
367
sub _LocateApkFile
368
{
369
    my ($arg, $arch) = @_;
370
    Verbose("LocateApkFile: Processing: $arg");
371
 
372
    my @type = qw( P );
373
    my @apk_file_path;
374
    my %type = ('P' => '-release', 'D' => '-debug' );
6306 dpurdie 375
    my @searchPath;
6302 dpurdie 376
 
1119 dpurdie 377
    #
6302 dpurdie 378
    #   Extract sub-options
379
    #       --Prod[uction]
380
    #       --Debug
381
    #       --Architecture=yyy
1119 dpurdie 382
    #
6302 dpurdie 383
    my ($base_name, @opts) = split( ',', $arg );
384
    foreach ( @opts )
1119 dpurdie 385
    {
6302 dpurdie 386
        if ( m/^--Arch(.*)=(.+)/ ) {
387
            $arch=$2;
388
        } elsif ( m/^--Prod/ ) {
389
            @type = 'P';
390
        } elsif ( m/^--Debug/ ) {
391
            @type = 'D';
392
        } else {
393
            Warning ('--Apk: Unknown Option: ' . $_);
1119 dpurdie 394
        }
6302 dpurdie 395
    }
1119 dpurdie 396
 
6302 dpurdie 397
    #
398
    #   Scan all packages for the specified APK package
399
    #   Try:
400
    #       Raw name - for apks from the SDK or 3rd parties
401
    #       PLATFORM(P|D)/baseName-(release|debug) - Expected
402
    #       baseName-(release|debug) - Repackaged badly
6306 dpurdie 403
    # 
404
    foreach my $pkgEntry ( getPackageList() )
6302 dpurdie 405
    {
6306 dpurdie 406
        next if ($pkgEntry->getType() eq 'interface');
407
        my $pkgVersion = $pkgEntry->getVersion();
408
 
409
        my $pkgLocal = $pkgEntry->getBase(2);
410
        my $pkgRoot = $pkgEntry->getDir();
1119 dpurdie 411
 
6306 dpurdie 412
        #
413
        #   Helper function
414
        #   Uses closure
415
        #   Notes: Test the package in dpkg_archive so that we can retain the package-version
416
        #          Use the version in the interface directory if BuildPkgArchive
417
        #   $pkgLocal - Local base of the package. May in the interface directory
418
        #   $pkgRoot  - Directory in dpkg_achive. Will have version info
419
        #   $subdir   - subdir within the package
420
        #   $fname    - File to look for
421
        #   
422
        #   Returns: Nothing
423
        #   Maintains: apk_file_path. Tupple: filename, PackageVersion
424
        #
425
        my $testOneFile = sub {
426
            my ( $subdir, $fname) = @_;
427
            my $testFile = "$pkgRoot/$subdir";
428
            $testFile =~ s~//~/~g;
429
            $testFile =~ s~/$~~;
430
            UniquePush(\@searchPath, $testFile);
431
            return unless (-d $testFile);
6302 dpurdie 432
 
6306 dpurdie 433
            $testFile .= '/' . $fname;
434
            if (-f $testFile ) {
435
                if ($pkgLocal ne $pkgRoot) {
436
                    my $testFile2 = "$pkgLocal/$subdir/$fname";
437
                    $testFile2 =~ s~//~/~g;
438
                    if ( -f $testFile2 ) {
439
                        $testFile = $testFile2;
440
                    }
441
                }
442
 
443
             $testFile = join($;, $testFile, $pkgVersion);
444
             push @apk_file_path, $testFile;
445
            }
446
        };
447
 
448
        #
449
        #   Test for the specified file in the package root
450
        #
451
        $testOneFile->("", "${base_name}.apk");
452
 
453
        #
454
        #   Test for BIN/PLATFORM
455
        #   
6302 dpurdie 456
        foreach my $type ( @type )
1119 dpurdie 457
        {
6302 dpurdie 458
            my $typeSuffix = $type{$type};
6306 dpurdie 459
            foreach my $joiner ( qw(/ .) ) {
460
                $testOneFile->("bin$joiner$arch$type","${base_name}${typeSuffix}.apk");
1119 dpurdie 461
            }
462
        }
6306 dpurdie 463
 
6302 dpurdie 464
        foreach my $type ( @type )
465
        {
466
            my $typeSuffix = $type{$type};
6306 dpurdie 467
            $testOneFile->("","${base_name}${typeSuffix}.apk");
6302 dpurdie 468
        }
6306 dpurdie 469
        $package_dirs{$pkgRoot}{used} = 1 if (@apk_file_path) ;
1119 dpurdie 470
    }
1129 dpurdie 471
 
6306 dpurdie 472
    #
473
    #   Keep user informed
474
    #   Report errors and provide useful information
475
    #
476
    if (IsVerbose(1) || IsDebug(1) || $#apk_file_path != 0)
477
    {
478
        Message ("Search for ($base_name). In search Path", @searchPath);
479
    }
480
 
6302 dpurdie 481
    ReportError ("Required APK package not found: $base_name") unless @apk_file_path;
482
    ReportError ("Multiple matching APK Packages located: $base_name", @apk_file_path ) if ( $#apk_file_path > 0 );
6306 dpurdie 483
 
484
#DebugDumpData("apk_file_path", \@apk_file_path);
6302 dpurdie 485
    return $apk_file_path[0];
486
}
487
 
488
#-------------------------------------------------------------------------------
489
# Function        : _LocateMugDir
490
#
491
# Description     : Locate the directory containing the mugfiles
492
#                   Internal Function
493
#
494
# Inputs          : Mufile package, with embedded options
495
#
496
# Returns         : Full path
497
#
498
sub _LocateMugDir
499
{
500
    my ($mug_package) = @_;
501
 
1129 dpurdie 502
    #
6302 dpurdie 503
    #   Locate the mugfile subdir
1129 dpurdie 504
    #
6302 dpurdie 505
    my $package_name = $mug_package;
506
    my @dirs = 'mug';
507
    my $mug_dir;
508
 
1129 dpurdie 509
    #
6302 dpurdie 510
    #   Extract sub options
511
    #       --Subdir=xxxx,yyyy,zzzz
1129 dpurdie 512
    #
6302 dpurdie 513
    if ( $package_name =~ m/(.*?),--Subdir=(.*)/ )
1129 dpurdie 514
    {
6302 dpurdie 515
        $package_name = $1;
516
        @dirs = split( ',', $2 );
517
    }
1129 dpurdie 518
 
6302 dpurdie 519
    my $package = GetPackageEntry( $package_name );
520
    unless ( $package )
521
    {
522
        ReportError ("ManifestFiles: Package not known to build: $package_name");
523
        return undef;
524
    }
1129 dpurdie 525
 
6302 dpurdie 526
    foreach my $subdir ( @dirs )
527
    {
528
        my $dir = "$package->{'ROOT'}/$subdir";
529
        if ( -d $dir )
1129 dpurdie 530
        {
6302 dpurdie 531
            Warning ("Multiple Mugfile directories located. Only the first will be used",
532
                     "Ignoring: $subdir" )if ( $mug_dir );
533
            $mug_dir = $dir;
534
        }
535
    }
536
    ReportError ("Mugfile directory not found in package: $package_name")
537
        unless $mug_dir;
5105 dpurdie 538
 
6302 dpurdie 539
    return $mug_dir;
540
}
5105 dpurdie 541
 
1129 dpurdie 542
 
6302 dpurdie 543
#-------------------------------------------------------------------------------
544
# Function        : _ImportManifest
545
#
546
# Description     : Import an existing manifest
547
#
548
# Inputs          : Args    - PackageName[,Subdir=name,--ReWrite]
549
#                   tier    - May be null
550
#                   name    - May be null
551
#
552
# Returns         : A hash of data to be used later
553
#
554
sub _ImportManifest
555
{
556
    my ($args, $tier, $name) = @_;
557
    my @file_contents;
558
    my @file_list;
1129 dpurdie 559
 
6302 dpurdie 560
    #
561
    #   Locate the mugfile subdir
562
    #
563
    my $package_name = $args;
564
    my @dirs = 'mug';
565
    my $pkg_dir;
566
    my $pkg_root;
567
    my $manifest;
568
    my $first_tier;
569
    my $first_name;
570
    my $rewrite;
571
 
572
    #
573
    #   Extract sub options
574
    #       --Subdir=xxxx,yyyy,zzzz
575
    #       --ReWrite
576
    #
577
    if ( $package_name =~ m/(.*?)(,.*)/ )
578
    {
579
        $package_name = $1;
580
        my @subargs = split(',--', $2);
581
        foreach ( @subargs)
5105 dpurdie 582
        {
6302 dpurdie 583
            next unless (length($_) > 0);
584
            if (m~^Subdir=(.*)~i){
585
                @dirs = split( ',', $1 );
5105 dpurdie 586
 
6302 dpurdie 587
            } elsif (m~^ReWrite~i) {
588
                $rewrite = 1;
589
 
590
            } else {
591
                ReportError("ManifestFiles: Unknown suboption to ImportManifest:" . $_);
1129 dpurdie 592
            }
593
        }
6302 dpurdie 594
    }
1129 dpurdie 595
 
6302 dpurdie 596
    my $package = GetPackageEntry( $package_name );
597
    unless ( $package )
598
    {
599
        ReportError ("ManifestFiles: Package not known to build: $package_name");
600
        return undef;
601
    }
5105 dpurdie 602
 
6302 dpurdie 603
    if (defined ($rewrite) && ( !defined($tier) || !defined($name)))
604
    {
605
        ReportError ("ManifestFiles: ImportManifest. --ReWrite cannot be used unless tier and name are specified");
606
        return undef;
607
    }
1129 dpurdie 608
 
6302 dpurdie 609
    foreach my $subdir ( @dirs )
610
    {
611
        my $dir = "$package->{'ROOT'}/$subdir";
612
        my $root = $package->{'ROOT'};
613
        if ( -d $dir )
5105 dpurdie 614
        {
6302 dpurdie 615
            Warning ("Multiple Package directories located. Only the first will be used",
616
                     "Ignoring: $subdir" )if ( $pkg_dir );
617
            $pkg_dir = $dir;
618
            $pkg_root = $root;
5105 dpurdie 619
        }
6302 dpurdie 620
    }
1129 dpurdie 621
 
6302 dpurdie 622
    unless ($pkg_dir)
623
    {
624
        ReportError ("Package directory not found in package: $package_name");
625
        return undef;
626
    }
5105 dpurdie 627
 
6302 dpurdie 628
    #
629
    #   Determine Manifest File name
630
    #
631
    foreach my $file ( glob ($pkg_dir . '/Manifest*' ) )
632
    {
633
            next unless ( -f $file );
634
            Warning ("Multiple Manifest Files find. Only the first will be used",
635
                     "Using: $manifest",
636
                     "Ignoring: $file" ) if ( $manifest );
637
            $manifest = $file;
638
    }
639
 
640
    unless ($manifest)
641
    {
642
        ReportError ("ImportManifest. No Manifest found: $package_name");
643
        return undef;
644
    }
645
 
646
 
647
    #
648
    #
649
    #
650
    open (MF, '<', $manifest ) || Error ("Cannot open the Manifest file: $manifest", $!);
651
    while ( <MF> )
652
    {
1129 dpurdie 653
        #
6302 dpurdie 654
        #   Clean trailing whitespace ( line-feed and new lines )
655
        #   Comment out [Version] data
1129 dpurdie 656
        #
6302 dpurdie 657
        s~\s+$~~;
658
        s~(\s*\[Version])~#$1~;
659
 
5649 dpurdie 660
        #
6302 dpurdie 661
        #   Part lines and determine files
662
        #
663
        next unless ( $_ );
664
        next if ( m~\s*#~ );
665
        next if ( m~\s*\[~ );
666
        my( $aname, $atier, $afile) = split(/\s*\,\s*/, $_);
1129 dpurdie 667
#            print "---------- $_\n";
668
#            print "T: $atier, N:$aname, F:$afile\n";
6302 dpurdie 669
        push @file_list, $afile;
1129 dpurdie 670
 
6302 dpurdie 671
        #
672
        #   Rewrite the name and tier
673
        #
674
        if ($rewrite)
675
        {
676
            $_ = join(',', $name, $tier, $afile);
677
            $first_tier = $tier;
678
            $first_name = $name;
679
        }
680
        else
681
        {
1129 dpurdie 682
            #
6302 dpurdie 683
            #   Capture first tier and name
1129 dpurdie 684
            #
6302 dpurdie 685
            $first_tier = $atier unless ( defined $first_tier );
686
            $first_name = $aname unless ( defined $first_name );
1129 dpurdie 687
        }
6302 dpurdie 688
    }
689
    continue
690
    {
691
        push @file_contents, $_;
692
    }
693
    close MF;
1129 dpurdie 694
 
6302 dpurdie 695
    #
696
    #   Create a hash of data that describes the manifest that has
697
    #   just been read in.
698
    #
699
    $package_dirs{$pkg_root}{used} = 1;
700
    $manifest =~ s~.*/~~;
701
    return { 'contents' => \@file_contents,
702
              'files' => \@file_list,
703
              'file_base' => $pkg_dir,
704
              'manifest' => $manifest,
705
              'pkg_dir' => $pkg_root,
706
              'tier' => $first_tier,
707
              'name' => $first_name,
708
              'rewrite' => $rewrite,
709
            };
1119 dpurdie 710
}
711
 
712
#-------------------------------------------------------------------------------
713
# Function        : ManifestFiles_Generate
714
#
715
# Description     : Internal Function
716
#                   Process all the collected data and create directives
717
#                   for the creation of the manifest
718
#
719
#                   This function will be called, just before the Makefile
720
#                   is created. The function will:
721
#                       1) Create the Manifest File
722
#                       2) Package the Manifest File
723
#                       3) Package the manifest file contents
724
#
725
#                   using (mostly) normal makefile.pl directives.
726
#
727
# Inputs          : None
728
#
729
# Returns         : Nothing
730
#
731
sub ManifestFiles_Generate
732
{
733
    Debug ("ManifestFiles_Generate");
734
    Message ("Generating Manifest File");
1123 dpurdie 735
 
736
    #
737
    #   Need at least one Manifest Entry
738
    #
739
    return unless ( @Manifests );
1119 dpurdie 740
#DebugDumpData ( "Manifests", \@Manifests );
741
 
742
    #
1125 alewis 743
    #   Determine the target packaging directory
744
    #   Default is .../mug
745
    #
746
    my $pkgdir = 'mug';
1129 dpurdie 747
    if ( exists $Manifests[0]->{pkgsubdir} && defined $Manifests[0]->{pkgsubdir} )
1125 alewis 748
    {
749
        my $subdir = $Manifests[0]->{pkgsubdir};
750
        $pkgdir .= '/' . $subdir;
751
        $pkgdir =~ s~^mug/mug~mug~;
752
    }
753
 
754
    #
1119 dpurdie 755
    #   Create the Manifest File as we process the lists
1125 alewis 756
    #   Place this in the 'lib' directory:
1119 dpurdie 757
    #       - So that it will be deleted on clobber
1123 dpurdie 758
    #       - So that it can be placed in a target-specific subdir
1125 alewis 759
    #       - So that we can have one per makefile.pl
1119 dpurdie 760
    #
761
    Error ("ManifestFiles: Needs local directory specified in build.pl") unless ( $::ScmLocal );
762
 
1125 alewis 763
    my $manifest_dir = "$::ScmPlatform.LIB";
1119 dpurdie 764
    System( "$::GBE_BIN/mkdir -p $manifest_dir" );
765
 
1125 alewis 766
    my $manifest_file = $manifest_dir . '/Manifest';
767
    $manifest_file .= '_' . $::ScmBuildVersion if ( $Manifest_has_version );
768
    ToolsetGenerate( $manifest_file );
1119 dpurdie 769
    Verbose ("ManifestFiles_Generate: File: $manifest_file");
5649 dpurdie 770
 
1125 alewis 771
    PackageFile ('*', $manifest_file, '--Subdir=' . $pkgdir, '--Strip' );
1119 dpurdie 772
 
773
    open (MF, '>', $manifest_file ) || Error ("Cannot create the Manifest file: $manifest_file");
774
 
5711 kspencer 775
    binmode (MF);
5767 alewis 776
 
1119 dpurdie 777
    print_mf ("# PackageName: $::ScmBuildPackage");
778
    print_mf ("# PackageVersion: $::ScmBuildVersion");
779
    print_mf ("# BuildDate: $::CurrentTime");
780
    print_mf ("#");
781
    print_mf ("[Version],$::ScmBuildVersion");
782
    print_mf ("#");
783
 
784
    #
1125 alewis 785
    #   Process each tier in the order presented in the source file
1119 dpurdie 786
    #
1123 dpurdie 787
    my $last_was_comment = 0;
1119 dpurdie 788
    foreach my $entry ( @Manifests )
789
    {
1127 alewis 790
    #print_mf ("#");
1119 dpurdie 791
 
792
#DebugDumpData ( "Manifest Entry", $entry );
793
 
794
        my $tier = $entry->{tier};
795
        my $name = $entry->{name};
5649 dpurdie 796
        my $include_md5 = $entry->{md5};
1119 dpurdie 797
 
5767 alewis 798
        if ( $entry->{dmf} )
799
        {
6302 dpurdie 800
            DmfGenerate($entry);
5767 alewis 801
        }
802
 
1119 dpurdie 803
        #
804
        #   Insert all the files that have been specified
805
        #   The user specified order is preserved
806
        #
1123 dpurdie 807
        #   Entries may be either a file or a comment
808
        #   Comments: Merge multiple comments and create blocks
809
        #
810
        #
1119 dpurdie 811
        my @files = @{ $entry->{files} };
1123 dpurdie 812
        foreach my $fentry ( @files )
1119 dpurdie 813
        {
1123 dpurdie 814
            if ( my $cmt = $fentry->{'cmt'} )
815
            {
816
                print_mf ('') unless ( $last_was_comment ) ;
817
                print_mf ( map (('# ' . $_) , split ("\n", $cmt) ));
818
                $last_was_comment = 1;
819
                next;
820
            }
821
 
822
            print_mf ('#') if ( $last_was_comment );
823
            if ( my $file = $fentry->{'file'} )
824
            {
825
                my $base_file = StripDir( $file );
6306 dpurdie 826
                my @extraItems;
5649 dpurdie 827
                if ($include_md5) {
828
                    my $md5 = digest_file_hex($file, 'MD5');
6306 dpurdie 829
                    push @extraItems, "MD5=$md5" ;
830
                }
831
 
832
                if (exists $entry->{fileVersions} && exists $entry->{fileVersions}{$file} ) {
833
                    push @extraItems, "VERSION=" . $entry->{fileVersions}{$file};
834
                }
835
                if (@extraItems) {
836
                    print_mf ('--NoCheckLineWidth', "$name,$tier,$base_file," . join (',', @extraItems));
5649 dpurdie 837
                } else {
838
                    print_mf ("$name,$tier,$base_file");
839
                }
1125 alewis 840
                PackageFile ('*', $file, '--Subdir=' . $pkgdir, '--Strip' );
1123 dpurdie 841
                $last_was_comment = 0;
842
            }
1125 alewis 843
 
844
            if ( my $file = $fentry->{'filenocopy'} )
845
            {
846
                print_mf ("$name,$tier,$file");
847
                $last_was_comment = 0;
848
            }
1129 dpurdie 849
 
850
            if ( my $emf = $fentry->{'manifest'} )
851
            {
852
                $last_was_comment = 0;
853
                #
854
                #   Insert the entire manifest
855
                #   Items are:
856
                #        contents
857
                #        files
858
                #        file_base
859
                #        manifest
860
                #
861
#DebugDumpData ( "Embedded Manifest Entry", $emf );
862
                print_mf ( '## Included Manifest: ' .  $emf->{'manifest'}  );
863
                print_mf ($_) foreach  ( @{$emf->{'contents'}} );
864
                PackageFile ('*', $emf->{'file_base'}. '/' . $_, '--Subdir=' . $pkgdir, '--Strip' )foreach  ( @{$emf->{'files'}});;
865
                print_mf ( '## End Included Manifest' );
866
            }
1119 dpurdie 867
        }
868
 
869
        #
870
        #   Expand out the entire MUG directory
871
        #   All .mug files in the MUG directory will be added to the manifest
872
        #   The assumption is that the MUG directory has been created by
873
        #   something that knows what its doing
874
        #
875
        if ( my $mugdir = $entry->{mugdir} )
876
        {
877
            foreach my $file ( glob ($mugdir . '/*.mug' ) )
878
            {
879
                next unless ( -f $file );
880
                my $base_file = StripDir($file);
5654 dpurdie 881
                if ($include_md5) {
882
                    my $md5 = digest_file_hex($file, 'MD5');
883
                    print_mf ('--NoCheckLineWidth', "$name,$tier,$base_file,MD5=$md5");
884
                } else {
885
                    print_mf ("$name,$tier,$base_file");
886
                }
1119 dpurdie 887
                PackageFile ('*', $file, '--Subdir=mug', '--Strip' );
888
            }
889
        }
890
    }
891
 
892
    #
893
    #   Complete the creation of the Manifest File
894
    #
895
    print_mf ("#");
896
    print_mf ("# End of File");
897
    close MF;
898
    ErrorDoExit();
1121 dpurdie 899
 
900
    #
901
    #   Sanity test of packages that did not provide a debian file
902
    #   Just a hint that something may have been missed
903
    #
904
    my @not_used_packages;
905
    foreach my $package_dir ( getPackagePaths ('--All') )
906
    {
907
        next if ( $package_dir =~ m~/manifest-tool/~ );
908
        unless ( exists $package_dirs{$package_dir}{used} )
909
        {
910
            push @not_used_packages, $package_dir;
911
        }
912
    }
913
    if ( @not_used_packages )
914
    {
915
        Warning ("Packages that did not contribute packages to the manifest:",
916
                  @not_used_packages );
917
    }
918
 
1119 dpurdie 919
    return;
920
 
921
    #-------------------------------------------------------------------------------
922
    # Function        : print_mf
923
    #
924
    # Description     : Internal Function
925
    #                   Print one line to the Manifest File
926
    #                   Checks the length of the line being created
927
    #
928
    # Inputs          : $line
929
    #
5649 dpurdie 930
    # Returns         :
1119 dpurdie 931
    #
932
 
933
    sub print_mf
934
    {
5649 dpurdie 935
        my $check_line_width = 1;
936
 
937
        if ($_[0] eq '--NoCheckLineWidth')
938
        {
939
            shift @_;
940
            $check_line_width = 0;
941
        }
942
 
1119 dpurdie 943
        foreach  ( @_ )
944
        {
945
            ReportError ( "Manifest line too long",
5649 dpurdie 946
                    "Line: $_" ) if ( $check_line_width && length ($_) > 79);
1119 dpurdie 947
            print MF $_ . "\n";
948
        }
949
    }
950
}
951
 
5767 alewis 952
# Bring in the DMF build requirements.
953
my $directory;
954
BEGIN {
955
    use File::Spec::Functions qw(rel2abs);
956
    use File::Basename qw(dirname);
957
 
958
    my $path = rel2abs( __FILE__ );
959
    $directory = dirname( $path );
960
}
961
use lib $directory;
962
 
963
use Archive::Zip qw( :ERROR_CODES :CONSTANTS );
964
use JSON;
965
 
966
#-------------------------------------------------------------------------------
967
# Function        : DmfGenerate
968
#
969
# Description     : Import an existing manifest
970
#
971
# Inputs          : entry   - The manifest that is being processed.
972
#
973
# Returns         : Nothing
974
#
975
sub DmfGenerate
976
{
977
    my ($entry) = @_;
978
 
979
    # Get the generation time.
980
    my $gen_time = time();
981
 
982
    my $work_dir = "$::ScmPlatform.BIN/";
983
    System( "$::GBE_BIN/mkdir -p $work_dir" );
984
 
985
    my $name = $entry->{name};
986
    my $version = $entry->{dmf_version};
987
 
988
    # Configure base manifest information.
989
    my %manifest;
5771 alewis 990
    $manifest{'mugsetId'} = $name . '_' . $version;
5767 alewis 991
    $manifest{'name'} = $name;
992
    $manifest{'version'} = $version;
5771 alewis 993
    $manifest{'packageName'} = $::ScmBuildPackage;
994
    $manifest{'packageVersion'} = $::ScmBuildVersionFull;
5767 alewis 995
    $manifest{'datetime'} = localtime($gen_time);
996
    $gen_time *= 1000;  # Make to milliseconds
997
    $manifest{'timestamp'} = $gen_time;
998
    $manifest{'tier'} = $entry->{tier};
999
 
1000
    # Process each file.
1001
    my @files = @{ $entry->{files} };
1002
    my $zip = Archive::Zip->new();
1003
    my $i = 0;
1004
    foreach my $fentry ( @files )
1005
    {
1006
        if ( my $file = $fentry->{'file'} )
1007
        {
6302 dpurdie 1008
            my $order = $i + 1;
5767 alewis 1009
            my $base_file = StripDir( $file );
1010
            my $publish_file = $name . '_' . $version . '_' . $order . '.aup';
1011
            my $aup_file = $work_dir . $publish_file;
1012
 
1013
            GenerateCesFile($file, $aup_file, 0x3, $gen_time, $publish_file);
1014
 
1015
            my $file_member = $zip->addFile( $aup_file, $publish_file );
1016
 
1017
            $manifest{'tasks'}[$i]{'order'} = 1 * $order;
1018
            $manifest{'tasks'}[$i]{'filename'} = $base_file;
1019
            $manifest{'tasks'}[$i]{'download'} = $publish_file;
5771 alewis 1020
            $manifest{'tasks'}[$i]{'sha256'} = digest_file_base64($file, 'SHA-256');
1021
            $manifest{'tasks'}[$i]{'size'} = -s $file;
1022
 
5767 alewis 1023
            if ($base_file =~ /\.sh$/)
1024
            {
1025
                $manifest{'tasks'}[$i]{'action'} = 'exec-shell';
1026
            }
1027
            elsif ($base_file =~ /\.deb$/)
1028
            {
1029
                $manifest{'tasks'}[$i]{'action'} = 'dpkg-install';
5771 alewis 1030
 
1031
                my ($pkg_name, $pkg_version, $pkg_arch) = ($base_file =~ /([^_]*)_([^_]*)_(.*)/);
1032
                $manifest{'tasks'}[$i]{'arch'} = $pkg_arch;
1033
                $manifest{'tasks'}[$i]{'name'} = $pkg_name;
1034
                $manifest{'tasks'}[$i]{'version'} = $pkg_version;
5767 alewis 1035
            }
1036
            else
1037
            {
1038
                ReportError ("Manifest entry $base_file does not have a supported DMF install action");
1039
            }
1040
 
1041
            $i = $i + 1;
1042
        }
1043
    }
1044
 
1045
    # Encode and commit the JSON.
1046
    my $json_encoder = JSON->new->allow_nonref;
1047
    my $json = $json_encoder->pretty->encode( \%manifest );
1048
 
1049
    my $manifest_filename = $name . '_' . $version;
1050
    my $aum_filename = $manifest_filename . '_0.aum';
1051
    my $manifest_file = $work_dir . $manifest_filename . '.json';
1052
    my $aum_file = $work_dir . $aum_filename;
1053
 
1054
    # Save our manifest.
1055
    open (J, '>', $manifest_file ) || Error ("Cannot create the DMF Manifest file");
1056
    binmode (J);
1057
    print J $json;
1058
 
1059
    close J;
1060
 
1061
    GenerateCesFile($manifest_file, $aum_file, 0x2, $gen_time, $aum_filename);
1062
 
1063
    $zip->addFile($aum_file, $aum_filename);
1064
 
1065
    my $zip_filename = $work_dir . $name . '_' . $version . '.zip';
1066
    if ( $zip->writeToFileNamed($zip_filename) != AZ_OK )
1067
    {
1068
        ReportError("DMF ZIP file creation failed");
1069
    }
1070
    PackageFile('*', $zip_filename, '--Strip');
1071
    PackageFile('*', $manifest_file, '--Strip');
1072
 
1073
}
1074
 
1075
#-------------------------------------------------------------------------------
1076
# Function        : DmfGenerate
1077
#
1078
# Description     : Import an existing manifest
1079
#
1080
# Inputs          : src_file     - The input file.
1081
#                   dst_file     - The output CES file.
1082
#                   content_type - The content type to report.
1083
#                   gen_time     - The generation time for the file.
1084
#                   filename     - The filename to embed in the CES file.
1085
#
1086
#
1087
# Returns         : Nothing
1088
#
1089
sub GenerateCesFile
1090
{
1091
    my ($src_file, $dst_file, $content_type, $gen_time, $filename) = @_;
1092
 
1093
    open (INF, '<', $src_file ) || Error ("Cannot open file $src_file for reading");
1094
    binmode (INF);
1095
 
1096
    open (OUTF, '>', $dst_file ) || Error ("Cannot open file $dst_file for writing");
1097
    binmode (OUTF);
1098
 
1099
    my $signing_key_name = "";
1100
    my $signature_size = 0;
1101
    my $format_version = 0xCE500000;
1102
    my $compression_method = 0;
1103
    my $encryption_method = 0;
1104
    my $kek_name = "";
1105
    my $encryption_key_size = 0;
1106
    my $filename_size = length($filename);
1107
 
1108
    print OUTF pack("Z32", $signing_key_name);
1109
    print OUTF pack("n", $signature_size);
1110
    print OUTF pack("N", $format_version);
1111
    print OUTF pack("N", $content_type);
1112
    print OUTF pack("Q>", $gen_time);
1113
    print OUTF pack("N", $compression_method);
1114
    print OUTF pack("N", $encryption_method);
1115
    print OUTF pack("Z32", $kek_name);
1116
    print OUTF pack("n", $encryption_key_size);
1117
    print OUTF pack("n", $filename_size);
1118
    # Encryption key HERE
1119
    print OUTF pack("A$filename_size", $filename);
1120
 
1121
    my $buf;
1122
    while (read(INF,$buf,65536))
1123
    {
1124
        print OUTF $buf;
1125
    }
1126
    print OUTF $buf;
1127
    close INF;
1128
 
1129
    # Signature HERE
1130
 
1131
    # Finish with file.
1132
    close OUTF;
1133
}
1134
 
1119 dpurdie 1135
1;