Sunday, December 16, 2007

Using Maven for Bash Script Projects

I recently created a Maven project unlike any I have ever created. This project contained no Java sources! No it was not a Groovy project ;) It was a project that contained only bash scripts. Read up for the why and the how.

I created a set of bash scripts that allow invoking SOAP services, returning the XML response. The SOAP services provide information on email distribution lists, such as which addresses are on a list and which lists a user's email address is subscribed to. These scripts are likely to change and grow over time so I made sure to put them into Subversion. Not too shabby. But what about distributing the scripts? What about managing versions of the scripts? I have become accustomed to having the aforementioned handled in my projects via Maven. Maven makes such things simple to set up and automate. I determined I could move these bash scripts into a Maven project to cultivate these benefits.

Now the how. For packaging I use the Maven assembly plugin. It allows created automated creation of zip tar.gz and gzip archives. These archives work great work distributing a project. I started my work by creating a skeleton Maven project. I put the scripts and related files into the src/main/scripts folder of the project. Next I created a xml file used by the assembly plugin to direct how files will be structured in the created compressed archive or archives. Here my file:

<?xml version="1.0"?>
<assembly>
<id>zimbrascripts</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<outputDirectory>hacksdb/lib</outputDirectory>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>src/main/scriptapp/bin</directory>
<outputDirectory>zimbrascripts/bin</outputDirectory>
<fileMode>0755</fileMode>
<directoryMode>0755</directoryMode>
</fileSet>
<fileSet>
<directory>src/main/scriptapp/etc</directory>
<outputDirectory>zimbrascripts/etc</outputDirectory>
<fileMode>0644</fileMode>
<directoryMode>0755</directoryMode>
</fileSet>
<fileSet>
<directory>src/main/scriptapp/tokens</directory>
<outputDirectory>zimbrascripts/tokens</outputDirectory>
<fileMode>0600</fileMode>
<directoryMode>0777</directoryMode>
</fileSet>
<fileSet>
<directory>src/main/scriptapp/xml</directory>
<outputDirectory>zimbrascripts/xml</outputDirectory>
<fileMode>0644</fileMode>
<directoryMode>0755</directoryMode>
</fileSet>
</fileSets>
<files>
<file>
<source>src/main/scriptapp/README.txt</source>
<outputDirectory>zimbrascripts</outputDirectory>
</file>
</files>
</assembly>

I'll write up a more thorough article on using the assembly plugin later. For now suffice to say this file will instruct Maven to create a zip archive containing the files listed above. The last thing we want to do is configure the assembly plugin in the project's POM file. I used the following XML in my projects pom:

<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>src/main/assembly/assembly.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make</id>
<phase>package</phase>
<goals>
<goal>assembly</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

In the above config I also bind the assembly goal to the package phase. This means when I execute "mvn package" the assembly plugin will fire off and create the zip archive. Nice! Otherwise you can also use "mvn assembly:assembly" should do the job. Now so that I could use the scm and release plugins to check in changes to SVN and create tagged releases of the project I added the following to the POM:

<scm>
<connection>scm:svn:https://svn.com/DistributionLists/DistListScriptsMaven/trunk/</connection>
<developerConnection>scm:svn:https://svn.com/DistributionLists/DistListScriptsMaven/trunk/</developerConnection>
<url>https://svn.com/DistributionLists/DistListScriptsMaven/</url>
</scm>

Now to release the current version of the project I can type "mvn release:prepare". This will tag the current version in SVN, then update the POM to the new version number and check those changes into the SVN trunk. This saves me the hassle and reduces the chances of user error in this boring, repetitive process. In the vein of the SCM configuration you could now use other plugins such as the JIRA reporting plugin, site plugin etc. to bolster this simple bash script project.