Subversion Repositories DevTools

Rev

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

package com.erggroup.buildtool.abt;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;

import java.net.InetAddress;
import java.net.UnknownHostException;

import java.util.Iterator;
import java.util.Vector;
import java.util.Properties;

import org.apache.log4j.Logger;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Target;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.taskdefs.Execute;
import org.apache.tools.ant.taskdefs.Redirector;
import org.apache.tools.ant.BuildException;

import com.erggroup.buildtool.smtp.Smtpsend;

public class ABT extends Task
{
  // static fields
  // public
  // protected
  // private
  
  // fields
  // public
  // protected
  // private
  // System
  private String fs = System.getProperty( "file.separator" );
  private String ls = System.getProperty( "line.separator" );
  private String gbeMachtype = System.getenv("GBE_MACHTYPE");
  private String dpkg_archive = System.getenv("GBE_DPKG");
  private String gatherMetricsOnly = System.getenv("GBE_GATHER_METRICS");

  // ant built in
  private Project project;
  private String basedir;
  // global
  private boolean master = false;
  private String gbebuildfilter;
  private String mailServer;
  private String mailSender;
  // project related
  private String rtagId;
  private String daemon;
  private String release;
  private String buildtoolVersion;
  private String family;
  private String oldExtension;
  private String newExtension;
  // target related
  private Target target;
  private String packageVersionID;
  private String packageAlias;
  private String packageName;
  private String packageVersion;
  private String packageFullVersion;
  private String packageExtension;
  private String packageLoc;
  private String packageVcsTag;
  private String directChange;
  private String doesNotRequireSourceControlInteraction;
  private String testBuildInstruction;
  private String generic;
  private String loc;
  private String unittests;
  private Vector<Depend> dependCollection = new Vector<Depend>();
  private Vector<Platform> platformCollection = new Vector<Platform>();
  private Vector<Jats> jatsCollection = new Vector<Jats>();
  private Vector<Ant> antCollection = new Vector<Ant>();
  private String owners;
  private Machine mMachine;

  // set up in execute
  private BuildStandards buildStandard = BuildStandards.JATS;
  private JavaVersions javaVersion = JavaVersions.NONE;
  private CompileTargets compileTarget = CompileTargets.NONE;
  // abt task result property
  private String propertyValue = "0";
  // output redirector
  private Redirector re;
  private File output;
  // exec thread
  private String[] command = new String[100];
  private int commandIndex = 0;
  private String cwd;
  private Execute thread;
  private File wd;
  private String newVcsTag;
  private static final Logger mLogger = Logger.getLogger(ABT.class);
  private String fullyPublished = "no";
  private String hostname = new String("unknown");

  private void Log(String message1, String message2)
  {
    Log( message1 + message2, info );
  }
  
  private static final char debug = 0;
  private static final char info = 1;
  private static final char warn = 2;
  private static final char error = 3;
  private static final char fatal = 4;
  
  private void Log(String message, char facility)
  {
    if ( daemon != null )
    {
            if ( facility == debug)
            {
              mLogger.debug(message);
            }
            else
            if ( facility == info)
            {
              mLogger.info(message);
            }
            else
            if ( facility == warn)
            {
              mLogger.warn(message);
            }
            else
            if ( facility == error)
            {
              mLogger.error(message);
            }
            else
            {
              mLogger.fatal(message);
            }
    }
    
    log( message );
  }

  private void initCommand()
  {
    for( int i = 0; i < 100; i++ )
    {
      command[ i ] = null;
    }
    commandIndex = 0;
  }
  
  private void addCommand( String c )
  {
    command[ commandIndex ] = c;
    commandIndex++;
  }
  
  private String printCommand( String addendum, boolean log )
  {
    String commandToPrint = "";
    
    for( int i = 0; i < 100; i++ )
    {
      if ( command[ i ] != null )
      {
        commandToPrint += command[ i ] + " ";
      }
      else
      {
        break;
      }
    }
    
    if ( addendum != null )
    {
      commandToPrint += addendum;
    }
    
    if ( log )
    {
      Log( commandToPrint, warn );
    }
    
    return commandToPrint;
  }
  
  private int runCommand( String message ) throws Exception
  {
    String cmd[] = new String[commandIndex];
    for ( int i = 0; i < commandIndex; i++ )
    {
      cmd[i] = command[i];
    }
    thread.setCommandline(cmd);
    printCommand( null, true );
    int retVal = thread.execute();
    
    if ( retVal == Execute.INVALID )
    {
      reportErrorException( "Failure to execute thread, internal ABT problem", 256 );
    }
    else
    {
      printCommand( " returned " + String.valueOf( retVal ), true );

      if ( message != null && retVal != 0 )
      {
        reportErrorException( message + " : " + printCommand( " returned " + String.valueOf( retVal ), true ), retVal );
      }
    }

    return retVal;
  }

