Rev 6314 | Rev 6734 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
######################################################################### COPYRIGHT - VIX IP PTY LTD ("VIX"). ALL RIGHTS RESERVED.## Module name : ManifestFiles.pm# Module type : Makefile system# Environment(s): JATS Build System# Documents : MASS-00232 Format of the Linux App Upgrade Manifest File## Description : This package extends the JATS toolset at build time# It provides additional directives to the JATS makefiles# to simplify the directives.## This directive does all its work at 'build' time# It uses makefile.pl directives## Operation : This package adds the JATS directive ManifestFiles# This is used to create linux manifest files## Syntax : ManifestFiles (<platforms>, Options+);# See the function header for details##......................................................................#require 5.6.1;use strict;use warnings;use Digest::file qw(digest_file_hex);use Digest::file qw(digest_file_base64);use ArrayHashUtils;## Globals#my @Manifests; # Manifest entriesmy $Manifest_has_version = 1; # Create Manifest_xxxx by defaultmy %package_dirs; # Package dirs discovered and usedmy $pkg_subdir; # Alternate packagingmy $ManifestLineWidth; # Max length of lines#-------------------------------------------------------------------------------# Function : BEGIN## Description : Setup directive hooks# Register a function to be called just before we start to# generate makefiles. This will be used to process the data# collected in all the ManifestFiles directives## Inputs : None## Returns : None#BEGIN{RegisterMakefileGenerate (\&ManifestFiles_Generate);}#-------------------------------------------------------------------------------# Function : ManifestFiles## Description : Create a ManifestFiles entry## Inputs : Platform - Active Platform Selector# Options - One or more options# --Name=Name - Mandatory# --Tier=Name - Mandatory# --Architecture=xxxx - Default actitecture is the current target# --Product=yyyy - Product Family# --Debian=BaseName[,--Prod,--Debug,--Arch=xxxx,--Product=yyyy]# --Apk=BaseName[,--Prod,--Debug,--Platform=pppp]# Default platform = ANDROID# Default type = Production# --MugPackage=Package[,--Subdir=subdir[,subdir]+]# --SrcFile=xxx# --SrcFileNoCopy=xxx# --Comment=xxx - Add comment to Manifst# --NoManifestVersion - Create unversioned Manifest File# --PkgSubdir=xxx - Specifies packaging subdir# --ImportManifest=Package[,--Subdir=subdir,--ReWrite] - Import Manifest from package# --Md5 - Add MD5 checksums to the Manifest File# --Dmf - Generate the Device Management Framework# combined archive ZIP file.# --DmfVersion=xxxx - Generate the Device Management Framework# combined archive ZIP using a modified# version number; only for testing!# --LineLength=nnn - Limit line length. Default is 79# --SubManifest - Create a sub-manifest (not installable). Manifest will have no version.# Gives a default name, tier and subdir if not explicitly provided.## Returns : Nothing#sub ManifestFiles{my( $platforms, @elements ) = @_;Debug2( "ManifestFiles($platforms, @elements)" );return if ( ! ActivePlatform($platforms) );my $name;my $tier;my @files;my %fileVersions;my $mug_dir;my $default_arch = $::ScmPlatform;my $default_prod = '';my $imported_manifest = 0;my $include_md5 = 0;my $generate_dmf = 0;my $dmf_version = $::ScmBuildVersionFull;my $useDefaultLineWidth = 1;my $is_sub_manifest = 0;## Collect user options#foreach ( @elements ){if ( m~^--Name=(.+)~ ) {if ( $name ) {ReportError ("ManifestFiles:--Name option is only allowed once");next;}$name = $1;} elsif ( m~^--Tier=(.+)~ ) {if ( $tier ) {ReportError ("ManifestFiles:--Tier option is only allowed once");next;}$tier = $1;} elsif ( m~^--Comment=~ ) {my $cmt = $_;$cmt =~ s~.+=~~;$cmt =~ s~\s*\n\s*~\n~g;push @files, {'cmt' => $cmt };} elsif ( m~^--Debian=(.+)~ ) {push @files, {'file' => _LocateDebianFile($1, $default_arch, $default_prod)};} elsif ( m~^--Apk=(.+)~ ) {my $apkData = _LocateApkFile($1, $default_arch);my ($fname, $fversion) = split($;, $apkData);$fileVersions{$fname} = $fversion;push @files, {'file' => $fname };$useDefaultLineWidth = 0;} elsif ( m~^--SrcFile=(.+)~ ) {push @files, {'file' => LocatePreReq($1)};} elsif ( m~^--SrcFileNoCopy=(.+)~ ) {push @files, {'filenocopy' => $1};} elsif ( m~^--MugPackage=(.+)~ ) {if ( $mug_dir ) {ReportError ("ManifestFiles:--MugPackage option is only allowed once");next;}$mug_dir = _LocateMugDir($1);} elsif ( m/^--Arch(.*)=(.+)/ ) {$default_arch = $2;} elsif ( m/^--Product=(.+)/ ) {$default_prod = $1;} elsif ( m/^--NoManifestVersion/i ) {$Manifest_has_version = 0;} elsif ( m/^--PkgSubdir=(.+)/i ) {if ( $pkg_subdir ) {ReportError ("ManifestFiles:--PkgSubdir option is only allowed once");next;}$pkg_subdir = $1;} elsif ( m/^--ImportManifest=(.+)/i ) {my $import_info = _ImportManifest($1, $tier, $name);#DebugDumpData("ImportInfo", $import_info );push @files, {'manifest' => $import_info };## Fill in details unless already provided#$tier = $import_info->{'tier'} unless ( defined $tier );$name = $import_info->{'name'} unless ( defined $name );$imported_manifest = 1;} elsif (m/^--Md5/i) {$include_md5 = 1;$useDefaultLineWidth = 0;} elsif (m/^--Dmf/i) {$generate_dmf = 1} elsif ( m/^--DmfVersion=(.+)/ ) {$generate_dmf = 1;$dmf_version = $1;} elsif ( m/^--LineLength=(\d+)$/i ) {$ManifestLineWidth = $1;$useDefaultLineWidth = 0;} elsif (m/^--SubManifest/i) {$is_sub_manifest = 1;$Manifest_has_version = 0;$name = $::ScmPlatformunless $name;$pkg_subdir = $nameunless $pkg_subdir;$tier = 0unless defined($tier);} else {ReportError ("ManifestFiles: Unknown option or argument: $_");}}## Sanity test the user options#ReportError ("ManifestFiles: No name specified")unless $name;ReportError ("ManifestFiles: No tier specified")unless defined ($tier);ReportError ("ManifestFiles: Cannot mix --Debian/-Apk/--SrcFile with --MugPackage in one directive")if ( $mug_dir && (@files || $imported_manifest) );ReportError ("ManifestFiles: Must specify files to add to Manifest")unless ( $mug_dir || @files || $imported_manifest);ErrorDoExit();## Set ManifestLineWidth# The default is largely historical - for MOS#unless (defined $ManifestLineWidth) {$ManifestLineWidth = $useDefaultLineWidth ? 79 : 0;}Verbose("ManifestLineWidth:$ManifestLineWidth");## Save information for processing at the end of the parsing phase# Data collected from ALL the ManifestFiles directives will be collected# and processed into one Manifest file#my %data;$data{tier} = $tier;$data{name} = $name;$data{files} = \@files;$data{fileVersions} = \%fileVersions;$data{mugdir} = $mug_dir;$data{pkgsubdir} = $pkg_subdir;$data{md5} = $include_md5;$data{dmf} = $generate_dmf;$data{arch} = $default_arch;$data{dmf_version} = $dmf_version;$data{is_sub_manifest} = $is_sub_manifest;#DebugDumpData("DirectiveData", \%data );push @Manifests, \%data;return;}#-------------------------------------------------------------------------------# Function : _LocateDebianFile## Description : Locate a debian file# Internal Function## Scan packages for the Debian package specified# The user provides the base name of the package# A Debian Package name has several fields# These are:# 1) Base Name - Provided by the user# 2) Version - Version will be wildcarded# 3) Architecture - Wildcarded. Uses bin/arch directory## Expect to find Debian Packages in the bin/PLATFORM subdir## Inputs : Debian base name, complete with suboptions## Returns : Full path of the file#sub _LocateDebianFile{my ($arg, $arch, $product) = @_;Verbose("LocateDebianFile: Processing: $arg");my @type = qw( P D );my @debian_file_path;my @searchPath;## Extract sub-options# --Prod[uction]# --Debug# --Arch[itecture]=yyy# --Product=yyy#my ($base_name, @opts) = split( ',', $arg );foreach ( @opts ){if ( m/^--Arch(.*)=(.+)/ ) {$arch=$2;} elsif ( m/^--Product=(.+)/ ) {$product=$1;} elsif ( m/^--Prod/ ) {@type = 'P';} elsif ( m/^--Debug/ ) {@type = 'D';} else {Warning ('--Debian: Unknown Option: ' . $_);}}## Create a list of products# ie: PRODUCT_ARCH#my @products;push @products, $product . '_' . $arch if ( $product );push @products, $arch;## Scan all packages for the specified debian package#foreach my $package_dir ( getPackagePaths ('--All') ){foreach my $type ( @type ){foreach my $prd ( @products ){foreach my $joiner ( qw(/ .) ){my $dir = "$package_dir/bin$joiner$prd$type";UniquePush(\@searchPath, $dir);next unless ( -d $dir );my @files = glob ( "$dir/${base_name}_*.deb" );next unless ( @files );push @debian_file_path, @files;$package_dirs{$package_dir}{used} = 1;}}}foreach my $type ( @type ){foreach my $prd ( @products ){my $dir = "$package_dir";UniquePush(\@searchPath, $dir);next unless ( -d $dir );my @files = glob ( "$dir/${base_name}_*_${prd}_${type}.deb" );next unless ( @files );push @debian_file_path, @files;$package_dirs{$package_dir}{used} = 1;}}}## Keep user informed# Report errors and provide useful information#if (IsVerbose(1) || IsDebug(1) || $#debian_file_path != 0){Message ("Search for ($base_name). In search Path", @searchPath);}ReportError ("Required Debian package not found: $base_name") unless @debian_file_path;ReportError ("Multiple matching Debian Packages located: $base_name", @debian_file_path ) if ( $#debian_file_path > 0 );return $debian_file_path[0];}#-------------------------------------------------------------------------------# Function : _LocateApkFile## Description : Locate a APK file# Internal Function## Scan packages for the APK package specified# The user provides the base name of the package# APK ( Android Packages )# Expect to have a '-release' or '-debug' suffix, except those provided via a# 3rd party SDK.# Expect to find APK Packages in the bin/PLATFORM(P/D) subdir# Expect to find -debug in the <PLATFORM>D directory# Expect to find -release' in the <PLATFORM>P directory## Allow for:# Full path to .apk file# .apk in package root directory## Inputs : Apk base name, complete with suboptions## Returns : Full path of the file $; PackageVersion# apk packages do not appear to have version numbers in the file name# Retain package version number for later processing#sub _LocateApkFile{my ($arg, $arch) = @_;Verbose("LocateApkFile: Processing: $arg");my @type = qw( P );my @apk_file_path;my %type = ('P' => '-release', 'D' => '-debug' );my @searchPath;## Extract sub-options# --Prod[uction]# --Debug# --Architecture=yyy#my ($base_name, @opts) = split( ',', $arg );foreach ( @opts ){if ( m/^--Arch(.*)=(.+)/ ) {$arch=$2;} elsif ( m/^--Prod/ ) {@type = 'P';} elsif ( m/^--Debug/ ) {@type = 'D';} else {Warning ('--Apk: Unknown Option: ' . $_);}}## Scan all packages for the specified APK package# Try:# Raw name - for apks from the SDK or 3rd parties# PLATFORM(P|D)/baseName-(release|debug) - Expected# baseName-(release|debug) - Repackaged badly#foreach my $pkgEntry ( getPackageList() ){next if ($pkgEntry->getType() eq 'interface');my $pkgVersion = $pkgEntry->getVersion();my $pkgLocal = $pkgEntry->getBase(2);my $pkgRoot = $pkgEntry->getDir();## Helper function# Uses closure# Notes: Test the package in dpkg_archive so that we can retain the package-version# Use the version in the interface directory if BuildPkgArchive# $pkgLocal - Local base of the package. May in the interface directory# $pkgRoot - Directory in dpkg_achive. Will have version info# $subdir - subdir within the package# $fname - File to look for## Returns: Nothing# Maintains: apk_file_path. Tupple: filename, PackageVersion#my $testOneFile = sub {my ( $subdir, $fname) = @_;my $testFile = "$pkgRoot/$subdir";$testFile =~ s~//~/~g;$testFile =~ s~/$~~;UniquePush(\@searchPath, $testFile);return unless (-d $testFile);$testFile .= '/' . $fname;if (-f $testFile ) {if ($pkgLocal ne $pkgRoot) {my $testFile2 = "$pkgLocal/$subdir/$fname";$testFile2 =~ s~//~/~g;if ( -f $testFile2 ) {$testFile = $testFile2;}}$testFile = join($;, $testFile, $pkgVersion);push @apk_file_path, $testFile;}};## Test for the specified file in the package root#$testOneFile->("", "${base_name}.apk");## Test for BIN/PLATFORM#foreach my $type ( @type ){my $typeSuffix = $type{$type};foreach my $joiner ( qw(/ .) ) {$testOneFile->("bin$joiner$arch$type","${base_name}${typeSuffix}.apk");}}foreach my $type ( @type ){my $typeSuffix = $type{$type};$testOneFile->("","${base_name}${typeSuffix}.apk");}$package_dirs{$pkgRoot}{used} = 1 if (@apk_file_path) ;}## Keep user informed# Report errors and provide useful information#if (IsVerbose(1) || IsDebug(1) || $#apk_file_path != 0){Message ("Search for ($base_name). In search Path", @searchPath);}ReportError ("Required APK package not found: $base_name") unless @apk_file_path;ReportError ("Multiple matching APK Packages located: $base_name", @apk_file_path ) if ( $#apk_file_path > 0 );#DebugDumpData("apk_file_path", \@apk_file_path);return $apk_file_path[0];}#-------------------------------------------------------------------------------# Function : _LocateMugDir## Description : Locate the directory containing the mugfiles# Internal Function## Inputs : Mufile package, with embedded options## Returns : Full path#sub _LocateMugDir{my ($mug_package) = @_;## Locate the mugfile subdir#my $package_name = $mug_package;my @dirs = 'mug';my $mug_dir;## Extract sub options# --Subdir=xxxx,yyyy,zzzz#if ( $package_name =~ m/(.*?),--Subdir=(.*)/ ){$package_name = $1;@dirs = split( ',', $2 );}my $package = GetPackageEntry( $package_name );unless ( $package ){ReportError ("ManifestFiles: Package not known to build: $package_name");return undef;}foreach my $subdir ( @dirs ){my $dir = "$package->{'ROOT'}/$subdir";if ( -d $dir ){Warning ("Multiple Mugfile directories located. Only the first will be used","Ignoring: $subdir" )if ( $mug_dir );$mug_dir = $dir;}}ReportError ("Mugfile directory not found in package: $package_name")unless $mug_dir;return $mug_dir;}#-------------------------------------------------------------------------------# Function : _ImportManifest## Description : Import an existing manifest## Inputs : Args - PackageName[,Subdir=name,--ReWrite]# tier - May be null# name - May be null## Returns : A hash of data to be used later#sub _ImportManifest{my ($args, $tier, $name) = @_;my @file_contents;my @item_list;## Locate the mugfile subdir#my $package_name = $args;my @dirs = 'mug';my $pkg_dir;my $pkg_root;my $manifest;my $first_tier;my $first_name;my $rewrite;## Extract sub options# --Subdir=xxxx,yyyy,zzzz# --ReWrite#if ( $package_name =~ m/(.*?)(,.*)/ ){$package_name = $1;my @subargs = split(',--', $2);foreach ( @subargs){next unless (length($_) > 0);if (m~^Subdir=(.*)~i){@dirs = split( ',', $1 );} elsif (m~^ReWrite~i) {$rewrite = 1;} else {ReportError("ManifestFiles: Unknown suboption to ImportManifest:" . $_);}}}my $package = GetPackageEntry( $package_name );unless ( $package ){ReportError ("ManifestFiles: Package not known to build: $package_name");return undef;}if (defined ($rewrite) && ( !defined($tier) || !defined($name))){ReportError ("ManifestFiles: ImportManifest. --ReWrite cannot be used unless tier and name are specified");return undef;}foreach my $subdir ( @dirs ){my $dir = "$package->{'ROOT'}/$subdir";my $root = $package->{'ROOT'};if ( -d $dir ){Warning ("Multiple Package directories located. Only the first will be used","Ignoring: $subdir" )if ( $pkg_dir );$pkg_dir = $dir;$pkg_root = $root;}}unless ($pkg_dir){ReportError ("Package directory not found in package: $package_name");return undef;}## Determine Manifest File name#foreach my $file ( glob ($pkg_dir . '/Manifest*' ) ){next unless ( -f $file );Warning ("Multiple Manifest Files find. Only the first will be used","Using: $manifest","Ignoring: $file" ) if ( $manifest );$manifest = $file;}unless ($manifest){ReportError ("ImportManifest. No Manifest found: $package_name");return undef;}###open (MF, '<', $manifest ) || Error ("Cannot open the Manifest file: $manifest", $!);while ( <MF> ){## Clean trailing whitespace ( line-feed and new lines )# Comment out [Version] data#s~\s+$~~;s~(\s*\[Version])~#$1~;## Part lines and determine files#next unless ( $_ );if (( m~\s*#~ ) || ( m~\s*\[~ )) {push @item_list, { 'comment' => $_ };next;}my( $aname, $atier, $afile, @additionnal_info) = split(/\s*\,\s*/, $_);# print "---------- $_\n";# print "T: $atier, N:$aname, F:$afile\n";my $file = { 'file_name' => $afile, 'file_info' => \@additionnal_info};push @item_list, $file;## Rewrite the name and tier#if ($rewrite){$_ = join(',', $name, $tier, $afile);$first_tier = $tier;$first_name = $name;}else{## Capture first tier and name#$first_tier = $atier unless ( defined $first_tier );$first_name = $aname unless ( defined $first_name );}}continue{push @file_contents, $_;}close MF;## Create a hash of data that describes the manifest that has# just been read in.#$package_dirs{$pkg_root}{used} = 1;$manifest =~ s~.*/~~;return { 'contents' => \@file_contents,'items' => \@item_list,'file_base' => $pkg_dir,'manifest' => $manifest,'pkg_dir' => $pkg_root,'tier' => $first_tier,'name' => $first_name,'rewrite' => $rewrite,};}#-------------------------------------------------------------------------------# Function : ManifestFiles_Generate## Description : Internal Function# Process all the collected data and create directives# for the creation of the manifest## This function will be called, just before the Makefile# is created. The function will:# 1) Create the Manifest File# 2) Package the Manifest File# 3) Package the manifest file contents## using (mostly) normal makefile.pl directives.## Inputs : None## Returns : Nothing#sub ManifestFiles_Generate{Debug ("ManifestFiles_Generate");Message ("Generating Manifest File");## Need at least one Manifest Entry#return unless ( @Manifests );#DebugDumpData ( "Manifests", \@Manifests );## Determine the target packaging directory# Default is .../mug#my $pkgdir = 'mug';if ( exists $Manifests[0]->{pkgsubdir} && defined $Manifests[0]->{pkgsubdir} ){my $subdir = $Manifests[0]->{pkgsubdir};$pkgdir .= '/' . $subdir;$pkgdir =~ s~^mug/mug~mug~;}## Create the Manifest File as we process the lists# Place this in the 'lib' directory:# - So that it will be deleted on clobber# - So that it can be placed in a target-specific subdir# - So that we can have one per makefile.pl#Error ("ManifestFiles: Needs local directory specified in build.pl") unless ( $::ScmLocal );my $manifest_dir = "$::ScmPlatform.LIB";System( "$::GBE_BIN/mkdir -p $manifest_dir" );my $manifest_file = $manifest_dir . '/Manifest';$manifest_file .= '_' . $::ScmBuildVersion if ( $Manifest_has_version );ToolsetGenerate( $manifest_file );Verbose ("ManifestFiles_Generate: File: $manifest_file");PackageFile ('*', $manifest_file, '--Subdir=' . $pkgdir, '--Strip' );open (MF, '>', $manifest_file ) || Error ("Cannot create the Manifest file: $manifest_file");binmode (MF);if ($Manifests[0]->{is_sub_manifest} == 1) {print_mf ("# Package $::ScmBuildPackage $::ScmBuildVersion built: $::CurrentTime");} else {print_mf ("# PackageName: $::ScmBuildPackage");print_mf ("# PackageVersion: $::ScmBuildVersion");print_mf ("# BuildDate: $::CurrentTime");print_mf ("#");print_mf ("[Version],$::ScmBuildVersion");print_mf ("#");}## Process each tier in the order presented in the source file#my $last_was_comment = 0;foreach my $entry ( @Manifests ){#DebugDumpData ( "Manifest Entry", $entry );my $tier = $entry->{tier};my $name = $entry->{name};my $include_md5 = $entry->{md5};if ( $entry->{dmf} ){DmfGenerate($entry);}## Insert all the files that have been specified# The user specified order is preserved## Entries may be either a file or a comment# Comments: Merge multiple comments and create blocks##my @files = @{ $entry->{files} };foreach my $fentry ( @files ){if ( my $cmt = $fentry->{'cmt'} ){print_mf ('') unless ( $last_was_comment ) ;print_mf ( map (('# ' . $_) , split ("\n", $cmt) ));$last_was_comment = 1;next;}print_mf ('#') if ( $last_was_comment );if ( my $file = $fentry->{'file'} ){my $base_file = StripDir( $file );my @items = ($name, $tier, $base_file);if ($include_md5) {my $md5 = digest_file_hex($file, 'MD5');push @items, "MD5=$md5" ;}if (exists $entry->{fileVersions} && exists $entry->{fileVersions}{$file} ) {push @items, "VERSION=" . $entry->{fileVersions}{$file};}print_mf (join (',', @items));PackageFile ('*', $file, '--Subdir=' . $pkgdir, '--Strip' );$last_was_comment = 0;}if ( my $file = $fentry->{'filenocopy'} ){print_mf ("$name,$tier,$file");$last_was_comment = 0;}if ( my $emf = $fentry->{'manifest'} ){$last_was_comment = 0;## Insert the entire manifest# Items are:# contents# items:# file_name + arrays of file_info# or comment line to copy# file_base# manifest##DebugDumpData ( "Embedded Manifest Entry", $emf );if ($emf->{'rewrite'}) {foreach my $item ( @{$emf->{'items'}}) {if (defined($item->{'file_name'})){my @items = ($name, $tier, $item->{'file_name'});my $md5_added = 0;foreach my $info (@{$item->{'file_info'}}) {push @items, $info;$md5_added = 1 if ($info =~ m~^MD5=~i);}if ($include_md5 && $md5_added == 0) { # add md5 if requested and not already added from submanifestmy $md5 = digest_file_hex($emf->{'file_base'} . '/' . $item->{'file_name'}, 'MD5');push @items, "MD5=$md5";}print_mf (join (',', @items));PackageFile ('*', $emf->{'file_base'}. '/' . $item->{'file_name'}, '--Subdir=' . $pkgdir, '--Strip' );}elsif (defined($item->{'comment'})) {print_mf($item->{'comment'});}}print_mf('#');}else {print_mf ($_) foreach ( @{$emf->{'contents'}} );foreach my $item ( @{$emf->{'items'}}) {PackageFile ('*', $emf->{'file_base'}. '/' . $item->{'file_name'}, '--Subdir=' . $pkgdir, '--Strip' )if (defined($item->{'file_name'}));}print_mf('#');}}}## Expand out the entire MUG directory# All .mug files in the MUG directory will be added to the manifest# The assumption is that the MUG directory has been created by# something that knows what its doing#if ( my $mugdir = $entry->{mugdir} ){foreach my $file ( glob ($mugdir . '/*.mug' ) ){next unless ( -f $file );my $base_file = StripDir($file);my @items = ($name, $tier, $base_file);if ($include_md5) {my $md5 = digest_file_hex($file, 'MD5');push @items, "MD5=$md5" ;}print_mf (join (',', @items));PackageFile ('*', $file, '--Subdir=mug', '--Strip' );}}}## Complete the creation of the Manifest File#print_mf ("# end of $::ScmBuildPackage");close MF;ErrorDoExit();## Sanity test of packages that did not provide a debian file# Just a hint that something may have been missed#my @not_used_packages;foreach my $package_dir ( getPackagePaths ('--All') ){next if ( $package_dir =~ m~/manifest-tool/~ );unless ( exists $package_dirs{$package_dir}{used} ){push @not_used_packages, $package_dir;}}if ( @not_used_packages ){Warning ("Packages that did not contribute packages to the manifest:",@not_used_packages );}return;#-------------------------------------------------------------------------------# Function : print_mf## Description : Internal Function# Print one line to the Manifest File# Checks the length of the line being created## Inputs : $line## Returns :#sub print_mf{foreach ( @_ ){my $ll = length ($_);ReportError ( "Manifest line too long: $ll. Max is $ManifestLineWidth.","Line: $_" ) if ( $ManifestLineWidth && $ll > $ManifestLineWidth);print MF $_ . "\n";}}}# Bring in the DMF build requirements.my $directory;BEGIN {use File::Spec::Functions qw(rel2abs);use File::Basename qw(dirname);my $path = rel2abs( __FILE__ );$directory = dirname( $path );}use lib $directory;use Archive::Zip qw( :ERROR_CODES :CONSTANTS );use JSON;#-------------------------------------------------------------------------------# Function : DmfGenerate## Description : Import an existing manifest## Inputs : entry - The manifest that is being processed.## Returns : Nothing#sub DmfGenerate{my ($entry) = @_;# Get the generation time.my $gen_time = time();my $work_dir = "$::ScmPlatform.BIN/";System( "$::GBE_BIN/mkdir -p $work_dir" );my $name = $entry->{name};my $version = $entry->{dmf_version};# Configure base manifest information.my %manifest;$manifest{'mugsetId'} = $name . '_' . $version;$manifest{'name'} = $name;$manifest{'version'} = $version;$manifest{'packageName'} = $::ScmBuildPackage;$manifest{'packageVersion'} = $::ScmBuildVersionFull;$manifest{'datetime'} = localtime($gen_time);$gen_time *= 1000; # Make to milliseconds$manifest{'timestamp'} = $gen_time;$manifest{'tier'} = $entry->{tier};# Process each file.my @files = @{ $entry->{files} };my $zip = Archive::Zip->new();my $i = 0;foreach my $fentry ( @files ){if ( my $file = $fentry->{'file'} ){my $order = $i + 1;my $base_file = StripDir( $file );my $publish_file = $name . '_' . $version . '_' . $order . '.aup';my $aup_file = $work_dir . $publish_file;GenerateCesFile($file, $aup_file, 0x3, $gen_time, $publish_file);my $file_member = $zip->addFile( $aup_file, $publish_file );$manifest{'tasks'}[$i]{'order'} = 1 * $order;$manifest{'tasks'}[$i]{'filename'} = $base_file;$manifest{'tasks'}[$i]{'download'} = $publish_file;$manifest{'tasks'}[$i]{'sha256'} = digest_file_base64($file, 'SHA-256');$manifest{'tasks'}[$i]{'size'} = -s $file;if ($base_file =~ /\.sh$/){$manifest{'tasks'}[$i]{'action'} = 'exec-shell';}elsif ($base_file =~ /\.deb$/){$manifest{'tasks'}[$i]{'action'} = 'dpkg-install';my ($pkg_name, $pkg_version, $pkg_arch) = ($base_file =~ /([^_]*)_([^_]*)_(.*)/);$manifest{'tasks'}[$i]{'arch'} = $pkg_arch;$manifest{'tasks'}[$i]{'name'} = $pkg_name;$manifest{'tasks'}[$i]{'version'} = $pkg_version;}else{ReportError ("Manifest entry $base_file does not have a supported DMF install action");}$i = $i + 1;}}# Encode and commit the JSON.my $json_encoder = JSON->new->allow_nonref;my $json = $json_encoder->pretty->encode( \%manifest );my $manifest_filename = $name . '_' . $version;my $aum_filename = $manifest_filename . '_0.aum';my $manifest_file = $work_dir . $manifest_filename . '.json';my $aum_file = $work_dir . $aum_filename;# Save our manifest.open (J, '>', $manifest_file ) || Error ("Cannot create the DMF Manifest file");binmode (J);print J $json;close J;GenerateCesFile($manifest_file, $aum_file, 0x2, $gen_time, $aum_filename);$zip->addFile($aum_file, $aum_filename);my $zip_filename = $work_dir . $name . '_' . $version . '.zip';if ( $zip->writeToFileNamed($zip_filename) != AZ_OK ){ReportError("DMF ZIP file creation failed");}PackageFile('*', $zip_filename, '--Strip');PackageFile('*', $manifest_file, '--Strip');}#-------------------------------------------------------------------------------# Function : DmfGenerate## Description : Import an existing manifest## Inputs : src_file - The input file.# dst_file - The output CES file.# content_type - The content type to report.# gen_time - The generation time for the file.# filename - The filename to embed in the CES file.### Returns : Nothing#sub GenerateCesFile{my ($src_file, $dst_file, $content_type, $gen_time, $filename) = @_;open (INF, '<', $src_file ) || Error ("Cannot open file $src_file for reading");binmode (INF);open (OUTF, '>', $dst_file ) || Error ("Cannot open file $dst_file for writing");binmode (OUTF);my $signing_key_name = "";my $signature_size = 0;my $format_version = 0xCE500000;my $compression_method = 0;my $encryption_method = 0;my $kek_name = "";my $encryption_key_size = 0;my $filename_size = length($filename);print OUTF pack("Z32", $signing_key_name);print OUTF pack("n", $signature_size);print OUTF pack("N", $format_version);print OUTF pack("N", $content_type);print OUTF pack("Q>", $gen_time);print OUTF pack("N", $compression_method);print OUTF pack("N", $encryption_method);print OUTF pack("Z32", $kek_name);print OUTF pack("n", $encryption_key_size);print OUTF pack("n", $filename_size);# Encryption key HEREprint OUTF pack("A$filename_size", $filename);my $buf;while (read(INF,$buf,65536)){print OUTF $buf;}print OUTF $buf;close INF;# Signature HERE# Finish with file.close OUTF;}1;