Subversion Repositories DevTools

Rev

Blame | Last modification | View Log | RSS feed

########################################################################
# Copyright (c) VIX TECHNOLOGY (AUST) LTD
#
# Module name   : JatsLocatePkgFile.pm
# Module type   : Makefile system
# Compiler(s)   : Perl
# Environment(s): jats
#
# Description   : Package to simplify the process of locating one or more
#                 files with the JATS build environment.
#
#                 Specifically designed to assist in the creation of:
#                       Day0 file systems
#                       Debian Packages
#                       Deployable packages
#
#                 Intended to locate files in dependent packages
#                 Supports LinkPkgArchive and BuildPkgArchive
#
#                 Knows about the construction of programs and shared
#                 libraries as well as other special file types.
#
#                 Uses a set of options to identify the file
#                 The file specifier is of the form
#                       Name[,--Option]+
#
#                 Available Options are:
#                       --prog          - Name is a program
#                                         Search where programs are stored
#                                         Append the target specific suffix
#                       --bin           - Similar to --prog, but does not modify
#                                         the provided name.
#                       --deb           - Name is the base of a Debian Package
#                                         Searchs in BIN directories
#                       --lib           - Name is the base of a Shared Library
#                                         Searchs in LIB directories
#                       --dir=SubDir    - Search for Name in a subdir of the
#                                         dependent packages
#                       --pkg           - Search for Name in a pkg subdir
#                                         Limited by the current target
#                       --etc           - Same as --dir=etc
#                       --jar           - Same as --dir=jar
#                       --scripts       - Same as --dir=scripts
#
#                       --AllowMultiple - Allow multiple files
#
# Usage:
#
#   $Locator = JatsLocatePkgFile::New( Platform, 'P' );
#   $result = $Locator->LocateFile ('busybox,--prog');
#
#
#......................................................................#

require 5.008_002;
use strict;
use warnings;

package JatsLocatePkgFile;

use JatsError;
use JatsMakeConfig;

# automatically export what we need into namespace of caller.
use Exporter();
our (@ISA, @EXPORT);
@ISA         = qw(Exporter);
@EXPORT      = qw(
                    FileSet
                );

#
#   Hash of known file location specifications
#   Only allowed to have one in any one definition
#
my %LocSpec = (
    'prog'          => { code => \&searchProg },
    'bin'           => { code => \&searchBin },
    'deb'           => { code => \&searchDeb },
    'dir'           => { code => \&searchDir },
    'pkg'           => { code => \&searchPkg },
    'lib'           => { code => \&searchLib },
    'etc'           => { code => \&searchSimple, dir => 'etc' },
    'jar'           => { code => \&searchSimple, dir => 'jar'},
    'scripts'       => { code => \&searchSimple, dir => 'scripts'},
#    'thx'           => 1,
#    'jar'           => 1,
#    'local'         => 1,
#    'interface'     => 1,
);

#-------------------------------------------------------------------------------
# Function        : FileSet
#
# Description     : Create a new instance of a File Locator
#                   Used to provide the basic configuration of the target
#                   system
#
# Inputs          : None
#                   Useful information is prsent in the environment
#
#
# Returns         : Class Ref
#
sub FileSet
{
    Debug ("New JatsLocatePkgFile");
    my $self;

    #
    #   Load all the MakeFile generate information and  data structures
    #
    my $mi = JatsMakeConfigLoader::Load();

    #
    #   Document Class Variables
    #
    $self->{'platform'} = $mi->{'PLATFORM'};
    $self->{'type'}     = $mi->{'TYPE'};
    $self->{'cache'}    = undef;

    #
    #   Create a class
    #   Bless my self
    #
    bless ($self, __PACKAGE__);

    #
    #   Locate required entries
    #
    my @result;
    for my $entry ( @{$mi->GetDataItem('%ScmBuildPkgRules')} )
    {
        #
        #   If a BuildPkgArchive, then skip as its data will be embedded
        #   in the pseudo INTERFACE package
        #
        next if ( ($entry->{'TYPE'} eq 'build' ) );
        push @result, $entry->{'ROOT'};
    }
    $self->{'BuildPaths'} = \@result;
    $self->{'BuildParts'} = $mi->GetDataItem('%BUILDPLATFORM_PARTS');

    $self->{'a'}    =  $mi->GetDataItem('$a');
    $self->{'exe'}  =  $mi->GetDataItem('$exe');
    $self->{'so'}   =  $mi->GetDataItem('$so');

#    DebugDumpData(__PACKAGE__, $self );
    return $self;
}

