Browse Source

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
master
Stefan Bodewig 15 years ago
parent
commit
bd52e7b9b1
8 changed files with 183 additions and 58 deletions
  1. +1
    -0
      CONTRIBUTORS
  2. +12
    -0
      WHATSNEW
  3. +4
    -0
      contributors.xml
  4. +11
    -0
      docs/manual/targets.html
  5. +22
    -3
      src/main/org/apache/tools/ant/ProjectHelper.java
  6. +78
    -46
      src/main/org/apache/tools/ant/helper/ProjectHelper2.java
  7. +10
    -9
      src/main/org/apache/tools/ant/taskdefs/AntStructure.java
  8. +45
    -0
      src/tests/antunit/core/extension-point-test.xml

+ 1
- 0
CONTRIBUTORS View File

@@ -70,6 +70,7 @@ Daniel Henrique
Daniel Ribagnac
Daniel Spilker
Danno Ferrin
Danny Yates
Dante Briones
Davanum Srinivas
Dave Brondsema


+ 12
- 0
WHATSNEW View File

@@ -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
===================================



+ 4
- 0
contributors.xml View File

@@ -303,6 +303,10 @@
<first>Danno</first>
<last>Ferrin</last>
</name>
<name>
<first>Danny</first>
<last>Yates</last>
</name>
<name>
<first>Dante</first>
<last>Briones</last>


+ 11
- 0
docs/manual/targets.html View File

@@ -205,6 +205,17 @@
<em>since Ant 1.8.0.</em></td>
<td align="center" valign="top">No</td>
</tr>
<tr>
<td valign="top">onMissingExtensionPoint</td>
<td valign="top">What to do if this target tries to extend a
missing
<a href="#extension-points">extension-point</a>. ("fail",
"warn", "ignore").
<em>since Ant 1.8.2.</em></td>
<td align="center" valign="top">No. Not allowed unless
<code>extensionOf</code> is present. Defaults to <code>fail</code>.
</td>
</tr>
</table>

<p>A target name can be any alphanumeric string valid in the


+ 22
- 3
src/main/org/apache/tools/ant/ProjectHelper.java View File

@@ -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;


+ 78
- 46
src/main/org/apache/tools/ant/helper/ProjectHelper2.java View File

@@ -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 {
* <code>"project"</code>
*/
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);


+ 10
- 9
src/main/org/apache/tools/ant/taskdefs/AntStructure.java View File

@@ -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("<!ATTLIST ");
out.println(tag);
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(" description CDATA #IMPLIED>");
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("");
}



+ 45
- 0
src/tests/antunit/core/extension-point-test.xml View File

@@ -88,4 +88,49 @@
<au:assertLogContains text="in target prepare"/>
</target>

<target name="testMissingExtensionPointCausesError">
<mkdir dir="${output}"/>
<echo file="${output}/build.xml"><![CDATA[
<project default="bar">
<target name="bar" extensionOf="foo"/>
</project>]]></echo>
<au:expectfailure
expectedMessage="can't add target bar to extension-point foo because the extension-point is unknown">
<ant dir="${output}" target="bar"/>
</au:expectfailure>
</target>

<target name="testMissingExtensionPointCausesWarningWhenConfigured">
<mkdir dir="${output}"/>
<echo file="${output}/build.xml"><![CDATA[
<project default="bar">
<target name="bar" extensionOf="foo" onMissingExtensionPoint="warn"/>
</project>]]></echo>
<ant dir="${output}" target="bar"/>
<au:assertLogContains level="warning"
text="can't add target bar to extension-point foo because the extension-point is unknown" />
</target>

<target name="testMissingExtensionPointIgnoredWhenConfigured">
<mkdir dir="${output}"/>
<echo file="${output}/build.xml"><![CDATA[
<project default="bar">
<target name="bar" extensionOf="foo" onMissingExtensionPoint="ignore"/>
</project>]]></echo>
<ant dir="${output}" target="bar"/>
<au:assertLogDoesntContain level="warning"
text="can't add target bar to extension-point foo because the extension-point is unknown" />
</target>

<target name="testOnlyAllowsExtensionPointMissingAttributeWhenExtensionOfPresent">
<mkdir dir="${output}"/>
<echo file="${output}/build.xml"><![CDATA[
<project default="bar">
<target name="bar" onMissingExtensionPoint="ignore"/>
</project>]]></echo>
<au:expectfailure
expectedMessage="onMissingExtensionPoint attribute cannot be specified unless extensionOf is specified">
<ant dir="${output}" target="bar"/>
</au:expectfailure>
</target>
</project>

Loading…
Cancel
Save