Mercurial > public > develkit
view fixivy.groovy @ 89:15f4da8bdbd3
add ability to control order of attributes, whitespace. more cleanup up of dependencies and exclusions
author | smith@nwoca.org |
---|---|
date | Fri, 17 Feb 2012 15:09:35 +0000 |
parents | fix-ivy.groovy@9f2ab59a5333 |
children | c207cdcaf13e |
line wrap: on
line source
import groovy.xml.QName; import org.codehaus.groovy.runtime.InvokerHelper; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.util.HashMap; import java.util.List; import java.util.Map; import groovy.xml.* //args = [ '-r'] println args ant = new AntBuilder() if (args.any { it.toUpperCase() == '-R'} ) { new File('.').traverse ([ type: groovy.io.FileType.DIRECTORIES, maxDepth: 3 ]) { project -> if (new File(project,'ivy.xml').exists() ) { processIvy(new File(project,'ivy.xml')) } } } else { processIvy(new File('ivy.xml')) } def processIvy(file) { println "-" * 60 println "processing: $file" def xml = new XmlSlurper() def ivy = xml.parse(file) def cfgs = ivy.configurations // default mapping for most dependencies: cfgs.@defaultconfmapping = 'compile->default(*)' // Add default config, if missing: if (!cfgs.children().find { it.@name == 'default' } ) { println "adding default config" cfgs.appendNode { conf(name:"default",extends:'compile',visibility:'public') } } if (ivy.dependencies.children().find { it.@name == 'org.springframework.web.servlet' } && !ivy.dependencies.children().find { it.@name == 'servlet-api' } ) { ivy.dependencies.children().findAll { it.name() == 'dependency' }.list().last() + { dependency(name:'servlet-api', org: 'javax.servlet', rev: '2.5') dependency(name:'jsp-api', org: 'javax.servlet', rev: '2.0') } } ivy.dependencies.children().each { dep -> if ( dep.@conf.text()?.contains('test') ) { dep.@conf = 'compile-test->default(*)' } else if ( dep.@conf.text().contains('castor-ant') ) { dep.@conf = 'castor-ant->default(*)' } else { dep.attributes().remove('conf') } } // find groovy dependencies (or null) groovy = ivy.dependencies.children().find { it.@org == 'org.codehaus.groovy' && it.@name.text().startsWith('groovy') } if (groovy) { // Add a groovy conig for groovy projects: if (!cfgs.children().any { it.@name == 'groovy' } ) { println "added private groovy conf" cfgs.appendNode { conf(name:'groovy',visibility:'private',transitive: true) } } // Adjust 'compile' to exend from 'groovy' conf cfgs.children().find { it.@name == 'compile' }.@extends = 'groovy' cfgs.children().find { it.@name == 'groovy' }.@transitive = 'true' groovy.@conf = "groovy->default" println "Groovy ${groovy.@rev} conf changed to ${groovy.@conf}" // Switch project to use groovy-all instead of groovy + deps if (groovy.@name == 'groovy') { println "changed groovy to groovy-all" groovy.@name = 'groovy-all' } def template = new File(file.parent ?: ".",'template.mf') if (template.exists()) { println "updating groovy in $template" ant.replace(file: template, token: 'org.codehaus.groovy-groovy:major',value:'org.codehaus.groovy-groovy-all:major') } } ensure(ivy.dependencies, 'hibernate-validator', ['org.slf4j:slf4j-api:1.5.6','org.slf4j:slf4j-log4j12:1.5.6']) ensure(ivy.dependencies, 'org.springframework.test', ['junit:junit:4.8.2']) // remove exclude for groovy-all ivy.dependencies.children().find { it.name() == 'exclude' && it.@module.text() == 'groovy-all' }.replaceNode {} // Add exclude for regular groovy: ensureExcluded(ivy.dependencies,"org.codehaus.groovy:groovy") // ensure modules covered by springsource are exluded; ensureSpringSourceExcludes(ivy.dependencies) ensureConfiguration(ivy.dependencies,'org.springframework.test','compile-test') //remove bad junit dependencies and excludes ivy.dependencies.children().find { it.@org == 'org.junit' && it.@module.text() == 'org.junit' }.replaceNode {} ivy.dependencies.children().find { it.@org == 'org.junit' && it.@name.text() == 'org.junit' }.replaceNode {} cfgs.children().each { it.@visibility = 'public' } // Should be 'private' after initial conversions. cfgs.children().find {it.@name == 'runtime' }.@extends = 'compile' cfgs.children().find {it.@name == 'compile-test' }.@extends = 'compile' cfgs.children().find {it.@name == 'runtime-test' }.@extends = 'runtime,compile-test' cfgs.children().find {it.@name == 'default' }.@visibility = 'public' cfgs.children().find {it.@name == 'default' }.@extends = 'runtime' if (!cfgs.children().any { it.@name == 'archives' } ) { println "added public 'archives' conf" cfgs.appendNode { conf(name:'archives',visibility:'public') } } cfgs.children().find {it.@name == 'archives' }.@visibility = 'public' def outputBuilder = new StreamingMarkupBuilder() //new File('ivy.xml').write( XmlUtil.serialize( outputBuilder.bind { mkp.yield ivy }).replaceAll('>','>')) def stringWriter = new StringWriter() def node = new XmlParser().parseText( XmlUtil.serialize( outputBuilder.bind { mkp.yield ivy })) new MyNodePrinter(new IndentPrinter( new PrintWriter(stringWriter))).print(node) file.write(stringWriter.toString()) } def ensureConfiguration(depends,name,cfg) { depends.children().findAll { it.name() == 'dependency' && it.@name == name}.each { it.@conf = "$cfg->default(*)" } } def ensureExcluded(depends,excludeModule) { def (o,m) = excludeModule.split(':') if (!depends.children().any { it.name() == 'exclude' && it.@module.text() == m}) { depends.appendNode { println "excluding $o:$m" exclude(org: o, module: m) } } } def ensure(depends,exists,requires) { if (depends.children().any { it.name() == 'dependency' && it.@name == exists } ) { requires.each { def (org,name,rev) = it.split(":") if (!depends.children().any { it.@name == name } ) { println " adding requirement $org:$name for $exists" depends.children().findAll { it.name() == 'dependency' }.list().last() + { dependency(name: name, org: org, rev: rev) } } } } } def ensureSpringSourceExcludes(depends) { def exclusions = [] depends.children().findAll { it.name() == 'dependency' && it.@name.text().startsWith('com.springsource.') }.each { exclusions << "${it.@org}:${it.@name.text() - 'com.springsource.'}" } exclusions.each { ensureExcluded(depends,it) } } /* The class below is a copy/paste of groovy's XmlNodePrinter customized to order Ivy.xml attributes in the desired order and to add some whitespace. */ class MyNodePrinter { protected void printNameAttributes(Map attributes, ctx) { if (attributes == null || attributes.isEmpty()) { return; } def writer = new StringBuffer() attributes.entrySet().sort{ switch (it.key ) { case 'org': 1 break case 'name': 2 break case 'rev': 3 break case 'extends': 5 break default: 99 } }.each { p -> def tmp = new StringBuffer() Map.Entry entry = (Map.Entry) p; tmp << " " tmp << getName(entry.getKey()) tmp << "=" Object value = entry.getValue(); tmp << quote tmp << value // if (value instanceof String) { // printEscaped((String) value); // } else { // printEscaped(InvokerHelper.toString(value)); // } tmp << quote def size = entry.getKey() in ['org','name'] ? 35 : 22 writer << String.format(" %-${size}s",tmp.toString()) // printNamespace(entry.getKey(), ctx); } out.print(" " + writer.toString().trim()) } protected final IndentPrinter out; private String quote; private boolean namespaceAware = true; private boolean preserveWhitespace = false; public MyNodePrinter(PrintWriter out) { this(out, " "); } public MyNodePrinter(PrintWriter out, String indent) { this(out, indent, "\""); } public MyNodePrinter(PrintWriter out, String indent, String quote) { this(new IndentPrinter(out, indent), quote); } public MyNodePrinter(IndentPrinter out) { this(out, "\""); } public MyNodePrinter(IndentPrinter out, String quote) { if (out == null) { throw new IllegalArgumentException("Argument 'IndentPrinter out' must not be null!"); } this.out = out; this.quote = quote; } public MyNodePrinter() { this(new PrintWriter(new OutputStreamWriter(System.out))); } public void print(Node node) { print(node, new NamespaceContext()); } /** * Check if namespace handling is enabled. * Defaults to <code>true</code>. * * @return true if namespace handling is enabled */ public boolean isNamespaceAware() { return namespaceAware; } /** * Enable and/or disable namespace handling. * * @param namespaceAware the new desired value */ public void setNamespaceAware(boolean namespaceAware) { this.namespaceAware = namespaceAware; } /** * Check if whitespace preservation is enabled. * Defaults to <code>false</code>. * * @return true if whitespaces are honoured when printing simple text nodes */ public boolean isPreserveWhitespace() { return preserveWhitespace; } /** * Enable and/or disable preservation of whitespace. * * @param preserveWhitespace the new desired value */ public void setPreserveWhitespace(boolean preserveWhitespace) { this.preserveWhitespace = preserveWhitespace; } /** * Get Quote to use when printing attributes. * * @return the quote character */ public String getQuote() { return quote; } /** * Set Quote to use when printing attributes. * * @param quote the quote character */ public void setQuote(String quote) { this.quote = quote; } protected void print(Node node, NamespaceContext ctx) { /* * Handle empty elements like '<br/>', '<img/> or '<hr noshade="noshade"/>. */ if (isEmptyElement(node)) { printLineBegin(); out.print("<"); out.print(getName(node)); if (ctx != null) { printNamespace(node, ctx); } printNameAttributes(node.attributes(), ctx); out.print("/>"); printLineEnd(); out.flush(); return; } /* * Hook for extra processing, e.g. GSP tag element! */ if (printSpecialNode(node)) { out.flush(); return; } /* * Handle normal element like <html> ... </html>. */ Object value = node.value(); if (value instanceof List) { printName(node, ctx, true, isListOfSimple((List) value)); printList((List) value, ctx); printName(node, ctx, false, isListOfSimple((List) value)); out.flush(); return; } // treat as simple type - probably a String printName(node, ctx, true, preserveWhitespace); printSimpleItemWithIndent(value); printName(node, ctx, false, preserveWhitespace); out.flush(); } private boolean isListOfSimple(List value) { for (Object p : value) { if (p instanceof Node) return false; } return preserveWhitespace; } protected void printLineBegin() { out.printIndent(); } protected void printLineEnd() { printLineEnd(null); } protected void printLineEnd(String comment) { if (comment != null) { out.print(" <!-- "); out.print(comment); out.print(" -->"); } out.println(); out.flush(); } protected void printList(List list, NamespaceContext ctx) { out.incrementIndent(); for (Object value : list) { NamespaceContext context = new NamespaceContext(ctx); /* * If the current value is a node, recurse into that node. */ if (value instanceof Node) { print((Node) value, context); continue; } printSimpleItem(value); } out.decrementIndent(); } protected void printSimpleItem(Object value) { if (!preserveWhitespace) printLineBegin(); printEscaped(InvokerHelper.toString(value)); if (!preserveWhitespace) printLineEnd(); } protected void printName(Node node, NamespaceContext ctx, boolean begin, boolean preserve) { if (node == null) { throw new NullPointerException("Node must not be null."); } Object name = node.name(); if (name == null) { throw new NullPointerException("Name must not be null."); } if (!preserve || begin) printLineBegin(); out.print("<"); if (!begin) { out.print("/"); } out.print(getName(node)); if (ctx != null) { printNamespace(node, ctx); } if (begin) { printNameAttributes(node.attributes(), ctx); } out.print(">"); if (!preserve || !begin) printLineEnd(); } protected boolean printSpecialNode(Node node) { return false; } protected void printNamespace(Object object, NamespaceContext ctx) { if (namespaceAware) { if (object instanceof Node) { printNamespace(((Node) object).name(), ctx); } else if (object instanceof QName) { QName qname = (QName) object; String namespaceUri = qname.getNamespaceURI(); if (namespaceUri != null) { String prefix = qname.getPrefix(); if (!ctx.isPrefixRegistered(prefix, namespaceUri)) { ctx.registerNamespacePrefix(prefix, namespaceUri); out.print(" "); out.print("xmlns"); if (prefix.length() > 0) { out.print(":"); out.print(prefix); } out.print("=" + quote); out.print(namespaceUri); out.print(quote); } } } } } private boolean isEmptyElement(Node node) { if (node == null) { throw new IllegalArgumentException("Node must not be null!"); } if (!node.children().isEmpty()) { return false; } return node.text().length() == 0; } private String getName(Object object) { if (object instanceof String) { return (String) object; } else if (object instanceof QName) { QName qname = (QName) object; if (!namespaceAware) { return qname.getLocalPart(); } return qname.getQualifiedName(); } else if (object instanceof Node) { Object name = ((Node) object).name(); return getName(name); } return object.toString(); } private void printSimpleItemWithIndent(Object value) { if (!preserveWhitespace) out.incrementIndent(); printSimpleItem(value); if (!preserveWhitespace) out.decrementIndent(); } // For ' and " we only escape if needed. As far as XML is concerned, // we could always escape if we wanted to. private void printEscaped(String s) { for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); switch (c) { case '<': out.print("<"); break; case '>': out.print(">"); break; case '&': out.print("&"); break; case '\'': if (quote.equals("'")) out.print("'"); else out.print(c); break; case '"': if (quote.equals("\"")) out.print("""); else out.print(c); break; default: out.print(c); } } } protected class NamespaceContext { private final Map<String, String> namespaceMap; public NamespaceContext() { namespaceMap = new HashMap<String, String>(); } public NamespaceContext(NamespaceContext context) { this(); namespaceMap.putAll(context.namespaceMap); } public boolean isPrefixRegistered(String prefix, String uri) { return namespaceMap.containsKey(prefix) && namespaceMap.get(prefix).equals(uri); } public void registerNamespacePrefix(String prefix, String uri) { if (!isPrefixRegistered(prefix, uri)) { namespaceMap.put(prefix, uri); } } public String getNamespace(String prefix) { Object uri = namespaceMap.get(prefix); return (uri == null) ? null : uri.toString(); } } }