/*---[ Problem ]---*/
This week I was faced with the need to write a Groovy script that would run on a Hadoop node at work, but we don't yet have groovy installed on the Hadoop nodes (and I don't have privileges to do that). Since Groovy is our defined scripting language, I had two options in the meantime:
- Download the groovy zip package, just unzip it in my user directory on the Hadoop node and run my thing.
- Compile the groovy script to bytecode and build an uber-jar with groovy in it and then run it like a Java program (with
java -cp myjar.jar blah blah blah
).
/*---[ Solution ]---*/
Since the second sounded like more of a challenge and would teach me a few things I hadn't done yet, I picked that. It worked out - here's my cheat sheet for future reference.
/*---[ Quoth the Maven ]---*/
Create a new maven project:
mvn archetype:generate -DarchetypeArtifactId=maven-archetype-quickstart \
-DinteractiveMode=false -DgroupId=net.thornydev -DartifactId=script
/*---[ Two plugins ]---*/
To compile groovy to bytecode use the groovy-eclipse-compiler plugin. Yes, I know that sounds weird, but you don't need to fire up Eclipse. You don't even need to have Eclipse installed.
To build the uberjar having your compiled script and all of groovy, use the maven-shade-plugin. Like most things about maven, I find name "shade-plugin" irritating, but it gets the job done.
Finally include groovy-all.jar as a dependency.
Here's my pom:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>net.thornydev</groupId> <artifactId>script</artifactId> <packaging>jar</packaging> <version>1.0</version> <name>script</name> <url>http://maven.apache.org</url> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <compilerId>groovy-eclipse-compiler</compilerId> </configuration> <dependencies> <dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy-eclipse-compiler</artifactId> <version>2.7.0-01</version> </dependency> </dependencies> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>2.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> </execution> </executions> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy-all</artifactId> <version>2.0.7</version> </dependency> </dependencies> </project>
/*---[ Treat groovy like a first class citizen ]---*/
Put your groovy file(s) in the src/main/java
directory, not src/main/groovy
like that other Groovy compiler tool wants.
The directory structure:
$ tree
.
├── pom.xml
└── src
├── main
│ └── java
│ └── net
│ └── thornydev
│ └── GroovyApp.groovy
The Groovy code:
package net.thornydev; class Script { def main(args) { println "Hello ${args[0]}. I'm groovy." } } new Script().main(args)
/*---[ Package, push, run ]---*/
Next: mvn clean package
Then scp the script-1.0.jar
in the target dir to your desired system and run it:
$ java -cp script-1.0.jar net.thornydev.GroovyApp thornydev
Hello thornydev. I'm groovy.
QED.
You can make your jar file self-executable (allowing you to just type "java -jar script-1.0.jar thornydev") by adding the Main-Class attribute to your jar manifest with the value net.thornydev.GroovyApp. Looking at the docs for the shade plugin, it appears they even have an option for it - http://maven.apache.org/plugins/maven-shade-plugin/examples/executable-jar.html
ReplyDeleteGood point. I have made executable jars in the past, but never with the shade plugin. Thanks for the tip.
DeleteAnother, much nicer option, is to use Gradle shadow plugin (a conceptual port of the Maven shade plugin) - https://github.com/johnrengelman/shadow
ReplyDelete