  /**
   * Check that one marker file has been published into dpkg_archive
   * 
   * @param archive     - Archive to test
   * @param tag         - Marker suffix
   * 
   * @return "yes" or "no" as text 
   */
  private String checkPublished(String archive, String tag) throws Exception
  {
    String retVal = "no";
    
    if (archive == null)
    {
      reportErrorException( "GBE_DPKG environment variable not set", 256 );
    }
    
    String destination = archive + fs + packageName + fs + packageFullVersion;

    String filename = "built." + tag;
    
    //
    //  Due to NFS caching of small file requests the file may take
    //  a few seconds to appear. Try several times
    //    5 seconds does not appear to be enough
    //    Bumped to 60 seconds: 23-Sep-2013, except for escrow where its not used
    //
    boolean found = false;
    int   maxwait = (daemon == null) ? 1 : (60*2);
    for ( int ii = 0; ii < maxwait && !found; ii++)
    {
        File flag = new File( destination, filename );
        found = flag.exists();
        if ( !found )
        {
              try
              {
                String files;
                File folder = new File(destination);
                File[] listOfFiles = folder.listFiles();
                if ( listOfFiles == null )
                {
                  Log( "published. Destination not a dir: " + destination, fatal );
                }
                else
                {

                  for (int i = 0; i < listOfFiles.length; i++) 
                  {
                    if (listOfFiles[i].isFile())
                    {
                      files = listOfFiles[i].getName();
                      Log("published. DirContent:" + files , warn);
                    }
                  }
                }
              }
              catch( Exception e )
              {
                Log( "published. Display files caught Exception:" + e.getMessage(), fatal );
              }
              

           Thread.sleep(500);
           Log("published. Wait for " + filename + ".(" + ii +")" , warn);
        }
    }

    if ( found )
    {
      retVal = "yes";
      Log("published " + filename + " exists", warn);
    }
    else
    {
      Log("published " + filename + " does not exist", warn);
    }

    return retVal;
  }

  private void printPackage( FileWriter file, String packageName, String packageFullVersion ) throws IOException
  {
    String line = packageName;
    if ( packageFullVersion != null )
    {
      line += " " + packageFullVersion;
    }
    
    line += ls;
    file.write( line );
  }
  
  private void copyFile( File source, File copy )
  {
    if ( source.exists() )
    {
      try
      {
        FileInputStream fis = new FileInputStream(source);
        FileOutputStream fos = new FileOutputStream(copy);
        byte[] buf = new byte[1024];
        int i = 0;
        while( (i=fis.read(buf)) != -1)
        {
          fos.write(buf, 0, i);
        }
        fis.close();
        fos.close();
      }
      catch( Exception e )
      {
        Log( "copyFile caught Exception", error );
      }
    }
  }

  //
  //  Save the log file
  //    used on error build
  //    used on complete build
  //
  private boolean saveLogs()
  {
    if ( daemon == null )
    {
      // do nothing more in escrow
      return false;
    }

    // persist the failure log to GBE_LOG/hostname/rtagid/timestamp
    String log = System.getenv("GBE_LOG");
    
    if ( log == null )
    {
      // cannot happen, GBE_LOG is checked in BuildDaemon at startup
      return false;
    }
    
    File destinationLog = new File( log );
    File destinationHostname = new File( destinationLog, hostname );
    File destinationRtagId = new File( destinationHostname, rtagId );
    // create directories
    new File( destinationRtagId, daemon).mkdirs();
    
    File destinationTimestamp = new File( destinationRtagId, daemon );
    
    if ( destinationTimestamp.exists() )
    {
      File buildsource = new File(rtagId + "build.xml");
      File logsource = new File(rtagId + ".log");
      File buildcopy = new File( destinationTimestamp, packageAlias + ".xml");
      copyFile( buildsource, buildcopy );
      File logcopy = new File( destinationTimestamp, packageAlias + ".log");
      copyFile( logsource, logcopy );
      Log("reportError persisting " + logcopy.getName(), warn);
    }

    return true;
  }

  private void reportError(String error, int retVal)
  {
    propertyValue = String.valueOf( retVal );

    Log( error, ABT.error );
    Log( "reportError propertyValue = " + propertyValue.toString() + ", ", error);

    //  Save the logs
    //      Will return false in situations were we can't proceed
    if ( ! saveLogs() )
    {
        return;
    }
    
    if ( !ABTData.ownerCollection.isEmpty() || mailServer == null || mailSender == null )
    {
      String unc = System.getenv("GBE_UNC");
      
      if ( unc == null )
      {
        // cannot happen, GBE_UNC is checked in BuildDaemon at startup
        return;
      }
      
      String href = hostname + "/" + rtagId + "/" + daemon + "/" + packageAlias + ".log";
      unc += "/" + href;

      String body = new String();
      body = "Release: " + release + "<p>" +
             "Package: " + packageName + "<p>" + 
             "Build machine: " + hostname + "<p>" +
             "GBE_MACHTYPE: " + gbeMachtype + "<p>" +
             "Error: " + error + "<p>" +
             "Log File: <a href=\"" + unc + "\">" + href + "</a> ... URL expires in 5 working days time<p><hr>";
      
      try
      {
        Smtpsend.send( mailServer,  // mailServer
                       mailSender,  // source
                       owners,      // target
                       null,        // cc
                       null,        // bcc
                       "BUILD FAILURE on package " + packageName, // subject
                       body,        // body
                       null         // attachment
                      );
      }
      catch( Exception e )
      {
        // not fatal
        Log( "reportError caught Exception", warn);
      }
    }

  }
  
  private void reportErrorException(String error, int retVal) throws Exception
  {
    reportError( error, retVal );
    throw new Exception( hostname );
  }
  
