#! perl
########################################################################
# COPYRIGHT - VIX IP PTY LTD ("VIX"). ALL RIGHTS RESERVED.
#
# Module name   : jats.sh
# Module type   : Makefile system
# Compiler(s)   : n/a
# Environment(s): jats
#
# Description:
#       This is a wrapper script to simplify access to the jats
#       build system
#
# Usage:        jats build | make | install | help | ...
#
# Package: PACKAGE_TAG
# Version: VERSION_TAG
#......................................................................#

require 5.008_002;
use strict;
use warnings;

use Cwd;
use File::Copy;
use Getopt::Long qw(:config require_order);     # Stop on non-option
use FindBin;                                    # Determine the current directory
use lib "$FindBin::Bin/LIB";                    # Allow JATS libraries
use Config;
use Sys::Hostname;                              # For hostname

use Pod::Usage;                                 # For help support
use JatsError;                                  # Common error reporting
use DescPkg;                                    # Package Descriptor processing
use JatsSystem;                                 # System call interface
use JatsBuildFiles;                             # Parse Build Files

my $GBE_VERSION = "VERSION_TAG";                # Will be re-written when released
my $GBE_NOT_RELEASED = "RELEASE_TAG";           # Will be re-written (to empty) when released
my $opr_done;
my $opt_here = 0;
my $BUILD_FILE      = "build.pl";
my @BUILD_FILE_ALT  = qw(auto.pl build_test.pl);
my $BUILD_FILE_SET;
my $RESULT = 0;
my $PSPLIT = ':';                               # Win/Unix path splitter
my $opt_time = 0;
my $opt_help = 0;
my $opt_locate = 0;
my $opt_locate_file;
my $opt_locate_package;
my $opt_locate_dir;
my $opt_dir;
my $opt_java;
my $opt_export_vars = 1;
my $result;
my $opt_logfile;
my $opt_script;
my $notaBuildMachine = 0;
my @opt_buildfilter;

#
#   Grab a copy of ALL the environment variable that will be used
#   This will simplify the script a great deal
#

our $GBE_JATS_VERSION   = $ENV{'GBE_JATS_VERSION'}   || '';
our $GBE_JATS_SANE      = $ENV{'GBE_JATS_SANE'}      || 0;
our $GBE_CORE           = $ENV{'GBE_CORE'}           || '';
our $GBE_BIN            = $ENV{'GBE_BIN'}            || '';
our $GBE_CONFIG         = $ENV{'GBE_CONFIG'}         || '';
our $GBE_DPLY           = $ENV{'GBE_DPLY'}           || '';
our $GBE_DPKG           = $ENV{'GBE_DPKG'}           || '';
our $GBE_DPKG_REPLICA   = $ENV{'GBE_DPKG_REPLICA'}   || '';
our $GBE_DPKG_STORE     = $ENV{'GBE_DPKG_STORE'}     || '';
our $GBE_DPKG_LOCAL     = $ENV{'GBE_DPKG_LOCAL'}     || '';
our $GBE_DPKG_ESCROW    = $ENV{'GBE_DPKG_ESCROW'}    || '';
our $GBE_DPKG_CACHE     = $ENV{'GBE_DPKG_CACHE'}     || '';
our $GBE_DPKG_SBOX      = $ENV{'GBE_DPKG_SBOX'}      || '';
our $GBE_SANDBOX        = $ENV{'GBE_SANDBOX'}        || '';
our $GBE_PERL           = $ENV{'GBE_PERL'}           || '';
our $GBE_TOOLS          = $ENV{'GBE_TOOLS'}          || '';
our $GBE_MACHTYPE       = $ENV{'GBE_MACHTYPE'}       || '';
our $GBE_HOSTMACH       = $ENV{'GBE_HOSTMACH'}       || $GBE_MACHTYPE;
our $GBE_PLATFORM       = $ENV{'GBE_PLATFORM'}       || '';
our $GBE_BUILDFILTER    = $ENV{'GBE_BUILDFILTER'}    || '';
our $GBE_DEBUG          = $ENV{'GBE_DEBUG'}          || 0;
our $GBE_VERBOSE        = $ENV{'GBE_VERBOSE'}        || 0;
our $GBE_DRV            = $ENV{'GBE_DRV'}            || '';
our $GBE_HOSTNAME       = $ENV{'GBE_HOSTNAME'}       || hostname || '';
our $USER               = $ENV{'USER'}               || '';
our $PERL5LIB           = $ENV{'PERL5LIB'}           || '';
our $JAVA_HOME          = $ENV{'JAVA_HOME'}          || '';
our $GBE_ABT            = $ENV{'GBE_ABT'}            || '';
our $GBE_OPTS           = $ENV{'GBE_OPTS'}           || '';
our $GBE_VIEWBASE       = $ENV{'GBE_VIEWBASE'}       || '';
our $GBE_VCS            = $ENV{'GBE_VCS'}            || 'SVN';
our $GBE_UNIX           = $^O ne "MSWin32" ;
our $CWD;

#-------------------------------------------------------------------------------
#   Clean up some environment variables
#       GBE_BUILDFILTER - may be space or comma separated list
#       GBE_PLATFORM - may be space or comma separated list
#       GBE_ABT - may be space or comma separated list
#       GBE_HOSTNAME - No whitespace
#       GBE_VCS - lowercase to match command ccrelease and others
#
$GBE_BUILDFILTER = join (' ', split( /[,\s]+/, $GBE_BUILDFILTER));
$GBE_PLATFORM    = join (' ', split( /[,\s]+/, $GBE_PLATFORM));
$GBE_ABT         = join (' ', split( /[,\s]+/, $GBE_ABT));
$GBE_OPTS        = join (' ', split( /[,\s]+/, $GBE_OPTS));
$GBE_HOSTNAME    =~ s~\s+~~g;
$GBE_VCS         = lc( $GBE_VCS );

# Capture NON Build Machine config before parsing the command line
#   Yes the user can still fudge the environment
if (exists $ENV{GBE_ABT} && $ENV{GBE_ABT} eq 'NONE' )
{
    $GBE_ABT = '';
    $notaBuildMachine = 1;
}

#-------------------------------------------------------------------------------
#   Parse the user options
#   GetOptions has been configured so that it will stop parsing on the first
#   non-options. This allows the command syntax to the script to have options
#   that are directed to this script before the command keyword, and command
#   options to the subcommand to be after the keyword.
#
$result = GetOptions (
            "help|h:+"          => \$opt_help,
            "manual:3"          => \$opt_help,
            "verbose|v:+"       => \$GBE_VERBOSE,
            "debug:+"           => \$GBE_DEBUG,
            "cd|changedir=s"    => \$opt_dir,
            "locate"            => \$opt_locate,
            "locatefile=s"      => \$opt_locate_file,
            "locatepkg=s"       => \$opt_locate_package,
            "locatedir=s"       => \$opt_locate_dir,
            "here"              => \$opt_here,
            "time"              => \$opt_time,
            "b|buildfile=s"     => \&opts_buildfile,
            "java=s"            => \$opt_java,
            "version=s",        => \&opts_version,
            "platform:s",       => sub{ opts_extend( \$GBE_PLATFORM, @_ )},
            "buildfilter:s"     => \@opt_buildfilter,
            "abt:s"             => sub{ opts_extend( \$GBE_ABT, @_ )},
            "opts:s"            => sub{ opts_extend( \$GBE_OPTS, @_ )},
            "exportvars!"       => \$opt_export_vars,
            "logfile=s",        => \$opt_logfile,
            "script!",          => \$opt_script,
            );

#
#   Configure the error reporting process now that we have the user options
#
ErrorConfig( 'name'    => 'JATS',
             'debug'   => $GBE_DEBUG,
             'verbose' => $GBE_VERBOSE );
#
#   Post process some of the options
#
Error ("Options not parsed. Use -help for help") unless $result;
Verbose3 ('ARGS', @ARGV);

#
#   Option Helper Routine
#   Save alternate buildfile. Flag that it has been set
#
sub opts_buildfile
{
    my ($junk, $bf) = @_;
    $BUILD_FILE = $bf;
    $BUILD_FILE_SET = 1;
    Verbose ("Use alternate buildfile: $BUILD_FILE");
    return;
}

#
#   Options Helper Routine
#   Collect a space/comma delimited list and replace/append to string
#   Allows the string to be reset
#   Use of a +" will append to existing value
#
#       arg1 - Ref to string to store data
#       arg2 - Option name
#       arg3 - Option value
#
sub opts_extend
{
    my( $ref, $name, $value) = @_;
    if ( $value )
    {
        $value =~ s/,/ /g;
        $value = ${$ref} . ' ' . $value
            if ( $value =~ s/\+/ /g );
        $value =~ s/^\s+//;
        $value =~ s/\s+/ /;
    }
    ${$ref} = $value;
    return;
}

#
#   Options Helper routine
#   Collect --version=version, then stop processing of the command line
#   This will simulate a '--'
#
sub opts_version
{
    my ($junk, $vn) = @_;
    $GBE_JATS_VERSION = $vn;
    die("!FINISH\n");
}

################################################################################
#
#   Ensure that essential environment variables are present and that they
#   do not contain spaces.
#
ReportError('Set env-var GBE_PERL (typically "/usr/bin/perl")')   unless ( $GBE_PERL );
ReportError('Set env-var GBE_DPKG (typically "/devl/dpkg_archive")') unless ( $GBE_DPKG );
ReportError('Set env-var GBE_CORE (typically "/devl/dpkg_archive/PACKAGE_TAG/VERSION_TAG")')  unless ( $GBE_CORE );
ReportError('Hostname cannot be determined') unless ( $GBE_HOSTNAME );

################################################################################
#
#   Warn if using a version of perl that is newer than expected
#   The 'require' does a lower limit test
#
#   Notes:
#       Ubuntu 9.04 provides Perl 10 - don't complain
#       PDK is only available on Windows
#
if ( ! $GBE_JATS_SANE && ! $GBE_UNIX)
{
    Warning ("Perl Version may not be compatible",
             "Jats has been tested with: 5.8.8",
             "This version is: $]",
            ) if ( $] > 5.010000 );

    Warning ("The PDK, as used by some deployed packages does not work with",
             "this version of perl. VIX only has a licence for PDK V5 and",
             "this only works with Perl 5.6 and 5.8.",
             "This version is: $]",
            ) if ( $] > 5.009000 );
}

#
#   Warn if this is not an active state release
#
#   Would be nice, but I can't figure out how to do it - yet
#   The following does not work on all platforms
#
#unless ( $ActivePerl::VERSION )
#{
#    Warning ("Perl does not appear to be an ActiveState Release", "Jats may not function as expected");
#}
#else
#{
#    Verbose ("ActiveState Version: $ActivePerl::VERSION");
#}

################################################################################
#
#   Warn if this version of JATS is not correctly versioned
#   Users should be using correctly versioned copies of JATS. These come
#   from dpkg_archive.
#
#   Display warnings at the end of the run
#   This is an attempt to make them visible to the user
#
my @endWarnings;
if ( ! $GBE_JATS_SANE && $GBE_NOT_RELEASED ) {
    @endWarnings = ( "*** Unofficial version of JATS ***");
} else {

    #
    #   Windows only
    #   Attempt to detect JATS no being run via the jats2_current link
    #
    unless  ( $GBE_UNIX || $GBE_JATS_SANE || $GBE_ABT || $GBE_CORE =~ m~core_devl[/\\]jats2_current~ ) {
        @endWarnings =
            ("***",
             "*** Jats is being invoked from a batch file that does not ",
             "*** automatically track the latest version. Update jats.bat",
             "*** so that GBE_CORE references core_devl/jats2_current",
             "***"
             );
    }
}

