diff options
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/SubAnt.java')
-rw-r--r-- | framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/SubAnt.java | 642 |
1 files changed, 642 insertions, 0 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/SubAnt.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/SubAnt.java new file mode 100644 index 00000000..35109faa --- /dev/null +++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/SubAnt.java @@ -0,0 +1,642 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.tools.ant.taskdefs; + +import java.io.File; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Vector; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Main; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.taskdefs.Ant.TargetElement; +import org.apache.tools.ant.types.DirSet; +import org.apache.tools.ant.types.FileList; +import org.apache.tools.ant.types.FileSet; +import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.types.PropertySet; +import org.apache.tools.ant.types.Reference; +import org.apache.tools.ant.types.ResourceCollection; + + +/** + * Calls a given target for all defined sub-builds. This is an extension + * of ant for bulk project execution. + * <p> + * <h2> Use with directories </h2> + * <p> + * subant can be used with directory sets to execute a build from different directories. + * 2 different options are offered + * </p> + * <ul> + * <li> + * run the same build file /somepath/otherpath/mybuild.xml + * with different base directories use the genericantfile attribute + * </li> + * <li>if you want to run directory1/build.xml, directory2/build.xml, .... + * use the antfile attribute. The base directory does not get set by the subant task in this case, + * because you can specify it in each build file. + * </li> + * </ul> + * @since Ant1.6 + * @ant.task name="subant" category="control" + */ +public class SubAnt extends Task { + + private Path buildpath; + + private Ant ant = null; + private String subTarget = null; + private String antfile = getDefaultBuildFile(); + private File genericantfile = null; + private boolean verbose = false; + private boolean inheritAll = false; + private boolean inheritRefs = false; + private boolean failOnError = true; + private String output = null; + + private Vector properties = new Vector(); + private Vector references = new Vector(); + private Vector propertySets = new Vector(); + + /** the targets to call on the new project */ + private Vector/*<TargetElement>*/ targets = new Vector(); + + /** + * Get the default build file name to use when launching the task. + * <p> + * This function may be overrided by providers of custom ProjectHelper so they can implement easily their sub + * launcher. + * + * @return the name of the default file + * @since Ant 1.8.0 + */ + protected String getDefaultBuildFile() { + return Main.DEFAULT_BUILD_FILENAME; + } + + /** + * Pass output sent to System.out to the new project. + * + * @param output a line of output + * @since Ant 1.6.2 + */ + @Override + public void handleOutput(String output) { + if (ant != null) { + ant.handleOutput(output); + } else { + super.handleOutput(output); + } + } + + /** + * Process input into the ant task + * + * @param buffer the buffer into which data is to be read. + * @param offset the offset into the buffer at which data is stored. + * @param length the amount of data to read + * + * @return the number of bytes read + * + * @exception IOException if the data cannot be read + * + * @see Task#handleInput(byte[], int, int) + * + * @since Ant 1.6.2 + */ + @Override + public int handleInput(byte[] buffer, int offset, int length) + throws IOException { + if (ant != null) { + return ant.handleInput(buffer, offset, length); + } else { + return super.handleInput(buffer, offset, length); + } + } + + /** + * Pass output sent to System.out to the new project. + * + * @param output The output to log. Should not be <code>null</code>. + * + * @since Ant 1.6.2 + */ + @Override + public void handleFlush(String output) { + if (ant != null) { + ant.handleFlush(output); + } else { + super.handleFlush(output); + } + } + + /** + * Pass output sent to System.err to the new project. + * + * @param output The error output to log. Should not be <code>null</code>. + * + * @since Ant 1.6.2 + */ + @Override + public void handleErrorOutput(String output) { + if (ant != null) { + ant.handleErrorOutput(output); + } else { + super.handleErrorOutput(output); + } + } + + /** + * Pass output sent to System.err to the new project. + * + * @param output The error output to log. Should not be <code>null</code>. + * + * @since Ant 1.6.2 + */ + @Override + public void handleErrorFlush(String output) { + if (ant != null) { + ant.handleErrorFlush(output); + } else { + super.handleErrorFlush(output); + } + } + + /** + * Runs the various sub-builds. + */ + @Override + public void execute() { + if (buildpath == null) { + throw new BuildException("No buildpath specified"); + } + + final String[] filenames = buildpath.list(); + final int count = filenames.length; + if (count < 1) { + log("No sub-builds to iterate on", Project.MSG_WARN); + return; + } +/* + //REVISIT: there must be cleaner way of doing this, if it is merited at all + if (subTarget == null) { + subTarget = getOwningTarget().getName(); + } +*/ + BuildException buildException = null; + for (int i = 0; i < count; ++i) { + File file = null; + String subdirPath = null; + Throwable thrownException = null; + try { + File directory = null; + file = new File(filenames[i]); + if (file.isDirectory()) { + if (verbose) { + subdirPath = file.getPath(); + log("Entering directory: " + subdirPath + "\n", Project.MSG_INFO); + } + if (genericantfile != null) { + directory = file; + file = genericantfile; + } else { + file = new File(file, antfile); + } + } + execute(file, directory); + if (verbose && subdirPath != null) { + log("Leaving directory: " + subdirPath + "\n", Project.MSG_INFO); + } + } catch (RuntimeException ex) { + if (!(getProject().isKeepGoingMode())) { + if (verbose && subdirPath != null) { + log("Leaving directory: " + subdirPath + "\n", Project.MSG_INFO); + } + throw ex; // throw further + } + thrownException = ex; + } catch (Throwable ex) { + if (!(getProject().isKeepGoingMode())) { + if (verbose && subdirPath != null) { + log("Leaving directory: " + subdirPath + "\n", Project.MSG_INFO); + } + throw new BuildException(ex); + } + thrownException = ex; + } + if (thrownException != null) { + if (thrownException instanceof BuildException) { + log("File '" + file + + "' failed with message '" + + thrownException.getMessage() + "'.", Project.MSG_ERR); + // only the first build exception is reported + if (buildException == null) { + buildException = (BuildException) thrownException; + } + } else { + log("Target '" + file + + "' failed with message '" + + thrownException.getMessage() + "'.", Project.MSG_ERR); + thrownException.printStackTrace(System.err); + if (buildException == null) { + buildException = + new BuildException(thrownException); + } + } + if (verbose && subdirPath != null) { + log("Leaving directory: " + subdirPath + "\n", Project.MSG_INFO); + } + } + } + // check if one of the builds failed in keep going mode + if (buildException != null) { + throw buildException; + } + } + + /** + * Runs the given target on the provided build file. + * + * @param file the build file to execute + * @param directory the directory of the current iteration + * @throws BuildException is the file cannot be found, read, is + * a directory, or the target called failed, but only if + * <code>failOnError</code> is <code>true</code>. Otherwise, + * a warning log message is simply output. + */ + private void execute(File file, File directory) + throws BuildException { + if (!file.exists() || file.isDirectory() || !file.canRead()) { + String msg = "Invalid file: " + file; + if (failOnError) { + throw new BuildException(msg); + } + log(msg, Project.MSG_WARN); + return; + } + + ant = createAntTask(directory); + String antfilename = file.getAbsolutePath(); + ant.setAntfile(antfilename); + final int size = targets.size(); + for (int i = 0; i < size; i++) { + TargetElement targetElement = (TargetElement) targets.get(i); + ant.addConfiguredTarget(targetElement); + } + + try { + if (verbose) { + log("Executing: " + antfilename, Project.MSG_INFO); + } + ant.execute(); + } catch (BuildException e) { + if (failOnError || isHardError(e)) { + throw e; + } + log("Failure for target '" + subTarget + + "' of: " + antfilename + "\n" + + e.getMessage(), Project.MSG_WARN); + } catch (Throwable e) { + if (failOnError || isHardError(e)) { + throw new BuildException(e); + } + log("Failure for target '" + subTarget + + "' of: " + antfilename + "\n" + + e.toString(), + Project.MSG_WARN); + } finally { + ant = null; + } + } + + /** whether we should even try to continue after this error */ + private boolean isHardError(Throwable t) { + if (t instanceof BuildException) { + return isHardError(t.getCause()); + } else if (t instanceof OutOfMemoryError) { + return true; + } else if (t instanceof ThreadDeath) { + return true; + } else { // incl. t == null + return false; + } + } + + /** + * This method builds the file name to use in conjunction with directories. + * + * <p>Defaults to "build.xml". + * If <code>genericantfile</code> is set, this attribute is ignored.</p> + * + * @param antfile the short build file name. Defaults to "build.xml". + */ + public void setAntfile(String antfile) { + this.antfile = antfile; + } + + /** + * This method builds a file path to use in conjunction with directories. + * + * <p>Use <code>genericantfile</code>, in order to run the same build file + * with different basedirs.</p> + * If this attribute is set, <code>antfile</code> is ignored. + * + * @param afile (path of the generic ant file, absolute or relative to + * project base directory) + * */ + public void setGenericAntfile(File afile) { + this.genericantfile = afile; + } + + /** + * Sets whether to fail with a build exception on error, or go on. + * + * @param failOnError the new value for this boolean flag. + */ + public void setFailonerror(boolean failOnError) { + this.failOnError = failOnError; + } + + /** + * The target to call on the different sub-builds. Set to "" to execute + * the default target. + * @param target the target + * <p> + */ + // REVISIT: Defaults to the target name that contains this task if not specified. + public void setTarget(String target) { + this.subTarget = target; + } + + /** + * Add a target to this Ant invocation. + * @param t the <code>TargetElement</code> to add. + * @since Ant 1.7 + */ + public void addConfiguredTarget(TargetElement t) { + String name = t.getName(); + if ("".equals(name)) { + throw new BuildException("target name must not be empty"); + } + targets.add(t); + } + + /** + * Enable/ disable verbose log messages showing when each sub-build path is entered/ exited. + * The default value is "false". + * @param on true to enable verbose mode, false otherwise (default). + */ + public void setVerbose(boolean on) { + this.verbose = on; + } + + /** + * Corresponds to <code><ant></code>'s + * <code>output</code> attribute. + * + * @param s the filename to write the output to. + */ + public void setOutput(String s) { + this.output = s; + } + + /** + * Corresponds to <code><ant></code>'s + * <code>inheritall</code> attribute. + * + * @param b the new value for this boolean flag. + */ + public void setInheritall(boolean b) { + this.inheritAll = b; + } + + /** + * Corresponds to <code><ant></code>'s + * <code>inheritrefs</code> attribute. + * + * @param b the new value for this boolean flag. + */ + public void setInheritrefs(boolean b) { + this.inheritRefs = b; + } + + /** + * Corresponds to <code><ant></code>'s + * nested <code><property></code> element. + * + * @param p the property to pass on explicitly to the sub-build. + */ + public void addProperty(Property p) { + properties.addElement(p); + } + + /** + * Corresponds to <code><ant></code>'s + * nested <code><reference></code> element. + * + * @param r the reference to pass on explicitly to the sub-build. + */ + public void addReference(Ant.Reference r) { + references.addElement(r); + } + + /** + * Corresponds to <code><ant></code>'s + * nested <code><propertyset></code> element. + * @param ps the propertyset + */ + public void addPropertyset(PropertySet ps) { + propertySets.addElement(ps); + } + + /** + * Adds a directory set to the implicit build path. + * <p> + * <em>Note that the directories will be added to the build path + * in no particular order, so if order is significant, one should + * use a file list instead!</em> + * + * @param set the directory set to add. + */ + public void addDirset(DirSet set) { + add(set); + } + + /** + * Adds a file set to the implicit build path. + * <p> + * <em>Note that the directories will be added to the build path + * in no particular order, so if order is significant, one should + * use a file list instead!</em> + * + * @param set the file set to add. + */ + public void addFileset(FileSet set) { + add(set); + } + + /** + * Adds an ordered file list to the implicit build path. + * <p> + * <em>Note that contrary to file and directory sets, file lists + * can reference non-existent files or directories!</em> + * + * @param list the file list to add. + */ + public void addFilelist(FileList list) { + add(list); + } + + /** + * Adds a resource collection to the implicit build path. + * + * @param rc the resource collection to add. + * @since Ant 1.7 + */ + public void add(ResourceCollection rc) { + getBuildpath().add(rc); + } + + /** + * Set the buildpath to be used to find sub-projects. + * + * @param s an Ant Path object containing the buildpath. + */ + public void setBuildpath(Path s) { + getBuildpath().append(s); + } + + /** + * Creates a nested build path, and add it to the implicit build path. + * + * @return the newly created nested build path. + */ + public Path createBuildpath() { + return getBuildpath().createPath(); + } + + /** + * Creates a nested <code><buildpathelement></code>, + * and add it to the implicit build path. + * + * @return the newly created nested build path element. + */ + public Path.PathElement createBuildpathElement() { + return getBuildpath().createPathElement(); + } + + /** + * Gets the implicit build path, creating it if <code>null</code>. + * + * @return the implicit build path. + */ + private Path getBuildpath() { + if (buildpath == null) { + buildpath = new Path(getProject()); + } + return buildpath; + } + + /** + * Buildpath to use, by reference. + * + * @param r a reference to an Ant Path object containing the buildpath. + */ + public void setBuildpathRef(Reference r) { + createBuildpath().setRefid(r); + } + + /** + * Creates the <ant> task configured to run a specific target. + * + * @param directory : if not null the directory where the build should run + * + * @return the ant task, configured with the explicit properties and + * references necessary to run the sub-build. + */ + private Ant createAntTask(File directory) { + Ant antTask = new Ant(this); + antTask.init(); + if (subTarget != null && subTarget.length() > 0) { + antTask.setTarget(subTarget); + } + + + if (output != null) { + antTask.setOutput(output); + } + + if (directory != null) { + antTask.setDir(directory); + } else { + antTask.setUseNativeBasedir(true); + } + + antTask.setInheritAll(inheritAll); + for (Enumeration i = properties.elements(); i.hasMoreElements();) { + copyProperty(antTask.createProperty(), (Property) i.nextElement()); + } + + for (Enumeration i = propertySets.elements(); i.hasMoreElements();) { + antTask.addPropertyset((PropertySet) i.nextElement()); + } + + antTask.setInheritRefs(inheritRefs); + for (Enumeration i = references.elements(); i.hasMoreElements();) { + antTask.addReference((Ant.Reference) i.nextElement()); + } + + return antTask; + } + + /** + * Assigns an Ant property to another. + * + * @param to the destination property whose content is modified. + * @param from the source property whose content is copied. + */ + private static void copyProperty(Property to, Property from) { + to.setName(from.getName()); + + if (from.getValue() != null) { + to.setValue(from.getValue()); + } + if (from.getFile() != null) { + to.setFile(from.getFile()); + } + if (from.getResource() != null) { + to.setResource(from.getResource()); + } + if (from.getPrefix() != null) { + to.setPrefix(from.getPrefix()); + } + if (from.getRefid() != null) { + to.setRefid(from.getRefid()); + } + if (from.getEnvironment() != null) { + to.setEnvironment(from.getEnvironment()); + } + if (from.getClasspath() != null) { + to.setClasspath(from.getClasspath()); + } + } + +} // END class SubAnt |