  private void genbuild() throws Exception
  {
    if ( master )
    {
      // gather metrics
      // jats -locatefile=.jats.packageroot etool jats_metrics -mode=init -rootdir=.
      // -locate=.jats.packageroot causes jats to cd to the folder containing the file .jats.packageroot
      // this file is created in the -path folder by jats release -extract
      // DEVI 51370 it is essential for metrics branch calculation the metrics utility is started within a static view
      initCommand();
      addCommand( "jats" );
      addCommand( "-locatefile=.jats.packageroot" );
      addCommand( "etool" );
      addCommand( "jats_metrics" );
      addCommand( "-mode=init" );
      addCommand( "-rootdir=." );
      
      runCommand( "Failure to collect metrics" );
    }

    if ( gatherMetricsOnly != null )
    {
      return;
    }

    //
    //  Create build files with updated dependency information
    //  In escrow mode : No new dependency information
    //  In daemon mode :
    //      Ripple     : New dependency information
    //      Verify     : Existing dependency information
    //
    //  In all modes  : ANT builds need an auto.xml
    //
    //  In order to create auto.xml/auto.pl with package dependencies need to
    //  create file with dependency data (auto.cfg) only because its
    //  needed by "jats_rewrite"
    //
    File cfg = null;
    boolean  create_file = false;
    if ( daemon != null )
    {
      create_file = true;
      
      // always generate auto.cfg
      cfg = new File( cwd + fs + "auto.cfg" );
      cfg.createNewFile();
      
      if ( !cfg.exists() || !cfg.canWrite() )
      {
        reportErrorException( "Failed to open auto.cfg", 263 );
      }
      
      try
      {
        FileWriter cfgfw = new FileWriter(cfg);
        printPackage( cfgfw, packageName, packageFullVersion );
        
        // provide releasemanager.projectname=<name[0]> and releasemanager.releasename=<name[1]>
        String[] name = release.split( " > ", 2 );
        
        if ( name.length == 2 )
        {
          printPackage( cfgfw, "releasemanager.projectname=" + name[0], null );
          printPackage( cfgfw, "releasemanager.releasename=" + name[1], null );
        }
    
        for (Iterator<Depend> it=dependCollection.iterator(); it.hasNext(); )
        {
          Depend depend = it.next();
          printPackage( cfgfw, depend.getPackage_Alias(), null );
        }
    
        cfgfw.close();
      }
      catch( IOException e )
      {
        reportErrorException( "Failure to write to auto.cfg", 263 );
      }
    }
    else
    if ( buildStandard == BuildStandards.ANT )
    {
      // Have not created an auto.xml with updated dependencies
      // Ant build still would like an auto.xml file
      //
      // ie packages with a line <import file="auto.xml" optional="true"/> are fine
      //    but in escrow and rebuild we still need an auto.xml to be kind
      //
      create_file = true;
    }

    //
    //  Create the auto.pl/auto.xml file if required
    //
    if ( create_file )
    {
      initCommand();
      addCommand( "jats" );

      if ( buildStandard == BuildStandards.ANT )
      {
        addCommand( "-locatefile=" + packageName + ".xml" );
        addCommand( "etool" );
        addCommand( "jats_rewrite" );
        addCommand( "-infile=" + packageName + "depends.xml" );
        addCommand( "-outfile=auto.xml" );
      }
      else
      {
        addCommand( "-locatepkg=" + packageLoc );
        addCommand( "etool" );
        addCommand( "jats_rewrite" );
        addCommand( "-infile=build.pl" );
        addCommand( "-outfile=auto.pl" );
      }

      if ( cfg != null )
      {
        addCommand( "-config=" + cfg.getAbsolutePath() );

        if ( doesNotRequireSourceControlInteraction != null && testBuildInstruction.compareTo("0") == 0 )
        {
            // Have a config file, but we are not rippling the package
            // just rebuilding it. Validate the versions in Release Manager
            // against those in the build files
            addCommand( "-validate");
        }
      }
      else
      {
        addCommand( "-noconfig");
      }
      
      if ( oldExtension != null )
      {
        addCommand( "-oldproject=" + oldExtension );
        addCommand( "-newproject=" + newExtension );
      }
  
      runCommand( "Failure to generate auto.pl potentially caused by missing dependencies in the Release Manager database" );
    }
  }
    
  private void jatsBuildPackage() throws Exception
  {
    //--------------------------------------------------------------------------
    //  Build Phase
    //  Create build environment

    initCommand();
    addCommand( "jats" );

    if ( gbebuildfilter != null )
    {
      addCommand( "-buildfilter" );
      addCommand( gbebuildfilter);
    }

    if ( buildStandard == BuildStandards.ANT )
    {
      addCommand( "-locatefile=" + packageName + ".xml" );
      addCommand( "abt" );
      addCommand( "-java=" + javaVersion.getJavaVersion() );
      addCommand( "-buildfile=" + packageName + ".xml" );
      addCommand( "build" );
    }
    else
    {
      addCommand( "-locatepkg=" + packageLoc );
      addCommand( "build" );
      addCommand( "--package" );
      
      if ( family.compareTo( "windows" ) == 0 )
      {
        addCommand( "--cache" );
      }
    }
    
    runCommand( "Failure to set up sandbox" );
    
    //--------------------------------------------------------------------------
    //  Make Package phase
    //  Create the package (make)

    initCommand();
    addCommand( "jats" );

    if ( gbebuildfilter != null )
    {
      addCommand( "-buildfilter" );
      addCommand( gbebuildfilter);
    }

    if ( buildStandard == BuildStandards.ANT )
    {
      addCommand( "-locatefile=" + packageName + ".xml" );
      addCommand( "abt" );
      addCommand( "-java=" + javaVersion.getJavaVersion() );
      addCommand( "-buildfile=" + packageName + ".xml" );
      addCommand( "make_package" );
    }
    else
    {
      addCommand( "-locatepkg=" + packageLoc );
      addCommand( "make" );
      addCommand( "NODEPEND=1" );

      if ( compileTarget == CompileTargets.PROD )
      {
        addCommand( "prod" );
        addCommand( "package_prod" );
      }
      else if ( compileTarget == CompileTargets.DEBUG )
      {
        addCommand( "debug" );
        addCommand( "package_debug" );
      }
      else
      {
        addCommand( "all" );
      }
    }
    
    runCommand( "Failure to generate derived files" );


    //--------------------------------------------------------------------------
    //  Unit tests phase
    //  Run autonimous unit tests

    if ( unittests != null )
    {
      initCommand();
      addCommand( "jats" );

      if ( gbebuildfilter != null )
      {
        addCommand( "-buildfilter" );
        addCommand( gbebuildfilter);
      }

      if ( buildStandard == BuildStandards.ANT )
      {
        addCommand( "-locatefile=" + packageName + ".xml" );
        addCommand( "abt" );
        addCommand( "-java=" + javaVersion.getJavaVersion() );
        addCommand( "-buildfile=" + packageName + ".xml" );
        addCommand( "run_tests" );
      }
      else
      {
        addCommand( "-locatepkg=" + packageLoc );
        addCommand( "make" );
        if ( compileTarget == CompileTargets.PROD )
        {
          addCommand( "run_unit_tests_prod" );
        }
        else if ( compileTarget == CompileTargets.DEBUG )
        {
          addCommand( "run_unit_tests_debug" );
        }
        else
        {
          addCommand( "run_unit_tests" );
        }
      }

      runCommand( "Failure to run unit tests" );
    }

    //--------------------------------------------------------------------------
    //  create_dpkg phase
    //  Publish the package to dpkg_archive
    //

    initCommand();
    addCommand( "jats" );
    if ( buildStandard == BuildStandards.ANT )
    {
      addCommand( "-locatefile=" + packageName + ".xml" );
    }
    else
    {
      addCommand( "-locatepkg=" + packageLoc );
    }
    addCommand( "create_dpkg" );
    addCommand( "-o" );
    addCommand( "-m" );
    addCommand( "-pname" );
    addCommand( packageName );
    addCommand( "-pversion" );
    addCommand( packageFullVersion );
    
    if ( generic != null )
    {
      addCommand( "-generic" );
    }
    
    runCommand( "Failure to publish to archive" );
  }
  
