You are viewing a plain text version of this content. The canonical link for it is here.
Posted to easyant-commits@incubator.apache.org by hi...@apache.org on 2011/02/17 17:01:56 UTC

svn commit: r1071697 [23/42] - in /incubator/easyant: buildtypes/ buildtypes/trunk/ buildtypes/trunk/build-osgi-bundle-java/ buildtypes/trunk/build-osgi-bundle-java/src/ buildtypes/trunk/build-osgi-bundle-java/src/main/ buildtypes/trunk/build-osgi-bund...

Added: incubator/easyant/core/trunk/src/main/java/org/apache/easyant/tasks/menu/RegisterMenuGeneratorTask.java
URL: http://svn.apache.org/viewvc/incubator/easyant/core/trunk/src/main/java/org/apache/easyant/tasks/menu/RegisterMenuGeneratorTask.java?rev=1071697&view=auto
==============================================================================
--- incubator/easyant/core/trunk/src/main/java/org/apache/easyant/tasks/menu/RegisterMenuGeneratorTask.java (added)
+++ incubator/easyant/core/trunk/src/main/java/org/apache/easyant/tasks/menu/RegisterMenuGeneratorTask.java Thu Feb 17 17:01:07 2011
@@ -0,0 +1,151 @@
+/* 
+ *  Copyright 2008-2010 the EasyAnt project
+ * 
+ *  See the NOTICE file distributed with this work for additional information
+ *  regarding copyright ownership. 
+ * 
+ *  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.easyant.tasks.menu;
+
+import org.apache.easyant.core.menu.MenuGenerator;
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.util.ClasspathUtils;
+
+import java.io.IOException;
+
+/**
+ * This {@link Task} is used to register a new MenuGenerator to a given context.
+ */
+public class RegisterMenuGeneratorTask extends AbstractMenuGeneratorTask {
+
+    /**
+     * Lists built-in menu generator types, which can be specified with a short name rather
+     * than full classname.
+     */
+    public static enum BuiltinType {
+        xooki("org.apache.easyant.menu.XookiMenuGenerator");
+
+        private String generator;
+        private BuiltinType(String generator) {
+            this.generator = generator;
+        }
+
+        public String getGeneratorClassName() {
+            return generator;
+        }
+    }
+
+    private String className;
+    private BuiltinType type;
+	private Path classpath;
+
+	@Override
+	public void execute() throws BuildException {
+		if (getClassName() == null) {
+			throw new BuildException("either className or type argument is required !");
+		}
+
+		MenuGenerator menuGenerator = (MenuGenerator) ClasspathUtils.newInstance(getClassName(), getClassLoader(), MenuGenerator.class);
+		getMenuGeneratorForContext(getContext()).addMenuGenerator(menuGenerator);
+	}
+
+	/**
+	 * Get the classname to register
+	 * @return a classname
+	 */
+	public String getClassName() {
+		return className;
+	}
+
+	/**
+	 * Set the classname to register
+	 * @param className a classname
+	 */
+	public void setClassName(String className) {
+		this.className = className;
+	}
+
+    public BuiltinType getType() {
+        return type;
+    }
+
+    /**
+     * Set a builtin type to use, as an alternative to {@link #setClassName(String)}.
+     */
+    public void setType(BuiltinType type) {
+        this.type = type;
+        if (type != null) {
+            setClassName(type.getGeneratorClassName());
+        }
+    }
+
+    protected AntClassLoader getClassLoader() {
+		// defining a new specialized classloader and setting it as the thread
+		// context classloader
+		AntClassLoader loader = null;
+		if (classpath != null) {
+			loader = new AntClassLoader(this.getClass().getClassLoader(),
+					getProject(), classpath, false);
+		} else {
+			loader = new AntClassLoader(this.getClass().getClassLoader(),
+					false);
+		}
+		loader.setThreadContextLoader();
+		return loader;
+	}
+	
+	/**
+	 * Get the classpath used to locate the specified classname
+	 * @return a classpath
+	 */
+	public Path getClasspath() {
+		return classpath;
+	}
+	
+	
+		/**
+		 * The the classpath used to locate the specified classname
+		 * 
+		 * @param classpath
+		 */
+		public void setClasspath(Path classpath) {
+			createClasspath().append(classpath);
+		}
+
+		/**
+		 * Classpath to use, by reference, when compiling the rulebase
+		 * 
+		 * @param a reference to an existing classpath
+		 */
+		public void setClasspathref(Reference r) {
+			createClasspath().setRefid(r);
+		}
+
+		/**
+		 * Adds a path to the classpath.
+		 * 
+		 * @return created classpath
+		 */
+		public Path createClasspath() {
+			if (this.classpath == null) {
+				this.classpath = new Path(getProject());
+			}
+			return this.classpath.createPath();
+		}
+
+}

Propchange: incubator/easyant/core/trunk/src/main/java/org/apache/easyant/tasks/menu/RegisterMenuGeneratorTask.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/easyant/core/trunk/src/main/java/org/apache/easyant/tasks/menu/RegisterMenuGeneratorTask.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision Author HeadURL Id

Propchange: incubator/easyant/core/trunk/src/main/java/org/apache/easyant/tasks/menu/RegisterMenuGeneratorTask.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: incubator/easyant/core/trunk/src/main/java/org/apache/easyant/tasks/menu/StartMenuTask.java
URL: http://svn.apache.org/viewvc/incubator/easyant/core/trunk/src/main/java/org/apache/easyant/tasks/menu/StartMenuTask.java?rev=1071697&view=auto
==============================================================================
--- incubator/easyant/core/trunk/src/main/java/org/apache/easyant/tasks/menu/StartMenuTask.java (added)
+++ incubator/easyant/core/trunk/src/main/java/org/apache/easyant/tasks/menu/StartMenuTask.java Thu Feb 17 17:01:07 2011
@@ -0,0 +1,45 @@
+package org.apache.easyant.tasks.menu;
+
+import org.apache.easyant.core.menu.MenuGenerator;
+import org.apache.tools.ant.BuildException;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Create a new menu using any registered generators.
+ */
+public class StartMenuTask extends AbstractMenuGeneratorTask {
+
+	private String file;
+
+	@Override
+	public void execute() throws BuildException {
+		if (getFile() == null) {
+			throw new BuildException("file argument is required !");
+		}
+
+		//TODO: this isn't quite right.  we shouldn't be passing the same file argument to every generator.
+		List<MenuGenerator> generators = getMenuGeneratorForContext(getContext()).getMenuGenerators();
+		for (MenuGenerator generator : generators) {
+			try {
+			    generator.startMenu(getContext(), getFile());
+			} catch (IOException ioe) {
+			    throw new BuildException("Error writing menu file " + getFile() + ": " + ioe.getMessage(), ioe);
+			}
+		}
+	}
+
+	/**
+	 * Get the file associated to this generator
+	 * @return a file
+	 */
+	public String getFile() {
+		return file;
+	}
+
+	public void setFile(String file) {
+		this.file = file;
+	}
+
+}

