Cmvn is a helper tool for developers targeted at the Java Virtual Machine (JVM). Its main focus is to declaratively describe and configure the required development and build environment.
A most significant difference between existing Java-targeted build systems compared to those for C/C++ (e.g. Autotools + GNU Make, CMake, Scons) is the lack of a defined configuration step before executing the compiler. Although building a Java application is a lot more easy compared to platform dependent programming languages and tools, nevertheless a lot of the (configuration) tasks of those other build systems are still required. Often the lack of a configuration process in Java build systems results in very obscure setups.
A very popular build system for Java is Apache Maven, currently in version 3. It partially helps the developer with managing her dependencies but fails miserably at producing reliable builds, at least without support of a complex build infrastructure (…like a Repository Manager).
Cmvn tries to close this gap by providing a configuration step before the actual build system. Concrete, this goal will be reached by generating the build scripts for the underlying (native) build system. Whenever a configuration has changed Cmvn will first regenerate the build scripts and after that executes the underlying build system with the right (configured) settings. To assist the developer but do not stay in his way, Cmvn does not aim to replace existing build chains. Instead, its main focus is adding another (first) configuration step to the build chain to create more reliable and reproducable build environments.
In its first release Cmvn supports Apache Maven 2.0 and above although using Apache Maven 3.0 is highly recommended.
In later releases, support for various other build chains might be added, e.g. Apache Ant + Ivy, SBT, SBuild, or others.
Although Cmvn generates the build scripts (in Maven case: pom.xml
files) it cannot and it does not want to handle all aspects of the underlying build infrastructure.
To leave the full power to the developer, Cmvn supports templates for the underlying build scripts for those settings Cmvn can not generate.
But for common project setup, this is rarely needed.
Besides the configuration concept, Cmvn brings you concise and maintainable build scripts and empowers you (again) to understand and control your buildsystem! E.g. the cmvn.conf
equivalent of the pom.xml
in the "Maven in 5 Minutes" tutorial looks like this:
project: com.mycompany.app:my-app:1.0-SNAPSHOT;packaging=jar
test: junit:junit:4.8.2
New features in Cmvn 0.2.0:
-
A new POM converter was added to easily convert existing Maven projects to Cmvn. See <xref linkend="sec:convertPom" />
-
Cmvn can now generate
<reporting>
-blocks. -
Cmvn can now generate
parent
-blocks. -
New execution mode
--info
to gather various project information, e.g. root project location, variables, … -
Support for repository layout setting.
Changes in Cmvn 0.2.0
-
Setting
-generateConfigClass
was renamed togenerateConfigClass
-
Setting
requireCmvn
was renamed to-requireCmvn
-
Internally, Cmvn uses now the CmdOption toolkit to parse commandlines.
-
Inproved up-to-date detection which should now detect all relevant changes in input files.
-
Dependencies, that only differ in its
type
property are no longer swallowed. -
Plugin dependencies now support excludes.
-
various internal changes and improvements.
Cmvn can be run in different execution modes. The main modes are:
-
Configuration (
--configure
,--reconfigure
) -
Build (
--build
) -
Cleanup (
--clean
,--distclean
) -
Convert POM (
--convert-pom
) -
Information (
--info
)
The execution mode is given as (first) parameter when executing Cmvn.
Simplest Example:
shell> cmvn --configure
Just generates the needed build scripts (if needed) of the underlying buildsystem.
For Maven this generates a pom.xml
and a Maven settings file .cmvn/settings.xml
in a local hidden directory.
For a complete list of options see the built-in commandline help: cmvn --configure --help
.
Whenever an input file of Cmvn changed, Cmvn will detect the change at the next execution time and will automatically run a --reconfigure
before further processing.
However, if there is for some reason the need to disable this automatism, you can add the --no-auto-reconfigure
option when configuring the project. If Cmvn detects, that some input files changed, it will claim, that it is out-ouf-date and needs reconfiguration and stop any further processing.
To reconfigure, one can use the option --reconfigure
which does exactly the same as --configure
except that the concrete initial configuration is preserved, thus only the files were recreated without changing the current configuration.
shell> cmvn --reconfigure
By default, cmvn --configure
initally created an new project-local Maven settings file and thus uses a project-local repository.
This is intended to isolate projects from each other while still maintaining project-interoperability via (remotely) released dependencies.
This default way enables the developer to easily build branches without fearing of interferences and inconsistencies caused by multiple projects (branches) that are installing (in the Maven sense) to the same local repository.
Of course, the newly created repository and Maven settings file is shared between all sub projects of the one you just configured.
In case, this default behavior is not desired, you can tell Cmvn to use an alternative existing Maven settings file with the option --maven-settings
.
In this case, you could loose the benefits of side-effect free development of multiple project on the same computer.
Also this may limit the reproducability of the build process in different environments.
shell> cmvn --configure --maven-settings /home/user/.m2/settings.xml
Notice, that if you use an alternative Maven settings file, Cmvn will not touch this file and the Local Maven Repository when running in cleanup execution mode.
If all you want is to reuse an existing Maven local repository, you can use the --maven-repo
option.
shell> cmvn --configure --maven-repo /home/user/.m2/repository
The --maven-repo
option is preferred over --maven-settings
as you do not get the potential side effects from the external settings file. As these settings are normally not part of the build environment (e.g. not managed by a version control system), they increase the risk to get non-repoducable builds and build failures.
When Cmvn detects the presence of a file pom.xml.cmvn
it will use it as template when generating the pom.xml file for Maven.
Cmvn will first read the template file and afterward extend it with the settings found in cmvn.conf
.
You can use this to easily migrate existing Maven projects or if you need complex setups and Maven features (like <profile>
).
Maven Example: Clean project build and install the build jar file into the local Maven repository.
shell> cmvn --build clean install
The build execution mode is automatically enabled if no other mode was requested and at least one non-option argument was given to Cmvn. So the example above could also be written as:
shell> cmvn clean install
The execution mode cleanup is used to remove all generated files and the configuration data.
Currently there are two variants to enable the cleanup mode: one version enabled with --clean
removes only the generated native build scripts, the other variant --distclean
cleans also the configuration state and any other generated environment setup, e.g. a hidden project local Maven repository.
shell> cmvn --clean
Cleans up all generated native build scripts.
shell> cmvn --distclean
Cleans up all generated files including configured state.
To easily use Cmvn with existing Maven projects, one can use the built-in pom.xml
converter.
shell> cmvn --convert-pom --dry-run
This command will show you how the conversion result looks like. If issues are detected, e.g. unresolvable versions for plugins, a warning will be shown.
To convert a whole multi-project recursive, execute the following:
shell> cmvn --convert-pom --recursive
For more options see the built-in commandline help: cmvn --convert-pom --help
The config file has a very simplistic human readable and editable format:
-
empty lines were ignored
-
the hash sign (
#
) starts a comment until end of line -
each non-comment line consists of a pair of key and value delimited by a colon (
:
) -
keys starting with a hyphen (
-
) are directives all other keys were settings -
values may have options, in which case options are separated by a semicolon (
;
) -
value-options are themselves key-value pairs delimited by equal sign (
=
) -
if an option-value is ommitted (an option without an equal sign) it is evaluated to
true
-
non-comment lines ending with a backslash (
\
) were continued on the next line
The following is an example project config file cmvn.conf
:
# Include directive
-include: ../common/cmvncommon.conf
# Immutable variable directive
-val: EXAMPLE_VERSION=0.0.1
# project settings using a variable
# cmvn uses a short syntax for projects and dependencies
# group:artifact:version (GAV) or org:name:rev
project: de.tototec:de.tototec.example:$${EXAMPLE_VERSION}
# a dependency with option spreading two lines
compile: de.tototec:de.tototec.example.utils:$${EXAMPLE_VERSION}; \
classifier=jdk15
# compile-scope dependency
compile: org.slf4j:slf4j-api:1.6.1
# optional runtime-dependency
runtime: ch.qos.logback:logback-classic:0.9.26;optional
# test-scope dependency
test: org.testng:testng:5.14.6
The following sections contain tables that use the following keywords in the format column:
Format | Description |
---|---|
BOOLEAN |
A boolean value: "true" or "false" |
DIR |
A directory in the local file system |
FILE |
A file in the local file system |
GAV |
groupId:_artifactId_:_version_ (analog to Maven) or org:_name_:_rev_ (analog to Ivy) |
GA |
Same as GAV, but without a version |
LIST[X] |
A semicolon delimited list of X (if ommitted, than text) |
OPTION |
A key=value pair |
TEXT |
Text |
URL |
A URL |
VERSION |
A version number |
XML |
A XML fragement |
Directives are instructions to Cmvn to do something special.
Directive | Format | Description |
---|---|---|
|
LIST[OPTION] |
Deprecated. See |
|
FILE |
Include the content of the given file. The content will be treated as if it was in the actual file. |
|
VERSION |
Ensure, that the version of the executing Cmvn executable is at least the given version. |
|
OPTION |
Create an immutable variable key with content value. All occurences of this variable were expanded in the value-part of all succeeding lines (except |
Settings are used to generate the underlying (native) build scripts. Currently the only supported buildsystem is Maven 2 or greater.
Setting | Format | Description |
---|---|---|
|
URL[;OPTION]* |
Alias for |
|
GAV[;OPTION]* |
Alias for |
|
LIST[OPTION] |
Generate a Java class as source code containing static methods. |
|
GAV[;OPTION]* |
A project/package dependency |
|
GAV[;OPTION]* |
Managed dependency in |
|
LIST[OPTION] |
List of options to generate a |
|
GA |
Exclude the given dependency in transitive dependencies. Will generate exclusion-blocks in any dependency-block. |
|
DIR[;OPTION]* |
The path of a sub project |
plugin |
GAV[;OPTION]* |
Maven plugin coordinates |
|
URL[;OPTION]* |
Alias for |
|
GAV[;OPTION]* |
Project coordinates |
|
OPTION |
Definition of property key with value value |
|
GAV[;OPTION]* |
Alias for |
|
URL[;OPTION]* |
Alias for |
|
URL[;OPTION]* |
Maven Repository |
|
GAV[;OPTION]* |
Alias for |
|
GAV[;OPTION]* |
Alias for |
|
GAV[;OPTION]* |
Alias for |
Essential project information mandatory for Maven.
Format: GAV[;OPTION]*
Options:
project
Option | Format | Description |
---|---|---|
|
TEXT |
The packaging of the project, if omitted, then |
Example:
# using maven-bundle-plugin
project: org.example:org.example.osgibundle:1.0.0;packaging=bundle
Definition of a sub project.
Format: DIR[;OPTION]*
Options:
module
Option | Format | Description |
---|---|---|
|
BOOLEAN |
This sub project is a pure Maven project. Do not try to find a |
Example:
module: org.example.domain
module: org.example.service
module: org.example.service.impl.legacy;skipCmvn
A dependency referencing a project in a Maven repository (in most cases a *.jar
file).
Format: GAV[;OPTION]*
Options:
module
Option | Format | Description |
---|---|---|
|
TEXT |
The scope of the dependency. One of |
|
FILE |
The local file path to the jar file. Only valid if |
|
TEXT |
The classifier, e.g. |
|
TEXT |
The type. |
|
BOOLEAN |
An optional dependency is not optional for the current project but will be ignored in a transitive dependency resolution. (In an ideal world any compile time dependency should be optional!) |
|
GA |
Excluded dependency from transitive resolved dependency tree. |
|
BOOLEAN |
Additionally the dependency will be added to the |
Aliases:
dependency
Alias | Description |
---|---|
|
A dependency with option |
|
A dependency with option |
|
A dependency with option |
|
A dependency with option |
|
A managed dependency only in |
|
A dependency with option |
Example:
compile: org.slf4j:slf4j-api:1.6.1;optional
compile: org.slf4j:jcl-over-slf4j:1.6.1;optional;forceversion
test: org.testng:testng:6.0.1
Define a property in a <properties>
-block.
Format: OPTION
Example:
property: maven.compiler.source=1.6
property: maven.compiler.target=1.6
property: project.build.sourceEncoding=UTF-8
A remote Maven repository used to download dependencies.
Format: URL[;OPTION]*
Options:
repository
Option | Format | Description |
---|---|---|
|
TEXT |
The repository ID. |
|
TEXT |
The repository layout, e.g. "default", "p2". |
|
BOOLEAN |
Can be used to download Maven plugins (default: |
|
BOOLEAN |
Can be used to download Maven artifacts (default: |
|
BOOLEAN |
Can be used to download released dependencies. |
|
BOOLEAN |
Can be used to download snapshot dependencies. |
Aliases:
repository
Alias | Description |
---|---|
|
Same as |
|
A repository with option |
|
A repository with option |
A Maven plugin contribution to the Maven lifecycle.
Format: GAV[;OPTION]*
Options: Any option has the format OPTION and is added to the <configuration>
-block of the plugin definition.
Directives:
plugin
Directive | Format | Description |
---|---|---|
|
BOOLEAN |
Specify if this plugin is an extensions-plugin (and thus e.g. can contribute new project packaging types). |
|
XML |
A free XML fragement that will be placed inside the |
|
GAV[;OPTION]* |
A dependency used when executing the plugin command, e.g. to override a version. |
|
XML |
Can be used if the option-value is XML and not text. |
Options:
plugin
Option | Format | Description |
---|---|---|
|
GA |
Excluded dependency from transitive resolved dependency tree. |
Example:
plugin: org.apache.maven.plugins:maven-assembly-plugin:2.2-beta-5; \
appendAssemblyId=false; \
-xml:descriptorRefs= \
<descriptorRef>jar-with-dependencies</descriptorRef>; \
-xml:archive= \
<manifest> \
<mainClass>org.example.Main</mainClass> \
</manifest>
Redefine some project default settings.
Format: LIST[OPTION]
Options:
build
Option | Format | Description |
---|---|---|
|
DIR |
The directory containing the source files. |
|
DIR |
The directory containing the test source files. |
|
FILE |
The name of the final build JAR file. |
|
DIR |
The directory containing the build output files (e.g. |
Generate a .classpath
file which can be used by Eclipse to generate the project classpath container.
Format: LIST[OPTION]
Options:
eclipseClasspath
Option | Format | Description |
---|---|---|
|
TEXT |
Auto-generate lib-entries for project dependencies of the given scope. Supported scopes are: compile (includes provided and system), test, runtime. |
|
BOOLEAN |
Generate an optional-marker for the actual entry. |
key |
TEXT |
A free key added as attribute in the classpathentry-element. Known supported attributes are, e.g.: kind, path, output, sourcepath, … |
Example:
Multiple given eclipseClasspath settings to configure a Java 6 project with tests.
eclipseClasspath: kind=src;path=src/main/java
eclipseClasspath: kind=src;path=src/main/resources
eclipseClasspath: kind=output;path=target/classes
eclipseClasspath: kind=src;output=target/test-classes;path=src/test/java
eclipseClasspath: kind=con;path=org.eclipse.jdt.launching.JRE_CONTAINER/\
org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6
eclipseClasspath: autoGenerate=compile
eclipseClasspath: autoGenerate=test
This Feature is deprecated and superceeded by the Eclipse Classpath Container for Cmvn.
Since Cmvn 0.1.8 there is an Eclipse Cmvn Plugin that provides a classpath container, thus making the use of other classpath containers like the Maven classpath container obsolete.
Features:
-
Provides classpath dependencies instantly
-
non-transitive classpath, only add explicit listed dependencies to classpath
-
different resolution scopes configurable (compile, runtime, test)
-
very fast (especially a lot faster than Maven and Ivy classpath containers)
-
Workspace resolution for dependencies (configurable)
-
uses project-local configuration (uses exact same repositories and dependencies as the command line tool)
-
supports attached sources and javadoc
Restrictions in Cmvn 0.1.8 (might be fixed in later versions):
-
If cmvn was configured with
--maven-settings
the Cmvn classpath container will fall back to aM2_REPO
variable, which must be defined in Eclipse. In most cases you should prefer the--maven-repo
commandline switch to specify external local Maven repositories.
Notice: If you use the Eclipse Cmvn classpath container, you usually do not want to use the eclipseClasspath autoGenerate
setting.
Cmvn is published under the Apache License, Version 2.0.
Cmvn is distributed as executable jar including all its required dependencies.
For convenience, you may want to create a simple shell script cmvn
as an executable wrapper around the program:
#!/bin/sh
# pass all arguments to cmvn with $@
exec java -jar cmvn-executable-0.2.1.jar "$@"
Since Cmvn 0.1.4 there is also a released Windows binary version cmvn-0.1.4.exe
. As long as this executable exists on the search path (PATH
-variable), no command shell wrapper is needed.
If you can not or want not use the executable binary version of Cmvn for Windows, you can alternatively use a command shell wrapper like this one:
:init
@REM Decide how to startup depending on the version of windows
@REM -- Windows NT with Novell Login
if "%OS%"=="WINNT" goto WinNTNovell
@REM -- Win98ME
if NOT "%OS%"=="Windows_NT" goto Win9xArg
:WinNTNovell
@REM -- 4NT shell
if "%@eval[2+2]" == "4" goto 4NTArgs
@REM -- Regular WinNT shell
set CMVN_CMD_LINE_ARGS=%*
goto endInit
@REM The 4NT Shell from jp software
:4NTArgs
set CMVN_CMD_LINE_ARGS=%$
goto endInit
:Win9xArg
@REM Slurp the command line arguments. This loop allows for an unlimited number
@REM of agruments (up to the command line limit, anyway).
set CMVN_CMD_LINE_ARGS=
:Win9xApp
if %1a==a goto endInit
set CMVN_CMD_LINE_ARGS=%CMVN_CMD_LINE_ARGS% %1
shift
goto Win9xApp
@REM Reaching here means variables are defined and arguments have been captured
:endInit
SET CMVN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
%CMVN_JAVA_EXE% -jar cmvn-executable.jar %CMVN_CMD_LINE_ARGS%
set CMVN_JAVA_EXE=
set CMVN_CMD_LINE_ARGS=