From bd52e7b9b16b87287bed0c011c4fc1794543e9fb Mon Sep 17 00:00:00 2001 From: Stefan Bodewig Date: Wed, 23 Jun 2010 12:15:13 +0000 Subject: [PATCH] allow targets to deal with missing extension points. PR 49473. Submitted by Danny Yates. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@957170 13f79535-47bb-0310-9956-ffa450edef68 --- CONTRIBUTORS | 1 + WHATSNEW | 12 ++ contributors.xml | 4 + docs/manual/targets.html | 11 ++ .../org/apache/tools/ant/ProjectHelper.java | 25 +++- .../tools/ant/helper/ProjectHelper2.java | 124 +++++++++++------- .../tools/ant/taskdefs/AntStructure.java | 19 +-- .../antunit/core/extension-point-test.xml | 45 +++++++ 8 files changed, 183 insertions(+), 58 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index f2fafafe5..6cec079a0 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -70,6 +70,7 @@ Daniel Henrique Daniel Ribagnac Daniel Spilker Danno Ferrin +Danny Yates Dante Briones Davanum Srinivas Dave Brondsema diff --git a/WHATSNEW b/WHATSNEW index 3df3ddb56..feb4cf5c2 100644 --- a/WHATSNEW +++ b/WHATSNEW @@ -27,6 +27,11 @@ Changes that could break older environments: formatter where ampersands will now always get encoded. Bugzilla Report 49404. + * The list elements returned by ProjectHelper#getExtensionStack are + now String arrays of length 3 rather than 2 in order to support the + onMissingExtensionPoint attribute. + Bugzilla Report 49473. + Fixed bugs: ----------- @@ -100,6 +105,13 @@ Other changes: when used in any other way than a CLASSPATH for a forked Java VM. Bugzilla Report 46842. + * A new attribute allows targets to deal with non-existant extensions + points, i.e. they can extend and extension-point if it has been + defined or silently work as plain targets if it hasn't. This is + useful for targets that get included/imported in different + scenarios where a given extension-point may or may not exist. + Bugzilla Report 49473. + Changes from Ant 1.8.0 TO Ant 1.8.1 =================================== diff --git a/contributors.xml b/contributors.xml index 76157d616..c72594345 100644 --- a/contributors.xml +++ b/contributors.xml @@ -303,6 +303,10 @@ Danno Ferrin + + Danny + Yates + Dante Briones diff --git a/docs/manual/targets.html b/docs/manual/targets.html index 01a812e86..c95b7ba29 100644 --- a/docs/manual/targets.html +++ b/docs/manual/targets.html @@ -205,6 +205,17 @@ since Ant 1.8.0. No + + onMissingExtensionPoint + What to do if this target tries to extend a + missing + extension-point. ("fail", + "warn", "ignore"). + since Ant 1.8.2. + No. Not allowed unless + extensionOf is present. Defaults to fail. + +