Propchange: incubator/easyant/core/trunk/src/main/java/org/apache/easyant/tasks/menu/StartMenuTask.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/easyant/core/trunk/src/main/java/org/apache/easyant/tasks/menu/StartMenuTask.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision Author HeadURL Id

Propchange: incubator/easyant/core/trunk/src/main/java/org/apache/easyant/tasks/menu/StartMenuTask.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: incubator/easyant/core/trunk/src/main/patches/ant-697121-easyant-patch.diff
URL: http://svn.apache.org/viewvc/incubator/easyant/core/trunk/src/main/patches/ant-697121-easyant-patch.diff?rev=1071697&view=auto
==============================================================================
--- incubator/easyant/core/trunk/src/main/patches/ant-697121-easyant-patch.diff (added)
+++ incubator/easyant/core/trunk/src/main/patches/ant-697121-easyant-patch.diff Thu Feb 17 17:01:07 2011
@@ -0,0 +1,461 @@
+Index: src/main/org/apache/tools/ant/helper/AntXMLContext.java
+===================================================================
+--- src/main/org/apache/tools/ant/helper/AntXMLContext.java	(révision 697121)
++++ src/main/org/apache/tools/ant/helper/AntXMLContext.java	(copie de travail)
+@@ -95,6 +95,9 @@
+ 
+     /** Keeps track of targets in files */
+     private Map currentTargets = null;
++    
++    /** The prefix to use in import 'use' mode */
++    private String usePrefix = null;
+ 
+     /**
+      * constructor
+@@ -362,6 +365,24 @@
+         this.currentTargets = currentTargets;
+     }
+ 
++    /**
++	 * Get the prefix to use in import 'use' mode.
++	 * 
++	 * @return the prefix to use in import 'use' mode, <code>null</code> if we
++	 *         are not parsing file in import 'use' mode.
++	 */
++	public String getUsePrefix() {
++		return usePrefix;
++	}
++    
++    /**
++	 * Set the prefix to use in import 'use' mode.
++	 * 
++	 * @param usePrefix the prefix to use in import 'use' mode.
++	 */
++    public void setUsePrefix(String usePrefix) {
++		this.usePrefix = usePrefix;
++	}
+ }
+ 
+ 
+Index: src/main/org/apache/tools/ant/helper/ProjectHelper2.java
+===================================================================
+--- src/main/org/apache/tools/ant/helper/ProjectHelper2.java	(révision 697121)
++++ src/main/org/apache/tools/ant/helper/ProjectHelper2.java	(copie de travail)
+@@ -47,6 +47,7 @@
+ import java.util.Hashtable;
+ import java.util.Map;
+ import java.util.Stack;
++import java.util.StringTokenizer;
+ 
+ /**
+  * Sax2 based project reader
+@@ -139,6 +140,7 @@
+             context = new AntXMLContext(project);
+             project.addReference(REFID_CONTEXT, context);
+             project.addReference(REFID_TARGETS, context.getTargets());
++            setContext(context);
+         }
+         if (getImportStack().size() > 1) {
+             // we are in an imported file.
+@@ -727,6 +729,16 @@
+                         MagicNames.ANT_FILE + "." + context.getCurrentProjectName(), context
+                                 .getBuildFile().toString());
+             }
++            String usePrefix = context.getUsePrefix();
++            if ("${ant.project.name}".equals(usePrefix)) {
++            	// the use prefix to use is the default one: the current project name
++            	context.setUsePrefix(usePrefix = context.getCurrentProjectName());
++            }
++            if (usePrefix != null) {
++            	project.log("importing project in 'use' mode: "
++            			+ "all targets will be prefixed with '" + usePrefix +"'", 
++            			Project.MSG_VERBOSE);
++            }
+             if (context.isIgnoringProjectTag()) {
+                 // no further processing
+                 return;
+@@ -773,7 +785,8 @@
+          */
+         public AntHandler onStartChild(String uri, String name, String qname, Attributes attrs,
+                                        AntXMLContext context) throws SAXParseException {
+-            return name.equals("target") && (uri.equals("") || uri.equals(ANT_CORE_URI))
++            return (name.equals("target") || name.equals("phase")) 
++            			&& (uri.equals("") || uri.equals(ANT_CORE_URI))
+                     ? ProjectHelper2.targetHandler : ProjectHelper2.elementHandler;
+         }
+     }
+@@ -807,12 +820,15 @@
+                                    AntXMLContext context) throws SAXParseException {
+             String name = null;
+             String depends = "";
++            String phase = "";
+ 
+             Project project = context.getProject();
+             Target target = new Target();
+             target.setProject(project);
+             target.setLocation(new Location(context.getLocator()));
+             context.addTarget(target);
++            
++            target.setType(tag);
+ 
+             for (int i = 0; i < attrs.getLength(); i++) {
+                 String attrUri = attrs.getURI(i);
+@@ -829,6 +845,8 @@
+                     }
+                 } else if (key.equals("depends")) {
+                     depends = value;
++                } else if (key.equals("phase")) {
++                    phase = value;
+                 } else if (key.equals("if")) {
+                     target.setIf(value);
+                 } else if (key.equals("unless")) {
+@@ -839,6 +857,8 @@
+                     }
+                 } else if (key.equals("description")) {
+                     target.setDescription(value);
++                } else if (key.equals("type")) {
++                    target.setType(value);
+                 } else {
+                     throw new SAXParseException("Unexpected attribute \"" + key + "\"", context
+                             .getLocator());
+@@ -849,6 +869,18 @@
+                 throw new SAXParseException("target element appears without a name attribute",
+                         context.getLocator());
+             }
++            
++            boolean isPhase = "phase".equals(target.getType());
++            
++            String targetPrefix = isPhase ? null : context.getUsePrefix();
++            
++			// check if we should prefix the target name
++            if (targetPrefix != null) {
++            	project.log("import 'use' mode: prefixing target '" + name + "' with '"
++            			+ targetPrefix + "'", Project.MSG_DEBUG);
++            	
++            	name = targetPrefix + name;
++            }
+ 
+             // Check if this target is in the current build file
+             if (context.getCurrentTargets().get(name) != null) {
+@@ -867,10 +899,93 @@
+                 usedTarget = true;
+             }
+             if (depends.length() > 0) {
+-                target.setDepends(depends);
++            	if (targetPrefix != null) {
++            		// parse depends to add prefix to all dependencies
++            		// the parsing logic is copied from Target#setDepends(String), which is
++            		// not a good thing, but I don't want to make Target 'use' mode aware.
++            		// We could move the parsing logic in all cases over here if it wasn't part of 
++            		// Target public API.
++                    StringTokenizer tok =
++                        new StringTokenizer(depends, ",", true);
++                    while (tok.hasMoreTokens()) {
++                        String token = tok.nextToken().trim();
++
++                        // Make sure the dependency is not empty string
++                        if ("".equals(token) || ",".equals(token)) {
++                            throw new BuildException(
++                            		"Syntax Error: depends " + "attribute of target \""
++                                    + name + "\" has an empty string as dependency.");
++                        }
++
++                        Target t = (Target) project.getTargets().get(token);
++                        if (t != null && "phase".equals(t.getType())) {
++                        	target.addDependency(token);
++                        } else {
++                        	target.addDependency(targetPrefix + token);
++                        }
++
++                        // Make sure that depends attribute does not
++                        // end in a ,
++                        if (tok.hasMoreTokens()) {
++                            token = tok.nextToken();
++                            if (!tok.hasMoreTokens() || !",".equals(token)) {
++                                throw new BuildException("Syntax Error: Depend "
++                                        + "attribute for target \"" + name
++                                        + "\" ends with a , character");
++                            }
++                        }
++                    }
++            	} else {
++            		target.setDepends(depends);
++            	}
+             }
++            if (phase.length() > 0) {
++            	if (isPhase) {
++            		throw new SAXParseException(
++            				"phase not allowed on phase", context.getLocator());
++            	}
++                StringTokenizer tok =
++                    new StringTokenizer(phase, ",", true);
++                while (tok.hasMoreTokens()) {
++                    String token = tok.nextToken().trim();
++
++                    // Make sure the dependency is not empty string
++                    if ("".equals(token) || ",".equals(token)) {
++                        throw new BuildException(
++                        		"Syntax Error: phase " + "attribute of target \""
++                                + name + "\" has an empty string as phase.");
++                    }
++
++                    Target p = (Target) projectTargets.get(token);
++                    if (p == null) {
++                        throw new BuildException(
++                        		"Syntax Error: unknown phase \""
++                                + token + "\" referenced by \"" + name + "\".");
++                    } else if (!"phase".equals(p.getType())) {
++                        throw new BuildException(
++                        		"Syntax Error: phase \""
++                                + token + "\" referenced by \"" + name 
++                                + "\" is not a phase.");
++                    } else {
++                    	p.addDependency(name);
++                    }
++
++                    // Make sure that phase attribute does not
++                    // end in a ,
++                    if (tok.hasMoreTokens()) {
++                        token = tok.nextToken();
++                        if (!tok.hasMoreTokens() || !",".equals(token)) {
++                            throw new BuildException("Syntax Error: Phase "
++                                    + "attribute for target \"" + name
++                                    + "\" ends with a , character");
++                        }
++                    }
++                }
++            }
++            
+             if (context.isIgnoringProjectTag() && context.getCurrentProjectName() != null
+-                    && context.getCurrentProjectName().length() != 0) {
++                    && context.getCurrentProjectName().length() != 0
++                    && !isPhase) {
+                 // In an impored file (and not completely
+                 // ignoring the project tag)
+                 String newName = context.getCurrentProjectName() + "." + name;
+Index: src/main/org/apache/tools/ant/ProjectHelper.java
+===================================================================
+--- src/main/org/apache/tools/ant/ProjectHelper.java	(révision 697121)
++++ src/main/org/apache/tools/ant/ProjectHelper.java	(copie de travail)
+@@ -28,6 +28,7 @@
+ 
+ import org.xml.sax.AttributeList;
+ 
++import org.apache.tools.ant.helper.AntXMLContext;
+ import org.apache.tools.ant.helper.ProjectHelper2;
+ import org.apache.tools.ant.util.LoaderUtils;
+ 
+@@ -129,6 +130,20 @@
+     public Vector getImportStack() {
+         return importStack;
+     }
++    
++    private AntXMLContext context = null;
++    
++    /**
++     * Returns the current parsing context
++     * @return the current parsing context
++     */
++    public AntXMLContext getContext() {
++		return context;
++	}
++    
++    protected void setContext(AntXMLContext context) {
++		this.context = context;
++	}
+ 
+     // --------------------  Parse method  --------------------
+     /**
+Index: src/main/org/apache/tools/ant/taskdefs/ImportTask.java
+===================================================================
+--- src/main/org/apache/tools/ant/taskdefs/ImportTask.java	(révision 697121)
++++ src/main/org/apache/tools/ant/taskdefs/ImportTask.java	(copie de travail)
+@@ -18,15 +18,16 @@
+ 
+ package org.apache.tools.ant.taskdefs;
+ 
++import java.io.File;
++import java.util.Vector;
++
+ import org.apache.tools.ant.BuildException;
++import org.apache.tools.ant.Project;
+ import org.apache.tools.ant.ProjectHelper;
+-import org.apache.tools.ant.Project;
+ import org.apache.tools.ant.Task;
++import org.apache.tools.ant.helper.AntXMLContext;
+ import org.apache.tools.ant.util.FileUtils;
+ 
+-import java.io.File;
+-import java.util.Vector;
+-
+ /**
+  * Task to import another build file into the current project.
+  * <p>
+@@ -55,6 +56,9 @@
+ public class ImportTask extends Task {
+     private String file;
+     private boolean optional;
++	private String mode = "extends";
++	private String as;
++	
+     private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+ 
+     /**
+@@ -79,6 +83,22 @@
+     }
+ 
+     /**
++     * The import mode to use. It can be either 'use' or 'extends'
++     * @param mode the import mode to use
++     */
++	public void setMode(String mode) {
++		this.mode = mode;
++	}
++
++	/**
++	 * The prefix to use when importing in 'use' mode.
++	 * @param as the prefix for 'use' mode
++	 */
++	public void setAs(String as) {
++		this.as = as;
++	}
++	
++    /**
+      *  This relies on the task order model.
+      *
+      */
+@@ -134,19 +154,45 @@
+                 throw new BuildException(message);
+             }
+         }
+-
+-        if (importStack.contains(importedFile)) {
++        //here we suppose that using import "as" mode you know what you do
++        if ((!"use".equals(mode)) && importStack.contains(importedFile)) {
+             getProject().log(
+                 "Skipped already imported file:\n   "
+                 + importedFile + "\n", Project.MSG_VERBOSE);
+             return;
+         }
+ 
++        AntXMLContext context = helper.getContext();
++        String oldUsePrefix = null;
+         try {
++        	if ("use".equals(mode)) {
++        		if (context == null) {
++        			throw new IllegalStateException("null context while calling import in use mode."
++        				+ " The ProjectHelper implementation you use may not support 'use' mode");
++        		}
++        		oldUsePrefix = context.getUsePrefix();
++        		if (as != null) {
++        			if (oldUsePrefix != null) {
++        				context.setUsePrefix(oldUsePrefix + as);
++        			} else { 
++        				context.setUsePrefix(as);
++        			}
++        		} else {
++        			if (oldUsePrefix != null) {
++        			context.setUsePrefix(oldUsePrefix + "${ant.project.name}");
++        			} else {
++        				context.setUsePrefix("${ant.project.name}");	
++        			}
++        		}
++        	}
+             helper.parse(getProject(), importedFile);
+         } catch (BuildException ex) {
+             throw ProjectHelper.addLocationToBuildException(
+                 ex, getLocation());
++        } finally {
++        	if ("use".equals(mode) && context != null) {
++        		context.setUsePrefix(oldUsePrefix);
++        	}
+         }
+     }
+ 
+Index: src/main/org/apache/tools/ant/Main.java
+===================================================================
+--- src/main/org/apache/tools/ant/Main.java	(révision 697121)
++++ src/main/org/apache/tools/ant/Main.java	(copie de travail)
+@@ -1044,6 +1044,8 @@
+         Vector topNames = new Vector();
+         Vector topDescriptions = new Vector();
+         Vector subNames = new Vector();
++        Vector phases = new Vector();
++        Vector phasesDescriptions = new Vector();
+ 
+         for (Iterator i = ptargets.values().iterator(); i.hasNext();) {
+             currentTarget = (Target) i.next();
+@@ -1057,17 +1059,28 @@
+                 int pos = findTargetPosition(subNames, targetName);
+                 subNames.insertElementAt(targetName, pos);
+             } else {
+-                int pos = findTargetPosition(topNames, targetName);
+-                topNames.insertElementAt(targetName, pos);
+-                topDescriptions.insertElementAt(targetDescription, pos);
+-                if (targetName.length() > maxLength) {
+-                    maxLength = targetName.length();
+-                }
++            	if (currentTarget.getType().equals("phase")) {
++            		int pos = findTargetPosition(phases, targetName);
++            		phases.insertElementAt(targetName, pos);
++            		phasesDescriptions.insertElementAt(targetDescription, pos);
++            	} else {
++            		int pos = findTargetPosition(topNames, targetName);
++                    topNames.insertElementAt(targetName, pos);
++                    topDescriptions.insertElementAt(targetDescription, pos);
++                  
++            	}
++            	  if (targetName.length() > maxLength) {
++                      maxLength = targetName.length();
++                  }	
++                
+             }
+         }
+ 
++        printTargets(project, phases,phasesDescriptions,"Main phases:",maxLength);
+         printTargets(project, topNames, topDescriptions, "Main targets:",
+                      maxLength);
++        
++        
+         //if there were no main targets, we list all subtargets
+         //as it means nothing has a description
+         if (topNames.size() == 0) {
+Index: src/main/org/apache/tools/ant/Target.java
+===================================================================
+--- src/main/org/apache/tools/ant/Target.java	(révision 697121)
++++ src/main/org/apache/tools/ant/Target.java	(copie de travail)
+@@ -56,6 +56,9 @@
+ 
+     /** Description of this target, if any. */
+     private String description = null;
++    
++    /** The type of target ("target" or "phase") */
++    private String type = "target";
+ 
+     /** Default constructor. */
+     public Target() {
+@@ -172,6 +175,24 @@
+     public String getName() {
+         return name;
+     }
++    
++    /**
++     * Returns the type of this target.
++     * 
++     * @return the type of this target
++     */
++    public String getType() {
++		return type;
++	}
++    
++    /**
++     * Sets the type of this target.
++     * 
++     * @param type the new type of this target
++     */
++    public void setType(String type) {
++		this.type = type;
++	}
+ 
+     /**
+      * Adds a task to this target.

Added: incubator/easyant/core/trunk/src/main/patches/ant-713373-easyant-patch.diff
URL: http://svn.apache.org/viewvc/incubator/easyant/core/trunk/src/main/patches/ant-713373-easyant-patch.diff?rev=1071697&view=auto
==============================================================================
--- incubator/easyant/core/trunk/src/main/patches/ant-713373-easyant-patch.diff (added)
+++ incubator/easyant/core/trunk/src/main/patches/ant-713373-easyant-patch.diff Thu Feb 17 17:01:07 2011
@@ -0,0 +1,211 @@
+Index: src/main/org/apache/tools/ant/helper/ProjectHelper2.java
+===================================================================
+--- src/main/org/apache/tools/ant/helper/ProjectHelper2.java	(révision 713424)
++++ src/main/org/apache/tools/ant/helper/ProjectHelper2.java	(copie de travail)
+@@ -769,7 +769,7 @@
+          */
+         public AntHandler onStartChild(String uri, String name, String qname, Attributes attrs,
+                                        AntXMLContext context) throws SAXParseException {
+-            return name.equals("target") && (uri.equals("") || uri.equals(ANT_CORE_URI))
++            return (name.equals("target") || name.equals("phase")) && (uri.equals("") || uri.equals(ANT_CORE_URI))
+                     ? ProjectHelper2.targetHandler : ProjectHelper2.elementHandler;
+         }
+     }
+@@ -803,12 +803,15 @@
+                                    AntXMLContext context) throws SAXParseException {
+             String name = null;
+             String depends = "";
++            String phase = ""; 
+ 
+             Project project = context.getProject();
+             Target target = new Target();
+             target.setProject(project);
+             target.setLocation(new Location(context.getLocator()));
+             context.addTarget(target);
++            
++            target.setType(tag); 
+ 
+             for (int i = 0; i < attrs.getLength(); i++) {
+                 String attrUri = attrs.getURI(i);
+@@ -825,6 +828,8 @@
+                     }
+                 } else if (key.equals("depends")) {
+                     depends = value;
++                } else if (key.equals("phase")) { 
++                 	phase = value; 
+                 } else if (key.equals("if")) {
+                     target.setIf(value);
+                 } else if (key.equals("unless")) {
+@@ -835,12 +840,17 @@
+                     }
+                 } else if (key.equals("description")) {
+                     target.setDescription(value);
++                } else if (key.equals("type")) {
++                	target.setType(value);
++
+                 } else {
+                     throw new SAXParseException("Unexpected attribute \"" + key + "\"", context
+                             .getLocator());
+                 }
+             }
+-
++            
++            boolean isPhase = "phase".equals(target.getType()); 
++         	
+             if (name == null) {
+                 throw new SAXParseException("target element appears without a name attribute",
+                         context.getLocator());
+@@ -849,9 +859,10 @@
+             String prefix = null;
+             boolean isInIncludeMode =
+                 context.isIgnoringProjectTag() && isInIncludeMode();
++
+             String sep = getCurrentPrefixSeparator();
+ 
+-            if (isInIncludeMode) {
++            if (isInIncludeMode && !isPhase) {
+                 prefix = getTargetPrefix(context);
+                 if (prefix == null) {
+                     throw new BuildException("can't include build file "
+@@ -888,12 +899,40 @@
+                     for (Iterator iter =
+                              Target.parseDepends(depends, name).iterator();
+                          iter.hasNext(); ) {
+-                        target.addDependency(prefix + sep + iter.next());
++                    	String token = (String) iter.next();
++                    	Target t = (Target) project.getTargets().get(token); 
++                     	if (t != null && "phase".equals(t.getType())) { 
++                     		target.addDependency(token); 
++                     	} else { 
++                     		target.addDependency(prefix + sep + token); 
++                     	} 
+                     }
+                 }
+             }
++            if (phase.length() > 0) {
++				if (isPhase) {
++					throw new SAXParseException("phase not allowed on phase",
++							context.getLocator());
++				}
++				for (Iterator iter = Target.parseDepends(phase, name)
++						.iterator(); iter.hasNext();) {
++					String token = (String) iter.next();
++					Target p = (Target) projectTargets.get(token);
++					if (p == null) {
++						throw new BuildException(
++								"Syntax Error: unknown phase \"" + token
++										+ "\" referenced by \"" + name + "\".");
++					} else if (!"phase".equals(p.getType())) {
++						throw new BuildException("Syntax Error: phase \""
++								+ token + "\" referenced by \"" + name
++								+ "\" is not a phase.");
++					} else {
++						p.addDependency(name);
++					}
++				}
++			}
+             if (!isInIncludeMode && context.isIgnoringProjectTag()
+-                && (prefix = getTargetPrefix(context)) != null) {
++                && (prefix = getTargetPrefix(context)) != null && !isPhase) {
+                 // In an imported file (and not completely
+                 // ignoring the project tag or having a preconfigured prefix)
+                 String newName = prefix + sep + name;
+@@ -906,9 +945,11 @@
+ 
+         private String getTargetPrefix(AntXMLContext context) {
+             String configuredValue = getCurrentTargetPrefix();
++            /*
+             if (configuredValue != null && configuredValue.length() == 0) {
+                 configuredValue = null;
+             }
++            */
+             if (configuredValue != null) {
+                 return configuredValue;
+             }
+Index: src/main/org/apache/tools/ant/Main.java
+===================================================================
+--- src/main/org/apache/tools/ant/Main.java	(révision 713424)
++++ src/main/org/apache/tools/ant/Main.java	(copie de travail)
+@@ -1058,6 +1058,8 @@
+         Vector topNames = new Vector();
+         Vector topDescriptions = new Vector();
+         Vector subNames = new Vector();
++        Vector phases = new Vector();
++        Vector phasesDescriptions = new Vector();
+ 
+         for (Iterator i = ptargets.values().iterator(); i.hasNext();) {
+             currentTarget = (Target) i.next();
+@@ -1071,17 +1073,28 @@
+                 int pos = findTargetPosition(subNames, targetName);
+                 subNames.insertElementAt(targetName, pos);
+             } else {
+-                int pos = findTargetPosition(topNames, targetName);
+-                topNames.insertElementAt(targetName, pos);
+-                topDescriptions.insertElementAt(targetDescription, pos);
+-                if (targetName.length() > maxLength) {
+-                    maxLength = targetName.length();
+-                }
++            	if (currentTarget.getType().equals("phase")) {
++            		int pos = findTargetPosition(phases, targetName);
++            		phases.insertElementAt(targetName, pos);
++            		phasesDescriptions.insertElementAt(targetDescription, pos);
++            	} else {
++            		int pos = findTargetPosition(topNames, targetName);
++                    topNames.insertElementAt(targetName, pos);
++                    topDescriptions.insertElementAt(targetDescription, pos);
++                  
++            	}
++            	  if (targetName.length() > maxLength) {
++                      maxLength = targetName.length();
++                  }	
++                
+             }
+         }
+ 
++        printTargets(project, phases,phasesDescriptions,"Main phases:",maxLength);
+         printTargets(project, topNames, topDescriptions, "Main targets:",
+                      maxLength);
++        
++        
+         //if there were no main targets, we list all subtargets
+         //as it means nothing has a description
+         if (topNames.size() == 0) {
+Index: src/main/org/apache/tools/ant/Target.java
+===================================================================
+--- src/main/org/apache/tools/ant/Target.java	(révision 713424)
++++ src/main/org/apache/tools/ant/Target.java	(copie de travail)
+@@ -55,6 +55,9 @@
+ 
+     /** Description of this target, if any. */
+     private String description = null;
++    
++    /** The type of target ("target" or "phase") */
++    private String type = "target";
+ 
+     /** Default constructor. */
+     public Target() {
+@@ -186,6 +189,24 @@
+     public String getName() {
+         return name;
+     }
++    
++    /**
++     * Returns the type of this target.
++     * 
++     * @return the type of this target
++     */
++    public String getType() {
++		return type;
++	}
++    
++    /**
++     * Sets the type of this target.
++     * 
++     * @param type the new type of this target
++     */
++    public void setType(String type) {
++		this.type = type;
++	}
+ 
+     /**
+      * Adds a task to this target.

Added: incubator/easyant/core/trunk/src/main/patches/ant-713748-easyant-patch.diff
URL: http://svn.apache.org/viewvc/incubator/easyant/core/trunk/src/main/patches/ant-713748-easyant-patch.diff?rev=1071697&view=auto
==============================================================================
--- incubator/easyant/core/trunk/src/main/patches/ant-713748-easyant-patch.diff (added)
+++ incubator/easyant/core/trunk/src/main/patches/ant-713748-easyant-patch.diff Thu Feb 17 17:01:07 2011
@@ -0,0 +1,193 @@
+Index: src/main/org/apache/tools/ant/helper/ProjectHelper2.java
+===================================================================
+--- src/main/org/apache/tools/ant/helper/ProjectHelper2.java	(révision 713748)
++++ src/main/org/apache/tools/ant/helper/ProjectHelper2.java	(copie de travail)
+@@ -777,7 +777,7 @@
+          */
+         public AntHandler onStartChild(String uri, String name, String qname, Attributes attrs,
+                                        AntXMLContext context) throws SAXParseException {
+-            return name.equals("target") && (uri.equals("") || uri.equals(ANT_CORE_URI))
++            return (name.equals("target") || name.equals("phase")) && (uri.equals("") || uri.equals(ANT_CORE_URI)) 
+                     ? ProjectHelper2.targetHandler : ProjectHelper2.elementHandler;
+         }
+     }
+@@ -811,12 +811,15 @@
+                                    AntXMLContext context) throws SAXParseException {
+             String name = null;
+             String depends = "";
++            String phase = "";  
+ 
+             Project project = context.getProject();
+             Target target = new Target();
+             target.setProject(project);
+             target.setLocation(new Location(context.getLocator()));
+             context.addTarget(target);
++            
++            target.setType(tag);  
+ 
+             for (int i = 0; i < attrs.getLength(); i++) {
+                 String attrUri = attrs.getURI(i);
+@@ -833,6 +836,8 @@
+                     }
+                 } else if (key.equals("depends")) {
+                     depends = value;
++                } else if (key.equals("phase")) {  
++                	phase = value;  
+                 } else if (key.equals("if")) {
+                     target.setIf(value);
+                 } else if (key.equals("unless")) {
+@@ -843,11 +848,15 @@
+                     }
+                 } else if (key.equals("description")) {
+                     target.setDescription(value);
++                } else if (key.equals("type")) {
++                	target.setType(value); 
+                 } else {
+                     throw new SAXParseException("Unexpected attribute \"" + key + "\"", context
+                             .getLocator());
+                 }
+             }
++            
++            boolean isPhase = "phase".equals(target.getType());  
+ 
+             if (name == null) {
+                 throw new SAXParseException("target element appears without a name attribute",
+@@ -859,7 +868,7 @@
+                 context.isIgnoringProjectTag() && isInIncludeMode();
+             String sep = getCurrentPrefixSeparator();
+ 
+-            if (isInIncludeMode) {
++            if (isInIncludeMode && !isPhase) {
+                 prefix = getTargetPrefix(context);
+                 if (prefix == null) {
+                     throw new BuildException("can't include build file "
+@@ -896,12 +905,40 @@
+                     for (Iterator iter =
+                              Target.parseDepends(depends, name).iterator();
+                          iter.hasNext(); ) {
+-                        target.addDependency(prefix + sep + iter.next());
++                    	String token = (String) iter.next(); 
++                    	Target t = (Target) project.getTargets().get(token);  
++                    	if (t != null && "phase".equals(t.getType())) {  
++                    		target.addDependency(token);  
++                    	 } else {  
++                    		 target.addDependency(prefix + sep + token);  
++                    	}  
+                     }
+                 }
+             }
++            if (phase.length() > 0) { 
++             	if (isPhase) { 
++             		throw new SAXParseException("phase not allowed on phase", 
++             				context.getLocator()); 
++             	} 
++             	for (Iterator iter = Target.parseDepends(phase, name) 
++             			.iterator(); iter.hasNext();) { 
++	             	String token = (String) iter.next(); 
++	             	Target p = (Target) projectTargets.get(token); 
++	             	if (p == null) { 
++	             		throw new BuildException( 
++	             				"Syntax Error: unknown phase \"" + token 
++	             				+ "\" referenced by \"" + name + "\"."); 
++	             	} else if (!"phase".equals(p.getType())) { 
++	             		throw new BuildException("Syntax Error: phase \"" 
++	             				+ token + "\" referenced by \"" + name 
++	             				+ "\" is not a phase."); 
++	             	} else { 
++	             		p.addDependency(name); 
++	             	} 
++             	} 
++            } 
+             if (!isInIncludeMode && context.isIgnoringProjectTag()
+-                && (prefix = getTargetPrefix(context)) != null) {
++                && (prefix = getTargetPrefix(context)) != null && !isPhase) {
+                 // In an imported file (and not completely
+                 // ignoring the project tag or having a preconfigured prefix)
+                 String newName = prefix + sep + name;
+Index: src/main/org/apache/tools/ant/Main.java
+===================================================================
+--- src/main/org/apache/tools/ant/Main.java	(révision 713748)
++++ src/main/org/apache/tools/ant/Main.java	(copie de travail)
+@@ -1058,6 +1058,8 @@
+         Vector topNames = new Vector();
+         Vector topDescriptions = new Vector();
+         Vector subNames = new Vector();
++        Vector phases = new Vector();
++        Vector phasesDescriptions = new Vector();
+ 
+         for (Iterator i = ptargets.values().iterator(); i.hasNext();) {
+             currentTarget = (Target) i.next();
+@@ -1071,17 +1073,28 @@
+                 int pos = findTargetPosition(subNames, targetName);
+                 subNames.insertElementAt(targetName, pos);
+             } else {
+-                int pos = findTargetPosition(topNames, targetName);
+-                topNames.insertElementAt(targetName, pos);
+-                topDescriptions.insertElementAt(targetDescription, pos);
+-                if (targetName.length() > maxLength) {
+-                    maxLength = targetName.length();
+-                }
++            	if (currentTarget.getType().equals("phase")) {
++            		int pos = findTargetPosition(phases, targetName);
++            		phases.insertElementAt(targetName, pos);
++            		phasesDescriptions.insertElementAt(targetDescription, pos);
++            	} else {
++            		int pos = findTargetPosition(topNames, targetName);
++                    topNames.insertElementAt(targetName, pos);
++                    topDescriptions.insertElementAt(targetDescription, pos);
++                  
++            	}
++            	  if (targetName.length() > maxLength) {
++                      maxLength = targetName.length();
++                  }	
++                
+             }
+         }
+ 
++        printTargets(project, phases,phasesDescriptions,"Main phases:",maxLength);
+         printTargets(project, topNames, topDescriptions, "Main targets:",
+                      maxLength);
++        
++        
+         //if there were no main targets, we list all subtargets
+         //as it means nothing has a description
+         if (topNames.size() == 0) {
+Index: src/main/org/apache/tools/ant/Target.java
+===================================================================
+--- src/main/org/apache/tools/ant/Target.java	(révision 713748)
++++ src/main/org/apache/tools/ant/Target.java	(copie de travail)
+@@ -55,6 +55,9 @@
+ 
+     /** Description of this target, if any. */
+     private String description = null;
++    
++    /** The type of target ("target" or "phase") */
++    private String type = "target";
+ 
+     /** Default constructor. */
+     public Target() {
+@@ -186,6 +189,24 @@
+     public String getName() {
+         return name;
+     }
++    
++    /**
++     * Returns the type of this target.
++     * 
++     * @return the type of this target
++     */
++    public String getType() {
++		return type;
++	}
++    
++    /**
++     * Sets the type of this target.
++     * 
++     * @param type the new type of this target
++     */
++    public void setType(String type) {
++		this.type = type;
++	}
+ 
+     /**
+      * Adds a task to this target.

Added: incubator/easyant/core/trunk/src/main/patches/extendsIvyFile-ivy-r709181.patch
URL: http://svn.apache.org/viewvc/incubator/easyant/core/trunk/src/main/patches/extendsIvyFile-ivy-r709181.patch?rev=1071697&view=auto
==============================================================================
--- incubator/easyant/core/trunk/src/main/patches/extendsIvyFile-ivy-r709181.patch (added)
+++ incubator/easyant/core/trunk/src/main/patches/extendsIvyFile-ivy-r709181.patch Thu Feb 17 17:01:07 2011
@@ -0,0 +1,220 @@
+Index: src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParser.java
+===================================================================
+--- src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParser.java	(révision 709181)
++++ src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParser.java	(copie de travail)
+@@ -40,6 +40,7 @@
+ import org.apache.ivy.core.module.descriptor.DefaultIncludeRule;
+ import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor;
+ import org.apache.ivy.core.module.descriptor.DependencyArtifactDescriptor;
++import org.apache.ivy.core.module.descriptor.DependencyDescriptor;
+ import org.apache.ivy.core.module.descriptor.ExcludeRule;
+ import org.apache.ivy.core.module.descriptor.IncludeRule;
+ import org.apache.ivy.core.module.descriptor.License;
+@@ -49,15 +50,21 @@
+ import org.apache.ivy.core.module.id.ArtifactId;
+ import org.apache.ivy.core.module.id.ModuleId;
+ import org.apache.ivy.core.module.id.ModuleRevisionId;
++import org.apache.ivy.core.resolve.ResolveData;
++import org.apache.ivy.core.resolve.ResolveEngine;
++import org.apache.ivy.core.resolve.ResolveOptions;
++import org.apache.ivy.core.resolve.ResolvedModuleRevision;
+ import org.apache.ivy.plugins.conflict.ConflictManager;
+ import org.apache.ivy.plugins.conflict.FixedConflictManager;
+ import org.apache.ivy.plugins.matcher.PatternMatcher;
+ import org.apache.ivy.plugins.namespace.Namespace;
+ import org.apache.ivy.plugins.parser.AbstractModuleDescriptorParser;
+ import org.apache.ivy.plugins.parser.ModuleDescriptorParser;
++import org.apache.ivy.plugins.parser.ModuleDescriptorParserRegistry;
+ import org.apache.ivy.plugins.parser.ParserSettings;
+ import org.apache.ivy.plugins.repository.Resource;
+ import org.apache.ivy.plugins.repository.url.URLResource;
++import org.apache.ivy.plugins.resolver.DependencyResolver;
+ import org.apache.ivy.util.Message;
+ import org.apache.ivy.util.XMLHelper;
+ import org.apache.ivy.util.extendable.ExtendableItemHelper;
+@@ -211,6 +218,7 @@
+         private StringBuffer buffer;
+         private String descriptorVersion;
+         private String[] publicationsDefaultConf;
++
+         
+         public Parser(ModuleDescriptorParser parser, ParserSettings ivySettings) {
+             super(parser);
+@@ -276,6 +284,8 @@
+                     ivyModuleStarted(attributes);
+                 } else if ("info".equals(qName)) {
+                     infoStarted(attributes);
++                } else if (state == State.INFO && "extends".equals(qName)) {
++                    extendsStarted(attributes);
+                 } else if (state == State.INFO && "license".equals(qName)) {
+                     getMd().addLicense(new License(settings.substitute(attributes.getValue("name")),
+                                         settings.substitute(attributes.getValue("url"))));
+@@ -340,7 +350,148 @@
+                 throw sax;
+             }
+         }
++        
++        protected String getDefaultParentLocation() {
++            return "../ivy.xml";
++        }
++        
++        protected void extendsStarted(Attributes attributes) throws ParseException {
++            String parentOrganisation = attributes.getValue("organisation");
++            String parentModule = attributes.getValue("name");
++            String parentRevision = attributes.getValue("revision");
++            String location = attributes.getValue("location") != null ? attributes
++                    .getValue("location") : getDefaultParentLocation();
++            ModuleDescriptor parent = null;
+ 
++            String extendType = attributes.getValue("extendType") != null ? attributes.getValue(
++                "extendType").toLowerCase() : "all";
++
++            List/* <String> */extendTypes = Arrays.asList(extendType.split(","));
++
++            
++            try {
++                Message.debug("Trying to parse included ivy file :" + location);
++                parent = parseOtherIvyFileOnFileSystem(location);
++            } catch (ParseException e) {
++                Message.warn("Unable to parse included ivy file : " + location);
++            } catch (IOException e) {
++                Message.warn("Unable to parse included ivy file : " + location);
++            }
++
++            // if the included ivy file is not found on file system, tries to resolve using
++            // repositories
++            if (parent == null) {
++                try {
++                    Message
++                            .debug("Trying to parse included ivy file by asking repository for module :"
++                                    + parentOrganisation
++                                    + "#"
++                                    + parentModule
++                                    + ";"
++                                    + parentRevision);
++                    parent = parseOtherIvyFile(parentOrganisation, parentModule, parentRevision);
++                } catch (ParseException e) {
++                    Message.warn("Unable to parse included ivy file for " + parentOrganisation
++                            + "#" + parentModule + ";" + parentRevision);
++                }
++            }
++
++            if (parent == null) {
++                throw new ParseException("Unable to parse included ivy file for "
++                        + parentOrganisation + "#" + parentModule + ";" + parentRevision, 0);
++            }
++            mergeWithOtherModuleDescriptor(extendTypes,parent);
++        }
++        
++        protected void mergeWithOtherModuleDescriptor(List/*<String>*/ extendTypes,ModuleDescriptor parent) {
++            if (extendTypes.contains("all")) {
++                mergeAll(parent);
++            } else {
++                if (extendTypes.contains("configurations")) {
++                    mergeConfigurations(parent.getConfigurations());
++                }
++
++                if (extendTypes.contains("dependencies")) {
++                    mergeDependencies(parent.getDependencies());
++                }
++
++                if (extendTypes.contains("description")) {
++                    mergeDescription(parent.getDescription());
++                }
++            }
++            
++        }
++        
++        protected void mergeAll(ModuleDescriptor parent) {
++            mergeConfigurations(parent.getConfigurations());
++            mergeDependencies(parent.getDependencies());
++            mergeDescription(parent.getDescription());
++        }
++
++        protected void mergeConfigurations(Configuration[] configurations) {
++            for (int i = 0; i < configurations.length; i++) {
++                Configuration configuration = configurations[i];
++                Message.debug("Merging configuration with: " + configuration.getName());
++                // TODO: Here we need to merge configuration
++                getMd().addConfiguration(configuration);
++            }
++        }
++
++        protected void mergeDependencies(DependencyDescriptor[] dependencies) {
++            for (int i = 0; i < dependencies.length; i++) {
++                DependencyDescriptor dependencyDescriptor = dependencies[i];
++                Message.debug("Merging dependency with: "
++                        + dependencyDescriptor.getDependencyRevisionId().toString());
++                // TODO: Here we need to merge dependencies
++                getMd().addDependency(dependencyDescriptor);
++            }
++        }
++        
++        protected void mergeDescription(String description) {
++            if (getMd().getDescription() == null)
++                getMd().setDescription(description);
++        }
++
++        protected ModuleDescriptor parseOtherIvyFileOnFileSystem(String location)
++                throws ParseException, IOException {
++            URL url = null;
++            ModuleDescriptor parent = null;
++            url = getSettings().getRelativeUrlResolver().getURL(descriptorURL, location);
++            Message.debug("Trying to load included ivy file from " + url.toString());
++            URLResource res = new URLResource(url);
++            ModuleDescriptorParser parser = ModuleDescriptorParserRegistry.getInstance().getParser(
++                res);
++
++            parent = parser.parseDescriptor(getSettings(), url, isValidate());
++            return parent;
++        }
++
++        protected ModuleDescriptor parseOtherIvyFile(String parentOrganisation,
++                String parentModule, String parentRevision) throws ParseException {
++            ModuleId parentModuleId = new ModuleId(parentOrganisation, parentModule);
++            ModuleRevisionId parentMrid = new ModuleRevisionId(parentModuleId, parentRevision);
++            DependencyDescriptor dd = new DefaultDependencyDescriptor(parentMrid, true);
++            ResolveData data = IvyContext.getContext().getResolveData();
++            if (data == null) {
++                ResolveEngine engine = IvyContext.getContext().getIvy().getResolveEngine();
++                ResolveOptions options = new ResolveOptions();
++                options.setDownload(false);
++                data = new ResolveData(engine, options);
++            }
++
++            DependencyResolver resolver = getSettings().getResolver(parentMrid);
++            if (resolver == null) {
++                // TODO: Throw exception here?
++                return null;
++            } else {
++                ResolvedModuleRevision otherModule = resolver.getDependency(dd, data);
++                if (otherModule == null)
++                    throw new ParseException("Unable to find " + parentMrid.toString(), 0);
++                return otherModule.getDescriptor();
++            }
++
++        }
++
+         protected void publicationsStarted(Attributes attributes) {
+             state = State.PUB;
+             artifactsDeclared = true;
+Index: src/java/org/apache/ivy/plugins/parser/xml/ivy.xsd
+===================================================================
+--- src/java/org/apache/ivy/plugins/parser/xml/ivy.xsd	(révision 709181)
++++ src/java/org/apache/ivy/plugins/parser/xml/ivy.xsd	(copie de travail)
+@@ -60,6 +60,15 @@
+   		    <xs:element name="info">
+             	<xs:complexType>
+ 			        <xs:sequence>
++			        	<xs:element name="extends" minOccurs="0" maxOccurs="unbounded">
++			        		<xs:complexType>
++			        			<xs:attribute name="organisation" type="xs:string" use="required"/>
++			        			<xs:attribute name="name" type="xs:string" use="required"/>
++			        			<xs:attribute name="revision" type="xs:string" use="required"/>
++			        			<xs:attribute name="location" type="xs:string" />
++			        			<xs:attribute name="extendType" type="xs:string" />
++			        		</xs:complexType>
++			        	</xs:element>
+ 			      		<xs:element name="license" minOccurs="0" maxOccurs="unbounded">
+ 			            	<xs:complexType>
+ 					            <xs:attribute name="name" type="xs:string" use="required"/>