3

Having written a command-line program in Java, using Maven as the build system, what's the recommended way to go from there to having the program available as a command?

Suppose the program is called Foo. In the foo directory I can run mvn package to generate target/foo-1.0-SNAPSHOT.jar, which can in turn be run with java -cp target/foo-1.0-SNAPSHOT.jar foo.Main %* but that command is too long to expect users to type. I need to get to the point where typing foo on the command line will run the program. mvn install doesn't; it just copies the jar to the local maven repository.

What's the recommended way to make a program available as a command?

rwallace
  • 31,405
  • 40
  • 123
  • 242
  • 2
    what a bout a ``foo.bat`` or ``foo.sh`` that executes that command? – f1sh Nov 28 '18 at 14:08
  • @f1sh Indeed. What's the recommended way to generate and install such? Does Maven provide any assistance, or do you have to fall back on doing it entirely with other tools? – rwallace Nov 28 '18 at 14:12
  • 1
    You can also configure maven so it knows where the main class is like [here](https://stackoverflow.com/a/574650/4417306). Then you can do `java -jar foo-1.0-SNAPSHOT.jar` to execute it. Still not entirely what you want though but maybe a step closer. – Mark Nov 28 '18 at 14:14

2 Answers2

3

You can use Maven Assembler Plugin like this:

        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>appassembler-maven-plugin</artifactId>
            <version>1.10</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>assemble</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <programs>
                    <program>
                        <mainClass>sandbox.Main</mainClass>
                        <id>app</id>
                    </program>
                </programs>
            </configuration>
        </plugin>

Running mvn package will generate a windows (.bat) and unix shell script in the bin folder of the ${project.build.directory}/appassembler sub folder.

  • That does indeed create a script in `target/appassembler/bin`. The problem now is that the script (both Windows and UNIX) stops working as soon as it is moved anywhere else. How do you get the script to keep working from a more accessible location? – rwallace Nov 28 '18 at 16:17
  • @rwallace That's because the script expect the jar to be in ../../ location (that is two folders above) so the script has to be adapted if you want both the script and the jar files to be in the same directory. I'm working on this issue right now. –  Nov 28 '18 at 16:27
  • Right; the ideal would be if the script just hardcoded the absolute path to the jar files. That way the jar files could be left where they are while the script was moved to a convenient location. – rwallace Nov 28 '18 at 16:33
  • @rwallace Anyway, if you copy the jar and the appassembler folder elsewhere still works. Also you can rename appassembler the way you want. Editing the generated files defeats the purpose of this plugin. –  Nov 28 '18 at 16:41
0

I ended up just writing a simple Python script: https://github.com/russellw/ayane/blob/master/build.py

#!/usr/bin/python3
import subprocess
import os   

subprocess.check_call("mvn package", shell=True)
if os.name == "nt":
    with open("ayane.bat", "w") as f:
        f.write("java -ea -jar %s\\target\\ayane-3.0-SNAPSHOT.jar %%*\n" % os.getcwd())
else:
    with open("ayane", "w") as f:
        f.write("#!/bin/sh\n")
        f.write('java -ea -jar %s/target/ayane-3.0-SNAPSHOT.jar "$@"\n' % os.getcwd())
    st = os.stat("ayane")
    os.chmod("ayane", st.st_mode | 0o111)
rwallace
  • 31,405
  • 40
  • 123
  • 242