#-------------------------------------------------------------------------------
# Function        : END
#
# Description     : Display user warnings at the end of the processing
#                   unless we are processing with a script
#
# Inputs          : global: @endWarnings
#
END
{
    Message (@endWarnings)
        if ( @endWarnings && !$opt_script );
}

################################################################################
#   If running with cygwin then warn if the CYGWIN environment variable
#   contains "tty". tty mode causes some strange behaviour such as:
#       1) Non flushing of perl scripts under some conditions (eg:create_dpkg)
#
if ( $ENV{'CYGWIN'} && $ENV{'CYGWIN'} =~ m/tty/ )
{
    Warning ("The CYGWIN variable contains \"tty\".",
             "This can cause strange behaviour with interactive scripts");
}

#
#   Remove CDPATH - this breaks things when cygwin is running
#   even if we are not running under cygwin perl
#
delete $ENV{'CDPATH'};


################################################################################
#   Sanitize GBE_CORE and others for internal Perl use
#   It may contain \ to be added to PATH but within perl is needs /
#
$PERL5LIB =~ tr~\\/~/~s;

TestDirectoryConfig( 'GBE_CORE' );
TestDirectoryConfig( 'GBE_BIN' );
TestDirectoryConfig( 'GBE_PERL' );
TestDirectoryConfig( 'GBE_DPLY' );
TestDirectoryConfig( 'GBE_DPKG' );
TestDirectoryConfig( 'GBE_DPKG_CACHE' );
TestDirectoryConfig( 'GBE_DPKG_LOCAL' );
TestDirectoryConfig( 'GBE_DPKG_STORE' );
TestDirectoryConfig( 'GBE_DPKG_REPLICA' );
TestDirectoryConfig( 'GBE_DPKG_ESCROW' );
TestDirectoryConfig( 'GBE_DPKG_SBOX' );
TestDirectoryConfig( 'GBE_SANDBOX' );

################################################################################
#   Setup the Machine Type
#
#   GBE_MACHTYPE is used to determine the BIN directory from which JATS will
#   pull local binary executables from. The directory must exist.
#
#   We need GBE_MACHTYPE to be correctly defined by the user
#   This is machine specific and should be done in jats.sh/jats.bat
#
unless ( $GBE_MACHTYPE )
{
    $GBE_MACHTYPE = 'win32' if ( $^O eq "cygwin" );
    $GBE_MACHTYPE = 'win32' if ( $^O eq "MSWin32" );
    $GBE_MACHTYPE = 'win32' if ( $^O eq "win95" );
    $GBE_HOSTMACH = $GBE_MACHTYPE;
    Verbose ("Setting GBE_MACHTYPE: $GBE_MACHTYPE") ;
}

ReportError ('Set env-var GBE_MACHTYPE (typically "win32")') unless ( $GBE_MACHTYPE );
ErrorDoExit();

if ( $GBE_HOSTMACH eq 'win32' )
{
    $PSPLIT = ';';
    $GBE_UNIX = 0;
}

################################################################################
#   Windows: If the user is running JATS from within the development view
#   then they may not provide a drive letter in the full name of GBE_CORE
#   For correct operation GBE_CORE needs to be able to run programs and
#   scripts from any other drive
#
#   If GBE_CORE does not have a driver letter - then add one
#   Note: Use the CWD before any CD operations
#
if ( $GBE_HOSTMACH eq 'win32'  && $GBE_CORE !~ m/^\w\:/ )
{
        my $cwd = getcwd();
        $GBE_CORE = substr( $cwd, 0, 2 ) . '/' . $GBE_CORE;
        $GBE_CORE =~ s~//~/~g;
        Verbose2 ("Setting GBE_CORE drive: $GBE_CORE");
}

################################################################################
#   Attempt to run JATS from a local cache
#   This mechanism allows JATS to be a link to a desired version on a network
#   drive, but to have the version transferred locally if required
#
#   The transfer/check is only done on the first invocation of jats. If jats uses
#   jats to perform functions, then it will not be performed.
#
#   If we want to run an alternate version of JATS, then don't attempt to
#   cache the initial version of JATS.
#
if ( $ENV{GBE_CACHE_JATS} && ! $GBE_JATS_SANE && ! $GBE_JATS_VERSION)
{
    my $state = "Not Cached: Not running from dpkg_archive";
    #
    #   Must have the DPKG_ARCHIVE cache
    #   Must be running from DPKG_ARCHIVE - prevent messing with local copies
    #
    if ( $GBE_DPKG_CACHE )
    {
        #
        #   JATS must be running from an archive, otherwise we assume that its
        #   a local copy. Detected by:
        #       GBE_NOT_RELEASED being set
        #       Lack of descpkg file
        #
        if ( ! $GBE_NOT_RELEASED  && -f "$GBE_CORE/descpkg" )
        {
            my ($archive, $package, $aName) = LocateJatsVersion( $GBE_VERSION );
            if ( $archive )
            {
                #
                #   If the required version is found in the cache, then use it
                #   This will bypass the slowish process of invoking cache_dpkg
                #   at the expense of not being able to handle situations where
                #   version is updated on the fly
                #
                if (($aName ne 'GBE_DPKG_CACHE') && ( $ENV{GBE_CACHE_JATS} < 2))
                {
                    Verbose ("Update cached version of JATS: $GBE_VERSION");
                    #
                    #   Attempt to cache the package
                    #   Need enough JATS environment to run the cache_dpkg utility
                    #
                    {
                        local %ENV = %ENV;

                        $ENV{GBE_TOOLS} = "$GBE_CORE/TOOLS";
                        $ENV{PERL5LIB} = "$GBE_CORE/TOOLS/LIB" ;
                        $ENV{GBE_BIN}  = "$GBE_CORE/BIN.$GBE_HOSTMACH";
                        $ENV{GBE_VERBOSE}  = $GBE_VERBOSE;

                        etool ( 'cache_dpkg.pl', $package );
                    }
                }
                else
                {
                    Verbose("Required version found in cache");
                }

                my $tgt = "$GBE_DPKG_CACHE/$package";
                if ( -d $tgt )
                {
                    Verbose ("Using cached version of JATS: $GBE_VERSION");
                    $GBE_CORE = $tgt;
                    $state = "Cached";
                }
                else
                {
                    $state = "Not Cached: Copy Failure";
                }
            }
            else
            {
                $state = "Not Cached: Not found in archives";
            }
        }
    }
    else
    {
        $state = "Not Cached: No GBE_DPKG_CACHE";
    }

    #
    #   Flag JATS having been cached on the machine
    #
    $ENV{GBE_CACHE_JATS} = $state;
}


################################################################################
#   Establish a relationship between GBE_BIN, GBE_TOOLS and GBE_CONFIG
#   unless the user has already provided one.
#
#   Only NEED GBE_CORE - the others will be derived
#
unless ( $GBE_BIN )
{
    $GBE_BIN = "$GBE_CORE/BIN.$GBE_MACHTYPE";
    Verbose2 ("Setting GBE_BIN: $GBE_BIN");
}
ReportError ('GBE_MACHTYPE is not valid.',
             'There must be a corresponding BIN directory in GBE_CORE',
             "GBE_BIN     : $GBE_BIN",
             "GBE_MACHTYPE: $GBE_MACHTYPE"
             ) unless ( -d $GBE_BIN );

ReportError ('Machine specific binary directory does not appear to setup',
             'After JATS is installed the PostInstall script must be run',
             "GBE_BIN     : $GBE_BIN"
             ) unless ( -x $GBE_BIN . '/sh' || -x $GBE_BIN . '/sh.exe'  );

unless ( $GBE_TOOLS )
{
    $GBE_TOOLS = "$GBE_CORE/TOOLS";
    Verbose2 ("Setting GBE_TOOLS: $GBE_TOOLS");
}

unless ( $GBE_CONFIG )
{
    $GBE_CONFIG = "$GBE_CORE/CFG";
    Verbose2 ("Setting GBE_CONFIG: $GBE_CONFIG");
}

#
#   Extend the PERL5 with our own Module Repository
#
$PERL5LIB = join( $PSPLIT, split( $PSPLIT, $PERL5LIB), "$GBE_CORE/TOOLS/LIB" );


################################################################################
#   Sanity Test
#   The ABT environment requires several parameters to specify the location
#   of the Release/Deployment Managers
#
#   GBE_DM_LOCATION will be set GBE_RM_LOCATION, if not set
#
#   Only perform the test:
#       - On the first invocation of JATS, not nested invocations
#       - Based on the EnvVar, not the user option. This will allow a user
#         to invoke ABT without the need for these values to be present
#
if ( ! $GBE_JATS_SANE && $ENV{GBE_RM_LOCATION} && ! $ENV{GBE_DM_LOCATION} )
{
    $ENV{GBE_DM_LOCATION} = $ENV{GBE_RM_LOCATION};
}

if ( ! $GBE_JATS_SANE && $ENV{GBE_ABT} )
{
    foreach my $var ( qw(GBE_DM_LOCATION GBE_DM_USERNAME GBE_DM_PASSWORD GBE_RM_URL))
    {
        Warning("Deployment Manager EnvVar may need to be defined: $var") unless ( $ENV{$var} );
    }

    foreach my $var ( qw(GBE_RM_LOCATION GBE_RM_USERNAME GBE_RM_PASSWORD GBE_DM_URL))
    {
        ReportError("Release Manager EnvVar needs to be defined: $var") unless ( $ENV{$var} );
    }
}

################################################################################
#   Locate a specified directory - normally a view root
#   Scan upwards from the current directory loccing for the specified path
#
if ( $opt_locate_dir )
{
    my ($path) = scan_for_dir ($opt_locate_dir);
    Error ("Cannot locate directory: $opt_locate_dir") unless ( $path );
    change_dir ( $path );
}

################################################################################
#
#   Change to the required root directory
#       The user may specify a start directory( -c )
#
change_dir ( $opt_dir );

