Subversion Repositories DevTools

Rev

Rev 1588 | Blame | Compare with Previous | Last modification | View Log | RSS feed

########################################################################
# Copyright (C) 2006 ERG Limited, All rights reserved
#
# Program Name        : deploylib.pm
#
# Program Type        : Perl Module (.pm)
#
# Original Author(s)  : V.Chatzimichail(vasilic)
#
# Description / Purpose:
#      Deploylib is a set of high-level functions written in Perl (for portability) 
#      that allow a user to quickly setup a deployment configuration and produce a 
#      deliverable package.
#
# Description:
#
#
#......................................................................#

require 5.6.1;

#------------------------------------------------------------------------------
# Package definition
#------------------------------------------------------------------------------
package deploylib;

#------------------------------------------------------------------------------
# Pragmas
#------------------------------------------------------------------------------
use strict;
use Getopt::Std;
use File::Copy;
use File::Find;
use File::Basename;
use File::Path;
use Cwd;
use Carp;
use DBI;
use DeployUtils::RmPkgInfo;
use BuildConfig;
use Exporter();

use ArrayHashUtils;
use JatsEnv;
use JatsError;
use JatsSystem;

#
#   The LWP is a part of the Active State Perl, but not the solaris perl
#   If the user has not read the installation doco that insists we use
#   ActiveState perl...
#
my $UserAgentAvailable = eval "require LWP::UserAgent";


#-------------------------------------------------------------------------------
#   Export variables and function into the users name space
#-------------------------------------------------------------------------------
our @ISA    = qw(Exporter);
our @EXPORT = qw(
                    &Init
                    &setPkgDescription
                    &setPkgName
                    &setErgAfcBaseDir
                    &setPkgOverview
                    &addInstallshieldFiles
                    &installAllDpkgArchivePkgFiles
                    &installAllDpkgArchivePkgFiles2
                    &installAllDpkgArchiveDevcdFiles
                    &installAllDpkgArchiveJspFiles
                    &installAllDpkgArchiveFiles
                    &installAllDpkgArchiveAcHtmlFiles
                    &installAllDpkgArchiveInfoFilesFiles
                    &installAllDpkgArchiveSqlFiles
                    &installAllDpkgArchiveWarFiles
                    &installAllDpkgArchiveJarFiles
                    &installAllDpkgArchiveEtcFiles
                    &installAllDpkgArchiveScriptsFiles
                    &installAllDpkgArchiveIncludeFiles
                    &installAllDpkgArchiveDocFiles
                    &installDpkgArchiveFile
                    &installDpkgArchiveAcHtmlFile
                    &installDpkgArchiveRptFile
                    &installDpkgArchiveRoxFile
                    &installDpkgArchiveDatFile
                    &installDpkgArchiveThxFile
                    &installDpkgArchiveMugFile
                    &installDpkgArchiveInfoFilesFile
                    &installDpkgArchiveSqlFile
                    &installDpkgArchiveWarFile
                    &installDpkgArchiveJarFile
                    &installDpkgArchiveSarFile
                    &installDpkgArchiveEtcFile
                    &installDpkgArchiveScriptsFile
                    &installDpkgArchiveIncludeFile
                    &installDpkgArchiveDocFile
                    &installDpkgArchiveBinFile
                    &installDpkgArchiveLibFile
                    &installPkgAddConfigFile
                    &installPkgAddSystemClassFile
                    &installDpkgArchivePkgRaw
                    &updatePrototypeFileAddItem
                    &updatePrototypeFileAddItem2
                    &addPath2Prototype
                    &createAfcRcScriptLink
                    &createAfcRcScriptLink2
                    &installAllDpkgArchiveBinFiles
                    &CreateTargetDirStructure
                    &createPatch
                    &createPackage
                    &createPrototypeFile
                    &addPatchInfo2ProtoTypeFile
                    &addPkgInfoClasses
                    &addPkgInfoField
                    &updatePrototypeFileItemClass
                    &useReplaceClass
                    &setReplaceClassFiles
                    &createPkginfoFile
                    &updatePrototypeFileItemOwner
                    &setPermissions
                    &chmod
                    &chmodRecursive
                    &chmodDir
                    &chmodFile
                    &createSymbolicLink
                    &createPrototypeFile2
                    &installDeployFile
                    &createDpkgArchive
                    &generateHtmlReleaseNote
                    &generateIShieldIncludeFile
                    &createPerlSvcWin32
                    &createPerlAppWin32
                    &convertFile

                    &getErgAfcBaseDir
                    &getGenericNameNoVersionForLib
                    &getGenericNameForLib
                    &createZip
                    &generateXmlDependancy

                    %TargetDstDirStructure
                    %LocalSrcDirStructure
                    %BuildPkgArchive
                    $MachType
                    $TargetHomeDir
                    $TargetBaseDir

                    $PkgName
                    $PkgVersionUser
                    $PkgVersion

                );

#------------------------------------------------------------------------------
# Constants global/local to this package
#------------------------------------------------------------------------------
use vars qw ( $opt_n $opt_v $opt_r $opt_t $opt_m $opt_d $opt_p $opt_o $opt_k $opt_g );

my ($VENDOR_DESC)            = "ERG Transit Systems Ltd";
my ($CATEGORY_DESC)          = "application";
my ($ERGAFC_BASEDIR)         = "/afc";
my ($MAXINST)                = "1000";
my ($PKG_OVERVIEW)           = "To Be Defined.";

my (@PATCH_INFO_FILES) = qw (
    checkinstall 
    copyright 
    patch_checkinstall 
    patch_postinstall 
    i.none 
    postinstall 
    preinstall 
) ;

my (@PATCH_UTIL_FILES) = qw ( backoutpatch installpatch );

my (@PKG_UTIL_FILES) = qw ( requestlib.sh );

my (@PKG_ISHIELD_FILES)   = qw ( ishieldlib.rul ishieldlib.h );

my (@PKG_ISHIELD_IMG_FILES) = qw ( 
   islib_pane.bmp
   islib_splash.bmp
   islib_topicon.bmp
);


my (@PATCH_ISHIELD_FILES) = qw ( 
    postinstall.rul
    preinstall.rul 
    postremove.rul 
    preremove.rul 
);
                    
my ($PKG_ISHIELD_DEF_FILE) = "pkgdef.h";
my ($PKG_ISHIELD_DIR)      = "";

my ($PKG_UTIL_DIR)   = "";
my ($PATCH_UTIL_DIR) = "";


my ($m_UID)  = "";
my ($m_GID)  = "";
my ($m_MASK) = "";
my ($m_KEEP_MASK) = "";


#------------------------------------------------------------------------------
# Variables global/local to this package
#------------------------------------------------------------------------------
our $InterfaceDir       = "";

our $DpkgBinDir         = "";
our %DpkgBinDirList     = ();
our $DpkgLibDir         = "";
our %DpkgLibDirList     = ();
our $DpkgScriptsDir     = "";
our $DpkgEtcDir         = "";
our $DpkgJarDir         = "";
our $DpkgSarDir         = "";
our $DpkgWarDir         = "";
our $DpkgSqlDir         = "";
our $DpkgInfoFilesDir   = "";
our $DpkgPkgDir         = "";
our $DpkgJspDir         = "";
our $DpkgRoxDir         = "";
our $DpkgRptDir         = "";
our $DpkgAcHtmlDir      = "";
our $DpkgIncludeDir     = "";
our $DpkgDevcdDir       = "";
our $DpkgDatDir         = "";
our $DpkgThxDir         = "";
our $DpkgMugDir         = "";
our $DpkgDocDir         = "";

our @LibCheckList       = ();

our $CurrentDir         = "";
our $RootDir            = "";
our $BuildType          = "";
our $MachType           = "";
our $Platform           = "";
our $Product            = "";
our $Target             = "";
our $SrcDir             = "";
our $PkgDir             = "";
our $ReleaseDir         = "";
our $Username           = "";

our $PkgBaseDir         = "";
our $PkgInfoFileName    = "pkginfo";
our $PkgInfoFile        = "";
our $ProtoTypeFileName  = "prototype";
our $ProtoTypeFile      = "";

our $PkgPatchName       = "";
our $PkgPatchID         = "";
our $PkgPatchNum        = "";
our $PkgPatchReadme     = "";
our $PkgPatchTmpDir     = "";

our $PkgVersion         = "";
our $PkgVersionStr      = "";
our $PkgVersionUser     = "";
our $PkgName            = "";
our $PkgBuildNum        = "";
our $PkgOutputFile      = "";
our $PkgReleaseNote     = "";
our $PkgLabel           = "";
our $PkgDesc            = "";
our $PkgNameLong        = "";
our $PkgInfoClasses     = "none";

our $PkgPreviousVersionStr = "";
our $TargetBaseDir      = "";
our $TargetHomeDir      = "";

our $SandBoxName        = "";
our $ProjectAcronym     = "";

our $TmpGlobalVariable  = ""; # used to pass variables into PERL find functions

our %TargetDstDirStructure = ();
our %LocalSrcDirStructure  = ();

our $BuildFileInfo       = "";
# This was removed to add the use of the Buildfile.pm module, but this hash is needed 
# because the deployfiles use it for library version numbers in the file lists.
# So it is left here and is a simply copy of the hash from buildfile pm
our %BuildPkgArchive     = ();

our $RmPkgDetails        = undef;
our $RmPvPkgDetails      = undef;

my  $autobuild = $ENV{'GBE_ABT'} || 0;


#------------------------------------------------------------------------------
# Initialization actions
#------------------------------------------------------------------------------

#
#   Init the error and message subsystem
#
ErrorConfig( 'name'    => 'DEPLOYLIB' ,
             'debug'   => $ENV{GBE_DEBUG},
             'verbose' => $ENV{GBE_VERBOSE},
             );


#------------------------------------------------------------------------------
# Package Interface Subroutines
#
# The following functions are used by the Makefile.pl scripts.  Programmers
# call the following functions to set up the basic requirements that the
# automated make system requires.
#------------------------------------------------------------------------------


#------------------------------------------------------------------------------
sub Init
#
# Description:
#       Tests Environment Variables, it also checks the required command line 
#       variables.
#
# Inputs:
#       Command line.
#
# Returns:
#  1
#
# Globals:
#  $makelib::RootDir
#
# Notes:
#  -
#
# Todo:
#  -
#------------------------------------------------------------------------------
{

    # first we deal with the command line values we expect, these include:
    #   GBE_ROOT                                                       (-r)
    #   Package Name                                                   (-n)
    #   Package Home Directory (relative to the ERGAFC_BASEDIR)        (-d)
    #   Package Version                                                (-v)
    #   Build Type                                                     (-t)
    #   Patch Number                                                   (-p)
    #   Previous (old) version number                                  (-o)
    #   Platform                                                       (-m)
    #   Product (optional)                                             (-k)
    #   Machine Type (optional)                                        (-g)
    
    $CurrentDir = cwd;

    my ($i);
    Getopt::Std::getopts ('v:n:r:t:m:d:p:o:k:g:');
    if ( $opt_n )
    {
        $PkgName      = $opt_n;
    }
    else
    {
        Error("Package Name not supplied!");
    }

    if ( $opt_r )
    {
        # lets change to root dir and get fully qualified path from cwd and return back
        chdir($opt_r);
        $RootDir = cwd;
        chdir($CurrentDir);

        $SandBoxName      = File::Basename::basename($RootDir);
    }
    else
    {
        Error("GBE_ROOT not supplied!");
    }

    if ( $opt_t )
    {
        $BuildType = $opt_t;
    }
    else
    {
        Error("GBE_TYPE not supplied!");
    }

    #
    #   Target machine type ( Underlying machine type in a Product Family)
    #   If not provided, the assume that its the same as the platform (compat)
    #
    $opt_g = $opt_m unless ( $opt_g );
    if ( $opt_g )
    {
        $Target = $opt_g;
        if ( $Target =~ /^SOLARIS/ )
        {
            $MachType = 'sparc';
        }
        elsif ( $Target =~ /^WCE/ )
        {
            $MachType = 'WinCE';
        }
        elsif ( $Target =~ /^WIN32/ )
        {
            $MachType = 'win32';
        }
        else
        {
            Error("Unknown target [$opt_g] supplied!");
        }
    }

    #
    #   Platform
    #   This is the full product name in a product family.
    #
    if ( $opt_m )
    {
        $Platform = $opt_m;
    }
    else
    {
        Error("Platform not supplied!");
    }

    #
    #   Setup Product
    #   If not defined then use the platform
    #
    $Product = $opt_k ? $opt_k : $Platform;

    if ( $opt_d )
    {
        $TargetBaseDir = $opt_d;
    }
    else
    {
        Error("Package base directory not supplied!");
    }

    if ( $opt_p )
    {
        my $pNum = sprintf("%02s", $opt_p);
        if ( "$pNum" =~ m/^[0-9][0-9]$/ )
        {
            $PkgPatchNum = $pNum;
        }
        else
        {
            Error("-p command line arg [$opt_p] has invalid format",
                     "Required format is an integer value.");
        }
    }

    if ($opt_v)
    {
        if( "$opt_v" =~ m/^(\d*)\.(\d*)\.(\d*)-(\d*)\.([a-z]{2,3})$/ ) # N.N.N-N.ppp
        {
            my ($s1, $s2, $s3, $s4, $s5) = ($1, $2, $3, $4, $5);

            $PkgVersionStr = sprintf("%02s%02s%02s", $s1,$s2,$s3);
            $PkgVersion  = "$s1\.$s2\.$s3";
            $PkgBuildNum = $s4;
            $ProjectAcronym   = $s5;
        }
        elsif( "$opt_v" =~ m/^(\d*)\.(\d*)\.(\d*)\.([a-z]{2,3})$/ ) # N.N.N.ppp
        {
            my ($s1, $s2, $s3, $s4) = ($1, $2, $3, $4);

            $PkgVersionStr = sprintf("%02s%02s%02s", $s1,$s2,$s3);
            $PkgVersion  = "$s1\.$s2\.$s3";
            $PkgBuildNum = "1";
            $ProjectAcronym   = $s4;
        }
        else
        {
            Error("-v command line arg [$opt_v] has invalid format",
                  "Allowed formats are N.N.N-B.ppp and N.N.N.ppp where:",
                  "    N is an integer",
                  "    B is an integer",
                  "    ppp is the project acronym",
                  "Check propject acronym.");

        }
        $PkgVersionUser  = $opt_v;
    }
    else
    {
        Error("Package Version not supplied!");
    }


    # lets check to see if we have a previous version 
    if ($opt_o)
    {
        $PkgPreviousVersionStr = $opt_o;
    }

    # Load the JATS-parsed information from the build.pl file
    #
    $BuildFileInfo = DeployUtils::BuildConfig->new($RootDir, $Platform);

    # Load all our build dependencies
    #
    %BuildPkgArchive = $BuildFileInfo->getDpkgArchiveHash();

    # lets define where we get our stuff from
    #
    if ( $ERGAFC_BASEDIR =~ m|/$| )
    {
        $TargetHomeDir= "$ERGAFC_BASEDIR$TargetBaseDir"; 
    }
    else
    {
        $TargetHomeDir= "$ERGAFC_BASEDIR/$TargetBaseDir"; 
    }
    $PkgDir       = "$RootDir/pkg";
    $SrcDir       = "$RootDir/src"; 
    $InterfaceDir = "$RootDir/interface";
    $ReleaseDir   = "$RootDir/build/deploy";

    $PKG_UTIL_DIR   = "$InterfaceDir/deployfiles";
    $PATCH_UTIL_DIR = $PKG_UTIL_DIR;
    #
    #   InstallShield files are provided via a package
    #   Ensure that a suitable package has been provided
    #
    if ( ! -d  $PKG_UTIL_DIR )
    {
        Error("No deployment support files found",
              "These MUST be provided by a dependant package in build.pl");
    }


    $Username     = getlogin || getpwuid($<);

    if ( "$BuildType" eq "D" )
    {
        $PkgBaseDir = "$PkgDir/debug"; 
    }
    else
    {
        $PkgBaseDir = "$PkgDir/prod"; 
    }
 
    $PkgInfoFile   = "$PkgBaseDir/$PkgInfoFileName";
    $ProtoTypeFile = "$PkgBaseDir/$ProtoTypeFileName";

    $DpkgScriptsDir = "$InterfaceDir/scripts";


    $DpkgEtcDir     = "$InterfaceDir/etc";
    $DpkgJarDir     = "$InterfaceDir/jar";
    $DpkgSarDir     = "$InterfaceDir/sar";
    $DpkgWarDir     = "$InterfaceDir/war";
    $DpkgSqlDir     = "$InterfaceDir/sql";

    $DpkgInfoFilesDir = "$InterfaceDir/infofiles";
    $DpkgPkgDir       = "$InterfaceDir/pkg";
    $DpkgJspDir       = "$InterfaceDir/jsp";
    $DpkgRoxDir       = "$InterfaceDir/rox";
    $DpkgRptDir       = "$InterfaceDir/rpt";
    $DpkgAcHtmlDir    = "$InterfaceDir/achtml";
    $DpkgIncludeDir   = "$InterfaceDir/include";
    $DpkgDevcdDir     = "$InterfaceDir/devcd";
    $DpkgDatDir       = "$InterfaceDir/dat";
    $DpkgThxDir       = "$InterfaceDir/thx";
    $DpkgMugDir       = "$InterfaceDir/mug";
    $DpkgDocDir       = "$InterfaceDir/doc";


    $DpkgLibDir     = "$InterfaceDir";
    $DpkgBinDir     = "$InterfaceDir";
   

    #   Define where we might find our artifacts
    #   The search order is: Platform, Product, --Uses extensions,Target, MachineType
    #   Much of this list, and its described in the build.pl file, use the JATS
    #   generated information to extract the correct information
    #
    #   Only add the directory to the list if it actually exists
    #   This will speed up searching later.
    #
    #   Create multiple search paths
    #       One for an exaustive search
    #       Others for selective searchs
    #
    #
    foreach my $part ( $BuildFileInfo->getPlatformParts($Platform), $MachType )
    {
        next unless ( $part );
        foreach my $subdir ( "lib." . "$part",
                             "lib." . "$part" . "$BuildType",
                             "lib/lib." . "$part" . "$BuildType",
                             "lib/$part" . "$BuildType",
                             "lib/$part" )
        {
            if ( -d "$DpkgLibDir/$subdir" )
            {
                UniquePush( \@{$DpkgLibDirList{_ALL_}}, $subdir);
                UniquePush( \@{$DpkgLibDirList{$part}}, $subdir);
            }
        }
    }

    foreach my $part ( $BuildFileInfo->getPlatformParts($Platform), $MachType )
    {
        next unless ( $part );
        foreach my $subdir ( "bin." . "$part" . "$BuildType",
                             "bin." . "$part",
                             "bin/bin." . "$part" . "$BuildType",
                             "bin/" . "$part" . "$BuildType",
                             "bin/" . uc($part) . "$BuildType",
                             "bin/$part",

                             "bin." . "$part" . "P",
                             "bin/bin." . "$part" . "P",
                             "bin/" . "$part" . "P",
                             "bin/" . uc($part) . "P" )
        {
            if ( -d "$DpkgBinDir/$subdir" )
            {
                UniquePush( \@{$DpkgBinDirList{_ALL_}}, $subdir);
                UniquePush( \@{$DpkgBinDirList{$part}}, $subdir);
            }
        }

    }

    Information("------------------------------------------------------------");


    # lets generate the patch id if we are building a patch
    #
    if ( "x$PkgPatchNum" ne "x" )
    {
        Information("This is a PATCH build...");

        $PkgPatchName = uc ($PkgName);


        my ($_tmpStr) = sprintf("%s%s", $PkgPatchName, 
                                        $PkgVersionStr);


        $PkgPatchID     = "$_tmpStr" . "-" . "$PkgPatchNum"; 
        $PkgPatchReadme = "$PkgBaseDir" . "/README." . "$PkgPatchID"; 
        $PkgPatchTmpDir = "$PkgBaseDir/tmp";

        $PkgReleaseNote = "$ReleaseDir" . "/$PkgPatchName" .
                                                                "$PkgVersionStr\_" . 
                                                                "$PkgPatchNum\_" . 
                                                                "$ProjectAcronym\_" . 
                                                                "$Platform"; 

        $PkgLabel = uc ($ProjectAcronym) . "_" .
                               $PkgPatchName . "_" .
                               $PkgVersionStr . 
                               "_P" . $PkgPatchNum;  


        # lets define what our output package name shall be
        #
        $PkgOutputFile = "na"; 
    }
    else
    {
        Information("This is a normal RELEASE build...");
        $PkgReleaseNote = "$ReleaseDir" . "/" .
                                                                "$PkgName" . "-" . 
                                                                "$PkgVersion" . "." .
                                                                "$ProjectAcronym" . "-" .
                                                                "$Platform";

        $PkgLabel = uc ($ProjectAcronym) . "_" .
                               uc ($PkgName) . "_" .
                               "R_" .
                               "$PkgVersionStr";  


        # lets define what our output package name shall be
        #
        $PkgOutputFile = "$PkgName" . "-" . 
                         "$PkgVersion" . "." .
                         "$ProjectAcronym" . "-" .
                         "$Platform" . "-" .
                         "$BuildType\.pkg";
    }

    Information("------------------------------------------------------------");


    # lets just show what we have determined.
    #
    Information("Current environment definitions (Increase Verbose Level to see all definitions)...");

    Verbose("DeployFiles      =[$PKG_UTIL_DIR]");

    Information("PkgName          =[$PkgName]");
    Information("PkgVersionUser   =[$PkgVersionUser]");

    Information("PkgVersion       =[$PkgVersion]");
    Information("PkgVersionStr    =[$PkgVersionStr]");

    Information("PkgBuildNum      =[$PkgBuildNum]");

    if ( "x$PkgPatchID" ne "x" )
    {
        Information("PkgPatchName     =[$PkgPatchName]");
        Information("PkgPatchNum      =[$PkgPatchNum]");
        Information("PkgPatchID       =[$PkgPatchID]");
        Information("PkgPatchTmpDir   =[$PkgPatchTmpDir]");
    }

    Information("PkgReleaseNote   =[$PkgReleaseNote]") unless ($autobuild);
    Information("PkgReleaseNote   =[Generated later by ABT]") if ($autobuild);
    Information("PkgLabel         =[$PkgLabel]");

    Information("PkgPreviousVersionStr=[$PkgPreviousVersionStr]");

    Information("ProjectAcronym   =[$ProjectAcronym]");
    Information("BuildType        =[$BuildType]");
    Information("MachType         =[$MachType]");
    Information("Platform         =[$Platform]");
    Information("Product          =[$Product]");
    Information("Target           =[$Target]");
    Verbose("BuildParts       =[" . join(',',$BuildFileInfo->getPlatformParts($Platform)) . "]");
    
    Information("CurrentDir       =[$CurrentDir]");
    Information("RootDir          =[$RootDir]");
    Information("SandBoxName      =[$SandBoxName]");
    Information("Username         =[$Username]");

    Information("TargetBaseDir    =[$TargetBaseDir]");
    Information("TargetHomeDir    =[$TargetHomeDir]");

    Information("PkgBaseDir       =[$PkgBaseDir]");
    Information("SrcDir           =[$SrcDir]");
    Information("PkgDir           =[$PkgDir]");
    Information("ReleaseDir       =[$ReleaseDir]");

    Verbose("InterfaceDir     =[$InterfaceDir]");
    Verbose("DpkgScriptsDir   =[$DpkgScriptsDir]");
    Verbose("DpkgBinDir(s)    =[");
    foreach $i (@{$DpkgBinDirList{'_ALL_'}})
    {
        Verbose("                   $DpkgBinDir/$i");
    }
    Verbose("                  ]");


    Verbose("DpkgLibDir(s)    =[");
    foreach $i (@{$DpkgLibDirList{'_ALL_'}})
    {
        Verbose("                   $DpkgLibDir/$i");
    }
    Verbose("                  ]");


    Verbose("DpkgEtcDir       =[$DpkgEtcDir]");
    Verbose("DpkgJarDir       =[$DpkgJarDir]");
    Verbose("DpkgSarDir       =[$DpkgSarDir]");
    Verbose("DpkgWarDir       =[$DpkgWarDir]");
    Verbose("DpkgSqlDir       =[$DpkgSqlDir]");
    Verbose("DpkgJspDir       =[$DpkgJspDir]");
    Verbose("DpkgRoxDir       =[$DpkgRoxDir]");
    Verbose("DpkgRptDir       =[$DpkgRptDir]");
    Verbose("DpkgAcHtmlDir    =[$DpkgAcHtmlDir]");
    Verbose("DpkgIncludeDir   =[$DpkgIncludeDir]");
    Verbose("DpkgDevcdDir     =[$DpkgDevcdDir]");
    Verbose("DpkgDatDir       =[$DpkgDatDir]");
    Verbose("DpkgThxDir       =[$DpkgThxDir]");
    Verbose("DpkgMugDir       =[$DpkgMugDir]");
    Verbose("DpkgDocDir       =[$DpkgDocDir]");

    Verbose("DpkgInfoFilesDir =[$DpkgInfoFilesDir]");
    Verbose("DpkgPkgDir       =[$DpkgPkgDir]");

    Verbose("PkgInfoFile      =[$PkgInfoFile]");
    Verbose("ProtoTypeFile    =[$ProtoTypeFile]");

    foreach $i ( $BuildFileInfo->getDpkgArchiveList() )
    {
        my $moduleInfo = $BuildFileInfo->getDpkgArchiveInfo($i);
        
        Verbose(  "Build Dependency =" .
                  "[$moduleInfo->{type}] " .
                  "[$i] " .
                  "[$moduleInfo->{version}] " .
                  "[$moduleInfo->{proj}]");
    }

    if ( "$MachType" eq "sparc" )
    {
        Information("PkgOutputFile    =[$PkgOutputFile]");
    }

    Information("PkgOverview      =[$PKG_OVERVIEW]");


    # Lets evaluate TargetDstDirStructure to expand any vars
    foreach $i ( keys %TargetDstDirStructure )
    {
        if ( $TargetDstDirStructure{$i} =~ /\$/ )
        {
            Debug("-n", "Expanding TargetDstDirStructure [$TargetDstDirStructure{$i}] to ");
            $TargetDstDirStructure{$i} = eval "sprintf " . qq/"$TargetDstDirStructure{$i}"/;
            Information("TargetDstDir $i =[$TargetDstDirStructure{$i}]");
        }
    }

    # lets check waht we can before proceeding.
    #
    ValidateLocalSrcDirStructure();

    # Everything went ok lets begin by creating some dirs...
    #
    CreateTargetDirStructure();

    # lets get some details for our package
    getRmDetails();

    # done
    return 1;
}


#------------------------------------------------------------------------------
sub setPkgDescription
#
# Description:
#       This sub-routine is used to set the Package DESC field
#       from within the deployfile.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 1 )
    {
        Error("Incorrect number of params passed to setPkgDescription() function.",
              "Check deploy config.");
    }
    my ($lpkgDesc) = shift;
   
    # we use what was defined in deployfile if
    # the RM details are not available
    if ( ! defined($RmPkgDetails) )
    {
        $PkgDesc = $lpkgDesc;
    }
    else
    {
        # let's use the details if we have them
        if ( $RmPkgDetails->foundDetails() )
        {
            # we have RM details, we will only use them
            # if nothing is locally defined,
            # (ie locally defined details takes precedence)
            if ( "x$lpkgDesc" eq "x" )
            {
                $PkgDesc = $RmPkgDetails->pv_description();
            }
            else
            {
                $PkgDesc = $lpkgDesc;
            }
        }
        else
        {
            $PkgDesc = $lpkgDesc;
        }
    }

    # done
    return 1;
}

