You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@ant.apache.org by ma...@apache.org on 2010/05/07 22:00:50 UTC
svn commit: r942195 [2/3] - in /ant/ivy/core/trunk: ./ doc/ doc/ivyfile/
doc/use/ src/java/org/apache/ivy/ant/ src/java/org/apache/ivy/core/deliver/
src/java/org/apache/ivy/core/module/descriptor/
src/java/org/apache/ivy/core/publish/ src/java/org/apac...
Modified: ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorUpdater.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorUpdater.java?rev=942195&r1=942194&r2=942195&view=diff
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorUpdater.java (original)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorUpdater.java Fri May 7 20:00:48 2010
@@ -27,6 +27,7 @@ import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
+import java.io.StringWriter;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
@@ -34,6 +35,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
@@ -42,6 +44,12 @@ import java.util.StringTokenizer;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.ivy.Ivy;
+import org.apache.ivy.core.module.descriptor.Configuration;
+import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor;
+import org.apache.ivy.core.module.descriptor.DependencyDescriptor;
+import org.apache.ivy.core.module.descriptor.ExtendsDescriptor;
+import org.apache.ivy.core.module.descriptor.InheritableItem;
+import org.apache.ivy.core.module.descriptor.ModuleDescriptor;
import org.apache.ivy.core.module.id.ModuleId;
import org.apache.ivy.core.module.id.ModuleRevisionId;
import org.apache.ivy.plugins.namespace.NameSpaceHelper;
@@ -153,6 +161,23 @@ public final class XmlModuleDescriptorUp
private static class UpdaterHandler extends DefaultHandler implements LexicalHandler {
+ /** standard attributes of ivy-module/info */
+ private static final Collection stdAtts = Arrays.asList(new String[] {"organisation", "module", "branch",
+ "revision", "status", "publication", "namespace"});
+
+ /** elements that may appear inside ivy-module, in expected order */
+ private static final List moduleElements = Arrays.asList(new String[] {
+ "info", "configurations", "publications", "dependencies", "conflicts"
+ });
+ /** element position of "configurations" inside "ivy-module" */
+ private static final int CONFIGURATIONS_POSITION = moduleElements.indexOf("configurations");
+ /** element position of "dependencies" inside "ivy-module" */
+ private static final int DEPENDENCIES_POSITION = moduleElements.indexOf("dependencies");
+
+ /** elements that may appear inside of ivy-module/info */
+ private static final Collection infoElements = Arrays.asList(new String[]{
+ "extends", "ivyauthor", "license", "repository", "description" });
+
private final ParserSettings settings;
private final PrintWriter out;
@@ -213,6 +238,21 @@ public final class XmlModuleDescriptorUp
// with /> instead of ></qName>
private String justOpen = null;
+ //track the size of the left indent, so that inserted elements are formatted
+ //like nearby elements.
+
+ //true when we're reading indent whitespace
+ private boolean indenting;
+ private StringBuffer currentIndent = new StringBuffer();
+ private ArrayList indentLevels = new ArrayList(); // ArrayList<String>
+
+ //true if an ivy-module/info/description element has been found in the published descriptor
+ private boolean hasDescription = false;
+ //true if merged configurations have been written
+ private boolean mergedConfigurations = false;
+ //true if merged deps have been written
+ private boolean mergedDependencies = false;
+
// the new value of the defaultconf attribute on the publications tag
private String newDefaultConf = null;
@@ -225,10 +265,15 @@ public final class XmlModuleDescriptorUp
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
inHeader = false;
+ endIndent();
if (justOpen != null) {
write(">");
}
+
+ flushMergedElementsBefore(qName);
context.push(qName);
+
+ String path = getContext();
if ("info".equals(qName)) {
infoStarted(attributes);
} else if (replaceInclude && "include".equals(qName)
@@ -236,15 +281,17 @@ public final class XmlModuleDescriptorUp
//TODO, in the case of !replaceInclude, we should still replace the relative path
//by an absolute path.
includeStarted(attributes);
- } else if ("ivy-module/dependencies/dependency".equals(getContext())) {
+ } else if ("ivy-module/info/extends".equals(path)) {
+ startExtends(attributes);
+ } else if ("ivy-module/dependencies/dependency".equals(path)) {
startElementInDependency(attributes);
} else if ("dependencies".equals(qName)) {
startDependencies(attributes);
- } else if ("ivy-module/configurations/conf".equals(getContext())) {
+ } else if ("ivy-module/configurations/conf".equals(path)) {
startElementInConfigurationsConf(qName, attributes);
- } else if ("ivy-module/publications/artifact/conf".equals(getContext())
- || "ivy-module/dependencies/dependency/conf".equals(getContext())
- || "ivy-module/dependencies/dependency/artifact/conf".equals(getContext())) {
+ } else if ("ivy-module/publications/artifact/conf".equals(path)
+ || "ivy-module/dependencies/dependency/conf".equals(path)
+ || "ivy-module/dependencies/dependency/artifact/conf".equals(path)) {
buffers.push(new ExtendedBuffer(getContext()));
((ExtendedBuffer) confAttributeBuffers.peek()).setDefaultPrint(false);
String confName = substitute(settings, attributes.getValue("name"));
@@ -257,7 +304,7 @@ public final class XmlModuleDescriptorUp
+ substitute(settings, attributes.getValue(i)) + "\"");
}
}
- } else if ("ivy-module/publications/artifact".equals(getContext())) {
+ } else if ("ivy-module/publications/artifact".equals(path)) {
ExtendedBuffer buffer = new ExtendedBuffer(getContext());
buffers.push(buffer);
confAttributeBuffers.push(buffer);
@@ -278,7 +325,7 @@ public final class XmlModuleDescriptorUp
+ substitute(settings, attributes.getValue(i)) + "\"");
}
}
- } else if ("ivy-module/dependencies/dependency/artifact".equals(getContext())) {
+ } else if ("ivy-module/dependencies/dependency/artifact".equals(path)) {
ExtendedBuffer buffer = new ExtendedBuffer(getContext());
buffers.push(buffer);
confAttributeBuffers.push(buffer);
@@ -298,9 +345,22 @@ public final class XmlModuleDescriptorUp
+ substitute(settings, attributes.getValue(i)) + "\"");
}
}
- } else if ("ivy-module/publications".equals(getContext())) {
+ } else if ("ivy-module/publications".equals(path)) {
startPublications(attributes);
} else {
+ if (options.isMerge() && path.startsWith("ivy-module/info")) {
+ ModuleDescriptor merged = options.getMergedDescriptor();
+ if (path.equals("ivy-module/info/description")) {
+ //if the descriptor already contains a description, don't bother printing
+ //the merged version.
+ hasDescription = true;
+ } else if (!infoElements.contains(qName)) {
+ //according to the XSD, we should write description after all of the other
+ //standard <info> elements but before any extended elements.
+ writeInheritedDescription(merged);
+ }
+ }
+
// copy
write("<" + qName);
for (int i = 0; i < attributes.getLength(); i++) {
@@ -312,6 +372,47 @@ public final class XmlModuleDescriptorUp
// indent.append("\t");
}
+ private void startExtends(Attributes attributes) {
+ // in merge mode, comment out extends element
+ if (options.isMerge()) {
+ write("<!-- ");
+ }
+ write("<extends");
+
+ String org = substitute(settings, attributes.getValue("organisation"));
+ String module = substitute(settings, attributes.getValue("module"));
+ ModuleId parentId = new ModuleId(org, module);
+
+ for (int i = 0; i < attributes.getLength(); i++) {
+ String name = attributes.getQName(i);
+ String value = null;
+
+ if ("revision".equals(name)) {
+ //replace inline revision with resolved parent revision
+ ModuleDescriptor merged = options.getMergedDescriptor();
+ if (merged != null) {
+ ExtendsDescriptor[] parents = merged.getInheritedDescriptors();
+ for (int j = 0; value == null && j < parents.length; ++j) {
+ ModuleRevisionId resolvedId = parents[j].getResolvedParentRevisionId();
+ if (parentId.equals(resolvedId.getModuleId())) {
+ value = resolvedId.getRevision();
+ }
+ }
+ }
+ if (value == null) {
+ value = substitute(settings, attributes.getValue(i));
+ }
+ } else if ("organisation".equals(name)) {
+ value = org;
+ } else if ("module".equals(name)) {
+ value = module;
+ } else {
+ value = substitute(settings, attributes.getValue(i));
+ }
+ write(" " + name + "=\"" + value + "\"");
+ }
+ }
+
private void startElementInConfigurationsConf(String qName, Attributes attributes) {
buffers.push(new ExtendedBuffer(getContext()));
String confName = substitute(settings, attributes.getValue("name"));
@@ -556,18 +657,66 @@ public final class XmlModuleDescriptorUp
throw new SAXException(e);
}
}
-
+
private void infoStarted(Attributes attributes) {
- organisation = substitute(settings, attributes.getValue("organisation"));
+
String module = substitute(settings, attributes.getValue("module"));
- String rev = revision;
- if (rev == null) {
+ String rev = null;
+ String branch = null;
+ String status = null;
+ String namespace = null;
+ Map/*<String,String>*/ extraAttributes = null;
+
+ if (options.isMerge()) {
+ //get attributes from merged descriptor, ignoring raw XML
+ ModuleDescriptor merged = options.getMergedDescriptor();
+ ModuleRevisionId mergedMrid = merged.getModuleRevisionId();
+ organisation = mergedMrid.getOrganisation();
+ branch = mergedMrid.getBranch();
+ rev = mergedMrid.getRevision();
+ status = merged.getStatus();
+
+ //TODO: should namespace be added to ModuleDescriptor interface, so we don't
+ // have to do this kind of check?
+ if (merged instanceof DefaultModuleDescriptor) {
+ Namespace ns = ((DefaultModuleDescriptor)merged).getNamespace();
+ if (ns != null) {
+ namespace = ns.getName();
+ }
+ }
+ if (namespace == null) {
+ namespace = attributes.getValue("namespace");
+ }
+
+ extraAttributes = merged.getQualifiedExtraAttributes();
+ } else {
+ //get attributes from raw XML, performing property substitution
+ organisation = substitute(settings, attributes.getValue("organisation"));
rev = substitute(settings, attributes.getValue("revision"));
- }
- String branch = options.getBranch();
- if (branch == null) {
branch = substitute(settings, attributes.getValue("branch"));
+ status = substitute(settings, attributes.getValue("status"));
+ namespace = substitute(settings, attributes.getValue("namespace"));
+ extraAttributes = new LinkedHashMap(attributes.getLength());
+ for (int i = 0; i < attributes.getLength(); i++) {
+ String qname = attributes.getQName(i);
+ if (!stdAtts.contains(qname)) {
+ extraAttributes.put(qname, substitute(settings, attributes.getValue(i)));
+ }
+ }
+ }
+
+ //apply override values provided in options
+ if (revision != null) {
+ rev = revision;
+ }
+ if (options.getBranch() != null) {
+ branch = options.getBranch();
}
+ if (this.status != null) {
+ status = this.status;
+ }
+
+ //if necessary translate mrid using optional namespace argument
ModuleRevisionId localMid = ModuleRevisionId.newInstance(organisation, module, branch,
rev, ExtendableItemHelper.getExtraAttributes(settings, attributes,
new String[] {"organisation", "module", "revision", "status", "publication",
@@ -575,46 +724,40 @@ public final class XmlModuleDescriptorUp
ModuleRevisionId systemMid = ns == null ? localMid : ns.getToSystemTransformer()
.transform(localMid);
- write("<info organisation=\"" + XMLHelper.escape(systemMid.getOrganisation())
- + "\" module=\"" + XMLHelper.escape(systemMid.getName()) + "\"");
+ write("<info");
+ if (organisation != null) {
+ write(" organisation=\"" + XMLHelper.escape(systemMid.getOrganisation()) + "\"");
+ }
+ write(" module=\"" + XMLHelper.escape(systemMid.getName()) + "\"");
if (branch != null) {
write(" branch=\"" + XMLHelper.escape(systemMid.getBranch()) + "\"");
}
if (systemMid.getRevision() != null) {
write(" revision=\"" + XMLHelper.escape(systemMid.getRevision()) + "\"");
}
- if (status != null) {
- write(" status=\"" + XMLHelper.escape(status) + "\"");
- } else {
- write(" status=\"" + substitute(settings, attributes.getValue("status")) + "\"");
- }
+ write(" status=\"" + XMLHelper.escape(status) + "\"");
if (pubdate != null) {
write(" publication=\"" + Ivy.DATE_FORMAT.format(pubdate) + "\"");
} else if (attributes.getValue("publication") != null) {
write(" publication=\""
+ substitute(settings, attributes.getValue("publication")) + "\"");
}
- Collection stdAtts = Arrays.asList(new String[] {"organisation", "module", "branch",
- "revision", "status", "publication", "namespace"});
- if (attributes.getValue("namespace") != null) {
- write(" namespace=\"" + substitute(settings, attributes.getValue("namespace"))
- + "\"");
+ if (namespace != null) {
+ write(" namespace=\"" + namespace + "\"");
}
- for (int i = 0; i < attributes.getLength(); i++) {
- if (!stdAtts.contains(attributes.getQName(i))) {
- write(" " + attributes.getQName(i) + "=\""
- + substitute(settings, attributes.getValue(i)) + "\"");
- }
+
+ for (Iterator extras = extraAttributes.entrySet().iterator(); extras.hasNext(); ) {
+ Map.Entry extra = (Map.Entry)extras.next();
+ write(" " + extra.getKey() + "=\"" + extra.getValue() + "\"");
}
}
private void write(String content) {
- if (buffers.isEmpty()) {
- out.print(content);
- } else {
- ExtendedBuffer buffer = (ExtendedBuffer) buffers.peek();
- buffer.getBuffer().append(content);
- }
+ getWriter().print(content);
+ }
+
+ private PrintWriter getWriter() {
+ return buffers.isEmpty() ? out : ((ExtendedBuffer) buffers.peek()).getWriter();
}
private String getContext() {
@@ -684,15 +827,278 @@ public final class XmlModuleDescriptorUp
return newList.toString();
}
+ public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
+ characters(ch, start, length);
+ }
+
public void characters(char[] ch, int start, int length) throws SAXException {
if (justOpen != null) {
write(">");
justOpen = null;
}
write(String.valueOf(ch, start, length));
+
+ //examine characters for current indent level, keeping in mind
+ //that our indent might be split across multiple calls to characters()
+ for (int i = start, end = start + length; i < end; ++i) {
+ char c = ch[i];
+ if (c == '\r' || c == '\n') {
+ //newline resets the indent level
+ currentIndent.setLength(0);
+ indenting = true;
+ } else if (indenting) {
+ //indent continues until first non-whitespace character
+ if (Character.isWhitespace(c)) {
+ currentIndent.append(c);
+ } else {
+ endIndent();
+ }
+ }
+ }
+ }
+
+ /** record the current indent level for future elements that appear at the same depth */
+ private void endIndent() {
+ if (indenting) {
+ //record the indent at this level. if we insert any elements at
+ //this level, we'll use the same indent.
+ setIndent(context.size() - 1, currentIndent.toString());
+ indenting = false;
+ }
+ }
+
+ /**
+ * Set the indent for the given depth. Indents less than the provided depth
+ * will be calculated automatically, if they have not already been defined.
+ */
+ private void setIndent(int level, String indent) {
+ fillIndents(level);
+ indentLevels.set(level, indent);
+ }
+
+ /**
+ * Guarantee that indent levels have been calculated up to and including the
+ * given depth (starting at 0).
+ */
+ private void fillIndents(int level) {
+ if (indentLevels.isEmpty()) {
+ //add a default single-level indent until we see indents in the document
+ indentLevels.add(" ");
+ }
+ String oneLevel = (String) indentLevels.get(0);
+ for (int fill = indentLevels.size(); fill <= level; ++fill) {
+ indentLevels.add(indentLevels.get(fill - 1) + oneLevel);
+ }
+ }
+
+ /** get the whitespace that should precede new elements at the current depth in the document */
+ private String getIndent() {
+ int level = context.size() - 1;
+ fillIndents(level);
+ return (String) indentLevels.get(level);
+ }
+
+ /**
+ * Write XML elements that do not appear in the source descriptor, but have been copied in
+ * from a parent module descriptor via <extends> declaration.
+ * @param merged child descriptor containing the merged data
+ * @param items the list of inherited items to print
+ * @param printer a printer that knows how to write the given type of item
+ * @param itemName the name of the container element, e.g. "configurations"
+ * @param includeContainer if true, include an enclosing element named
+ * <code>itemName</code>. Otherwise just write the inherited items inline,
+ * with a comment indicating where they came from.
+ */
+ private void writeInheritedItems(ModuleDescriptor merged,
+ InheritableItem[] items, ItemPrinter printer, String itemName,
+ boolean includeContainer) {
+ //first categorize inherited items by their source module, so that
+ //we can add some useful comments
+ PrintWriter out = getWriter();
+
+ Map inheritedItems = collateInheritedItems(merged, items);
+ boolean hasItems = !inheritedItems.isEmpty();
+
+ if (hasItems && includeContainer) {
+ if (currentIndent.length() == 0) {
+ out.print(getIndent());
+ }
+ out.print("<" + itemName + ">");
+ context.push(itemName);
+ justOpen = null;
+ }
+
+ for (Iterator parents = inheritedItems.entrySet().iterator(); parents.hasNext();) {
+ Map.Entry entry = (Map.Entry) parents.next();
+ ModuleRevisionId parent = (ModuleRevisionId) entry.getKey();
+ List list = (List) entry.getValue();
+
+ if (justOpen != null) {
+ out.println(">");
+ justOpen = null; //helps endElement() decide how to write close tags
+ }
+ writeInheritanceComment(itemName, parent);
+ for (int c = 0; c < list.size(); ++c) {
+ InheritableItem item = (InheritableItem) list.get(c);
+ out.print(getIndent());
+ printer.print(merged, item, out);
+ }
+ }
+
+ if (hasItems) {
+ if (includeContainer) {
+ context.pop();
+ out.println(getIndent() + "</" + itemName + ">");
+ out.println();
+ }
+ //restore the prior indent
+ out.print(currentIndent);
+ }
+ }
+
+
+ private void writeInheritanceComment(String itemDescription, Object parentInfo) {
+ PrintWriter out = getWriter();
+ out.println();
+ out.println(getIndent() + "<!-- " + itemDescription + " inherited from "
+ + parentInfo + " -->");
+ }
+
+ /**
+ * Collect the given list of inherited descriptor items into lists keyed by parent Id.
+ * Thus all of the items inherited from parent A can be written together, then all of
+ * the items from parent B, and so on.
+ * @param merged the merged child descriptor
+ * @param items the inherited items to collate
+ * @return maps parent ModuleRevisionId to a List of InheritedItems imported from that parent
+ */
+ private Map/*<ModuleRevisionId,List>*/ collateInheritedItems(ModuleDescriptor merged,
+ InheritableItem[] items) {
+ LinkedHashMap/*<ModuleRevisionId,List>*/ inheritedItems = new LinkedHashMap();
+ for (int i = 0; i < items.length; ++i) {
+ ModuleRevisionId source = items[i].getSourceModule();
+ //ignore items that are defined directly in the child descriptor
+ if (source != null
+ && !source.getModuleId().equals(merged.getModuleRevisionId().getModuleId())) {
+ List accum = (List) inheritedItems.get(source);
+ if (accum == null) {
+ accum = new ArrayList();
+ inheritedItems.put(source, accum);
+ }
+ accum.add(items[i]);
+ }
+ }
+ return inheritedItems;
+ }
+
+ /**
+ * If no info/description element has yet been written, write the description inherited from
+ * the parent descriptor, if any. Calling this method more than once has no affect.
+ */
+ private void writeInheritedDescription(ModuleDescriptor merged) {
+ if (!hasDescription) {
+ hasDescription = true;
+ String description = merged.getDescription();
+ if (description != null) {
+ PrintWriter writer = getWriter();
+ if (justOpen != null) {
+ writer.println(">");
+ }
+ writeInheritanceComment("description", "parent");
+ writer.println(getIndent() + "<description>" + XMLHelper.escape(description) + "</description>");
+ //restore the indent that existed before we wrote the extra elements
+ writer.print(currentIndent);
+ justOpen = null;
+ }
+ }
+ }
+
+ private void writeInheritedConfigurations(ModuleDescriptor merged) {
+ if (!mergedConfigurations) {
+ mergedConfigurations = true;
+ writeInheritedItems(merged, merged.getConfigurations(),
+ ConfigurationPrinter.INSTANCE, "configurations", false);
+ }
+ }
+
+ private void writeInheritedDependencies(ModuleDescriptor merged) {
+ if (!mergedDependencies) {
+ mergedDependencies = true;
+ writeInheritedItems(merged, merged.getDependencies(),
+ DependencyPrinter.INSTANCE, "dependencies", false);
+ }
+ }
+
+ /**
+ * <p>If publishing in merge mode, guarantee that any merged elements appearing
+ * before <code>moduleElement</code> have been written. This method should
+ * be called <i>before</i> we write the start tag of <code>moduleElement</code>.
+ * This covers cases where merged elements like "configurations" and "dependencies" appear
+ * in the parent descriptor, but are completely missing in the child descriptor.</p>
+ *
+ * <p>For example, if "moduleElement" is "dependencies", guarantees that "configurations"
+ * has been written. If <code>moduleElement</code> is <code>null</code>, then all
+ * missing merged elements will be flushed.</p>
+ *
+ * @param moduleElement a descriptor element name, for example "configurations" or "info"
+ */
+ private void flushMergedElementsBefore(String moduleElement) {
+ if (options.isMerge() && context.size() == 1 && "ivy-module".equals(context.peek())
+ && !(mergedConfigurations && mergedDependencies)) {
+
+ //calculate the position of the element in ivy-module
+ int position = moduleElement == null ? moduleElements.size()
+ : moduleElements.indexOf(moduleElement);
+
+ ModuleDescriptor merged = options.getMergedDescriptor();
+
+ //see if we should write <configurations>
+ if (!mergedConfigurations && position > CONFIGURATIONS_POSITION
+ && merged.getConfigurations().length > 0) {
+
+ mergedConfigurations = true;
+ writeInheritedItems(merged, merged.getConfigurations(),
+ ConfigurationPrinter.INSTANCE, "configurations", true);
+
+ }
+ //see if we should write <dependencies>
+ if (!mergedDependencies && position > DEPENDENCIES_POSITION
+ && merged.getDependencies().length > 0) {
+
+ mergedDependencies = true;
+ writeInheritedItems(merged, merged.getDependencies(),
+ DependencyPrinter.INSTANCE, "dependencies", true);
+
+ }
+ }
+ }
+ private void flushAllMergedElements() {
+ flushMergedElementsBefore(null);
}
public void endElement(String uri, String localName, String qName) throws SAXException {
+
+ String path = getContext();
+ if (options.isMerge()) {
+ ModuleDescriptor merged = options.getMergedDescriptor();
+
+ if ("ivy-module/info".equals(path)) {
+ //guarantee that inherited description has been written before
+ //info element closes.
+ writeInheritedDescription(merged);
+ } else if ("ivy-module/configurations".equals(path)) {
+ //write inherited configurations after all child configurations
+ writeInheritedConfigurations(merged);
+ } else if ("ivy-module/dependencies".equals(path)) {
+ //write inherited dependencies after all child dependencies
+ writeInheritedDependencies(merged);
+ } else if ("ivy-module".equals(path)) {
+ //write any remaining inherited data before we close the
+ //descriptor.
+ flushAllMergedElements();
+ }
+ }
+
if (qName.equals(justOpen)) {
write("/>");
} else {
@@ -701,21 +1107,26 @@ public final class XmlModuleDescriptorUp
if (!buffers.isEmpty()) {
ExtendedBuffer buffer = (ExtendedBuffer) buffers.peek();
- if (buffer.getContext().equals(getContext())) {
+ if (buffer.getContext().equals(path)) {
buffers.pop();
if (buffer.isPrint()) {
- write(buffer.getBuffer().toString());
+ write(buffer.toString());
}
}
}
if (!confAttributeBuffers.isEmpty()) {
ExtendedBuffer buffer = (ExtendedBuffer) confAttributeBuffers.peek();
- if (buffer.getContext().equals(getContext())) {
+ if (buffer.getContext().equals(path)) {
confAttributeBuffers.pop();
}
}
+ //<extends> element is commented out when in merge mode.
+ if (options.isMerge() && "ivy-module/info/extends".equals(path)) {
+ write(" -->");
+ }
+
justOpen = null;
context.pop();
}
@@ -834,7 +1245,9 @@ public final class XmlModuleDescriptorUp
private boolean defaultPrint = false;
- private StringBuffer buffer = new StringBuffer();
+ private StringWriter buffer = new StringWriter();
+
+ private PrintWriter writer = new PrintWriter(buffer);
ExtendedBuffer(String context) {
this.context = context;
@@ -855,12 +1268,48 @@ public final class XmlModuleDescriptorUp
this.defaultPrint = print;
}
- StringBuffer getBuffer() {
- return buffer;
+ PrintWriter getWriter() {
+ return writer;
}
String getContext() {
return context;
}
+
+ public String toString() {
+ writer.flush();
+ return buffer.toString();
+ }
+ }
+
+ /**
+ * Prints a descriptor item's XML representation
+ */
+ protected static interface ItemPrinter {
+ /**
+ * Print an XML representation of <code>item</code> to <code>out</code>.
+ * @param parent the module descriptor containing <code>item</code>
+ * @param item subcomponent of the descriptor, for example a {@link DependencyDescriptor}
+ * or {@link Configuration}
+ */
+ public void print(ModuleDescriptor parent, Object item, PrintWriter out);
+ }
+
+ protected static class DependencyPrinter implements ItemPrinter {
+
+ public static final DependencyPrinter INSTANCE = new DependencyPrinter();
+
+ public void print(ModuleDescriptor parent, Object item, PrintWriter out) {
+ XmlModuleDescriptorWriter.printDependency(parent, (DependencyDescriptor) item, out);
+ }
+ }
+
+ protected static class ConfigurationPrinter implements ItemPrinter {
+
+ public static final ConfigurationPrinter INSTANCE = new ConfigurationPrinter();
+
+ public void print(ModuleDescriptor parent, Object item, PrintWriter out) {
+ XmlModuleDescriptorWriter.printConfiguration((Configuration) item, out);
+ }
}
}
Modified: ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorWriter.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorWriter.java?rev=942195&r1=942194&r2=942195&view=diff
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorWriter.java (original)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorWriter.java Fri May 7 20:00:48 2010
@@ -29,19 +29,11 @@ import java.util.Map.Entry;
import org.apache.ivy.Ivy;
import org.apache.ivy.core.IvyPatternHelper;
-import org.apache.ivy.core.module.descriptor.Artifact;
-import org.apache.ivy.core.module.descriptor.Configuration;
-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.DependencyDescriptorMediator;
-import org.apache.ivy.core.module.descriptor.ExcludeRule;
-import org.apache.ivy.core.module.descriptor.IncludeRule;
-import org.apache.ivy.core.module.descriptor.License;
-import org.apache.ivy.core.module.descriptor.ModuleDescriptor;
-import org.apache.ivy.core.module.descriptor.OverrideDependencyDescriptorMediator;
+import org.apache.ivy.core.module.descriptor.*;
+import org.apache.ivy.core.module.id.ModuleRevisionId;
import org.apache.ivy.plugins.matcher.MapMatcher;
import org.apache.ivy.util.Message;
+import org.apache.ivy.util.StringUtils;
import org.apache.ivy.util.XMLHelper;
import org.apache.ivy.util.extendable.ExtendableItem;
@@ -93,82 +85,89 @@ public final class XmlModuleDescriptorWr
if (dds.length > 0) {
out.println("\t<dependencies>");
for (int i = 0; i < dds.length; i++) {
- out.print("\t\t<dependency");
- out.print(" org=\""
- + XMLHelper.escape(dds[i].getDependencyRevisionId().getOrganisation()) + "\"");
- out.print(" name=\""
- + XMLHelper.escape(dds[i].getDependencyRevisionId().getName()) + "\"");
- if (dds[i].getDependencyRevisionId().getBranch() != null) {
- out.print(" branch=\""
- + XMLHelper.escape(dds[i].getDependencyRevisionId().getBranch()) + "\"");
- }
- out.print(" rev=\""
- + XMLHelper.escape(dds[i].getDependencyRevisionId().getRevision()) + "\"");
- if (!dds[i].getDynamicConstraintDependencyRevisionId()
- .equals(dds[i].getDependencyRevisionId())) {
- if (dds[i].getDynamicConstraintDependencyRevisionId().getBranch() != null) {
- out.print(" branchConstraint=\"" + XMLHelper.escape(
- dds[i].getDynamicConstraintDependencyRevisionId().getBranch()) + "\"");
- }
- out.print(" revConstraint=\"" + XMLHelper.escape(
- dds[i].getDynamicConstraintDependencyRevisionId().getRevision()) + "\"");
- }
- if (dds[i].isForce()) {
- out.print(" force=\"" + dds[i].isForce() + "\"");
- }
- if (dds[i].isChanging()) {
- out.print(" changing=\"" + dds[i].isChanging() + "\"");
- }
- if (!dds[i].isTransitive()) {
- out.print(" transitive=\"" + dds[i].isTransitive() + "\"");
- }
- out.print(" conf=\"");
- String[] modConfs = dds[i].getModuleConfigurations();
- for (int j = 0; j < modConfs.length; j++) {
- String[] depConfs = dds[i].getDependencyConfigurations(modConfs[j]);
- out.print(XMLHelper.escape(modConfs[j]) + "->");
- for (int k = 0; k < depConfs.length; k++) {
- out.print(XMLHelper.escape(depConfs[k]));
- if (k + 1 < depConfs.length) {
- out.print(",");
- }
- }
- if (j + 1 < modConfs.length) {
- out.print(";");
- }
- }
- out.print("\"");
-
- printExtraAttributes(dds[i], out, " ");
-
- DependencyArtifactDescriptor[] depArtifacts = dds[i].getAllDependencyArtifacts();
- if (depArtifacts.length > 0) {
- out.println(">");
- }
- printDependencyArtefacts(md, out, depArtifacts);
-
- IncludeRule[] includes = dds[i].getAllIncludeRules();
- if (includes.length > 0 && depArtifacts.length == 0) {
- out.println(">");
- }
- printDependencyIncludeRules(md, out, includes);
-
- ExcludeRule[] excludes = dds[i].getAllExcludeRules();
- if (excludes.length > 0 && includes.length == 0 && depArtifacts.length == 0) {
- out.println(">");
- }
- printDependencyExcludeRules(md, out, excludes);
- if (includes.length + excludes.length + depArtifacts.length == 0) {
- out.println("/>");
- } else {
- out.println("\t\t</dependency>");
- }
+ DependencyDescriptor dep = dds[i];
+ out.print("\t\t");
+ printDependency(md, dep, out);
}
printAllExcludes(md, out);
printAllMediators(md, out);
out.println("\t</dependencies>");
}
}
+
+ protected static void printDependency(ModuleDescriptor md, DependencyDescriptor dep,
+ PrintWriter out) {
+ out.print("<dependency");
+ out.print(" org=\""
+ + XMLHelper.escape(dep.getDependencyRevisionId().getOrganisation()) + "\"");
+ out.print(" name=\""
+ + XMLHelper.escape(dep.getDependencyRevisionId().getName()) + "\"");
+ if (dep.getDependencyRevisionId().getBranch() != null) {
+ out.print(" branch=\""
+ + XMLHelper.escape(dep.getDependencyRevisionId().getBranch()) + "\"");
+ }
+ out.print(" rev=\""
+ + XMLHelper.escape(dep.getDependencyRevisionId().getRevision()) + "\"");
+ if (!dep.getDynamicConstraintDependencyRevisionId()
+ .equals(dep.getDependencyRevisionId())) {
+ if (dep.getDynamicConstraintDependencyRevisionId().getBranch() != null) {
+ out.print(" branchConstraint=\"" + XMLHelper.escape(
+ dep.getDynamicConstraintDependencyRevisionId().getBranch()) + "\"");
+ }
+ out.print(" revConstraint=\"" + XMLHelper.escape(
+ dep.getDynamicConstraintDependencyRevisionId().getRevision()) + "\"");
+ }
+ if (dep.isForce()) {
+ out.print(" force=\"" + dep.isForce() + "\"");
+ }
+ if (dep.isChanging()) {
+ out.print(" changing=\"" + dep.isChanging() + "\"");
+ }
+ if (!dep.isTransitive()) {
+ out.print(" transitive=\"" + dep.isTransitive() + "\"");
+ }
+ out.print(" conf=\"");
+ String[] modConfs = dep.getModuleConfigurations();
+ for (int j = 0; j < modConfs.length; j++) {
+ String[] depConfs = dep.getDependencyConfigurations(modConfs[j]);
+ out.print(XMLHelper.escape(modConfs[j]) + "->");
+ for (int k = 0; k < depConfs.length; k++) {
+ out.print(XMLHelper.escape(depConfs[k]));
+ if (k + 1 < depConfs.length) {
+ out.print(",");
+ }
+ }
+ if (j + 1 < modConfs.length) {
+ out.print(";");
+ }
+ }
+ out.print("\"");
+
+ printExtraAttributes(dep, out, " ");
+
+ DependencyArtifactDescriptor[] depArtifacts = dep.getAllDependencyArtifacts();
+ if (depArtifacts.length > 0) {
+ out.println(">");
+ }
+ printDependencyArtefacts(md, out, depArtifacts);
+
+ IncludeRule[] includes = dep.getAllIncludeRules();
+ if (includes.length > 0 && depArtifacts.length == 0) {
+ out.println(">");
+ }
+ printDependencyIncludeRules(md, out, includes);
+
+ ExcludeRule[] excludes = dep.getAllExcludeRules();
+ if (excludes.length > 0 && includes.length == 0 && depArtifacts.length == 0) {
+ out.println(">");
+ }
+ printDependencyExcludeRules(md, out, excludes);
+ if (includes.length + excludes.length + depArtifacts.length == 0) {
+ out.println("/>");
+ } else {
+ out.println("\t\t</dependency>");
+ }
+ }
private static void printAllMediators(ModuleDescriptor md, PrintWriter out) {
Map/*<MapMatcher, DependencyDescriptorMediator>*/ mediators
@@ -381,34 +380,40 @@ public final class XmlModuleDescriptorWr
if (confs.length > 0) {
out.println("\t<configurations>");
for (int i = 0; i < confs.length; i++) {
- out.print("\t\t<conf");
- out.print(" name=\"" + XMLHelper.escape(confs[i].getName()) + "\"");
- out.print(" visibility=\""
- + XMLHelper.escape(confs[i].getVisibility().toString()) + "\"");
- if (confs[i].getDescription() != null) {
- out.print(" description=\""
- + XMLHelper.escape(confs[i].getDescription()) + "\"");
- }
- String[] exts = confs[i].getExtends();
- if (exts.length > 0) {
- out.print(" extends=\"");
- for (int j = 0; j < exts.length; j++) {
- out.print(XMLHelper.escape(exts[j]));
- if (j + 1 < exts.length) {
- out.print(",");
- }
- }
- out.print("\"");
- }
- if (confs[i].getDeprecated() != null) {
- out.print(" deprecated=\"" + XMLHelper.escape(confs[i].getDeprecated()) + "\"");
- }
- printExtraAttributes(confs[i], out, " ");
- out.println("/>");
+ Configuration conf = confs[i];
+ out.print("\t\t");
+ printConfiguration(conf, out);
}
out.println("\t</configurations>");
}
}
+
+ protected static void printConfiguration(Configuration conf, PrintWriter out) {
+ out.print("<conf");
+ out.print(" name=\"" + XMLHelper.escape(conf.getName()) + "\"");
+ out.print(" visibility=\""
+ + XMLHelper.escape(conf.getVisibility().toString()) + "\"");
+ if (conf.getDescription() != null) {
+ out.print(" description=\""
+ + XMLHelper.escape(conf.getDescription()) + "\"");
+ }
+ String[] exts = conf.getExtends();
+ if (exts.length > 0) {
+ out.print(" extends=\"");
+ for (int j = 0; j < exts.length; j++) {
+ out.print(XMLHelper.escape(exts[j]));
+ if (j + 1 < exts.length) {
+ out.print(",");
+ }
+ }
+ out.print("\"");
+ }
+ if (conf.getDeprecated() != null) {
+ out.print(" deprecated=\"" + XMLHelper.escape(conf.getDeprecated()) + "\"");
+ }
+ printExtraAttributes(conf, out, " ");
+ out.println("/>");
+ }
private static void printInfoTag(ModuleDescriptor md, PrintWriter out) {
out.println("\t<info organisation=\""
@@ -442,6 +447,21 @@ public final class XmlModuleDescriptorWr
}
if (requireInnerInfoElement(md)) {
out.println("\t>");
+ ExtendsDescriptor[] parents = md.getInheritedDescriptors();
+ for (int i = 0; i < parents.length; i++) {
+ ExtendsDescriptor parent = parents[i];
+ ModuleRevisionId mrid = parent.getParentRevisionId();
+ out.print("\t\t<extends organisation=\"" + XMLHelper.escape(mrid.getOrganisation()) + "\""
+ + " module=\"" + XMLHelper.escape(mrid.getName()) + "\""
+ + " revision=\"" + XMLHelper.escape(mrid.getRevision()) + "\"");
+
+ String location = parent.getLocation();
+ if (location != null) {
+ out.print(" location=\"" + XMLHelper.escape(location) + "\"");
+ }
+ out.print(" extendTypes=\"" + StringUtils.join(parent.getExtendsTypes(), ",") + "\"");
+ out.println("/>");
+ }
License[] licenses = md.getLicenses();
for (int i = 0; i < licenses.length; i++) {
License license = licenses[i];
@@ -492,7 +512,8 @@ public final class XmlModuleDescriptorWr
return md.getExtraInfo().size() > 0
|| md.getHomePage() != null
|| (md.getDescription() != null && md.getDescription().trim().length() > 0)
- || md.getLicenses().length > 0;
+ || md.getLicenses().length > 0
+ || md.getInheritedDescriptors().length > 0;
}
private static String getConfs(ModuleDescriptor md, Artifact artifact) {
Modified: ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/parser/xml/ivy.xsd
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/parser/xml/ivy.xsd?rev=942195&r1=942194&r2=942195&view=diff
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/parser/xml/ivy.xsd (original)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/parser/xml/ivy.xsd Fri May 7 20:00:48 2010
@@ -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="module" 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"/>
@@ -91,7 +100,7 @@
</xs:element>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other" processContents="lax"/>
</xs:sequence>
- <xs:attribute name="organisation" type="xs:string" use="required"/>
+ <xs:attribute name="organisation" type="xs:string"/>
<xs:attribute name="module" type="xs:string" use="required"/>
<xs:attribute name="branch" type="xs:string"/>
<xs:attribute name="revision" type="xs:string"/>
Modified: ant/ivy/core/trunk/test/java/org/apache/ivy/ant/IvyDeliverTest.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/test/java/org/apache/ivy/ant/IvyDeliverTest.java?rev=942195&r1=942194&r2=942195&view=diff
==============================================================================
--- ant/ivy/core/trunk/test/java/org/apache/ivy/ant/IvyDeliverTest.java (original)
+++ ant/ivy/core/trunk/test/java/org/apache/ivy/ant/IvyDeliverTest.java Fri May 7 20:00:48 2010
@@ -20,6 +20,9 @@ package org.apache.ivy.ant;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.text.ParseException;
import java.util.HashMap;
import java.util.Map;
@@ -87,6 +90,64 @@ public class IvyDeliverTest extends Test
del.execute();
}
+ public void testMergeParent() throws IOException, ParseException {
+ //publish the parent descriptor first, so that it can be found while
+ //we are reading the child descriptor.
+ project.setProperty("ivy.dep.file", "test/java/org/apache/ivy/ant/ivy-multiconf.xml");
+ IvyResolve res = new IvyResolve();
+ res.setProject(project);
+ res.execute();
+
+ IvyPublish pubParent = new IvyPublish();
+ pubParent.setProject(project);
+ pubParent.setResolver("1");
+ pubParent.setPubrevision("1.0");
+ File art = new File("build/test/deliver/resolve-simple-1.0.jar");
+ FileUtil.copy(new File("test/repositories/1/org1/mod1.1/jars/mod1.1-1.0.jar"), art, null);
+ pubParent.execute();
+
+ //resolve and deliver the child descriptor
+ project.setProperty("ivy.dep.file", "test/java/org/apache/ivy/ant/ivy-extends-multiconf.xml");
+ res = new IvyResolve();
+ res.setProject(project);
+ res.execute();
+
+ deliver.setPubrevision("1.2");
+ deliver.setDeliverpattern("build/test/deliver/merge/ivy-[revision].xml");
+ deliver.execute();
+
+ // should have delivered the file to the specified destination
+ File delivered = new File("build/test/deliver/merge/ivy-1.2.xml");
+ assertTrue(delivered.exists());
+
+ // do a text compare, since we want to test comments as well as structure.
+ // we could do a better job of this with xmlunit
+ int lineNo = 1;
+
+ BufferedReader merged = new BufferedReader(new FileReader(delivered));
+ BufferedReader expected = new BufferedReader(new InputStreamReader(getClass()
+ .getResourceAsStream("ivy-extends-merged.xml")));
+ try {
+ for (String mergeLine = merged.readLine(),
+ expectedLine = expected.readLine();
+ mergeLine != null && expectedLine != null;
+ mergeLine = merged.readLine(),
+ expectedLine = expected.readLine()) {
+
+ mergeLine = mergeLine.trim();
+ expectedLine = expectedLine.trim();
+
+ if (!mergeLine.startsWith("<info"))
+ assertEquals("published descriptor matches at line[" + lineNo + "]", expectedLine.trim(), mergeLine.trim());
+
+ ++lineNo;
+ }
+ } finally {
+ merged.close();
+ expected.close();
+ }
+ }
+
public void testSimple() throws Exception {
project.setProperty("ivy.dep.file", "test/java/org/apache/ivy/ant/ivy-latest.xml");
IvyResolve res = new IvyResolve();
Modified: ant/ivy/core/trunk/test/java/org/apache/ivy/ant/IvyPublishTest.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/test/java/org/apache/ivy/ant/IvyPublishTest.java?rev=942195&r1=942194&r2=942195&view=diff
==============================================================================
--- ant/ivy/core/trunk/test/java/org/apache/ivy/ant/IvyPublishTest.java (original)
+++ ant/ivy/core/trunk/test/java/org/apache/ivy/ant/IvyPublishTest.java Fri May 7 20:00:48 2010
@@ -20,7 +20,9 @@ package org.apache.ivy.ant;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
+import java.io.IOException;
import java.io.InputStreamReader;
+import java.text.ParseException;
import junit.framework.TestCase;
@@ -85,6 +87,124 @@ public class IvyPublishTest extends Test
del.execute();
}
+ public void testMergeParent() throws IOException, ParseException {
+ //publish the parent descriptor first, so that it can be found while
+ //we are reading the child descriptor.
+ project.setProperty("ivy.dep.file", "test/java/org/apache/ivy/ant/ivy-multiconf.xml");
+ IvyResolve res = new IvyResolve();
+ res.setProject(project);
+ res.execute();
+
+ IvyPublish pubParent = new IvyPublish();
+ pubParent.setProject(project);
+ pubParent.setResolver("1");
+ pubParent.setPubrevision("1.0");
+ File art = new File("build/test/publish/resolve-simple-1.0.jar");
+ FileUtil.copy(new File("test/repositories/1/org1/mod1.1/jars/mod1.1-1.0.jar"), art, null);
+ pubParent.execute();
+
+ //update=true implies merge=true
+ project.setProperty("ivy.dep.file", "test/java/org/apache/ivy/ant/ivy-extends-multiconf.xml");
+ publish.setResolver("1");
+ publish.setUpdate(true);
+ publish.setOrganisation("apache");
+ publish.setModule("resolve-extends");
+ publish.setRevision("1.0");
+ publish.setPubrevision("1.2");
+ publish.setStatus("release");
+ publish.addArtifactspattern("test/java/org/apache/ivy/ant/ivy-extends-multiconf.xml");
+ publish.execute();
+
+ // should have published the files with "1" resolver
+ File published = new File("test/repositories/1/apache/resolve-extends/ivys/ivy-1.2.xml");
+ assertTrue(published.exists());
+
+ // do a text compare, since we want to test comments as well as structure.
+ // we could do a better job of this with xmlunit
+
+ int lineNo = 1;
+
+ BufferedReader merged = new BufferedReader(new FileReader(published));
+ BufferedReader expected = new BufferedReader(new InputStreamReader(getClass()
+ .getResourceAsStream("ivy-extends-merged.xml")));
+ for (String mergeLine = merged.readLine(),
+ expectedLine = expected.readLine();
+ mergeLine != null && expectedLine != null;
+ mergeLine = merged.readLine(),
+ expectedLine = expected.readLine()) {
+
+ //strip timestamps for the comparison
+ if (mergeLine.indexOf("<info") >= 0) {
+ mergeLine = mergeLine.replaceFirst("\\s?publication=\"\\d+\"", "");
+ }
+ //discard whitespace-only lines
+ if (!(mergeLine.trim().equals("") && expectedLine.trim().equals(""))) {
+ assertEquals("published descriptor matches at line[" + lineNo + "]", expectedLine, mergeLine);
+ }
+
+ ++lineNo;
+ }
+ }
+
+ public void testMinimalMerge() throws IOException, ParseException {
+ //publish the parent descriptor first, so that it can be found while
+ //we are reading the child descriptor.
+ project.setProperty("ivy.dep.file", "test/java/org/apache/ivy/ant/ivy-multiconf.xml");
+ IvyResolve res = new IvyResolve();
+ res.setProject(project);
+ res.execute();
+
+ IvyPublish pubParent = new IvyPublish();
+ pubParent.setProject(project);
+ pubParent.setResolver("1");
+ pubParent.setPubrevision("1.0");
+ File art = new File("build/test/publish/resolve-simple-1.0.jar");
+ FileUtil.copy(new File("test/repositories/1/org1/mod1.1/jars/mod1.1-1.0.jar"), art, null);
+ pubParent.execute();
+
+ //update=true implies merge=true
+ project.setProperty("ivy.dep.file", "test/java/org/apache/ivy/ant/ivy-extends-minimal.xml");
+ publish.setResolver("1");
+ publish.setUpdate(true);
+ publish.setOrganisation("apache");
+ publish.setModule("resolve-extends");
+ publish.setRevision("1.0");
+ publish.setPubrevision("1.2");
+ publish.setStatus("release");
+ publish.addArtifactspattern("test/java/org/apache/ivy/ant/ivy-extends-minimal.xml");
+ publish.execute();
+
+ // should have published the files with "1" resolver
+ File published = new File("test/repositories/1/apache/resolve-minimal/ivys/ivy-1.2.xml");
+ assertTrue(published.exists());
+
+ // do a text compare, since we want to test comments as well as structure.
+ // we could do a better job of this with xmlunit
+
+ int lineNo = 1;
+
+ BufferedReader merged = new BufferedReader(new FileReader(published));
+ BufferedReader expected = new BufferedReader(new InputStreamReader(getClass()
+ .getResourceAsStream("ivy-extends-minimal-merged.xml")));
+ for (String mergeLine = merged.readLine(),
+ expectedLine = expected.readLine();
+ mergeLine != null && expectedLine != null;
+ mergeLine = merged.readLine(),
+ expectedLine = expected.readLine()) {
+
+ //strip timestamps for the comparison
+ if (mergeLine.indexOf("<info") >= 0) {
+ mergeLine = mergeLine.replaceFirst("\\s?publication=\"\\d+\"", "");
+ }
+ //discard whitespace-only lines
+ if (!(mergeLine.trim().equals("") && expectedLine.trim().equals(""))) {
+ assertEquals("published descriptor matches at line[" + lineNo + "]", expectedLine, mergeLine);
+ }
+
+ ++lineNo;
+ }
+ }
+
public void testSimple() throws Exception {
project.setProperty("ivy.dep.file", "test/java/org/apache/ivy/ant/ivy-multiconf.xml");
IvyResolve res = new IvyResolve();
Added: ant/ivy/core/trunk/test/java/org/apache/ivy/ant/ivy-extends-merged.xml
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/test/java/org/apache/ivy/ant/ivy-extends-merged.xml?rev=942195&view=auto
==============================================================================
--- ant/ivy/core/trunk/test/java/org/apache/ivy/ant/ivy-extends-merged.xml (added)
+++ ant/ivy/core/trunk/test/java/org/apache/ivy/ant/ivy-extends-merged.xml Fri May 7 20:00:48 2010
@@ -0,0 +1,51 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you 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.
+-->
+<ivy-module version="2.0">
+
+ <info organisation="apache" module="resolve-extends" revision="1.2" status="release">
+ <!-- <extends organisation="apache" module="resolve-simple" revision="1.0" location="./ivy-multiconf.xml"/> -->
+
+ <!-- description inherited from parent -->
+ <description>Demonstrates configuration-specific dependencies</description>
+ </info>
+
+ <configurations>
+ <!-- conf not in parent -->
+ <conf name="extra"/>
+ <!-- overrides conf in parent -->
+ <conf name="default" extends="compile" description="overrides the conf definition in parent descriptor"/>
+
+ <!-- configurations inherited from apache#resolve-simple;1.0 -->
+ <conf name="compile" visibility="public"/>
+ </configurations>
+
+ <publications/>
+
+ <dependencies>
+ <!-- not in parent -->
+ <dependency org="org2" name="mod2.1" rev="0.3" conf="default"/>
+ <!-- overrides parent -->
+ <dependency org="org1" name="mod1.1" rev="1.1" conf="default,compile->default" transitive="false"/>
+
+ <!-- dependencies inherited from apache#resolve-simple;1.0 -->
+ <dependency org="org1" name="mod1.2" rev="2.0" conf="default->default"/>
+ <dependency org="org1" name="mod1.1" rev="2.0" transitive="false" conf="compile->default"/>
+ </dependencies>
+
+</ivy-module>
\ No newline at end of file
Propchange: ant/ivy/core/trunk/test/java/org/apache/ivy/ant/ivy-extends-merged.xml
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: ant/ivy/core/trunk/test/java/org/apache/ivy/ant/ivy-extends-minimal-merged.xml
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/test/java/org/apache/ivy/ant/ivy-extends-minimal-merged.xml?rev=942195&view=auto
==============================================================================
--- ant/ivy/core/trunk/test/java/org/apache/ivy/ant/ivy-extends-minimal-merged.xml (added)
+++ ant/ivy/core/trunk/test/java/org/apache/ivy/ant/ivy-extends-minimal-merged.xml Fri May 7 20:00:48 2010
@@ -0,0 +1,42 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you 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.
+-->
+<ivy-module version="2.0">
+
+ <info organisation="apache" module="resolve-minimal" revision="1.2" status="release">
+ <!-- <extends organisation="apache" module="resolve-simple" revision="1.0" location="./ivy-multiconf.xml"/> -->
+
+ <!-- description inherited from parent -->
+ <description>Demonstrates configuration-specific dependencies</description>
+ </info>
+
+ <configurations>
+ <!-- configurations inherited from apache#resolve-simple;1.0 -->
+ <conf name="default" visibility="public"/>
+ <conf name="compile" visibility="public"/>
+ </configurations>
+
+ <publications/>
+
+ <dependencies>
+ <!-- dependencies inherited from apache#resolve-simple;1.0 -->
+ <dependency org="org1" name="mod1.2" rev="2.0" conf="default->default"/>
+ <dependency org="org1" name="mod1.1" rev="2.0" transitive="false" conf="compile->default"/>
+ </dependencies>
+
+</ivy-module>
\ No newline at end of file
Propchange: ant/ivy/core/trunk/test/java/org/apache/ivy/ant/ivy-extends-minimal-merged.xml
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: ant/ivy/core/trunk/test/java/org/apache/ivy/ant/ivy-extends-minimal.xml
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/test/java/org/apache/ivy/ant/ivy-extends-minimal.xml?rev=942195&view=auto
==============================================================================
--- ant/ivy/core/trunk/test/java/org/apache/ivy/ant/ivy-extends-minimal.xml (added)
+++ ant/ivy/core/trunk/test/java/org/apache/ivy/ant/ivy-extends-minimal.xml Fri May 7 20:00:48 2010
@@ -0,0 +1,27 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you 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.
+-->
+<ivy-module version="2.0">
+
+ <info module="resolve-minimal">
+ <extends organisation="apache" module="resolve-simple" revision="latest.integration" location="./ivy-multiconf.xml"/>
+ </info>
+
+ <publications/>
+
+</ivy-module>
\ No newline at end of file
Propchange: ant/ivy/core/trunk/test/java/org/apache/ivy/ant/ivy-extends-minimal.xml
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: ant/ivy/core/trunk/test/java/org/apache/ivy/ant/ivy-extends-multiconf.xml
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/test/java/org/apache/ivy/ant/ivy-extends-multiconf.xml?rev=942195&view=auto
==============================================================================
--- ant/ivy/core/trunk/test/java/org/apache/ivy/ant/ivy-extends-multiconf.xml (added)
+++ ant/ivy/core/trunk/test/java/org/apache/ivy/ant/ivy-extends-multiconf.xml Fri May 7 20:00:48 2010
@@ -0,0 +1,41 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you 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.
+-->
+<ivy-module version="2.0">
+
+ <info module="resolve-extends">
+ <extends organisation="apache" module="resolve-simple" revision="latest.integration" location="./ivy-multiconf.xml"/>
+ </info>
+
+ <configurations>
+ <!-- conf not in parent -->
+ <conf name="extra" />
+ <!-- overrides conf in parent -->
+ <conf name="default" extends="compile" description="overrides the conf definition in parent descriptor"/>
+ </configurations>
+
+ <publications/>
+
+ <dependencies>
+ <!-- not in parent -->
+ <dependency org="org2" name="mod2.1" rev="0.3" conf="default" />
+ <!-- overrides parent -->
+ <dependency org="org1" name="mod1.1" rev="1.1" conf="default,compile->default" transitive="false" />
+ </dependencies>
+
+</ivy-module>
\ No newline at end of file
Propchange: ant/ivy/core/trunk/test/java/org/apache/ivy/ant/ivy-extends-multiconf.xml
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: ant/ivy/core/trunk/test/java/org/apache/ivy/ant/ivy-multiconf.xml
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/test/java/org/apache/ivy/ant/ivy-multiconf.xml?rev=942195&r1=942194&r2=942195&view=diff
==============================================================================
--- ant/ivy/core/trunk/test/java/org/apache/ivy/ant/ivy-multiconf.xml (original)
+++ ant/ivy/core/trunk/test/java/org/apache/ivy/ant/ivy-multiconf.xml Fri May 7 20:00:48 2010
@@ -21,7 +21,9 @@
module="resolve-simple"
revision="1.0"
status="release"
- />
+ >
+ <description>Demonstrates configuration-specific dependencies</description>
+ </info>
<configurations>
<conf name="default" />
<conf name="compile" />
Modified: ant/ivy/core/trunk/test/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParserTest.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/test/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParserTest.java?rev=942195&r1=942194&r2=942195&view=diff
==============================================================================
--- ant/ivy/core/trunk/test/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParserTest.java (original)
+++ ant/ivy/core/trunk/test/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParserTest.java Fri May 7 20:00:48 2010
@@ -31,7 +31,6 @@ import org.apache.ivy.core.module.descri
import org.apache.ivy.core.module.descriptor.Configuration;
import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor;
import org.apache.ivy.core.module.descriptor.DependencyDescriptor;
-import org.apache.ivy.core.module.descriptor.DependencyDescriptorMediator;
import org.apache.ivy.core.module.descriptor.ExcludeRule;
import org.apache.ivy.core.module.descriptor.License;
import org.apache.ivy.core.module.descriptor.ModuleDescriptor;
@@ -46,6 +45,8 @@ import org.apache.ivy.plugins.matcher.Ex
import org.apache.ivy.plugins.matcher.GlobPatternMatcher;
import org.apache.ivy.plugins.matcher.PatternMatcher;
import org.apache.ivy.plugins.parser.AbstractModuleDescriptorParserTester;
+import org.apache.ivy.plugins.resolver.FileSystemResolver;
+import org.apache.ivy.util.FileUtil;
import org.apache.ivy.util.XMLHelper;
public class XmlModuleDescriptorParserTest extends AbstractModuleDescriptorParserTester {
@@ -55,6 +56,8 @@ public class XmlModuleDescriptorParserTe
super.setUp();
this.settings = new IvySettings();
+ //prevent test from polluting local cache
+ settings.setDefaultCache(new File("build/cache"));
}
public void testSimple() throws Exception {
@@ -78,7 +81,7 @@ public class XmlModuleDescriptorParserTe
assertNotNull(md.getDependencies());
assertEquals(0, md.getDependencies().length);
}
-
+
public void testNamespaces() throws Exception {
ModuleDescriptor md = XmlModuleDescriptorParser.getInstance().parseDescriptor(settings,
getClass().getResource("test-namespaces.xml"), true);
@@ -1018,4 +1021,333 @@ public class XmlModuleDescriptorParserTe
// expected
}
}
+
+ public void testExtendsAll() throws Exception {
+ //default extends type is 'all' when no extendsType attribute is specified.
+ ModuleDescriptor md = XmlModuleDescriptorParser.getInstance().parseDescriptor(settings,
+ getClass().getResource("test-extends-all.xml"), true);
+ assertNotNull(md);
+
+ assertEquals("myorg", md.getModuleRevisionId().getOrganisation());
+ assertEquals("mymodule", md.getModuleRevisionId().getName());
+ assertEquals(Ivy.getWorkingRevision(), md.getModuleRevisionId().getRevision());
+ assertEquals("integration", md.getStatus());
+
+ //verify that the parent description was merged.
+ assertEquals("Parent module description.", md.getDescription());
+
+ //verify that the parent and child configurations were merged together.
+ final Configuration[] expectedConfs = { new Configuration("default"),
+ new Configuration("conf1"), new Configuration("conf2") };
+ assertNotNull(md.getConfigurations());
+ assertEquals(Arrays.asList(expectedConfs), Arrays
+ .asList(md.getConfigurations()));
+
+ //verify parent and child dependencies were merged together.
+ DependencyDescriptor[] deps = md.getDependencies();
+ assertNotNull(deps);
+ assertEquals(2, deps.length);
+
+ assertEquals(Arrays.asList(new String[]{ "default" }),
+ Arrays.asList(deps[0].getModuleConfigurations()));
+ ModuleRevisionId dep = deps[0].getDependencyRevisionId();
+ assertEquals("myorg", dep.getModuleId().getOrganisation());
+ assertEquals("mymodule1", dep.getModuleId().getName());
+ assertEquals("1.0", dep.getRevision());
+
+ assertEquals(Arrays.asList(new String[]{ "conf1", "conf2" }),
+ Arrays.asList(deps[1].getModuleConfigurations()));
+ dep = deps[1].getDependencyRevisionId();
+ assertEquals("myorg", dep.getModuleId().getOrganisation());
+ assertEquals("mymodule2", dep.getModuleId().getName());
+ assertEquals("2.0", dep.getRevision());
+
+ //verify only child publications are present
+ Artifact[] artifacts = md.getAllArtifacts();
+ assertNotNull(artifacts);
+ assertEquals(1, artifacts.length);
+ assertEquals("mymodule", artifacts[0].getName());
+ assertEquals("jar", artifacts[0].getType());
+ }
+
+ public void testExtendsDependencies() throws Exception {
+ //descriptor specifies that only parent dependencies should be included
+ ModuleDescriptor md = XmlModuleDescriptorParser.getInstance().parseDescriptor(settings,
+ getClass().getResource("test-extends-dependencies.xml"), true);
+ assertNotNull(md);
+
+ assertEquals("myorg", md.getModuleRevisionId().getOrganisation());
+ assertEquals("mymodule", md.getModuleRevisionId().getName());
+ assertEquals(Ivy.getWorkingRevision(), md.getModuleRevisionId().getRevision());
+ assertEquals("integration", md.getStatus());
+
+ //verify that the parent description was ignored.
+ assertEquals("", md.getDescription());
+
+ //verify that the parent configurations were ignored.
+ final Configuration[] expectedConfs = { new Configuration("default") };
+ assertNotNull(md.getConfigurations());
+ assertEquals(Arrays.asList(expectedConfs), Arrays
+ .asList(md.getConfigurations()));
+
+ //verify parent dependencies were merged.
+ DependencyDescriptor[] deps = md.getDependencies();
+ assertNotNull(deps);
+ assertEquals(2, deps.length);
+
+ assertEquals(Arrays.asList(new String[]{ "default" }),
+ Arrays.asList(deps[0].getModuleConfigurations()));
+ ModuleRevisionId dep = deps[0].getDependencyRevisionId();
+ assertEquals("myorg", dep.getModuleId().getOrganisation());
+ assertEquals("mymodule1", dep.getModuleId().getName());
+ assertEquals("1.0", dep.getRevision());
+
+ assertEquals(Arrays.asList(new String[]{ "default" }),
+ Arrays.asList(deps[1].getModuleConfigurations()));
+ dep = deps[1].getDependencyRevisionId();
+ assertEquals("myorg", dep.getModuleId().getOrganisation());
+ assertEquals("mymodule2", dep.getModuleId().getName());
+ assertEquals("2.0", dep.getRevision());
+
+ //verify only child publications are present
+ Artifact[] artifacts = md.getAllArtifacts();
+ assertNotNull(artifacts);
+ assertEquals(1, artifacts.length);
+ assertEquals("mymodule", artifacts[0].getName());
+ assertEquals("jar", artifacts[0].getType());
+ }
+
+ public void testExtendsConfigurations() throws Exception {
+ //descriptor specifies that only parent configurations should be included
+ ModuleDescriptor md = XmlModuleDescriptorParser.getInstance().parseDescriptor(settings,
+ getClass().getResource("test-extends-configurations.xml"), true);
+ assertNotNull(md);
+
+ assertEquals("myorg", md.getModuleRevisionId().getOrganisation());
+ assertEquals("mymodule", md.getModuleRevisionId().getName());
+ assertEquals(Ivy.getWorkingRevision(), md.getModuleRevisionId().getRevision());
+ assertEquals("integration", md.getStatus());
+
+ //verify that the parent description was ignored.
+ assertEquals("", md.getDescription());
+
+ //verify that the parent and child configurations were merged together.
+ final Configuration[] expectedConfs = { new Configuration("default"),
+ new Configuration("conf1"), new Configuration("conf2") };
+ assertNotNull(md.getConfigurations());
+ assertEquals(Arrays.asList(expectedConfs), Arrays
+ .asList(md.getConfigurations()));
+
+ //verify parent dependencies were ignored.
+ DependencyDescriptor[] deps = md.getDependencies();
+ assertNotNull(deps);
+ assertEquals(1, deps.length);
+
+ assertEquals(Arrays.asList(new String[]{ "conf1", "conf2" }),
+ Arrays.asList(deps[0].getModuleConfigurations()));
+ ModuleRevisionId dep = deps[0].getDependencyRevisionId();
+ assertEquals("myorg", dep.getModuleId().getOrganisation());
+ assertEquals("mymodule2", dep.getModuleId().getName());
+ assertEquals("2.0", dep.getRevision());
+
+ //verify only child publications are present
+ Artifact[] artifacts = md.getAllArtifacts();
+ assertNotNull(artifacts);
+ assertEquals(1, artifacts.length);
+ assertEquals("mymodule", artifacts[0].getName());
+ assertEquals("jar", artifacts[0].getType());
+ }
+
+ public void testExtendsDescription() throws Exception {
+ //descriptor specifies that only parent description should be included
+ ModuleDescriptor md = XmlModuleDescriptorParser.getInstance().parseDescriptor(settings,
+ getClass().getResource("test-extends-description.xml"), true);
+ assertNotNull(md);
+
+ assertEquals("myorg", md.getModuleRevisionId().getOrganisation());
+ assertEquals("mymodule", md.getModuleRevisionId().getName());
+ assertEquals(Ivy.getWorkingRevision(), md.getModuleRevisionId().getRevision());
+ assertEquals("integration", md.getStatus());
+
+ //verify that the parent description was merged.
+ assertEquals("Parent module description.", md.getDescription());
+
+ //verify that the parent configurations were ignored.
+ final Configuration[] expectedConfs = { new Configuration("default") };
+ assertNotNull(md.getConfigurations());
+ assertEquals(Arrays.asList(expectedConfs), Arrays
+ .asList(md.getConfigurations()));
+
+ //verify parent dependencies were ignored.
+ DependencyDescriptor[] deps = md.getDependencies();
+ assertNotNull(deps);
+ assertEquals(1, deps.length);
+
+ assertEquals(Arrays.asList(new String[]{ "default" }),
+ Arrays.asList(deps[0].getModuleConfigurations()));
+ ModuleRevisionId dep = deps[0].getDependencyRevisionId();
+ assertEquals("myorg", dep.getModuleId().getOrganisation());
+ assertEquals("mymodule2", dep.getModuleId().getName());
+ assertEquals("2.0", dep.getRevision());
+
+ //verify only child publications are present
+ Artifact[] artifacts = md.getAllArtifacts();
+ assertNotNull(artifacts);
+ assertEquals(1, artifacts.length);
+ assertEquals("mymodule", artifacts[0].getName());
+ assertEquals("jar", artifacts[0].getType());
+ }
+
+ public void testExtendsDescriptionWithOverride() throws Exception {
+ //descriptor specifies that only parent description should be included
+ ModuleDescriptor md = XmlModuleDescriptorParser.getInstance().parseDescriptor(settings,
+ getClass().getResource("test-extends-description-override.xml"), true);
+ assertNotNull(md);
+
+ assertEquals("myorg", md.getModuleRevisionId().getOrganisation());
+ assertEquals("mymodule", md.getModuleRevisionId().getName());
+ assertEquals(Ivy.getWorkingRevision(), md.getModuleRevisionId().getRevision());
+ assertEquals("integration", md.getStatus());
+
+ //child description should always be preferred, even if extendType="description"
+ assertEquals("Child description overrides parent.", md.getDescription());
+
+ //verify that the parent configurations were ignored.
+ final Configuration[] expectedConfs = { new Configuration("default") };
+ assertNotNull(md.getConfigurations());
+ assertEquals(Arrays.asList(expectedConfs), Arrays
+ .asList(md.getConfigurations()));
+
+ //verify parent dependencies were ignored.
+ DependencyDescriptor[] deps = md.getDependencies();
+ assertNotNull(deps);
+ assertEquals(1, deps.length);
+
+ assertEquals(Arrays.asList(new String[]{ "default" }),
+ Arrays.asList(deps[0].getModuleConfigurations()));
+ ModuleRevisionId dep = deps[0].getDependencyRevisionId();
+ assertEquals("myorg", dep.getModuleId().getOrganisation());
+ assertEquals("mymodule2", dep.getModuleId().getName());
+ assertEquals("2.0", dep.getRevision());
+
+ //verify only child publications are present
+ Artifact[] artifacts = md.getAllArtifacts();
+ assertNotNull(artifacts);
+ assertEquals(1, artifacts.length);
+ assertEquals("mymodule", artifacts[0].getName());
+ assertEquals("jar", artifacts[0].getType());
+ }
+
+ public void testExtendsMixed() throws Exception {
+ //descriptor specifies that parent configurations and dependencies should be included
+ ModuleDescriptor md = XmlModuleDescriptorParser.getInstance().parseDescriptor(settings,
+ getClass().getResource("test-extends-mixed.xml"), true);
+ assertNotNull(md);
+
+ assertEquals("myorg", md.getModuleRevisionId().getOrganisation());
+ assertEquals("mymodule", md.getModuleRevisionId().getName());
+ assertEquals(Ivy.getWorkingRevision(), md.getModuleRevisionId().getRevision());
+ assertEquals("integration", md.getStatus());
+
+ //verify that the parent description was ignored.
+ assertEquals("", md.getDescription());
+
+ //verify that the parent and child configurations were merged together.
+ final Configuration[] expectedConfs = { new Configuration("default"),
+ new Configuration("conf1"), new Configuration("conf2") };
+ assertNotNull(md.getConfigurations());
+ assertEquals(Arrays.asList(expectedConfs), Arrays
+ .asList(md.getConfigurations()));
+
+ //verify parent and child dependencies were merged together.
+ DependencyDescriptor[] deps = md.getDependencies();
+ assertNotNull(deps);
+ assertEquals(2, deps.length);
+
+ assertEquals(Arrays.asList(new String[]{ "default" }),
+ Arrays.asList(deps[0].getModuleConfigurations()));
+ ModuleRevisionId dep = deps[0].getDependencyRevisionId();
+ assertEquals("myorg", dep.getModuleId().getOrganisation());
+ assertEquals("mymodule1", dep.getModuleId().getName());
+ assertEquals("1.0", dep.getRevision());
+
+ assertEquals(Arrays.asList(new String[]{ "conf1", "conf2" }),
+ Arrays.asList(deps[1].getModuleConfigurations()));
+ dep = deps[1].getDependencyRevisionId();
+ assertEquals("myorg", dep.getModuleId().getOrganisation());
+ assertEquals("mymodule2", dep.getModuleId().getName());
+ assertEquals("2.0", dep.getRevision());
+
+ //verify only child publications are present
+ Artifact[] artifacts = md.getAllArtifacts();
+ assertNotNull(artifacts);
+ assertEquals(1, artifacts.length);
+ assertEquals("mymodule", artifacts[0].getName());
+ assertEquals("jar", artifacts[0].getType());
+ }
+
+ public void testExtendsCached() throws Exception {
+ //configure a resolver to serve the parent descriptor, so that parse succeeds.
+ File resolveRoot = new File("build/tmp/xmlModuleDescriptorTest");
+ assertTrue(resolveRoot.exists() || resolveRoot.mkdirs());
+
+ FileUtil.copy(getClass().getResource("test-extends-parent.xml"),
+ new File(resolveRoot, "myorg/myparent/ivy.xml"), null);
+
+ FileSystemResolver resolver = new FileSystemResolver();
+ resolver.setSettings(settings);
+ resolver.setName("testExtendsCached");
+ resolver.addIvyPattern(resolveRoot.getAbsolutePath()
+ + "/[organisation]/[module]/[artifact].[ext]");
+
+ settings.addResolver(resolver);
+ settings.setDefaultResolver("testExtendsCached");
+
+ //descriptor extends a module without a location="..." attribute, so resolver lookup
+ //must be performed.
+ ModuleDescriptor md = XmlModuleDescriptorParser.getInstance().parseDescriptor(settings,
+ getClass().getResource("test-extends-cached.xml"), true);
+ assertNotNull(md);
+
+ assertEquals("myorg", md.getModuleRevisionId().getOrganisation());
+ assertEquals("mymodule", md.getModuleRevisionId().getName());
+ assertEquals(Ivy.getWorkingRevision(), md.getModuleRevisionId().getRevision());
+ assertEquals("integration", md.getStatus());
+
+ //verify that the parent description was merged.
+ assertEquals("Parent module description.", md.getDescription());
+
+ //verify that the parent and child configurations were merged together.
+ final Configuration[] expectedConfs = { new Configuration("default"),
+ new Configuration("conf1"), new Configuration("conf2") };
+ assertNotNull(md.getConfigurations());
+ assertEquals(Arrays.asList(expectedConfs), Arrays
+ .asList(md.getConfigurations()));
+
+ //verify parent and child dependencies were merged together.
+ DependencyDescriptor[] deps = md.getDependencies();
+ assertNotNull(deps);
+ assertEquals(2, deps.length);
+
+ assertEquals(Arrays.asList(new String[]{ "default" }),
+ Arrays.asList(deps[0].getModuleConfigurations()));
+ ModuleRevisionId dep = deps[0].getDependencyRevisionId();
+ assertEquals("myorg", dep.getModuleId().getOrganisation());
+ assertEquals("mymodule1", dep.getModuleId().getName());
+ assertEquals("1.0", dep.getRevision());
+
+ assertEquals(Arrays.asList(new String[]{ "conf1", "conf2" }),
+ Arrays.asList(deps[1].getModuleConfigurations()));
+ dep = deps[1].getDependencyRevisionId();
+ assertEquals("myorg", dep.getModuleId().getOrganisation());
+ assertEquals("mymodule2", dep.getModuleId().getName());
+ assertEquals("2.0", dep.getRevision());
+
+ //verify only child publications are present
+ Artifact[] artifacts = md.getAllArtifacts();
+ assertNotNull(artifacts);
+ assertEquals(1, artifacts.length);
+ assertEquals("mymodule", artifacts[0].getName());
+ assertEquals("jar", artifacts[0].getType());
+ }
}