Managing multiple Maven versions
Lately I’ve been using Apache Maven 3.0 snapshots to test build compatibility on ServiceMix, Karaf and some of the other projects I work on. I’m also using 2.0.9, 2.0.10, and 2.2.1 to replicate customer environments and build servers, so it gets to be a real pain in the ass to change these around all the time. To make my life easier, this weekend I hacked up a Maven version of the awesome setjdk and defaultjdk commands written by David Blevins for Mac OSX (if you’re on a Mac and not using these scripts, you should be).
This script makes some assumptions about where your Maven versions are and how they are named. First of all, it is assumed that you put all of your Maven installs in the same place. It could be hacked to look in multiple locations, but we’re lazy developers so why the fuss? Second assumption is that you retain the directory naming of the tar.gz or .zip distributions of Maven. These begin with apache-maven-* and that’s how the script finds the versions. I’m building the 3.0-SNAPSHOTs into the same common location so that I can switch between them easily as well.
As a bonus, if you set up your default M2_HOME to point to the symlink “apache-maven” in your $MAVEN_PARENT location, you can change the default Maven version for new terminal instances as well using defaultmvn.
I know there is some room for improvement, but as it is this script works well on Mac OSX as well as Linux, so hopefully someone else can find it useful.
Installation: Click the “copy to clipboard” link in the top right corner and save this as /etc/profile.d/setmvn.sh or just source it into your terminal by some other means. Modify the MAVEN_PARENT to your parent location such as /opt or /usr/local/share, etc.
Usage: The command includes completions, so from your shell just “setmvn <hit tab>” and you should see all of your maven versions. Partial completions work too, so if you are a tab-happy completion-abusing lazy developer like me, this will be right up your alley.
#!/bin/bash
MAVEN_PARENT=/usr/share
function defaultmvn {
local mvndir=$MAVEN_PARENT
local ver=${1?Usage: defaultmvn <version>}
local mvnprefix=apache-maven-
[ -z "$2" ] || error="Too many arguments"
[ -d $mvndir/$mvnprefix$ver ] || local error="Unknown Maven version: $ver"
[ "$(readlink $mvndir/apache-maven)" != "$mvndir/$mvnprefix$ver" ] || local error="Default Maven already set to $ver"
if [ -n "$error" ]; then
echo $error
return 1
fi
echo "Setting default Maven to $ver ... "
if [ "$(/usr/bin/id -u)" != "0" ]; then
SUDO=sudo
fi
$SUDO /bin/rm $mvndir/apache-maven
$SUDO /bin/ln -s $mvndir/$mvnprefix$ver $mvndir/apache-maven
echo Done.
}
function setmvn {
local mvndir=$MAVEN_PARENT
local ver=${1?Usage: setmvn <version>}
local mvnprefix=apache-maven-
[ -d $mvndir/$mvnprefix$ver ] || {
echo Unknown Maven version: $ver
return 1
}
echo "Setting current Maven version to $ver ..."
export M2_HOME=$mvndir/$mvnprefix$ver
PATH=$(echo $PATH | tr ':' '\n' | grep -v $mvndir/$mvnprefix | tr '\n' ':')
export PATH=$M2_HOME/bin:$PATH
mvn -v
}
function _setmvn_completion (){
COMPREPLY=()
local mvndir=$MAVEN_PARENT
local cur=${COMP_WORDS[COMP_CWORD]//\\\\/}
local options=$(cd $mvndir; ls -d -1 apache-maven-* | awk '{match($0,"apache-maven-.*"); print substr($0,14,RLENGTH-13)}' | tr '\n' ' ')
COMPREPLY=($(compgen -W "${options}" ${cur}))
}
complete -F _setmvn_completion -o filenames setmvn
complete -F _setmvn_completion -o filenames defaultmvn
In order to get the defaultmvn part to work, I have the following in my /etc/profile.d/maven.sh file (adjust based on your OS).
M2_HOME=/usr/share/apache-maven PATH=$M2_HOME/bin:$PATH export M2_HOME PATH
So thanks to David Blevins for the still awesome after all these years setjdk script which I completely and unabashedly stole for the basis for the setmvn script.


Nice.. but.. what exactly is not ok with using flat smybolic links ?
At least this works for me for all maven versions ( switch regularly with 2.0.10, 2.2.1 and 3-SNAPSHOT, works perfect)
cheers,
Toni
Mostly because I will regularly have multiple shells open, and need to use different Maven versions at the same time. This way I don’t have any surprises. The symlink approach is fine but it means everything uses that version.
Sure, if you want that, you’ll need something like you did.