  /**   Check if the package has been Published on all the required machines
   *    If its a 'generic' package then a tag of built.generic will have been placed in the package
   *    Otherwise each build machine will place a built.<MachName> file in the package
   *  
   *    All we know is which MachTypes we build for. This needs to be expanded into
   *    a list of MachineNames. Thus a build-set with multiple machines of the same MachType
   *    can indicate build failures.
   */
  private void publish() throws Exception
  {  
    
    //  Metrics gathering (only) does not create anything in dpkg_archive
    if ( gatherMetricsOnly != null )
    {
        fullyPublished = "yes";
        return;
    }
        
    if ( generic != null )
    {
        //  Generic - only one maker file
        fullyPublished = checkPublished( dpkg_archive, "generic" );
    }
    else
    {
        //  Multi machine package
        //  Scan required target machines artifacts
        //  Expand from MachType to one or more MachName's
        scanBuilds:
        for (Iterator<Platform> ip=platformCollection.iterator(); ip.hasNext(); )
        {
          Platform platform = ip.next();
          for (Iterator<Machine> it=ABTData.machineCollection.iterator(); it.hasNext(); )
          {
            Machine ma = it.next();
            if (ma.getMachtype().compareTo(platform.getGbe_Machtype()) == 0 )
            {
                fullyPublished = checkPublished( dpkg_archive, ma.getName() );
                if ( fullyPublished.compareTo("no") == 0 )
                {
                  //  Break out of both loops
                  //  Once we have seen an error we need to retain it.
                  break scanBuilds;
                }
            }
          }
        }
    }

    //  Detect problem with zero length descpkg file
    //      May be caused by write clash from multiple machines
    //      Don't know
    //
    if ( fullyPublished.compareTo("yes") == 0 )
    {
        if (dpkg_archive == null)
        {
          reportErrorException( "GBE_DPKG environment variable not set", 256 );
        }

        String destination = dpkg_archive + fs + packageName + fs + packageFullVersion;
        String filename = "descpkg";

        File flag = new File( destination, filename );

        //  File Must
        //      Exist
        //      Be a File
        //      Have a length. Problem appers to be zero length file
        //
        boolean found = false;
        Log( "published. Descpkg Sanity Test: " + flag.getPath(), info );
        if (!flag.exists() ) {
            Log( "published. Descpkg Sanity Test: File not found", fatal );

        } else if ( !flag.isFile()) {
            Log( "published. Descpkg Sanity Test: Is not a file", fatal );

        } else if ( flag.length() <= 0 ) {
            Log( "published. Descpkg Sanity Test: Zero length File", fatal );

        } else {
            Log( "published. Descpkg Sanity Test: Passed", info );
            found = true;
        }

        if (!found) {
            fullyPublished = "no";
        }
    }

    if ( fullyPublished.compareTo("yes") == 0 && daemon != null )
    {
      if ( doesNotRequireSourceControlInteraction == null )
      {
        //
        //  Save modified build files
        //  Label the resultant files
        //  Create a command of the form:
        //      jats etool jats_vcssave_build
        //          -infile     auto.xml/auto.pl
        //          -outfile    xxxdepends.xml/build.pl
        //          -pname      package_name
        //          -pversion   package_version
        //          -infofile   path_to_info_file
        //          -wiplabel   Existing WIP label (optional)
        //          -baselabel  View label

        Log("publish save build files", warn);

        File saveinfo = new File(basedir + fs + rtagId + "abtinfo.txt");
        if ( saveinfo.exists() )
        {
          saveinfo.delete();
        }
        
        initCommand();
        addCommand( "jats" );
        if ( buildStandard == BuildStandards.ANT )
        {
          addCommand( "-locatefile=" + packageName + ".xml" );
        }
        else
        {
          addCommand( "-locatepkg=" + packageLoc );
        }

        addCommand( "etool" );
        addCommand( "jats_vcssave_build" );

        if ( buildStandard == BuildStandards.ANT )
        {
          addCommand( "-infile" );
          addCommand( "auto.xml" );
          addCommand( "-outfile" );
          addCommand( packageName + "depends.xml" );
        }
        else
        {
          addCommand( "-infile" );
          addCommand( "auto.pl" );
          addCommand( "-outfile" );
          addCommand( "build.pl" );
        }
        
        addCommand( "-pname" );
        addCommand( packageName );

        addCommand( "-pversion" );
        addCommand( packageFullVersion );

        if ( directChange != null )
        {
          addCommand( "-isawip" );
        }
        
        addCommand( "-infofile" );
        addCommand( saveinfo.getAbsolutePath() );

        addCommand( "-baselabel" );
        addCommand( packageVcsTag );
        

        if ( oldExtension != null && newExtension != null && packageExtension.compareTo( newExtension ) == 0 )
        {
          // only branch build.pl where its extension is being migrated
          addCommand( "-branch" );
          addCommand( "project_migration_branch" );
          addCommand( "-newbranch" );
        }

        runCommand( "Failure to save build file changes into source control" );

        //
        //  The command creates an info file(saveinfo) to pass information back
        //  to the caller (me). This is a 'properties' file
        //  Need to extract the following information
        //    newVcsTag - which is held as VCS.tag
        //
        Log("publish read info file", info);

        Properties properties = new Properties();
        try
        {
          properties.load(new FileInputStream(saveinfo));
        }
        catch (IOException e)
        {
          reportErrorException( "Failed to open save_build info file", 262 );
        }

        newVcsTag = properties.getProperty("VCS.tag" );
        if ( newVcsTag == null )
        {
          reportErrorException( "Save_build info. Missing property:VCS.tag", 262 );
        }
        Log("publish read info file. Label:" + newVcsTag , info);
      }
    }
  }

/** determineBuildStandard
 *  Process the current target and set up
 *      buildStandard
 *      compileTarget
 *      javaVersion
 */
  private void determineBuildStandard() throws Exception
  {
      // Scan the platform collection looking for an entry that matches the current machine
      // Remember the index - as it used to locate a matching entry in the 
      // jatsCollection or jatsCollection
      // 
      // Just wanting to set up
      //    buildStandard and one of
      //        compileTarget
      //    OR  javaVersion
      //
      int platformIndex = 0;
      for ( Iterator<Platform> it = platformCollection.iterator(); it.hasNext(); )
      {
        Platform platform = it.next();
        platformIndex++;
        
        if ( gbeMachtype.compareTo( platform.getGbe_Machtype() ) == 0 )
        {
          break;
        }
      }
      
      int index = 0;
      for (Iterator<Jats> it=jatsCollection.iterator(); it.hasNext(); )
      {
        Jats j = it.next();
        index++;
        
        if ( platformIndex == index )
        {
          String target = j.getTarget();
          if ( target.compareTo( "none" ) == 0 )
          {
            compileTarget = CompileTargets.NONE;
          }
          else
          if ( target.compareTo( "production" ) == 0 )
          {
            compileTarget = CompileTargets.PROD;
          }
          else
          if ( target.compareTo( "debug") == 0 )
          {
            compileTarget = CompileTargets.DEBUG;
          }
          else
          if ( target.compareTo( "all" ) == 0 )
          {
            compileTarget = CompileTargets.ALL;
          }
          else
          {
            reportErrorException( "Failure, unsupported build environment " + target + ", internal ABT problem", 256 );
          }
          Log( "execute buildStandard: ", buildStandard.getBuildStandard() );
          Log( "execute compileTarget: ", compileTarget.getCompileTarget() );
          break;
        }
      }
      
      for (Iterator<Ant> it=antCollection.iterator(); it.hasNext(); )
      {
        Ant a = it.next();
        index++;
        
        if ( platformIndex == index )
        {
          buildStandard = BuildStandards.ANT;
          String version = a.getJava();
          if ( version.compareTo( "none" ) == 0 )
          {
            javaVersion = JavaVersions.NONE;
          }
          else
          if ( version.compareTo( "1.4" ) == 0 )
          {
            javaVersion = JavaVersions.FOUR;
          }
          else
          if ( version.compareTo( "1.5" ) == 0 )
          {
            javaVersion = JavaVersions.FIVE;
          }
          else
          if ( version.compareTo( "1.6" ) == 0 )
          {
            javaVersion = JavaVersions.SIX;
          }
          else
          if ( version.compareTo( "1.7" ) == 0 )
          {
            javaVersion = JavaVersions.SEVEN;
          }
          else
          {
            reportErrorException( "Failure, unsupported build environment " + version + ", internal ABT problem", 256 );
          }
          Log( "execute buildStandard: ", buildStandard.getBuildStandard() );
          Log( "execute javaVersion: ", javaVersion.getJavaVersion() );
          break;
        }
      }
  }

