Build profiles and Sakai dependencies

>In the development of Profile2 I have come to the point where I need the one version of Profile2 to build in all 4 of the current flavours of Sakai: 2.4, 2.5, 2.6 and trunk.

Impossible you say, 2.6 and beyond uses the Kernel whereas 2.5 and lower uses the old set of dependencies!

One would think this task could only be accomplished by making 4 releases tailored to each version. That would be a maintenance nightmare.

The other way would be cutting a release and saying any new developments will only work in the latest versions of Sakai (2.6 and trunk/2.7); i.e. dropping support for 2.4 and potentially 2.5. Being a branch manager for both of those versions, I didn’t like that option either.
The solution I have in place now employs an oft-underused feature in the Sakai world, Maven build profiles. In a nutshell, I have two build profiles that wrap my Sakai dependencies, one for the older style dependencies used in Sakai 2.5, and one for the Kernel dependencies used in 2.6 and beyond. Any other dependencies go in a normal dependencies block.
Here’s an example:
<dependencies>
<!-- EXTERNAL DEPENDENCIES -->
<dependency>
<groupId>org.apache.wicket</groupId>
<artifactId>wicket</artifactId>
</dependency>
<dependency>
<groupId>org.apache.wicket</groupId>
<artifactId>wicket-extensions</artifactId>
</dependency>
<dependency>
<groupId>org.apache.wicket</groupId>
<artifactId>wicket-spring</artifactId>
</dependency>

<!-- GENERIC SAKAI DEPENDENCIES -->
<dependency>
<groupId>org.sakaiproject</groupId>
<artifactId>sakai-common-edu-person-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.sakaiproject</groupId>
<artifactId>sakai-common-manager-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.sakaiproject</groupId>
<artifactId>sakai-common-type-api</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>

<profiles>
<profile>
<id>pre-K1</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<!-- SAKAI 2.5.X SPECIFIC DEPENDENCIES -->
<dependencies>
<dependency>
<groupId>org.sakaiproject</groupId>
<artifactId>sakai-tool-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.sakaiproject</groupId>
<artifactId>sakai-user-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.sakaiproject</groupId>
<artifactId>sakai-authz-api</artifactId>
<scope>provided</scope>
</dependency>
....
</dependencies>
</profile>
<profile>
<id>K1</id>
<!-- SAKAI 2.6+ SPECIFIC DEPENDENCIES -->
<dependencies>
<dependency>
<groupId>org.sakaiproject.kernel</groupId>
<artifactId>sakai-kernel-api</artifactId>
</dependency>
<dependency>
<groupId>org.sakaiproject.kernel</groupId>
<artifactId>sakai-component-manager</artifactId>
</dependency>
...
</dependencies>
</profile>
</profiles>
Something like that would go in your POM’s wherever you had to bind to any Sakai specific core dependencies.
Since I am building for 2.5 mainly, I have set the activeByDefault flag to true for that profile, so building on 2.5 is unaffected. To build on 2.6/trunk you just add -P K1 to your mvn command to choose the K1 build profile, like so:
mvn clean install sakai:deploy -P K1
Maven will use the right profile block to find it’s dependencies and ignore the other one. And thats it, I’ve got one tool building in both 2.5 and 2.6/trunk.
Ideally, I’d like for the activation of these profiles to be available via reading which version of Sakai we are building against.
Something like:
<profiles>
<profile>
<id>pre-K1</id>
<activation>
<property>
<name>sakai.version</name>
<value>[2.5.0,2.5.4)</value>
</property>
</activation>
<dependencies />
</profile>
<profile>
<id>K1</id>
<activation>
<property>
<name>sakai.version</name>
<value>[2.6.0,2.7)</value>
</property>
</activation>
<dependencies />
</profile>
</profiles>
But unfortunately that is not possible as Maven only reads properties explicitly set on the commandline to activate profiles via -Dproperty=value. Since it’s less work to just specify which profile we want via -P K1, that is the option I’ve chosen for now.
Finally, the 2.4 support is achieved via backporting the pom.xml to project.xml for Maven1 to use. See my last post about backporting Maven2 to Maven1.

Backporting Maven2 to Maven1

I was recently tasked with backporting a project that builds in Maven 2 to Maven 1 (odd I know). It was a nightmare of a job.

You get so used to Maven 2 pulling in all the dependencies it needs (transitive dependencies) and doing all the work for you (building the Java source) that you forget how tedious it used to be. ie specifying all of the jars that you need, and all the dependent jars that those jars need.

Anyway, I finally finished it, but with the help of a simple Maven2 command:

mvn dependency:tree

which produces the following tree of all your dependencies and dependencies of those dependencies:

Certainly helps tracking down any missing dependencies in your project.xml

Visualising a software project

Something I came across recently and thought was really neat is an app called CodeSwarm. In a nutshell, it shows the history of commits in a software project, day by day and as cool organic images.
Here’s an example of what it produces:

This is a snapshot in time of the Eclipse project.

I was originally alerted to this by Chuck on a sakai-dev posting where some of his students made a video. I decided to make my own and it was refreshingly simple:

svn co http://codeswarm.googlecode.com/svn/trunk/ codeswarmcd codeswarmant run

Enter the repository URL, a few seconds later it’s done and playing onscreen. You can also get it to dump out images and then assemble them into a video with a soothing backing track like many others have done.

Try it out!