caiorss / build-fat-jar

Unix Shell Script to build java/Scala fat-jars and make the distributions and deployment of Scala applications easier.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

jar-tools.sh - Unix Shell Script to build java/Scala fat-jars

jart-tools.sh

Overview

jart-tools is a Unix shell script to build fat-jars from scala applications It means build a single and self-contained jar file with the underlying application, all dependencies and scala runt-time libraries.

Motivation: It makes the distribution of java and scala libraries easier as the user only needs to run $ java -jar application.jar or double click at the application.jar file. The developer also doesn’t need to build any shell script to run the jar file.

Benefits:

  • Inspect jar files.
  • Bundle a java/scala application with all its dependencies.
  • Make the deployment and distribution easy and simple.
  • Run Scala application in a machine without Scala installed.
  • Run a Scala/java application with a simple double click.

Install

Just copy the script jart-tools.sh to any directory listed in the $PATH variable.

No dependencies are required. It only needs java and scala available.

Download it:

cd ~/bin
$ curl -O -L https://github.com/caiorss/jart-tools/raw/master/jar-tools.sh
$ chmod +x jar-tools.sh

$ ./jar-tools.sh

Usage and Examples

Show user help

  • ./jart-tools.sh
$ jar-tools.sh 
Build fat jar. Tool like one-jar to build java fat jar.

Options:

 + Show information about Scala libraries.

    * ./jar-tools.sh -scala-lib

 + Run an application compiled with Scala using its runtime.

   * ./jar-tools.sh -scala-run scalaApp.jar

 + Start scala repl loading all *.jar files in classpath from ./lib

   * ./jar-tools.sh -scala-repl

 + Build a fat jar for a Scala application. out/output-jar.jar. The
 main-jar file contains the main class.

   * ./jar-tools.sh -scala-build-jar out/output-jar.jar main-jar.jar lib/dependency1.jar lib/dependency2.jar


 + Display manifest of a jar file.

   * ./jar-tools.sh -jar-mainifest file.jar

 + Display main class of a jar file.

   * ./jar-tools.sh -jar-main file.jar

 + View contents of a jar file

   * ./jar-tools.sh -jar-view file.jar

 + Make a self-executable jar-file.sh out of jar-file.jar 
   that can be run as ./jar-file.sh instead of '$ java -jar jar-file.jar.'

   * ./jar-tools.sh -jar-to-sh file.jar

 + Makes a self-executable jar file with .sh extension out of a scala
   compiled jar file. It assumes that scala is instaled in the target machine. 
   The generated file, app.sh that can be run as ./app.sh instead of '$ java -jar app.sh'

   *  ./jar-tools.sh -jar-to-sh2 file.jar

Note: Use the command below to enable debug.

      $ env DEBUG=true ./build-fat-jar.sh

Show scala libraries location

  • ./jart-tools.sh -scala-lib
$ jart-tools.sh -scala-lib
Scala library path = /home/archbox/opt/scala-2.11.8/lib

/home/archbox/opt/scala-2.11.8/lib/akka-actor_2.11-2.3.10.jar
/home/archbox/opt/scala-2.11.8/lib/config-1.2.1.jar
/home/archbox/opt/scala-2.11.8/lib/jline-2.12.1.jar
/home/archbox/opt/scala-2.11.8/lib/scala-actors-2.11.0.jar
/home/archbox/opt/scala-2.11.8/lib/scala-actors-migration_2.11-1.1.0.jar
/home/archbox/opt/scala-2.11.8/lib/scala-compiler.jar
/home/archbox/opt/scala-2.11.8/lib/scala-continuations-library_2.11-1.0.2.jar
/home/archbox/opt/scala-2.11.8/lib/scala-continuations-plugin_2.11.8-1.0.2.jar
/home/archbox/opt/scala-2.11.8/lib/scala-library.jar
/home/archbox/opt/scala-2.11.8/lib/scalap-2.11.8.jar
/home/archbox/opt/scala-2.11.8/lib/scala-parser-combinators_2.11-1.0.4.jar
/home/archbox/opt/scala-2.11.8/lib/scala-reflect.jar
/home/archbox/opt/scala-2.11.8/lib/scala-swing_2.11-1.0.2.jar
/home/archbox/opt/scala-2.11.8/lib/scala-xml_2.11-1.0.4.jar

