######################################################################## # Copyright (C) 2007 ERG Limited, All rights reserved # # Module name : jats.sh # Module type : Makefile system # Compiler(s) : n/a # Environment(s): jats # # 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 (, Options+); # See the function header for details # #......................................................................# require 5.6.1; use strict; use warnings; # # Globals # my @Manifests; # Manifest entries my $Manifest_has_version = 1; # Create Manifest_xxxx by default my %package_dirs; # Package dirs discovered and used my $pkg_subdir; # Alternate packaging #------------------------------------------------------------------------------- # 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] # --MugPackage=Package[,--Subdir=subdir[,subdir]+] # --SrcFile=xxx # --Comment=xxx - Add comment to Manifst # --NoManifestVersion - Create unversioned Manifest File # --PkgSubdir=xxx - Specifies packaging subdir # # Returns : Nothing # sub ManifestFiles { my( $platforms, @elements ) = @_; Debug2( "ManifestFiles($platforms, @elements)" ); return if ( ! ActivePlatform($platforms) ); my $name; my $tier; my @files; my $mug_dir; my $default_arch = $::ScmPlatform; my $default_prod = ''; # # 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~^--SrcFile=(.+)~ ) { push @files, {'file' => LocatePreReq($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:--MugPackage option is only allowed once"); next; } $pkg_subdir = $1; } 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 $tier; ReportError ("ManifestFiles: Cannot mix --Debian/--SrcFile with --MugPackage in one directive") if ( $mug_dir && @files ); ReportError ("ManifestFiles: Must specify files to add to Manifest") unless ( $mug_dir || @files ); ErrorDoExit(); # # 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{mugdir} = $mug_dir; $data{pkgsubdir} = $pkg_subdir; 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; # # Extract sub-options # --Prod[uction] # --Debug # --Arch[itecture]=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'; } } # # 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"; Verbose("ManifestFiles: Search in $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; } } } } ReportError ("Required Debain 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 : 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 : 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} ) { 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"); 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 ) { print_mf ("#"); #DebugDumpData ( "Manifest Entry", $entry ); my $tier = $entry->{tier}; my $name = $entry->{name}; # # 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 ); print_mf ("$name,$tier,$base_file"); PackageFile ('*', $file, '--Subdir=' . $pkgdir, '--Strip' ); $last_was_comment = 0; } } # # 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); print_mf ("$name,$tier,$base_file"); PackageFile ('*', $file, '--Subdir=mug', '--Strip' ); } } } # # Complete the creation of the Manifest File # print_mf ("#"); print_mf ("# End of File"); 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 ( @_ ) { ReportError ( "Manifest line too long", "Line: $_" ) if ( length ($_) > 79 ); print MF $_ . "\n"; } } } 1;