Save the Wrapper

Evan J B | Apr 12, 2017

TL;DR (Abstract)

Get started with the "wrapper" implementations for maven and gradle projects. Peruse a sample project on github.

Intro

It's hard to get away from dependencies. Even if you properly list all compile and runtime dependencies for your app, you are still dependent on the build tools themselves.

Is maven installed? How about Java?

This is where the wrappers come in!

Fig. Maven and gradle wrappers depicted as the candy they represent. Sweet, sweet build tool independence.

The maven and gradle wrappers provide a simple pair of scripts (along with a jar and properties file) that fetch the dependency managment build tool. These scripts are meant to be part of your project's collective source code now just like the build files.

Usage

Let's apply this to a maven-based project first.

Maven Wrapper

The maven wrapper won't create the pom.xml for you so let's add a simple maven project to test building with the wrapper.

mvn archetype:generate -DgroupId=com.evanjbowling.blog -DartifactId=new-project -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

Now add the maven wrapper:

cd new-project && mvn -N io.takari:maven:wrapper

This will result in the following:

new-project
 └ .mvn/wrapper/maven-wrapper.jar
 └ .mvn/wrapper/maven-wrapper.properties
 └ mvnw
 └ mvnw.cmd
 └ pom.xml
 └ src/

Now test it with:

# Unix users
./mvnw clean compile

# Windows users
mvnw.cmd clean compile

Maven Wrapper in Docker

Our project builds successfully now, but we used a maven installation to run the archetype plugin and create the project in the first place. We can create a simple docker container to create an isolated environment where maven doesn't exist. Create a file called "Dockerfile" in the same directory with the following contents:

FROM openjdk:8

COPY . /usr/src/myapp
WORKDIR /usr/src/myapp

CMD ["./mvnw clean compile"]

Build the docker image with:

docker build -t my-mvnw-app .

Now run the docker container in interactive mode and start a bash shell:

docker run --rm -it my-mvnw-app bash
root@1e2827d18962:/usr/src/myapp# which mvn
# no output proves maven isn't installed

Now run the maven wrapper:

./mvnw clean compile

You should see the following output:

[INFO] Installing /usr/src/myapp/pom.xml to /root/.m2/repository/com/evanjbowling/blog/new-project/1.0-SNAPSHOT/new-project-1.0-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 37.066 s
[INFO] Finished at: 2017-04-08T01:16:26+00:00
[INFO] Final Memory: 18M/121M
[INFO] ------------------------------------------------------------------------

Gradle Wrapper

The maven wrapper above was created by using a plugin. The gradle wrapper is a part of the standard gradle distribution. It can be used with the following command:

gradle init

This creates the following:

new-project
 └ build.gradle
 └ gradle/wrapper/gradle-wrapper.jar
 └ gradle/wrapper/gradle-wrapper.properties
 └ gradlew
 └ gradlew.bat
 └ settings.gradle
 └ src/

Now execute a build:

./gradlew build

Gradle Wrapper in Docker

Let's use the same Dockerfile as before with a new default command:

FROM openjdk:8

COPY . /usr/src/myapp
WORKDIR /usr/src/myapp

CMD ["./gradlew build"]

Build the docker image with:

docker build -t my-gradlew-app .

Once again, let's un the docker container in interactive mode and start a bash shell:

docker run --rm -it my-gradlew-app bash

Now run the gradle wrapper:

root@5cdf9749ef83:/usr/src/myapp# ./gradlew build
------------------------------------------------------------
Root project
------------------------------------------------------------

classpath
No dependencies

BUILD SUCCESSFUL

Total time: 16.159 secs

So how far should this go with our buildchain? A Java wrapper? A docker wrapper? I'm not sure but these two wrappers are a great start. The gradle init method is simple, fast and includes the wrapper by default. Ultimately, this provides a more portable build.

Critiques

References