#! perl ######################################################################## # COPYRIGHT - VIX IP PTY LTD ("VIX"). ALL RIGHTS RESERVED. # # Module name : jats.sh # Module type : Makefile system # Compiler(s) : n/a # Environment(s): jats # # Description : Package Entry # # New Create a new package entry instance. # # RuleInc Check whether the specific 'include' path should # be included within the PINCDIRS list. # # RuleLib Check whether the specific 'lib' path should # be included within the PLIBDIRS list. # # Cleanup Performs any record cleanup required prior to the # entry being published. # # Usage: # # Version Who Date Description # #......................................................................# require 5.006_001; use strict; use warnings; use DescPkg; use JatsError; our $BUILDNAME_PACKAGE; our $BUILDNAME_VERSION; our $BUILDNAME_PROJECT; our $BUILDINTERFACE; our @BUILDTOOLS; package PackageEntry; our %DescPkgCache = (); # Hash of known packages our %PackageDefined = (); # Quick defined package test our @PackageList = (); # Ordered array of packages #------------------------------------------------------------------------------- # Function : EmptyEntry # # Description : Create an empty class element # Populated with the basic items # # Inputs : None # # Returns : New, empty entry # sub EmptyEntry { my ($self) = { PINCDIRS => [], PLIBDIRS => [], LIBEXAMINED => {}, INCEXAMINED => {}, TOOLDIRS => [], THXDIRS => [], }; return bless $self, __PACKAGE__; } #------------------------------------------------------------------------------- # Function : New # # Description : Create a new instance of the PackageEntry class # # Inputs : $base - Path to the package # $name - Package Name # $version - Version # $type - 'link' or 'build' # $local - Is from a local archive # No version check. # Display path to package # $pkgSig - Package Signature # # Returns : # sub New { my ($base, $name, $version, $type, $local, $pkgSig) = @_; my $self = EmptyEntry(); # Load package description ... # Note: The results are cached within DescPkgCache #.. if ( ! exists( $DescPkgCache{$base} ) ) { my ($rec); my ($desc) = ""; if ( -f "$base/descpkg" ) { $rec = ::ReadDescpkg( "$base/descpkg", 1 ); } else { # doesn't exist ::Error( "Package description does not exist", "Package Location: $base" ) } ::Error("Cannot determine package description", "Package Location: $base" ) unless ( $rec ); ::Warning( "Package names do not match: $rec->{NAME}, $name" ) if ( $rec->{NAME} ne $name ); if ( $local ) { # display results my $logPrefix = " ->"; ::Log( "$logPrefix $base" ); } elsif ( $rec->{VERSION_FULL} ne $version ) { ::Warning( "Package versions do not match: $name : $rec->{VERSION_FULL}, $version" ); } # # Extend the package information to contain sufficient data # for general use. Information will be retained to allow the # user to extact specific package information # $version =~ m~(\d+\.\d+\.\d+)\.(\w+)~ ; my $vnum = $1 || $version; my $proj = $2 || ''; $rec->{UNAME} = $name; $rec->{UVERSION} = $version; $rec->{UVNUM} = $vnum; $rec->{UPROJ} = $proj; $rec->{type} = $type; $rec->{PKGSIG} = $pkgSig; $PackageDefined{$name}{$proj}{$vnum} = $base; push @PackageList, $base; $DescPkgCache{$base} = $rec; # cache result } # Build the package entry record #.. my ($descpkg) = $DescPkgCache{$base}; # descpkg details $self->{'base'} = $base; $self->{'name'} = $name; $self->{'version'} = $version; $self->{'dname'} = $descpkg->{NAME}; $self->{'dversion'} = $descpkg->{VERSION}; $self->{'dproj'} = $descpkg->{PROJ} || $descpkg->{UPROJ} || ''; $self->{'packages'} = $descpkg->{PACKAGES}; $self->{'type'} = $type; $self->{'sandbox'} = $local; $self->{'cfgdir'} = "/gbe" if ( -d $base."/gbe" ); # $self->{pkgsig} = $descpkg->{PKGSIG}; return $self; } #------------------------------------------------------------------------------- # Function : Interface # # Description : Create a specialised 'interface' entry # # Inputs : $base - Path to the Interface directory # # Returns : Ref to this class # sub Interface { my ($base) = @_; my $self = EmptyEntry(); $self->{'base'} = $base; $self->{'name'} = 'INTERFACE'; $self->{'version'} = '0.0.0'; $self->{'dname'} = $self->{'name'}; $self->{'dversion'} = $self->{'version'}; $self->{'dproj'} = ''; $self->{'packages'} = ''; $self->{'type'} = 'interface'; $self->{'cfgdir'} = '/gbe'; return $self; } sub RuleInc { my( $self ) = shift; my( $path ) = @_; my( $examined ) = $self->{INCEXAMINED}; my( $list ) = $self->{PINCDIRS}; return if ( $$examined{$path} ); $$examined{$path} = 1; push @$list, $path if ( -d $self->{'base'}.$path ); } # # Examine Path to ensure that it is a directory and that it contains files # Simplify Lib Path searching by removing useless paths. # # If there are ANY files then the directory is useful # If there are no files ( only subdirectories ) then the directory is not useful # sub isUsefulDir { my ($path) = @_; if ( -d $path ) { opendir (USEFUL, $path) or ::Error ("Cannot open $path"); my @dirlist = readdir USEFUL; closedir USEFUL; foreach ( @dirlist ) { return 1 if ( -f "$path/$_" ); } } return 0; } sub RuleLib { my( $self ) = shift; my( $path ) = @_; my( $examined ) = $self->{LIBEXAMINED}; my( $list ) = $self->{PLIBDIRS}; return if ( $$examined{$path} ); $$examined{$path} = 1; push @$list, $path."D" if ( isUsefulDir($self->{'base'}.$path."D") ); push @$list, $path."P" if ( isUsefulDir($self->{'base'}.$path."P") ); push @$list, $path if ( isUsefulDir($self->{'base'}.$path) ); } #------------------------------------------------------------------------------- # Function : ExamineToolPath # # Description : Given the root of a package, locate any # toolset extension paths within the tree. These will be # saved and later used when user tools and scripts are # invoked. # # Examine: # - tools/bin/GBE_MACHTYPE/bin - Hardware specfic tools # - tools/bin/GBE_MACHTYPE - Hardware specfic tools # - tools/bin - Hardware independent tools - scripts # - tools/scripts/GBE_MACHINE - Hardware specific scripts # - tools/scripts - Hardware independent scripts (too) # # Inputs : self # # Returns : Nothing # sub ExamineToolPath { my( $self ) = shift; # # Determine base dir # LinkPkgArchive : From the package # BuildPkgArchive : From the interface directory # my $pbase_dir = $self->{'base'}; # Package relative base directory my $base_dir = $self->{'base'}; # Base directory to use $base_dir = "$::CwdFull/$BUILDINTERFACE" if ( $self->{'type'} eq 'build' ); my @searchList; my $path = "/tools/bin"; foreach my $suffix ( "/$::GBE_MACHTYPE", "/$::GBE_MACHTYPE/bin", "" ) { push @searchList, $path . $suffix; } $path = "/tools/scripts"; foreach my $suffix ( "/$::GBE_MACHTYPE", "" ) { push @searchList, $path . $suffix; } for my $path (@searchList ) { # Test against the Package Directory # So that we correctly identify packages witg tools # Store the Use base directory # So that BuildPkgArchive will be in the interface my $dir = $base_dir . $path; if ( isUsefulDir( $pbase_dir . $path ) ) { ::UniquePush( \@{$self->{'TOOLDIRS'}}, $dir ); ::UniquePush( \@BUILDTOOLS, $dir ); } } } #------------------------------------------------------------------------------- # Function : ExamineThxPath # # Description : Given the root of a package, locate some well known # packaging directories for later use. # # Examine: # /thx/$platform # /thx # # Inputs : self # platform - Current build platform # # Returns : nothing # sub ExamineThxPath { my( $self, $platform ) = @_; my $dir = $self->{'base'} . '/thx'; if ( -d $dir ) { push @{$self->{'THXDIRS'}}, "/thx/$platform" if isUsefulDir( "$dir/$platform" ); push @{$self->{'THXDIRS'}}, "/thx" if isUsefulDir( $dir ); } } sub Cleanup { my ($self) = shift; delete $self->{LIBEXAMINED}; delete $self->{INCEXAMINED}; } #------------------------------------------------------------------------------- # Function : GetBaseDir # # Description : Return the base directory of a given package # Simple getter function # # Inputs : self # path - Optional path within package # # Returns : The base directory of the package # sub GetBaseDir { my ($self, $path) = @_; my $dir = $self->{'base'}; $dir .= '/' . $path if ( $path ); return $dir; } #------------------------------------------------------------------------------- # Function : SanityTest # # Description : Examine all the packages used in the current build.pl # and all the packages used to build them. Then generate # warning if there are mismatches. # # All the data has been collected and stored within # $DescPkgCache. This routine processes the data and # constructs a data structure to locate packages with # multiple versions. # # The project name is considered to be a part of the package # name. Thus aaaa_11.22.33.mass is different to aaaa_11.22.33.syd # # Inputs : # # Returns : # my %package_list; sub AddEntry { my( $root, $rver, $rproj, $name, $version ) = @_; my $ver; my $proj; if ($version eq "!current") { $ver = "current"; $proj = ""; } else { $version =~ m~(.*)\.(.*?)$~; $ver = $1 || 'BadVer'; $proj = $2 || 'BadProj'; } ::UniquePush( \@{$package_list{"$name$;$proj"}{$ver}}, "${root}_${rver}.${rproj}"); } sub SanityTest { foreach my $package ( keys %DescPkgCache ) { my $pptr = $DescPkgCache{$package}; my $lver = $pptr->{'VERSION'}; $lver .= '.' . $pptr->{'PROJ'} if ( $pptr->{'PROJ'} ); AddEntry( $BUILDNAME_PACKAGE, $BUILDNAME_VERSION, $BUILDNAME_PROJECT, $pptr->{'NAME'}, $lver ); foreach my $subpkg ( @{$pptr->{'PACKAGES'}} ) { my $name = $subpkg->{name}; my $ver = $subpkg->{version}; AddEntry( $pptr->{'NAME'}, $pptr->{'VERSION'}, $pptr->{'PROJ'}, $name, $ver ); } } #::DebugDumpData("XXX", \%package_list ); # # Detect and print warnings about multiple entries # my $first_found = 0; foreach my $pentry ( sort keys %package_list) { my @versions = keys %{$package_list{$pentry}}; if ( $#versions > 0 ) { ::Warning("Package mismatchs detected.") unless ( $first_found++ ); my ($pname, $pproj) = split $;, $pentry ; foreach my $version ( @versions ) { ::Warning("Package ${pname}_${version}.${pproj} used by:", @{$package_list{$pentry}{$version}}); } } } } #------------------------------------------------------------------------------- # Function : Exists # # Description : A class function to determine if a given package is known # to the PackageEntry manager. Used to detect multiple package # definitions. # # The test ignores package versions # It is not possible to include different versions of the # same package. The test ignores the project part of the # version. This allows for # sysbasetypes aa.bb.cc.mas and # sysbasetypes xx.yy.zz.syd # # Inputs : $name - User package name # $version - User version ( with project ) # # Returns : True: Package exists # sub Exists { my ($name, $version) = @_; $version =~ m~(\d+\.\d+\.\d+)\.(\w+)~ ; my $vnum = $1 || $version; my $proj = $2 || ''; return exists( $PackageDefined{$name}{$proj} ); } #------------------------------------------------------------------------------- # Function : GetPackageList # # Description : A class function to return a list of packages # The list cannot be used directly. It is really a set of # keys to an internal data structure. # # The result can be used to iterate over the list of packages # using other functions. # # Inputs : None # # Returns : An array of package tags # The array is ordered by package definition order # sub GetPackageList { return @PackageList; } #------------------------------------------------------------------------------- # Function : GetPackageData # # Description : A class function to return specific data for a given package # # Inputs : $tag - An iteration tag provided by GetPackageList() # # Returns : A list of # Package name # Package version # Package type : build or link # sub GetPackageData { my ($tag) = @_; my $rec = $DescPkgCache{$tag}; return $rec->{UNAME}, $rec->{UVERSION}, $rec->{type}; } #------------------------------------------------------------------------------- # Function : GetNameVersion # # Description : Return a package name and version for display purposes # # Inputs : $tag - An iteration tag provided by GetPackageList() # # Returns : A list of # Package name # Package version # Package type : build or link # sub GetNameVersion { my ($tag) = @_; my $rec = $DescPkgCache{$tag}; return join( ' ', $rec->{NAME}, $rec->{VERSION_FULL} ); } #------------------------------------------------------------------------------- # Function : GetPackageVersionList # # Description : A class function to return a list of package names as used # to generate version strings # # # Inputs : None # # Returns : An array of version list entries # Each element of the form: "name (version)" # sub GetPackageVersionList { my @list; foreach my $tag ( @PackageList ) { my $rec = $DescPkgCache{$tag}; push @list, "$rec->{UNAME} ($rec->{UVERSION})"; } return @list; } #------------------------------------------------------------------------------- # Function : GetPackageSignature # # Description : A class function to return a packages signature # # # Inputs : None # # Returns : An array of version list entries # Each element of the form: "name (version)" # sub GetPackageSignature { my ($tag) = @_; my $rec = $DescPkgCache{$tag}; return $rec->{PKGSIG}; } #------------------------------------------------------------------------------- # Function : Dump # # Description : Internal diagnostic tool # Dumps internal data structures # # Inputs : None # # Returns : Nothing # sub Dump { ::DebugDumpData("PackageEntry",\%DescPkgCache); } ### End of package: PackageEntry 1;