#------------------------------------------------------------------------------
sub setPkgName
#
# Description:
#       This sub-routine is used to set the Package NAME field
#       from within the deployfile.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 1 )
    {
        Error("Incorrect number of params passed to " .
                  "setPkgName() function. ",
                  "Check deploy config.");
    }
    $PkgNameLong = shift;

    # done
    return 1;
}


#------------------------------------------------------------------------------
sub setErgAfcBaseDir
#
# Description:
#       This sub-routine is used to reset the ERG AFC base dir global variable
#       from within the deployfile.
#
#------------------------------------------------------------------------------
{
    # if TargetBaseDir is empty then init has not been called yet so we can set 
    # base dir, if however it is not null then init has been called and setting
    # base dir after init causes problems in some cases.
    if ( $TargetBaseDir ne "" )
    {
        Error("setErgAfcBaseDir() cannot be called after Init(), place before Init() in deployfile.pl");
    }

    # correct number of parameters?
    if ( ($#_+1) != 1 )
    {
        Error("Incorrect number of params passed to " .
                  "setErgBaseDir() function. ",
                  "Check deploy config.");
    }

    my ($newDir) = @_;
    $ERGAFC_BASEDIR = "$newDir";

    return 1;
}



#------------------------------------------------------------------------------
sub getErgAfcBaseDir
#
# Description:
#       This sub-routine is used to get the ERG AFC base dir global variable
#       to be used within the deployfile.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 0 )
    {
        Error("Incorrect number of params passed to " .
                  "getErgBaseDir() function. ",
                  "Check deploy config.");
    }

    return "$ERGAFC_BASEDIR";
}


#------------------------------------------------------------------------------
sub setPkgOverview
#
# Description:
#       This sub-routine is used to reset the package overview that
#       is used to build the package from within the deployfile.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 1 )
    {
        Error("Incorrect number of params passed to " .
                  "setPkgOverview() function. ",
                  "Check deploy config.");
    }

    my ($mStr) = @_;
    $PKG_OVERVIEW = "$mStr";

    return 1;
}


#------------------------------------------------------------------------------
sub getPkgOverview
#
# Description:
#       This sub-routine is used to get the package overview string global variable
#       to be used within the deployfile.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 0 )
    {
        Error("Incorrect number of params passed to " .
                  "getPkgOverview() function. ",
                  "Check deploy config.");
    }

    return "$PKG_OVERVIEW";
}



#------------------------------------------------------------------------------
sub addInstallshieldFiles
#
#    Description:
#        This is called to add extra installshield files to the PKG_ISHIELD_FILES array.
#        For each parameter it checks for the existense of arg.* in the PKG_UTIL_DIR
#        and adds all found files to the array
#        This must be called before init() is called.
#
#    INPUT:
#        files to add
#
#    RETURN:
#        nothing
#
#------------------------------------------------------------------------------
{
    my @files;

    # lets just check to see if we can execute this function on this machine.
    if ( "$MachType" eq "sparc" )
    {
        Warning("addInstallshieldFiles() not supported on this machine type.");
        return 1;
    }

    foreach my $i ( @_ )
    {
        @files = glob("$PKG_UTIL_DIR/$i.*");
        foreach my $j ( @files )
        {
            $j = basename($j);
            Verbose("Adding Installshield file $j");
            push(@PKG_ISHIELD_FILES, $j);
        }
    }
    return 1;
}   # addInstallshieldFiles



#------------------------------------------------------------------------------
sub removeBuildTypeFromItemName
#
#    Description:
#        This sub-routine is used to remove the buildtype from the item name.
#        i.e. debug files will be tagged with *D.* 
#             prod  file will be tagged with *P.*
#
#    INPUT:
#        item name
#
#    RETURN:
#        new item name.
#
#------------------------------------------------------------------------------
{
    my ($file) = @_;

    my ($nfile) = $file;
    $nfile =~ s/D\.|P\./\./;
    return "$nfile";
}



#------------------------------------------------------------------------------
sub installAllDpkgArchivePkgFiles
#
# Description:
#       This sub-routine is used to install all infofiles files from the
#       dpkg_archive into the defined install area.
#
#       It assumes based on the build type where the src files will be located.
#
#       If it has any problems it will log an error and stop processing.
#
#       Source directory: $DpkgPkgDir       (interface/pkg)
#       Target directory: $PkgBaseDir       (output/pkg/[debug|prod]
#
#------------------------------------------------------------------------------
{
    #
    #   Use the (now) more general function installAllDpkgArchivePkgFiles2
    #   with spacial parameters to mimic the original function
    #
    #   Copy all from the 'pkg' directory to the PkgBaseDir
    #
    installAllDpkgArchivePkgFiles2 ( "--Dstdir=$PkgBaseDir", '--Srcdir=pkg', @_ );
    return 1;
}


#------------------------------------------------------------------------------
sub installAllDpkgArchivePkgFiles2
#
# Description:
#       This sub-routine is used to install all pkg files from the
#       dpkg_archive into the defined install area.
#
#       Simlar to installAllDpkgArchivePkgFiles, but the target directory
#       is specified by the user.
#
#       It assumes based on the build type where the src files will be located.
#
#       If it has any problems it will log an error and stop processing.
#
# Inputs          : targetTag       - Target directory      [Mandatory]
#                   options         - Optional options
#                                       --Srcdir=path       [default=pkg]
#                                       --Dstdir=abs_path   [internal use]
#                                       --NoRecurse
#                                       --Recurse           [default]
#                                       --Flatten
#                                       --NoFlatten         [default]
#                                       --FilterIn=xx
#                                       --FilterInRE=xx     [default=.*]
#                                       --FilterOut=xx
#                                       --FilterOutRE=xx
#
# Notes:    --FilterIn=xxxx, --FilterOut=xxx
#           xxx is a simple Shell style filter where:
#               * means one or more charters        '*.EXE'
#               ? means a single character          '*.?'
#               [abc] means either a or b or c      'file.[ch]'
#
#           --FilterInRE=xxx, --FilterOutRE=xxx
#           xxx is a Regular Expression. There are harder to use but very
#           powerful. ie '.*\.EXE$'
#
#           The 'In' filters are applied before the 'Out' filters.
#
#           If no 'In' filters are specified then all files will be included.
#
#           The filter rules are applied to the path below the Srcdir, and, for
#           the purposes of the filter the path starts with a '/'.
#
#------------------------------------------------------------------------------
{
    my $src_base_dir;
    my $flatten = 0;
    my $dstDir;
    my $search =  LocateFiles->new(recurse => 1);

    Information("Installing all Prepared pkg files...");
    
    #
    #   Process the arguments and extract parameters and options
    #
    foreach ( @_ )
    {
        if ( m/^--Srcdir=(.*)/ ) {
            Error("installAllDpkgArchivePkgFiles2: Multiple --Srcdir not allowed")
                if ( $src_base_dir );
            $src_base_dir = "$InterfaceDir/$1";
            $src_base_dir =~ s~/\.$~~;
            $src_base_dir =~ s~/$~~;

        } elsif ( /^--Dstdir=(.*)/ ) {
            Error("installAllDpkgArchivePkgFiles2: Multiple target directories not allowed")
                if ( $dstDir );
            $dstDir = $1;

        } elsif ( m/^--NoRecurse/ ) {
            $search->recurse(0);

        } elsif ( m/^--Recurse/ ) {
            $search->recurse(1);

        } elsif ( /^--FilterOut=(.*)/ ) {
            $search->filter_out( $1 );

        } elsif ( /^--FilterOutRE=(.*)/ ) {
            $search->filter_out_re( $1 );

        } elsif ( /^--FilterIn=(.*)/ ) {
            $search->filter_in( $1 );

        } elsif ( /^--FilterInRE=(.*)/ ) {
            $search->filter_in_re( $1 );

        } elsif ( /^--Flatten/ ) {
            $flatten = 1;

        } elsif ( /^--NoFlatten/ ) {
            $flatten = 0;

        } elsif ( m/^--/ ) {
            Error("installAllDpkgArchivePkgFiles2: Unknown option: $_")

        } else {
            Error("installAllDpkgArchivePkgFiles2: Multiple target directories not allowed")
                if ( $dstDir );

            #   Convert the symbolic target directory name into a real path
            
            $dstDir = getTargetDstDirValue($_, "A");
        }
    }

    #
    #   Ensure that we have a valid source directory
    #   Data taken from the 'pkg' directory unless otherwise specified by the user
    #
    $src_base_dir = $DpkgPkgDir unless $src_base_dir;
    Error("installAllDpkgArchivePkgFiles2: Package directory not found: $src_base_dir")
        unless ( -d $src_base_dir );

    #
    #   Ensure that the user has specified a target directory
    #
    Error("installAllDpkgArchivePkgFiles2: No target directories specified")
        unless ( $dstDir );

    #
    #   Build up a list of files to copy
    #   Creating a list allows:
    #       Simplified coding
    #       Flattening and testing of the flattening
    #
    my @elements = $search->search( $src_base_dir);

    #
    #   Perform the file copy
    #   This copy will NOT create empty directories, but it will create needed
    #   directories on the fly.
    #
    foreach  my $sfile ( @elements )
    {

        #
        #   Split into directory and file as we may need to make the directory
        #   since the copy operation will not
        #
        my $dir;                                # Target directory
        my $tfile;                              # Target path
       (my $fname = $sfile )=~ s~^.*/+~~;       # Filename(only)

        unless ( $flatten )
        {
            $sfile =~ m~^(.*/)~;
            $dir = "$dstDir/$1";
            $tfile = $sfile;
        }
        else
        {
            $dir = $dstDir;
            $tfile = $fname;
        }

        #
        #   Ensure the target directory is present
        #
        make_directory ( $dir, 0775 );

        #
        #   Copy the file
        #   Ensure that the target file does not already exist
        #   This is most likely to occur when flattening the directory structure
        #
        my $m_sfile = "$src_base_dir$sfile";
        my $m_tfile = "$dstDir/$tfile";

        if ( -f $m_tfile  )
        {
            Error("Failed to copy file [$m_sfile] to [$m_tfile]: File already exists");
        }

        if( File::Copy::copy("$m_sfile", "$m_tfile") )
        {
            Verbose("Copied [$fname] to [$m_tfile] ...");
        }
        else
        {
            Error("Failed to copy file [$m_sfile] to [$m_tfile]: $!");
        }
    }

    return 1;
}

#------------------------------------------------------------------------------
sub installDpkgArchivePkgRaw
#
# Description:
#       This sub-routine is used to install all pkg files from the named package
#       in dpkg_archive into the defined install area.
#
#       If it has any problems it will log an error and stop processing.
#
# Inputs          : targetTag       - Target directory      [Mandatory]
#                   package         - Source Package        [Mandatory]
#                   options         - Optional options
#                                       --NoRecurse
#                                       --Recurse           [default]
#                                       --Flatten
#                                       --NoFlatten         [default]
#                                       --FilterIn=xx
#                                       --FilterInRE=xx     [default=.*]
#                                       --FilterOut=xx
#                                       --FilterOutRE=xx
#                                       --Warn              [ default]
#                                       --NoWarn
#
# Notes:    --FilterIn=xxxx, --FilterOut=xxx
#           xxx is a simple Shell style filter where:
#               * means one or more charters        '*.EXE'
#               ? means a single character          '*.?'
#               [abc] means either a or b or c      'file.[ch]'
#
#           --FilterInRE=xxx, --FilterOutRE=xxx
#           xxx is a Regular Expression. There are harder to use but very
#           powerful. ie '.*\.EXE$'
#
#           The 'In' filters are applied before the 'Out' filters.
#
#           If no 'In' filters are specified then all files will be included.
#
#           The filter rules are applied to the path below the Srcdir, and, for
#           the purposes of the filter the path starts with a '/'.
#
#
#       --NoWarn
#           Supresses the warning message generated if no files are transferred
#
#------------------------------------------------------------------------------
{
    my $flatten = 0;
    my $dstDir;
    my @args;
    my $src_base_dir;
    my $warning = 1;
    my $search =  LocateFiles->new(recurse => 1);
    
    #
    #   Process the arguments and extract parameters and options
    #
    foreach ( @_ )
    {
        if ( m/^--NoRecurse/ ) {
            $search->recurse(0);

        } elsif ( m/^--Recurse/ ) {
            $search->recurse(1);

        } elsif ( /^--FilterOut=(.*)/ ) {
            $search->filter_out( $1 );

        } elsif ( /^--FilterOutRE=(.*)/ ) {
            $search->filter_out_re( $1 );

        } elsif ( /^--FilterIn=(.*)/ ) {
            $search->filter_in( $1 );

        } elsif ( /^--FilterInRE=(.*)/ ) {
            $search->filter_in_re( $1 );

        } elsif ( /^--Flatten/ ) {
            $flatten = 1;

        } elsif ( /^--NoFlatten/ ) {
            $flatten = 0;

        } elsif ( /^--NoWarn/ ) {
            $warning = 0;

        } elsif ( /^--Warn/ ) {
            $warning = 1;

        } elsif ( m/^--/ ) {
            Error("installDpkgArchivePkgRaw: Unknown option: $_")

        } else {
            push @args, $_;

        }
    }

    #
    #   Have removed all the options
    #   Must have two parameters left
    #
    if ( $#args != 1 )
    {
        Error("Incorrect number of params passed to installDpkgArchivePkgRaw() function.",
              "Check deploy config.");
    }
    
    my ( $dstDirTag, $pkgName ) = @args;

    #
    #   Ensure that the user has specified a target directory
    #   Convert the symbolic target directory to a real path
    #
    Error("installDpkgArchivePkgRaw: No target directories specified")
        unless ( $dstDirTag );
    $dstDir = getTargetDstDirValue($dstDirTag, "A");

    #
    #   Convert the package name into a real path name to the package as
    #   held in dpkg_archive. Do not use the copy in the 'interface' directory
    #
    $src_base_dir = LocatePackageBase ( "installDpkgArchivePkgRaw", $pkgName );

    #
    #   Build up a list of files to copy
    #   Creating a list allows:
    #       Simplified coding
    #       Flattening and testing of the flattening
    #
    my @elements = $search->search( $src_base_dir );
    Information("Installing Raw Pkg files: $pkgName") if @elements;

    #
    #   Perform the file copy
    #   This copy will NOT create empty directories, but it will create needed
    #   directories on the fly.
    #
    foreach  my $sfile ( @elements )
    {

        #
        #   Split into directory and file as we may need to make the directory
        #   since the copy operation will not
        #
        my $dir;                                # Target directory
        my $tfile;                              # Target path
       (my $fname = $sfile )=~ s~^.*/+~~;       # Filename(only)

        unless ( $flatten )
        {
            $sfile =~ m~^(.*/)~;
            $dir = "$dstDir/$1";
            $tfile = $sfile;
        }
        else
        {
            $dir = $dstDir;
            $tfile = $fname;
        }

        #
        #   Ensure the target directory is present
        #
        make_directory ( $dir, 0775 );

        #
        #   Copy the file
        #   Ensure that the target file does not already exist
        #   This is most likely to occur when flattening the directory structure
        #
        my $m_sfile = "$src_base_dir$sfile";
        my $m_tfile = "$dstDir/$tfile";

        if ( -f $m_tfile  )
        {
            Error("Failed to copy file [$m_sfile] to [$m_tfile]: File already exists");
        }

        if( File::Copy::copy("$m_sfile", "$m_tfile") )
        {
            Verbose("Copied [$fname] to [$m_tfile] ...");
        }
        else
        {
            Error("Failed to copy file [$m_sfile] to [$m_tfile]: $!");
        }
    }

    #
    #   Return the number of files transferred
    #
    my $nfiles = $#elements + 1;
    Warning("Installing Raw Pkg files: $pkgName - No files transferred") if ( $warning && ! $nfiles ) ;

    return $nfiles;
}


#------------------------------------------------------------------------------
sub installAllDpkgArchiveDevcdFiles
#
# Description:
#       This sub-routine is used to install all devcd files from the
#       dpkg_archive into the defined install area.
#
#       It assumes based on the build type where the src files will be located.
#
#       If it has any problems it will log an error and stop processing.
#
#       Source directory: $DpkgDevcdDir       (interface/devcd)
#       Target directory: Symbolic Directory
#
# Inputs: None
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 1 )
    {
        Error("Incorrect number of params passed to " .
              "installAllDpkgArchiveDevcdFiles() function. ",
              "Check deploy config.");
    }

    Information("Installing all Prepared Day 0 devcd files...");


    my ($targetTag) = @_;
    
    # lets check to see if the target tag exists
    # if does not the process with log an error.
    #
    my ($targetValue) = getTargetDstDirValue($targetTag, "R");


    # ok we have a valid dst value we now need to get a hold of all the 
    # lib scripts files.
    #
    if ( "$MachType" eq "win32" || "$MachType" eq "WinCE" )
    {
        $TmpGlobalVariable = $targetValue; 
        File::Find::find( \&pkgFindDevcd, "$DpkgDevcdDir");
    }
    else
    {
        my ($i);
        my(@FindRes) = `find $DpkgDevcdDir -follow`;
        my ($m_sfile);
        my ($tmp_DstDir) = "$PkgBaseDir/$targetValue";
        my ($tmp_SrcDir) = "$DpkgDevcdDir";
        foreach $i (@FindRes)
        {

            chomp($i);
            my($base)= File::Basename::basename($i);

            if ( $base eq "devcd" )
            {
                next;
            }

            my ($tmp_dItem) = $i;
            $tmp_dItem =~ s/$tmp_SrcDir/$tmp_DstDir/;

            if ( -d $i )
            {
                make_directory ( $tmp_dItem, 0775 );
            }
            else
            {
                if(File::Copy::copy( $i , $tmp_dItem ))
                {
                    Verbose("Copied [$base] to [$tmp_dItem] ...");
                }
                else
                {
                    Error("Failed to copy pkg file [$tmp_dItem] to [$i]: $!");
                }
            }
        }
    }

    return 1;
}


#------------------------------------------------------------------------------
sub pkgFindDevcd
#
#    Description:
#        This subroutine is used to locate all associated devcd files in 
#        a pre-defined dpkg_archive.
#
#   Trick: Will not copy a file/directory called 'devcd'
#          Not too sure why. May be an attempt to prevent empty devcd directories
#          If you know better, then correct this comment.
#------------------------------------------------------------------------------
{
    my($item)= "$File::Find::name";
    my($base)= File::Basename::basename($item);
   
    if ( $base eq "devcd" )
    {
        return 1;
    }

    my ($tmp_dItem) = $item;
    my ($tmp_DstDir) = "$PkgBaseDir/$TmpGlobalVariable";
    my ($tmp_SrcDir) = "$DpkgDevcdDir";
    $tmp_dItem =~ s/$tmp_SrcDir/$tmp_DstDir/;

    # we need to determine what type of item we are dealing with file we are dealing with
    if ( -d "$item")
    {
        make_directory( $tmp_dItem, 0775 );
    }
    else
    {
        if(File::Copy::copy("$item", "$tmp_dItem"))
        {
            Verbose("Copied [$base] to [$tmp_dItem] ...");
        }
        else
        {
            Error("Failed to copy pkg file [$tmp_dItem] to [$item]: $!"); 
        }
    }
}

#------------------------------------------------------------------------------
sub installAllDpkgArchiveFiles
#
# Description:
#       This sub-routine is used to install all files from the
#       dpkg_archive into the defined install area.
#
#       It assumes based on the build type where the src files will be located.
#
#       If it has any problems it will log an error and stop processing.
#
# Inputs:   $targetType         - Internal tag to specify source file
#           $targetTag          - Users tag for destination
#
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 2 )
    {
        Error("Incorrect number of params passed to " .
              "installAllDpkgArchiveFiles() function. ",
              "Check deploy config.");
    }

    my ($targetType, $targetTag) = @_;

    # lets check to see if the target tag exists
    # if does not the process with log an error.
    #
    my $targetValue;
    if ( $targetTag eq "--NoTag" )
    {
        $targetValue = "$PkgBaseDir/$TargetBaseDir";
    }
    else
    {
       $targetValue = getTargetDstDirValue($targetTag, "A");
    }

    # ok we have a valid dst value we now need to get a hold of all the 
    # lib scripts files.
    #
    local *DIR;
    my $src_dir;

    if    ( "$targetType" eq "jar" )        { $src_dir = $DpkgJarDir; }
    elsif ( "$targetType" eq "sar" )        { $src_dir = $DpkgSarDir; }
    elsif ( "$targetType" eq "include" )    { $src_dir = $DpkgIncludeDir; }
    elsif ( "$targetType" eq "war" )        { $src_dir = $DpkgWarDir; }
    elsif ( "$targetType" eq "infofiles" )  { $src_dir = $DpkgInfoFilesDir; }
    elsif ( "$targetType" eq "sql" )        { $src_dir = $DpkgSqlDir; }
    elsif ( "$targetType" eq "etc" )        { $src_dir = $DpkgEtcDir; }
    elsif ( "$targetType" eq "scripts" )    { $src_dir = $DpkgScriptsDir; }
    elsif ( "$targetType" eq "rox" )        { $src_dir = $DpkgRoxDir; }
    elsif ( "$targetType" eq "rpt" )        { $src_dir = $DpkgRptDir; }
    elsif ( "$targetType" eq "doc" )        { $src_dir = $DpkgDocDir; }
    elsif ( "$targetType" eq "jsp" )        { $src_dir = $DpkgJspDir; }
#    elsif ( "$targetType" eq "achtml" )     { $src_dir = $DpkgAcHtmlDir; }
    else  {
        Error("installAllDpkgArchiveFiles() passed unknown target type [$targetType].");
    }

    opendir(DIR, $src_dir) or
            Error("Can't opendir $src_dir: $!");


    # lets process what we have found
    #
    my ($file);
    while (defined($file = readdir(DIR))) 
    {
        if ( $file !~ /^.$/  && 
             $file !~ /^..$/ ) 
        {
            my ($m_fLoc) = "$src_dir/$file";

            if(File::Copy::copy("$m_fLoc", "$targetValue"))
            {
                Verbose("Copied [$targetType] item [$file] to [$targetValue] ...");
            }
            else
            {
                Error("Failed to copy [$targetType] item [$m_fLoc]: $!"); 
            }
        }
    }

    closedir(DIR);
    return 1;
}


#------------------------------------------------------------------------------
sub installAllDpkgArchiveAcHtmlFiles
#
# Description:
#       This sub-routine is used to install all achtml files from the
#       dpkg_archive into the defined install area.
#
#       It assumes based on the build type where the src files will be located.
#
#       If it has any problems it will log an error and stop processing.
#
#
# Ugly trick:
#       This function tags a $$targetType argument which is used in constructing
#       the source directory path. ie: InterfaceDir/achtml/$targetType
#
#       Could provide as an option to installAllDpkgArchiveFiles and re-use that
#       function
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 2 )
    {
        Error("Incorrect number of params passed to " .
              "installAllDpkgArchiveAcHtmlFiles() function. ",
              "Check deploy config.");
    }
    my ($targetType, $targetTag) = @_;

    # lets check to see if the target tag exists
    # if does not the process with log an error.
    #
    my ($targetValue) = getTargetDstDirValue($targetTag, "A");

    # lets check to see if the source type dir actually exists
    #
    my($m_sDirLoc)  = "$DpkgAcHtmlDir/$targetType";
    if( ! -d "$m_sDirLoc" )
    {
        Error("Failed to locate [$targetType] AcHtml dir [$m_sDirLoc].");
    }

    # know everything exists so lets do the biz.
    #
    # now we need to copy all the files.
    #
    local *DIR;
    opendir(DIR, $m_sDirLoc) or 
        Error("Can't opendir $m_sDirLoc: $!");

    my ($m_fLoc) = "";
    my ($file) = "";
    while (defined($file = readdir(DIR)))
    {
        if ( $file !~ /^.$/  &&
             $file !~ /^..$/ )
        {
            $m_fLoc = "$m_sDirLoc/$file";
            if(File::Copy::copy("$m_fLoc", "$targetValue"))
            {
                Verbose("Copied AcHtml [$targetType] item [$file] to [$targetValue] ...");
            }
            else
            {
                Error("Failed to copy AcHtml [$targetType] item [$m_fLoc]: $!");
            }
        }
    }

    closedir(DIR);
    return 1;
}


#------------------------------------------------------------------------------
sub installAllDpkgArchiveInfoFilesFiles
#
# Description:
#       This sub-routine is used to install all infofiles files from the
#       dpkg_archive into the defined install area.
#
#       It assumes based on the build type where the src files will be located.
#
#       If it has any problems it will log an error and stop processing.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 1 )
    {
        Error("Incorrect number of params passed to " .
              "installAllDpkgArchiveInfoFilesFiles() function. ",
              "Check deploy config.");
    }

    my ($targetTag) = @_;
    
    # lets check to see if the target tag exists
    # if does not the process with log an error.
    #
    my ($targetValue) = getTargetDstDirValue($targetTag, "A");

       
    # for now lets call the generic funtion to move all items
    # in the associated dpkg_archive dir.
    #
    installAllDpkgArchiveFiles("infofiles", $targetTag);
    
    return 1;
}



#------------------------------------------------------------------------------
sub installAllDpkgArchiveSqlFiles
#
# Description:
#       This sub-routine is used to install all sql files from the
#       dpkg_archive into the defined install area.
#
#       It assumes based on the build type where the src files will be located.
#
#       If it has any problems it will log an error and stop processing.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 1 )
    {
        Error("Incorrect number of params passed to " .
              "installAllDpkgArchiveSqlFiles() function. ",
              "Check deploy config.");
    }

    my ($targetTag) = @_;
    
    # lets check to see if the target tag exists
    # if does not the process with log an error.
    #
    my ($targetValue) = getTargetDstDirValue($targetTag, "A");

       
    # for now lets call the generic funtion to move all items
    # in the associated dpkg_archive dir.
    #
    installAllDpkgArchiveFiles("sql", $targetTag);
    
    return 1;
}


#------------------------------------------------------------------------------
sub installAllDpkgArchiveWarFiles
#
# Description:
#       This sub-routine is used to install all war files from the
#       dpkg_archive into the defined install area.
#
#       It assumes based on the build type where the src files will be located.
#
#       If it has any problems it will log an error and stop processing.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 1 )
    {
        Error("Incorrect number of params passed to " .
              "installAllDpkgArchiveWarFiles() function. " ,
              "Check deploy config.");
    }

    my ($targetTag) = @_;
    
    # lets check to see if the target tag exists
    # if does not the process with log an error.
    #
    my ($targetValue) = getTargetDstDirValue($targetTag, "A");

       
    # for now lets call the generic funtion to move all items
    # in the associated dpkg_archive dir.
    #
    installAllDpkgArchiveFiles("war", $targetTag);
    
    return 1;
}


#------------------------------------------------------------------------------
sub installAllDpkgArchiveJarFiles
#
# Description:
#       This sub-routine is used to install all jar files from the
#       dpkg_archive into the defined install area.
#
#       It assumes based on the build type where the src files will be located.
#
#       If it has any problems it will log an error and stop processing.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 1 )
    {
        Error("Incorrect number of params passed to " .
              "installAllDpkgArchiveJarFiles() function. " ,
              "Check deploy config.");
    }

    my ($targetTag) = @_;
    
    # lets check to see if the target tag exists
    # if does not the process with log an error.
    #
    my ($targetValue) = getTargetDstDirValue($targetTag, "A");

       
    # for now lets call the generic funtion to move all items
    # in the associated dpkg_archive dir.
    #
    installAllDpkgArchiveFiles("jar", $targetTag);
    
    return 1;
}