A target name can be any alphanumeric string valid in the diff --git a/src/main/org/apache/tools/ant/ProjectHelper.java b/src/main/org/apache/tools/ant/ProjectHelper.java index 70aa56238..c5241eb6c 100644 --- a/src/main/org/apache/tools/ant/ProjectHelper.java +++ b/src/main/org/apache/tools/ant/ProjectHelper.java @@ -82,6 +82,23 @@ public class ProjectHelper { helper.parse(project, buildFile); } + /** + * Possible value for target's onMissingExtensionPoint attribute: + * fail if the extension-point is not defined. + */ + public static final String MISSING_EP_FAIL = "fail"; + /** + * Possible value for target's onMissingExtensionPoint attribute: + * warn if the extension-point is not defined. + */ + public static final String MISSING_EP_WARN = "warn"; + /** + * Possible value for target's onMissingExtensionPoint attribute: + * ignore the extensionOf attribute if the extension-point is not + * defined. + */ + public static final String MISSING_EP_IGNORE = "ignore"; + /** Default constructor */ public ProjectHelper() { } @@ -108,9 +125,11 @@ public class ProjectHelper { * Extension stack. * Used to keep track of targets that extend extension points. * - * @return a list of two element string arrays where the first - * element is the name of the extensionpoint and the second the - * name of the target + * @return a list of three element string arrays where the first + * element is the name of the extensionpoint, the second the name + * of the target and the third one of the MISSINS_EP constants + * defined inside this class - it determines how to deal with + * targets that want to extend missing extension-points. */ public List getExtensionStack() { return extensionStack; diff --git a/src/main/org/apache/tools/ant/helper/ProjectHelper2.java b/src/main/org/apache/tools/ant/helper/ProjectHelper2.java index 5f29e6aee..681c39691 100644 --- a/src/main/org/apache/tools/ant/helper/ProjectHelper2.java +++ b/src/main/org/apache/tools/ant/helper/ProjectHelper2.java @@ -59,6 +59,7 @@ import java.util.Stack; * */ public class ProjectHelper2 extends ProjectHelper { + /** Reference holding the (ordered) target Vector */ public static final String REFID_TARGETS = "ant.targets"; @@ -183,21 +184,29 @@ public class ProjectHelper2 extends ProjectHelper { String[] extensionInfo = (String[]) i.next(); String tgName = extensionInfo[0]; String name = extensionInfo[1]; + String missingBehaviour = extensionInfo[2]; Hashtable projectTargets = project.getTargets(); if (!projectTargets.containsKey(tgName)) { - throw new BuildException("can't add target " - + name + " to extension-point " - + tgName - + " because the extension-point" - + " is unknown."); - } - Target t = (Target) projectTargets.get(tgName); - if (!(t instanceof ExtensionPoint)) { - throw new BuildException("referenced target " - + tgName - + " is not an extension-point"); + String message = "can't add target " + name + + " to extension-point " + tgName + + " because the extension-point is unknown."; + if (missingBehaviour.equals(MISSING_EP_FAIL)) { + throw new BuildException(message); + } else if (missingBehaviour.equals(MISSING_EP_WARN)) { + Target target = (Target) projectTargets.get(name); + context.getProject().log(target, + "Warning: " + message, + Project.MSG_WARN); + } + } else { + Target t = (Target) projectTargets.get(tgName); + if (!(t instanceof ExtensionPoint)) { + throw new BuildException("referenced target " + + tgName + + " is not an extension-point"); + } + t.addDependency(name); } - t.addDependency(name); } } } @@ -250,7 +259,7 @@ public class ProjectHelper2 extends ProjectHelper { buildFileName = url.toString(); } else { throw new BuildException("Source " + source.getClass().getName() - + " not supported by this plugin"); + + " not supported by this plugin"); } InputStream inputStream = null; InputSource inputSource = null; @@ -297,7 +306,7 @@ public class ProjectHelper2 extends ProjectHelper { parser.parse(inputSource); } catch (SAXParseException exc) { Location location = new Location(exc.getSystemId(), exc.getLineNumber(), exc - .getColumnNumber()); + .getColumnNumber()); Throwable t = exc.getException(); if (t instanceof BuildException) { @@ -317,11 +326,11 @@ public class ProjectHelper2 extends ProjectHelper { } catch (FileNotFoundException exc) { throw new BuildException(exc); } catch (UnsupportedEncodingException exc) { - throw new BuildException("Encoding of project file " + buildFileName + " is invalid.", - exc); + throw new BuildException("Encoding of project file " + buildFileName + " is invalid.", + exc); } catch (IOException exc) { throw new BuildException("Error reading project file " + buildFileName + ": " - + exc.getMessage(), exc); + + exc.getMessage(), exc); } finally { FileUtils.close(inputStream); ZipFile.closeQuietly(zf); @@ -440,7 +449,7 @@ public class ProjectHelper2 extends ProjectHelper { public AntHandler onStartChild(String uri, String tag, String qname, Attributes attrs, AntXMLContext context) throws SAXParseException { throw new SAXParseException("Unexpected element \"" + qname + " \"", context - .getLocator()); + .getLocator()); } /** @@ -453,7 +462,7 @@ public class ProjectHelper2 extends ProjectHelper { * @exception SAXParseException if an error occurs */ public void onEndChild(String uri, String tag, String qname, AntXMLContext context) - throws SAXParseException { + throws SAXParseException { } /** @@ -480,7 +489,7 @@ public class ProjectHelper2 extends ProjectHelper { * case of error in an overridden version */ public void characters(char[] buf, int start, int count, AntXMLContext context) - throws SAXParseException { + throws SAXParseException { String s = new String(buf, start, count).trim(); if (s.length() > 0) { @@ -548,9 +557,9 @@ public class ProjectHelper2 extends ProjectHelper { if (!file.isAbsolute()) { file = FILE_UTILS.resolveFile(context.getBuildFileParent(), path); context.getProject().log( - "Warning: '" + systemId + "' in " + context.getBuildFile() - + " should be expressed simply as '" + path.replace('\\', '/') - + "' for compliance with other XML tools", Project.MSG_WARN); + "Warning: '" + systemId + "' in " + context.getBuildFile() + + " should be expressed simply as '" + path.replace('\\', '/') + + "' for compliance with other XML tools", Project.MSG_WARN); } context.getProject().log("file=" + file, Project.MSG_DEBUG); try { @@ -559,7 +568,7 @@ public class ProjectHelper2 extends ProjectHelper { return inputSource; } catch (FileNotFoundException fne) { context.getProject().log(file.getAbsolutePath() + " could not be found", - Project.MSG_WARN); + Project.MSG_WARN); } } @@ -583,7 +592,7 @@ public class ProjectHelper2 extends ProjectHelper { * "project" */ public void startElement(String uri, String tag, String qname, Attributes attrs) - throws SAXParseException { + throws SAXParseException { AntHandler next = currentHandler.onStartChild(uri, tag, qname, attrs, context); antHandlers.push(currentHandler); currentHandler = next; @@ -678,10 +687,10 @@ public class ProjectHelper2 extends ProjectHelper { } if (name.equals(qname)) { throw new SAXParseException("Unexpected element \"{" + uri - + "}" + name + "\" {" + ANT_CORE_URI + "}" + name, context.getLocator()); + + "}" + name + "\" {" + ANT_CORE_URI + "}" + name, context.getLocator()); } throw new SAXParseException("Unexpected element \"" + qname - + "\" " + name, context.getLocator()); + + "\" " + name, context.getLocator()); } } @@ -774,7 +783,7 @@ public class ProjectHelper2 extends ProjectHelper { } else { // XXX ignore attributes in a different NS ( maybe store them ? ) throw new SAXParseException("Unexpected attribute \"" + attrs.getQName(i) - + "\"", context.getLocator()); + + "\"", context.getLocator()); } } @@ -805,8 +814,8 @@ public class ProjectHelper2 extends ProjectHelper { if (context.isIgnoringProjectTag() && !dupFile.equals(contextFile)) { project.log("Duplicated project name in import. Project " - + context.getCurrentProjectName() + " defined first in " + dup - + " and again in " + contextFile, Project.MSG_WARN); + + context.getCurrentProjectName() + " defined first in " + dup + + " and again in " + contextFile, Project.MSG_WARN); } } if (nameAttributeSet) { @@ -839,7 +848,7 @@ public class ProjectHelper2 extends ProjectHelper { project.setBasedir(baseDir); } else { project.setBaseDir(FILE_UTILS.resolveFile(context.getBuildFileParent(), - baseDir)); + baseDir)); } } } @@ -905,6 +914,7 @@ public class ProjectHelper2 extends ProjectHelper { String name = null; String depends = ""; String extensionPoint = null; + String extensionPointMissing = null; Project project = context.getProject(); Target target = "target".equals(tag) @@ -940,15 +950,17 @@ public class ProjectHelper2 extends ProjectHelper { target.setDescription(value); } else if (key.equals("extensionOf")) { extensionPoint = value; + } else if (key.equals("onMissingExtensionPoint")) { + extensionPointMissing = value; } else { throw new SAXParseException("Unexpected attribute \"" + key + "\"", context - .getLocator()); + .getLocator()); } } if (name == null) { throw new SAXParseException("target element appears without a name attribute", - context.getLocator()); + context.getLocator()); } String prefix = null; @@ -978,7 +990,7 @@ public class ProjectHelper2 extends ProjectHelper { // If the name has not already been defined define it if (projectTargets.containsKey(name)) { project.log("Already defined in main or a previous import, ignore " + name, - Project.MSG_VERBOSE); + Project.MSG_VERBOSE); } else { target.setName(name); context.getCurrentTargets().put(name, target); @@ -1008,10 +1020,16 @@ public class ProjectHelper2 extends ProjectHelper { context.getCurrentTargets().put(newName, newTarget); project.addOrReplaceTarget(newName, newTarget); } + if (extensionPointMissing != null && extensionPoint == null) { + throw new BuildException("onMissingExtensionPoint attribute cannot " + + "be specified unless extensionOf is specified", + target.getLocation()); + + } if (extensionPoint != null) { ProjectHelper helper = (ProjectHelper) context.getProject(). - getReference(ProjectHelper.PROJECTHELPER_REFERENCE); + getReference(ProjectHelper.PROJECTHELPER_REFERENCE); for (Iterator iter = Target.parseDepends(extensionPoint, name, "extensionOf") .iterator(); @@ -1020,12 +1038,26 @@ public class ProjectHelper2 extends ProjectHelper { if (isInIncludeMode()) { tgName = prefix + sep + tgName; } - - // defer extensionpoint resolution until the full - // import stack has been processed - helper.getExtensionStack().add(new String[] { - tgName, name - }); + if (extensionPointMissing == null) { + extensionPointMissing = MISSING_EP_FAIL; + } + if (extensionPointMissing.equals(MISSING_EP_FAIL) || + extensionPointMissing.equals(MISSING_EP_IGNORE) || + extensionPointMissing.equals(MISSING_EP_WARN)) { + // defer extensionpoint resolution until the full + // import stack has been processed + helper.getExtensionStack().add(new String[] { + tgName, name, extensionPointMissing + }); + } else { + throw new BuildException("onMissingExtensionPoint" + + " attribute can only be '" + + MISSING_EP_FAIL + + "', '" + MISSING_EP_WARN + + "' or '" + MISSING_EP_IGNORE + + "'", + target.getLocation()); + } } } } @@ -1128,7 +1160,7 @@ public class ProjectHelper2 extends ProjectHelper { task.setTaskName(qname); Location location = new Location(context.getLocator().getSystemId(), context - .getLocator().getLineNumber(), context.getLocator().getColumnNumber()); + .getLocator().getLineNumber(), context.getLocator().getColumnNumber()); task.setLocation(location); task.setOwningTarget(context.getCurrentTarget()); @@ -1159,8 +1191,8 @@ public class ProjectHelper2 extends ProjectHelper { // be namespaced, need to extract the name // and convert from qualified name to uri/name if (ANT_TYPE.equals(name) - || (ANT_CORE_URI.equals(attrUri) - && ANT_TYPE.equals(attrs.getLocalName(i)))) { + || (ANT_CORE_URI.equals(attrUri) + && ANT_TYPE.equals(attrs.getLocalName(i)))) { name = ANT_TYPE; int index = value.indexOf(":"); if (index >= 0) { @@ -1168,10 +1200,10 @@ public class ProjectHelper2 extends ProjectHelper { String mappedUri = context.getPrefixMapping(prefix); if (mappedUri == null) { throw new BuildException("Unable to find XML NS prefix \"" + prefix - + "\""); + + "\""); } value = ProjectHelper.genComponentName(mappedUri, value - .substring(index + 1)); + .substring(index + 1)); } } wrapper.setAttribute(name, value); diff --git a/src/main/org/apache/tools/ant/taskdefs/AntStructure.java b/src/main/org/apache/tools/ant/taskdefs/AntStructure.java index 475cc832f..8176bcb0f 100644 --- a/src/main/org/apache/tools/ant/taskdefs/AntStructure.java +++ b/src/main/org/apache/tools/ant/taskdefs/AntStructure.java @@ -106,8 +106,8 @@ public class AntStructure extends Task { while (dataTypes.hasNext()) { String typeName = (String) dataTypes.next(); printer.printElementDecl( - out, getProject(), typeName, - (Class) getProject().getDataTypeDefinitions().get(typeName)); + out, getProject(), typeName, + (Class) getProject().getDataTypeDefinitions().get(typeName)); } Iterator tasks = getProject().getCopyOfTaskDefinitions().keySet() @@ -266,13 +266,14 @@ public class AntStructure extends Task { private void printTargetAttrs(PrintWriter out, String tag) { out.print(""); + out.println(" id ID #IMPLIED"); + out.println(" name CDATA #REQUIRED"); + out.println(" if CDATA #IMPLIED"); + out.println(" unless CDATA #IMPLIED"); + out.println(" depends CDATA #IMPLIED"); + out.println(" extensionOf CDATA #IMPLIED"); + out.println(" onMissingExtensionPoint CDATA #IMPLIED"); + out.println(" description CDATA #IMPLIED>"); out.println(""); } diff --git a/src/tests/antunit/core/extension-point-test.xml b/src/tests/antunit/core/extension-point-test.xml index 810ad33aa..e1875b9fc 100644 --- a/src/tests/antunit/core/extension-point-test.xml +++ b/src/tests/antunit/core/extension-point-test.xml @@ -88,4 +88,49 @@ + + + + +]]> + + + + + + + + + +]]> + + + + + + + + +]]> + + + + + + + + +]]> + + + +