Jan 05

Syncing up your IntelliJ IML files with Maven and Groovy

Builds, Groovy, Tech No Comments »

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 ""
}
}

# -----------------------------------------------------------------------------
#  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? ;)

Jan 05

Syncing up your IntelliJ IML files with Maven and Groovy

Builds, Groovy, Tech No Comments »

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 ""
}
}

# -----------------------------------------------------------------------------
#  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? ;)

Dec 07

Maven 1.0.2

Builds, Tech 5 Comments »

Yeah, I know it is a point release, but I am glad that Maven 1.0.2 is released as 1.0.1 wasn’t grabbing dependencies for me (which is fixed by “Fail on 403 response to dependency download (and also anything > = 400) Fixes MAVEN-1502.”).

The Apache Maven team is pleased to announce the release of Maven 1.0.2.

http://maven.apache.org/start/download.html

This release contains further bugfixes since the Maven 1.0 release. In addition, all of the latest stable plugin releases are included, which include both bugfixes and some new features.

We recommend that all users upgrade to this release, in particular those using pre-1.0 betas or release candidates.

Maven is a project management and project comprehension tool. Maven is based
on the concept of a project object model: builds, documentation creation, site
publication, and distribution publication are all controlled from the project
object model. Maven also provides tools to create source metrics, change logs
based directly on source repository, and source cross-references.

To see a list of changes to Maven, please refer to the Changes Report, or the brief summary below:

  • [MAVEN-1428] – “Response content length not known”
  • [MAVEN-1501] – maven seems not to evaluate .properties of parent pom
  • [MAVEN-1502] – Build doesn’t fail when dependency can’t be downloaded due to wrong permissions
  • [MAVEN-1507] – Fails on IBM 1.3 JDK
  • [MAVEN-1511] – Jar override does not work when trying to override to SNAPSHOT
  • [MAVEN-1518] – Wrong behaviour for non existing overwritten dependency

Please note that each plugin has its own changes report – please refer to the plugins site to see the plugin you are interested in.

We hope you enjoy using Maven! If you have any questions, please consult:

For news and information, see:

- The Apache Maven Team

Dec 01

Groovy mavenisms again: Building a lib dir from dependencies

Builds, Groovy, Tech 1 Comment »

To follow on in the same vein as my last post, I also have had the need now and then to take my maven world, and build a lib directory snapshot of my projects dependencies to pass on to others.

This was used with people not using maven, and for awhile for my IDE to point too (although now I can % maven idea). The only annoying part of maven idea is that it whipes your config each time, and you can’t share the project as the files are all absolute to your own personal maven repo.

Maven Jar Builder

#!/bin/env groovy
# -----------------------------------------------------------------------------
# maven2jar.g: Take a given project.xml and build a directory with jar files
# -----------------------------------------------------------------------------

import groovy.util.XmlParser
import java.io.*
import java.nio.channels.*

# -- Enforce the project.xml and dir
if (args.length < 1) {
println """
Usage: maven2jar.g project.xml [newdir]

e.g. maven2jar.g /foo/project.xml tempdir (defaults to .)
"""
System.exit(1)
}

# -- Variables
projectxml   = args[0]
todir        = (args.length > 1) ? args[1] : ".";
badFiles     = []
mavenLocalRepository = System.getProperty("user.home") + "/.maven/repository"

# -- Open up the file and do the work
project = new XmlParser().parse(projectxml)

project.dependencies.dependency.each {
groupId    = it.groupId[0].text()
artifactId = it.artifactId[0].text()
version    = it.version[0].text()

fromFileName = "${mavenLocalRepository}/${groupId}/jars/${artifactId}-${version}.jar"
toFileName   = "${todir}/${artifactId}-${version}.jar"

println "-----------------------------------------------------------------------"
println " Copying From: ${fromFileName}"
println " Copying To  : ${toFileName}"

try {
copyFile(new File(fromFileName), new File(toFileName))
} catch (Exception e) {
println "Error: Could not copy: ${e}"
}
}

# -- Define the function to copy the files
def copyFile(inFile, outFile) {
FileChannel sourceChannel = new FileInputStream(inFile).getChannel()
FileChannel destinationChannel = new FileOutputStream(outFile).getChannel()
sourceChannel.transferTo(0, sourceChannel.size(), destinationChannel)
sourceChannel.close()
destinationChannel.close()
}
Nov 30

