An open API service indexing awesome lists of open source software.

https://github.com/caiorss/build-fat-jar

Unix Shell Script to build java/Scala fat-jars and make the distributions and deployment of Scala applications easier.
https://github.com/caiorss/build-fat-jar

bash deploy fat-jar fatjar jar java scala script shell tool unix utility

Last synced: about 2 months ago
JSON representation

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

Awesome Lists containing this project

README

          

#+TITLE: jar-tools.sh - Unix Shell Script to build java/Scala fat-jars
#+AUTHOR: Caio Rodrigues
#+STARTUP: showall
#+KEYWORDS: unix shell script java scala fatjar fat-jar deploy dependency

* 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:

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

$ ./jar-tools.sh
#+END_SRC

** Usage and Examples
*** Show user help

+ =./jart-tools.sh=

#+BEGIN_SRC text
$ 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

#+END_SRC

*** Show scala libraries location

+ =./jart-tools.sh -scala-lib=

#+BEGIN_SRC sh
$ 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

#+END_SRC

*** Inspect Jar files
**** Show manifest file

Example:

- =$ jar-tools.sh -jar-manifest canvas.jar=

#+BEGIN_SRC sh
$ jar-tools.sh -jar-manifest canvas.jar
Manifest-Version: 1.0
Scala-Compiler-Version: 2.11.8
Main-Class: Main
#+END_SRC

**** Show contents

+ =$ jar-tools.sh -jar-view canvas.jar=

#+BEGIN_SRC sh
$ 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
... ... ...
#+END_SRC

*** 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

#+BEGIN_SRC sh
$ jar-tools.sh -jar-to-sh out/linuxPanel.jar
Build jar-executable out/linuxPanel.sh
Run it with ./out/linuxPanel.sh
#+END_SRC

2. The command above generates linuxPanel.sh that can be executed with:

#+BEGIN_SRC sh
./linuxPanel.sh
#+END_SRC

*** 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

#+BEGIN_SRC sh
$ scalac linuxPanel.scala -d linuxPanel.jar
#+END_SRC

2. Build the self-executable jar, named linuxPanel.sh.

#+BEGIN_SRC 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
#+END_SRC

3. Run the application linuxPanel.sh

#+BEGIN_SRC sh
./linuxPanel.sh
#+END_SRC

4. Optional - Check linuxPanel.sh

#+BEGIN_SRC 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
#+END_SRC

*** 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 [[file:testProgram.scala][file:testProgram.scala]]

1. Compile the scala program to a jar file.

#+BEGIN_SRC sh
$ scalac testProgram.scala -d testProgram.jar
#+END_SRC

Run it with scala:

#+BEGIN_SRC sh
$ scala testProgram.jar
Hello world Scala

#+END_SRC

It will display a simple GUI:

[[file:images/program-screenshot.png][file:images/program-screenshot.png]]

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

#+BEGIN_SRC sh
$ 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

#+END_SRC

Try again. Now it works.

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

#+END_SRC

*2. Build a fat jar.*

It will create the file testProgram-fat.jar.

#+BEGIN_SRC sh
$ ./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.

#+END_SRC

*3. Check the generated file*

#+BEGIN_SRC sh
$ 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

#+END_SRC

*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.

#+BEGIN_SRC sh
$ java -jar testProgram-fat.jar
Hello world Scala
#+END_SRC

**** 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_.

#+BEGIN_SRC sh
$ 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

#+END_SRC