Introduction

Sonatype has released a nifty utility called Maven Shell that allows developers to execute maven goals/phases in a pre-loaded shell environment, significantly reducing the build time. It does this by loading up a JVM, Maven, and any loaded plugin once and leverages that existing load for each subsequent build. I downloaded the .10 binary and played around with it with a very simple multi-module project. Here is a quick primer on some of the things you can expect from Maven Shell.

Efficiency

I used a simple mult-module JEE project shell that's mostly void of code and unit tests to test out efficiency. Because some of the overhead associated with a build is loading numerous plugins, I wanted to run this build at least one time before I started comparing it to a build outside of Maven Shell. My first build ran as such, taking 7.420 seconds:

[INFO] ----------------------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] parent Multi Project .............................................. SUCCESS [1.088s]
[INFO] Util Project ...................................................... SUCCESS [3.292s]
[INFO] beans JEE5 EJB .................................................... SUCCESS [0.830s]
[INFO] web JEE5 Webapp ................................................... SUCCESS [0.807s]
[INFO] app JEE5 Assembly ................................................. SUCCESS [1.123s]
[INFO]
[INFO] ----------------------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ----------------------------------------------------------------------------------------
[INFO] Total time: 7.420s
[INFO] Finished at: Tue Mar 23 13:46:19 EDT 2010
[INFO] Final Memory: 16M/79M
[INFO] ----------------------------------------------------------------------------------------

The subsequent build took 3.519 seconds:

INFO] ----------------------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] parent Multi Project .............................................. SUCCESS [0.264s]
[INFO] Util Project ...................................................... SUCCESS [1.569s]
[INFO] beans JEE5 EJB .................................................... SUCCESS [0.404s]
[INFO] web JEE5 Webapp ................................................... SUCCESS [0.509s]
[INFO] app JEE5 Assembly ................................................. SUCCESS [0.673s]
[INFO]
[INFO] ----------------------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ----------------------------------------------------------------------------------------
[INFO] Total time: 3.519s
[INFO] Finished at: Tue Mar 23 13:58:24 EDT 2010
[INFO] Final Memory: 25M/79M
[INFO] ----------------------------------------------------------------------------------------

Great, but how does this compare to running maven via the command line outside of Maven Shell? Running outside of Maven Shell, the build took 7.085 seconds:

