Pure Danger Tech


Open source frustration

22 Jan 2007

Today was a day of frustration, primarily at the hands of two open source projects: Ant and CruiseControl. I’ve been attempting to set up two things – a sync from Perforce in an Ant build and a CruiseControl continuous integration server.

The Perforce task seems extremely simple in the Ant manual. Should look something like this:

<property name="p4.port" value="host:6999"/>
	<property name="p4.user" value="user"/>
	<property name="p4.client" value="client"/>

	<target name="sync">
		<p4sync view="//depot/path" />		

So I tried it out:

   [p4sync] java.lang.NullPointerException

C:\perforce\dev\alsync\build\build.xml:34: Problem exec'ing P4 command: java.io.
IOException: CreateProcess: p4 -phost:6999 -uuser -cclient -s sync //depot/path error=2

Not good. Got an NPE somewhere. I did get an error message with a command line though, which is a great place to start. So, I made sure that the command worked by itself, which it did. I tried a few other permutations and continued to get the NPE no matter what I tried. I tried using -debug on the Ant run and managed to get a stack trace at least:

at org.apache.tools.ant.taskdefs.optional.perforce.P4Base.execP4Command(P4Base.java:297)
        at org.apache.tools.ant.taskdefs.optional.perforce.P4Sync.execute(P4Sync.java:105)
        at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:288)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:585)
        at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:105)
        at org.apache.tools.ant.Task.perform(Task.java:348)
        at org.apache.tools.ant.Target.execute(Target.java:357)
        at org.apache.tools.ant.Target.performTasks(Target.java:385)
        at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1329)
        at org.apache.tools.ant.Project.executeTarget(Project.java:1298)
        at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
        at org.apache.tools.ant.Project.executeTargets(Project.java:1181)
        at org.apache.tools.ant.Main.runBuild(Main.java:698)
        at org.apache.tools.ant.Main.startAnt(Main.java:199)
        at org.apache.tools.ant.launch.Launcher.run(Launcher.java:257)
        at org.apache.tools.ant.launch.Launcher.main(Launcher.java:104)

So, I headed to the source. The top line is in P4Base, which is basically the base class for all the Perforce tasks, all of which basically just execute a command line to the p4 shell based on your args. The source file shows that the error is coming from the catch block at the very end of the class. If you’re too lazy to look at the code, the pertinent bits looks like this:

try {

            // a gazillion lines of code  

        } catch (Exception e) {
            String failMsg = "Problem exec'ing P4 command: " + e.getMessage();
            if (failOnError) {
                throw new BuildException(failMsg);
            } else {
                log(failMsg, Project.MSG_ERR);

So, we know that given the error message, we’re seeing some kind of IOException. I’d sure kill to see e.printStackTrace() here though to know which of the gazillion lines of code is actually throwing the exception. I can deduce a few things from looking at the code and surely something has gone awry in creating or running the Process but who knows what or where.

My next thought was to reproduce in Eclipse since I could then debug into the code. Unfortunately, it actually worked in Eclipse. Arrghgh.

Examining the source history for P4Base, it said an NPE had been fixed in the recently release Ant 1.7, so I upgraded from Ant 1.6.5 to 1.7, which I’d probably want to do eventually anyways. No dice, same error.

I tried the Google of course, to no avail. At this point, I’m contemplating either patching the code or attaching a debugger. Not sure which is easier yet but I might be too lazy to do either. In any case, I think this is a good lesson in exception handling and logging and how a little more thought could have saved me at least a few hours. In this case, chaining the original exception into the BuildException would have gotten me the whole story, which presumably would help track down the NPE. Of course, I’m sure the code pre-dates exception chaining and just hasn’t been updated but the lesson serves.

CruiseControl was more of just an installation / documentation mess. And I’m sure that all of the good folks working on CC have been trying really hard, but I think the story on how you get the build and web server started up (even in light of the docs targeted at exactly that) is still too confusing. I managed to get the CC instance itself going pretty quickly, but I can’t figure out exactly which env vars should be set, working directories, etc.

On my very first attempt to start CruiseControl, it blew chunks because there was a space in my JAVA_HOME env variable. Never mind that c:\program files is the default install location for the JDK on Windows and many people have it installed there, making this a common use case. Even once I got it going, the built-in Jetty console dumps this scary error message every few seconds saying that the accept timed out. This makes you think you’ve done something horribly wrong, but is actually apparently the normal operation of Jetty based on a bit of searching. Seems like a bad choice for a default message strategy.

Anyhow, I’ll dive back into the fray tomorrow.

UPDATE: For those interested, Stefan Bodewig (an Ant committer) saw my post and had fixed the chained exception by the time I woke up this morning. He was also dead-on in his suggestion that I was missing p4 in my path. I had outsmarted myself in my .cmd file and it was a quick fix to get it running. So, Ant+Perforce is happy. Thank you Stefan!