Inspect Jar files

Show manifest file

Example:

  • $ jar-tools.sh -jar-manifest canvas.jar
$ jar-tools.sh -jar-manifest canvas.jar 
Manifest-Version: 1.0
Scala-Compiler-Version: 2.11.8
Main-Class: Main

Show contents

  • $ jar-tools.sh -jar-view canvas.jar
$ jar-tools.sh -jar-view canvas.jar 
    75 Fri Jul 21 18:35:46 BRT 2017 META-INF/MANIFEST.MF
  1773 Fri Jul 21 18:35:46 BRT 2017 Main$$anon$2$OriginXY$.class
  2930 Fri Jul 21 18:35:46 BRT 2017 Main$$anon$2$OriginXY.class
   626 Fri Jul 21 18:35:46 BRT 2017 Main$$anon$2$OriginType.class
  1755 Fri Jul 21 18:35:46 BRT 2017 Main$$anon$2$OriginC$.class
  1759 Fri Jul 21 18:35:46 BRT 2017 Main$$anon$2$OriginBL$.class
  1894 Fri Jul 21 18:35:46 BRT 2017 Main$$anon$2$DrawUtils$$anonfun$withContext$1.class
  1682 Fri Jul 21 18:35:46 BRT 2017 Main$$anon$2$DrawUtils$$anonfun$withColor$1$$anonfun$apply$4.class
  1654 Fri Jul 21 18:35:46 BRT 2017 Main$$anon$2$DrawUtils$$anonfun$withColor$1.class
     ... ... ... 

Make a self-executable jar file

It generates a self-executable jar-file with ‘.sh’ extension of unix shell script from a runnable jar file named app.jar which can be executed with:

  • $ java -jar app.jar

The application can be executed with ./app.sh.

  1. Run
$ jar-tools.sh -jar-to-sh out/linuxPanel.jar
Build jar-executable out/linuxPanel.sh
Run it with ./out/linuxPanel.sh
  1. The command above generates linuxPanel.sh that can be executed with:
./linuxPanel.sh

Make a self-executable jar file without scala-library bundled

This command builds a self-executable jar-file out of a scala-compiled jar file that cannot be run with ‘java -jar’ directly, but can be run with ‘scala app.jar’.

Example:

  1. Build the program linuxPanel.jar
$ scalac linuxPanel.scala -d linuxPanel.jar
  1. Build the self-executable jar, named linuxPanel.sh.
$ jar-tools.sh -jar-to-sh2 linuxPanel.jar 
Input      = linuxPanel.jar
Output     = linuxPanel.sh
Main class =  linuxPanel.Main
Build jar-executable linuxPanel.sh
Run it with ./linuxPanel.sh
  1. Run the application linuxPanel.sh
./linuxPanel.sh 
  1. Optional - Check linuxPanel.sh
$ file linuxPanel.sh 
linuxPanel.sh: a /usr/bin/env sh script executable (binary data)


$ head -n 15 linuxPanel.sh 
#!/usr/bin/env sh

# set -x

SCALA_LIB_PATH="$(dirname $(dirname $(which scala)))"/lib

jars=""
for f in $(ls $SCALA_LIB_PATH); do
    jars=$SCALA_LIB_PATH/$f:$jars
done
jars=$jars"."

java -cp $jars:$0  linuxPanel.Main

exit 0

Build a fat jar for a scala application

Overview

  • ./jart-tools.sh -scala out/output-jar.jar main-jar.jar dep1.jar dep2.jar ...

Build a fat jar for the application main-jar.jar that contains the main class packing it with the scala run-time (scala-library.jar) and the jar dependencies dep1.jar dep2.jar and so on.

Example 1

It will build a fat-jar for the sample-scala program testProgram.scala

  1. Compile the scala program to a jar file.