#-------------------------------------------------------------------------------
# Function        : LocateFile
#
# Description     : Locate a file as specified by a user description
#
# Inputs          : $self                   - Instance Data
#                   $fspec                  - A file specification
#
# Returns         : A list of files that match
#                   May not return on error
#
sub LocateFile
{
    my $self = shift;
    my ($fspec) = @_;
    my $opts;
    my $mode;

    #
    #   Split the file spec into bits
    #   Extract options and the base file name
    #       Create a hash of options
    #       Convert options to lowercase
    #       Extract any assignments
    #       Treat --Flag as --Flag=1
    #
    $self->{'uspec'} = $fspec;
    while ( $fspec =~ m~^(.*),--(.*?)(=(.*?))?,*$~ )
    {
        $fspec = $1;

        my $opt = lc($2);
        $opts->{$opt} = defined($3) ? $4 : 1;

        $mode = $LocSpec{$opt}
            if ( exists $LocSpec{$opt} )
    }

    #
    #   Save the remainder as the filename
    #   It may not exist
    #
    $opts->{'file'} = $fspec;
    $opts->{'Mode'} = $mode;

#    DebugDumpData("File", $opts);

    #
    #   Dispatch to a suitable processing routine
    #
    if ( $mode )
    {
        if ( $mode->{'code'} )
        {

            my @result = ( $mode->{'code'}( $self, $opts ) );
print "-----Files found: $#result\n";            
            if ( ! $opts->{'allowmultiple'} )
            {
                Error ("Mutliple Files found: $self->{'uspec'}" )
                    if ( $#result > 1 );
            }
            return wantarray ? @result : $result[0];
        }
        DebugDumpData("File", $opts);
        Error ("Unknown search method: @_");
    }
    else
    {
        #
        #   No Mode specified
        #   Must be a local file
        #
        my $ufile = $opts->{'file'};
        return $ufile
            if ( -f $ufile );
        return undef;
    }
}

#-------------------------------------------------------------------------------
# Function        : searchLib
#
# Description     : The user is looking for a shared library file
#                   It will have a specific extension
#                   It will be in one of the 'lib' directories known to JATS
#
#                   Current Limitations:
#                       Does not perform Unix Lib Prefix
#                       Does not handle Name.version.so
#                       Does not handle 'so' Name and 'real' name pairs
#
#
# Inputs          : $self                   - Instance Data
#                   $opts                   - Options Hash
#
# Returns         : 
#
sub searchLib
{
    my ($self, $opts) = @_;

    my $ufile = $opts->{'file'};
    my $ext =  $self->{so} ? '.' . $self->{a} : '';
    my @results;
    foreach my $dir ( @{ LibDirs($self) } )
    {
        foreach  ( glob ( "$dir/*") )
        {
            foreach my $type ( $self->{'type'}, '' )
            {
                push @results, $_  if ( $_ =~ "/$ufile$type$ext\$" );
            }
        }

#        foreach my $type ( $self->{'type'}, '' )
#        {
#            my $file = "$dir/$ufile" . $type . $ext;
#            push @results, $file
#                if ( -f $file );
#            }
    }
    return @results;
}


#-------------------------------------------------------------------------------
# Function        : searchProg
#
# Description     : The user is looking for a program file
#                   It will have a specific extension
#                   It will be in one of the 'Bin' directories known to JATS
#
# Inputs          : $self                   - Instance Data
#                   $opts                   - Options Hash
#
# Returns         : 
#
sub searchProg
{
    my ($self, $opts) = @_;

    my $ufile = $opts->{'file'} . $self->{exe};
    my @results;
    foreach my $dir ( @{ BinDirs($self) } )
    {
        foreach  ( glob ( "$dir/*") )
        {
            push @results, $_  if ( $_ =~ "/$ufile\$" );
        }
    }
    return @results;

#    my $ufile = $opts->{'file'} . $self->{exe};
#    foreach my $dir ( @{ BinDirs($self) } )
#    {
#        my $file = "$dir/$ufile";
#        return $file
#            if ( -f $file );
#    }
#    return undef;
}

#-------------------------------------------------------------------------------
# Function        : searchBin
#
# Description     : The user is looking for a program file
#                   It will be in one of the 'Bin' directories known to JATS
#
# Inputs          : $self                   - Instance Data
#                   $opts                   - Options Hash
#
# Returns         : 
#
sub searchBin
{
    my ($self, $opts) = @_;

    my $ufile = $opts->{'file'};
    my @results;
    foreach my $dir ( @{ BinDirs($self) } )
    {
        foreach  ( glob ( "$dir/*") )
        {
            push @results, $_  if ( $_ =~ "/$ufile\$" );
        }
    }
    return @results;
}


#-------------------------------------------------------------------------------
# Function        : searchDeb
#
# Description     : The user is looking for a Debian Package
#                   It will have a specific extension
#                   It will be in one of the 'Bin' directories known to JATS
#
# Inputs          : $self                   - Instance Data
#                   $opts                   - Options Hash
#
# Returns         : 
#
sub searchDeb
{
    my ($self, $opts) = @_;

    foreach my $dir ( @{ BinDirs($self) } )
    {
        if ( my @files = glob ( "$dir/$opts->{file}_*.deb" ) )
        {
            return $files[0];
        }
    }
    return undef;
}

#-------------------------------------------------------------------------------
# Function        : searchDir
#
# Description     : The user is looking for a file in a package subdir
#                   It will be in one of the package directories
#
# Inputs          : $self                   - Instance Data
#                   $opts                   - Options Hash
#
# Returns         : 
#
sub searchDir
{
    my ($self, $opts) = @_;

    my $ufile = $opts->{'file'};
    foreach my $dir ( @{ MiscDirs($self, $opts->{'dir'}) } )
    {
        my $file = "$dir/$ufile";
        return $file
            if ( -f $file );
    }
    return undef;
}

#-------------------------------------------------------------------------------
# Function        : searchSimple
#
# Description     : The user is looking for a file in known subdir subdir
#                   It will be in one of the package directories
#
# Inputs          : $self                   - Instance Data
#                   $opts                   - Options Hash
#
# Returns         : 
#
sub searchSimple
{
    my ($self, $opts) = @_;

    my $mode = $opts->{'Mode'}{'dir'};
    Error ("JatsLocatePkgFile. searchSimple. Internal Error. No 'dir' configured'",
            "Entry: $self->{'uspec'}") unless ( $mode );

    $opts->{'dir'} = $mode;
    return searchDir( $self, $opts );
}

#-------------------------------------------------------------------------------
# Function        : searchPkg
#
# Description     : The user is looking for a file in a package pkg subdir
#                   It will be in one of the package directories
#
# Inputs          : $self                   - Instance Data
#                   $opts                   - Options Hash
#
# Returns         : 
#
sub searchPkg
{
    my ($self, $opts) = @_;

    my $ufile = $opts->{'file'};
    foreach my $dir ( @{ PkgDirs($self) } )
    {
        my $file = "$dir/$ufile";
        return $file
            if ( -f $file );
    }
    return undef;
}

#-------------------------------------------------------------------------------
# Function        : BinDirs
#
# Description     : Return an array of directories to search for Bin files
#                   Cache results for future use
#
#                   Bin dirs are used to hold:
#                       Programs
#                       Debian Packages
#                       File System Images
#
#                   The directory is named after a platform and will have
#                   a P or D suffix
#
#                   Template:       {BASE}/bin/{PLATFORM}{TYPE}
#                   Compatability:  {BASE}/bin.{PLATFORM}{TYPE}
#                                   {BASE}/bin/bin.{PLATFORM}{TYPE}
#
# Inputs          : $self                   - Instance Data
#
# Returns         : An Array
#
sub BinDirs
{
    my $self = shift;
    #
    #   Return cached results
    #
    unless ( $self->{'cache'}{'bin'} )
    {
        #
        #   Create an array of location to search
        #
        my @dirs;
        foreach my $base ( @{$self->{'BuildPaths'}} )
        {
            foreach my $type ( $self->{'type'}, '' )
            {
                foreach my $subdir ( @{$self->{'BuildParts'}} )
                {
                    my $dir = "$base/bin/$subdir$type";
#print "----Try : $dir\n";
                    push @dirs, $dir if ( -d $dir );
                }
            }
        }
        $self->{'cache'}{'bin'} = \@dirs;
    }
    return $self->{'cache'}{'bin'}
}

#-------------------------------------------------------------------------------
# Function        : LibDirs
#
# Description     : Return an array of directories to search for Lib files
#                   Cache results for future use
#
#                   Lib dirs are used to hold:
#                       Shared Libraries
#                       Static Libraries
#
#                   The file name should have an embedded type (P or D)
#
#                   Template:       {BASE}/lib/{PLATFORM}
#                   Compatability:  {BASE}/lib/{PLATFORM}{TYPE}
#                                   {BASE}/lib.{PLATFORM}{TYPE}
#                                   {BASE}/lib/lib.{PLATFORM}{TYPE}
#
# Inputs          : $self                   - Instance Data
#
# Returns         : An Array
#
sub LibDirs
{
    my $self = shift;
    #
    #   Return cached results
    #
    unless ( $self->{'cache'}{'lib'} )
    {
        #
        #   Create an array of location to search
        #
        my @dirs;
        foreach my $base ( @{$self->{'BuildPaths'}} )
        {
            foreach my $type ( $self->{'type'}, '' )
            {
                foreach my $subdir ( @{$self->{'BuildParts'}})
                {
                    my $dir = "$base/lib/$subdir$type";
#print "----Try : $dir\n";
                    push @dirs, $dir if ( -d $dir );
                }
            }
        }
        $self->{'cache'}{'lib'} = \@dirs;
    }
    return $self->{'cache'}{'lib'}
}

#-------------------------------------------------------------------------------
# Function        : PkgDirs
#
# Description     : Return an array of directories to search for Pkg files
#                   Cache results for future use
#
#                   pkg dirs are used to contain foreign subdirectory trees
#                   Typically used to transparently transfer 3rd parts software
#
#                   There are two forms of pkg dir
#                   Both are not supported within the same package
#
#                   Form-1
#                   Template:       {BASE}/pkg
#
#                   Form-2
#                   Template:       {BASE}/pkg.{PLATFORM}
#                   Template:       {BASE}/pkg.{MACHTYPE}
#
#                   Currently NOT a very good pkg searcher
#                   It does not handle pkg/pkg.MACHTYPE dirs
#
# Inputs          : $self                   - Instance Data
#
# Returns         : An Array
#
sub PkgDirs
{
    my $self = shift;
    #
    #   Return cached results
    #
    unless ( $self->{'cache'}{'pkg'} )
    {
        #
        #   Create an array of location to search
        #
        my @dirs;
        foreach my $base ( @{$self->{'BuildPaths'}} )
        {
            next unless ( -d "$base/pkg" );
            foreach my $subdir ( @{$self->{'BuildParts'}} )
            {
                my $dir = "$base/pkg/$subdir";
#print "----Try : $dir\n";
                push @dirs, $dir if ( -d $dir );
            }

            unless ( @dirs )
            {
                push @dirs, $base;
            }

        }
        $self->{'cache'}{'pkg'} = \@dirs;
    }
    return $self->{'cache'}{'pkg'}
}

#-------------------------------------------------------------------------------
# Function        : MiscDirs
#
# Description     : Return an array of directories to search for Misc files
#                   Cache results for future use
#
#                   Misc dirs are used to contains files of known types
#                   Normally a flat directory structure
#                   No 'type' information
#
#                   Template:   {BASE}/{DIR}
#
#                   Used for dirs that are not special, like the Bin and Lib
#
# Inputs          : $self                   - Instance Data
#                   $root                   - Base of the section
#
# Returns         : An Array
#
sub MiscDirs
{

    my ($self, $root) = @_;

    #
    #   Clean up the user path
    #   Remove leading, trailing and multiple /
    #
    $root =~ s~/+~/~g;
    $root =~ s~^/~~;
    $root =~ s~/$~~;

    #
    #   Return cached results
    #
    unless ( $self->{'cache'}{$root} )
    {
        #
        #   Create an array of location to search
        #
        my @dirs;
        foreach my $base ( @{$self->{'BuildPaths'}} )
        {
            my $dir = "$base/$root";
#print "----Try : $dir\n";
            push @dirs, $dir if ( -d $dir );
        }
        $self->{'cache'}{$root} = \@dirs;
    }
    return $self->{'cache'}{$root}
}


#sub DESTROY
#{
#    DebugDumpData(__PACKAGE__, @_);
#}
1;