Mercurial > public > develkit
comparison 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 |
comparison
equal
deleted
inserted
replaced
88:9f2ab59a5333 | 89:15f4da8bdbd3 |
---|---|
1 | |
2 import groovy.xml.QName; | |
3 import org.codehaus.groovy.runtime.InvokerHelper; | |
4 | |
5 import java.io.OutputStreamWriter; | |
6 import java.io.PrintWriter; | |
7 import java.util.HashMap; | |
8 import java.util.List; | |
9 import java.util.Map; | |
10 | |
11 import groovy.xml.* | |
12 | |
13 //args = [ '-r'] | |
14 println args | |
15 | |
16 ant = new AntBuilder() | |
17 | |
18 | |
19 if (args.any { it.toUpperCase() == '-R'} ) { | |
20 | |
21 new File('.').traverse ([ type: groovy.io.FileType.DIRECTORIES, maxDepth: 3 ]) { project -> | |
22 if (new File(project,'ivy.xml').exists() ) { | |
23 processIvy(new File(project,'ivy.xml')) | |
24 } | |
25 } | |
26 | |
27 } else { | |
28 processIvy(new File('ivy.xml')) | |
29 } | |
30 | |
31 def processIvy(file) { | |
32 println "-" * 60 | |
33 println "processing: $file" | |
34 def xml = new XmlSlurper() | |
35 def ivy = xml.parse(file) | |
36 | |
37 def cfgs = ivy.configurations | |
38 | |
39 // default mapping for most dependencies: | |
40 cfgs.@defaultconfmapping = 'compile->default(*)' | |
41 | |
42 // Add default config, if missing: | |
43 if (!cfgs.children().find { it.@name == 'default' } ) { | |
44 println "adding default config" | |
45 cfgs.appendNode { | |
46 conf(name:"default",extends:'compile',visibility:'public') | |
47 } | |
48 } | |
49 | |
50 if (ivy.dependencies.children().find { it.@name == 'org.springframework.web.servlet' } && | |
51 !ivy.dependencies.children().find { it.@name == 'servlet-api' } ) { | |
52 ivy.dependencies.children().findAll { it.name() == 'dependency' }.list().last() + { | |
53 dependency(name:'servlet-api', org: 'javax.servlet', rev: '2.5') | |
54 dependency(name:'jsp-api', org: 'javax.servlet', rev: '2.0') | |
55 } | |
56 | |
57 } | |
58 | |
59 ivy.dependencies.children().each { dep -> | |
60 if ( dep.@conf.text()?.contains('test') ) { | |
61 dep.@conf = 'compile-test->default(*)' | |
62 } else if ( dep.@conf.text().contains('castor-ant') ) { | |
63 dep.@conf = 'castor-ant->default(*)' | |
64 } | |
65 else { | |
66 dep.attributes().remove('conf') | |
67 } | |
68 } | |
69 | |
70 // find groovy dependencies (or null) | |
71 groovy = ivy.dependencies.children().find { it.@org == 'org.codehaus.groovy' && it.@name.text().startsWith('groovy') } | |
72 | |
73 if (groovy) { | |
74 // Add a groovy conig for groovy projects: | |
75 if (!cfgs.children().any { it.@name == 'groovy' } ) { | |
76 println "added private groovy conf" | |
77 cfgs.appendNode { | |
78 conf(name:'groovy',visibility:'private',transitive: true) | |
79 } | |
80 } | |
81 // Adjust 'compile' to exend from 'groovy' conf | |
82 cfgs.children().find { it.@name == 'compile' }.@extends = 'groovy' | |
83 cfgs.children().find { it.@name == 'groovy' }.@transitive = 'true' | |
84 groovy.@conf = "groovy->default" | |
85 println "Groovy ${groovy.@rev} conf changed to ${groovy.@conf}" | |
86 // Switch project to use groovy-all instead of groovy + deps | |
87 if (groovy.@name == 'groovy') { | |
88 println "changed groovy to groovy-all" | |
89 groovy.@name = 'groovy-all' | |
90 } | |
91 | |
92 def template = new File(file.parent ?: ".",'template.mf') | |
93 if (template.exists()) { | |
94 println "updating groovy in $template" | |
95 ant.replace(file: template, token: 'org.codehaus.groovy-groovy:major',value:'org.codehaus.groovy-groovy-all:major') | |
96 } | |
97 | |
98 } | |
99 | |
100 | |
101 ensure(ivy.dependencies, 'hibernate-validator', ['org.slf4j:slf4j-api:1.5.6','org.slf4j:slf4j-log4j12:1.5.6']) | |
102 | |
103 ensure(ivy.dependencies, 'org.springframework.test', ['junit:junit:4.8.2']) | |
104 | |
105 // remove exclude for groovy-all | |
106 ivy.dependencies.children().find { it.name() == 'exclude' && it.@module.text() == 'groovy-all' }.replaceNode {} | |
107 | |
108 // Add exclude for regular groovy: | |
109 ensureExcluded(ivy.dependencies,"org.codehaus.groovy:groovy") | |
110 | |
111 // ensure modules covered by springsource are exluded; | |
112 ensureSpringSourceExcludes(ivy.dependencies) | |
113 | |
114 ensureConfiguration(ivy.dependencies,'org.springframework.test','compile-test') | |
115 | |
116 //remove bad junit dependencies and excludes | |
117 ivy.dependencies.children().find { it.@org == 'org.junit' && it.@module.text() == 'org.junit' }.replaceNode {} | |
118 ivy.dependencies.children().find { it.@org == 'org.junit' && it.@name.text() == 'org.junit' }.replaceNode {} | |
119 | |
120 | |
121 cfgs.children().each { it.@visibility = 'public' } // Should be 'private' after initial conversions. | |
122 | |
123 cfgs.children().find {it.@name == 'runtime' }.@extends = 'compile' | |
124 cfgs.children().find {it.@name == 'compile-test' }.@extends = 'compile' | |
125 cfgs.children().find {it.@name == 'runtime-test' }.@extends = 'runtime,compile-test' | |
126 cfgs.children().find {it.@name == 'default' }.@visibility = 'public' | |
127 cfgs.children().find {it.@name == 'default' }.@extends = 'runtime' | |
128 | |
129 if (!cfgs.children().any { it.@name == 'archives' } ) { | |
130 println "added public 'archives' conf" | |
131 cfgs.appendNode { | |
132 conf(name:'archives',visibility:'public') | |
133 } | |
134 } | |
135 | |
136 cfgs.children().find {it.@name == 'archives' }.@visibility = 'public' | |
137 | |
138 | |
139 def outputBuilder = new StreamingMarkupBuilder() | |
140 //new File('ivy.xml').write( XmlUtil.serialize( outputBuilder.bind { mkp.yield ivy }).replaceAll('>','>')) | |
141 | |
142 def stringWriter = new StringWriter() | |
143 | |
144 | |
145 def node = new XmlParser().parseText( XmlUtil.serialize( outputBuilder.bind { mkp.yield ivy })) | |
146 new MyNodePrinter(new IndentPrinter( new PrintWriter(stringWriter))).print(node) | |
147 file.write(stringWriter.toString()) | |
148 | |
149 } | |
150 | |
151 def ensureConfiguration(depends,name,cfg) { | |
152 depends.children().findAll { it.name() == 'dependency' && it.@name == name}.each { | |
153 it.@conf = "$cfg->default(*)" | |
154 } | |
155 } | |
156 | |
157 def ensureExcluded(depends,excludeModule) { | |
158 def (o,m) = excludeModule.split(':') | |
159 if (!depends.children().any { it.name() == 'exclude' && it.@module.text() == m}) { | |
160 depends.appendNode { | |
161 println "excluding $o:$m" | |
162 exclude(org: o, module: m) | |
163 } | |
164 } | |
165 } | |
166 | |
167 def ensure(depends,exists,requires) { | |
168 | |
169 if (depends.children().any { it.name() == 'dependency' && it.@name == exists } ) { | |
170 requires.each { | |
171 def (org,name,rev) = it.split(":") | |
172 if (!depends.children().any { it.@name == name } ) { | |
173 println " adding requirement $org:$name for $exists" | |
174 depends.children().findAll { it.name() == 'dependency' }.list().last() + { | |
175 dependency(name: name, org: org, rev: rev) | |
176 } | |
177 } | |
178 } | |
179 } | |
180 } | |
181 | |
182 def ensureSpringSourceExcludes(depends) { | |
183 def exclusions = [] | |
184 depends.children().findAll { it.name() == 'dependency' && it.@name.text().startsWith('com.springsource.') }.each { | |
185 exclusions << "${it.@org}:${it.@name.text() - 'com.springsource.'}" | |
186 } | |
187 exclusions.each { ensureExcluded(depends,it) } | |
188 | |
189 } | |
190 | |
191 /* | |
192 The class below is a copy/paste of groovy's XmlNodePrinter customized to order Ivy.xml attributes in | |
193 the desired order and to add some whitespace. | |
194 */ | |
195 class MyNodePrinter { | |
196 | |
197 protected void printNameAttributes(Map attributes, ctx) { | |
198 | |
199 if (attributes == null || attributes.isEmpty()) { | |
200 return; | |
201 } | |
202 def writer = new StringBuffer() | |
203 attributes.entrySet().sort{ | |
204 switch (it.key ) { | |
205 case 'org': | |
206 1 | |
207 break | |
208 case 'name': 2 | |
209 break | |
210 case 'rev': 3 | |
211 break | |
212 case 'extends': 5 | |
213 break | |
214 default: 99 | |
215 } | |
216 }.each { p -> | |
217 def tmp = new StringBuffer() | |
218 Map.Entry entry = (Map.Entry) p; | |
219 | |
220 tmp << " " | |
221 tmp << getName(entry.getKey()) | |
222 tmp << "=" | |
223 Object value = entry.getValue(); | |
224 tmp << quote | |
225 tmp << value | |
226 // if (value instanceof String) { | |
227 // printEscaped((String) value); | |
228 // } else { | |
229 // printEscaped(InvokerHelper.toString(value)); | |
230 // } | |
231 tmp << quote | |
232 def size = entry.getKey() in ['org','name'] ? 35 : 22 | |
233 writer << String.format(" %-${size}s",tmp.toString()) | |
234 // printNamespace(entry.getKey(), ctx); | |
235 } | |
236 out.print(" " + writer.toString().trim()) | |
237 } | |
238 | |
239 protected final IndentPrinter out; | |
240 private String quote; | |
241 private boolean namespaceAware = true; | |
242 private boolean preserveWhitespace = false; | |
243 | |
244 public MyNodePrinter(PrintWriter out) { | |
245 this(out, " "); | |
246 } | |
247 | |
248 public MyNodePrinter(PrintWriter out, String indent) { | |
249 this(out, indent, "\""); | |
250 } | |
251 | |
252 public MyNodePrinter(PrintWriter out, String indent, String quote) { | |
253 this(new IndentPrinter(out, indent), quote); | |
254 } | |
255 | |
256 public MyNodePrinter(IndentPrinter out) { | |
257 this(out, "\""); | |
258 } | |
259 | |
260 public MyNodePrinter(IndentPrinter out, String quote) { | |
261 if (out == null) { | |
262 throw new IllegalArgumentException("Argument 'IndentPrinter out' must not be null!"); | |
263 } | |
264 this.out = out; | |
265 this.quote = quote; | |
266 } | |
267 | |
268 public MyNodePrinter() { | |
269 this(new PrintWriter(new OutputStreamWriter(System.out))); | |
270 } | |
271 | |
272 public void print(Node node) { | |
273 print(node, new NamespaceContext()); | |
274 } | |
275 | |
276 /** | |
277 * Check if namespace handling is enabled. | |
278 * Defaults to <code>true</code>. | |
279 * | |
280 * @return true if namespace handling is enabled | |
281 */ | |
282 public boolean isNamespaceAware() { | |
283 return namespaceAware; | |
284 } | |
285 | |
286 /** | |
287 * Enable and/or disable namespace handling. | |
288 * | |
289 * @param namespaceAware the new desired value | |
290 */ | |
291 public void setNamespaceAware(boolean namespaceAware) { | |
292 this.namespaceAware = namespaceAware; | |
293 } | |
294 | |
295 /** | |
296 * Check if whitespace preservation is enabled. | |
297 * Defaults to <code>false</code>. | |
298 * | |
299 * @return true if whitespaces are honoured when printing simple text nodes | |
300 */ | |
301 public boolean isPreserveWhitespace() { | |
302 return preserveWhitespace; | |
303 } | |
304 | |
305 /** | |
306 * Enable and/or disable preservation of whitespace. | |
307 * | |
308 * @param preserveWhitespace the new desired value | |
309 */ | |
310 public void setPreserveWhitespace(boolean preserveWhitespace) { | |
311 this.preserveWhitespace = preserveWhitespace; | |
312 } | |
313 | |
314 /** | |
315 * Get Quote to use when printing attributes. | |
316 * | |
317 * @return the quote character | |
318 */ | |
319 public String getQuote() { | |
320 return quote; | |
321 } | |
322 | |
323 /** | |
324 * Set Quote to use when printing attributes. | |
325 * | |
326 * @param quote the quote character | |
327 */ | |
328 public void setQuote(String quote) { | |
329 this.quote = quote; | |
330 } | |
331 | |
332 protected void print(Node node, NamespaceContext ctx) { | |
333 /* | |
334 * Handle empty elements like '<br/>', '<img/> or '<hr noshade="noshade"/>. | |
335 */ | |
336 if (isEmptyElement(node)) { | |
337 printLineBegin(); | |
338 out.print("<"); | |
339 out.print(getName(node)); | |
340 if (ctx != null) { | |
341 printNamespace(node, ctx); | |
342 } | |
343 printNameAttributes(node.attributes(), ctx); | |
344 out.print("/>"); | |
345 printLineEnd(); | |
346 out.flush(); | |
347 return; | |
348 } | |
349 | |
350 /* | |
351 * Hook for extra processing, e.g. GSP tag element! | |
352 */ | |
353 if (printSpecialNode(node)) { | |
354 out.flush(); | |
355 return; | |
356 } | |
357 | |
358 /* | |
359 * Handle normal element like <html> ... </html>. | |
360 */ | |
361 Object value = node.value(); | |
362 if (value instanceof List) { | |
363 printName(node, ctx, true, isListOfSimple((List) value)); | |
364 printList((List) value, ctx); | |
365 printName(node, ctx, false, isListOfSimple((List) value)); | |
366 out.flush(); | |
367 return; | |
368 } | |
369 | |
370 // treat as simple type - probably a String | |
371 printName(node, ctx, true, preserveWhitespace); | |
372 printSimpleItemWithIndent(value); | |
373 printName(node, ctx, false, preserveWhitespace); | |
374 out.flush(); | |
375 } | |
376 | |
377 private boolean isListOfSimple(List value) { | |
378 for (Object p : value) { | |
379 if (p instanceof Node) return false; | |
380 } | |
381 return preserveWhitespace; | |
382 } | |
383 | |
384 protected void printLineBegin() { | |
385 out.printIndent(); | |
386 } | |
387 | |
388 protected void printLineEnd() { | |
389 printLineEnd(null); | |
390 } | |
391 | |
392 protected void printLineEnd(String comment) { | |
393 if (comment != null) { | |
394 out.print(" <!-- "); | |
395 out.print(comment); | |
396 out.print(" -->"); | |
397 } | |
398 out.println(); | |
399 out.flush(); | |
400 } | |
401 | |
402 protected void printList(List list, NamespaceContext ctx) { | |
403 out.incrementIndent(); | |
404 for (Object value : list) { | |
405 NamespaceContext context = new NamespaceContext(ctx); | |
406 /* | |
407 * If the current value is a node, recurse into that node. | |
408 */ | |
409 if (value instanceof Node) { | |
410 print((Node) value, context); | |
411 continue; | |
412 } | |
413 printSimpleItem(value); | |
414 } | |
415 out.decrementIndent(); | |
416 } | |
417 | |
418 protected void printSimpleItem(Object value) { | |
419 if (!preserveWhitespace) printLineBegin(); | |
420 printEscaped(InvokerHelper.toString(value)); | |
421 if (!preserveWhitespace) printLineEnd(); | |
422 } | |
423 | |
424 protected void printName(Node node, NamespaceContext ctx, boolean begin, boolean preserve) { | |
425 if (node == null) { | |
426 throw new NullPointerException("Node must not be null."); | |
427 } | |
428 Object name = node.name(); | |
429 if (name == null) { | |
430 throw new NullPointerException("Name must not be null."); | |
431 } | |
432 if (!preserve || begin) printLineBegin(); | |
433 out.print("<"); | |
434 if (!begin) { | |
435 out.print("/"); | |
436 } | |
437 out.print(getName(node)); | |
438 if (ctx != null) { | |
439 printNamespace(node, ctx); | |
440 } | |
441 if (begin) { | |
442 printNameAttributes(node.attributes(), ctx); | |
443 } | |
444 out.print(">"); | |
445 if (!preserve || !begin) printLineEnd(); | |
446 } | |
447 | |
448 protected boolean printSpecialNode(Node node) { | |
449 return false; | |
450 } | |
451 | |
452 protected void printNamespace(Object object, NamespaceContext ctx) { | |
453 if (namespaceAware) { | |
454 if (object instanceof Node) { | |
455 printNamespace(((Node) object).name(), ctx); | |
456 } else if (object instanceof QName) { | |
457 QName qname = (QName) object; | |
458 String namespaceUri = qname.getNamespaceURI(); | |
459 if (namespaceUri != null) { | |
460 String prefix = qname.getPrefix(); | |
461 if (!ctx.isPrefixRegistered(prefix, namespaceUri)) { | |
462 ctx.registerNamespacePrefix(prefix, namespaceUri); | |
463 out.print(" "); | |
464 out.print("xmlns"); | |
465 if (prefix.length() > 0) { | |
466 out.print(":"); | |
467 out.print(prefix); | |
468 } | |
469 out.print("=" + quote); | |
470 out.print(namespaceUri); | |
471 out.print(quote); | |
472 } | |
473 } | |
474 } | |
475 } | |
476 } | |
477 | |
478 | |
479 | |
480 private boolean isEmptyElement(Node node) { | |
481 if (node == null) { | |
482 throw new IllegalArgumentException("Node must not be null!"); | |
483 } | |
484 if (!node.children().isEmpty()) { | |
485 return false; | |
486 } | |
487 return node.text().length() == 0; | |
488 } | |
489 | |
490 private String getName(Object object) { | |
491 if (object instanceof String) { | |
492 return (String) object; | |
493 } else if (object instanceof QName) { | |
494 QName qname = (QName) object; | |
495 if (!namespaceAware) { | |
496 return qname.getLocalPart(); | |
497 } | |
498 return qname.getQualifiedName(); | |
499 } else if (object instanceof Node) { | |
500 Object name = ((Node) object).name(); | |
501 return getName(name); | |
502 } | |
503 return object.toString(); | |
504 } | |
505 | |
506 private void printSimpleItemWithIndent(Object value) { | |
507 if (!preserveWhitespace) out.incrementIndent(); | |
508 printSimpleItem(value); | |
509 if (!preserveWhitespace) out.decrementIndent(); | |
510 } | |
511 | |
512 // For ' and " we only escape if needed. As far as XML is concerned, | |
513 // we could always escape if we wanted to. | |
514 private void printEscaped(String s) { | |
515 for (int i = 0; i < s.length(); i++) { | |
516 char c = s.charAt(i); | |
517 switch (c) { | |
518 case '<': | |
519 out.print("<"); | |
520 break; | |
521 case '>': | |
522 out.print(">"); | |
523 break; | |
524 case '&': | |
525 out.print("&"); | |
526 break; | |
527 case '\'': | |
528 if (quote.equals("'")) | |
529 out.print("'"); | |
530 else | |
531 out.print(c); | |
532 break; | |
533 case '"': | |
534 if (quote.equals("\"")) | |
535 out.print("""); | |
536 else | |
537 out.print(c); | |
538 break; | |
539 default: | |
540 out.print(c); | |
541 } | |
542 } | |
543 } | |
544 | |
545 protected class NamespaceContext { | |
546 private final Map<String, String> namespaceMap; | |
547 | |
548 public NamespaceContext() { | |
549 namespaceMap = new HashMap<String, String>(); | |
550 } | |
551 | |
552 public NamespaceContext(NamespaceContext context) { | |
553 this(); | |
554 namespaceMap.putAll(context.namespaceMap); | |
555 } | |
556 | |
557 public boolean isPrefixRegistered(String prefix, String uri) { | |
558 return namespaceMap.containsKey(prefix) && namespaceMap.get(prefix).equals(uri); | |
559 } | |
560 | |
561 public void registerNamespacePrefix(String prefix, String uri) { | |
562 if (!isPrefixRegistered(prefix, uri)) { | |
563 namespaceMap.put(prefix, uri); | |
564 } | |
565 } | |
566 | |
567 public String getNamespace(String prefix) { | |
568 Object uri = namespaceMap.get(prefix); | |
569 return (uri == null) ? null : uri.toString(); | |
570 } | |
571 } | |
572 } |