$ scalac testProgram.scala -d testProgram.jar

Run it with scala:

$ scala testProgram.jar
Hello world Scala

It will display a simple GUI:

images/program-screenshot.png

Run it with java: It first will fail because the dependency scala-library.jar is missing.

$ java -cp testProgram.jar scalaApp.Main
Exception in thread "main" java.lang.NoClassDefFoundError: scala/Predef$
	at scalaApp.Main$.main(testProgram.scala:8)
	at scalaApp.Main.main(testProgram.scala)
Caused by: java.lang.ClassNotFoundException: scala.Predef$
	at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
	... 2 more

$ java -jar testProgram.jar
Exception in thread "main" java.lang.NoClassDefFoundError: scala/Predef$
	at scalaApp.Main$.main(testProgram.scala:8)
	at scalaApp.Main.main(testProgram.scala)
Caused by: java.lang.ClassNotFoundException: scala.Predef$
	at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
	... 2 more

Try again. Now it works.

$ java -cp /home/archbox/opt/scala-2.11.8/lib/scala-library.jar:testProgram.jar  scalaApp.Main
Hello world Scala

2. Build a fat jar.

It will create the file testProgram-fat.jar.

$ ./jar-tools.sh -scala-build-jar testProgram-fat.jar testProgram.jar
At directory /home/archbox/Documents/projects/jart-tools.sh/temp

Manifest Content META-INF/MANIFEST.MF

Manifest-Version: 1.0
Scala-Compiler-Version: 2.11.8
Main-Class: scalaApp.Main

Building fat-jar file ...
added manifest
adding: library.properties(in = 187) (out= 135)(deflated 27%)
ignoring entry META-INF/
ignoring entry META-INF/MANIFEST.MF
adding: rootdoc.txt(in = 4279) (out= 1329)(deflated 68%)
adding: scala/(in = 0) (out= 0)(stored 0%)
adding: scala/languageFeature.class(in = 2317) (out= 1471)(deflated 36%)
adding: scala/Function6.class(in = 1739) (out= 1012)(deflated 41%)

.... ... ... ... .... .... ... ... ... .... .... ... ... ... ....

adding: scala/Function1.class(in = 2600) (out= 1431)(deflated 44%)
adding: scala/Function2$mcFJI$sp.class(in = 323) (out= 195)(deflated 39%)
adding: scala/Tuple3$.class(in = 1555) (out= 720)(deflated 53%)
adding: scala/Unit.class(in = 1133) (out= 809)(deflated 28%)
adding: scala/Function21.class(in = 3610) (out= 1671)(deflated 53%)
adding: scala/Enumeration$$anonfun$scala$Enumeration$$isValDef$1$1.class(in = 1771) (out= 890)(deflated 49%)
adding: scala/Function7.class(in = 1851) (out= 1055)(deflated 43%)
adding: scala/Function18$$anonfun$tupled$1.class(in = 2393) (out= 1019)(deflated 57%)
adding: scala/Predef$StringFormat$.class(in = 2107) (out= 1010)(deflated 52%)
adding: scala/Tuple5$.class(in = 1805) (out= 768)(deflated 57%)
adding: scala/Function2$mcZJD$sp.class(in = 323) (out= 196)(deflated 39%)
adding: scala/Char.class(in = 6084) (out= 3604)(deflated 40%)
adding: scala/Float.class(in = 5382) (out= 3268)(deflated 39%)
adding: scala/Enumeration$ValueSet$$anon$2.class(in = 1673) (out= 668)(deflated 60%)
adding: scalaApp/(in = 0) (out= 0)(stored 0%)
adding: scalaApp/Main.class(in = 585) (out= 472)(deflated 19%)
adding: scalaApp/Main$.class(in = 1386) (out= 830)(deflated 40%)
--------------------------------------

Built file: testProgram-fat.jar Ok.

3. Check the generated file

$ file testProgram-fat.jar
testProgram-fat.jar: Java archive data (JAR)