  /** execute
   *  The Aant Task entry point. This is invoked to perform the
   *  targets action
   */
  public void execute()
  {
    boolean errorReported = false;
    boolean benign = false;


    try
    {
      re = new Redirector(this);
      
      // early ant built in
      project = getProject();
      // required by the Execute API on non win32 platforms, don't ask because I don't know
      project.setProperty("ant.home", System.getenv("ANT_HOME"));

      daemon = project.getProperty("abt_daemon");
      if ( daemon != null )
      {
        Log("execute daemon: yes", info);
      }

      // Get the current hostname
      // Perhaps this should be injected by the calling task
      // Daemon Mode:
      //    When sending emails
      //    Identify the target machine parameters
      // Escrow Mode:
      //    Deterime escrow build components    
      try
      {
        InetAddress local = InetAddress.getLocalHost();
        hostname = local.getHostName();
      }
      catch( UnknownHostException e )
      {
        // do nothing, shouldn't happen, but hostname will be "unknown" if it does
      }

      // early target related
      target = getOwningTarget();
      packageAlias = target.getName();
      packageVcsTag = project.getProperty(packageAlias + "packagevcstag");
      Log("execute packageVcsTag: ", packageVcsTag);
      
      if ( packageVcsTag == null )
      {
        // this abt task has no properties, by design
        // future use to estimate build completion time
        Log("execute packageAlias: " + packageAlias, info);
        return;
      }
      
      Log("execute packageAlias: " + packageAlias, warn);

      // ant built in
      basedir = project.getProperty("basedir");
      Log("execute basedir: ", basedir);
  
      // global

      if ( gbeMachtype == null ) {
        reportErrorException( "GBE_MACHTYPE environment variable not set", 256 );
      }

      mailServer = project.getProperty("abt_mail_server");
      if ( mailServer == null )
      {
          reportErrorException( "Missing ANT property: abt_mail_server", 256 );
      }
      Log("execute mailServer: ", mailServer);
  
      mailSender = project.getProperty( "abt_mail_sender" );
      if ( mailSender == null )
      {
          reportErrorException( "Missing ANT property: abt_mail_sender", 256 );
      }
      Log("execute mailSender: ", mailSender);

      for (Iterator<Owner> it=ABTData.ownerCollection.iterator(); it.hasNext(); )
      {
        Owner owner = it.next();
        
        if ( owners == null )
        {
          owners = new String();
        }
        else
        {
          owners += ",";
        }
        owners += owner.getEmail();
        Log("execute owner: ", owner.getEmail());
      }
      Log("execute owners: ", owners);

  
      // project related
      rtagId = project.getProperty("abt_rtag_id");
      Log("execute rtagId: ", rtagId);
      
      release = project.getProperty("abt_release");
      Log("execute release: ", release);

      buildtoolVersion = project.getProperty("abt_buildtool_version");
      Log("execute buildtoolVersion: ", buildtoolVersion);

      family = project.getProperty("abt_family");
      Log("execute family: ", family);

      oldExtension = project.getProperty("abt_old_extension");
      Log("execute oldExtension: ", oldExtension);

      newExtension = project.getProperty("abt_new_extension");
      Log("execute newExtension: ", newExtension);

      testBuildInstruction = project.getProperty("abt_test_build_instruction");
      Log("execute testBuildInstruction: ", testBuildInstruction);

      // Locate Machine Information for this machine
      //    It contains the build filter for the current machine
      //    Only present in daemon builds
      //
      for (Iterator<Machine> it=ABTData.machineCollection.iterator(); it.hasNext(); )
      {
        Machine ma = it.next();
        if (ma.getName().compareTo(hostname) == 0 )
        {
            mMachine = ma;
            Log("execute machine: ", mMachine.getName() + ", Type:" + mMachine.getMachtype() + ", Class:" + mMachine.getMachclass() + ", Master:" + mMachine.getMaster() ); 
            break;
        }
      }

      if ( (daemon != null) && (mMachine == null) ) {
          reportErrorException( "Cannot find Machine entry for: " + hostname, 256 );
      }
      
      //  Setup machine specific information
      //    Build Filter
      //    Master Mode
      if (mMachine != null) 
      {
          if (mMachine.getMaster() != null)
          {
            master = true;
            Log("execute master: ", "true");
          }

          gbebuildfilter = mMachine.getBuildfilter(); 
          if ( gbebuildfilter != null )
          {
            //
            // Ensure the Execute task passes gbebuildfilter as one parameter...
            // Replace spaces with commas
            //
            gbebuildfilter = gbebuildfilter.replace( " ", ",");
            Log("execute gbebuildfilter: ", gbebuildfilter);
          }
      }

      if ( testBuildInstruction == null )
      {
        // use a meaningful default
        testBuildInstruction = "0";
      }
  
      // redirect all thread (therefore jats) output to the output file in the basedir
      if ( daemon != null )
      {
        // thread logging is done to <rtagId>thread.log and is continually re-used every build
        // full thread and non thread (ie abt logging) is done to the DefaultLogger set up by the build daemons, <rtagId>.log
        // this file is copied on a build failure to cwd (if it exists) and is continually re-used every build
        output = new File( rtagId + "thread.log" );
        // capture full logging
        re.setAlwaysLog(true);
      }
      else
      {
        output = new File( packageAlias + ".log" );
      }

      re.setOutput( output );
      thread = new Execute(re.createHandler());
      thread.setAntRun( project );
      thread.setVMLauncher(false);

      // must set up package name and owners before reportError
      packageName = project.getProperty(packageAlias + "packagename");
      Log("execute packageName: ", packageName);
      
      //-----------------------------------------------------------------------
      //    AbtSetUp
      //
      if ( packageAlias.compareTo("AbtSetUp") == 0 )
      {
        // create rtag_id directory from scratch
        File rId = new File( rtagId );
        deleteDirectory( rId );
        rId.mkdirs();
          
        // jats jats_vcsrelease -extract -label=pkgVcsTag -path=src_path -root=rtag_id/timestamp -tag=timestamp -noprefix
        initCommand();
        addCommand( "jats" );
        addCommand( "jats_vcsrelease" );
        addCommand( "-extract" );
        addCommand( "-label=" + packageVcsTag );
        addCommand( "-root=" + rtagId );
        addCommand( "-tag=" + daemon );
        addCommand( "-noprefix" );
        addCommand( "-verbose=2" );

        runCommand( "Failure to extract source code from source control" );
        return;
      }

      //-----------------------------------------------------------------------
      //    AbtTearDown
      //
      if ( packageAlias.compareTo("AbtTearDown") == 0 )
      {
        // tear the build view down, regardless of build error
        wd = new File( basedir );
          
        // only now change the thread working directory back
        thread.setWorkingDirectory( wd );
        
        File buildDirectory = new File(wd + getProject().getProperty("abt_package_location"));
        
        if ( buildDirectory.exists() )
        {
          // jats jats_vcsrelease -label pkgTag -root=rtag_id/timestamp -tag=timestamp -noprefix -delete=2
          initCommand();
          addCommand( "jats" );
          addCommand( "jats_vcsrelease" );
          addCommand( "-label=" + packageVcsTag );
          addCommand( "-root=" + rtagId );
          addCommand( "-tag=" + daemon );
          addCommand( "-noprefix" );
          addCommand( "-delete=2" );
          addCommand( "-verbose=2" );

          runCommand( "Failure to remove source code extraction" );
        }

        // delete the rtag directory
        deleteDirectory( new File( rtagId ) );

        // Always save the log files
        saveLogs();

        return;      
      }
    
      // target related    
      packageVersion = project.getProperty(packageAlias + "packageversion");
      Log("execute packageVersion: ", packageVersion);

      packageExtension = project.getProperty(packageAlias + "packageextension");
      Log("execute packageExtension: ", packageExtension);

      packageFullVersion = packageVersion + packageExtension;
      Log("execute packageFullVersion: ", packageFullVersion);

      packageLoc = packageName + packageExtension;
      Log("execute packageLoc: ", packageLoc);
      
      generic = project.getProperty(packageAlias + "generic");
      if ( generic != null ) {
        Log("execute generic: yes", info);  
      }
      
      // Extract the build standard information from the abt element
      determineBuildStandard();

      directChange = project.getProperty(packageAlias + "directchange");
      if ( directChange != null )
      {
        Log("execute directChange: yes", info);  
      }
      
      doesNotRequireSourceControlInteraction = project.getProperty(packageAlias + "doesnotrequiresourcecontrolinteraction");
      if ( doesNotRequireSourceControlInteraction != null )
      {
        Log("execute doesNotRequireSourceControlInteraction: true", info);  
      }
      
      //    Display details of the Platform Jats and Ant elements within the
      //    current ABT element
      //
      for (Iterator<Platform> it=platformCollection.iterator(); it.hasNext(); )
      {
        Platform platform = it.next();
        Log("execute platform: ", platform.getGbe_Machtype());
      }
      
      for (Iterator<Jats> it=jatsCollection.iterator(); it.hasNext(); )
      {
        Jats jats = it.next();
        Log("execute jats: ", jats.getTarget());
      }
      
      for (Iterator<Ant> it=antCollection.iterator(); it.hasNext(); )
      {
        Ant ant = it.next();
        Log("execute ant: ", ant.getJava());
      }

      // Set newVsTag to the existing VcsTag
      // Will be used when rebuilding a package that already exists
      newVcsTag = packageVcsTag;

      loc = project.getProperty(packageAlias + "loc");
      Log("execute loc: ", loc);

      cwd = basedir + loc;
      Log("execute cwd: ", cwd);

      wd = new File( cwd );
      if ( !wd.exists() )
      {
        reportErrorException( "Failure " + cwd + " does not exist", 265 );
      }
      
      // only now change the thread working directory
      thread.setWorkingDirectory( wd );
      
      //-----------------------------------------------------------------------
      //    AbtPublish
      //    Note: Have changed directory to the working directory
      //
      if ( packageAlias.compareTo("AbtPublish") == 0 )
      {
        publish();
        if ( daemon != null )
        {
          // set properties to drive BuildThread attributes
          // these are used to determine what ant did
          getProject().setProperty("abt_fully_published", fullyPublished);
          getProject().setProperty("abt_new_vcstag", newVcsTag);
        }
        
        return;
      }
      
      //-----------------------------------------------------------------------
      //    Build Target
      //    Note: Have changed directory to the working directory
      //
      packageVersionID = project.getProperty(packageAlias + "pv_id");
      Log("execute packageVersionID: ", packageVersionID);
      unittests = project.getProperty(packageAlias + "unittests");
      
      if ( unittests != null )
      {
        Log("execute unittests: yes", info);
      }
      
      for (Iterator<Depend> it=dependCollection.iterator(); it.hasNext(); )
      {
        Depend depend = it.next();
        Log("execute depend: ", depend.getPackage_Alias());
      }
            
      if ( daemon == null )
      {
        // escrow centric
        // recognise an escrow will be run multiple times on a build stage
        // do not force continuous rebuilding each time
        // has this package version already been published on this platform
        String published = checkPublished( dpkg_archive, ( generic != null ) ? "generic" : hostname );

        if ( published.compareTo("no") != 0 )
        {
          Log( "execute package has been published on this platform - skipping", info);
          propertyValue = "257";
          throw new Exception();
        }
      }
      else
      {
        // DEVI 56714 daemon centric check
        String majorV = this.getClass().getPackage().getSpecificationVersion();
        
        if ( buildtoolVersion.compareTo( majorV ) != 0 )
        {
          reportErrorException( "Failure, incompatible build.xml not generated with version " + majorV, 256 );
        }
      }
      
      if ( ( buildStandard == BuildStandards.ANT && javaVersion == JavaVersions.NONE ) ||
           ( buildStandard == BuildStandards.JATS && compileTarget == CompileTargets.NONE ) )
      {
        //  Flag a benign build is good
        //  A benign is a no-operation. The build is not rquired on the current machine
        //  Issue: We have already extracted the source and will need to tear it down
        //
        benign = true;
      }
      
      // Pre Build processing
      //    Init metrics gathering
      //    Generate auto.pl or <PackageName>depends.xml file
      //
      genbuild();
      
      if ( !benign && gatherMetricsOnly == null )
      {
          //
          //    Build the target package
          //
          jatsBuildPackage();
      }
      
      if ( master )
      {
        File metrics = new File(basedir + fs + rtagId + "abtmetrics.txt");
        if ( metrics.exists() )
        {
          metrics.delete();
        }

        // gather metrics
        // jats -locatefile=.jats.packageroot etool jats_metrics -mode=finish -out=abtmetrics.txt
        initCommand();
        addCommand( "jats" );
        addCommand( "-locatefile=.jats.packageroot" );
        addCommand( "etool" );
        addCommand( "jats_metrics" );
        addCommand( "-mode=finish" );
        addCommand( "-out=" + metrics.getAbsolutePath() );

        runCommand( "Failure to collect metrics" );
      }
    }
    catch( SecurityException e)
    {
      errorReported = true;
      reportError( "Failure caught SecurityException", 256 );
    }
    catch( IOException e)
    {
      errorReported = true;
      reportError( "Failure caught IOException", 256 );
    }
    catch( Exception e)
    {
      // assume this condition has been reported on
      errorReported = true;

      if ( e.getMessage() != null )
      {
        Log( "execute caught Exception " + e.getMessage(), warn );
      }
      else
      {
        Log( "execute caught Exception", warn );
      }
    }
    finally
    {
      try
      {
        if ( daemon != null )
        {
          // do not write to publish.log
          throw new IOException();
        }
        
        FileWriter publish = new FileWriter( basedir + fs + "publish.log", true );
        if ( propertyValue.compareTo( "0" ) == 0 )
        {
          if ( benign )
          {
            publish.write( "successfully published " + packageName + " at " + packageFullVersion + ", no action required on this platform" );
          }
          else
          {
            publish.write( "successfully published " + packageName + " at " + packageFullVersion );
          }
          
          publish.write( ls );
        }
        else
        if ( propertyValue.compareTo( "256" ) == 0 )
        {
          publish.write( "failed to publish " + packageName + " at " + packageFullVersion +  ", internal abt issue" + ls );
        }
        else
        if ( propertyValue.compareTo( "257" ) == 0 )
        {
          errorReported = false;
          publish.write( "previously published " + packageName + " at " + packageFullVersion + ls );
        }
        else
        if ( propertyValue.compareTo( "262" ) == 0 )
        {
          publish.write( "failed to publish " + packageName + " at " + packageFullVersion + ", couldn't process save_build info" + ls );
        }
        else
        if ( propertyValue.compareTo( "263" ) == 0 )
        {
          publish.write( "failed to publish " + packageName + " at " + packageFullVersion + ", couldn't write to auto.cfg" + ls );
        }
        else
        if ( propertyValue.compareTo( "265" ) == 0 )
        {
          publish.write( "failed to publish " + packageName + " at " + packageFullVersion + ", " + cwd + " does not exist" + ls );
        }
        else
        {
          // nb jats or ant can presumably return a value 1 to 255
          publish.write( "failed to publish " + packageName + " at " + packageFullVersion + ", jats or ant failed" + ls );
        }

        publish.close();
      }
      catch( IOException e )
      {
        if ( daemon == null )
        {
          reportError( "Failure to write to publish.log", 266 );
        }
      }
      catch( Exception e )
      {
        if ( daemon == null )
        {
          reportError( "Failure to write to publish.log", 266 );
        }
      }

      getProject().setProperty(packageAlias + ".res", propertyValue);
      
      if ( errorReported )
      {
        // designed to prevent subsequent build activity on this build file
        // supply the build failure log file in message with / as file sep
        // takes the form hostname/rtag_id/daemon/logfile
        if ( daemon != null )
        {
          String message = hostname + "/" + rtagId + "/" + daemon + "/" + packageAlias + ".log";
          throw new BuildException( message );
        }
        else
        {
          throw new BuildException();
        }
      }

    }
  }
  