Checking my maven repository with Groovy

Builds, Groovy, Tech 8 Comments »

I am finding myself grabbing Groovy rather than Perl for some of those small scripting tasks that you run into.

One I ran into recently revolved around my maven repository.

We setup our own Maven repo (we don’t want to keep hitting the poor ibiblio site!), and whenever we add dependencies, we grab the files from ibiblio and put them in our own repo.

However, it is easy to forget, so I whipped up a script that will check the dependencies in our project.xml and make sure those files exist in the repo, else it will shout at me to do the move.

It would also be cool to have it automatically do the copy itself!

I really like how you can whip through XML

Groovy Maven Script

#!/bin/env groovy
# -----------------------------------------------------------------------------
# mavenTestRepository.g: Take a given project.xml and a Maven repo, shout out
#                        which files are there, and which are not
# -----------------------------------------------------------------------------

import groovy.util.XmlParser
import java.io.File

# -- Enforce the project.xml and dir
if (args.length < 2) {
println """
Usage: mavenTestRepository.g project.xml mavenRepoDir

e.g. mavenTestRepository.g /foo/project.xml /www/adigio/maven
"""
System.exit(1)
}

# -- Variables
projectxml   = args[0]
mavenRepoDir = args[1]
badFiles     = []

# -- Open up the file and do the work
project = new XmlParser().parse(projectxml)

project.dependencies.dependency.each {
groupId    = it.groupId[0].text()
artifactId = it.artifactId[0].text()
version    = it.version[0].text()

println "-----------------------------------------------------------------------"
println " Group ID    : ${groupId}"
println "  Artifact ID: ${artifactId}"
println "  Version    : ${version}"

boolean fileExists = true
try {
new File("${mavenRepoDir}/${groupId}/jars/${artifactId}-${version}.jar").eachLine { }
} catch (Exception e) {
fileExists = false
}

if (fileExists) {
println "Good: File exists in repo"
} else {
badFiles += ["${groupId}: ${artifactId}-${version}"]
println "Bad: File DOES NOT exist in repo"
}
}

# -- Print out the bad ones
if (badFiles.size() > 0) {
println "\n-----------------------------------------------------------------------"
println "Dependencies not in the repository:\n"
badFiles.each { println it }
}
Nov 22

Handling Dependencies: A generation tool, or something smarter in Maven

Builds, Java, Tech 5 Comments »

How long does it take to setup your Maven >dependency<’s for a project that uses a lot of open source?

You find yourself following a chain of “X needs Y…” as you keep adding your dependencies.

What would be nice is to be able to write a script that takes high level tools (e.g. Spring) and builds the dependencies for all of the sub projects.

What would be even cooler is to have maven give it a go. You could say “I want Spring version X”, and maven will download all of the items that Spring needs automagically.

No more following the breadcrumbs.

Aug 30

Sick of Ant? Not ready for Maven? How about Java::Build

Builds, Java, Tech No Comments »

There is definately a group of people that are a bit sick of Ant. This is a general “I don’t want to code in XML” problem too. Some are making the leap to Maven, with all of its b# builds. Others are just going back to the basics.

Philip Crow has just added Java::Build to CPAN.

He writes:

“Java/Build version 0.01
=====================

In my shop, we grew tired of using Ant for builds. We wanted to script,
and as the O’Reilly book on the subject points out at length, Ant is not
a scripting language. We wanted variables, loops, conditionals, and
subroutines, to name a few things. Eventually we decided to move to a
Perl based build system. This is the result of that work.

Ant provides one essential feature:

It uses only one JVM

In our builds, this issue is only important for compiling. All of the
other tasks are uncommon enough that starting a new JVM for each one is
not prohibitively expensive. (It is possible to add to Java::Build::JVM to
use its JVM for additional tasks, but we haven’t needed to yet.)

By using Java::Build::JVM, you get one JVM which you can keep using
for compilation throughout your script.

Java::Build::Tasks provides some useful helper functions. None of them
are essential, but they seem to make our scripts easier to write and more
consistent. The tasks currently include: jar, signjar, read_prop_file,
update_prop_file, build_file_list, and what_needs_compiling (the later uses
time stamps to decide which class files are missing or stale).”