[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] parent Multi Project .............................. SUCCESS [1.024s]
[INFO] Util Project ...................................... SUCCESS [3.787s]
[INFO] beans JEE5 EJB .................................... SUCCESS [0.341s]
[INFO] web JEE5 Webapp ................................... SUCCESS [1.029s]
[INFO] app JEE5 Assembly ................................. SUCCESS [0.691s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 7.085s
[INFO] Finished at: Tue Mar 23 13:59:43 EDT 2010
[INFO] Final Memory: 13M/79M
[INFO] ------------------------------------------------------------------------

That's about a decrease of ~4 seconds execution time for this very simple build, with hardly any plugins loaded. I'd imagine multi-module builds with numerous plugins executed in Maven Shell would see an exponential decrease in time to finish.

Note: After completion of this blog, I downloaded the source for Maven Shell 0.11 SNAPSHOT and built that using the .10 Maven Shell binary, to test these efficiency increases on an actual project with real source and real plugin inclusions. I had even better results. The initial mvnsh clean install took ~23 seconds, each subsequent clean install took ~13 seconds and the standard command line build took about ~20 seconds. That's a savings of about ~7 seconds on every build!

Navigation

Maven Shell provides a bash-esque shell for navigation and binary execution, at least on my Mac; I imagine it would be the same on Linux distros (Windows?). You navigate as you would in a regular shell, using the cd command. The command prompt will look something similar to this :

mvnsh(/logging/logger):~/Projects/fyb_maven_workspace/multi-example>

The mvnsh prefix helps identify to the user they are in the Maven Shell environment. The value in the parenthesis identifies which command group the user is currently in. Currently we are in the /logging/logger command group. We'll cover command groups in a subsequent section. After the command group and colon, the current location in our file system is identified. In our example, we are in the ~/Projects/fyb_maven_workspace/multi-exampledirectory.

Executing a Command

Executing a command is as easy as it is in the bash shell, simple type the name of the command and any parameters and press return. Changing a directory:

mvnsh(/):~/Projects/fyb_maven_workspace/multi-example> cd ..
mvnsh(/):~/Projects/fyb_maven_workspace>

Help

Typing help or ? and pressing return will provide the help menu. The help menu will identify all the commands available to the user. To receive help on a specific command, type help . For example, to receive help on rm, type help rm and the user will be provided with a man page on the rm command.

Something very important to know is that help is command group aware. If the current command group is /pref, not only will you see all the default commands available, you will be presented with the commands available to the pref command group.

Here is the root(/) help listing:

mvnsh(/):~/Projects/fyb_maven_workspace/multi-example> help
Available pages:
 . Alias to: source
 ? Alias to: help
 alias Define an alias or list defined aliases.
 archetype Command group: archetype
 cd Changes the current directory.
 dir Alias to: ls
 echo Print arguments to standard output.
 encrypt-password Encrypt passwords.
 exit Exit the current shell.
 help Display help pages.
 history Display history.
 hostname Displays the name of the current host.
 info Display information about the shell and environment.
 install-jna Alias to: source /Developer/Applications/mvnsh-0.10/scripts/install-jna.msh
 logging Command group: logging
 ls List the contents of a file or directory.
 mkdir Create a directory.
 mvn Execute Maven.
 nexus Command group: nexus
 pref Command group: pref
 pwd Displays the current directory.
 recall Recall an item from history.
 rm Remove a file.
 rmdir Remove a directory.
 set Set a variable or property.
 shell-env Shell environment variables overview.
 shell-files Shell configuration files overview.
 shell-navigation Shell navigation overview.
 shell-syntax Shell syntax overview.
 source Execute commands from a source into the current shell.
 unalias Undefine an alias.
 unset Unset a variable or property.
 wget Fetch a file from a URL.

And the help listing from within the /pref command group:

mvnsh(/pref):~/Projects/fyb_maven_workspace/multi-example> help
Available pages:
 . Alias to: source
 ? Alias to: help
 alias Define an alias or list defined aliases.
 archetype Command group: archetype
 cd Changes the current directory.
 dir Alias to: ls
 echo Print arguments to standard output.
 encrypt-password Encrypt passwords.
 exit Exit the current shell.
 export Export preferences.
 get Get a preference.
 help Display help pages.
 history Display history.
 hostname Displays the name of the current host.
 import Import preferences.
 info Display information about the shell and environment.
 install-jna Alias to: source /Developer/Applications/mvnsh-0.10/scripts/install-jna.msh
 list List preferences.
 logging Command group: logging
 ls List the contents of a file or directory.
 mkdir Create a directory.
 mvn Execute Maven.
 nexus Command group: nexus
 pref Command group: pref
 pwd Displays the current directory.
 recall Recall an item from history.
 remove Remove preferences.
 rm Remove a file.
 rmdir Remove a directory.
 set Set a preference.
 shell-env Shell environment variables overview.
 shell-files Shell configuration files overview.
 shell-navigation Shell navigation overview.
 shell-syntax Shell syntax overview.
 source Execute commands from a source into the current shell.
 unalias Undefine an alias.
 unset Unset a preference.
 wget Fetch a file from a URL.

Notice the addition of the list, set, get, unset, remove, import, and export commands.

Command Groups

Command groups are a logical way of grouping like commands together, in a hierarchical fashion. It allows for easy execution of specific commands within a command group. For example, the /logging/logger command group has the following commands:

mvnsh(/logging):~/Projects/fyb_maven_workspace/multi-example> help logger
Help pages in group logger:
 set Set the level of a logger.
 list List loggers.
 levels List valid logger levels.

If we are in the /logging/logger command group, we can execute the levels command to print out the list of logging levels available to the Maven reactor during a build:

mvnsh(/logging/logger):~/Projects/fyb_maven_workspace/multi-example> levels
TRACE
DEBUG
INFO
WARN
ERROR
OFF

You can execute a command no matter where you are in the command group hierarchy if you specify it's full path, ie printing logger levels from within the /pref command group.:

mvnsh(/pref):~/Projects/fyb_maven_workspace/multi-example> /logging/logger/levels
TRACE
DEBUG
INFO
WARN
ERROR
OFF

Features

There is a laundry list of features on the Maven Shell wiki site, look for a subsequent blog on these features in detail.

Conclusion

If you're a developer using Maven and do a lot of your interaction with Maven from the command line, I highly recommend taking a look at Maven Shell. It'll shave precious time from builds allowing you to accomplish more in your day all the while providing for a nice interface for interacting with Maven. Keep in mind, it won't speed up unit tests, plugin execution, etc, but will remove the overhead associated with loading these items every launch.

References