#------------------------------------------------------------------------------
sub installAllDpkgArchiveEtcFiles
#
# Description:
#       This sub-routine is used to install all etc files from the
#       dpkg_archive into the defined install area.
#
#       It assumes based on the build type where the src files will be located.
#
#       If it has any problems it will log an error and stop processing.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 1 )
    {
        Error("Incorrect number of params passed to " .
              "installAllDpkgArchiveEtcFiles() function. " ,
              "Check deploy config.");
    }

    my ($targetTag) = @_;
    
    # lets check to see if the target tag exists
    # if does not the process with log an error.
    #
    my ($targetValue) = getTargetDstDirValue($targetTag, "A");

       
    # for now lets call the generic funtion to move all items
    # in the associated dpkg_archive dir.
    #
    installAllDpkgArchiveFiles("etc", $targetTag);
    
    return 1;
}


#------------------------------------------------------------------------------
sub installAllDpkgArchiveScriptsFiles
#
# Description:
#       This sub-routine is used to install all scripts files from the
#       dpkg_archive into the defined install area.
#
#       It assumes based on the build type where the src files will be located.
#
#       If it has any problems it will log an error and stop processing.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 1 )
    {
        Error("Incorrect number of params passed to " .
              "installAllDpkgArchiveScriptsFiles() function. " ,
              "Check deploy config.");
    }

    my ($targetTag) = @_;
    
    # lets check to see if the target tag exists
    # if does not the process with log an error.
    #
    my ($targetValue) = getTargetDstDirValue($targetTag, "A");

       
    # for now lets call the generic funtion to move all items
    # in the associated dpkg_archive dir.
    #
    installAllDpkgArchiveFiles("scripts", $targetTag);
    
    return 1;
}


#------------------------------------------------------------------------------
sub installAllDpkgArchiveIncludeFiles
#
# Description:
#       This sub-routine is used to install all include files from the
#       dpkg_archive into the defined install area.
#
#       It assumes based on the build type where the src files will be located.
#
#       If it has any problems it will log an error and stop processing.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 1 )
    {
        Error("Incorrect number of params passed to " .
              "installAllDpkgArchiveIncludeFiles() function. " ,
              "Check deploy config.");
    }

    my ($targetTag) = @_;
    
    # lets check to see if the target tag exists
    # if does not the process with log an error.
    #
    my ($targetValue) = getTargetDstDirValue($targetTag, "A");

       
    # for now lets call the generic funtion to move all items
    # in the associated dpkg_archive dir.
    #
    installAllDpkgArchiveFiles("include", $targetTag);
    
    return 1;
}


#------------------------------------------------------------------------------
sub installAllDpkgArchiveDocFiles
#
# Description:
#       This sub-routine is used to install all include files from the
#       dpkg_archive into the defined install area.
#
#       It assumes based on the build type where the src files will be located.
#
#       If it has any problems it will log an error and stop processing.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 1 )
    {
        Error("Incorrect number of params passed to " .
              "installAllDpkgArchiveIncludeFiles() function. " ,
              "Check deploy config.");
    }

    my ($targetTag) = @_;
    
    # lets check to see if the target tag exists
    # if does not the process with log an error.
    #
    my ($targetValue) = getTargetDstDirValue($targetTag, "A");

       
    # for now lets call the generic funtion to move all items
    # in the associated dpkg_archive dir.
    #
    installAllDpkgArchiveFiles("doc", $targetTag);
    
    return 1;
}

#------------------------------------------------------------------------------
sub installAllDpkgArchiveJspFiles
#
# Description:
#       This sub-routine is used to install all jsp associated files from the
#       dpkg_archive into the defined install area.
#
#       It assumes based on the build type where the src files will be located.
#
#       If it has any problems it will log an error and stop processing.
#
#   Source directory: $DpkgJspDir
#   Target directory: $TargetBaseDir
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 0 )
    {
        Error("Incorrect number of params passed to " .
              "installAllDpkgArchiveJspFiles() function. " ,
              "Check deploy config.");
    }

    return installAllDpkgArchiveFiles ('jsp', '--NoTag');
}


#------------------------------------------------------------------------------
sub installDpkgArchiveFile
#
# Description:
#       This sub-routine is used to install a file of a particular type
#       from the dpkg_archive into the supplied install dir. 
#
#       It assumes based on the build type where the file will be located.
#
#       If it fails to find the file it will report an error and terminates
#       processing.
#
# Inputs:   $targetType         - Type of target ( provides source directory)
#           $sfile              - Source file name, within source directory
#           $targetTag          - Symbolic target dir
#
#
# Note: This function will copy a single file
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 3 )
    {
        Error("Incorrect number of params passed to " .
              "installDpkgArchiveFile() function. " ,
              "Check deploy config.");
    }

    my ($targetType, $sfile, $targetTag) = @_;

    # lets check to see if the target tag exists
    # if does not the process with log an error.
    #
    my ($targetValue) = getTargetDstDirValue($targetTag, "A");


    # lets define the absolute location of the file
    #
    my ($m_dstFileLocation) = "$targetValue/$sfile";
    my ($m_srcFileLocation) = "";
    
    if    ( "$targetType" eq "jar" )        { $m_srcFileLocation = "$DpkgJarDir/$sfile"; }
    elsif ( "$targetType" eq "sar" )        { $m_srcFileLocation = "$DpkgSarDir/$sfile"; }
    elsif ( "$targetType" eq "include" )    { $m_srcFileLocation = "$DpkgIncludeDir/$sfile"; }
    elsif ( "$targetType" eq "war" )        { $m_srcFileLocation = "$DpkgWarDir/$sfile"; }
    elsif ( "$targetType" eq "infofiles" )  { $m_srcFileLocation = "$DpkgInfoFilesDir/$sfile"; }
    elsif ( "$targetType" eq "sql" )        { $m_srcFileLocation = "$DpkgSqlDir/$sfile"; }
    elsif ( "$targetType" eq "etc" )        { $m_srcFileLocation = "$DpkgEtcDir/$sfile"; }
    elsif ( "$targetType" eq "scripts" )    { $m_srcFileLocation = "$DpkgScriptsDir/$sfile";  }
    elsif ( "$targetType" eq "rox" )        { $m_srcFileLocation = "$DpkgRoxDir/$sfile";  }
    elsif ( "$targetType" eq "dat" )        { $m_srcFileLocation = "$DpkgDatDir/$sfile";  }
    elsif ( "$targetType" eq "thx" )        { $m_srcFileLocation = "$DpkgThxDir/$sfile";  }
    elsif ( "$targetType" eq "mug" )        { $m_srcFileLocation = "$DpkgMugDir/$sfile";  }
    elsif ( "$targetType" eq "rpt" )        { $m_srcFileLocation = "$DpkgRptDir/$sfile";  }
    elsif ( "$targetType" eq "doc" )        { $m_srcFileLocation = "$DpkgDocDir/$sfile";  }
    else  {
        Error("installDpkgArchiveFile() passed unknown target type [$targetType].");
    }
    
    
    # we will check to see if the file exists.
    #
    if ( -f "$m_srcFileLocation" )
    {
        # now we need to copy the file. 
        if(File::Copy::copy("$m_srcFileLocation", "$m_dstFileLocation"))
        {
            Verbose("Copied [$targetType] item [$sfile] to [$m_dstFileLocation] ...");
        }
        else
        {
            Error("Failed to copy [$targetType] item [$sfile]: $!"); 
        }
    }
    else
    {
        Error("Dpkg_archive [$targetType] item [$sfile] does not exist.");
    }

    return 1;
}


#------------------------------------------------------------------------------
sub installDpkgArchiveAcHtmlFile
#
# Description:
#       This sub-routine is used to install a achtml file from the
#       dpkg_archive into the supplied install dir. 
#
#       It assumes based on the build type where the file will be located.
#
#       If it fails to find the file it will report an error and terminates
#       processing.
#
# Ugly trick:
#       This function tags a $$targetType argument which is used in constructing
#       the source directory path. ie: InterfaceDir/achtml/$targetType
#
#       Could provide as an option to installDpkgArchiveFile and re-use that
#       function
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 3 )
    {
        Error("Incorrect number of params passed to " .
              "installDpkgArchiveAcHtmlFile() function. " ,
              "Check deploy config.");
    }
    my ($targetType, $sfile, $targetTag) = @_;

    # lets check to see if the source type and file actually exist
    #
    my($m_sDirLoc)  = "$DpkgAcHtmlDir/$targetType";
    if( ! -d "$m_sDirLoc" )
    {
        Error("Failed to locate [$targetType] AcHtml dir [$m_sDirLoc].");
    }

    # lets check to see if the file exists
    #
    my($m_sFileLoc) = "$DpkgAcHtmlDir/$targetType/$sfile";
    if( ! -f "$m_sFileLoc" )
    {
        Error("Failed to locate [$targetType] AcHtml file [$m_sFileLoc].");
    }

    # lets check to see if the target tag exists
    # if does not the process with log an error.
    #
    my ($targetValue) = getTargetDstDirValue($targetTag, "A");

    # know everything exists so lets do the biz.
    #
    # now we need to copy the file.
    if(File::Copy::copy("$m_sFileLoc", "$targetValue"))
    {
        Verbose("Copied [$targetType] AcHtml item [$sfile] to [$targetValue] ...");
    }
    else
    {
        Error("Failed to copy [$targetType] AcHtml item [$sfile]: $!");
    }
    
    return 1;
}


#------------------------------------------------------------------------------
sub installDpkgArchiveRptFile
#
# Description:
#       This sub-routine is used to install a rpt file from the
#       dpkg_archive into the supplied install dir. 
#
#       It assumes based on the build type where the file will be located.
#
#       If it fails to find the file it will report an error and terminates
#       processing.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 2 )
    {
        Error("Incorrect number of params passed to " .
              "installDpkgArchiveRptFile() function. " ,
              "Check deploy config.");
    }

    my ($sfile, $targetTag) = @_;

    # lets check to see if the target tag exists
    # if does not the process with log an error.
    #
    my ($targetValue) = getTargetDstDirValue($targetTag, "A");
    
    
    # for now lets call the generic funtion to move all items
    # in the associated dpkg_archive dir.
    #
    installDpkgArchiveFile("rpt", $sfile, $targetTag);

    return 1;
}


#------------------------------------------------------------------------------
sub installDpkgArchiveRoxFile
#
# Description:
#       This sub-routine is used to install a rox file from the
#       dpkg_archive into the supplied install dir. 
#
#       It assumes based on the build type where the file will be located.
#
#       If it fails to find the file it will report an error and terminates
#       processing.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 2 )
    {
        Error("Incorrect number of params passed to " .
              "installDpkgArchiveRoxFile() function. " ,
              "Check deploy config.");
    }

    my ($sfile, $targetTag) = @_;

    # lets check to see if the target tag exists
    # if does not the process with log an error.
    #
    my ($targetValue) = getTargetDstDirValue($targetTag, "A");
    
    
    # for now lets call the generic funtion to move all items
    # in the associated dpkg_archive dir.
    #
    installDpkgArchiveFile("rox", $sfile, $targetTag);

    return 1;
}


#------------------------------------------------------------------------------
sub installDpkgArchiveDatFile
#
# Description:
#       This sub-routine is used to install a dat file from the
#       dpkg_archive into the supplied install dir. 
#
#       It assumes based on the build type where the file will be located.
#
#       If it fails to find the file it will report an error and terminates
#       processing.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 2 )
    {
        Error("Incorrect number of params passed to " .
              "installDpkgArchiveDatFile() function. " ,
              "Check deploy config.");
    }

    my ($sfile, $targetTag) = @_;

    # lets check to see if the target tag exists
    # if does not the process with log an error.
    #
    my ($targetValue) = getTargetDstDirValue($targetTag, "A");
    
    
    # for now lets call the generic funtion to move all items
    # in the associated dpkg_archive dir.
    #
    installDpkgArchiveFile("dat", $sfile, $targetTag);

    return 1;
}


#------------------------------------------------------------------------------
sub installDpkgArchiveThxFile
#
# Description:
#       This sub-routine is used to install a thx file from the
#       dpkg_archive into the supplied install dir. 
#
#       It assumes based on the build type where the file will be located.
#
#       If it fails to find the file it will report an error and terminates
#       processing.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 2 )
    {
        Error("Incorrect number of params passed to " .
              "installDpkgArchiveThxFile() function. " ,
              "Check deploy config.");
    }

    my ($sfile, $targetTag) = @_;

    # lets check to see if the target tag exists
    # if does not the process with log an error.
    #
    my ($targetValue) = getTargetDstDirValue($targetTag, "A");
    
    
    # for now lets call the generic funtion to move all items
    # in the associated dpkg_archive dir.
    #
    installDpkgArchiveFile("thx", $sfile, $targetTag);

    return 1;
}


#------------------------------------------------------------------------------
sub installDpkgArchiveMugFile
#
# Description:
#       This sub-routine is used to install a mug file from the
#       dpkg_archive into the supplied install dir. 
#
#       It assumes based on the build type where the file will be located.
#
#       If it fails to find the file it will report an error and terminates
#       processing.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 2 )
    {
        Error("Incorrect number of params passed to " .
              "installDpkgArchiveMugFile() function. " ,
              "Check deploy config.");
    }

    my ($sfile, $targetTag) = @_;

    # lets check to see if the target tag exists
    # if does not the process with log an error.
    #
    my ($targetValue) = getTargetDstDirValue($targetTag, "A");
    
    
    # for now lets call the generic funtion to move all items
    # in the associated dpkg_archive dir.
    #
    installDpkgArchiveFile("mug", $sfile, $targetTag);

    return 1;
}


#------------------------------------------------------------------------------
sub installDpkgArchiveInfoFilesFile
#
# Description:
#       This sub-routine is used to install a infofiles file from the
#       dpkg_archive into the supplied install dir. 
#
#       It assumes based on the build type where the file will be located.
#
#       If it fails to find the file it will report an error and terminates
#       processing.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 2 )
    {
        Error("Incorrect number of params passed to " .
              "installDpkgArchiveInfoFilesFile() function. " ,
              "Check deploy config.");
    }

    my ($sfile, $targetTag) = @_;

    # lets check to see if the target tag exists
    # if does not the process with log an error.
    #
    my ($targetValue) = getTargetDstDirValue($targetTag, "A");
    
    
    # for now lets call the generic funtion to move all items
    # in the associated dpkg_archive dir.
    #
    installDpkgArchiveFile("infofiles", $sfile, $targetTag);

    return 1;
}


#------------------------------------------------------------------------------
sub installDpkgArchiveSqlFile
#
# Description:
#       This sub-routine is used to install a sql file from the
#       dpkg_archive into the supplied install dir. 
#
#       It assumes based on the build type where the file will be located.
#
#       If it fails to find the file it will report an error and terminates
#       processing.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 2 )
    {
        Error("Incorrect number of params passed to " .
              "installDpkgArchiveSqlFile() function. " ,
              "Check deploy config.");
    }

    my ($sfile, $targetTag) = @_;

    # lets check to see if the target tag exists
    # if does not the process with log an error.
    #
    my ($targetValue) = getTargetDstDirValue($targetTag, "A");
    
    
    # for now lets call the generic funtion to move all items
    # in the associated dpkg_archive dir.
    #
    installDpkgArchiveFile("sql", $sfile, $targetTag);

    return 1;
}


#------------------------------------------------------------------------------
sub installDpkgArchiveWarFile
#
# Description:
#       This sub-routine is used to install a war file from the
#       dpkg_archive into the supplied install dir. 
#
#       It assumes based on the build type where the file will be located.
#
#       If it fails to find the file it will report an error and terminates
#       processing.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 2 )
    {
        Error("Incorrect number of params passed to " .
              "installDpkgArchiveWarFile() function. " ,
              "Check deploy config.");
    }

    my ($sfile, $targetTag) = @_;

    # lets check to see if the target tag exists
    # if does not the process with log an error.
    #
    my ($targetValue) = getTargetDstDirValue($targetTag, "A");
    
    
    # for now lets call the generic funtion to move all items
    # in the associated dpkg_archive dir.
    #
    installDpkgArchiveFile("war", $sfile, $targetTag);

    return 1;
}



#------------------------------------------------------------------------------
sub installDpkgArchiveJarFile
#
# Description:
#       This sub-routine is used to install a jar file from the
#       dpkg_archive into the supplied install dir. 
#
#       It assumes based on the build type where the file will be located.
#
#       If it fails to find the file it will report an error and terminates
#       processing.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 2 )
    {
        Error("Incorrect number of params passed to " .
              "installDpkgArchiveJarFile() function. " ,
              "Check deploy config.");
    }

    my ($sfile, $targetTag) = @_;

    # lets check to see if the target tag exists
    # if does not the process with log an error.
    #
    my ($targetValue) = getTargetDstDirValue($targetTag, "A");
    
    
    # for now lets call the generic funtion to move all items
    # in the associated dpkg_archive dir.
    #
    installDpkgArchiveFile("jar", $sfile, $targetTag);

    return 1;
}



#------------------------------------------------------------------------------
sub installDpkgArchiveSarFile
#
# Description:
#       This sub-routine is used to install a sar file from the
#       dpkg_archive into the supplied install dir. 
#
#       It assumes based on the build type where the file will be located.
#
#       If it fails to find the file it will report an error and terminates
#       processing.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 2 )
    {
        Error("Incorrect number of params passed to " .
              "installDpkgArchiveSarFile() function. " ,
              "Check deploy config.");
    }

    my ($sfile, $targetTag) = @_;

    # lets check to see if the target tag exists
    # if does not the process with log an error.
    #
    my ($targetValue) = getTargetDstDirValue($targetTag, "A");
    
    
    # for now lets call the generic funtion to move all items
    # in the associated dpkg_archive dir.
    #
    installDpkgArchiveFile("sar", $sfile, $targetTag);

    return 1;
}





#------------------------------------------------------------------------------
sub installDpkgArchiveEtcFile
#
# Description:
#       This sub-routine is used to install an etc file from the
#       dpkg_archive into the supplied install dir. 
#
#       It assumes based on the build type where the file will be located.
#
#       If it fails to find the file it will report an error and terminates
#       processing.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 2 )
    {
        Error("Incorrect number of params passed to " .
              "installDpkgArchiveEtcFile() function. " ,
              "Check deploy config.");
    }

    my ($sfile, $targetTag) = @_;

    # lets check to see if the target tag exists
    # if does not the process with log an error.
    #
    my ($targetValue) = getTargetDstDirValue($targetTag, "A");
    
    
    # for now lets call the generic funtion to move all items
    # in the associated dpkg_archive dir.
    #
    installDpkgArchiveFile("etc", $sfile, $targetTag);

    return 1;
}


#------------------------------------------------------------------------------
sub installDpkgArchiveScriptsFile
#
# Description:
#       This sub-routine is used to install a scripts file from the
#       dpkg_archive into the supplied install dir. 
#
#       It assumes based on the build type where the file will be located.
#
#       If it fails to find the file it will report an error and terminates
#       processing.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 2 )
    {
        Error("Incorrect number of params passed to " .
              "installDpkgArchiveScriptsFile() function. " ,
              "Check deploy config.");
    }

   my ($sfile, $targetTag) = @_;

    # lets check to see if the target tag exists
    # if does not the process with log an error.
    #
    my ($targetValue) = getTargetDstDirValue($targetTag, "A");
    
    
    # for now lets call the generic funtion to move all items
    # in the associated dpkg_archive dir.
    #
    installDpkgArchiveFile("scripts", $sfile, $targetTag);

    return 1;
}



#------------------------------------------------------------------------------
sub installDpkgArchiveIncludeFile
#
# Description:
#       This sub-routine is used to install a include file from the
#       dpkg_archive into the supplied install dir. 
#
#       It assumes based on the build type where the file will be located.
#
#       If it fails to find the file it will report an error and terminates
#       processing.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 2 )
    {
        Error("Incorrect number of params passed to " .
              "installDpkgArchiveIncludeFile() function. " ,
              "Check deploy config.");
    }

   my ($sfile, $targetTag) = @_;

    # lets check to see if the target tag exists
    # if does not the process with log an error.
    #
    my ($targetValue) = getTargetDstDirValue($targetTag, "A");
    
    
    # for now lets call the generic funtion to move all items
    # in the associated dpkg_archive dir.
    #
    installDpkgArchiveFile("include", $sfile, $targetTag);

    return 1;
}



#------------------------------------------------------------------------------
sub installDpkgArchiveDocFile
#
# Description:
#       This sub-routine is used to install a include file from the
#       dpkg_archive into the supplied install dir. 
#
#       It assumes based on the build type where the file will be located.
#
#       If it fails to find the file it will report an error and terminates
#       processing.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 2 )
    {
        Error("Incorrect number of params passed to " .
              "installDpkgArchiveDocFile() function. " ,
              "Check deploy config.");
    }

   my ($sfile, $targetTag) = @_;

    # lets check to see if the target tag exists
    # if does not the process with log an error.
    #
    my ($targetValue) = getTargetDstDirValue($targetTag, "A");
    
    
    # for now lets call the generic funtion to move all items
    # in the associated dpkg_archive dir.
    #
    installDpkgArchiveFile("doc", $sfile, $targetTag);

    return 1;
}