################################################################################
#   Locate the root of the build - if required
#   This is used by the autobuild tools to:
#       1) Locate the build.pl file for JATS based builds
#          The name of the target package can be provided to resolve
#          cases of multiple build files.
#
#       2) Locate the <ProjectName>depends.xml file for ANT based builds
#          The name of the buildfile will be specified
#          There must be only one file of this name in the tree
#
#   Note: If only one build file is found, then it will be used
#         It will not be sanity tested. This is intentional
#         for backward compatability.
#
if ( $opt_locate || $opt_locate_file || $opt_locate_package )
{
    #
    #   Allow the user to specify the name of the build file
    #   This will be used in ANT builds as the name changes
    #   but it can be predetermined
    #
    $opt_locate_file = $BUILD_FILE unless ( $opt_locate_file );

    #
    #   Create a Build File Scanner object
    #   This will be used to locate a suitable build file
    #
    Verbose ("Autolocate the build file: $opt_locate_file");

    my $bscanner = BuildFileScanner ( '.', $opt_locate_file );
    my $count = $bscanner->locate();

    Error ("Autolocate. Build file not found: $opt_locate_file" )
        if ( $count <= 0 );

    #
    #   If multiple build files have been found
    #   If $opt_locate_package is set then we can attempt to resolve the package
    #
    #   Scan the buildfiles and determine the names of the packages that will
    #   be built. This can be used to generate nice error messages
    if ( $count > 1 )
    {
        $bscanner->scan();
        $count = $bscanner->match( $opt_locate_package );
#DebugDumpData ("Bscan", \$bscanner );

        my $errmess;
        unless ( $opt_locate_package ) {
            $errmess = "Use -locatepkg=pkg to resolve required package";

        } elsif ( $count <= 0 ) {
            $errmess = "None found that build package: $opt_locate_package";

        } elsif ( $count > 1 ) {
            $errmess = "Multiple build files build the required package: $opt_locate_package";
        }

        #
        #   Pretty error display
        #   Display build directory and the package name (mangled)
        #
        if ( $errmess )
        {
            Error ("Autolocate. Multiple build files found.",
                   $errmess,
                   "Build files found in:", $bscanner->formatData() );
        }
    }

    #
    #   Extract the required build file directory
    #
    my $dir = $bscanner->getMatchDir() || '';
    Verbose ("Autolocate. Found $count build files: $dir");

    #
    #   Select the one true build directory
    #
    change_dir ( $dir );

    #
    #   Kill location scan as we have already located the build file
    #
    $opt_here = 1;
}

################################################################################
#   Version redirection
#   JATS allows the version of JATS to be used to be specified
#   This mechanism operates on the assumption that the required version is
#   present in dpkg_archive. If a specific version is required then the bulk
#   of this script is bypassed and the arguments passed directly to the required
#   target
#
if ( $GBE_JATS_VERSION && $GBE_JATS_VERSION eq $GBE_VERSION )
{
    Message("Using current JATS version: $GBE_JATS_VERSION" );
    $GBE_JATS_VERSION = undef;
}

if ( $GBE_JATS_VERSION )
{
    #
    #   Report any errors detected
    #
    ErrorDoExit();
    Message("Using JATS version: $GBE_JATS_VERSION");

    #
    #   If we have a cache available, then attempt to transfer the required
    #   version into the cache. If we don't have a cache, then don't even try.
    #
    if ( $GBE_DPKG_CACHE )
    {
        #
        #   Attempt to locate the desired version in one of the well known
        #   package archives. This will give us its package name.
        #
        my ($archive, $package) = LocateJatsVersion ($GBE_JATS_VERSION);
        Error("Cannot find JATS version: $GBE_JATS_VERSION") unless $archive;

        #
        #   Do NOT propagate GBE_JATS_VERSION in the environment
        #   This will only cause problem in recursion
        #
        delete $ENV{GBE_JATS_VERSION};

        #
        #   Attempt to cache the package
        #   Need enough JATS environment to run the utility
        #
        {
            local %ENV = %ENV;

            $ENV{PERL5LIB} = $PERL5LIB;
            $ENV{GBE_BIN}  = $GBE_BIN;
            $ENV{GBE_VERBOSE}  = $GBE_VERBOSE;
            $ENV{GBE_TOOLS}  = $GBE_TOOLS;

            etool ( 'cache_dpkg.pl', $package );
        }
    }

    #
    #   Locate the version of JATS to be run (again)
    #   It should be in the cache, but it may not be
    #
    my ($archive, $package) = LocateJatsVersion ($GBE_JATS_VERSION);
    Error("Cannot find JATS version: $GBE_JATS_VERSION") unless $archive;
    
    $GBE_CORE = "$archive/$package";
    Verbose2 ("Using alternate version: $GBE_CORE");

    #
    #   Run the specified version of JATS
    #   Force the required version of GBE_CORE and invoke the wrapper script
    #
    $ENV{GBE_CORE} = $GBE_CORE;

    Verbose("Use ARGV: @ARGV");
    $RESULT = System ($GBE_PERL, "$GBE_CORE/TOOLS/jats.pl", @ARGV );
    do_exit();
}

################################################################################
#   Determine the current directory
#   Note: Don't use `pwd`. This sucks for so many reasons including
#         the fact that it may not be available until this wrapper
#         script has done it job.
#
$CWD = getcwd();
Error ("Cannot determine current directory - may be protected" )unless ( defined $CWD );
$CWD =~tr~\\/~/~s;
Verbose ("Current Working Directory: $CWD");

################################################################################
#   Setup drive
#   This is only required under windows
#   Purpose is unclear, but under windows it is required, so lets create one
#   if its not present
#
unless ( $GBE_UNIX )
{
    unless ( $GBE_DRV )
    {
        ($GBE_DRV = $CWD ) =~ s~[^:]*$~~;
        $GBE_DRV = "c:" if ( $GBE_DRV !~ m/:/ );
        Verbose2( "Setting GBE_DRV: $GBE_DRV" );
    }
}

################################################################################
#   Sanity test the main archive variable
#   This MUST address one archive
#

Error ("GBE_DPKG must not be a path list: $GBE_DPKG")
    if ( $GBE_DPKG =~ /$PSPLIT/ );
Error ("GBE_DPKG is not a directory : $GBE_DPKG")
    unless( -d $GBE_DPKG );

################################################################################
#   Sanity test the cache
#
Error ("GBE_DPKG_CACHE is not a directory : $GBE_DPKG_CACHE")
    if ( $GBE_DPKG_CACHE && ! -d $GBE_DPKG_CACHE );

################################################################################
#   Sanity test the global store
#
Error ("GBE_DPKG_STORE is not a directory : $GBE_DPKG_STORE")
    if ( $GBE_DPKG_STORE && ! -d $GBE_DPKG_STORE );

Error ("GBE_DPLY is not a directory : $GBE_DPLY")
    if ( $GBE_DPLY && ! -d $GBE_DPLY );

Error ("GBE_DPKG_REPLICA is not a directory : $GBE_DPKG_REPLICA")
    if ( $GBE_DPKG_REPLICA && ! -d $GBE_DPKG_REPLICA );

Error ("GBE_DPKG_ESCROW is not a directory : $GBE_DPKG_ESCROW")
    if ( $GBE_DPKG_ESCROW && ! -d $GBE_DPKG_ESCROW );
    
########################################################################
#
#       Locate a local_dpkg_archive directory, by searching from the CWD
#       to the root of the file system
#
unless ( $GBE_DPKG_LOCAL )
{
    ($GBE_DPKG_LOCAL) = scan_for_dir ('local_dpkg_archive');
}
else
{
    Error ("GBE_DPKG_LOCAL is not a directory : $GBE_DPKG_LOCAL")
        unless( -d $GBE_DPKG_LOCAL );
}

########################################################################
#
#       Locate a sandbox_dpkg_archive directory by searching from the CWD
#       to the root of the file system
#
#       sandbox_dpkg_archive is a dpkg_archive for packages that are being
#       co-developed. Package Versions within the sandbox are ignored
#

