Move keep-going awareness to Executors. PR: 22901 Submitted by: Alexey Solofnenko Reviewed by: Matt Benson git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@278114 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -0,0 +1,12 @@ | |||||
| <project> | |||||
| <target name="foo"> | |||||
| <echo>foo</echo> | |||||
| <fail if="failfoo" message="failfoo" /> | |||||
| </target> | |||||
| <target name="a" depends="foo"> | |||||
| <echo>a</echo> | |||||
| </target> | |||||
| <target name="b" depends="foo"> | |||||
| <echo>b</echo> | |||||
| </target> | |||||
| </project> | |||||
| @@ -1,5 +1,5 @@ | |||||
| /* | /* | ||||
| * Copyright 2004 The Apache Software Foundation | |||||
| * Copyright 2004-2005 The Apache Software Foundation | |||||
| * | * | ||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| * you may not use this file except in compliance with the License. | * you may not use this file except in compliance with the License. | ||||
| @@ -31,4 +31,11 @@ public interface Executor { | |||||
| */ | */ | ||||
| void executeTargets(Project project, String[] targetNames) | void executeTargets(Project project, String[] targetNames) | ||||
| throws BuildException; | throws BuildException; | ||||
| /** | |||||
| * Get the appropriate subproject Executor instance. | |||||
| * @return an Executor instance. | |||||
| */ | |||||
| Executor getSubProjectExecutor(); | |||||
| } | } | ||||
| @@ -37,7 +37,6 @@ import java.util.WeakHashMap; | |||||
| import org.apache.tools.ant.input.DefaultInputHandler; | import org.apache.tools.ant.input.DefaultInputHandler; | ||||
| import org.apache.tools.ant.input.InputHandler; | import org.apache.tools.ant.input.InputHandler; | ||||
| import org.apache.tools.ant.helper.DefaultExecutor; | import org.apache.tools.ant.helper.DefaultExecutor; | ||||
| import org.apache.tools.ant.helper.KeepGoingExecutor; | |||||
| import org.apache.tools.ant.types.FilterSet; | import org.apache.tools.ant.types.FilterSet; | ||||
| import org.apache.tools.ant.types.FilterSetCollection; | import org.apache.tools.ant.types.FilterSetCollection; | ||||
| import org.apache.tools.ant.types.Description; | import org.apache.tools.ant.types.Description; | ||||
| @@ -243,6 +242,7 @@ public class Project { | |||||
| ComponentHelper.getComponentHelper(subProject) | ComponentHelper.getComponentHelper(subProject) | ||||
| .initSubProject(ComponentHelper.getComponentHelper(this)); | .initSubProject(ComponentHelper.getComponentHelper(this)); | ||||
| subProject.setKeepGoingMode(this.isKeepGoingMode()); | subProject.setKeepGoingMode(this.isKeepGoingMode()); | ||||
| subProject.setExecutor(getExecutor().getSubProjectExecutor()); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -1015,23 +1015,23 @@ public class Project { | |||||
| } | } | ||||
| /** | /** | ||||
| * Execute the specified sequence of targets, and the targets | |||||
| * they depend on. | |||||
| * | |||||
| * @param targetNames A vector of target name strings to execute. | |||||
| * Must not be <code>null</code>. | |||||
| * | |||||
| * @exception BuildException if the build failed. | |||||
| * Set the Executor instance for this Project. | |||||
| * @param e the Executor to use. | |||||
| */ | */ | ||||
| public void executeTargets(Vector targetNames) throws BuildException { | |||||
| public void setExecutor(Executor e) { | |||||
| addReference("ant.executor", e); | |||||
| } | |||||
| /** | |||||
| * Get this Project's Executor (setting it if necessary). | |||||
| * @return an Executor instance. | |||||
| */ | |||||
| public Executor getExecutor() { | |||||
| Object o = getReference("ant.executor"); | Object o = getReference("ant.executor"); | ||||
| if (o == null) { | if (o == null) { | ||||
| String classname = getProperty("ant.executor.class"); | String classname = getProperty("ant.executor.class"); | ||||
| if (classname == null) { | if (classname == null) { | ||||
| classname = (keepGoingMode) | |||||
| ? KeepGoingExecutor.class.getName() | |||||
| : DefaultExecutor.class.getName(); | |||||
| classname = DefaultExecutor.class.getName(); | |||||
| } | } | ||||
| log("Attempting to create object of type " + classname, MSG_DEBUG); | log("Attempting to create object of type " + classname, MSG_DEBUG); | ||||
| try { | try { | ||||
| @@ -1046,17 +1046,27 @@ public class Project { | |||||
| } catch (Exception ex) { | } catch (Exception ex) { | ||||
| log(ex.toString(), MSG_ERR); | log(ex.toString(), MSG_ERR); | ||||
| } | } | ||||
| if (o != null) { | |||||
| addReference("ant.executor", o); | |||||
| if (o == null) { | |||||
| throw new BuildException( | |||||
| "Unable to obtain a Target Executor instance."); | |||||
| } | } | ||||
| setExecutor((Executor) o); | |||||
| } | } | ||||
| if (o == null) { | |||||
| throw new BuildException("Unable to obtain a Target Executor instance."); | |||||
| } else { | |||||
| String[] targetNameArray = (String[]) (targetNames.toArray( | |||||
| new String[targetNames.size()])); | |||||
| ((Executor) o).executeTargets(this, targetNameArray); | |||||
| } | |||||
| return (Executor) o; | |||||
| } | |||||
| /** | |||||
| * Execute the specified sequence of targets, and the targets | |||||
| * they depend on. | |||||
| * | |||||
| * @param names A vector of target name strings to execute. | |||||
| * Must not be <code>null</code>. | |||||
| * | |||||
| * @exception BuildException if the build failed. | |||||
| */ | |||||
| public void executeTargets(Vector names) throws BuildException { | |||||
| getExecutor().executeTargets(this, | |||||
| (String[]) (names.toArray(new String[names.size()]))); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -1,5 +1,5 @@ | |||||
| /* | /* | ||||
| * Copyright 2004 The Apache Software Foundation | |||||
| * Copyright 2004-2005 The Apache Software Foundation | |||||
| * | * | ||||
| * Licensed under the Apache License, Version 2.0 (the "License"); | * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| * you may not use this file except in compliance with the License. | * you may not use this file except in compliance with the License. | ||||
| @@ -17,25 +17,43 @@ | |||||
| package org.apache.tools.ant.helper; | package org.apache.tools.ant.helper; | ||||
| import org.apache.tools.ant.Project; | import org.apache.tools.ant.Project; | ||||
| import org.apache.tools.ant.Executor; | import org.apache.tools.ant.Executor; | ||||
| import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
| /** | /** | ||||
| * Default Target executor implementation. Runs each target individually | * Default Target executor implementation. Runs each target individually | ||||
| * (including all of its dependencies), halting immediately upon error. | |||||
| * (including all of its dependencies). If an error occurs, behavior is | |||||
| * determined by the Project's "keep-going" mode. | |||||
| * @since Ant 1.6.3 | * @since Ant 1.6.3 | ||||
| */ | */ | ||||
| public class DefaultExecutor implements Executor { | public class DefaultExecutor implements Executor { | ||||
| private static final SingleCheckExecutor SUB_EXECUTOR = new SingleCheckExecutor(); | |||||
| //inherit doc | //inherit doc | ||||
| public void executeTargets(Project project, String[] targetNames) | public void executeTargets(Project project, String[] targetNames) | ||||
| throws BuildException { | throws BuildException { | ||||
| BuildException thrownException = null; | |||||
| for (int i = 0; i < targetNames.length; i++) { | for (int i = 0; i < targetNames.length; i++) { | ||||
| project.executeTarget(targetNames[i]); | |||||
| try { | |||||
| project.executeTarget(targetNames[i]); | |||||
| } catch (BuildException ex) { | |||||
| if (project.isKeepGoingMode()) { | |||||
| thrownException = ex; | |||||
| } else { | |||||
| throw ex; | |||||
| } | |||||
| } | |||||
| } | |||||
| if (thrownException != null) { | |||||
| throw thrownException; | |||||
| } | } | ||||
| } | } | ||||
| //inherit doc | |||||
| public Executor getSubProjectExecutor() { | |||||
| return SUB_EXECUTOR; | |||||
| } | |||||
| } | } | ||||
| @@ -38,4 +38,9 @@ public class SingleCheckExecutor implements Executor { | |||||
| project.topoSort(targetNames, project.getTargets(), false)); | project.topoSort(targetNames, project.getTargets(), false)); | ||||
| } | } | ||||
| //inherit doc | |||||
| public Executor getSubProjectExecutor() { | |||||
| return this; | |||||
| } | |||||
| } | } | ||||
| @@ -64,9 +64,6 @@ import org.apache.tools.ant.util.FileUtils; | |||||
| */ | */ | ||||
| public class Ant extends Task { | public class Ant extends Task { | ||||
| /** Target Executor */ | |||||
| private static final Executor EXECUTOR = new SingleCheckExecutor(); | |||||
| private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); | private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); | ||||
| /** the basedir where is executed the build file */ | /** the basedir where is executed the build file */ | ||||
| @@ -396,9 +393,7 @@ public class Ant extends Task { | |||||
| try { | try { | ||||
| log("Entering " + antFile + "...", Project.MSG_VERBOSE); | log("Entering " + antFile + "...", Project.MSG_VERBOSE); | ||||
| newProject.fireSubBuildStarted(); | newProject.fireSubBuildStarted(); | ||||
| EXECUTOR.executeTargets(newProject, | |||||
| (String[]) (locals.toArray(new String[locals.size()]))); | |||||
| newProject.executeTargets(locals); | |||||
| } catch (BuildException ex) { | } catch (BuildException ex) { | ||||
| t = ProjectHelper | t = ProjectHelper | ||||
| .addLocationToBuildException(ex, getLocation()); | .addLocationToBuildException(ex, getLocation()); | ||||
| @@ -755,4 +750,4 @@ public class Ant extends Task { | |||||
| return name; | return name; | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| } | |||||
| @@ -0,0 +1,129 @@ | |||||
| /* | |||||
| * Copyright 2005 The Apache Software Foundation | |||||
| * | |||||
| * Licensed 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; | |||||
| import java.util.Vector; | |||||
| import org.apache.tools.ant.taskdefs.Exit; | |||||
| /** | |||||
| * Executor tests | |||||
| */ | |||||
| public class ExecutorTest extends BuildFileTest implements BuildListener { | |||||
| private static final String SINGLE_CHECK | |||||
| = "org.apache.tools.ant.helper.SingleCheckExecutor"; | |||||
| private static final Vector targetNames; | |||||
| static { | |||||
| targetNames = new Vector(); | |||||
| targetNames.add("a"); | |||||
| targetNames.add("b"); | |||||
| } | |||||
| private int targetCount; | |||||
| /* BuildListener stuff */ | |||||
| public void targetStarted(BuildEvent event) { | |||||
| targetCount++; | |||||
| } | |||||
| public void buildStarted(BuildEvent event) {} | |||||
| public void buildFinished(BuildEvent event) {} | |||||
| public void targetFinished(BuildEvent event) {} | |||||
| public void taskStarted(BuildEvent event) {} | |||||
| public void taskFinished(BuildEvent event) {} | |||||
| public void messageLogged(BuildEvent event) {} | |||||
| public ExecutorTest(String name) { | |||||
| super(name); | |||||
| } | |||||
| public void setUp() { | |||||
| configureProject("src/etc/testcases/core/executor.xml"); | |||||
| targetCount = 0; | |||||
| getProject().addBuildListener(this); | |||||
| } | |||||
| private Project getProject(String e) { | |||||
| return getProject(e, false); | |||||
| } | |||||
| private Project getProject(String e, boolean f) { | |||||
| return getProject(e, f, false); | |||||
| } | |||||
| private Project getProject(String e, boolean f, boolean k) { | |||||
| Project p = getProject(); | |||||
| p.setNewProperty("ant.executor.class", e); | |||||
| p.setKeepGoingMode(k); | |||||
| if (f) { | |||||
| p.setNewProperty("failfoo", "foo"); | |||||
| } | |||||
| return p; | |||||
| } | |||||
| public void testDefaultExecutor() { | |||||
| getProject().executeTargets(targetNames); | |||||
| assertEquals(targetCount, 4); | |||||
| } | |||||
| public void testSingleCheckExecutor() { | |||||
| getProject(SINGLE_CHECK).executeTargets(targetNames); | |||||
| assertEquals(targetCount, 3); | |||||
| } | |||||
| public void testDefaultFailure() { | |||||
| try { | |||||
| getProject(null, true).executeTargets(targetNames); | |||||
| fail("should fail"); | |||||
| } catch (BuildException e) { | |||||
| assertTrue(e.getMessage().equals("failfoo")); | |||||
| assertEquals(targetCount, 1); | |||||
| } | |||||
| } | |||||
| public void testSingleCheckFailure() { | |||||
| try { | |||||
| getProject(SINGLE_CHECK, true).executeTargets(targetNames); | |||||
| fail("should fail"); | |||||
| } catch (BuildException e) { | |||||
| assertTrue(e.getMessage().equals("failfoo")); | |||||
| assertEquals(targetCount, 1); | |||||
| } | |||||
| } | |||||
| public void testKeepGoingDefault() { | |||||
| try { | |||||
| getProject(null, true, true).executeTargets(targetNames); | |||||
| fail("should fail"); | |||||
| } catch (BuildException e) { | |||||
| assertTrue(e.getMessage().equals("failfoo")); | |||||
| assertEquals(targetCount, 2); | |||||
| } | |||||
| } | |||||
| public void testKeepGoingSingleCheck() { | |||||
| try { | |||||
| getProject(SINGLE_CHECK, true, true).executeTargets(targetNames); | |||||
| fail("should fail"); | |||||
| } catch (BuildException e) { | |||||
| assertTrue(e.getMessage().equals("failfoo")); | |||||
| assertEquals(targetCount, 1); | |||||
| } | |||||
| } | |||||
| } | |||||