#------------------------------------------------------------------------------
sub installDpkgArchiveBinFile
#
# Description:
#       This sub-routine is used to install a binary file from the
#       dpkg_archive into the supplied install dir. 
#
#       It assumes based on the build type where the file will be located.
#
#       If it fails to find the file it will report an error and terminates
#       processing.
#
# Inputs          :     $sfile              - Name of source file
#                                             or a reference to a list of files
#                       $targetTag          - Symbolic name of target
#                       Options             - Optional options
#
# Options:
#                   --SelectFrom=xxxx       - Limits file source selection
#                                             By default all LIB sources are searched.
#                                             The selector should be a Platform, Product
#                                             ,Target or MachineType
#
#
# Returns         :     Nothing of use
#                       Will not return if the file is not found
#
#------------------------------------------------------------------------------
{
    my @args;
    my $select = '_ALL_';

    #
    #   Process parameters and extract options
    #
    foreach  ( @_ )
    {
        if ( m/^--SelectFrom=(.*)/ ) {
            $select = $1;
            Error("installDpkgArchiveBinFile: Selector not known: $_")
                unless ( defined $DpkgLibDirList{$select} );

        } elsif ( m/^--/ ) {
            Warning ("installDpkgArchiveBinFile: Unknown option ignored: $_")

        } else {
            push @args, $_;
        }
    }


    # correct number of parameters?
    my ($fref, $targetTag) = @_;
    if ( $#args != 1 )
    {
        Error("Incorrect number of params passed to " .
              "installDpkgArchiveBinFile() function. " ,
              "Check deploy config.");
    }

    # lets check to see if the target tag exists
    # if does not the process with log an error.
    #
    my ($targetValue) = getTargetDstDirValue($targetTag, "A");

    #
    #   Process the file name
    #   This will either be a scalar name, or a reference to an array of names
    #   If the user has provided an array of names then expand the list
    #
    #   Convert $fref into an reference to a list
    #
    my @one_file;
    unless ( ref ( $fref ) eq 'ARRAY' )
    {
        push @one_file, $fref;
        $fref = \@one_file;
    }

    foreach my $sfile ( @$fref )
    {
    
        if ( "$MachType" eq "win32" )
        {
            # if the item does not have an .exe extention
            # we shall add one for convience.
            #
            if ( $sfile !~ m/\.exe$/  &&
                 $sfile !~ m/\.dll$/ )
            {
                $sfile = $sfile . ".exe";
            }
        }


        my ($i);
        my ($foundFileFlag) = "false";
        my ($m_DpkgBinDir)  = "";
        my ($m_srcFileLocation) = "";
        my ($m_dstFileLocation) = "";
        foreach $i (@{$DpkgBinDirList{$select}})
        {
            $m_DpkgBinDir = "$DpkgBinDir" . "/$i";
            if ( ! -d "$m_DpkgBinDir" )
            {
                Debug("Directory [$m_DpkgBinDir] not found.");
                next;
            }

            # lets define the absolute location of the file
            $m_srcFileLocation = "$m_DpkgBinDir/$sfile";
            $m_dstFileLocation = "$targetValue/$sfile";

            # we will check to see if the file exists.
            #
            if ( -f "$m_srcFileLocation" )
            {
                # now we need to copy the file.
                if(File::Copy::copy("$m_srcFileLocation", "$m_dstFileLocation"))
                {
                    Verbose("Copied Bin [$sfile] to [$m_dstFileLocation] ...");
                    $foundFileFlag = "true";
                 
                    # no need to go further, we have found the file.
                    #
                    last;
                }
                else
                {
                    Error("Failed to copy binary [$sfile]: $!");
                }
            }
            # else we have not found the file yet!
        }

        # if we do not find the file at all we need to inform
        # the user.
        #
        if ( "$foundFileFlag" eq "false" )
        {
            Error("Dpkg_archive bin file [$sfile] does not exist or is not in correct directory structure.");
        }
    }
    
    return 1;
}


#------------------------------------------------------------------------------
sub installDpkgArchiveLibFile
#
# Description:
#       This sub-routine is used to install a binary file from the
#       dpkg_archive into the supplied install location dir.
#
#       It assumes based on the build type where the file will be located.
#
#       If it fails to find the file it will report an error and terminates
#       processing.
#
#       Added optional 3rd parameter & if set to NoLinks then no generic named
#       libs will be created
#
# Inputs          :     $sfile              - Name of source file OR
#                                             A --Filter specification ( below)
#                                             A reference to a list of files OR
#                       $targetTag          - Symbolic name of target
#                       $links              - Optional. 'nolinks' will supress generic named libs
#                       Options             - Optional options
#
# Options:
#                   --NoLink                - same as 3rd arg == nolinks
#                   --Link                  - Default
#                   --SelectFrom=xxxx       - Limits file source selection
#                                             By default all LIB sources are searched.
#                                             The selector should be a Platform, Product
#                                             ,Target or MachineType
#
# SourceFile options:
#                   Source files may be a filter rule which will expand to
#                   one or more files.
#                       --FilterIn=xx
#                       --FilterInRE=xx
#                       --FilterOut=xx
#                       --FilterOutRE=xx
#
#                     Notes:    --FilterIn=xxxx, --FilterOut=xxx
#                               xxx is a simple Shell style filter where:
#                                   * means one or more charters        '*.EXE'
#                                   ? means a single character          '*.?'
#                                   [abc] means either a or b or c      'file.[ch]'
#
#                               --FilterInRE=xxx, --FilterOutRE=xxx
#                               xxx is a Regular Expression. There are harder to use but very
#                               powerful. ie '.*\.EXE$'
#
#                               The 'In' filters are applied before the 'Out' filters.
#
#                               Multiple options may be joined with a comma.
#
# Returns         :     Nothing of use
#                       Will not return if the file is not found
#
#------------------------------------------------------------------------------
{
    my @args;
    my $links = 1;
    my $select = '_ALL_';

    #
    #   Process parameters and extract options
    #
    foreach  ( @_ )
    {
        if ( m/^--NoLink/ ) {
            $links = 0;

        } elsif ( m/^--Link/ ) {
            $links = 1;

        } elsif ( m/^--SelectFrom=(.*)/ ) {
            $select = $1;
            Error("installDpkgArchiveLibFile: Selector not known: $_")
                unless ( defined $DpkgLibDirList{$select} );

        } elsif ( m/^--Filter.*=/ ) {
            push @args, $_;

        } elsif ( m/^--/ ) {
            Warning ("installDpkgArchiveLibFile: Unknown option ignored: $_")

        } else {
            push @args, $_;
        }
    }

    #
    #   Handle the optional 3rd argument
    #
    if ( $args[2] )
    {
        $links = $args[2] !~ m/nolink/i;
        delete $args[2];
    }

    # correct number of parameters?
    my ($fref, $targetTag) = @_;
    if ( $#args != 1 )
    {
        Error("Incorrect number of params passed to " .
              "installDpkgArchiveLibFile() function. " ,
              "Check deploy config.");
    }

    #
    # Check to see if the target tag exists
    # If does not the process with log an error.
    #
    my ($targetValue) = getTargetDstDirValue($targetTag, "A");

    #
    #   Process the file name
    #   This will either be a scalar name, or a reference to an array of names
    #   If the user has provided an array of names then expand the list
    #
    #   Convert $fref into an reference to a list
    #
    my @one_file;
    unless ( ref ( $fref ) eq 'ARRAY' )
    {
        push @one_file, $fref;
        $fref = \@one_file;
    }

    #
    #   If the source file contains a pattern, then expand the pattern
    #   This may result in multiple files.
    #   Note: Allow for a single entry of the form
    #           --Filterin=xxx,---FilterOut=yyy
    #
    my $search =  LocateFiles->new(recurse => 0);
    my @flist;
    foreach my $element ( @$fref )
    {
        foreach  ( split /,/ , $element )
        {
            if ( /^--FilterOut=(.*)/ ) {
                $search->filter_out( $1 );

            } elsif ( /^--FilterOutRE=(.*)/ ) {
                $search->filter_out_re( $1 );

            } elsif ( /^--FilterIn=(.*)/ ) {
                $search->filter_in( $1 );

            } elsif ( /^--FilterInRE=(.*)/ ) {
                $search->filter_in_re( $1 );

            } elsif ( m/^--/ ) {
                Warning( "installDpkgArchiveLibFile: Unknown Filter option ignored: $_");

            } else {
                push @flist, $_;
            }
        }
    }

    #
    #   If any patterns have been found, then expand them
    #
    if ( $search->has_filter() )
    {
        foreach my $i (@{$DpkgLibDirList{$select}})
        {
            my @elements = $search->search( "$DpkgLibDir/$i" );

            #
            #   Clean off any leading / from each filename then add to a list
            #   Remove any duplicates that were found
            #
            map { $_ =~ s~^/~~ } @elements;
            UniquePush \@flist, @elements;
        }
    }


    #
    #   Process each file
    #
    foreach my $sfile ( @flist )
    {

        # we exclude .dll files if this is a sparc build
        #
        if ( "$MachType" eq "sparc"  &&
             $sfile =~ m/\.dll/
           )
        {
            Verbose("Excluding item [$sfile] from build, as we do not deliver dlls for this machine type [$MachType].");
            return 1;
        }

        # we exclude .so files if this is a win32 build
        #
        if ( "$MachType" eq "win32"  &&
             $sfile =~ m/\.so/
           )
        {
            Verbose("Excluding item [$sfile] from build, as we do not deliver sosss for this machine type [$MachType].");
            return 1;
        }

        my ($libName) = $sfile;
        if ( "$MachType" eq "sparc" )
        {
            $libName =~ s/\.so.*$//;
        }

        # lets define the absolute location of the file
        my ($m_srcFileLocation) = "";
        my ($m_dstFileLocation) = "";
        my ($m_DpkgLibDir) = "";

        my ($i);
        my ($j);
        my ($count);
        my ($foundFileFlag) = "false";
        my ($ExcludedFlag) = "false";

        #
        #   Search all the 'lib' locations, or a specified subset
        #
        foreach $i (@{$DpkgLibDirList{$select}})
        {

            $m_DpkgLibDir = "$DpkgLibDir" . "/$i";
            if ( ! -d "$m_DpkgLibDir" )
            {
                Debug("Directory [$m_DpkgLibDir] not found.");
                next;
            }


            $m_srcFileLocation = "$m_DpkgLibDir/$sfile";
            $m_dstFileLocation = "$targetValue/$sfile";


            # we only want debug items in a debug build
            #
            if(excludeItemFromBuild($sfile))
            {
                Verbose("Excluding item [$sfile] from build as not compatible with build type [$BuildType].");
                $ExcludedFlag = "true";
            }
            else
            {
                # we need to ensure that only a single version/entry of the lib exists in the lib list
                #
                $count = 1;
                foreach $j (@LibCheckList)
                {
                    if ( $j =~ m/^$libName$/ )
                    {
                        $count++;
                    }
        
                    if ( $count > 1 )
                    {
                        Error("Detected multiple references of lib [$libName] in lib list, check item [$sfile].");
                    }
                }

                # we will check to see if the file exists.
                #
                if ( -f "$m_srcFileLocation" )
                {
                    # now we need to copy the file.

                    # we also want to create a generically named copy
                    # of the library. ie:
                    #       libraryP.nn.nn.nn.dll -> library.dll, libraryP.dll
                    #       libraryP.so.nn.nn.nn  -> library.so, libraryP.so
                    #
                    my ($gName)    = $sfile;
                    my ($nVerName) = $sfile;
                    $gName = removeBuildTypeFromItemName($sfile);
                    $gName = removeVersionNumberFromItemName($gName);
                    $nVerName = removeVersionNumberFromItemName($sfile);

                    if(File::Copy::copy("$m_srcFileLocation", "$m_dstFileLocation"))
                    {
                        Verbose("Copied Lib [$sfile] to [$m_dstFileLocation] ...");
                        $foundFileFlag = "true";

                        if ( $links && ( "x$PkgPatchID" eq "x" || "$MachType" eq "win32") )
                        {
                            # normal build or if we are building win32 we want generic names

                            # we want to create a copy of our target using
                            # the generic name
                            if ( $sfile ne $nVerName )
                            {
                                createGenericCopy("$sfile", "$m_srcFileLocation", "$nVerName", "$targetValue");
                            }
                            if ( $sfile ne $gName )
                            {
                                createGenericCopy("$sfile", "$m_srcFileLocation", "$gName",    "$targetValue");
                            }
                        }


                        # lets add this lib to our check list for next time.
                        #
                        push @LibCheckList, $libName;

                        # no need to go further, implies we found the file!
                        #
                        last;
                    }
                    else
                    {
                        # here found the file but we had some trouble
                        #
                        Error("Failed to copy lib [$m_srcFileLocation]: $!");
                    }

                }
                # else have not found the file yet!
            }
        }

        # if we do not find the file at all we need to inform
        # the user.
        #
        if ( "$foundFileFlag" eq "false" && $ExcludedFlag eq "false" )
        {
            Error("Dpkg_archive lib file [$sfile] does not exist or is not in correct directory structure.");
        }
    }

    return 1;
}


#------------------------------------------------------------------------------
sub installPkgAddConfigFile
#
# Description:
#       This sub-routine is used to install a package config file from a supplied
#       source location to a predefined destination location that is based on
#       the build type.
#
#       The sub routine also updates to the prototype file with an appropriate
#       entry for the associated file.
# Inputs:
#       sDirTag                 - Source directory tag
#                                 Or --Package=name,subdir
#                                 Or --Interface=subdir
#       sfile                   - Source File Name [Mandatory]
#       tfile                   - Not sure. Used in the prototype file.
#                                 Suggest using the same name as sfile
#
#       If it has any problems it will log an error and stop processing.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 3 )
    {
        Error("Incorrect number of params passed to " .
              "installPkgAddConfigFile() function. " ,
              "Check deploy config.");
    }

    # lets just check to see if we can execute this function on
    # this machine.
    #
    if ( "$MachType" ne "sparc" )
    {
        Verbose("installPkgAddConfigFile() not supported on this machine type.");
        return 1;
    }


    my ($sDirTag, $sfile, $tfile) = @_;


    # we must have a filename.
    #
    unless ( $sfile )
    {
        Error("Source filename not supplied. Check deploy config.");
    }

    # lets check to see if the local src dir tag exists
    # if does not the process with log an error.
    #
    my ($sDirValue) = getLocalDirValue("$sDirTag", "A");


    # lets check to see if the source file exists
    #
    if ( ! -f "$sDirValue/$sfile" )
    {
        Error("Failed to find local source file [$sDirValue/$sfile].");
    }

    if ( ! -f "$ProtoTypeFile" )
    {
        Error("Prototype file [$ProtoTypeFile] does not exist.",
              "Ensure createPrototypeFile() function has been called before executing installPkgAddConfigFile() function.",
              "Check deploy config.");
    }

    
    # lets determine which prototype file we are going to
    # use
    my ($dFileName);
    $dFileName     = "$PkgBaseDir/$sfile";

    # lets copy the file
    #
    if(File::Copy::copy("$sDirValue/$sfile", "$dFileName"))
    {
        Verbose("Copied [$sfile] to [$dFileName] ...");
    }
    else
    {
        Error("Failed to copy local source file [$sDirValue/$sfile]: $!"); 
    }

   
    # now we need to update the prototype file
    #
    local *FILE;
    open ( FILE, ">> $ProtoTypeFile") or
        Error("Failed to open file [$ProtoTypeFile].");
    printf FILE ("i $tfile=$sfile\n");
    close (FILE);


    return 1;
}


#------------------------------------------------------------------------------
sub installPkgAddSystemClassFile
#
# Description:
#       This sub-routine is used to install a package system class file from a supplied
#       source location to a predefined destination location the class type is also 
#       supplied and must be sed, awk, build or preserve
#
#       The sub routine also updates to the prototype file with an appropriate
#       entry for the associated file.
#
#       If it has any problems it will log an error and stop processing.
#
# Inputs:
#       sDirTag                 - Source directory tag
#                                 Or --Package=name,subdir
#                                 Or --Interface=subdir
#       sfile                   - Source File Name [Mandatory]
#       tfile                   - Not sure. Used in the prototype file.
#                                 Suggest using the same name as sfile
#       class                   - Class Name
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 4 )
    {
        Error("Incorrect number of params passed to " .
              "installPkgAddConfigFile() function. " ,
              "Check deploy config.");
    }

    # lets just check to see if we can execute this function on
    # this machine.
    #
    if ( "$MachType" ne "sparc" )
    {
        Verbose("installPkgAddConfigFile() not supported on this machine type.");
        return 1;
    }


    my ($sDirTag, $sfile, $tfile, $class) = @_;

    if ( $class ne "sed" && $class ne "build" && $class ne "awk" && $class ne "preserve" )
    {
        Error("Class Name for System Class File can only be one of sed, build, awk or preserve");
    }

    # we must have a filename.
    #
    if ( "x$sfile" eq "x" )
    {
        Error("Source filename not supplied. Check deploy config.");
    }


    # lets check to see if the local src dir tag exists
    # if does not the process with log an error.
    #
    my ($sDirValue) = getLocalDirValue("$sDirTag", "A");


    # lets check to see if the source file exists
    #
    if ( ! -f "$sDirValue/$sfile" )
    {
        Error("Failed to find local source file [$sDirValue/$sfile].");
    }

    if ( ! -f "$ProtoTypeFile" )
    {
        Error("Prototype file [$ProtoTypeFile] does not exist.",
              "Ensure createPrototypeFile() function has been called before executing installPkgAddConfigFile() function.",
              "Check deploy config.");
    }

    
    # lets determine which prototype file we are going to
    # use
    my ($dFileName);
    $dFileName     = "$PkgBaseDir/$sfile";

    # lets copy the file
    #
    if(File::Copy::copy("$sDirValue/$sfile", "$dFileName"))
    {
        Verbose("Copied [$sfile] to [$dFileName] ...");
    }
    else
    {
        Error("Failed to copy local source file [$sDirValue/$sfile]: $!"); 
    }

   
    # now we need to update the prototype file
    #
    local *FILE;
    open ( FILE, ">> $ProtoTypeFile") or
        Error("Failed to open file [$ProtoTypeFile].");
    printf FILE ("e $class $tfile=$sfile ? ? ?\n");
    close (FILE);


    return 1;
}



#------------------------------------------------------------------------------
sub updatePrototypeFileAddItem
#
# Description:
#       This sub-routine is used to update the prototype file with an
#       extra package add item. Here we pre-pend the ERGAFC_BASEDIR to the
#       destination item.
#
#       The only item type we support at this stage are "s" and "f" types.
#
#       You also need to supply the source tag, destination tag, user id, group id 
#       and permissions associated to this item.
#
#       If it has any problems it will log an error and stop processing.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 6 )
    {
        Error("Incorrect number of params passed to " .
              "updatePrototypeFileAddItem() function. " ,
              "Check deploy config.");
    }


    # lets just check to see if we can execute this function on
    # this machine.
    #
    if ( "$MachType" ne "sparc" )
    {
        Verbose("updatePrototypeFileAddItem() not supported on this machine type.");
        return 1;
    }

    my ($sTag, $dTag, $perms, $uid, $gid, $type) = @_;

    # lets determine which prototype file we are going to
    # use
    my ($protoTypeFile);
    $protoTypeFile = "$ProtoTypeFile";


    # lets check the valid types
    $type = uc($type);
    if ( "$type" !~ /S/ )
    {
        Error("Invalid type field supplied in updatePrototypeFileAddItem(). Check deploy config.");
    }

    # now we need to update the prototype file
    #
    local *FILE;
    open ( FILE, ">> $protoTypeFile") or
        Error("Failed to open file [$protoTypeFile].");
  
    my($m_Str)=""; 
    if ( "$type" eq "S" )
    {
        $m_Str = "s none $sTag=$ERGAFC_BASEDIR/$dTag $perms $uid $gid";
        Verbose("Updated prototype file with entry [$m_Str]");
    }
    else
    {
        $m_Str = "f none $sTag=$ERGAFC_BASEDIR/$dTag $perms $uid $gid";
        Verbose("Updated prototype file with entry [$m_Str]");
    }
    printf FILE ("$m_Str\n");
    close (FILE);

    return 1;
}