# A little bit heavier, but this size is insignificant and a very
# small price for all Scala's goodness.
#
$ du -h testProgram-fat.jar
5,5M    testProgram-fat.jar
5,5M    total

$ jar -tf testProgram-fat.jar
META-INF/
META-INF/MANIFEST.MF
library.properties
rootdoc.txt
scala/
scala/languageFeature.class
scala/Function6.class
scala/Function2$mcIDI$sp.class
scala/Function1$mcDI$sp.class
scala/Product2.class
scala/SerialVersionUID.class
scala/Function1$mcVI$sp$class.class
scala/Function22$class.class
... ... ... ... ... ....

scala/Float.class
scala/Enumeration$ValueSet$$anon$2.class
scalaApp/
scalaApp/Main.class
scalaApp/Main$.class

4. Run it and deploy.

The fat jar can be run with a simple command java -jar or by double clicking it if the desktop is configured properly. It can also be distributed to machines without Scala installed.

$ java -jar testProgram-fat.jar
Hello world Scala

Example 2

Example: It will build the fat-jar file out/exrates.jar from the application bin/demoTableExrates.jar and pack it with scala-library.jar and scala-xml_2.11-1.0.4.jar.

$ jar-tools.sh -scala out/exrates.jar \
  bin/demoTableExrates.jar \
  bin/jswing.jar /home/archbox/opt/scala-2.11.8/lib/scala-xml_2.11-1.0.4.jar

# Script output below
At directory /home/archbox/Documents/projects/jswing.scala/out/temp
Extracting /home/archbox/Documents/projects/jswing.scala/bin/jswing.jar
Extracting /home/archbox/Documents/projects/jswing.scala/bin/jswing.jar

Manifest Content META-INF/MANIFEST.MF

Manifest-Version: 1.0
Scala-Compiler-Version: 2.11.8
Main-Class: Main

added manifest
adding: jswing/(in = 0) (out= 0)(stored 0%)
adding: jswing/Event$$anon$1.class(in = 790) (out= 459)(deflated 41%)
adding: jswing/Dialog$FileChooser$$anonfun$run$1.class(in = 1179) (out= 613)(deflated 48%)
adding: jswing/JUtils$.class(in = 1984) (out= 1071)(deflated 46%)
adding: jswing/guis/(in = 0) (out= 0)(stored 0%)
adding: jswing/guis/TextView.class(in = 5485) (out= 3114)(deflated 43%)
adding: jswing/guis/PictureFrame$.class(in = 1114) (out= 561)(deflated 49%)
adding: jswing/guis/ListView.class(in = 6373) (out= 3410)(deflated 46%)
adding: jswing/guis/PictureFrame.class(in = 4352) (out= 2510)(deflated 42%)
adding: jswing/guis/ListView$.class(in = 859) (out= 456)(deflated 46%)
adding: jswing/guis/ListView$$anon$1.class(in = 1047) (out= 584)(deflated 44%)
adding: jswing/guis/ListView$$anonfun$onSelect$1.class(in = 1398) (out= 728)(deflated 47%)

... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...

adding: scala/Predef$StringFormat$.class(in = 2107) (out= 1010)(deflated 52%)
adding: scala/Tuple5$.class(in = 1805) (out= 768)(deflated 57%)
adding: scala/Function2$mcZJD$sp.class(in = 323) (out= 196)(deflated 39%)
adding: scala/Char.class(in = 6084) (out= 3604)(deflated 40%)
adding: scala/Float.class(in = 5382) (out= 3268)(deflated 39%)
adding: scala/Enumeration$ValueSet$$anon$2.class(in = 1673) (out= 668)(deflated 60%)
adding: scala-xml.properties(in = 112) (out= 76)(deflated 32%)
--------------------------------------

Built file: out/exrates.jar Ok.
Run it with $ java -jar out/exrates.jar

About

Unix Shell Script to build java/Scala fat-jars and make the distributions and deployment of Scala applications easier.

License:The Unlicense


Languages

Language:Shell 90.5%Language:Scala 9.5%