mbenson     2004/06/24 12:30:03

  Modified:    .        WHATSNEW
               docs/manual/CoreTasks ant.html antcall.html
               src/etc/testcases/taskdefs ant.xml calltarget.xml
               src/main/org/apache/tools/ant Project.java
               src/main/org/apache/tools/ant/taskdefs Ant.java
                        CallTarget.java
               src/testcases/org/apache/tools/ant/taskdefs AntTest.java
                        CallTargetTest.java
  Log:
  Added multiple targets to <ant> and <antcall> using nested <target> elements.
  PR: 5270, 8148, 17071, 6368, 29623
  
  Revision  Changes    Path
  1.631     +4 -0      ant/WHATSNEW
  
  Index: WHATSNEW
  ===================================================================
  RCS file: /home/cvs/ant/WHATSNEW,v
  retrieving revision 1.630
  retrieving revision 1.631
  diff -u -r1.630 -r1.631
  --- WHATSNEW  23 Jun 2004 19:41:27 -0000      1.630
  +++ WHATSNEW  24 Jun 2004 19:30:03 -0000      1.631
  @@ -21,6 +21,10 @@
   * A new base class DispatchTask has been added to facilitate elegant 
     creation of tasks with multiple actions.
   
  +* Added <target> nested elements to <ant> and <antcall> to allow
  +  specification of multiple sub-build targets, which are executed
  +  with a single dependency analysis.
  +
   Changes from Ant 1.6.1 to current Ant 1.6 CVS version
   =====================================================
   
  
  
  
  1.25      +20 -0     ant/docs/manual/CoreTasks/ant.html
  
  Index: ant.html
  ===================================================================
  RCS file: /home/cvs/ant/docs/manual/CoreTasks/ant.html,v
  retrieving revision 1.24
  retrieving revision 1.25
  diff -u -r1.24 -r1.25
  --- ant.html  3 Mar 2004 15:03:22 -0000       1.24
  +++ ant.html  24 Jun 2004 19:30:03 -0000      1.25
  @@ -135,6 +135,26 @@
   
   <p><em>since Ant 1.6</em>.</p>
   
  +<h4>target</h4>
  +
  +<p>You can specify multiple targets using nested &lt;target&gt; elements
  +instead of using the target attribute.  These will be executed as if
  +Ant had been invoked with a single target whose dependencies are the
  +targets so specified, in the order specified.</p>
  +<table border="1" cellpadding="2" cellspacing="0">
  +  <tr>
  +    <td valign="top"><b>Attribute</b></td>
  +    <td valign="top"><b>Description</b></td>
  +    <td align="center" valign="top"><b>Required</b></td>
  +  </tr>
  +  <tr>
  +    <td valign="top">name</td>
  +    <td valign="top">The name of the called target.</td>
  +    <td valign="top" align="center">Yes</td>
  +  </tr>
  +</table>
  +<p><em>since Ant 1.6.2</em>.</p>
  +
   <h3>Basedir of the new project</h3>
   
   <p>The basedir value of the new project is affected by the two
  
  
  
  1.25      +20 -0     ant/docs/manual/CoreTasks/antcall.html
  
  Index: antcall.html
  ===================================================================
  RCS file: /home/cvs/ant/docs/manual/CoreTasks/antcall.html,v
  retrieving revision 1.24
  retrieving revision 1.25
  diff -u -r1.24 -r1.25
  --- antcall.html      3 Mar 2004 15:03:22 -0000       1.24
  +++ antcall.html      24 Jun 2004 19:30:03 -0000      1.25
  @@ -120,6 +120,26 @@
   
   <p><em>since Ant 1.6</em>.</p>
   
  +<h4>target</h4>
  +
  +<p>You can specify multiple targets using nested &lt;target&gt; elements
  +instead of using the target attribute.  These will be executed as if
  +Ant had been invoked with a single target whose dependencies are the
  +targets so specified, in the order specified.</p>
  +<table border="1" cellpadding="2" cellspacing="0">
  +  <tr>
  +    <td valign="top"><b>Attribute</b></td>
  +    <td valign="top"><b>Description</b></td>
  +    <td align="center" valign="top"><b>Required</b></td>
  +  </tr>
  +  <tr>
  +    <td valign="top">name</td>
  +    <td valign="top">The name of the called target.</td>
  +    <td valign="top" align="center">Yes</td>
  +  </tr>
  +</table>
  +<p><em>since Ant 1.6.2</em>.</p>
  +
   <h3>Examples</h3>
   <pre>
     &lt;target name=&quot;default&quot;&gt;
  
  
  
  1.14      +22 -0     ant/src/etc/testcases/taskdefs/ant.xml
  
  Index: ant.xml
  ===================================================================
  RCS file: /home/cvs/ant/src/etc/testcases/taskdefs/ant.xml,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- ant.xml   10 Oct 2003 13:17:34 -0000      1.13
  +++ ant.xml   24 Jun 2004 19:30:03 -0000      1.14
  @@ -192,4 +192,26 @@
       </ant>
     </target>
   
  +  <target name="blank-target">
  +    <ant antfile="ant.topleveltest.xml">
  +      <target name="" />
  +    </ant>
  +  </target>
  +
  +  <target name="multiple-targets">
  +    <ant antfile="ant.xml">
  +      <target name="ta" />
  +      <target name="tb" />
  +      <target name="tc" />
  +    </ant>
  +  </target>
  +
  +  <target name="ta"><echo>ta</echo></target>
  +  <target name="tb" depends="da,dc"><echo>tb</echo></target>
  +  <target name="tc" depends="db,dc"><echo>tc</echo></target>
  +
  +  <target name="da"><echo>da</echo></target>
  +  <target name="db"><echo>db</echo></target>
  +  <target name="dc"><echo>dc</echo></target>
  +
   </project>
  
  
  
  1.4       +24 -1     ant/src/etc/testcases/taskdefs/calltarget.xml
  
  Index: calltarget.xml
  ===================================================================
  RCS file: /home/cvs/ant/src/etc/testcases/taskdefs/calltarget.xml,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- calltarget.xml    5 Aug 2003 13:56:26 -0000       1.3
  +++ calltarget.xml    24 Jun 2004 19:30:03 -0000      1.4
  @@ -50,4 +50,27 @@
               <param name="multi" value="SET"/>
           </antcall>
       </target>
  -</project>
  \ No newline at end of file
  +
  +    <target name="blank-target">
  +        <antcall>
  +            <target name="" />
  +        </antcall>
  +    </target>
  +
  +    <target name="multiple-targets">
  +        <antcall>
  +            <target name="ta" />
  +            <target name="tb" />
  +            <target name="tc" />
  +        </antcall>
  +    </target>
  +
  +    <target name="ta"><echo>ta</echo></target>
  +    <target name="tb" depends="da,dc"><echo>tb</echo></target>
  +    <target name="tc" depends="db,dc"><echo>tc</echo></target>
  +
  +    <target name="da"><echo>da</echo></target>
  +    <target name="db"><echo>db</echo></target>
  +    <target name="dc"><echo>dc</echo></target>
  +
  +</project>
  
  
  
  1.170     +41 -8     ant/src/main/org/apache/tools/ant/Project.java
  
  Index: Project.java
  ===================================================================
  RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/Project.java,v
  retrieving revision 1.169
  retrieving revision 1.170
  diff -u -r1.169 -r1.170
  --- Project.java      24 Jun 2004 11:16:40 -0000      1.169
  +++ Project.java      24 Jun 2004 19:30:03 -0000      1.170
  @@ -1187,7 +1187,16 @@
           // exist, and if there is any cycle in the dependency
           // graph.
           Vector sortedTargets = topoSort(targetName, targets);
  +        sortedTargets.setSize(sortedTargets.indexOf(targets.get(targetName)) 
+ 1);
  +        executeSortedTargets(sortedTargets);
  +    }
   
  +    /**
  +     * Executes a <CODE>Vector</CODE> of sorted targets.
  +     * @param sortedTargets   the aforementioned <CODE>Vector</CODE>.
  +     */
  +    public void executeSortedTargets(Vector sortedTargets)
  +        throws BuildException {
           Set succeededTargets = new HashSet();
           BuildException buildException = null; // first build exception
           for (Enumeration iter = sortedTargets.elements();
  @@ -1245,9 +1254,6 @@
                       }
                   }
               }
  -            if (curtarget.getName().equals(targetName)) { // old exit 
condition
  -                break;
  -            }
           }
           if (buildException != null) {
               throw buildException;
  @@ -1565,20 +1571,47 @@
        */
       public final Vector topoSort(String root, Hashtable targets)
           throws BuildException {
  +        return topoSort(new String[] {root}, targets);
  +    }
  +
  +    /**
  +     * Topologically sorts a set of targets.
  +     *
  +     * @param root <CODE>String[]</CODE> containing the names of the root 
targets.
  +     *             The sort is created in such a way that the sequence of 
Targets
  +     *             up to the root target is the minimum possible such 
sequence.
  +     *             Must not be <code>null</code>.
  +     * @param targets A map of names to targets (String to Target).
  +     *                Must not be <code>null</code>.
  +     * @return a vector of Target objects in sorted order.
  +     * @exception BuildException if there is a cyclic dependency among the
  +     *                           targets, or if a named target does not 
exist.
  +     */
  +    public final Vector topoSort(String[] root, Hashtable targets)
  +        throws BuildException {
           Vector ret = new Vector();
           Hashtable state = new Hashtable();
           Stack visiting = new Stack();
   
  -        // We first run a DFS based sort using the root as the starting node.
  -        // This creates the minimum sequence of Targets to the root node.
  +        // We first run a DFS based sort using each root as a starting node.
  +        // This creates the minimum sequence of Targets to the root node(s).
           // We then do a sort on any remaining unVISITED targets.
           // This is unnecessary for doing our build, but it catches
           // circular dependencies or missing Targets on the entire
           // dependency tree, not just on the Targets that depend on the
           // build Target.
   
  -        tsort(root, targets, state, visiting, ret);
  -        log("Build sequence for target `" + root + "' is " + ret, 
MSG_VERBOSE);
  +        for (int i = 0; i < root.length; i++) {
  +            tsort(root[i], targets, state, visiting, ret);
  +        }
  +        StringBuffer buf = new StringBuffer("Build sequence for target(s)");
  +
  +        for (int j = 0; j < root.length; j++) {
  +            buf.append((j == 0) ? " `" : ", `").append(root[j]).append('\'');
  +        }
  +        buf.append(" is " + ret);
  +        log(buf.toString(), MSG_VERBOSE);
  +
           for (Enumeration en = targets.keys(); en.hasMoreElements();) {
               String curTarget = (String) en.nextElement();
               String st = (String) state.get(curTarget);
  
  
  
  1.104     +83 -16    ant/src/main/org/apache/tools/ant/taskdefs/Ant.java
  
  Index: Ant.java
  ===================================================================
  RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/Ant.java,v
  retrieving revision 1.103
  retrieving revision 1.104
  diff -u -r1.103 -r1.104
  --- Ant.java  24 Jun 2004 11:56:20 -0000      1.103
  +++ Ant.java  24 Jun 2004 19:30:03 -0000      1.104
  @@ -71,9 +71,6 @@
        */
       private String antFile = null;
   
  -    /** the target to call if any */
  -    private String target = null;
  -
       /** the output */
       private String output  = null;
   
  @@ -98,6 +95,12 @@
       /** the sets of properties to pass to the new project */
       private Vector propertySets = new Vector();
   
  +    /** the targets to call on the new project */
  +    private Vector targets = new Vector();
  +
  +    /** whether the target attribute was specified **/
  +    private boolean targetAttributeSet = false;
  +
       /**
        * If true, pass all properties to the new Ant project.
        * Defaults to true.
  @@ -285,7 +288,7 @@
       public void execute() throws BuildException {
           File savedDir = dir;
           String savedAntFile = antFile;
  -        String savedTarget = target;
  +        Vector locals = new Vector(targets);
           try {
               if (newProject == null) {
                   reinit();
  @@ -317,8 +320,9 @@
               File file = FileUtils.newFileUtils().resolveFile(dir, antFile);
               antFile = file.getAbsolutePath();
   
  -            log("calling target " + (target != null ? target : "[default]")
  -                    + " in build file " +  antFile, Project.MSG_VERBOSE);
  +            log("calling target(s) "
  +                + ((locals.size() == 0) ? locals.toString() : "[default]")
  +                + " in build file " + antFile, Project.MSG_VERBOSE);
               newProject.setUserProperty("ant.file" , antFile);
   
               String thisAntFile = getProject().getProperty("ant.file");
  @@ -348,8 +352,11 @@
                       ex, getLocation());
               }
   
  -            if (target == null) {
  -                target = newProject.getDefaultTarget();
  +            if (locals.size() == 0) {
  +                String defaultTarget = newProject.getDefaultTarget();
  +                if (defaultTarget != null) {
  +                    locals.add(defaultTarget);
  +                }
               }
   
               if (newProject.getProperty("ant.file")
  @@ -358,13 +365,18 @@
   
                   String owningTargetName = getOwningTarget().getName();
   
  -                if (owningTargetName.equals(target)) {
  +                if (locals.contains(owningTargetName)) {
                       throw new BuildException(getTaskName() + " task calling "
                                                + "its own parent target.");
                   } else {
  -                    Target other =
  -                        (Target) getProject().getTargets().get(target);
  -                    if (other != null && other.dependsOn(owningTargetName)) {
  +                    boolean circular = false;
  +                    for (Iterator it = locals.iterator(); !circular && 
it.hasNext();) {
  +                        Target other = 
(Target)(getProject().getTargets().get(
  +                            (String)(it.next())));
  +                        circular |= (other != null
  +                            && other.dependsOn(owningTargetName));
  +                    }
  +                    if (circular) {
                           throw new BuildException(getTaskName()
                                                    + " task calling a target"
                                                    + " that depends on"
  @@ -377,12 +389,20 @@
   
               addReferences();
   
  -            if (target != null && !"".equals(target)) {
  +            if (locals.size() > 0 && !(locals.size() == 1 && locals.get(0) 
== "")) {
                   Throwable t = null;
                   try {
                       log("Entering " + antFile + "...", Project.MSG_VERBOSE);
                       newProject.fireSubBuildStarted();
  -                    newProject.executeTarget(target);
  +                    String[] nameArray =
  +                        (String[])(locals.toArray(new 
String[locals.size()]));
  +
  +                    Hashtable targets = newProject.getTargets();
  +                    Vector sortedTargets = newProject.topoSort(nameArray, 
targets);
  +
  +                    sortedTargets.setSize(sortedTargets.indexOf(targets.get(
  +                        locals.lastElement())) + 1);
  +                    newProject.executeSortedTargets(sortedTargets);
                   } catch (BuildException ex) {
                       t = ProjectHelper
                           .addLocationToBuildException(ex, getLocation());
  @@ -410,7 +430,6 @@
               }
               dir = savedDir;
               antFile = savedAntFile;
  -            target = savedTarget;
           }
       }
   
  @@ -601,7 +620,8 @@
               throw new BuildException("target attribute must not be empty");
           }
   
  -        this.target = s;
  +        targets.add(s);
  +        targetAttributeSet = true;
       }
   
       /**
  @@ -641,6 +661,23 @@
       }
   
       /**
  +     * Add a target to this Ant invocation.
  +     * @param target   the <CODE>TargetElement</CODE> to add.
  +     * @since Ant 1.7
  +     */
  +    public void addConfiguredTarget(TargetElement t) {
  +        if (targetAttributeSet) {
  +            throw new BuildException(
  +                "nested target is incompatible with the target attribute");
  +        }
  +        String name = t.getName();
  +        if (name.equals("")) {
  +            throw new BuildException("target name must not be empty");
  +        }
  +        targets.add(name);
  +    }
  +
  +    /**
        * Set of properties to pass to the new project.
        *
        * @param ps property set to add
  @@ -689,6 +726,36 @@
            */
           public String getToRefid() {
               return targetid;
  +        }
  +    }
  +
  +    /**
  +     * Helper class that implements the nested &lt;target&gt;
  +     * element of &lt;ant&gt; and &lt;antcall&gt;.
  +     * @since Ant 1.7
  +     */
  +    public static class TargetElement {
  +        private String name;
  +
  +        /**
  +         * Default constructor.
  +         */
  +        public TargetElement() {}
  +
  +        /**
  +         * Set the name of this TargetElement.
  +         * @param name   the <CODE>String</CODE> target name.
  +         */
  +        public void setName(String name) {
  +            this.name = name;
  +        }
  +
  +        /**
  +         * Get the name of this TargetElement.
  +         * @return <CODE>String</CODE>.
  +         */
  +        public String getName() {
  +            return name;
           }
       }
   }
  
  
  
  1.41      +24 -6     
ant/src/main/org/apache/tools/ant/taskdefs/CallTarget.java
  
  Index: CallTarget.java
  ===================================================================
  RCS file: 
/home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/CallTarget.java,v
  retrieving revision 1.40
  retrieving revision 1.41
  diff -u -r1.40 -r1.41
  --- CallTarget.java   9 Mar 2004 16:48:04 -0000       1.40
  +++ CallTarget.java   24 Jun 2004 19:30:03 -0000      1.41
  @@ -48,12 +48,13 @@
   public class CallTarget extends Task {
   
       private Ant callee;
  -    private String subTarget;
       // must match the default value of Ant#inheritAll
       private boolean inheritAll = true;
       // must match the default value of Ant#inheritRefs
       private boolean inheritRefs = false;
   
  +    private boolean targetSet = false;
  +
       /**
        * If true, pass all properties to the new Ant project.
        * Defaults to true.
  @@ -93,13 +94,13 @@
               init();
           }
   
  -        if (subTarget == null) {
  -            throw new BuildException("Attribute target is required.",
  -                                     getLocation());
  +        if (!targetSet) {
  +            throw new BuildException(
  +                "Attribute target or at least one nested target is 
required.",
  +                 getLocation());
           }
   
           callee.setAntfile(getProject().getProperty("ant.file"));
  -        callee.setTarget(subTarget);
           callee.setInheritAll(inheritAll);
           callee.setInheritRefs(inheritRefs);
           callee.execute();
  @@ -143,7 +144,24 @@
        * Target to execute, required.
        */
       public void setTarget(String target) {
  -        subTarget = target;
  +        if (callee == null) {
  +            init();
  +        }
  +        callee.setTarget(target);
  +        targetSet = true;
  +    }
  +
  +    /**
  +     * Target element identifying a data type to carry
  +     * over to the invoked target.
  +     * @since Ant 1.6.2
  +     */
  +    public void addConfiguredTarget(Ant.TargetElement t) {
  +        if (callee == null) {
  +            init();
  +        }
  +        callee.addConfiguredTarget(t);
  +        targetSet = true;
       }
   
       /**
  
  
  
  1.26      +9 -1      
ant/src/testcases/org/apache/tools/ant/taskdefs/AntTest.java
  
  Index: AntTest.java
  ===================================================================
  RCS file: 
/home/cvs/ant/src/testcases/org/apache/tools/ant/taskdefs/AntTest.java,v
  retrieving revision 1.25
  retrieving revision 1.26
  diff -u -r1.25 -r1.26
  --- AntTest.java      9 Mar 2004 16:48:56 -0000       1.25
  +++ AntTest.java      24 Jun 2004 19:30:03 -0000      1.26
  @@ -295,6 +295,14 @@
           project.removeBuildListener(pcFoo);
       }
   
  +    public void testBlankTarget() {
  +        expectBuildException("blank-target", "target name must not be 
empty");
  +    }
  +
  +    public void testMultipleTargets() {
  +        expectLog("multiple-targets", "tadadctbdbtc");
  +    }
  +
       private class BasedirChecker implements BuildListener {
           private String[] expectedBasedirs;
           private int calls = 0;
  
  
  
  1.8       +8 -0      
ant/src/testcases/org/apache/tools/ant/taskdefs/CallTargetTest.java
  
  Index: CallTargetTest.java
  ===================================================================
  RCS file: 
/home/cvs/ant/src/testcases/org/apache/tools/ant/taskdefs/CallTargetTest.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- CallTargetTest.java       9 Mar 2004 16:48:57 -0000       1.7
  +++ CallTargetTest.java       24 Jun 2004 19:30:03 -0000      1.8
  @@ -55,6 +55,14 @@
           assertLogContaining("multi is SETmulti is SET");
       }
   
  +    public void testBlankTarget() {
  +        expectBuildException("blank-target", "target name must not be 
empty");
  +    }
  +
  +    public void testMultipleTargets() {
  +        expectLog("multiple-targets", "tadadctbdbtc");
  +    }
  +
       public void tearDown() {
           project.executeTarget("cleanup");
       }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to