#------------------------------------------------------------------------------
sub updatePrototypeFileAddItem2
#
# Description:
#       This sub-routine is used to update the prototype file with an
#       extra package add item. Here we do not pre-append the 
#       ERGAFC_BASEDIR to the destination item.
#
#       The only item type we support at this stage are "s", "i" and "e" types.
#
#       You also need to supply the source tag, destination tag, user id, group id 
#       and permissions associated to this item.
#
#       If it has any problems it will log an error and stop processing.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 6 && ($#_+1) != 7 )
    {
        Error("Incorrect number of params passed to " .
              "updatePrototypeFileAddItem2() function. " ,
              "Check deploy config.");
    }


    # lets just check to see if we can execute this function on
    # this machine.
    #
    if ( "$MachType" ne "sparc" )
    {
        Verbose("updatePrototypeFileAddItem2() not supported on this machine type.");
        return 1;
    }

    # class must be last as it is optional
    my ($sTag, $dTag, $perms, $uid, $gid, $type, $class) = @_;

    $class = "none" if ( ($#_+1) == 6 );

    # lets determine which prototype file we are going to
    # use
    my ($protoTypeFile);
    $protoTypeFile = "$ProtoTypeFile";

    # lets check the valid types
    $type = uc($type);
    if ( "$type" !~ /S/ && "$type" !~ /I/ && "$type" !~ /E/ )
    {
        Error("Invalid type field supplied in updatePrototypeFileAddItem2(). Check deploy config.");
    }

    # now we need to update the prototype file
    #
    local *FILE;
    open ( FILE, ">> $protoTypeFile") or
        Error("Failed to open file [$protoTypeFile].");
  
    my($m_Str)="";
    if ( "$type" eq "S" )
    {
        $m_Str = "s $class $sTag=$dTag $perms $uid $gid";
        Verbose("Updated prototype file with entry [$m_Str]");
    }
    elsif ( "$type" eq "E" )
    {
        $m_Str = "e $class $sTag=$dTag $perms $uid $gid";
        Verbose("Updated prototype file with entry [$m_Str]");
    }
    else
    {
        $m_Str = "i $sTag=$dTag";
        Verbose("Updated prototype file with entry [$m_Str]");
    }
    printf FILE ("$m_Str\n");
    close (FILE);

    return 1;
}


#------------------------------------------------------------------------------
sub addPath2Prototype
#
# Description:
#       This sub-routine is used to add directory entries to the prototype file
#   to make sure the supplied path exists in the prototype file
#
#------------------------------------------------------------------------------
{
    # lets just check to see if we can execute this function on
    # this machine.
    #
    if ( "$MachType" ne "sparc" )
    {
        Verbose("addPath2Prototype() not supported on this machine type.");
        return 1;
    }

    # class must be last as it is optional
    my ($path, $perms, $uid, $gid, $class) = @_;
    
    # set defaults if not supplied
    $perms  = "?"       if ( ($#_+1) < 2 );
    $uid    = "?"       if ( ($#_+1) < 3 );
    $gid    = "?"       if ( ($#_+1) < 4 );
    $class  = "none"    if ( ($#_+1) < 5 );

    Information("addPathToPrototype adding path [$path $perms $uid $gid $class]");

    # lets determine which prototype file we are going to
    # use
    my ($protoTypeFile);
    $protoTypeFile = "$ProtoTypeFile";

    # now we need to update the prototype file
    #
    local *FILE;
    open ( FILE, "+<$protoTypeFile") or Error("Failed to open file [$protoTypeFile].");

    # set up has of all paths to be added
    my ( %pathDirs );
    my ( $workPath );
    my ( $i );

    $workPath = "/" if ( $path =~ s|^/|| );
    foreach $i ( split("/" , $path) )
    {
        $workPath .= $i;
        $pathDirs{$workPath} = 1;
        $workPath .= "/";
    }

    while ( <FILE> )
    {
        # lets get all the current dir entries and check for duplicates
        #        class   path    mode    owner   group
        if ( /^d ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*)/ )
        {
            # if this dir entry is defined in our paths to add we need to remove the entry
            if ( defined($pathDirs{$2}) )
            {
                Warning("addPath2Prototype: Path [$2] already exists in prototype file");
                delete($pathDirs{$2});
            }
        }
    }

    my $protoLine;
    # now we write the remaining dirs in the hash 
    foreach $i ( sort keys(%pathDirs) )
    {
        $protoLine = sprintf("d %s %s %s %s %s", $class, $i, $perms, $uid, $gid);
        Verbose("addPath2Prototype: Adding Dir entry [$protoLine]");
        printf FILE "$protoLine\n"; 
    }

    close FILE;
    return 1;
}


#------------------------------------------------------------------------------
sub createAfcRcScriptLink
#
#    Description:
#        This sub-routine is used to create links into /afc/rc.d for start & stop 
#         scripts.
#
#    INPUT:
#        Start prefix number (2 digit number)
#        Stop prefix Number (2 digit Number)
#        Full path to script to create link to.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 3 )
    {
        Error("Incorrect number of params passed to " .
              "createAfcRcScriptLink() function. " ,
              "Check deploy config.");
    }


    # lets just check to see if we can execute this function on
    # this machine.
    #
    if ( "$MachType" ne "sparc" )
    {
        Verbose("createAfcRcScriptLink() not supported on this machine type.");
        return 1;
    }

    my ($startPrefix, $stopPrefix, $scriptPath) = @_;

    if ( $startPrefix ne "" )
    {
        updatePrototypeFileAddItem2(sprintf("/afc/rc.d/S%02d%s", $startPrefix, $PkgName), 
                                    $scriptPath, "0755", "root", "other", "S");
    }
    if ( $stopPrefix ne "" )
    {
        updatePrototypeFileAddItem2(sprintf("/afc/rc.d/K%02d%s", $stopPrefix, $PkgName), 
                                    $scriptPath, "0755", "root", "other", "S");        
    }
}


#------------------------------------------------------------------------------
sub createAfcRcScriptLink2
#
#    Description:
#        This sub-routine is used to create links into the afc rc.d for start & stop 
#        scripts.  It differs from the original in that you pass a TargetDirType
#        parameter and the filename instead of a full path.  It then creates a relative
#        link from $BASEDIR/rc.d to TargetBaseDir
#
#    INPUT:
#        Start prefix number (2 digit number)
#        Stop prefix Number (2 digit Number)
#        Full path to script to create link to.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 4 )
    {
        Error("Incorrect number of params passed to " .
              "createAfcRcScriptLink() function. " ,
              "Check deploy config.");
    }


    # lets just check to see if we can execute this function on
    # this machine.
    #
    if ( "$MachType" ne "sparc" )
    {
        Verbose("createAfcRcScriptLink() not supported on this machine type.");
        return 1;
    }

    my ($startPrefix, $stopPrefix, $targetTag, $scriptPath) = @_;

    # lets check to see if the target tag exists if does not the process with log an error.
    my ($targetValue) = getTargetDstDirValue($targetTag, "R");

    if ( $startPrefix ne "" )
    {
        updatePrototypeFileAddItem2(sprintf("rc.d/S%02d%s", $startPrefix, $PkgName), 
                                    "../$targetValue/$scriptPath", "0755", "root", "other", "S");
    }
    if ( $stopPrefix ne "" )
    {
        updatePrototypeFileAddItem2(sprintf("rc.d/K%02d%s", $stopPrefix, $PkgName), 
                                    "../$targetValue/$scriptPath", "0755", "root", "other", "S");        
    }
}


#------------------------------------------------------------------------------
sub createGenericCopy
#
#    Description:
#        This sub-routine is used to create a generic copy of a specific item.
#
#        On sparc this will be a link, but on win32 it will be a file based on the
#        buildType.
#
#    INPUT:
#        src item name
#        generic item name
#        target dir
#
#    RETURN:
#         1
#
#------------------------------------------------------------------------------
{
    my ($sName, $sLoc, $gName, $tDir) = @_;

    my ($cmd);
    my ($retVal);
    if ( "$MachType" eq "sparc" )
    {
        # I want to cd into the tDir and then create the link.
        # only if an item of the same name does not already exist
        #
        if ( ! -f "$tDir/$gName" )
        {
            $cmd = "cd $tDir; ln -s $sName $gName";
            $retVal = system("$cmd");
            if ( $retVal != 0 )
            {
                Error("Failed to create generic link [$gName] to [$tDir/$sName]: $retVal");
            }
            else
            {
                Verbose("Created generic link [$gName] to [$tDir/$sName] ...");
            }
        }
    }
    else
    {

        # we only create a generic copy of the an item that matches
        # our build type.  (i.e. if we are building a debug package then
        # only the debug items shall be considered.
        #
        if ( "$BuildType" eq "D" )
        {
            if ( $sName !~ /D\./ )
            {
                # this item is not a debug one.
                return 1;
            }
        }
        else
        {
            # this is prod build
            if ( $sName !~ /P\./ )
            {
                # this item is not a prod one.
                return 1;
            }
        }


        # we have a match, lets create the copy.
        #
        if(File::Copy::copy("$sLoc", "$tDir/$gName"))
        {
            Verbose("Created generic lib copy [$tDir/$gName]...");
        }
        else
        {
            Error("Failed to create generic lib copy [$gName] from [$sLoc]: $!");
        }
    }

    return 1;
}



#------------------------------------------------------------------------------
sub removeVersionNumberFromItemName
#
#    Description:
#        This sub-routine is used to remove the version number from the item name.
#        i.e.  myFile.so.1.2.3 ==> myFile.so
#
#    INPUT:
#        item name
#
#    RETURN:
#        new item name.
#
#------------------------------------------------------------------------------
{
    my ($file) = @_;

    my ($nfile) = $file;

    if ( "$MachType" eq "sparc" )
    {
        $nfile =~ s/\.so.*$/\.so/;
    }
    else
    {
        $nfile =~ s/\.[0-9]+\.[0-9]+.*dll$/\.dll/;
    }
    return "$nfile";
}


#------------------------------------------------------------------------------
sub excludeItemFromBuild
#
#    Description:
#        This sub-routine is used to determine is a item is to be included in
#        a build based on the current build type and the extension 
#        it SHOULD HAVE!.
#
#        i.e. debug files will be tagged with *D.* 
#             prod  file will be tagged with *P.*
#
#        if the item does not have a *D.* or a *P.* we included it by default.
#
#        INPUT:
#              filename
#
#        RETURN: 
#              1  - exclude 
#              0  - include 
#
#------------------------------------------------------------------------------
{
    my ($file) = @_;

    # we only want to deliver
    if ( "$MachType" eq "win32" )
    {
        # we have to include it by default.
        return 0;
    }


    #######################################################
    #######################################################
    #######################################################
    # Third party packages do not adhere to the *D.* *P.*
    # conventions of debug and production builds.
    #
    # Hopefully we won't have to many of these, only found 
    # one so far.
    # 
    #######################################################
    #######################################################
    #######################################################
    if ( $file =~ /libTAO_BiDirGIOP\.so/ )
    {
        return 0;
    } 

    if ( $file !~ /D\./ &&
         $file !~ /P\./
       )
    {
        # we have to include it by default. 
        return 0;
    }


    # we only want to deliver 
    if ( "$BuildType" eq "D" )
    { 
        if ( $file !~ /D\./ )
        {
            # we do not want this file for this build type.
            return 1;
        }
        else
        {
            return 0;
        }
    }
    else
    {
        if ( $file !~ /P\./ )
        {
            # we do not want this file for this build type.
            return 1;
        }
        else
        {
            return 0;
        }
    }

    return 1;
}


#------------------------------------------------------------------------------
sub installAllDpkgArchiveBinFiles
#
# Description:
#       This sub-routine is used to install all bin files from the
#       dpkg_archive into the defined install area.
#
#       It assumes based on the build type where the src files will be located.
#
#       If it has any problems it will log an error and stop processing.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 1 )
    {
        Error("Incorrect number of params passed to " .
              "installAllDpkgArchiveBinFiles() function. " ,
              "Check deploy config.");
    }

    my ($targetTag) = @_;

    # lets check to see if the target tag exists
    # if does not the process with log an error.
    #
    my ($targetValue) = getTargetDstDirValue($targetTag, "A");


    # ok we have a valid dst value we now need to get a hold of all the 
    # lib files for this buildtype
    #
    my ($i);
    my ($m_DpkgBinDir);
    foreach $i (@{$DpkgBinDirList{'_ALL_'}})
    {
        $m_DpkgBinDir = "$DpkgBinDir/$i";
        if ( ! -d $m_DpkgBinDir )
        {
            Verbose("Directory [$m_DpkgBinDir] not found.");
            next;
        }

        local *DIR;
        opendir(DIR, $m_DpkgBinDir) or 
            Error("can't opendir $m_DpkgBinDir : $!");

        my ($file);
        while (defined($file = readdir(DIR))) 
        {
            if ( $file !~ /^\.$/  &&     # we do not want the . and .. entries.
                 $file !~ /^\.\.$/ &&
                 $file !~ /\.pdb$/ )
            {
                my ($m_fLoc) = "$m_DpkgBinDir/$file"; 
                if(File::Copy::copy("$m_fLoc", "$targetValue"))
                {
                    Verbose("Copied [$file] to [$targetValue] ...");
                }
                else
                {
                    Error("Failed to copy bin [$m_fLoc]: $!"); 
                }
            }
        }
        closedir(DIR);
    }

    return 1;
}


#------------------------------------------------------------------------------
sub rmDirectory
#
# Description:
#       This sub-routine is used to remove an entire directory tree.
#
#       It recurses from a starting point removing each item and if it
#       finds a dir it recurses into that dir cleaning it as well.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 1  )
    {
        Error("Incorrect number of params passed to rmDirectory() function.");
    }

    my ($startingPoint) = @_;
    return 0 unless ( -d $startingPoint );
    Verbose("Recursively removing Directory tree [$startingPoint]");

    #
    #   Use the rmtree function
    #   It works better than glob when given a filepath with spaces
    #
    rmtree($startingPoint, IsVerbose(1), 1);
    Error("Failed to remove dir [$startingPoint] : $!") if (-d $startingPoint);
    
    return 1;
}

#------------------------------------------------------------------------------
sub CreateTargetDirStructure
#
# Description:
#       This sub-routine create the target stucture based on what the user has
#       previously defined in the %TargetDstDirStructure hash array
#
#       It will also clean the contents of this location prior to creation.
#
#       In this function we also check to see if all the LocalSrcDirStructure
#       directories exist. We warn if they do not.
#
#------------------------------------------------------------------------------
{
    Information("Cleaning any previous target file items...");

    my ($i);

    #   Clean out PkgBaseDir
    #   This is the directory in which the final package image will be assembled
    #   Recreate the directory. Ensure that it does not have setgid on the directory
    #   as this will affect all the subdirectories that are created and will
    #   propergate into the target package.
    #
    rmDirectory( $PkgBaseDir );
    make_directory( $PkgDir, 0777, "Create target base dir");

    # lets create.
    #
    Information ("Creating target directory structure...");
    make_directory( "$PkgBaseDir/$TargetBaseDir", 0777, "Create target dir");
    foreach $i ( sort {$a cmp $b} values %TargetDstDirStructure )
    {
        make_directory("$PkgBaseDir/$TargetBaseDir/$i", 0777);
    }


    # lets determine if we have a InstallShield config dir
    #
    if ( "$MachType" eq "win32" || "$MachType" eq "WinCE" )
    {

        # if this is a patch build i expect to find a "p" in the front of the
        # file names. we use this as a simple visual differentiation.
        #
        my ($m_ishieldDir);    
        my ($m_ishieldProjFile);
        if ( "x$PkgPatchNum" ne "x" )
        {
            # patch build.
            $m_ishieldDir      = "$RootDir/" . "p$PkgName";
            $m_ishieldProjFile = "$RootDir/" . "p$PkgName" . ".ism";
        }
        else
        {
            # normal build.
            $m_ishieldDir      = "$RootDir/" . "$PkgName";
            $m_ishieldProjFile = "$RootDir/" . "$PkgName" . ".ism";
        }

        # here i can set the location of my IShield project dir
        # so i can use it later if required.
        $PKG_ISHIELD_DIR = $m_ishieldDir;


        # we check for an ism file based on the pkg name
        # if we find one we need to deal with the dir and
        # the isheildlib files.
        #
        if ( -f "$m_ishieldProjFile" )
        {
            if ( ! -d "$m_ishieldDir" )
            {
                Error ("Local InstallShield config dir [$m_ishieldDir] does not exist.",
                       "Please create before continuing.");
            }
            else
            {
                # we populate the ishield config dir with the ishieldlib files
                #
                my ($i);
                Verbose("Installing Standard ishieldlib files from [$PKG_UTIL_DIR] to [$m_ishieldDir]");
                foreach $i ( @PKG_ISHIELD_FILES )
                {
                    # first we remove the file (as previously it install read-only).
                    unlink("$m_ishieldDir/$i");
                    if( File::Copy::copy("$PKG_UTIL_DIR/$i", "$m_ishieldDir") )
                    {
                        Verbose("Copied [$PKG_UTIL_DIR/$i] to [$m_ishieldDir] ...");
                    }
                    else
                    {
                        Error("Failed to copy info file [$PKG_UTIL_DIR/$i] to [$m_ishieldDir] : $!");
                    }
                }


                # we also want to deliver the patch rule files
                # if this build is a patch build.
                #
                if ( "x$PkgPatchNum" ne "x" )
                {
                    Verbose("Installing Patch ishieldlib files from [$PKG_UTIL_DIR] to [$m_ishieldDir]");
                    foreach $i ( @PATCH_ISHIELD_FILES )
                    {
                        # first we remove the file (as previously it install read-only).
                        unlink("$m_ishieldDir/$i");
                        if( File::Copy::copy("$PKG_UTIL_DIR/$i", "$m_ishieldDir") )
                        {
                            Verbose("Copied [$PKG_UTIL_DIR/$i] to [$m_ishieldDir] ...");
                        }
                        else
                        {
                            Error("Failed to copy info file [$PKG_UTIL_DIR/$i] to [$m_ishieldDir] : $!");
                        }
                    }
                }


                # we also want to deliver the islib imgages to be
                # used by this project, we assume the image has a project
                # acronym prefix, and if not found we just WARN the user
                #
                # we assume our source dir is the interface/etc dir and our
                # dst dir is the PkgBaseDir
                #
                my ($m_islibImgFile) = "";
                Verbose("Installing ishield image files from [$DpkgEtcDir] to [$m_ishieldDir]");
                foreach $i ( @PKG_ISHIELD_IMG_FILES )
                {
                    $m_islibImgFile = "$DpkgEtcDir/$ProjectAcronym" . "_" . $i;
                    if ( -f "$m_islibImgFile" )
                    {
                        if( File::Copy::copy("$m_islibImgFile", "$PkgBaseDir") )
                        {
                            Verbose("Copied [$m_islibImgFile] to [$PkgBaseDir] ...");
                        }
                        else
                        {
                            Error("Failed to copy info file [$m_islibImgFile] to " .
                                     "[$PkgBaseDir] : $!");
                        }
                    }
                    else
                    {
                        # we shall check for the MASS items, if the exist we copy them
                        # over. Here we assume the 'mas' acronymn is correct.
                        #
                        $m_islibImgFile = "$DpkgEtcDir/mas" . "_" . $i;
                        if ( -f "$m_islibImgFile" )
                        {
                            if( File::Copy::copy("$m_islibImgFile", "$PkgBaseDir") )
                            {
                                Verbose("Copied [$m_islibImgFile] to [$PkgBaseDir] ...");
                            }
                            else
                            {
                                Error("Failed to copy info file [$m_islibImgFile] to " .
                                         "[$PkgBaseDir] : $!");
                            } 
                        } 
                        else
                        {
                            Warning("Failed to locate ishieldlib image [xxx_$i], no image copied, " .
                                    "check depolylib config.");
                        }
                    }
                }

            }
        }
        else
        {
            Warning("Did not detect InstallShield project file [$m_ishieldProjFile]");
            Warning("Not installing InstallShield library files.");
        }
    }

    # done.
    return 1;
}

#------------------------------------------------------------------------------
sub generateIShieldIncludeFile ()
#
# Description:
#     This subroutine is used to generate a definition include file 
#     that is used during IShield builds.
#
#     The output location of the file is the IShieldProjDir.
#    
#------------------------------------------------------------------------------
{
    my ($outFile) = "$PKG_ISHIELD_DIR/$PKG_ISHIELD_DEF_FILE";

    # this is only relavent for win32 builds.
    if ( "$MachType" eq "sparc" )
    {
        return 1;
    }

    # lets open the file.
    #
    local *FILE;
    open ( FILE, "> $outFile") or
        Error("Failed to open file [$outFile].");

    # lets populate the pkgdef file.

    printf FILE ("// This is an automatically generated include file.\n");
    printf FILE ("// Please do not modify, and please do not check into ClearCase.\n");
    printf FILE ("//\n");
    printf FILE ("#define PKG_NAME         \"$PkgName\"\n");
    printf FILE ("#define PKG_NAMELONG     \"$PkgNameLong\"\n");
    printf FILE ("#define PKG_VERSION      \"$PkgVersion\"\n");
    printf FILE ("#define PKG_BUILDNUM     \"$PkgBuildNum\"\n");
    printf FILE ("#define PKG_PROJACRONYM  \"$ProjectAcronym\"\n");
    printf FILE ("#define PKG_DESC         \"$PkgDesc\"\n");

    # if this build is a patch build.
    #
    if ( "x$PkgPatchNum" ne "x" )
    {
        printf FILE ("#define PATCH_NAME       \"$PkgPatchName\"\n");
        printf FILE ("#define PATCH_NUM        \"$PkgPatchNum\"\n");
        printf FILE ("#define PATCH_ID         \"$PkgPatchID\"\n");
    }
    else
    {
        printf FILE ("#define PATCH_NAME       \"\"\n");
        printf FILE ("#define PATCH_NUM        \"\"\n");
        printf FILE ("#define PATCH_ID         \"\"\n");
    }

    # lets close the file
    close FILE;

    # done.
    return 1;
}


#------------------------------------------------------------------------------
sub ValidateLocalSrcDirStructure
#
# Description:
#       This sub-routine is used to check the existence the local dir 
#       configuration items, these are stored in 
#       %LocalSrcDirStructure.
#
#------------------------------------------------------------------------------
{
    # lets check the configured local direcotry structure
    #
    my ($i);
    foreach $i ( values %LocalSrcDirStructure )
    {
        my ($m_Dir) = "$SrcDir/$i";
        if ( ! -d "$m_Dir" )
        {
            Warning ("Local src dir [$m_Dir] does not exist.");
        }
    }

    return 1;
}


#------------------------------------------------------------------------------
sub getLocalDirValue
#
# Description:
#       This sub-routine is used to return the local dir value from
#       %LocalSrcDirStructure based on providing the 
#       associated key.
#
#
# Input:
#       m_key               - A symbolic directory name to be found in the
#                             LocalSrcDirStructure
#
#                             A Package Name of the form
#                             --Package=PackageName,subdir
#
#                             A directory within the interface directory
#                             --Interface=subdir
#
#                             This form is only valid for an ABS address
#
#       m_type              - "A"   Absolute address
#                             else  Relative address
#
#       If the value does not exist then it will return an error
#       and terminate processing.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 2 ) 
    {
        Error("Incorrect number of params passed to " .
                  "getLocalDirValue() function.");
    }

    my ($m_key, $m_type) = @_;

    #
    #   Determine the type of lookup
    #
    if ( $m_key =~ m~^--Interface=(.*)~ )
    {
        Error("Locating Interface directory must be used in conjunction with an Absolute path")
            unless ( $m_type eq 'A' );

        my $SubDir = $1;
        my $Dir = "$InterfaceDir/$SubDir";
        Error ("Interface subdirectory not found: $SubDir" )
            unless ( -d $Dir );
        return $Dir;
    }

    if ( $m_key =~ m~^--Package=(.*)~ )
    {
        Error("Locating local source directory must be used in conjunction with an Absolute path")
            unless ( $m_type eq 'A' );

        #
        #   Locate directory within a package
        #
        my ($PkgName, $PkgSubDir) = split /[\/,]/, $1, 2;
        Error ("--Package requres a package name and a subdirectory") unless ( $PkgName && $PkgSubDir );
        my $PkgDir = LocatePackageBase( "getLocalDirValue", $PkgName, $PkgSubDir );
        return $PkgDir;
    }

    #
    #   Locate the directory within the LocalSrcDirStructure
    #   This is a symbolic reference to a local directory
    #
    if (exists  $LocalSrcDirStructure{$m_key} )
    {
        if ( "$m_type" eq "A" )
        {
            return "$SrcDir/$LocalSrcDirStructure{$m_key}";
        }
        else
        {
            return "$LocalSrcDirStructure{$m_key}";
        }
    }
    else
    {
        Error("Local src tag [$m_key] does not exist in " .
             "LocalSrcDirStructure. " ,
             "Check deploy configuration.");
    }

    return 1;
}


#------------------------------------------------------------------------------
sub getTargetDstDirValue
#
# Description:
#       This sub-routine is used to return the target dest dir value from
#       %TargetDstDirStructure based on providing the 
#       associated key.
#
#       If the value does not exist then it will return an error
#       and terminate processing.
#
# Inputs:   $m_key          Symbolic name for target directory
#           $m_type         Type : A    - Absolute
#                                  R    - Relative
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 2 ) 
    {
        Error("Incorrect number of params passed to " .
                  "getTargetDstDirValue() function.");
    }

    my ($m_key, $m_type) = @_;
    my $tdir;

    #
    #   Look up the users tag conversion hash
    #
    if ( exists $TargetDstDirStructure{$m_key} )
    {
        $tdir = $TargetBaseDir . '/' . $TargetDstDirStructure{$m_key};
    }
    else
    {
        Error("Target destination dir tag [$m_key] does not exist in " .
             "TargetDstDirStructure. " ,
             "Check deploy configuration.");
    }


    #
    #   If an absolute path is required than add the PkgBaseDir
    #   otherwise the user must be requesting a relative path.
    #
    if ( "$m_type" eq "A" ) {
        $tdir = "$PkgBaseDir/$tdir";
    } elsif ( "$m_type" eq "R" )  {
    } else {
        Error("getTargetDstDirValue: Bad call. Unknown type: $m_type");
    }

    return $tdir;
}


#------------------------------------------------------------------------------
sub createPatch
#
# Description:
#       This sub-routine is used to create a solaris patch.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 0 )
    {
        Error("Incorrect number of params passed to " .
              "createPatch() function.",
              "Check deploy config.");
    }

    # lets just check to see if we can execute this function on
    # this machine.
    #
    if ( "$MachType" ne "sparc" )
    {
        Verbose("createPatch() not supported on this machine type.");
        return 1;
    }

    # lets just check to see if we can execute this function on
    # for  this build.
    #
    if ( "x$PkgPatchNum" eq "x" )
    {
        Warning("createPatch() can only be called during a PATCH build.");
        return 1;
    }

    # we need to create the patch directory that contains
    #
    Information("Creating patch ...");

    my ( $m_pkgmkCmd );
    my ( $m_pkgtransCmd );
    $m_pkgmkCmd = "pkgmk -o " .
                  "-f $PkgBaseDir/prototype " .
                  "-d $PkgBaseDir";

    # lets execute the package commands.
    my ($retVal);
    $retVal = system("$m_pkgmkCmd");
    if ( $retVal != 0 )
    {
        Error("Failed to complete command [$m_pkgmkCmd].");
    }

    # we need to generate a README file to help during installation
    #
    generatePatchREADME();


    my ($m_Cmd)    = ""; 
    my ($m_tmpDir) = "$PkgPatchTmpDir/$PkgPatchID";

    Information("Creating staging area of patch...");
    $m_Cmd = "cd $PkgBaseDir && mkdir -p $m_tmpDir;";
    system($m_Cmd);

    Information("Copying patch contents to staging area of patch...");
    $m_Cmd = "cd $PkgBaseDir && cp -r $PkgName $m_tmpDir;";
    system($m_Cmd);

    # we need to copy the patch install utility files from
    # their resting place.
    #
    my ($i);
    foreach $i ( @PATCH_UTIL_FILES )
    {
        if( File::Copy::copy("$PATCH_UTIL_DIR/$i", "$PkgPatchTmpDir") )
        {
            Verbose("Copied [$PATCH_UTIL_DIR/$i] to [$PkgPatchTmpDir] ...");
            system("chmod 0755 $PkgPatchTmpDir/$i");
        }
        else
        {
            Error("Failed to copy info file [$PATCH_UTIL_DIR/$i] to [$PkgPatchTmpDir] : $!");
        }
    }

    # Lets put the readme in place
    #
    if( File::Copy::copy("$PkgPatchReadme", "$PkgPatchTmpDir") )
    {
        Verbose("Copied [$PkgPatchReadme] to [$PkgPatchTmpDir] ...");
    }
    else
    {
        Error("Failed to copy info file [$PkgPatchReadme] to [$PkgPatchTmpDir] : $!");
    }

    Information("Copying patch contents to staging area of patch...");
    $m_Cmd = "cd $PkgBaseDir && cp -r $PkgName $m_tmpDir;";
    system($m_Cmd);

    my ($m_oFile) = "$PkgPatchID-$ProjectAcronym\.tgz";
    Information("Creating a gzip'd compressed tar (.tgz) output file [$m_oFile]...");
    my ($base) = File::Basename::basename($PkgPatchTmpDir);
    $m_Cmd = "cd $PkgBaseDir && tar cvf - $base | gzip > $m_oFile";
    system($m_Cmd);

    return 1;
}



#------------------------------------------------------------------------------
sub generatePatchREADME
#
#   This function is used to generate a README text file to help the user
#   duing the patch installation.
#
#------------------------------------------------------------------------------
{
    local *FILE;
    open ( FILE, "> $PkgPatchReadme") or
        Error("Failed to open file [$PkgPatchReadme].");

    printf FILE ("This is a patch for $PkgName $PkgVersion\n");
    printf FILE ("---------------------------------------------------------------\n");
    printf FILE ("\n");
    printf FILE ("Installing patch (as the 'root' user) :\n");
    printf FILE ("---------------------------------------------------------------\n");
    printf FILE ("./installpatch $PkgPatchID\n");
    printf FILE ("\n");
    printf FILE ("Backing Out patch:\n");
    printf FILE ("---------------------------------------------------------------\n");
    printf FILE ("./backoutpatch $PkgPatchID\n");
    printf FILE ("\n");

    printf FILE ("Patch contents of $PkgPatchID\n");
    printf FILE ("---------------------------------------------------------------\n");
    close FILE;

    # now we need to get the contents of the patch we are creating.
    #
    File::Find::find(\&getPatchContents, "$PkgBaseDir/$TargetBaseDir");
   
    return 1;
}


#------------------------------------------------------------------------------
sub getPatchContents
#
#   This sub-routine adds an entry into the readme file for each
#   item in the patch delivery tree.
#
#------------------------------------------------------------------------------
{
    my($file)= "$File::Find::name";
    my($base)= File::Basename::basename($file);

    # we get the absolute path from the find, but we only require
    # a relative path from the starting dir.
    # so our start dir.

    my ($m_sfile) = $file;
    $file =~ s/$PkgBaseDir//;

    open ( FILE, ">> $PkgPatchReadme") or
         Error("Failed to open file [$deplylib::PkgPatchReadme].");

    # lets populate the prototype file.
    printf FILE ("* $file\n");

    close (FILE);
}


#------------------------------------------------------------------------------
sub createPackage
#
# Description:
#       This sub-routine is used to create a package.
#       The type of package is machine specific. The subroutine will invoke a
#       machine specfic function to do the real work.
#
#------------------------------------------------------------------------------
{
    Information("createPackage");

    # lets just check to see if we can execute this function on
    # this machine.
    #
    my $createRoutine = 'createPackage_' . $MachType;
    if ( exists &$createRoutine )
    {
        # lets just check to see if we can execute this function on
        # for  this build.
        #
        if ( $PkgPatchNum )
        {
            Warning("createPackage() can only be called during a RELEASE build.");
            return 1;
        }

        #
        #   Ensure the Release directory is present
        #
        make_directory( $ReleaseDir, 0777 );

        # Ensure that the package descriptor is transferred
        #
        my ($m_copydesc) = "cp $SrcDir/descpkg $ReleaseDir";
        system($m_copydesc);

        # Invoke the machine specific package builder by name
        # Need to relax strictness. Yes we do know what we are doing here
        #
        no strict "refs";
        &$createRoutine( @_ ) || Error("Unspecified error building package");
        use strict "refs";
    }
    else
    {
        Verbose("createPackage() not supported on this machine type: $MachType.");
    }
    return 1;
}


#------------------------------------------------------------------------------
sub createPackage_sparc
#
# Description:
#       This sub-routine is used to create a package.
#       The type of package is machine specific. The subroutine will invoke a
#       machine specfic function to do the real work.
#
#------------------------------------------------------------------------------
{
    Verbose("createPackage_sparc");

    # we need to copy the package utility files from
    # their resting place.
    #
    foreach my $i ( @PKG_UTIL_FILES )
    {
        if( File::Copy::copy("$PKG_UTIL_DIR/$i", "$PkgBaseDir") )
        {
            Verbose("Copied [$PKG_UTIL_DIR/$i] to [$PkgBaseDir] ...");
            updatePrototypeFileAddItem2("$i", "$i", "", "", "", "I");
            system("chmod 0755 $PkgBaseDir/$i");
        }
        else
        {
            Error("Failed to copy info file [$PKG_UTIL_DIR/$i] to [$PkgBaseDir] : $!");
        }
    }


    my ( $m_pkgmkCmd );
    my ( $m_pkgtransCmd );
    $m_pkgmkCmd = "pkgmk -o " .
                  "-f $PkgBaseDir/prototype " .
                  "-d $PkgBaseDir";


    $m_pkgtransCmd = "pkgtrans -o " .
                     "-s $PkgBaseDir " .
                     "$PkgOutputFile " .
                     "$PkgName";

    # lets execute the package commands.
    my ($retVal);
    $retVal = system("$m_pkgmkCmd");
    if ( $retVal != 0 )
    {
        Error("Failed to complete command [$m_pkgmkCmd].");
    }

    $retVal = system("$m_pkgtransCmd");
    system("$m_pkgtransCmd");
    if ( $retVal != 0 )
    {
        Error("Failed to complete command [$m_pkgtransCmd].");
    }

    # lets compress the output to save some space.
    #
    Information("Compressing $PkgOutputFile");
    my ($m_compressCmd) = "cd $PkgBaseDir; gzip $PkgOutputFile; mv ${PkgOutputFile}.gz $ReleaseDir";
    system($m_compressCmd);

    return 1;
}

#------------------------------------------------------------------------------
sub createPackage_WinCE
#
# Description:
#       This sub-routine is used to create a package.
#       Really a win32 machine type, but for some reason, the MachType gets
#       stuffed around. Don't know why.
#
#       Do have the option of creating a WinCE specific packager
#
#------------------------------------------------------------------------------
{
    Verbose("createPackage_WinCE");
    createPackage_win32(@_);
}

#------------------------------------------------------------------------------
sub createPackage_win32
#
# Description:
#       This sub-routine is used to create a package.
#       Invoke the isbuild.pl utility to build the install shield project
#
#------------------------------------------------------------------------------
{
    Verbose("createPackage_win32");

    #
    #   Process any options that may be present
    #   Don't complain about args we don't understand. They may apply to other
    #   platforms
    #
    my @user_options = ();
    foreach my $arg ( @_ )
    {
        if ( $arg =~ m/^-nonameversion/ || $arg =~ m/^-nameversion/   ) {
            push @user_options, $arg;

        } elsif ( $arg =~ m/^-nocode/ || $arg =~ m/^-code/   ) {
            push @user_options, $arg;

        } else {
            Message ( "createPackage_win32: Unknown option: $_");
        }
    }

    #
    #   Locate MergeModules in external packages
    #   These will be used by the InstallShield compiler
    #
    my @mm_dirs;
    my @mm_tld;
    my $tdir;

    #
    #   Check for Merge Modules in the local directory
    #   This must be a flat directory structure. ie: all files in the
    #   subdirectory called MergeModule.
    #
    $tdir = "$RootDir/MergeModules";
    push @mm_dirs, $tdir if ( -d $tdir );
    Verbose ("Discovered MergeModules in: $tdir") if ( -d $tdir );

    #
    #   Check for Merge Modules in the Interface directory
    #   This will be pulled in via a BuildPkgArchive
    #
    $tdir = "$InterfaceDir/MergeModules";
    push @mm_tld, $tdir if ( -d $tdir );
    Verbose ("Discovered MergeModules in: $tdir") if ( -d $tdir );

    #
    #   Check in LinkPkgArchive locations too
    for my $entry ( $BuildFileInfo->getBuildPkgRules() )
    {
        next unless ( $entry->{'TYPE'} eq 'link' );
        $tdir = $entry->{'ROOT'} . '/MergeModules';
        push @mm_tld, $tdir if ( -d $tdir );
        Verbose ("Discovered MergeModules in: $tdir") if ( -d $tdir );
    }

    #
    #   Expand the merge module subdirectory tree into
    #   suitable paths:
    #       Modules/i386
    #       Modules/i386/<language>
    #       Objects
    #       Merge Modules
    #
    foreach my $dir ( @mm_tld )
    {
        $tdir = $dir . '/Modules/i386';
        if ( -d $tdir )
        {
            push @mm_dirs, $tdir;
            foreach my $file ( glob( "$tdir/*" ))
            {
                next unless ( -d $file );
                push @mm_dirs, $file;
            }
        }

        $tdir = $dir . '/Objects';
        push @mm_dirs, $tdir if ( -d $tdir );

        $tdir = $dir . '/Merge Modules';
        push @mm_dirs, $tdir if ( -d $tdir );
    }


    #
    #   Locate the program
    #   It will be in a location addressed by the @INC path
    #
    my $prog_found;
    my $prog;
    foreach my $dir ( @INC )
    {
        $prog = $dir . '/isbuild.pl';
        next unless ( -f $prog );
        $prog_found = 1;
        last;
    }

    Error("isbuild.pl not found") unless $prog_found;
    Verbose("isbuild: $prog");
    my $rv = system ( $ENV{GBE_PERL}, $prog,
                            "-project=../$PkgName.ism",
                            "-version=$PkgVersionUser",
                            "-out=$ReleaseDir",
                            "-workdir=$InterfaceDir",
                            @user_options,
                            map { "-mergemodule=$_" } @mm_dirs
                             );
    Error ("InstallShield Builder Error" ) if ( $rv );
    return 1;
}

#------------------------------------------------------------------------------
sub createPrototypeFile
#
# Description:
#       This sub-routine is used to create the required package prototype file
#       from a known directory struture using the search path method.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 2 )
    {
        Error("Incorrect number of params passed to " .
              "createPrototypeFile() function",
              "Check deploy config.");
    }

    # lets just check to see if we can execute this function on
    # this machine.
    #
    if ( "$MachType" ne "sparc" )
    {
        Verbose("createPrototypeFile() not supported on this machine type.");
        return 1;
    }

    # lets take the passed in args.
    my ($uid, $gid) = @_;


    # we need to determine whiich file we are dealing with
    my ($protoTypeFile);
    my ($targetBaseDir);
    my ($pkgBaseDir);
    $protoTypeFile = "$ProtoTypeFile"; 
    $targetBaseDir = "$PkgBaseDir/$TargetBaseDir"; 
    $pkgBaseDir    = "$PkgBaseDir"; 


    # we need to locate the prototype file
    if ( -f "$protoTypeFile" )
    {
        unlink("$protoTypeFile");
        Verbose("Removing prototype file [$protoTypeFile].");
    }

    # lets open the prototype file.
    #    
    local *FILE;
    open ( FILE, "> $protoTypeFile") or
        Error("Failed to open file [$protoTypeFile].");

    # lets populate the prototype file.
    printf FILE ("i pkginfo\n");

    if ( "x$TargetBaseDir" ne "x." )
    {
        printf FILE ("!search $TargetBaseDir");
    }
    else
    {
        printf FILE ("!search ");
    }

    # now we need to add entries for each directory we will 
    # be installing 
    File::Find::find(\&prototypeFind, "$targetBaseDir");

    # lets populate the prototype file with a newline.
    open ( FILE, ">> $protoTypeFile") or
        Error("Failed to open file [$protoTypeFile].");
    printf FILE ("\n");
    close (FILE);


    # lets put the pre-deinfed generic entries into the 
    # prototype file
    #
    if ( "x$PkgPatchNum" ne "x" )
    {
        addPatchInfo2ProtoTypeFile();
    }


    # we need to expand and complete the creation of the 
    # prototype file
    # if targetbasedir is "." the pkgproto will pick up the pkginfo and
    # prototype files so we need to remove them
    my ($m_cmd) = "pkgproto " .
                  "$TargetBaseDir " .
                  "| egrep -v \"($ProtoTypeFileName|$PkgInfoFileName)\"" .
                  "| cut -f1-4 -d' ' | sed " . '"s/\$/ ' . "$uid $gid" . '/g"' . 
                  " >> $protoTypeFile";

    my ($retVal) = system("cd $pkgBaseDir; $m_cmd");
    if ( $retVal != 0 )
    {
        Error("Failed to create prototype file [$protoTypeFile].");
    }

    Information("Created prototype file [$protoTypeFile].");

    return 1;
}