  private void deleteDirectory(File directory)
  {
    Log("deleteDirectory " + directory.getName(), debug);
    try
    {
      if ( directory.exists() )
      {
        File[] children = directory.listFiles();
        
        if ( children != null )
        {
          for ( int child=0; child < children.length; child++ )
          {
            Log("deleteDirectory deleting " + children[ child ].getName(), warn);

            if ( children[ child ].isDirectory() )
            {
              deleteDirectory( children[ child ] );
            }
            else
            {
              children[ child ].delete();
            }
          }
        }
        directory.delete();
      }
    }
    catch( SecurityException e )
    {
      // this can be thrown by exists and delete
       Log("deleteDirectory caught SecurityException", warn);
    }
  }

  //---------------------------------------------------------------------------
  //    Extend the <abt> task with several new elements
  // //
  //        <depend package_alias="${debian_dpkg.cots}"/>
  //        <platform gbe_machtype="solaris10_x86"/>
  //        <jats target="all"/>
  //        <ant java="java 1.6"/>
  //
  public Depend createDepend()
  {
    Depend depend = new Depend();
    dependCollection.add(depend);
    return depend;
  }
       
  public Platform createPlatform()
  {
    Platform platform = new Platform();
    platformCollection.add(platform);
    return platform;
  }
         
  public Jats createJats()
  {
    Jats jats = new Jats();
    jatsCollection.add(jats);
    return jats;
  }

  public Ant createAnt()
  {
    Ant ant = new Ant();
    antCollection.add(ant);
    return ant;
  }
}