#
#   Ensure that the user does not set $GBE_SANDBOX or $GBE_DPKG_SBOX
#   $GBE_JATS_SANE will be set for multiple invocations, thus it is cleared
#   for the first one (unless the user messes with it).
#
unless ( $GBE_JATS_SANE )
{
    Error ("GBE_SANDBOX must not be set by the user") if ( $GBE_SANDBOX );
    Error ("GBE_DPKG_SBOX must not be set by the user") if ( $GBE_DPKG_SBOX );

    #
    #   The ABT does not use the sandbox
    #   It will never be found and will be ignored
    #
    unless ( $GBE_ABT )
    {
        ($GBE_DPKG_SBOX,$GBE_SANDBOX)  = scan_for_dir ('sandbox_dpkg_archive');
    }

    #
    #   Support sandbox specific buildfilter
    #   Remove comments(#) and empty lines
    #
    my $sbBuildFilter = $GBE_DPKG_SBOX . '/buildfilter';
    if ( $GBE_SANDBOX && -f $sbBuildFilter )
    {
        Verbose("sbBuildFilter:$sbBuildFilter");
        if ( open (my $BF, $sbBuildFilter ))
        {
            my @bf;
            while ( <$BF> )
            {
                s~\s$~~;
                s~^\s~~;
                next unless ( $_ );
                next if ( m~^#~ );
                push @bf,$_;
            }
            close $BF;
            if ( @bf )
            {
                $GBE_BUILDFILTER = join (' ', split( /[,\s]+/, join(',', @bf)));
                Verbose ("Local BuildFilter: $GBE_BUILDFILTER");
            }
        }
    }
}

#
#   Base buildfilter will be Machine or Sandbox
#   Now merge in user specified build filters
#
map opts_extend( \$GBE_BUILDFILTER, '', $_ ) , @opt_buildfilter;

########################################################################
#
#   Ensure that the user has been set
#   Under windows USER may not be set, but USERNAME may be
#   As a last resort, use getlogin data
#
$USER = $ENV{ 'USERNAME' } || '' unless ( $USER );
$USER = $ENV{ 'LOGNAME' }  || '' unless ( $USER );
$USER = getlogin()         || '' unless ( $USER );
ReportError ('Cannot determine USER name, via USER, USERNAME, LOGNAME or getlogin')
    unless ( $USER );
#Debug ("User: ", $USER, $ENV{ 'USERNAME'}, $ENV{ 'LOGNAME' }, getlogin() );

################################################################################
#   Sanitize the EnvVars for Windows
#
#   It appears the %ENV is magical (in Win32)
#   The keys are case insensitive, even though the underlying env is not
#       Some of the Win32 binary tools used by JATS cannot handle lower
#       case envVars. In particular Path/PATH.
#       This will also fix some issues within MAKE
#
#   Force all EnvVars to be uppercase
#       Need to delete the entry then reset it
#
#   Note: Under windows the %ENV hash is special. Inserts are forced to uppercase
#   Note: Have issues with VS2012 and Cygwin. We end up with EnvVar tmp and TMP
#         This causes VS2012 to fail.
#
unless ( $GBE_JATS_SANE || $GBE_UNIX )
{
    foreach my $var (keys %ENV)
    {
        my $val = $ENV{$var};
        delete $ENV{$var};
        delete $ENV{lc($var)};
        $ENV{$var} = $val;
    }
}

#
#   Have a very strange issue with Solaris X86 and the buildtool
#   The GBE_MACHTYPE disappears from the environment
#   For some reason, deleting the PATH EnvVar and recreating it will fix it.
#
my $PATH = $ENV{'PATH'};
delete $ENV{'PATH'};
$ENV{'PATH'} = $PATH;


################################################################################
#   There is some really ugly interaction between Cygwin, ActiveState Perl 5.8.2
#   and xmake. Even if none of the cygwin bits are used within JATS the fact that
#   Cygwin is in the path causes problems.
#
#   Problems seen:
#       1) "jats build"     xmake fails with a segment fault. Possibly when
#                           displaying an error message
#       2) Warnings and messages generated from within Perl don't always appear
#          In particular. The output from a Message() within a PLATFORM/xxx file
#          does not get displayed.
#
#   Solution:
#       Remove cygwin from the PATH
#
$PATH =~ s~c:\\cygwin[^;]*;~~ig;

################################################################################
#   Setup the default JAVA_HOME
#   User should specify 1.4, 1.5,1.6 ....
#
$JAVA_HOME = get_java_home ($opt_java) if ( $opt_java );
PathPrepend ("$JAVA_HOME/bin") if ( -d $JAVA_HOME );

################################################################################
#   Setup GBE_VIEWBASE
#   Ideally this should be configured externally
#
unless ( $GBE_VIEWBASE )
{
    if ( $GBE_UNIX ){
        my $HOME = $ENV{'HOME'};
        Error ("Unix HOME EnvVar not defined" ) unless ( $HOME );
        Error ("Unix HOME directory not found: $HOME" ) unless (-d $HOME );
        $GBE_VIEWBASE= "$HOME/jats_cbuilder";
    } else {
        $GBE_VIEWBASE= 'c:/clearcase';
    }
}

################################################################################
#   Ensure that the PATH contains the PERL executable
#   Need to true path to the PERL executable so that the user has access to some
#   of the perl utility programs such as pod2html
#
PathPrepend ($Config{'binexp'});

################################################################################
#   There is more ugliness if GBE_BIN is not in the users path
#   I suspect that it something within xmake (under win32) and that it needs
#   to be able to find sh within the path - even though its fully pathed
#
#   Add GBE_BIN to the start of the path to assist in searching
#   Also ensure that we pickup our version of utilities instead of random
#   versions.
#   
#   Under windows allow the use of selected parts of msys.
#   Place the msys/usr/bin directory AFTER the $GBE_BIN so that we will
#   pickup the original executables before attempting to find the msys
#   ones. Msys was initially used as it provides a full implementation of 
#   tar.
#
PathPrepend ($GBE_BIN . '/msys/usr/bin') unless $GBE_UNIX;
PathPrepend ($GBE_BIN);

################################################################################
# Under Windows - ensure that cmd.exe (or equivelent) is in the PATH
# Cygwin may remove it
# 
unless ( $GBE_JATS_SANE || $GBE_UNIX ) {
    if (exists $ENV{COMSPEC}) {
        $ENV{COMSPEC} =~ m~(.*)[\\/][^\\/]+~;
        $PATH = $PATH . $PSPLIT . $1;
    }
}

################################################################################
#   Clean PATH
#       Remove duplicates
#       Remove empty elements
#       Clean path endings
#       Place non-existent paths at the end. They will be seen, but not scanned
#
{
    my @new_path;
    my @non_exist;
    my %seen;
    foreach ( split($PSPLIT, $PATH) )
    {
        s~[/\\]+$~~;                                # Remove trailing / or \
        my $name = ( $GBE_UNIX ) ? $_ : lc ($_);    # Windows is case insensitive
        next unless ( $_ );                         # Remove empty elements
        next if ( /^\.+$/ );                        # Remove . and ..
        next if ( exists $seen{$name} );            # Remove duplicates
        if ( -d $_ ) {
            push @new_path, $_;                     # Exists
        } else {
            push @non_exist, $_;                    # Place non existent paths at the end
        }
        $seen{$name} = 1;
    }
    $PATH = join( $PSPLIT, @new_path, @non_exist );
}

################################################################################
#   Windows: Ensure that cmd.exe is in the users PATH
#            If cmd.exe cannot be found then the 'system' command will not work
#
unless ( $GBE_JATS_SANE || $GBE_UNIX )
{
    my $cmd_found;
    foreach ( split $PSPLIT, $PATH )
    {
        my $file = $_ . "/cmd.exe";
        Verbose2 ("Look for: $file");
        if ( -x $file  )
        {
            $cmd_found = 1;
            Verbose ("Found: $file");
            last;
        }
    }

    Warning( "Users PATH does not contain \"cmd.exe\"",
             "System commands may not work" ) unless $cmd_found;
}

################################################################################
#   Sanitize the Microsoft Visual Studio environment variables LIB and INCLUDE.
#   If these have a trailing \ then the generated makefiles
#   will fail. This is impossible to detect and fix within make so do it here
#
#   Note: JATS no longer allows these environment variables through to the
#         makefiles.
#
unless ( $GBE_JATS_SANE || $GBE_UNIX )
{
    for my $var (qw ( LIB INCLUDE ))
    {
        my $evar = $ENV{$var};
        if ( $evar )
        {
            $evar =~ s~\\;~;~g;         # Remove trailing \ from components \; -> ;
            $evar =~ s~\\$~~;           # Remove trailing \
            $evar =~ s~;$~~;            # Remove trailing ;
            $evar =~ s~;;~;~g;          # Remove empty items ;;
            $ENV{$var} = $evar;
        }
    }
}

################################################################################
#   Update the environment variables used by JATS, unless requested otherwise.
#
#   If JATS is being used to startup build daemons, then we don't want to
#   export many of the calculated values into the environment. In particular
#   GBE_CORE, GBE_BIN, GBE_CONFIG and GBE_TOOLS must not be exported as it will
#   prevent the daemon from picking up the 'current' version of JATS
#
#

if ( $opt_export_vars )
{
    $ENV{'PATH'}              = $PATH;
    $ENV{'GBE_VERSION'}       = $GBE_VERSION;
    $ENV{'GBE_CORE'}          = $GBE_CORE;
    $ENV{'GBE_BIN'}           = $GBE_BIN;
    $ENV{'GBE_CONFIG'}        = $GBE_CONFIG;
    $ENV{'GBE_DPLY'}          = $GBE_DPLY;
    $ENV{'GBE_DPKG'}          = $GBE_DPKG;
    $ENV{'JATS_HOME'}         = $GBE_DPKG;
    $ENV{'GBE_DPKG_ESCROW'}   = $GBE_DPKG_ESCROW;
    $ENV{'GBE_DPKG_CACHE'}    = $GBE_DPKG_CACHE;
    $ENV{'GBE_DPKG_REPLICA'}  = $GBE_DPKG_REPLICA;
    $ENV{'GBE_DPKG_STORE'}    = $GBE_DPKG_STORE;
    $ENV{'GBE_DPKG_LOCAL'}    = $GBE_DPKG_LOCAL;
    $ENV{'GBE_SANDBOX'}       = $GBE_SANDBOX;
    $ENV{'GBE_DPKG_SBOX'}     = $GBE_DPKG_SBOX;
    $ENV{'GBE_PERL'}          = $GBE_PERL;
    $ENV{'GBE_TOOLS'}         = $GBE_TOOLS;
    $ENV{'GBE_MACHTYPE'}      = $GBE_MACHTYPE;
    $ENV{'GBE_HOSTMACH'}      = $GBE_HOSTMACH;
    $ENV{'GBE_PLATFORM'}      = $GBE_PLATFORM;
    $ENV{'GBE_DRV'}           = $GBE_DRV;
    $ENV{'PERL5LIB'}          = $PERL5LIB;
    $ENV{'JAVA_HOME'}         = $JAVA_HOME if ($JAVA_HOME);
    $ENV{'GBE_JATS_SANE'}     = 1;
}
else
{
    #
    #   Delete, from the environment, values that are related to selecting
    #   the version of JATS being used
    #
    foreach ( qw( GBE_VERSION GBE_CORE GBE_BIN GBE_CONFIG GBE_TOOLS GBE_DRV PERL5LIB GBE_DPKG_SBOX GBE_SANDBOX GBE_PLATFORM GBE_JATS_SANE GBE_MAXMAKE ) )
    {
        delete $ENV{$_};
    }
}

#
#   The following don't affect the operation of the build daemons selecting
#   the current version of JATS. Some need to be passed through anyway
#
$ENV{'GBE_BUILDFILTER'}   = $GBE_BUILDFILTER;
$ENV{'GBE_ABT'}           = $GBE_ABT if ($GBE_ABT);
$ENV{'GBE_OPTS'}          = $GBE_OPTS if ($GBE_OPTS);
$ENV{'GBE_DEBUG'}         = $GBE_DEBUG;
$ENV{'GBE_VERBOSE'}       = $GBE_VERBOSE;
$ENV{'GBE_UNIX'}          = $GBE_UNIX;
$ENV{'USER'}              = $USER;
$ENV{'GBE_HOSTNAME'}      = $GBE_HOSTNAME;
$ENV{'GBE_VIEWBASE'}      = $GBE_VIEWBASE;
$ENV{'GBE_VCS'}           = $GBE_VCS;

#
#   Warn users of potential problem
#   Only do once. May change directory while getting here
unless ( $GBE_JATS_SANE )
{
    Warning ("Current working directory contains spaces")
        if ( $CWD =~ m/\s/ );
}


#-------------------------------------------------------------------------------
# Function        : PathPrepend
#
# Description     : Prepend stuff to the PATH
#
# Inputs          : Items to prepend
#
# Returns         : Nothing
#                   Modifies $PATH
#
sub PathPrepend
{
    foreach my $el ( @_ )
    {
        # Must NOT change the original argument, just a copy of it.
        # Don't use $_ as this messes up too
        my $item = $el;
        $item =~ s~/~\\~g unless ( $GBE_UNIX );
        $PATH = $item . $PSPLIT . $PATH;
    }
}

#-------------------------------------------------------------------------------
# Function        : LocateJatsVersion
#
# Description     : Scan archives looking for a specified version of JATS
#                   Complicated by the name change from core_devl to jats
#                   that occurred circa version 2.71.7.
#                   The required version may be in either of the packages
#
#                   Ensure that package is complete
#                   The caching process will write built.cache during the creation process
#
# Inputs          : $version            - Version to locate
#
# Returns         : undef               - if not found
#                   Array of:
#                       Repository
#                       package/version
#
sub LocateJatsVersion
{
    my ($version) = @_;
    my $package;
    my $path;

    foreach my $archive (qw ( GBE_DPKG_LOCAL GBE_DPKG_CACHE GBE_DPKG_ESCROW GBE_DPKG_REPLICA GBE_DPKG GBE_DPKG_STORE ))
    {
        no strict 'refs';
        $path = ${$archive};
        use strict 'refs';
        next unless ( $path );

        foreach my $package (qw( jats core_devl ))
        {
            Verbose2( "ExamineDir: $path/$package/$version" );
            if ( -d "$path/$package/$version" )
            {
                unless (-f "$path/$package/$version/built.cache")
                {
                    return $path, "$package/$version", $archive;
                }
            }
        }
    }
    return;
}


#-------------------------------------------------------------------------------
# Function        : TestDirectoryConfig
#
# Description     : Sanity test a user configurable directory or file
#                   Must not contain spaces
#                   Must not be a network drive ie: //computer
#
# Inputs          :
#
# Returns         :
#
sub TestDirectoryConfig
{
    my ($dir) = @_;

    no strict 'refs';
    my $val = ${$dir};

    if ( $val )
    {
        #
        #   Cleanup the path
        #
        $val =~ tr~\\/~/~s;
        $val =~ s~/+$~~;
        $val = '' if ( $val eq '-' || $val eq 'none' );
        ${$dir} = $val;

        ReportError("$dir path cannot contain spaces: $val") if ( $val =~ m/\s/ );
        ReportError("$dir path cannot be a computer name: $val") if ( $val =~ m~^//~  );
    }
    use strict 'refs';
    return;
}

#-------------------------------------------------------------------------------
# Function        : change_dir
#
# Description     : change directory to the specified directory
#
# Inputs          : $1      - Target directory
#
# Returns         :
#
sub change_dir
{
    my ($dir) = @_;

    if ( $dir && $dir ne '.' )
    {
        Verbose ("Changing to JATS build directory: $dir");
        chdir $dir || Error ("Bad change directory: $dir");

        #
        #   Reset the CWD
        #   Note: Don't use `pwd`. This sucks for so many reasons including
        #         the fact that it may not be available until this wrapper
        #         script has done it job.
        #
        $CWD = getcwd();
        Error ("Bad change directory: $dir","Cannot determine current directory - may be protected" )unless ( defined $CWD );
        $CWD =~tr~\\/~/~s;
    }
}

#-------------------------------------------------------------------------------
# Function        : scan_for_dir
#
# Description     : Scan from the current directory up to the root
#                   of the current file system looking for a named
#                   directory
#
# Inputs          : $target                 - Directory to locate
#
# Returns         : full_path               - Path of dir
#                   full_dir                - Containng dir
#

sub scan_for_dir
{
    my ($target) = @_;
    Verbose2 ("Scan for $target");

    my $test_dir = $CWD || getcwd();
    {
        do
        {
            #
            #   Stop at /home to prevent unix automounter spitting
            #   lots of error messages
            #
            last if ( $test_dir =~ m~/home$~ );
            Verbose2 ("Testing: $test_dir");

            my $test_path = $test_dir . '/' . $target;
            if ( -d $test_path )
            {
                Verbose ("Found $target: $test_path");
                return $test_path, $test_dir;
            }
            #
            #   Remove one directory
            #   Terminate the loop when no more can be removed
            #
        } while ( $test_dir =~ s~[/][^/]*$~~ );
    }
    return '','';
}

#-------------------------------------------------------------------------------
# Function        : get_java_home
#
# Description     : Convert user java option into a full path,or die
#
# Inputs          : User option
#
# Returns         : Full path
#
sub get_java_home
{
    my ($java) = @_;
    my $jv = "JAVA_HOME_$java";
    $jv =~ s~\.~_~g;

    unless ( exists($ENV{$jv}) )
    {
        Error ("Unknown JAVA version: $java",
               "Looking for EnvVar: $jv",
               "Example Usage: -java=1.5");
    }
    my $rv = $ENV{$jv};
    unless ( -d $rv )
    {
        Error ("Java home path not found: $jv",
               "Looking for: $rv" );
    }
    return $rv;
}

#-------------------------------------------------------------------------------
# Function        : get_version
#
# Description     : Return the version of JATS being run
#                   JATS should be run from a "package"
#                   The package should have a descpkg file
#                   Use this file
#
# Inputs          :
#
# Returns         : A string
#
sub get_version
{
    #
    #   The version number is embedded into this script by the release process
    #   The text [V]ERSION_TAG will be replaced by the real version number
    #   If this has not occurred then we know that the release is not official
    #   Need to be a little bit careful about the tag name
    #
    return ("Unreleased Version. Version tag has not been set")
        if ( $GBE_NOT_RELEASED );

    return "$GBE_VERSION [ Internal. Not an installed package ]"
        if ( ! -f "$GBE_CORE/descpkg" );

    my $rec;
    return $rec->{'VERSION_FULL'}
        if ($rec = ReadDescpkg ( "$GBE_CORE/descpkg" ) );

    return "ERROR";
}

#-------------------------------------------------------------------------------
# Function        : print_version
#
# Description     :
#
# Inputs          :
#
# Returns         :
#
sub print_version
{
    #
    #   Allow user to specify verboseness as an argument
    #
    foreach  ( @_ )
    {
        $GBE_VERBOSE++ if ( m/^-v/ );
    }

    Message get_version();
    Message "Internal: $GBE_VERSION" if ($GBE_VERBOSE);
    $opr_done = 1;
    return;
}


#-------------------------------------------------------------------------------
#
#   Give the user a clue
#
sub help
{
    my ($level) = @_;
    $level = $opt_help unless ( $level );

    pod2usage(-verbose => 0, -message => "Version: ". get_version())  if ($level == 1 );
    pod2usage(-verbose => $level - 1 );
}

#-------------------------------------------------------------------------------
# Function        : find_jats_dir
#
# Description     : Find a JATS build directory
#                   Can be supressed with JATS '-here' command line option
#
# Inputs          : files               - Files to look for
#                   options
#                       --Ant           - Allow Ant files too
#
# Returns         : Will not return if not found
#                   Will 'cd' to the build directory
#
sub find_jats_dir
{
    my $allow_ant;
    my @FILES;
    my $DIR;
    my $check_file;

    #
    #   Autodetect suppressed ?
    #
    return if ( $opt_here );

    #
    #   Collect options
    #   Collect the rest of the arguments
    #
    foreach ( @_ )
    {
        if ( m/^--Ant/ ) {
            $allow_ant = 1;
        }
        else {
            push @FILES, $_;
        }
    }

    push @FILES, @BUILD_FILE_ALT;
    push @FILES, 'build.xml' if ( $allow_ant );

    #
    #   Parent directories to search
    #   Child dirs to search
    #
    my @SEARCH = qw( . .. ../.. ../../.. );
    my @CHILD  = ('', '/jats', '/build', '/build/jats' );

    #
    #   Locate the JATS build files
    #   Allow the user to be in a number of parent directories
    #
    scan:
    for my $ROOTDIR (@SEARCH)
    {
        for my $SUBDIR (@CHILD)
        {
            $DIR = $ROOTDIR . $SUBDIR;
            next unless -d $DIR;

            for my $FILE ( @FILES)
            {
                $check_file = $DIR . '/' . $FILE;
                Verbose2 ("Check for: $check_file");
                last scan if ( -f $check_file );
            }

            next unless ( $allow_ant );
            foreach ( glob($DIR . '/*depends.xml' ) )
            {
                Verbose2 ("Check for: $_");
                if ( m/(.+)depends.xml/ )
                {
                    $check_file = "$1.xml";
                    last scan if ( -f $check_file );
                }
            }
        }
        $DIR = '';
    }

    #
    #   Change to the build directory if one has been found
    #
    if ( $DIR )
    {
        Verbose2 ("Found check file: $check_file");
        change_dir ( $DIR );
    }
    else
    {
        Error ( 'JATS build directory not found.',
                "Cannot locate: @FILES",
                $allow_ant ? 'or Ant <Package>.xml <Package>depends.xml pair' : undef,
                'Use -here option to supress this test'
                );
    }
}

#-------------------------------------------------------------------------------
#
#   Determine the real build file to use
#   Will select from a list of known build files.
#
sub getBuildFile
{
    my $build_file = $BUILD_FILE;
    #
    #   Use an alternative buildfile - if it exists
    #   Do not use this file if the user has specified a buildfile
    #
    unless ( $BUILD_FILE_SET )
    {
        Verbose ("Search for alternate build file");
        foreach my $test_file ( @BUILD_FILE_ALT )
        {
            Verbose2 ("Search for alternate build file: $test_file");
            if ( -f $test_file )
            {
                $build_file = $test_file;
                Message ("=== USING ALTERNATE BUILDFILE: $build_file ===");
                last;
            }
        }
    }
   return $build_file;
}

#-------------------------------------------------------------------------------
#
#   Kick off the build process
#
sub build
{
    isaBuildMachine();
    my $build_file = $BUILD_FILE;
    (my $name = $CWD) =~ s~^.*/~~ ;
    $opr_done = 1;

    find_jats_dir($build_file);
    Message ("=== Building $name ===");
    $build_file = getBuildFile();

    #
    #   Jats/make does not handle file systems with spaces in the path names
    #
    Error('$CWD path cannot contain spaces') if ( $CWD =~ m/\s/ );

    $RESULT = System ($GBE_PERL, $build_file, $CWD, "$GBE_TOOLS/buildlib.pl", @_ );

    Message ("=== Build $name NOT complete ===") if     ( $RESULT  );
    Message ("=== Build $name complete ===")     unless ( $RESULT );
    return $RESULT
}

#-------------------------------------------------------------------------------
# Function        : bmake_it
#
# Description     : Combo build and make operations
#
# Inputs          : ...     - COMMANDS or Make arguments.
#                             Key commands are BUILD and INSTALL
#
# Returns         : RESULT code
#
sub bmake_it
{
    my @make_args = @_;
    my $all = 1;
    my $msg;
    $opr_done = 1;
    isaBuildMachine();

    if ( $make_args[0] && $make_args[0] eq 'NOTALL' )
    {
        $all = 0;
        shift @make_args;
    }
    elsif ( $make_args[0] && $make_args[0] eq 'BUILD' )
    {
        Verbose ("Makeit build") ;
        $msg = "Component not built";
        build('-noforce');
        shift @make_args;
    }

    unless ( $RESULT )
    {
        push @make_args, '-default=all' if ( $all );
        Verbose ("Makeit make @make_args") ;

        find_jats_dir( 'makefile.pl', 'Makefile.gbe', $BUILD_FILE );
        Error ("No Makefile.gbe file found") unless ( -f 'Makefile.gbe' );

        etool ( 'jmake.pl', @make_args );
        $msg = "Component not made";
        @make_args = ();
    }


    Verbose ("Makeit Result: $RESULT") ;
    Error ( $msg ) if ( $RESULT );
    return  if ( $RESULT );
}

#-------------------------------------------------------------------------------
# Function        : dev_expand
#
# Description     : Expand the users arguments to the "debug/prod" command
#                   "debug/prod" builds and packages debug stuff
#
#                   Ignore make options.
#
# Inputs          : target
#                   Argument list
#
# Returns         : expanded argument list
#
sub dev_expand
{
    my @resultd;
    my @resultp;
    my @args;
    my @opts;

    #
    #   Remove options from the argument list
    #
    foreach ( @_ )
    {
        if ( m~=~ || m~^-~ ) {
            push @opts, $_;
        } else {
            push @args, $_;
        }
    }

    my $target = shift @args;
    my @cmd = $target;
    if ( $#args < 0 )
    {
        push @cmd, "package_$target";
    }
    else
    {
        foreach ( @args )
        {
            push @resultd, $_ . "_$target";
            push @resultp, $_ . "_package_$target";
            @cmd = ();
        }
    }

    return (@cmd, @resultd, @resultp, @opts);
}

#-------------------------------------------------------------------------------
# Function        : install_pkg
#
# Description     : Install the built package into local_dpkg_archive
#                   This will make it available for use, without populating the
#                   global archive
#
#                   This is done through an external utility to maintain
#                   consistent interface
#
sub install_pkg
{

    find_jats_dir($BUILD_FILE, '--Ant');
    etool ( 'create_dpkg.pl', '-archive=local', '-quiet', '-override',  @_ );
}

#-------------------------------------------------------------------------------
# Function        : create_dpkg
#
# Description     : Install a package into the main dpkg_archive
#                   This is done through an external utility to maintain
#                   consistent interface
#
#                   This function is simply an easy way to access the utility

sub create_dpkg
{
    find_jats_dir($BUILD_FILE, '--Ant');
    etool ( 'create_dpkg.pl',  @_ );
}

#-------------------------------------------------------------------------------
# Function        : etool
#
# Description     : Invoke an external tool program written in PERL
#
# Arguments       : $1  Name of the program to run
#                       With optional .pl suffix
#                   $2+ Program arguments
#
sub etool
{
    my $command = shift;
    my $cmd;
    my @etool_path = ( "$ENV{'GBE_TOOLS'}",
                       "$ENV{'GBE_TOOLS'}/DEPLOY",
                       "$ENV{'GBE_TOOLS'}/LOCAL",
                        );
    if ( $command )
    {
        #
        #   Locate a potential tool
        #   These will have the user name or a .pl extension
        #
        ETOOL_SEARCH:
        foreach my $ext ( '', '.pl' )
        {
            foreach my $dir ( @etool_path )
            {
                $cmd = "$dir/jats_$command$ext";
                last ETOOL_SEARCH if ( -f $cmd );
                
                $cmd = "$dir/$command$ext";
                last ETOOL_SEARCH if ( -f $cmd );
            }
            $cmd='';
        }

        Error ("Tool not found: $command", "Search path:", @etool_path) unless $cmd;
        $RESULT = System ( $GBE_PERL, $cmd, @_ );
    }
    else
    {
        #
        #   Display on the .pl commands
        #
        display_commands("Available Tools", \@etool_path, ['*.pl'] );
    }

    $opr_done = 1;
}

#-------------------------------------------------------------------------------
# Function        : ebin
#
# Description     : Invoke an external JATS provided binary
#                   within the JATS toolset
#
# Arguments       : $1  Name of the program to run
#                   $2+ Program arguments
#
sub ebin
{
    my $command = shift;
    my $cmd;
    my @ebin_path = ( "$GBE_BIN" );
    push (@ebin_path, $GBE_BIN . '/msys/usr/bin') unless $GBE_UNIX;


    if ( $command )
    {
        #
        #   Locate a potential executable
        #   This
        #
        ETOOL_SEARCH:
        foreach my $ext ( '', '.exe', '.sh' )
        {
            foreach my $dir ( @ebin_path )
            {
                $cmd = "$dir/$command$ext";
                last ETOOL_SEARCH if ( -f $cmd );
            }
            $cmd='';
        }

        Error ("Program not found: $command", "Search path:", @ebin_path) unless $cmd;
        $RESULT = System ( $cmd, @_ );
    }
    else
    {
        #
        #   Display a list of programs
        #
        display_commands("Available Programs", \@ebin_path, ['*'] );
    }

    $opr_done = 1;
}

#-------------------------------------------------------------------------------
# Function        : eprog
#
# Description     : Invoke an external program
#                   Will detect local .pl files and execute them
#                   Will detect local .jar files and execute them
#                   Will detect local .bat files and execute them
#
# Arguments       : $1  Name of the program to run
#                   $2+ Program arguments
#
sub eprog
{
    Verbose ("eprog: @_");
    my $name = fix_command_name (shift @_);
    Error ("eprog. No program specified") unless ( $name );

    $name .= ".pl"     if ( -f "${name}.pl" );
    $name .= ".jar"    if ( -f "${name}.jar" );
    $name .= ".bat"    if ( -f "${name}.bat" );

    #
    #   On Windows programs in the CWD will be found
    #   Mimic this behaviour on Unix
    #
    $name = "./$name" if ( $name !~ m~/~ && -f "./$name");

    if ( $name =~ m~\.pl$~ ) {
        $RESULT = System ( $GBE_PERL, $name, @_ );

    } elsif ( $name =~  m~\.jar$~ ) {
        $RESULT = System ( "$JAVA_HOME/bin/java", '-jar', $name, @_);

    } else {
        #
        #   Ensure .bat files are pathed with \, and not / characters
        #   The windows command interpreter does not like /
        #
        $name =~ s~/~\\~g if ( $name =~ m~\.bat$~ );

        $RESULT = System ( $name, @_ );
    }

    $opr_done = 1;
}

#-------------------------------------------------------------------------------
# Function        : display_commands
#
# Description     : Display a list of commands from a specified list of dirs
#                   Internal helper function
#
# Inputs          : $title      - Display header
#                   $ref_path   - Ref to an array that contains the search path
#                   $ref_ext    - Ref to an array of valid patterns
#
# Returns         : Nothing
#
sub display_commands
{
    my ( $title, $ref_path, $ref_ext ) = @_;

    #
    #   Display a list of commands
    #
    my %list;
    foreach ( @$ref_path )
    {
        foreach my $ext ( @$ref_ext )
        {
            foreach my $file (  glob( "$_/$ext") )
            {
                $file =~ s~.*/~~ unless $GBE_VERBOSE;
                $list{$file} = 1;
            }
        }
    }

    my $count = 0;
    my $limit = $GBE_VERBOSE ? 1 : 3;
    print "$title:\n";
    foreach ( sort keys %list )
    {
        printf "%-26s", $_;
        print "\n" if ( !( ++$count % $limit) );
    }
}

#-------------------------------------------------------------------------------
# Function        : fix_command_name
#
# Description     : Fix a command name parameter
#                   Simplify use of cygwin for some users by allowing
#                   that path of external tools to be a cygwin path
#
# Inputs          : cmd             - command
#
# Returns         : cleaned up version of cmd
#
sub fix_command_name
{
    my ($cmd) = @_;

    unless ( $GBE_UNIX )
    {
        #
        #   Cygwin kludge
        #       Replace /cygdrive/DriveLetter/ - with DriveLetter:/
        #       Replace /DriveLetter/          - With DriveLetter:/
        #
        $cmd =~ s~^/cygdrive/([A-Z])/(.*)~$1:/$2~i;
        $cmd =~ s~^/([A-Z])/(.*)~$1:/$2~i;
    }
    return $cmd;
}


#-------------------------------------------------------------------------------
# Function        : run_ant
#
# Description     : Invoke ant
#                   If the current directory looks like an VIX build system, then
#                   create and maintain an auto.xml file. Otherwise simply invoke ant
#
# Inputs          : $1+ program arguments
#
sub run_ant
{
    isaBuildMachine();
    my $JAVA_HOME = $ENV{JAVA_HOME} || Error ("JAVA_HOME is not defined in the environment");
    my $ANT_HOME  = $ENV{ANT_HOME}  || Error ("ANT_HOME is not defined in the environment" );

    #
    #   Detect an VIX formatted build
    #   This will have two files <projectname>.xml and <projectname>depends.xml
    #   Create the 'auto.xml' file only if its not present
    #
    my @ant_arg;
    my @flist;
    my $basename = '';
    my $scanner = '*depends.xml';

    #
    #   Use specified build file to resolve multiple names
    #   Strip any trailing depends.xml to make it user friendly
    #
    if ( $BUILD_FILE_SET )
    {
        $basename = $BUILD_FILE;
        $basename =~ s~\.xml$~~;
        $basename =~ s~depends$~~;
        $scanner = "${basename}depends.xml";
        Verbose ("Using buildfile: $basename");
    }

    my @buildlist = glob($scanner);
    foreach ( @buildlist )
    {
        if ( m/(.+)depends.xml/ )
        {
            my $pname = $1;
            push @flist, $pname if ( -f "$pname.xml" );
        }
    }

    if ( $#flist >= 0 )
    {
        Error ("Multiple depends.xml files found:", @flist,
               "Use 'jats -buildfile=name ant ...' to resolve") if ( $#flist > 0 );

        my $depend = "$flist[0]depends.xml";
        @ant_arg = ('-f', "$flist[0].xml");

        Message ("Ant using projectfiles: $flist[0].xml");

        #
        #   Create auto.xml if we have a depends.xml
        #
        if ( -f $depend )
        {
            #
            #   Check for depends.xml newer than auto.xml.
            #
            my $auto_timestamp   = (stat('auto.xml'))[9] || 0;
            my $depend_timestamp = (stat($depend))[9];
            if ( $depend_timestamp > $auto_timestamp )
            {
                Message ("Creating: auto.xml");
                copy( $depend, 'auto.xml' );
                chmod 0777, 'auto.xml';
            }
        }
        else
        {
            Warning ("Project file does not have a depends.xml file");
        }
    }
    elsif ( $BUILD_FILE_SET  )
    {
        Error ("Specified build file pair not found:", $basename, $basename . "depends.xml");
    }
    #
    #   The ant provided startup scripts don't return an exit code under
    #   windows. Invoke ant directly
    #
    launch_ant ( $JAVA_HOME, $ANT_HOME, @ant_arg, @_ );
    $opr_done = 1;
}

#-------------------------------------------------------------------------------
# Function        : run_abt
#
# Description     : Invoke auto build tool (older form)
#                   Options for the ABT
#                       --Java=x.x
#                   Invoke ANT for the ABT using a specified version of Java
#                   Do not play with the user environment.
#                   Don't stick java path into environment
#
# Inputs          : $1+ program arguments
#
sub run_abt
{
    my $ABT_JAVA = 'JAVA_HOME_1_6';         # Default version for the ABT
    my $JAVA_HOME = $ENV{$ABT_JAVA};
    my $ANT_HOME  = $ENV{ANT_HOME};
    my @abt_arg;
    my $buildfile = 'build.xml';

    ErrorConfig( 'name'    => 'JATS ABT' );
    isaBuildMachine();

    #
    #   Use the user specified buildfile
    #
    $buildfile = $BUILD_FILE
        if ( $BUILD_FILE_SET );

    #
    #   Extract known options
    #
    foreach  ( @_ )
    {
        if ( m/-java=(.*)/ ) {
            $JAVA_HOME = get_java_home($1);

        } elsif ( m/^-buildfile=(.+)/ ) {
            $buildfile = $1;

        } else {
            push @abt_arg, $_;
        }
    }

    Error ("$ABT_JAVA is not defined in the environment") unless $JAVA_HOME;
    Error ("ANT_HOME is not defined in the environment" ) unless $ANT_HOME;
    Error ("Ant buildfile not found: $buildfile" ) unless (-f $buildfile);

    #
    #   Insert correct build file arguments
    #
    push @abt_arg, '-buildfile', $buildfile;

    #
    #   Add current directory as java library directory, but only if
    #   it contains JAR files.
    #
    push @abt_arg, '-lib', $CWD
        if ( glob ('*.jar') );
    
    #
    #   Use the ant-launcher to invoke ant directly
    #
    launch_ant ( $JAVA_HOME, $ANT_HOME, @abt_arg );
    $opr_done = 1;
}

#-------------------------------------------------------------------------------
# Function        : launch_ant
#
# Description     : Start ANT - with sanity checking
#
# Inputs          : JAVA_HOME
#                   ANT_HOME
#                   @user_args
#
# Returns         : Result Code
#
sub launch_ant
{
    my ($JAVA_HOME, $ANT_HOME, @user_args ) = @_;

    Error ("Directory not found: $JAVA_HOME") unless ( -d "$JAVA_HOME" );
    Error ("Program not found: $JAVA_HOME/bin/java") unless ( -e "$JAVA_HOME/bin/java" || -e "$JAVA_HOME/bin/java.exe" );
    Error ("Jar not found: $ANT_HOME/lib/ant-launcher.jar") unless ( -e "$ANT_HOME/lib/ant-launcher.jar" );
    Error ("Directory not found: $ANT_HOME") unless ( -d "$ANT_HOME" );
    Error ("Directory not found: $ANT_HOME/lib") unless ( -d "$ANT_HOME/lib" );

    #
    #   Documented KLUDGE
    #   The 'ant-using' mechanism only understands GBE_DPKG
    #   This is not good in a cloud build configuration where GBE_DPKG_REPLICA is the fastest repository
    #   Solution: In an GBE_ABT environment IFF GBE_DPKG_REPLIA exists then set GBE_DPKG and JATS_HOME
    #
    if ($GBE_ABT && $GBE_DPKG_REPLICA)
    {
        $ENV{GBE_DPKG_ORIGINAL} = $ENV{GBE_DPKG};
        $ENV{GBE_DPKG} = $ENV{GBE_DPKG_REPLICA};
        $ENV{JATS_HOME} = $ENV{GBE_DPKG_REPLICA};
        Message("Setting GBE_DPKG to GBE_DPKG_REPLICA");
    }

    #
    #   Use the ant-launcher to invoke ant directly
    #
    $RESULT = System ( "$JAVA_HOME/bin/java",
                       #"-agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=y",      # Enable Remote Debug
                       "-classpath","$ANT_HOME/lib/ant-launcher.jar",
                       "-Dant.home=$ANT_HOME",
                       "org.apache.tools.ant.launch.Launcher",
                       "-lib","$ANT_HOME/lib",
                       @user_args
                       );
    
   return $RESULT;
}


#-------------------------------------------------------------------------------
#
#   Cleanup the sandbox
#   Perform a "make clean" then a "build clobber"
#
sub clobber
{
    isaBuildMachine();
    Message ("=== Removing ======");
    find_jats_dir( $BUILD_FILE );
    my $build_file = getBuildFile();
    

    #
    #   Run a "make clean" to clean out a lot of stuff
    #   Run a "build clobber" to get rid of interface and local directories
    #
    etool ( 'jmake.pl', 'clean' )
        if ( -f "Makefile.gbe" );

    if ( -f $build_file )
    {
        System ( $GBE_PERL, $build_file, $CWD, "$GBE_TOOLS/buildlib.pl", 'clobber' );
    }
    else
    {
        Error ("Cannot clobber. No buildfile found");
    }

    Message ("=== Remove complete ===");
    $opr_done = 1;
}

#-------------------------------------------------------------------------------
# Function        : do_exit
#
# Description     : Common exit point so that time information can be displayed
#
# Inputs          : Optional exit code
#
# Returns         :
#
sub do_exit
{
    my ($ecode) = @_;

    $RESULT = $ecode if ( $ecode );

    #..
    #   Determine the runtime
    #       $^T is the time that the program started
    #
    if ( $opt_time )
    {
        my ($TIMEU, $TIMES) = times;
        my $TIMER = time - $^T;
        my $m = int($TIMER / 60);
        my $s = $TIMER - ($m * 60);

        Message ( "Times: Real: $m:$s, User: $TIMEU, System: $TIMES");
    }
    #.
    #   Make sure that any important exit code is passed to the user
    #
    Verbose ("ExitCode: $RESULT");
    exit $RESULT;
}

#-------------------------------------------------------------------------------
# Function        : isaBuildMachine 
#
# Description     : Test that this machine is a build machine
#                   One that supports compilation
#                   Jats may be installed on machines where it may be used in 
#                   a support mode but not to build software. ie: auperaunx01
#
# Inputs          : None
#
# Returns         : May not return 
#
sub isaBuildMachine
{
    if ($notaBuildMachine)
    {
        Error("This machine does not support JATS for building software.",
              "This machine does support JATS for the purpose of running support utilities.");
    }


}


########################################################################
#
#   Main body of the script
#
#   Process help and manual options
#       Done after all the setup to ensure that the PATH is correct
#       Done before bombout to give user a chance
#

#
#   Redirect all output to a log file
#   Only perform redirection AFTER we have setup the users environment
#       May change this.
#
if ( $opt_logfile )
{
    open STDOUT, '>', $opt_logfile  or die "Can't redirect STDOUT: $!";
    open STDERR, ">&STDOUT"         or die "Can't dup STDOUT: $!";
}

help() if $opt_help;
ErrorDoExit();  # Exit if any error in setup
ErrorConfig( 'on_exit'    => \&do_exit );

#
#   Reset operational flags.
#   May have been used by setup
#
$opr_done = 0;
$RESULT = 0;

#
#   Process user commands
#
my $cmd = shift @ARGV || help(1);

print_version(@ARGV)                    if ( $cmd =~ m/^ver/ );

clobber                                 if ( $cmd =~ m/^clobber$/ );
build    (@ARGV)                        if ( $cmd =~ m/^build$/ );

bmake_it ('NOTALL', @ARGV)              if ( $cmd =~ m/^[x]*make$/ );
bmake_it (@ARGV)                        if ( $cmd =~ m/^go$/ );
bmake_it (dev_expand('debug', @ARGV) )  if ( $cmd =~ m/^debug$/ );
bmake_it (dev_expand('prod', @ARGV) )   if ( $cmd =~ m/^prod$/ );
bmake_it ("clean", @ARGV)               if ( $cmd =~ m/^clean$/ );
bmake_it ("rebuild", @ARGV)             if ( $cmd =~ m/^rebuild$/ );
bmake_it ('BUILD', @ARGV)               if ( $cmd =~ m/^all$/ );
bmake_it ($cmd, @ARGV )                 if ( $cmd =~ m/^run_unit_tests/ );

install_pkg(@ARGV)                      if ( $cmd =~ m/^install$/ );
create_dpkg(@ARGV)                      if ( $cmd =~ m/^create_dpkg$/ );

ebin  (@ARGV)                           if ( $cmd =~ m/^ebin/ );
etool (@ARGV)                           if ( $cmd =~ m/^etool/ );
eprog (@ARGV)                           if ( $cmd =~ m/^eprog$/ );
run_ant (@ARGV)                         if ( $cmd =~ m/^ant$/ );
run_abt (@ARGV)                         if ( $cmd =~ m/^abt$/ );

etool ('cache_dpkg', @ARGV)                         if ( $cmd =~ m/^dpkg/ );
etool ('gen_msprojects', @ARGV)                     if ( $cmd =~ m/^gen_msproject/ );
etool ("jats_${GBE_VCS}release.pl", @ARGV)                  if ( $cmd =~ m/^release/ );
etool ("jats_${GBE_VCS}release.pl", '-extractfiles' ,@ARGV) if ( $cmd =~ m/^extractf/ );
etool ("jats_${GBE_VCS}release.pl", '-extract' ,@ARGV)      if (!$opr_done && $cmd =~ m/^extract/ );

etool ("jats_svnrelease.pl", '-extractfiles' ,@ARGV) if ( $cmd =~ m/^svnextractf/ );
etool ("jats_svnrelease.pl", '-extract' ,@ARGV)      if (!$opr_done && $cmd =~ m/^svnextract/ );

etool ("jats_${GBE_VCS}label", @ARGV)                       if ( $cmd =~ m/^label$/ );
etool ('jats_sandbox', @ARGV)                       if ( $cmd =~ m/^sandbox$/ );
etool ('jats_help', @ARGV)                          if ( $cmd =~ m/^help$/ );
etool ('jats_help', '-man', @ARGV)                  if ( $cmd =~ m/^man$/ );
etool ('jats_vars.pl', @ARGV)                       if ( $cmd =~ m/^var/ );

etool ($cmd, @ARGV)                     unless ($opr_done); # Pass to etool if not known

do_exit();
#.

#-------------------------------------------------------------------------------
#   Documentation
#

=pod

=for htmltoc    CORE::AA::Jats

=head1 NAME

jats - JATS utility interface tool

=head1 SYNOPSIS

 Usage: jats [opts] command [cmd-options]

 Where opts:
    -h, -h -h, -man=[n] - Help messages with increasing verbosity
    -cd dir             - Change to specified directory
    -b file             - Use alternate build file
    -verbose[=n]        - Verbose operation
    -debug[=n]          - Enable debug mode of JATS scripts
    -here               - Disable JATS auto locate of build.pl
    -locate             - Locate build.pl file and change to directory
    -locatepkg=pkg      - Locate build.pl. Resolve multiple files via pkg
    -locatefile=file    - Locate specified build file and change to directory
    -locatedir=name     - Locate specified directory by scanning to the root
    -platform=[name]    - Set GBE_PLATFORM to name   (=+ to append)
    -buildfilter=[xxx]  - Set GBE_BUILDFILTER to xxx (=+ to append)
    -abt=[xxx]          - Set GBE_ABT to xxx (=+ to append)
    -opts=[xxx]         - Set GBE_OPTS to xxx (=+ to append)
    -java=version       - Alters java version used (1.4, 1.5, 1.6)
    -time               - Time build and compile times
    -version=xxx        - Use specified version of JATS
    -[no]exportvars     - Export sanitised JATS EnvVars (default)
    -logfile=xxxx       - All output is redirected to the specified file
    -[no]script         - Suppress JATS messages.

 Common commands include:
    build               - Rebuild the sandbox and makefiles
    make                - Make one or more components
    ant                 - Invoke an ant build
    abt [-java=xxx]     - Invoke the auto build tool
    install             - Install package into local_dpkg_archive
    help                - Display help message
    man                 - Display extended help message
    vars                - Display JATS related environment variables

    create_dpkg         - Install a package into main dpkg_archive
    label               - Labelling functions
    release             - Build a release from a VCS label/tag
    extract             - Extract a release from a VCS label/tag
    dpkg_cache          - Maintain a dpkg cache
    gen_msproject       - Generate MSVC project files
    sandbox             - Run Sandbox utility

    etool name          - Run internal tool
    eprog name          - Run external tool
    ebin name           - Run JATS binary tool

 Shortcut commands. Composites of basic commands
    all [opt]           - Same as a "build -noforce" and "make all"
    go  [opt]           - Same as a "make all"
    debug [tgt]         - Same as "make debug package_debug"
    prod  [tgt]         - Same as "make prod package_prod"
    clean               - Same as "make clean"
    clobber             - Same as "build clobber"
    *                   - Unknown commands are treated as arguments to etool

 Where [cmd-options] are command specific.
    Try "jats help command" for details

=head1 OPTIONS

=over 8

=item B<-help>

Print a brief help message and exits.

=item B<-help -help>

Print a detailed help message with an explanation for each option.

=item B<-man[=n]>

Prints the manual page and exits.

If a numeric manual level is provide then it will be used to control the
verbosity of help provided. This should be in the range of 1 to 3.

=item B<-b file> B<-buildfile file>

This option modifies the operation of the "build" command. The command will
use the specified file instead of the normal build.pl file.

=item B<-cd dir> B<-changedir dir>

This option will change to specified directory before the command is invoked.

=item B<--verbose[=n]>

This option will increase the level of verbosity of the JATS command and command
invoked by the JATS shell.

If an argument is provided, then it will be used to set the level, otherwise the
existing level will be incremented. This option may be specified multiple times.

=item B<-debug[=n]>

This option will increase the level of debug output of the JATS command and command
invoked by the JATS shell.

If an argument is provided, then it will be used to set the level, otherwise the
existing level will be incremented. This option may be specified multiple times.

=item B<-here>

This option will disable the "autolocate" mechanism of the JATS shell script.

By default JATS will "hunt" for a suitable "build.pl" or "makefile.pl" before
executing a build or a make command. JATS will look in the following directories
for a  suitable file. Under some conditions this mechanism is not useful.

By default JATS will hunt in the following directories: "." "jats" "build/
jats" ".." "../.." and "../../..".

=item B<-locate>

This option will cause the JATS wrapper script to locate the build.pl file and
then change to that directory. This allows users to locate the build root of
a project and then issue other JATS commands.

If the B<-c> option is also specified then searching will start in the specified
directory.

If an alternate build file is specified with the B<-b> option then that filename
will be used in the location process.

This option implies a B<-here>. No further scanning will be done.

Exactly one build file must be located. If more than buildfile is located then
the locations of the build files is displayed and JATS will terminate.


=item B<-locatepkg=packagename>

This option is similar to the B<-locate> option, but it allows the required
build files to be located by ensuring that the required buildfile builds the
specified package.

There are two forms in which the B<packagename> can be specified. It can be
specified as a full package name and version, or as a package name and the
project suffix. ie: jats-api.1.0.0000.cr or jats-api.cr

=item B<-locatefile=file>

This option is similar to the B<-locate> option, but it allows the name of the
build file to be located to be specified.

If the named file has an '.xml' suffix then the process will look for a pair of
ANT build files of the form xxx.xml and xxxdepends.xml.

=item B<-locatedir=name>

Locate the named directory by scanning from the current directory to the root
of the filesystem. This operation is performed before any other location
operations and before the B<-cd=path> operation.

It may be used to position the jats operation at the root of a view - provided
the view root is known.

=item B<-platform=[name]>

This option will set the JATS specific environment variable GBE_PLATFORM to
the specified name. The existing value of GBE_PLATFORM may be extended by
using "=+".

In practice the GBE_PLATFORM variable is of little use. The same effect can be
achieved directly with make targets or with GBE_BUILDFILTER.

=item B<-buildfilter=[xxx]>

This option will set the JATS specific environment variable GBE_BUILDFILTER to
the specified name. The existing value of GBE_BUILDFILTER may be extended by
using "=+".

This option may be used to limit the initial build, and subsequent "make" to a
limited set of platforms.

=item B<-abt=[xxx]>

This option will set the JATS specific environment variable GBE_ABT to
the specified name The existing value of GBE_ABT may be extended by
using "=+"..

This option is used to pass arguments directly to some tools within the
(ABT) Auto Build Tool framework, or to indicate that the build is being
performed within the ABT framework.

=item B<-java=version>

This option will override the default java version used by the ant builds and
passed to the underlying programs. The path to the Java SDK is determined from
the environment using the version string replacing the '.' with '_'

eg: -java=1.5, will examine the environment for JAVA_HOME_1_5 and will set
JAVA_HOME to that value. It will not setup the users PATH or classpath.

=item B<-time>

When this option is enabled the JATS script will report the runtime of the
underlying, invoked, command.

=item B<-version=xxx>

When this option is invoked JATS will attempt to use the specified version to
perform all processing. JATS will search the GBE_DPKG_LOCAL, GBE_DPKG_CACHE,
GBE_DPKG_REPLICA, GBE_DPKG, GBE_DPKG_STORE in order to locate the specified 
version of the package.

The entire command line will be passed to the JATS wrapper script within that
version. This bypasses the jats.bat or jats.sh startup scripts.

JATS will attempt to transfer the target version to the local cache in an
attempt to improve performance.

=item B<-[no]exportvars>

The default operation is to export sanitized and calculated values to the
programs running under JATS. The use of NoExportVars will prevent JATS from
exporting modified EnvVars into the environment. This may be required by
processes, such as the build daemons that need to pick up the current version of
JATS on the fly and not have it fixed when the daemon is started.

=item B<-logfile=xxxx>

This option will cause all output to be redirected to the named logroll. Both
STDOUT and STDERR will be redirected.

The redirection occurs after the sanity testing that JATS performs and before the
user command is invoked. The redirection occurs after any directory change option
is executed.

Output redirection continues until the program terminates. If JATS invokes other
programs or scripts, there default output will also be redirected.

=item B<-[no]script>

This option will suppress some internal warning messages, generated by the JATS wrapper
script. It is intended to allow JATS to be used with a shell script without the output 
being polluted with internal warnings.

The default operation is to show internal warnings. 

=back

=head1 ARGUMENTS

=head2 Basic Commands

The following commands are invoked directly by the JATS script to wrap the build
tools in a controlled manner.

=over 8

=item L<build|TOOLS::buildlib>

Build or rebuild the sandbox and makefiles.

This command must be used before the component can be "made" and when the
contents of the "buildpl" file change. It is a common mistake to use the "build"
command to much.

The script will hunt for a suitable build.pl file before running the build and
make subcommands.

The build process has a large number of options.
Use L<"JATS build help"|TOOLS::buildlib/"item_help"> to display the complete list.

=item L<make|TOOLS::jmake>

Make one or more components

This command will invoke a suitable "make" program on the makefile found in
the current directory. This makefile should have been generated by JATS.

The make process has a large number of options. Use
L<"JATS make help"|TOOLS::jmake/"item_help">" to display the complete list.

=item B<ant>

This command will use ANT to build a component. JATS will determine the
build.xml file to use with the following algorithm.

    If the files called <Project>depends.xml and <Project>.xml exist then JATS
    will create an 'auto.xml' from the depends file, if one does not already
    exist or is older than the depends.xml file and then use the <Project>.xml
    file as the ant build file.

    Otherwise ant is invoked and it will expect a build.xml file.

If multiple <Project>depends.xml and <Project>.xml file pairs are found the
command will fail. This can be resolved through the use of the -buildfile=name
option.

Ant is invoked with the version of Java specified with the -Java=x.x option.

=item B<abt>

This command is used to invoke the Auto Build Tool. It will invoke ANT on the
build.xml file in the current directory in such  manner as to not affect the
environment of the programs running under ANT.

The remainder of the command line is passed to the ABT, with the exception of
the options:

=over 8

=item *

-java=x.x. This is used to control the version of Java used by the
ABT. The default is 1.6.

=item *

-buildfile=name. This is used to provide a different build file to ant.
The default build file is 'build.xml'.

=back

=item L<help|TOOLS::jats_help>

Display the basic help message.

=item L<vars [-v]|TOOLS::jats_vars>

This command will display all the JATS related environment variables in a
readable form.

Additional information will be displayed if an argument of "-v" is provided.

=back

=head2 Extended Commands

The following commands support the build environment. They are supplemental to
the build environment. They are implemented as extensions to the basic JATS
command scripts.

=over 8

=item L<create_dpkg|TOOLS::create_dpkg>

This command will install a generated package into main dpkg_archive. This
command should not be used directly by a user as it does not ensure that package
has been created in a repeatable manner - use "jats release".

=item label

This command provides a number of useful labelling mechanisms to assist in the
labeling of source code.

The command will determine the default Version Control System and invoke the VCS
specific utility. This will be one of:

=over 4

=item   *

ClearCase: L<cclabel|TOOLS::jats_cclabel>

=item   *

Subversion: L<svnlabel|TOOLS::jats_svnlabel>

=back

=item release

This command allows a package to be built and released, given a label.
This is the desired release mechanism for manually releasing a package.

The command has two main uses:

=over 4

=item 1

Build a package for release. The process will ensure that the build is
controlled and repeatable.

=item 2

Rebuild a package for test or debugging purposes.

=back

The command will determine the default Version Control System and invoke the VCS
specific utility. This will be one of:

=over 4

=item   *

ClearCase: L<ccrelease|TOOLS::jats_ccrelease>

=item   *

Subversion: L<svnrelease|TOOLS::jats_svnrelease>

=back

=item L<extract|/"release">

This is the same as "release -extract"


=item L<dpkg_cache|TOOLS::cache_dpkg>

This utility provides a number of commands to maintain the local cache of
dpkg_archive.

=item L<gen_msproject|TOOLS::gen_msprojects>

This utility will generate a set of Microsoft Studio (Version 6) project and
workspace files to encapsulate the JATS build. The resultant project allows
Visual Studio to be used as an editor, source browser, debugger and build tool.
JATS is still used to perform the build.

=item B<install>

This command will install a generated "package" into the local_dpkg_archive
directory. This allows a group of packages to be tested before being published
into the global dpkg_archive.

=for htmlclass Note

Note. This command is no longer needed. The "build" process will place a
shortcut in the local_dpkg_archive to a components "pkg" directory. Other
components will utilize this shortcut directly and pickup the package without
the user needing to "install" the package - a step that can be forgotten.

=item B<etool name>

This command allows any JATS extension program to be run. The programs will by
found in the JATS TOOLS directory.

=item B<eprog name>

This command allows any JATS extension program to be run.
If the program end in .pl, then it will be run within a perl interpreter.
If the program end in .jar, then it will be run under a java interpreter.

=item B<ebin name>

This command allows any JATS support program to be run. The programs will by
found in the JATS BIN directory for the current platform. This command allows
a user script to access many of the machine independent utilities in a simple
manner.

Example: "JATS ebin ls" - will provide a "real" ls on all platforms.

Example: "JATS ebin sh" - will start up the shell used by make.

=back

=head2 Command Shortcuts

The following commands are user shortcuts to the basic commands. The are basic
commands run in sequence.

=over 8

=item B<all [make_opts]>

This command is the same as running the command "build" and "make all".
It will build a component with a single command.

If "make_opts" is not present then "make all" is used.

If "make_opts" is present then they are passed to the "make" command. In this
manner is it possible to build a WIN32 component of package with a single
command.

=item B<go [make_opts]>

This command is similar to the "all" shortcut, but it does not "build" the
sandbox. It may be used where the sandbox has already been prepared.

=item B<debug [target]>

This command is the same as running "make debug package_debug". It will make and
package all the debug components of a sandbox.

If any additional arguments are provided to the B<dev> command then they will be
treated as make targets and the commands will be expanded to make and package
the specified debug versions of the names platforms. Make options cannot be
passed in this manner.

Example: "JATS dev GAK" will create and package the debug parts for the
GAK_MOS68K and GAK_MOSCF.

=item B<prod [target]>

This command is the same as running "make prod package_prod". It will make and
package all the debug components of a sandbox.

If any additional arguments are provided to the B<prod> command then they will be
treated as make targets and the commands will be expanded to make and package
the specified debug versions of the names platforms. Make options cannot be
passed in this manner.

Example: "JATS prod GAK" will create and package the production parts for the
GAK_MOS68K and GAK_MOSCF.

=item B<clean>

This is the same as "make clean".

=item B<clobber>

This is the same as "build clobber"

=item B<else>

Commands that are not known to the JATS wrapper script are passed to etool.

ie: "JATS xxxx" is is the same as "JATS etool xxxx".

=back

=head1 DESCRIPTION

JATS is a wrapper script. It provides:

=over 4

=item *

A controlled and sanitized environment to all the build tools.

=item *

The same command interface on all supported machines: Windows, Solaris and
Linux.

=item *

Provides a framework for extending the build environment toolset.

=back

=head1 RELATED DOCUMENTATION

=over 4

=item   * L<Installation Notes|POD::InstallationNotes>

=item   * L<OverView|POD::OverView>

=item   * L<EnvVars|POD::EnvVars>

=item   * L<PkgArchives|POD::PkgArchives>

=back

Use L<jats help|TOOLS::jats_help> to see the available internal documentation.

=head1 EXAMPLES

=over 8

=item   L<JATS help|TOOLS::jats_help>

This will display the available internal documentation.

=item   L<JATS build|TOOLS::buildlib>

This will prime the current package being built ready for "make". The command
will locate the build.pl file and process it. This will locate all the external
packages and generate the required makefiles.

=item   L<JATS make|TOOLS::jmake>

This will run the GNU make program over the makefiles generated by the "build"
command. This may be executed in a subdirectory in order to limit the targets
that are "made".

=for htmlclass Note

B<NOTE:> Do not run "make" without using the JATS wrapper. It will not perform
as expected as the environment will not have been set up correctly.

=back

=cut