#------------------------------------------------------------------------------
sub prototypeFind
#
#    Description:
#        This subroutine is used to locate all associated package dirs.
#        It also adds an entry into the prototype file for each dir.
#
#------------------------------------------------------------------------------
{
    my($file)= "$File::Find::name";
    my($base)= File::Basename::basename($file);

    # we get the absolute path from the find, but we only require
    # a relative path from the starting dir.
    # so our start dir.

    # we need to determine whiich file we are dealing with
    my ($pfile);
    my ($tDir);
    $pfile = "$ProtoTypeFile"; 
    $tDir = "$PkgBaseDir/$TargetBaseDir"; 
    if ( "$file" ne "$tDir" )
    {
        if ( -d "$file" )  
        {
            my ($m_sfile) = $file;

            if ( "x$TargetBaseDir" eq "x." )
            {
                $tDir = $tDir . "/";
                $file =~ s/$tDir//;
            }
            else
            {
                $file =~ s/$tDir/$TargetBaseDir/;
            }

            open ( FILE, ">> $pfile") or
                 Error("Failed to open file [$pfile].");

            # lets populate the prototype file.
            printf FILE (" $file");
            close (FILE);
        }
    }
}


#------------------------------------------------------------------------------
sub addPatchInfo2ProtoTypeFile
#
# Description:
#       This sub-routine is used to add additonal genericinformation
#       used by the patch.
#
#------------------------------------------------------------------------------
{
    Information("Adding patch information files to patch build...");

    # we need to determine whiich file we are dealing with
    my ($protoTypeFile);
    $protoTypeFile = "$ProtoTypeFile";

    # lets open the prototype file.
    #
    local *FILE;
    open ( FILE, ">> $protoTypeFile") or
        Error("Failed to open file [$protoTypeFile].");


    # we need to copy the install informational files from
    # their resting place.
    my ($i);
    foreach $i ( @PATCH_INFO_FILES )
    {
        if( File::Copy::copy("$PATCH_UTIL_DIR/$i", "$PkgBaseDir") )
        {
            Verbose("Copied [$PATCH_UTIL_DIR/$i] to [$PkgBaseDir] ...");
            printf FILE ("i $i\n"); 
        }
        else
        {
            Error("Failed to copy info file [$PATCH_UTIL_DIR/$i]: $!");
        }
    }
    close FILE;
    
    return 1;
}


#------------------------------------------------------------------------------
sub useReplaceClass
#
# Description:
#       This sub-routine is used to add replace class to the classes list and
#       include the i.replace file in the PKG_INFO_FILES List
#
#------------------------------------------------------------------------------
{

    Information("useReplaceClass: Adding replace class to installer");

    $PkgInfoClasses = $PkgInfoClasses . " " . "replace";
    push(@PKG_UTIL_FILES, "i.replace");
}


#------------------------------------------------------------------------------
sub addPkgInfoClasses
#
# Description:
#       This sub-routine is used to add new classes to the pkginfo CLASSES variable.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) == 0 )
    {
        Error("Incorrect number of params passed to " .
              "createPkginfoFile() function",
              "Check deploy config.");
    }

    Information("addPkgInfoClasses() Adding classes \"" . join(" ", @_) . "\" to CLASSES List");

    $PkgInfoClasses = $PkgInfoClasses . " " . join(" ", @_);
}


#------------------------------------------------------------------------------
sub addPkgInfoField
#
# Description:
#       This sub-routine is used to add new fields to already created pkginfo file
#       Acccepts any number of fields of format A=B as one string parameter.
#------------------------------------------------------------------------------
{
    # lets just check to see if we can execute this function on this machine.
    if ( "$MachType" ne "sparc" )
    {
        Verbose("addPkgInfoField() not supported on this machine type.");
        return 1;
    }
    # lets open the pkginfo file.   
    local *FILE;
    open ( FILE, ">> $PkgInfoFile") or Error("Failed to open file [$PkgInfoFile].");

    foreach my $i ( @_ )
    {
        print FILE "$i\n";
    }
    close FILE;
    return 1;
}

#------------------------------------------------------------------------------
sub updatePrototypeFileItemClass
#
# Description:
#       This subroutine is used to change the class of a file already in the prototype file
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 2 )
    {
        Error("Incorrect number of params passed to " .
                  "updatePrototypeFileItemClass() function. Check deploy config.");
    }


    # lets just check to see if we can execute this function on
    # this machine.
    #
    if ( "$MachType" ne "sparc" )
    {
        Verbose("updatePrototypeFileItemClass() not supported on this machine type.");
        return 1;
    }


    # lets setup the passed values.
    my ($m_item, $class) = @_;

    my ($tmpProtoTypeFile) = "/tmp/xx_prototypefile.$$";

    # lets open the prototype file if it exists
    #
    open (PFILE, "< $ProtoTypeFile") or
        Error("Failed to open prototype file [$ProtoTypeFile].");

    open (PFILETMP, "> $tmpProtoTypeFile") or
        Error("Failed to open tmp prototype file [$tmpProtoTypeFile].");

    while ( <PFILE> )
    {
        chomp;
        # The path section will normally contain "path [mode]" or path=path
        # The passed arg can be full path or can skip top level dirs
        # eg prototype can have line with path ergbpeod/etc/afcbp.ini
        # arg to match can be ergbpeod/etc/afcbp.ini, etc/afcbp.ini or afcbp.ini
        # therefore we need to match arg to the end of the path in line 
        # so we append [= ] to arg
        s/^(\s*[bcdefilpsvx]\s*)[^\s]*(.*$)/$1$class$2/ if ( /$m_item[ =]/ );
        printf PFILETMP ("$_\n");
    }
    close PFILE;
    close PFILETMP;

    # now we need to copy the file.
    if(File::Copy::copy("$tmpProtoTypeFile", "$ProtoTypeFile"))
    {
        Verbose("Updated file $m_item to class $class");
        unlink($tmpProtoTypeFile);
    }
    else
    {
        Error("Failed to copy lib [$tmpProtoTypeFile]: $!");
    }

    return 1;

}



#------------------------------------------------------------------------------
sub setReplaceClassFiles
#
# Description:
#       This subroutine is used to change the class of a file already in the prototype file
#
#------------------------------------------------------------------------------
{
    # lets just check to see if we can execute this function on
    # this machine.
    #
    if ( "$MachType" ne "sparc" )
    {
        Verbose("updatePrototypeFileItemClass() not supported on this machine type.");
        return 1;
    }

    Error("Must call useReplaceClass() before calling setReplaceClassFiles()") if ( $PkgInfoClasses !~ /replace/ );

    my ($tmpProtoTypeFile) = "/tmp/xx_prototypefile.$$";

    # lets open the prototype file if it exists
    #
    open (PFILE, "< $ProtoTypeFile") or
        Error("Failed to open prototype file [$ProtoTypeFile].");

    open (PFILETMP, "> $tmpProtoTypeFile") or
        Error("Failed to open tmp prototype file [$tmpProtoTypeFile].");

    my $line;
    while ( $line = <PFILE> )
    {
        chomp $line;
        # The path section will normally contain "path [mode]" or path=path
        # The passed args can be full path or can skip top level dirs
        # eg prototype can have line with path ergbpeod/etc/afcbp.ini
        # args to match can be ergbpeod/etc/afcbp.ini, etc/afcbp.ini or afcbp.ini
        # therefore we need to match each arg to the end of the path in line 
        # so we append [= ] to end of each arg
        $line =~ s/^(\s*[bcdefilpsvx]\s*)[^\s]*(.*$)/$1replace$2/ if ( scalar(grep { $line =~ /$_[ =]/ } @_) > 0 );
        printf PFILETMP ("$line\n");
    }
    close PFILE;
    close PFILETMP;

    # now we need to copy the file.
    if(File::Copy::copy("$tmpProtoTypeFile", "$ProtoTypeFile"))
    {
        Verbose("Updated prototype file entries to class replace");
        unlink($tmpProtoTypeFile);
    }
    else
    {
        Error("Failed to copy lib [$tmpProtoTypeFile]: $!");
    }

    return 1;

}


#------------------------------------------------------------------------------
sub createPkginfoFile
#
# Description:
#       This sub-routine is used to create the required package info.
#       Accepts any number of parameters, with each parameter taken as a literal
#       Field=Value string and inserted into the PkgInfo File
#------------------------------------------------------------------------------
{
    # lets check to see if our description has been set
    if ( $PkgDesc eq "" )
    {
        Error("Package description not set. " .
                 "Use setPkgDescription('my package description') function.");
    }

    # lets check to see if our long name has been set
    if ( $PkgNameLong eq "" )
    {
        Error("Package name not set. Use setPkgName('my package long name') function.");
    }


    # lets just check to see if we can execute this function on
    # this machine.
    #
    if ( "$MachType" ne "sparc" )
    {
        generateIShieldIncludeFile();
        return 1;
    }

    # we need to determine whiich file we are dealing with
    my ($pkginfoFile) = "$PkgInfoFile"; 

    # we need to locate the pkginfo file
    if ( -f "$pkginfoFile" )
    {
        unlink("$pkginfoFile");
        Verbose("Removing pkginfo file [$pkginfoFile].");
    }

    # lets open the pkginfo file.
    #    
    local *FILE;
    open ( FILE, "> $pkginfoFile") or
        Error("Failed to open file [$pkginfoFile].");

    # lets populate the pkginfo file.
    printf FILE ("PKG=$PkgName\n");


    # here we deal with the new version number format
    #
    printf FILE ("NAME=$PkgNameLong\n");
    printf FILE ("VERSION=$PkgVersion.$ProjectAcronym\n");
    printf FILE ("ARCH=$MachType\n");
    printf FILE ("VENDOR=$VENDOR_DESC\n");
    printf FILE ("DESC=$PkgDesc\n");
    printf FILE ("CATEGORY=$CATEGORY_DESC\n");
    printf FILE ("BASEDIR=$ERGAFC_BASEDIR\n");
    printf FILE ("TARGETBASEDIR=$TargetBaseDir\n");
    printf FILE ("CLASSES=$PkgInfoClasses\n");

    foreach my $param ( @_ )
    {
        printf FILE "$param\n";
    }

    if ( "x$PkgPatchNum" ne "x" )
    {
        my ($count)=1;
        my ($pRev)="";
        printf FILE ("MAXINST=$MAXINST\n");
        printf FILE ("SUNW_PATCHID=$PkgPatchID\n");
        printf FILE ("SUNW_REQUIRES=\n");
        printf FILE ("SUNW_INCOMPAT=\n");

        $count=1;
        $pRev="";
        printf FILE ("SUNW_OBSOLETES=");
        while ( $count < $PkgPatchNum )
        {
            $pRev = sprintf ("%02s", $count); 
            printf FILE ("$PkgPatchName" . 
                         "$PkgVersionStr" . 
                         "-" . 
                         "$pRev ");
            $count++;
        }
        printf FILE ("\n");

        $count=1;
        $pRev="";
        printf FILE ("PATCH_OBSOLETES=");
        while ( $count < $PkgPatchNum )
        {
            $pRev = sprintf ("%02s", $count); 
            printf FILE ("$PkgPatchName" . 
                         "$PkgVersionStr" . 
                         "-" . 
                         "$pRev ");
            $count++;
        }
        printf FILE ("\n");
    }

    
    # now we will list the build dependencies so
    # we can refer to them online
    #
    my ($i);
    my ($m_Str);
    # printf FILE ("\n");
    my ($count) = 1;
    foreach $i ( $BuildFileInfo->getDpkgArchiveList() )
    {
         my $moduleInfo = $BuildFileInfo->getDpkgArchiveInfo($i);
        
         printf FILE ( "$moduleInfo->{type}\_$count=$i $moduleInfo->{version}");

         # we shall print the project bit if we have one
         if ( $moduleInfo->{proj} ne "" )
         {
             printf FILE ( "\.$moduleInfo->{proj}\n");
         }
         else
         {
             printf FILE ("\n");
         }
         $count++;
    }
    close FILE;


    # lets close the pkginfo file.
    close (FILE);
    Information("Created pkginfo file [$pkginfoFile].");

    return 1;
}


#------------------------------------------------------------------------------
sub updatePrototypeFileItemOwner
#
# Description:
#       This sub-routine is used to change the ownership of a file item
#       in the prototype file.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 4 )
    {
        Error("Incorrect number of params passed to " .
                  "updatePrototypeFileItemOwner() function. Check deploy config.");
    }


    # lets just check to see if we can execute this function on
    # this machine.
    #
    if ( "$MachType" ne "sparc" )
    {
        Verbose("chmod() not supported on this machine type.");
        return 1;
    }


    # lets setup the passed values.
    my ($m_item, $m_ownPerms, $m_ownUser, $m_ownGroup) = @_;


    my ($tmpProtoTypeFile) = "/tmp/xx_prototypefile.$$";


    # lets open the prototype file if it exists
    #
    open (PFILE, "< $ProtoTypeFile") or
        Error("Failed to open prototype file [$ProtoTypeFile].");

    open (PFILETMP, "> $tmpProtoTypeFile") or
        Error("Failed to open tmp prototype file [$tmpProtoTypeFile].");

    my ($inLine);
    while ( <PFILE> )
    {
        $inLine = $_;
        chomp($inLine);
        if ( "$inLine" =~ /^f / && "$inLine" =~ /$m_item/ )
        {
            my ($b1, $b2, $b3, $b4, $b5, $b6) = split (/ /, $inLine); 
            printf PFILETMP ("$b1 $b2 $b3 $m_ownPerms $m_ownUser $m_ownGroup\n");
        }
        else
        {
            printf PFILETMP ("$inLine\n");
        }
    }
    close PFILE;
    close PFILETMP;

    # now we need to copy the file.
    if(File::Copy::copy("$tmpProtoTypeFile", "$ProtoTypeFile"))
    {
        Verbose("Copied [$tmpProtoTypeFile] to [$ProtoTypeFile] ...");
        unlink($tmpProtoTypeFile);
    }
    else
    {
        Error("Failed to copy lib [$tmpProtoTypeFile]: $!");
    }

    return 1;

}


#------------------------------------------------------------------------------
sub setPermissions
#   Called to set permissions of files/dirs in a directory structure.
#       With no options sets DirTag and all files/dirs in it to perms
#   
#   Parameters:  
#               DirTag:  The directory tag to start setting permissions on
#       
#   Required Options:
#       One or both of
#               --FilePerms=    Sets the permissions of files to this permission.
#                               If not supplied then no files have their permissions changed
#               --DirPerms=     Sets the permissions of directories to this permission
#                               If not supplied then no directories have their permissions changed
#       OR
#               --Perms=        Sets the permissions of both files and directories to this permissions
#                               Equivalent to supplying both --FilePerms=X && --DirPerms=X
#               
#   Options:
#               --Recurse       Recurse the directory tree.  Does a deptth first recurse so that all 
#                               dir entries are processed before the dir itself
#               --NoRecurse     Dont recurse, default
#               --DirTagOnly    Only sets the permissions on the DirTag directory, 
#                               all other options ignored
#               --SkipDirTag    Does not set permissions on the DirTag Directory, 
#                               obviously mutually exlusive with --DirTagOnly
#               --FilterIn=     Apply permissions to files/directories that matches this value.
#                               Perl RE's can be used (Not Shell wildcards) and this option
#                               can be supplied mulitple times
#               --FilterOut=    Dont apply permissions to any files/directories matching this value
#                               Perl RE's can be used (Not Shell wildcards) and this option
#                               can be supplied mulitple times
#               
#                               FilterIn is applied before FilterOut.  If Recurse is specified 
#                               the directory will be recursed regardless of these filters, however
#                               the filter will be applied when it comes time to chmod the dir 
#
#               --RecursedCall  Used internally to indicate a recursed call
#------------------------------------------------------------------------------
{
    my ( @filterIn, @filterOut );
    my ( @recurseArgs ) = ( "--RecursedCall" );
    my ( $dirTag, $filePerms, $dirPerms );
    my ( $recurse, $dirTagOnly, $skipDirTag, $recursedCall ) = ( 0, 0, 0, 0 );

    foreach ( @_ )
    {
        if ( m/^--Perms=(.*)/ ) 
        {
            $filePerms = $1;
            $dirPerms = $1;
            push(@recurseArgs, $_);         # Pass this on in recursive calls
        } 
        elsif ( m/^--FilePerms=(.*)/ ) 
        {
            $filePerms = $1;
            push(@recurseArgs, $_);         # Pass this on in recursive calls
        } 
        elsif ( m/^--DirPerms=(.*)/ ) 
        {
            $dirPerms = $1;
            push(@recurseArgs, $_);         # Pass this on in recursive calls
        }
        elsif ( m/^--RecursedCall/ ) 
        {
            $recurse = 1;
            $recursedCall = 1;
        } 
        elsif ( m/^--Recurse/ ) 
        {
            $recurse = 1;
        } 
        elsif ( m/^--NoRecurse/ ) 
        {
            $recurse = 0;
        } 
        elsif ( m/^--DirTagOnly/ ) 
        {
            $dirTagOnly = 1;
        } 
        elsif ( m/^--SkipDirTag/ ) 
        {
            $skipDirTag = 1;
        } 
        elsif ( m/^--FilterIn=(.*)/ ) 
        {
            push @filterIn, $1;
            push(@recurseArgs, $_);         # Pass this on in recursive calls
        } 
        elsif ( m/^--FilterOut=(.*)/ ) 
        {
            push @filterOut, $1;
            push(@recurseArgs, $_);         # Pass this on in recursive calls
        } 
        else 
        {
            $dirTag = $_;
        }
    }

    Error("SetPermissions called with out DirTag parameter") if ( !defined($dirTag) );
    Error("SetPermissions called with out any Permission options") if ( !defined($filePerms) && !defined($dirPerms) );
    Error("SetPermissions: Options --DirTagOnly & --SkipDirTag are mutually exclusive" ) if ( $dirTagOnly && $skipDirTag );
    # Sanity check for internal recursed calls, cant have --DirTagOnly or --NotDirTag on recursed calls
    Error("SetPermissions Internal Error:  Recursively called with --DirTagOnly or --SkipDirTag")
        if ( $recursedCall && ( $dirTagOnly || $skipDirTag ) );

    # lets just check to see if the perms are in correct format.
    #
    if ( (defined($filePerms) && $filePerms !~ m/^\d{4}$/) || (defined($dirPerms) && $dirPerms !~ m/^\d{4}$/) )
    {
        Error("setPermissions called with invalid permissions format");
    }

    # if there is no filterIn set the first element of filterIn to match evrything
    push(@filterIn, '^.*$') if ( $#filterIn == -1 );
    # if there is no filterOut set the first element of filterOut to emtpy string which should not match anything
    push(@filterOut, '') if ( $#filterOut == -1 );


    # if recursed call then dirTag is already a path, otherwise get path for dirTag
    my ($topDir) = ( $recursedCall ) ? $dirTag : getTargetDstDirValue($dirTag, "A");

    if ( $dirTagOnly )
    {
        Error("SetPermissions:  --DirPerms or --Perms not supplied for setting perms with --DirTagOnly") 
            if ( ! defined($dirPerms) );
        Information("SetPermissions: Setting permissions on top level dir only [$topDir] to " . $dirPerms);
        chmodFile($topDir, $dirPerms);
        return;
    }

    if ( $recursedCall )
    {
        Debug2("SetPermissions: Processing Dir $topDir");
    }
    else
    {
        Information("SetPermissions: Called with options " . join(", ", @_));
    }

    local *DIR;
    opendir(DIR, $topDir) or Error("SetPermissions: Error opening dir $topDir: $!");

    my ($dirEntry, $fullPath);
    while (defined($dirEntry = readdir(DIR)))
    {
        next if ( $dirEntry =~ /^\.{1,2}$/ );   # skip . & ..
        
        $fullPath = "$topDir/$dirEntry";

        # if we have a dir and recurse is on then recurse into it first
        if ( -d $fullPath && $recurse )
        {
            # This dirs permissions will be set at the end of this call
            setPermissions($fullPath, @recurseArgs);
        }
        # else a dir and we dont have dirperms, so skip
        elsif ( -d $fullPath && !defined($dirPerms) )
        {
            Debug2("SetPermissions: Skipping dir $fullPath as we have no dir permissions");
        }
        # else a file and we dont have fileperms, so skip
        elsif ( -f $fullPath && !defined($filePerms) )
        {
            Debug2("SetPermissions: Skipping file $fullPath as we have no file permissions");
        }
        # else a file or a dir and have the right permissions and we are not recursing
        elsif ( -f $fullPath || -d $fullPath )
        {
            my $matchIn  = grep { $dirEntry =~ /$_/ } @filterIn;
            my $matchOut = grep { $dirEntry =~ /$_/ } @filterOut;

            if ( $matchIn > 0 && $matchOut == 0 )
            {
                chmodFile($fullPath, ( -f $fullPath ) ? $filePerms : $dirPerms);
            }
            else
            {
                Debug2("SetPermissions: Skipping element $fullPath on non filter match, (In,Out) = (" . $matchIn . "," . $matchOut . ")" );
            }
        }
        else
        {
            Warning("SetPermissions: Skipping $fullPath as its not a file or directory");
        }
    }
    close (DIR);

    # lets deal with topDir
    # If --SkipDirTag is on then we skip this, this is only applicable to first call, not recursed calls
    if ( !$skipDirTag && defined($dirPerms) )
    {
        $dirEntry = basename($topDir);
        my $matchIn  = grep { $dirEntry =~ /$_/ } @filterIn;
        my $matchOut = grep { $dirEntry =~ /$_/ } @filterOut;

        if ( $matchIn > 0 && $matchOut == 0 )
        {
            chmodFile($topDir, $dirPerms);
        }
        else
        {
            Debug2("SetPermissions: Skipping dir $topDir on non filter match, (In,Out) = (" . $matchIn . "," . $matchOut . ")" );
        }
    }
    else
    {
        Debug2("SetPermissions: Skipping dir $topDir " . 
              (($skipDirTag) ? "because of --SkipDirTag option" : "as we have no dir permissions") );
    }
}   # setPermissions


#------------------------------------------------------------------------------
sub chmod
#
# Description:
#       This sub-routine is used to change the ownership of a file or
#       directory structure.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    Error("Incorrect number of params passed to chmod() function. Check deploy config.") if ( ($#_+1) != 3 );

    # lets setup the passed values.
    my ($m_sDirTag, $m_sfile, $m_ownPerms) = @_;

    Warning("chmod has been deprecated by and now calls setPermissions, see deploylib.pm");

    # call setPermissions, if no File then do DirTagOnly, otherwise set FilterIn=File
    setPermissions($m_sDirTag, "--NoRecurse", "--Perms=$m_ownPerms", 
                    ($m_sfile eq "") ? "--DirTagOnly" : "--FilterIn=$m_sfile" );

    return 1;
}


#------------------------------------------------------------------------------
sub chmodRecursive
#
# Description:
#       This sub-routine is used to change the permissions recursively in
#       the target packgae.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    Error("Incorrect number of params passed to chmodRecursive() function. Check deploy config.") if ( ($#_+1) != 2 );

    # lets setup the passed values.
    my ($m_sDirTag, $m_ownPerms) = @_;

    Warning("chmodRecursive has been deprecated by and now calls setPermissions, see deploylib.pm");

    # call setPermissions, if no File then do DirTagOnly, otherwise set FilterIn=File
    setPermissions($m_sDirTag, "--Recurse", "--Perms=$m_ownPerms");

    return 1;
}




#------------------------------------------------------------------------------
sub chmodDir
#
# Description:
#       This sub-routine is used to change the permissions an entire directory tree.
#
#       It recurses from a starting point chmod'ing each item and if it
#       finds a dir it recurses into that dir chmod'ing it as well.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    Error("Incorrect number of params passed to chmodDir() function.") if ( ($#_+1) != 2 );

    my ($startingPoint, $perms) = @_;

    Warning("chmodDir has been deprecated by setPermissions, see deploylib.pm");

    Verbose("chmodDir: Recursively setting permsision of [$startingPoint] to [$perms]");

    local *DIR;
    opendir(DIR, $startingPoint) or Error("can't opendir $startingPoint: $!");

    my ($item);
    while (defined($item = readdir(DIR)))
    {
        if ( "$item" !~ /^\.$/  && "$item" !~ /^\.\.$/ )
        {
            if ( -d "$startingPoint/$item" )
            {
                chmodDir("$startingPoint/$item", $perms);
            }
            else
            {
                chmodFile("$startingPoint/$item", $perms);
            }
        }
    }
    close (DIR);

    # lets deal with starting dir
    # 
    chmodFile("$startingPoint", $perms);

    return 1;
}



#------------------------------------------------------------------------------
sub chmodFile
#
#    this function is used to chmod the perms od an item
#    it is passed the absolute path to the item and the associated 
#    perms.
#
#------------------------------------------------------------------------------
{
    my ($item, $perms) = @_;

    my ($noItems) = CORE::chmod oct($perms), $item;
    if ( $noItems == 0 )
    {
        Error("ERROR: Failed to chmod $item=$perms, retVal=[$noItems]");
    }
    else
    {
        Debug("Successfully chmod $item=$perms");
    }

    return 1;
}



#------------------------------------------------------------------------------
sub createSymbolicLink
#
# Description:
#       This sub-routine is used to copy a local deployment file into
#       the target destination dir. 
#
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 3 )
    {
        Error("Incorrect number of params passed to " .
                  "createSymbolicLink() function. Check deploy config.");
    }


    # lets just check to see if we can execute this function on
    # this machine.
    #
    if ( "$MachType" ne "sparc" )
    {
        Verbose("createSymbolicLink() not supported on this machine type.");
        return 1;
    }


    # lets setup the passed values.
    my ($m_sDirTag, $m_srcStr, $m_linkStr) = @_;

    # lets get the absolute src dir value
    my ($m_sDirAbsoluteValue) = getTargetDstDirValue($m_sDirTag, "A");


    # lets see if the source item exists
    #
    if ( ! -f "$m_sDirAbsoluteValue/$m_srcStr" )
    {
        Error("Failed to locate item [$m_sDirAbsoluteValue/$m_srcStr], link not created.");
    }



    my ($cmd) = "cd $m_sDirAbsoluteValue; ln -s $m_srcStr $m_linkStr";
    system("$cmd");
    if ( $? != 0 )
    {
        Error("Failed to complete command: [$cmd]");
    }
    else
    {
        Verbose("Executed command: [$cmd]");
    }

    return 1;
}


