Subversion Repositories DevTools

Rev

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