I often use the Maven IntelliJ plugin to create project files (.ipr/.iml/.iws).
A quick:
% maven idea
does the job nicely.
However, when dependencies change, I don’t want to re-run the idea task, as it wacks a lot of project settings that I may have had. What I really want to do is take the current .iml file, and tweak the classpath which has entries such as:
<orderEntry type="module-library"> <library name="asm"> <CLASSES> <root url="jar://C:/Documents and Settings/Dion/.maven/repository/asm/jars/asm-1.4.3.jar!/" /> </CLASSES> <JAVADOC /> <SOURCES /> </library> </orderEntry>
So, I put together a quick groovy script which does just this.
#!/bin/env groovy
# -----------------------------------------------------------------------------
# ideaSync.g: Take a given project.xml and an IntelliJ IDEA .iml file,
# and sync up the dependencies
# -----------------------------------------------------------------------------
import groovy.util.XmlParser
import java.io.File
import java.io.OutputStream
import java.util.*
import org.dom4j.Document
import org.dom4j.io.XMLWriter
import org.dom4j.io.OutputFormat
# -- Enforce the project.xml and dir
if (args.length < 3) {
println """
Usage: ideaSync.g project.xml
.iml /path/to/maven/repo
e.g. ideaSync.g /foo/project.xml /foo/project.iml /www/adigio/maven
"""
System.exit(1)
}
# -- Variables
projectxml = args[0]
intellijxml = args[1]
mavenRepoDir = args[2]
indent = 0
# -- Open up the IntelliJ
.iml file
intellij = new XmlParser().parse(intellijxml)
# -- Open up the project.xml file and get the dependencies, and create an updated XML node
project = new XmlParser().parse(projectxml)
# -- Build the order entries
orderEntries = []
project.dependencies.dependency.each {
groupId = it.groupId[0].text()
artifactId = it.artifactId[0].text()
version = it.version[0].text()
orderEntry = buildOrderEntry(groupId, "jar://${mavenRepoDir}/${groupId}/jars/${artifactId}-${version}.jar!/")
orderEntries += orderEntry
}
# -- Grab Order Entries
intellij.module.component.each { | c |
if (c['@name'] == 'NewModuleRootManager') {
oldOrderEntries = c.findAll { !it.orderEntry }
c = orderEntries
}
}
# -- Print the Header
println ''
outputDOM(intellij)
# -----------------------------------------------------------------------------
# From the given group ID and URL, return an Order Entry node
# -----------------------------------------------------------------------------
def buildOrderEntry(groupId, url) {
# -- Builder
builder = new groovy.util.NodeBuilder()
return builder.orderEntry(type: 'module-library') {
library(name: groupId) {
CLASSES() {
root(url: "jar://${mavenRepoDir}/${groupId}/jars/${artifactId}-${version}.jar!/")
}
JAVADOC()
SOURCES()
}
}
}
# -----------------------------------------------------------------------------
# Recursive function which outputs a node, and then child nodes
# -----------------------------------------------------------------------------
def outputDOM(node) {
String tagName = node.name()
Object tagValue = node.value()
boolean hasChildren = false;
String attributes = ""
printIndent()
print "<${tagName}"
# -- Print out any attributes
node.attributes().each { |entry|
attributes = " ${entry.key}=\"${entry.value}\"" + attributes
}
print attributes
if (tagValue instanceof String) {
println "${tagValue}"
hasChildren = true;
}
List children = node.children()
if (children != null && !children.isEmpty()) {
hasChildren = true
}
println( (hasChildren) ? ">" : " />" )
for (child in children) {
indent++
outputDOM(child)
indent--
}
if (hasChildren) {
printIndent()
println "${tagName}>"
}
}
# -----------------------------------------------------------------------------
# Print out the correct indent
# -----------------------------------------------------------------------------
def printIndent() {
print " " * indent
}
I was hoping that I could use the NodePrinter that is already in Groovy, but it prints out the nodes like foo() { bar(); …. not in XML.
I think it would be good to have an XMLNodePrinter, or just have a toXML() method in the NodePrinter to do that work, as I think this script follows a common pattern:
- Suck in an XML document into nodes
- Munge the nodes in some way
- Print out the new XML document
I would also really like to add this functionality to the maven plugin itself, so I could:
% maven idea:resynciml
or something like that. I think I will wait for m2 though, and see if I can use something other than Jelly for it? ;)