#------------------------------------------------------------------------------
sub createPrototypeFile2
#
# Description:
#       This sub-routine is used to create the required package prototype file
#       fom a known directory struture using the a=b format.
#
#------------------------------------------------------------------------------
{
    my ($opt_keep_mask, @args);

    #
    #   Process the arguments and extract parameters and options
    #
    foreach ( @_ )
    {
        if ( m/^--KeepMask/ ) {
            $opt_keep_mask = 1;

        } elsif ( m/^--/ ) {
            Error("createPrototypeFile2: Unknown option: $_")

        } else {
            push @args, $_;

        }
    }

    # correct number of parameters?
    if ( ($#args + 1) != 3 )
    {
        Error("Incorrect number of params passed to " .
                  "createPrototypeFile2() function. Check deploy config.");
    }

    # lets just check to see if we can execute this function on
    # this machine.
    #
    if ( "$MachType" ne "sparc" )
    {
        Verbose("createPrototypeFile2() not supported on this machine type.");
        return 1;
    }

    # lets take the passed in args.
    my ($uid, $gid, $mask) = @args;


    # we need to determine whiich file we are dealing with
    my ($protoTypeFile);
    my ($targetBaseDir);
    my ($pkgBaseDir);
    $protoTypeFile = "$ProtoTypeFile"; 
    $targetBaseDir = "$PkgBaseDir/$TargetBaseDir"; 
    $pkgBaseDir    = "$PkgBaseDir"; 


    # we need to locate the prototype file
    if ( -f "$protoTypeFile" )
    {
        unlink("$protoTypeFile");
        Verbose("Removing prototype file [$protoTypeFile].");
    }

    # lets open the prototype file.
    #    
    local *FILE;
    open ( FILE, "> $protoTypeFile") or
        Error("Failed to open file [$protoTypeFile].");
    # lets populate the prototype file.
    printf FILE ("!default $mask $uid $gid\n");
    printf FILE ("i pkginfo\n");
    close (FILE);


    # lets put the pre-deinfed generic entries into the
    # prototype file
    #
    if ( "x$PkgPatchNum" ne "x" )
    {
        addPatchInfo2ProtoTypeFile();
    }


    # lets set the associated uid, gid and mask
    # for the bits in the prototype file.
    #
    $m_UID  = $uid;
    $m_GID  = $gid;
    $m_MASK = $mask;
    $m_KEEP_MASK = $opt_keep_mask;


    # now we need to add entries for each directory we will 
    # be installing 
    File::Find::find(\&prototype2Find, "$targetBaseDir");


    # lets populate the prototype file with a newline.
    open ( FILE, ">> $protoTypeFile") or
        Error("Failed to open file [$protoTypeFile].");
    printf FILE ("\n");
    close (FILE);


    Information("Created prototype file [$protoTypeFile].");

    return 1;
}

#-------------------------------------------------------------------------------
# Function        : createZip
#
# Description     : Create a ZIp file of a given directory
#
# Inputs          : --Recurse               - Recurse subdirs
#                   --NoRecurse             - Done recurse subdirs
#                   --Dirnames              - Record Dir names
#                   --NoDirnames            - Don't record dirnames
#                   --NoQuiet               - Display the operatios
#                   --Dir=xxxx              - Symbolic Directory to zip
#                   --ZipDir=ttt            - Symbolic target directory
#                   --ZipFile=yyyy          - Zipfile to create
#
# Returns         : Will not return on error
#                   Requires 'zip' to be provided by a 'package' such as InfoZip
#
sub createZip
{
    my $recurse = 1;
    my $dirnames = 0;
    my $quiet = 1;
    my $sdir;
    my $tdir;
    my $tfile;

    #
    #   Only on Windows at the moment.
    #   Perhaps Unix should create a .gz file
    #
    Warning ("createZip not supported on $MachType. Operation skipped")
        unless ( "$MachType" eq "win32" );

    #
    #   Process user arguments
    #
    foreach ( @_ )
    {
        if ( m/^--Recurse/ ) {
            $recurse = 1;

        } elsif ( m/^--NoRecurse/) {
            $recurse = 0;

        } elsif ( m/^--Dirnames/ ) {
            $dirnames = 1;

        } elsif ( m/^--NoDirnames/ ) {
            $dirnames = 0;

        } elsif ( m/^--NoQuiets/ ) {
            $quiet = 0;

        } elsif ( m/^--Dir=(.*)/ ) {
            $sdir = $1;

        } elsif ( m/^--ZipDir=(.*)/ ) {
            $tdir = $1;
            
        } elsif ( m/^--ZipFile=(.*)/ ) {
            $tfile = $1;
            
        } else {
            Warning("createZip: Unknown argument ignored: $_");

        }
    }

    #
    #   Convert the source directory TAG into a real directory
    #
    Error ("createZip: Source directory not specified") unless ( $sdir );
    my $sdir_a = getTargetDstDirValue($sdir, "A");

    #
    #   Convert the destination directory tag into a real directory
    #
    Error ("createZip: Target directory not specified") unless ( $tdir );
    Error ("createZip: Target filename not specified") unless ( $tfile );
    my $tdir_a = getTargetDstDirValue($tdir, "A");

    #
    #   Locate the 'zip' uitilty
    #
    my $prog = LocateProgInPath( 'zip' );
    Error ("createZip: Cannot locate ZIP executable",
            "May need to use the 'infozip' package") unless ( $prog );

    #
    #   Generate command file
    #
    my $args = '-9';
    $args .= 'q' unless ( (! $quiet) || IsVerbose(1));
    $args .= 'r' if ( $recurse );
    $args .= 'j' unless ( $dirnames );

    #
    #   Zip up the files
    #
    Information ("Create Zip File: [$tdir] $tfile");
    chdir ( $sdir_a ) || Error ("Cannot cd to $sdir_a");
    my $rv = System ($prog, $args, "$tdir_a/$tfile", "." );
    chdir($CurrentDir) || Error ("Cannot cd to $CurrentDir");

    Error ("createZip: Zip file not created") if ( $rv );
}


#------------------------------------------------------------------------------
sub prototype2Find
#
#    Description:
#        This subroutine is used to locate all associated package dirs.
#        It also adds an entry into the prototype file for each dir.
#
#------------------------------------------------------------------------------
{
    my $file = $File::Find::name;
    my $fullfile = $file;
    my $base = File::Basename::basename($file);

    # we get the absolute path from the find, but we only require
    # a relative path from the starting dir.
    # so our start dir.

    # we need to determine which file we are dealing with
    my ($pfile);
    my ($tDir);
    $pfile = "$ProtoTypeFile";
    $tDir = "$PkgBaseDir/$TargetBaseDir";

    if ( "$file" ne "$tDir" )
    {
        my ($m_sfile) = $file;
        if ( "x$TargetBaseDir" eq "x." )
        {
            $tDir = $tDir . "/";
            $file =~ s/$tDir//;
        }
        else
        {
            $file =~ s/$tDir/$TargetBaseDir/;
        }

        # if TargetBaseDir is "." then find will find the pkginfo & prototype 
        # files so we need to exclude them
        if ( "$file" ne "$ProtoTypeFileName" &&
             "$file" ne "$PkgInfoFileName")
        {

            my $fmask = $m_MASK;
            if ( $m_KEEP_MASK )
            {
                $fmask = sprintf "%lo", ( (stat($fullfile))[2]) & 07777;
            }

            open ( FILE, ">> $pfile") or
                Error("Failed to open file [$pfile].");

            if ( -f "$m_sfile" )
            {
                printf FILE ("f none $file=$file $fmask $m_UID $m_GID\n");
            }

            if ( -d "$m_sfile" )
            {
                printf FILE ("d none $file $fmask $m_UID $m_GID\n");
            }

            close (FILE);
        }
    }
}

#-------------------------------------------------------------------------------
# Function        : convertFile
#
# Description     : This sub-routine is used to remove all carrage return\line
#                   feeds from a line and replace them with the platform
#                   specific equivalent chars.
#
#                   We let PERL determine what characters are written to the
#                   file base on the  platform you are running on.
#
#                   i.e. LF    for unix
#                   CR\LF for win32
#
# Inputs          : m_targetDirTag          - Symbolic name of target directory
#                   m_nfiles                - List of files in that directory
#                   or
#                   SearchOptions           - Search options to find files
#                                           --Recurse
#                                           --NoRecurse
#                                           --FilterIn=xxx
#                                           --FilterInRE=xxx
#                                           --FilterOut=xxx
#                                           --FilterOutRE=xxx
#
#
# Returns         : 1
#
sub convertFile
{
    my @uargs;
    my $search =  LocateFiles->new( recurse => 0 );

    #
    #   Process user arguments extracting options
    #
    foreach  ( @_ )
    {
        if ( m~^--Recurse~ ) {
            $search->recurse(1);

        } elsif ( m~^--NoRecurse~) {
            $search->recurse(0);

        } elsif ( /^--FilterOut=(.*)/ ) {
            $search->filter_out($1);

        } elsif ( /^--FilterOutRE=(.*)/ ) {
            $search->filter_out_re($1);

        } elsif ( /^--FilterIn=(.*)/ ) {
            $search->filter_in($1);

        } elsif ( /^--FilterInRE=(.*)/ ) {
            $search->filter_in_re($1);

        } elsif ( m~^--~) {
            Error ("convertFile: Unknown option: $_");

        } else {
            push @uargs, $_;
        }
    }

    #
    #   Process non-option arguments
    #       - Base dir
    #       - List of files
    #
    my ($m_targetDirTag, @m_nfiles) = @uargs;
    Error ("convertFiles: Target Dir must be specified" ) unless ( $m_targetDirTag );

    #
    # Convert symbolic dir tag to physical path
    #
    my ($m_targetDirValue) = getTargetDstDirValue($m_targetDirTag, "A");

    #
    #   Need to determine if we are searching or simply using a file list
    #   There are two forms of the functions. If any of the search options have
    #   been used then we assume that we are searchine
    #
    if ( $search->has_filter() )
    {
        Error ("convertFiles: Cannot mix search options with named files") if ( @m_nfiles );
        @m_nfiles = $search->search($m_targetDirValue);
    }
    Error ("convertFiles: No files specified") unless ( @m_nfiles );

    #
    #   Process all named files
    #
    foreach my $m_nfile ( @m_nfiles )
    {

        # this is our file that we want to clean.
        my ($m_ifileLoc) = "$m_targetDirValue/$m_nfile";
        my ($m_tfileLoc) = "$m_targetDirValue/$m_nfile\.tmp";


        # we will check to see if the file exists.
        #
        local *IFILE;
        local *TFILE;
        if ( -f "$m_ifileLoc" )
        {
            open (IFILE, "< $m_ifileLoc" ) or
                Error("Failed to open file [$m_ifileLoc] : $!");

            open (TFILE, "> $m_tfileLoc" ) or
                Error("Failed to open file [$m_tfileLoc] : $!");

            while ( <IFILE> ) 
            {
                chomp;
                print TFILE "$_\n";
            }
        }
        else
        {
            Error("Deploy file [$m_ifileLoc] does not exist.");
        }

        close IFILE;
        close TFILE;


        # lets replace our original file with the new one
        #
        if(File::Copy::move("$m_tfileLoc", "$m_ifileLoc"))
        {
            Information("Renamed [$m_tfileLoc] to [$m_ifileLoc] ...");
        }
        else
        {
            Error("Failed to rename file [$m_tfileLoc] to [$m_ifileLoc]: $!");
        }
    }

    return 1;
}

#-------------------------------------------------------------------------------
# Function        : installDeployFile
#
# Description     : This sub-routine is used to copy a local deployment file into
#                   the target destination dir.
#
# Inputs          : m_srcDirTag             - Tag for Source Dir name
#                                             Tag defined in %LocalSrcDirStructure
#                                             Or --Package=name,subdir
#                                             Or --Interface=subdir
#
#                   m_sfile                 - Name of the source file
#                   m_targetDirTag          - Tag for the target directory
#                                             Tag defined in %TargetDstDirStructure
#                   m_nfile                 - Target filename
#                                             Must be specified. If set to "", then
#                                             the source filename will be used.
#
# Returns         : True
#
#------------------------------------------------------------------------------

sub installDeployFile
{
    # correct number of parameters?
    if ( ($#_+1) != 4 )
    {
        Error("Incorrect number of params passed to " .
                  "installDeployFile() function. Check deploy config.");
    }

    my ($m_srcDirTag, $m_sfile, $m_targetDirTag, $m_nfile) = @_;

    # lets get the src dir value
    my ($m_targetDirValue) = getTargetDstDirValue($m_targetDirTag, "A");

    # lets get the target dir value
    my ($m_srcDirValue) = getLocalDirValue($m_srcDirTag, "A");


    # we know where we are getting this from and where we 
    # going to put them.
    my ($m_sfileLoc) = "$m_srcDirValue/$m_sfile";

    my ($m_nfileLoc) = "";
    # lets determine what we are going to call the new file.
    #
    if ( "x$m_nfile" eq "x" )
    {
        $m_nfileLoc = "$m_targetDirValue/$m_sfile";
    }
    else
    {
        $m_nfileLoc = "$m_targetDirValue/$m_nfile";
    }


    # we will check to see if the file exists.
    #
    if ( -f "$m_sfileLoc" )
    {
        # now we need to copy the file. 
        if(File::Copy::copy("$m_sfileLoc", "$m_nfileLoc"))
        {
            Verbose("Copied [$m_sfile] to [$m_nfileLoc] ...");

            # now we need to ensure the item is writable as it
            # has come from our VOB that is by definition read-only
            #
            CORE::chmod oct("0755"), $m_nfileLoc;

        }
        else
        {
            Error("Failed to copy lib [$m_sfileLoc]: $!"); 
        }
    }
    else
    {
        Error("Deploy file [$m_sfileLoc] does not exist.");
    }

    return 1;
}


#------------------------------------------------------------------------------
sub getGenericNameForLib
#
# Description:
#       This sub-routine is used to determine the generic name for
#       a library. I.E remove the buildtype and version number.
#
#       It also checks if the name provided should be excluded from
#       the build.
#
#------------------------------------------------------------------------------
{
   # correct number of parameters?
    if ( ($#_+1) != 1 )
    {
        Error("Incorrect number of params passed to " .
                  "getGenericNameForLib() function. Check deploy config.");
    }

    # lets just check to see if we can execute this function on
    # this machine.
    #
    if ( "$MachType" ne "sparc" )
    {
        Verbose("getGenericNameForLib() not supported on this machine type.");
        return "";
    }


    my($itemName) = @_;

    # first we need to check to see if it belongs in this build
    #
    my ($gName) = "";
    if(excludeItemFromBuild($itemName))
    {
        Verbose("Excluding item [$itemName] from build as not compatible with build type " .
                "[$BuildType].");
        return "";  # file should be excluded.
    }
    else
    {
        $gName = removeBuildTypeFromItemName($itemName);
        $gName = removeVersionNumberFromItemName($gName);

        return "$gName";
    }

    return 1;
}


#------------------------------------------------------------------------------
sub getGenericNameNoVersionForLib
#
# Description:
#       This sub-routine is used to determine the generic name for
#       a library. I.E removes the version number.
#
#       It also checks if the name provided should be excluded from
#       the build.
#
#------------------------------------------------------------------------------
{
   # correct number of parameters?
    if ( ($#_+1) != 1 )
    {
        Error("Incorrect number of params passed to " .
                  "getGenericNameNoVersionForLib() function. Check deploy config.");
    }

    # lets just check to see if we can execute this function on
    # this machine.
    #
    if ( "$MachType" ne "sparc" )
    {
        Verbose("getGenericNameNoVersionForLib() not supported on this machine type.");
        return "";
    }


    my($itemName) = @_;

    # first we need to check to see if it belongs in this build
    #
    my ($gName) = "";
    if(excludeItemFromBuild($itemName))
    {
        Verbose("Excluding item [$itemName] from build as not compatible with build type " .
                "[$BuildType].");
        return "";  # file should be excluded.
    }
    else
    {
        $gName = removeVersionNumberFromItemName($itemName);
        return "$gName";
    }

    return 1;
}


#------------------------------------------------------------------------------
sub getGenericNameNoVersionForXML
#
# Description:
#       This sub-routine is used to determine the generic name for
#       an XML file. I.E removes the version number.
#
#------------------------------------------------------------------------------
{
   # correct number of parameters?
    if ( ($#_+1) != 1 )
    {
        Error("Incorrect number of params passed to " .
                  "getGenericNameNoVersionForXML() function. Check deploy config.");
    }

    my($itemName) = @_;
    my ($gName) = "";
    $gName = removeVersionNumberFromXMLItemName($itemName);
    return "$gName";

    return 1;
}


#------------------------------------------------------------------------------
sub removeVersionNumberFromXMLItemName
#
#    Description:
#        This sub-routine is used to remove the version number from the item name.
#        i.e.  myFile_1_2_3.xml ==> myFile.xml
#
#    INPUT:
#        item name
#
#    RETURN:
#        new item name.
#
#------------------------------------------------------------------------------
{
    my ($file)  = @_;
    my ($nfile) = $file;

    if ( $nfile =~ m/_[0-9]+_[0-9]+_[0-9]+\.xml$/ )
    {
        # if we match lets deal with it.
        $nfile =~ s/_[0-9]+_[0-9]+_[0-9]+\.xml$/\.xml/;
    }
    else
    {
        Warning("Filename [$nfile] does not contain required format [myfile_N_N_N.xml].");
    }
    return "$nfile";
}


#------------------------------------------------------------------------------
sub createDpkgArchive
#
# Description:
#       This sub-routine is used to create a dpkg_archive directory
#       structure.
#
#------------------------------------------------------------------------------
{
    # correct number of parameters?
    if ( ($#_+1) != 1 )
    {
        Error("Incorrect number of params passed to " .
                  "createDpkgArchive() function. Check deploy config.");
    }

    my ($desc) = @_;

    # lets just check to see if we can execute this function on
    # for  this build.
    #
    if ( "x$PkgPatchNum" ne "x" )
    {
        Verbose("createDpkgArchive() can only be called during a RELEASE build.");
        return 1;
    }


    # 1. we create a dpkg_archive top level dir within the output directory
    #
    my ($m_tmpDir) = "$PkgBaseDir/dpkg_archive";
    make_directory( $m_tmpDir, 0777 );

    # 2. we create a sub-directory with the package name
    #
    $m_tmpDir = "$PkgBaseDir/dpkg_archive/$TargetBaseDir";
    make_directory( $m_tmpDir, 0777 );

    # 3. we create a sub-directory with the package version number
    #
    my ($m_tmpDir2) = "$PkgBaseDir/dpkg_archive/$TargetBaseDir/" .
                      "$PkgVersion" .  "." . "$ProjectAcronym";
    make_directory( $m_tmpDir2, 0777 );


    # 4. we replacate the contents of the original outputdir/package name
    #    to do this we shall execute a find starting within the original package target dir
    #    any copy all items we find to the new location under the dpkg_archive/package/version dir.
    #
    File::Find::find( \&DpkgFind, "$PkgBaseDir/$TargetBaseDir");


    # 5. we create a descpkg file, with the Package Name, Version and Desc
    #
    my ($m_DescPkgFile) = "$PkgBaseDir/dpkg_archive/$TargetBaseDir/$PkgVersion\.$ProjectAcronym/descpkg";

    # now we need to update the prototype file
    #
    local *FILE;
    open ( FILE, ">> $m_DescPkgFile") or
        Error("Failed to open file [$m_DescPkgFile].");
    printf FILE ("$PkgName, $PkgVersion.$ProjectAcronym - $desc\n");
    close (FILE);
   

    # done.
    Information("createDpkgArchive() completed.");

    return 1;
}


#------------------------------------------------------------------------------
sub DpkgFind
#
#    Description:
#        This subroutine is used to locate all associated items to
#        create a new dpkg_archive directory structure. 
#
#------------------------------------------------------------------------------
{
    my($item)= "$File::Find::name";
    my($base)= File::Basename::basename($item);


    # we get the absolute path from the find, but we only require
    # a relative path from the starting dir.


    # we need to determine which file we are dealing with
    if ( ! -d "$item")
    {
        my ($m_sfile) = $item;
        $item =~ s/$PkgBaseDir\/$TargetBaseDir/$PkgBaseDir\/dpkg_archive\/$TargetBaseDir\/$PkgVersion\.$ProjectAcronym/;

        if(File::Copy::copy("$m_sfile", "$item"))
        {
            Verbose("Copied [$base] to [$item] ...");
        }
        else
        {
            Error("Failed to copy pkg file [$m_sfile] to [$item]: $!");
        }
    }
    else
    {
        # we have found a dir
        my ($m_sDir) = $item;
        $item =~ s~$PkgBaseDir/$TargetBaseDir~$PkgBaseDir/dpkg_archive/$TargetBaseDir/$PkgVersion\.$ProjectAcronym~;
        make_directory( $item, 0777 );
    }
}




#------------------------------------------------------------------------------
sub getRmDetails
#
#    Description:
#        This is called to update the RM class objects with details from RM database
#------------------------------------------------------------------------------
{
    #
    #   If this script is invoked by the AutoBuildTool, then we may not be able
    #   to create a Release Note as the RM entry may not be available. More over
    #   the ABT will create a release note as the package is made official
    #
    if ( $autobuild )
    {
        Debug('getRmDetails: AutoBuild Environment supresses function');
        return;
    }


    if ( ! defined($RmPkgDetails) )
    {
        # Set defaults for elements in RM if not found
        DeployUtils::RmPkgInfo->DefaultDescription($PkgDesc);
        DeployUtils::RmPkgInfo->DefaultLabel($PkgLabel);

        $RmPkgDetails = DeployUtils::RmPkgInfo->new( 
                                    { PKG_NAME => $PkgName, 
                                      PKG_VERSION => ( "$PkgPatchNum" ne "" ) ? $PkgPatchID : $PkgVersionUser } );

        # lets check to see if we got something
        if ( $RmPkgDetails->foundPkg() )
        {
            $RmPvPkgDetails = DeployUtils::RmPkgInfo->new( { PKG_NAME => $PkgName, 
                                                             PKG_VERSION => $PkgPreviousVersionStr } );
            if ( $RmPvPkgDetails->foundDetails() )
            {
                sub MultiLineVerb
                {
                    my ($prefix, $text ) = @_;
                    my $zap = 0;

                    foreach my $line ( split /[\r\n]+/, $text  )
                    {
                        Verbose($prefix . "[" . $line . "]");
                        unless ( $zap )
                        {
                            $prefix = ' ' x length($prefix);
                            $zap = 1;
                        }
                    }
                }

                Information("Retrieved Package Details from Release Manager");
                if ( IsVerbose(1) )
                {
                    MultiLineVerb("RM pkg_name       = ",  $RmPkgDetails->pkg_name()       );
                    MultiLineVerb("RM pkg_id         = ",  $RmPkgDetails->pkg_id()         );
                    MultiLineVerb("RM pv_id          = ",  $RmPkgDetails->pv_id()          );
                    MultiLineVerb("RM pv_description = ",  $RmPkgDetails->pv_description() );
                    MultiLineVerb("RM pv_overview    = ",  $RmPkgDetails->pv_overview()    );
                    MultiLineVerb("RM pv_reason      = ",  $RmPkgDetails->pv_reason()      );
                    MultiLineVerb("RM pv_label       = ",  $RmPkgDetails->pv_label()       );
                    MultiLineVerb("RM previousPv_id  = ",  $RmPvPkgDetails->pv_id()        );
                    MultiLineVerb("RM pv_dlocked     = ",  $RmPvPkgDetails->pv_dlocked()   );
                }
            }
            else
            {
                # our package does not exist in release manager
                Warning("Could not retrieve package $PkgName $PkgVersionUser previous version " .
                        "details from Release Manager.")
            }
        }
        else
        {
            # our package does not exist in release manager 
            Warning("Package $PkgName $PkgVersionUser does not exist in the Release Manager",
                    "Please check configuration.")
        }
    }
}  



# This is now depricated
sub generateReleaseNote
{
    Error("generateReleaseNote is depricated please use generateHtmlReleaseNote");
    return 1;
}



#------------------------------------------------------------------------------
sub generateHtmlReleaseNote
#
#    Description:
#
#------------------------------------------------------------------------------
{

    #
    #   If this script is invoked by the AutoBuildTool, then we may not be able
    #   to create a Release Note as the RM entry may not be available. More over
    #   the ABT will create a release note as the package is made official
    #
    if ( $autobuild )
    {
        Warning('AutoBuild Environment. Release notes generated later');
        return;
    }

    #
    #   Ensure the Release directory is present
    #
    make_directory( $ReleaseDir, 0777 );

    if ( ! getRmReleaseNote() )
    {
        Error("No Release Manager details, release note not generated.");
    }
}



#------------------------------------------------------------------------------
sub getRmReleaseNote
#
#    Description:
#
#------------------------------------------------------------------------------
{
    # lets get some details for our package
    getRmDetails();


    # now we need to ensure that our local build file dependencies are
    # the same as those we have entered in the Release Manager database.
    checkDependencies();


    # let's update the release contents now
    #
    generateProductContents();

    #
    #   Is the interface available
    #
    unless ( $UserAgentAvailable )
    {
        Warning("Unable to retrieve Release Manager Release Notes: LWP module missing");
        return 0;
    }

    our $GBE_RM_URL;
    EnvImport('GBE_RM_URL');
    
    Information("Retrieving Release Notes From Release Manager...Please wait...");

    my $user_agent = LWP::UserAgent->new( timeout => 30 );
    my $response = $user_agent->get( $GBE_RM_URL . '/_adhoc_release_notes.asp?pv_id='. $RmPkgDetails->pv_id(),
                                    ':content_file' => "$PkgReleaseNote\.html");
    if ( $response->is_success )
    {
        Verbose("Retrieved Release Manager HTML Release note [$PkgReleaseNote\.html]");
        return 1;
    }
    else
    {
        Warning("Unable to retrieve Release Manager Release Notes");
        return 0;
    }
}

#------------------------------------------------------------------------------
sub checkDependencies
#
#------------------------------------------------------------------------------
{
    my ($i);
    my ($retValue) = 0;
    
    # first we want to loop through all our local build archives
    # 
    my ($versionStr) = "";
    foreach $i ( $BuildFileInfo->getDpkgArchiveList() )
    {
        my $moduleInfo = $BuildFileInfo->getDpkgArchiveInfo($i);
        
        $versionStr = "$moduleInfo->{version}"; 
        $versionStr .= "\.$moduleInfo->{proj}" if ( $moduleInfo->{proj} ne "" );
        my $depObj = $RmPkgDetails->getDependencyObject($i);

        if ( defined ( $depObj ) )
        {
            if ( $depObj->pkg_version() ne "$versionStr" )
            {
                Warning("Dependency difference, [$i] Local version $versionStr, RM version " . $depObj->pkg_version());
                $retValue = 1;
            }
        }  
        else
        {
            Warning("Dependency difference, [$i] Cannot locate archive in Release Manager database.");
            $retValue = 1;
        }
    }

    # lets check to see if we detected a difference 
    if ( $retValue != 0 )
    { 
        Error("Difference detected between the local build.pl and Release Manager config.",
              "Please check Release Manager configuration.");
    }



    # now we check release manager details against our local ones
    #
    foreach $i ( $RmPkgDetails->getDependencyNames() )
    {
        if ( "$i" eq "ishieldlibimg" || "$i" eq "ishieldlibicon" )
        {
            # these two packages are a special case,
            # we do not include them in the dependecy check
            #
            next;
        }

        my $moduleInfo = $BuildFileInfo->getDpkgArchiveInfo($i);

        if ( defined ( $moduleInfo ) )
        {
            $versionStr = "$moduleInfo->{version}"; 
            $versionStr .= "\.$moduleInfo->{proj}" if ( $moduleInfo->{proj} ne "" );
            my $depObj = $RmPkgDetails->getDependencyObject($i);

            if ( $depObj->pkg_version() ne "$versionStr" )
            {
                Warning("Dependency difference, [$i] local version $versionStr, RM version " . $depObj->pkg_version());
                $retValue = 1;
            }
        }  
        else
        {
            Warning("Dependency difference, cannot locate archive [$i] in local build.pl.");
            $retValue = 1;
        }
    }

    # lets check to see if we detected a difference 
    if ( $retValue != 0 )
    { 
        Error("Difference detected between Release Manager config and the local build.pl. ",
               "Please check the local configuration.");
    }

    return 1;
}

#-------------------------------------------------------------------------------
# Function        : generateXmlDependancy
#
# Description     : Generate an XML file that describes the despendencies of the
#                   released package.
#
#                   The generated file needs to be packaged for deployment. This
#                   function will only create the file. It needs to be added to the
#                   files that are deployed into the field. The file is primarily
#                   to be used by Windows based applications, but its use may be
#                   extended to other platforms.
#
#                   The file 'should' be deployed in the same directory as the main
#                   application executable, so that the executable may locate it.
#
#                   The XML file is named after the package. It is prefixed with
#                   the string "PkgInfo_".
#
#                   By default file will be placed in the 'TargetBaseDir'.
#                   This behaviour may be modified by the user.
#
#                   Refer to package_info.xsd for details on the structure of the
#                   generated XML file. Do not randomly chnage the structure.
#                   It is being used.
#
#                   This function requires access to Release Manager in order
#                   to locate the package description and build-time information
#
#                   The function will use the current/last version of the package
#                   in an attempt to locate package information.
#
#
# Inputs          : platform        - Platforms for which the file will be created
#                                     '*' indicate ALL platforms.
#                   options         - Options to control the detail of the generated file
#
#                   Valid options
#                       --TargetDir         - Symbolic target directory
#                                             Default: TargetBaseDir
#
#                       --Depth=nn          - Depth to traverse the dependancy tree
#                                             All packages below this depth will be ignored
#                                             Default: 0. All packages will be included
#                       --VisibleDepth=nn   - Package beyond this depth will be marked as invisible
#                                             Default: 1. Only top level packages will be marked
#                                             as visible.
#                       --Ignore=name       - Ignore this package
#                                             It will not be included in the dependancy list
#                                             Default: None
#                       --IgnoreChildren=name   - Do not include children of this package\
#                                             Default: None
#                       --Invisible=name    - Mark this package and its dependents as invisible
#                                             Default: None
#                       --InvisibleChildren=name
#                                           - Mark this package as visible, but its dependents as invisible
#                                             Default: None
#
# Example:
#               generateXmlDependancy('*', '--TargetDir=OcpDir' );
#               
#
# Returns         : Nothing
#
sub generateXmlDependancy
{
    my ($platforms, @opts) = @_;
    my %data;
    my $filename = "PkgInfo_$PkgName" . '.xml';
    my $targetTag;

    return if ( ! ActivePlatform($platforms) );
    Information("Generating XML dependancy information from RM data: $filename");

    #
    #   Insert defaults
    #
    $data{default_visible} = 1;

    #
    #   Parse the user options
    #
    foreach ( @opts )
    {
        if ( m/^--Depth=(\d+)/ ) {
            $data{default_depth} = $1;

        } elsif ( m/^--VisibleDepth=(\d+)/ ) {
            $data{default_visible} = $1;

        } elsif ( m/^--Ignore=(.*)/ ) {
            $data{ignore}{$1} = 1;

        } elsif ( m/^--IgnoreChildren=(.*)/ ) {
            $data{ignore_child}{$1} = 1;

        } elsif ( m/^--Invisible=(.*)/ ) {
            $data{invisible}{$1} = 1;

        } elsif ( m/^--InvisibleChildren=(.*)/ ) {
            $data{invisible_child}{$1} = 1;

        } elsif ( m/^--TargetDir=(.*)/ ) {
            $targetTag = $1;

        } else {
            Error ("generateXmlDependancy: Unknown option: $_");
        }
    }

    #
    #   Sanity Tests
    #
    if ( $data{default_visible} && $data{default_depth} )
    {
        Error ("generateXmlDependancy:Visible depth must be less than total depth")
            if ( $data{default_visible} > $data{default_depth} );
    }

    # lets check to see if the target tag exists
    # if does not the process with log an error.
    #
    my $targetValue;
    if ( $targetTag )
    {
        $targetValue = getTargetDstDirValue($targetTag, "A");
    }
    else
    {
        $targetValue = "$PkgBaseDir/$TargetBaseDir";
    }
    $filename = $targetValue . '/' . $filename;
    

    #
    #   Determine package information.
    #   Must cater for a number of situations
    #       1) Package rebuild
    #       2) Package ripple
    #       3) New package
    #


    # Set defaults for elements in RM if not found
    DeployUtils::RmPkgInfo->DefaultDescription($PkgDesc);
    DeployUtils::RmPkgInfo->DefaultLabel($PkgLabel);

    #
    #   Try with the current package version. It may be in RM
    #
    $RmPkgDetails = DeployUtils::RmPkgInfo->new( {
                        PKG_NAME => $PkgName,
                        PKG_VERSION => $PkgVersionUser,
                        NO_WARN => 1
                    } );

    unless ( $RmPkgDetails->foundDetails() && $PkgPreviousVersionStr )
    {
        #
        #   Try with the 'Previous' package
        #
        my $RmPkgDetailsPrev = DeployUtils::RmPkgInfo->new( {
                        PKG_NAME => $PkgName,
                        PKG_VERSION => $PkgPreviousVersionStr,
                        NO_WARN => 1
                    } );

        if ( $RmPkgDetailsPrev->foundDetails() )
        {
            Information ("generateXmlDependancy. Using previous version ($PkgPreviousVersionStr)");
            $RmPkgDetails = $RmPkgDetailsPrev;
        }
    }

    unless ( $RmPkgDetails->foundDetails() )
    {
        Warning ("generateXmlDependancy. Package Information not in RM. Using defaults");
    }


    #
    #   %packages   - information on packages that we have discovered
    #   @to_process - An array of packages discovered, but not yet processed
    #
    my @to_process;

    #
    #   Create the initial entry in the packages array
    #
    my @deps;
    foreach my $i ( $BuildFileInfo->getDpkgArchiveList() )
    {
        my $moduleInfo = $BuildFileInfo->getDpkgArchiveInfo($i);
        my $tag = join ($;, $i, $moduleInfo->{versionFull} );
        push @deps, $tag;
    }

    $data{packages}{$PkgName}{$PkgVersionUser}{date} = $RmPkgDetails->pv_modified_time() || localtime() ;
    $data{packages}{$PkgName}{$PkgVersionUser}{overview} = $RmPkgDetails->pv_description();
    $data{packages}{$PkgName}{$PkgVersionUser}{deps} = [ @deps ] ;


    push @to_process, @deps;

    while ( my $entry = pop @to_process )
    {
        my ($package, $version) = split ( $;, $entry );

        #
        #   Extract and save information for this package
        #
        next if ( exists $data{packages}{$package}{$version} );

        #
        #   Some packages need to be totally ignored
        #
        next if ( exists $data{ignore}{$package} );

        my $RmPkgDetails = DeployUtils::RmPkgInfo->new(
                        {
                            PKG_NAME => $package,
                            PKG_VERSION => $version,
                        } );
        Error ("generateXmlDependancy: Cannot locate base package: $package, $version")
            unless ( $RmPkgDetails->foundPkg() );

        #
        #   Determine the dependancies, unless we are ignoring the children too
        #   Do not use the RmPkgInfo class method getDependencyNames to fetch the
        #   dependancy information as this:
        #       1) gets it wrong
        #       2) Extracts a lot of data that we dont want.
        #
        my @deps;
        unless ( exists $data{ignore_child}{$package} )
        {
            my $deps = $RmPkgDetails->getDependenciesHash();
            foreach my $pkg ( keys %{$deps} )
            {
                foreach my $ver ( keys %{$deps->{$pkg}}  )
                {
                    my $tag = join ($;, $pkg, $ver );
                    push @deps, $tag;
                }
            }
        }

        $data{packages}{$package}{$version}{date} = $RmPkgDetails->pv_modified_time();
        $data{packages}{$package}{$version}{overview} = $RmPkgDetails->pv_description();
        $data{packages}{$package}{$version}{deps} = [ @deps ] ;

        push @to_process, @deps;
    }
#DebugDumpData ("Packages", \%packages);

    #
    #   Now walk the tree and generate XML
    #
    sub output_entry
    {
        my ($datap, $depth, $package, $version, $vis ) = @_;
        my $fh = $datap->{fh};
        $depth++;

        #
        #   Skip if too deep or an ignored package
        #
        return if ( $datap->{ignore}{$package} );
        return if ( $datap->{default_depth} && $depth > $datap->{default_depth} );

        #
        #   Check for invisible packages
        #
        $vis = 0 if ( $datap->{invisible}{$package} );


        my $indent = "    " x ($depth - 1);
        my $date = $datap->{packages}{$package}{$version}{date};
        my $overview = $datap->{packages}{$package}{$version}{overview};

        #
        #   Clean up the overview
        #
        $overview =~ s~\s+$~~;
        $overview =~ s~\r\n~\n~g;
        $overview =~ s~\n\r~\n~g;

        #
        #   Determine visibility
        #
        $vis = 0 if ( $datap->{default_visible} && $depth > $datap->{default_visible} );
        my $visible = ( $vis > 0 ) ? 'true' : 'false';
        $vis = 0 if ( $datap->{invisible_child}{$package} );

        #
        #   The top level entry is different
        #
        if ( $depth == 0 )
        {
            $indent = "    " ;
            print $fh "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
            print $fh "<ERG_Package xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"package_info.xsd\" SchemaVersion=\"1.0.0\">\n";
            print $fh "$indent<Package_Name>$package</Package_Name>\n";
            print $fh "$indent<Package_Version>$version</Package_Version>\n";
            print $fh "$indent<Package_Overview>$overview</Package_Overview>\n";
            print $fh "$indent<Build_Date>$date</Build_Date>\n";
        }
        else
        {
            print $fh "${indent}<Package Name=\"$package\" Version=\"$version\" BuildDate=\"$date\" Visible=\"$visible\">\n";
                    print $fh "${indent}    ";
            print $fh "<Overview>${overview}" if ($overview);
                    print $fh "</Overview>\n";
        }

        #
        #   Process dependancies
        #
        unless ( $datap->{ignore_child}{$package} )
        {
            foreach my $entry ( @{ $datap->{packages}{$package}{$version}{deps} } )
            {
                my ($package, $version) = split ( $;, $entry );
                output_entry ( $datap, $depth, $package, $version, $vis );
            }
        }

        if ( $depth == 0 )
        {
            print $fh "</ERG_Package>\n";
        }
        else
        {
                    print $fh "${indent}</Package>\n";
        }
    }

    #
    #   Output the XML header and information about the first package
    #
    Information ( "Creating file $filename" );
    open ( $data{fh}, ">", $filename ) || Error( "Cannot create $filename");
    output_entry ( \%data, -1, $PkgName, $PkgVersionUser, 1 );
    close $data{fh};

#    DebugDumpData( "DATA", \%data );
}


#------------------------------------------------------------------------------
sub createPerlSvcWin32
#
# Description:
#       This sub-routine is used to create a Win32  service 
#       using a PERL script as the input.
#
#       note we assume here that you have installed ther ActiveState PERL
#       developement KIT and have also installed a valid license key.
#
#------------------------------------------------------------------------------
{
    # lets just check to see if we can execute this function on
    # this machine.
    #
    if ( "$MachType" ne "win32" )
    {
        Information("createPerlSvcWin32() not supported on this machine type.");
        return 1;
    }


    my ($m_srcDirTag, $m_sfile, $m_targetDirTag, $m_ofile, @m_libDirTags) = @_;


    # lets get the src dir value
    my ($m_targetDirValue) = getTargetDstDirValue($m_targetDirTag, "A");


    # lets get the lib src dir value
    my (@m_libDirValue) = ();
    my $i;
    my ($_libStr) = "";
    foreach $i ( 0 .. $#m_libDirTags )
    {
        $m_libDirValue[$i] = getLocalDirValue($m_libDirTags[$i], "A");
        $_libStr = $_libStr . "$m_libDirValue[$i];"
    }
    if ( -d $DpkgScriptsDir )
    {
        $_libStr = $_libStr . "$DpkgScriptsDir";
    }
    Verbose("additional places to look for perl modules, [$_libStr]");


    # lets get the target dir value
    my ($m_srcDirValue) = getLocalDirValue($m_srcDirTag, "A");

    # we know where we are getting this from and where we
    # going to put them.
    my ($m_sfileLoc) = "$m_srcDirValue/$m_sfile";


    my ($_cmdStr) = "perlsvc --verbose --lib $_libStr --exe $m_targetDirValue/$m_ofile $m_sfileLoc";


    # lets execute the package commands.
    my ($retVal);
    $retVal = system("$_cmdStr");
    if ( $retVal != 0 )
    {
        Error("Failed to complete command [$_cmdStr].");
    }

    # done.
    return 1;
}


#------------------------------------------------------------------------------
sub createPerlAppWin32
#
# Description:
#       This sub-routine is used to create a Win32 free-standing application 
#       using a PERL script as the input.
#
#       note we assume here that you have installed ther ActiveState PERL
#       developement KIT and have also installed a valid license key.
#
#------------------------------------------------------------------------------
{
    # lets just check to see if we can execute this function on
    # this machine.
    #
    if ( "$MachType" ne "win32" )
    {
        Information("createPerlAppWin32() not supported on this machine type.");
        return 1;
    }


    my ($m_srcDirTag, $m_sfile, $m_targetDirTag, $m_ofile, @m_libDirTags) = @_;


    # lets get the src dir value
    my ($m_targetDirValue) = getTargetDstDirValue($m_targetDirTag, "A");


    # lets get the lib src dir value
    my (@m_libDirValue) = ();
    my $i;
    my ($_libStr) = "";
    foreach $i ( 0 .. $#m_libDirTags )
    {
        $m_libDirValue[$i] = getLocalDirValue($m_libDirTags[$i], "A");
        $_libStr = $_libStr . "$m_libDirValue[$i];"
    }
    if ( -d $DpkgScriptsDir )
    {
        $_libStr = $_libStr . "$DpkgScriptsDir";
    }
    Verbose("additional places to look for perl modules, [$_libStr]");


    # lets get the target dir value
    my ($m_srcDirValue) = getLocalDirValue($m_srcDirTag, "A");

    # we know where we are getting this from and where we
    # going to put them.
    my ($m_sfileLoc) = "$m_srcDirValue/$m_sfile";


    my ($_cmdStr) = "perlapp --verbose --clean --force --lib $_libStr --exe $m_targetDirValue/$m_ofile --script $m_sfileLoc";


    # lets execute the package commands.
    my ($retVal);
    $retVal = system("$_cmdStr");
    if ( $retVal != 0 )
    {
        Error("Failed to complete command [$_cmdStr].");
    }

    # done.
    return 1;
}


#------------------------------------------------------------------------------
sub generateProductContents
#
#------------------------------------------------------------------------------
{
    if ( ! defined($RmPkgDetails) )
    {
        # Set defaults for elements in RM if not found
        DeployUtils::RmPkgInfo->DefaultDescription($PkgDesc);
        DeployUtils::RmPkgInfo->DefaultLabel($PkgLabel);

        $RmPkgDetails = DeployUtils::RmPkgInfo->new( 
                        {
                            PKG_NAME => $PkgName,
                            PKG_VERSION => ( "$PkgPatchNum" ne "" ) ? $PkgPatchID : $PkgVersionUser
                        } );
    }


    # we only go on if we have a pkg 
    if ( $RmPkgDetails->foundPkg() )
    {
        # lets zap the product contents
        # only if the release manager entry is not locked.
        if ( $RmPkgDetails->pv_dlocked() ne "Y" )
        {
           Error("Failed to zap product contents.")
                if ( ! $RmPkgDetails->zapProductContents( $Platform ) );
        }


        # lets get a listing of the products contents
        #
        File::Find::find( \&ProductContentsFind, "$PkgBaseDir/$TargetBaseDir");
    }
    else
    {
        Warning("Unable to load product contents because we do not have a connection to Release Manager.");
    }


    # done
    return 1;
}


#------------------------------------------------------------------------------
sub ProductContentsFind
#
#    Description:
#        This subroutine is used to locate all associated items that 
#        have been designated for the product.
#
#------------------------------------------------------------------------------
{
    my($item)= "$File::Find::name";
    my($base)= File::Basename::basename($item);


    # we get the absolute path from the find, but we only require
    # a relative path from the starting dir.

    my ($_item)   = $item;
    my ($_subStr) = "$PkgBaseDir\/$TargetBaseDir";
    $_item =~ s/$_subStr//;

    my $cksumStr;
    my $cksumValue;
    my $cksumSize;
    my $cksumName;
    my $_tmpStr;
    my $retVal;
    my $cksumPath;

    if ( "$base" ne "." && "$base" ne ".." && "x$_item" ne "x" )
    {
        $_item =~ s/^\///;
        $cksumPath = $_item;
        $cksumName = File::Basename::basename($_item);

        # we need to determine which file we are dealing with
        if ( ! -d "$item")
        {
            $cksumStr  = `cksum "$item"`;
            $retVal    = $? / 256;
            if ( $retVal != 0 )
            {
                Error("Failed to determine cksum for product content item [$item].") 
            }
            else
            {
                chomp($cksumStr);
                $cksumStr =~ s/^\s+|\s+$//g;
                if ( $cksumStr =~ m/^([0-9]*)\s*([0-9]*)\s*(.*)$/ )
                {
                    ($cksumValue, $cksumSize, $_tmpStr) = ($1, $2, $3);
                    $cksumValue =~ s/^\s+|\s+$//g;
                    $cksumSize  =~ s/^\s+|\s+$//g;
                    $_tmpStr    =~ s/^\s+|\s+$//g;
                }
                else
                {
                    $cksumValue = '';
                    $cksumSize  = 0;
                    $_tmpStr    = '';
                }
            }

            $cksumPath = File::Basename::dirname($_item);
            if ( $cksumPath eq "." )
            {
                $cksumPath = '';
            }
            else
            {
                $cksumPath =~ s/$/\//;
            }

            # we only mess with the product contents
            # if the package is not released.
            if ( $RmPkgDetails->pv_dlocked() ne "Y" )
            {
                Error("Failed to insert product content item.")
                     if ( ! $RmPkgDetails->insertProductContentItem( $Target, $cksumPath, $cksumName, '', $cksumSize, $cksumValue) );
            }
            else
            {
                Verbose("product item - $Target, $cksumPath, $cksumName, '', $cksumSize, $cksumValue");
            }
        }
        else
        {
            $cksumPath =~ s/$/\//;
            if ( $RmPkgDetails->pv_dlocked() ne "Y" )
            {
               Error("Failed to insert product content item.")
                     if ( ! $RmPkgDetails->insertProductContentItem( $Target, $cksumPath, '', '', 0, '') );
            }
            else
            {
                Verbose("product dir - $Target, $cksumPath, '', '', 0, ''");
            }
        }
    }
}

#-------------------------------------------------------------------------------
# Function        : make_directory
#
# Description     : Create a directory if it does not already exist
#                   Simple function to provide user messages on the way
#                   Will create a complete path. There is no need to
#                   break it into bits.
#
# Inputs          : name        - path to the directory
#                   umask       - umask
#                   text        - User text (optional)
#
# Returns         :
#

sub make_directory
{
    my ($name, $umask, $text ) = @_;

    Error ("make_directory needs a umask") unless ( $umask );
    Error ("make_directory needs a path") unless ( $name );
    $text = "Create directory"  unless ( $text );

    my $umask_text = sprintf( "0%o", $umask );

    unless ( -d $name )
    {
        Verbose ( "$text: $name [$umask_text]");
        mkpath ( $name, 0, $umask);
    }
    else
    {
        Verbose2 ( "$text: $name [$umask_text] - already exists");
    }

    #
    #   Ensure that the target directory is not setgid
    #   as this will mess up the Solaris packaging process. The setgid on the
    #   directories will be propergated into the final package. This is not good.
    #
    #   If the user gets directories with SETGID, then they  must be created
    #   specifically after the directory has been created.
    #
    #   Why is this a problem? Seen when a build user has directory setgid
    #   for the purposes of making the directory accessible by many.
    #
    if ( -g $name )
    {
        system ('chmod', 'g-s', $name );
        Error ("Cannot remove setGID on directory.", "Dir: $name") if ( -g $name );
    }
}


#-------------------------------------------------------------------------------
# Function        : ActivePlatform
#
# Description     : Determine if the specified platform is currently 'active'
#                   This is used by all user directives in order to determine
#                   if the directive should be ignored for the current platform
#
# Inputs          : $platform_spec      - A (simple)platform specifier
#
# Returns         : TRUE if the platform spec contains the current platform
#
sub ActivePlatform
{
    my( $platform_spec ) = @_;

    Error ("No platform specified in some directive") unless ( $platform_spec );

    #
    #   Wild card
    #
    return 1 if ( $platform_spec eq '*' );

    #
    #   Simple test
    #
    foreach ( split (',', $platform_spec))
    {
        return 1 if ( $_ eq $Platform );
    }

    #
    #   Not for me
    #
    return 0;
}

#-------------------------------------------------------------------------------
# Function        : LocatePackageBase
#
# Description     : Locate a package and return the path to a directory within
#                   the package
#
# Inputs          : $ufn            - User function. Error reporting
#                   $PkgName        - Name of the Package
#                   $PkgSubDir      - Subdir within the package
#
#
# Returns         : Absolute path to a directory within the package
#
my %LocatePackageBase_cache;
sub LocatePackageBase
{
    my ( $ufn, $PkgName, $PkgSubDir ) = @_;
    my $src_base_dir;

    if ( exists $LocatePackageBase_cache{$PkgName} )
    {
        $src_base_dir = $LocatePackageBase_cache{$PkgName};
    }
    else
    {
        #
        #   Convert the package name into a real path name to the package as
        #   held in dpkg_archive. Do not use the copy in the 'interface' directory
        #
        for my $entry ( $BuildFileInfo->getBuildPkgRules() )
        {
            next unless ( $entry->{'DNAME'} eq $PkgName );
            $src_base_dir = $entry->{'ROOT'};
            Verbose ("Discovered package in: $src_base_dir");
        }

        Error ("$ufn: Package not located: $PkgName")
            unless ( $src_base_dir );

        Error ("$ufn: Package directory not found: $src_base_dir")
            unless ( -d $src_base_dir );

        #
        #   Mainatin a cache of located packages
        #
        $LocatePackageBase_cache{$PkgName} = $src_base_dir;
    }

    if ( $PkgSubDir )
    {
        $src_base_dir .= '/' . $PkgSubDir;
        Error ("$ufn: Package subdirectory not found: $PkgSubDir" )
            unless ( -d $src_base_dir );
    }

    return $src_base_dir;
}

#===============================================================================
#
#   Internal Package
#   An attempt to simplify the WildCardinf interface by capturing the parameters
#   in a package. The idea is that storing the arguments can be easier
#
package LocateFiles;
use JatsError;

#-------------------------------------------------------------------------------
# Function        : new
#
# Description     : Create a new instance of a searcher
#
# Inputs          : 
#
# Returns         : 
#
sub new {
    my $class = shift;
    my $self  = {};
    $self->{recurse}  = 0;
    $self->{exclude}  = [];
    $self->{include}  = [];
    $self->{base_dir} = undef;
    $self->{results}  = [];
    bless ($self, $class);

    #
    #   Process user arguments
    #   These are are a hash
    #
    my %href = @_;
    foreach my $entry ( keys %href )
    {
        Error( "LocateFiles:new. Unknown initialiser: $entry") unless ( exists $self->{$entry} );
        $self->{$entry} = $href{$entry};
    }
    return $self;
}

#-------------------------------------------------------------------------------
# Function        : recurse
#                   filter_in
#                   filter_in_re
#                   filter_out
#                   filter_out_re
#                   base_dir
#                   results
#
# Description     : Accessor functions
#
# Inputs          : class
#                   One argument (optional)
#
# Returns         : Current value of the daat item
#
sub recurse
{
    my $self = shift;
    if (@_) { $self->{recurse} = shift }
    return $self->{recurse};
}

sub filter_in
{
    my $self = shift;
    if (@_) { push @{$self->{include}}, glob2pat( shift ) }
    return $self->{include};
}

sub filter_in_re
{
    my $self = shift;
    if (@_) { push @{$self->{include}}, shift }
    return $self->{include};
}

sub filter_out
{
    my $self = shift;
    if (@_) { push @{$self->{exclude}}, glob2pat( shift ) }
    return $self->{exclude};
}

sub filter_out_re
{
    my $self = shift;
    if (@_) { push @{$self->{exclude}}, shift }
    return $self->{exclude};
}

sub base_dir
{
    my $self = shift;
    if (@_) { $self->{base_dir} = shift }
    return $self->{base_dir};
}

sub has_filter
{
    my $self = shift;
    return ( ( @{$self->{include}} || @{$self->{exclude}} ) );
}


#-------------------------------------------------------------------------------
# Function        : search
#
# Description     : This function performs the search for files as specified
#                   by the arguments already provided
#
# Inputs          : base_dir (Optional)
#
# Returns         : List of files that match the search criteria
#

my @search_list;             # Must be global to avoid closure problems
my $search_len;

sub search
{
    my $self = shift;
    $self->{base_dir} = $_[0] if (defined $_[0] );
    $self->{results} = ();

    #
    #   Ensure user has provided enough info
    #
    Error ("LocateFiles: No base directory provided") unless ( $self->{base_dir} );

    #
    #   Clean up the user dir. Remove any trailing / as we will be adding it back
    #
    $self->{base_dir} =~ s~/*$~~g;

    #
    #   Init recursion information
    #   Needed to avoid closure interactions
    #
    @search_list = ();
    $search_len = length( $self->{base_dir} );

    #
    #   Create a list of candidate files
    #   If we are recursing the subtree, then this is a little harder
    #   If we are not recursing then we can't simply glob the directory as
    #   not all files are processed.
    #
    #   Will end up with a list of files that
    #       1) Start with a '/'
    #       2) Are rooted as $dir, but don't include $dir
    #
    if ( $self->{recurse} )
    {
        sub find_file_wanted
        {
            return if ( -d $_ );
            my $file = $File::Find::name;
            push @search_list, substr($file, $search_len );
        }

        #
        #       Under Unix we need to follow symbolic links, but Perl's
        #       Find:find does not work with -follow under windows if the source
        #       path contains a drive letter.
        #
        #       Solution. Only use follow under non-windows systems.
        #                 Works as Windows does not have symlinks (yet).
        #
        my $follow_opt =  ! ( "$MachType" eq "win32" || "$MachType" eq "WinCE" );
        
        File::Find::find( {wanted => \&find_file_wanted, follow_fast => $follow_opt }, $self->{base_dir} );
    }
    else
    {
        local *DIR ;
        opendir DIR, $self->{base_dir} || die ("Cannot open $self->{base_dir}");
        foreach ( readdir( DIR ) )
        {
            next if /^\Q.\E$/;
            next if /^\Q..\E$/;
            next if ( -d "$self->{base_dir}/$_" );
            push @search_list, '/' . $_;

        }
        closedir DIR;
    }

    #
    #   If filtering is not present then return the entire file list
    #
    $self->{results} = \@search_list ;
    return @search_list
        unless ( @{$self->{include}} || @{$self->{exclude}} );

    #
    #   Filtering is present
    #   Apply the filterin rules and then the filter out rules
    #   If no filter-in rules, then assume that all files are allowed in and
    #   simply apply the filter-out rules.
    #
    my @patsin  = map { qr/$_/ } @{$self->{include}};
    my @patsout = map { qr/$_/ } @{$self->{exclude}};
    my @result;

#    map { print "Include:$_\n"; } @{$self->{include}};
#    map { print "Exclude:$_\n"; } @{$self->{exclude}};


    file:
    foreach my $file ( @search_list )
    {
        if ( @{$self->{include}} )
        {
            my $in = 0;
            for my $pat (@patsin)
            {
                if ( $file =~ /$pat/ )
                {
                    $in = 1;
                    last;
                }
            }
#print "------- Not included $file\n" unless $in;
            next unless ( $in );
        }

        for my $pat (@patsout)
        {
#print "------- REJECT $file :: $pat \n" if ( $file =~ /$pat/ );
            next file if ( $file =~ /$pat/ );
        }

        push @result, $file;
    }

    $self->{results} = \@result;
#DebugDumpData ("Search", $self);
    
    return @result;
}

#-------------------------------------------------------------------------------
# Function        : glob2pat
#
# Description     : Convert four shell wildcard characters into their equivalent
#                   regular expression; all other characters are quoted to
#                   render them literals.
#
# Inputs          : Shell style wildcard pattern
#
# Returns         : Perl RE
#

sub glob2pat
{
    my $globstr = shift;
    $globstr =~ s~^/~~;
    my %patmap = (
        '*' => '[^/]*',
        '?' => '[^/]',
        '[' => '[',
        ']' => ']',
    );
    $globstr =~ s{(.)} { $patmap{$1} || "\Q$1" }ge;
    return '/' . $globstr . '$';
}

#------------------------------------------------------------------------------
1;