Search code examples
javamavenjpackage

JPackage via maven and missing .desktop file and icon


pom.xml

I have a set of modular maven projects and a parent pom project. Under the parent there's also a converter.jlink project. In its pom I use the maven-jlink-plugin to create a runnable image in its target folder. It runs fine but now I want to package it up as a deb install file. I've added this to the converter.jlink pom:

<plugin>
    <groupId>com.github.akman</groupId>
    <artifactId>jpackage-maven-plugin</artifactId>
    <version>0.1.5</version>
    <configuration>
        <dest>target/dist/</dest>
        <name>Converter</name>
        <appversion>${project.version}</appversion>
        <type>PLATFORM</type> <!-- deb -->
        <icon>src/main/resources/converter.svg</icon>
        <vendor>Footeware.ca</vendor>
        <verbose>true</verbose>
        <runtimeimage>target/maven-jlink/default/</runtimeimage>
        <linuxshortcut>true</linuxshortcut>
        <linuxdebmaintainer>[email protected]</linuxdebmaintainer>
        <licensefile>src/main/resources/gpl-3.0.txt</licensefile>
        <resourcedir>src/main/resources/</resourcedir>
    </configuration>
    <executions>
        <execution>
            <id>jpackage-image</id>
            <phase>verify</phase>
            <goals>
                <goal>jpackage</goal>
            </goals>
        </execution>
    </executions>
</plugin>

The converter

The jlink's src/main/resources contains an app icon, a license file, and a converter.desktop file that I read somewhere had to be added via "resourcedir" to get found. The packaging seems to work - I've used "verbose" true but I see next to nothing from the maven output of jpackage. There is a deb file created that installs into /opt fine. But my $HOME/.local/share/applications folder doesn't get a converter.desktop file created. I've used "linuxshortcut" true but I see no shortcut. I've added an "icon" directive but I don't know where to look for it. It's not in $HOME/.local/share/icons. I've tried running jpackage on the cli but I'm getting the same results. What am I missing or doing wrong?


Solution

  • Specific Answer for https://github.com/CraigFoote/ca.footeware.swing.converter

    Only Modify sub poject: converter.app

    converter.app Tree

    converter.app
    ├── pom.xml
    └── src
        └── main
            ├── java
            ├── jpackage-data (1) DIR
            │   ├── converter.app.jpackage.settings (2)
            │   ├── converter.mime.properties (3)
            │   └── linuxOverride (4) DIR
            │       ├── converter.desktop (5)
            │       ├── postinst (6)
            │       └── postrm   (7)
            └── resources-extra  (8) DIR
                ├── gpl-3.0.txt  (9)
                └── images       (10) DIR
                    └── converter_32.png (11)
    

    converter.app.jpackage.settings

    The parameter can not put direct to pom.xml,

    because mail format have < and >

    --copyright "Copyright (c) 2024 Craig Foote <[email protected]>"
    --vendor "Craig Foote <[email protected]>"
    

    converter.mime.properties

    You can modify for your need.

    mime-type=application/txt
    extension=txt
    description=TXT
    

    converter.desktop

    Append %f in Exec=/opt/converter/bin/converter

    Let System can let this app in Open With App List.

    [Desktop Entry]
    Name=converter
    Comment=An application with a set of tab panels each doing some sort of conversion.
    Exec=/opt/converter/bin/converter %f
    Icon=/opt/converter/lib/converter.png
    Terminal=false
    Type=Application
    Categories=Utility
    MimeType=application/txt
    

    postinst

    • it will run after deb install finish.
    • add converter to /usr/bin/
    • you can open terminal in any directory , then run command converter (Like set PATH to your app folder)
    #!/bin/sh
    # postinst script for jpdfbookmarks
    #
    # see: dh_installdeb(1)
    
    set -e
    
    # summary of how this script can be called:
    #        * <postinst> `configure' <most-recently-configured-version>
    #        * <old-postinst> `abort-upgrade' <new version>
    #        * <conflictor's-postinst> `abort-remove' `in-favour' <package>
    #          <new-version>
    #        * <postinst> `abort-remove'
    #        * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
    #          <failed-install-package> <version> `removing'
    #          <conflicting-package> <version>
    # for details, see https://www.debian.org/doc/debian-policy/ or
    # the debian-policy package
    
    case "$1" in
        configure)
    xdg-desktop-menu install /opt/converter/lib/converter-converter.desktop
            # register /usr/bin/converter as a converter in the alternatives system
            update-alternatives \
                --install \
                    /usr/bin/converter \
                    converter \
                    /opt/converter/bin/converter \
                    50
        ;;
    
        abort-upgrade|abort-remove|abort-deconfigure)
        ;;
    
        *)
            echo "postinst called with unknown argument \`$1'" >&2
            exit 1
        ;;
    esac
    
    exit 0
    

    postrm

    • it will run remove deb install finish.
    #!/bin/sh
    # postrm script for jpdfbookmarks
    #
    # see: dh_installdeb(1)
    
    set -e
    
    # summary of how this script can be called:
    #        * <postrm> `remove'
    #        * <postrm> `purge'
    #        * <old-postrm> `upgrade' <new-version>
    #        * <new-postrm> `failed-upgrade' <old-version>
    #        * <new-postrm> `abort-install'
    #        * <new-postrm> `abort-install' <old-version>
    #        * <new-postrm> `abort-upgrade' <old-version>
    #        * <disappearer's-postrm> `disappear' <overwriter>
    #          <overwriter-version>
    # for details, see https://www.debian.org/doc/debian-policy/ or
    # the debian-policy package
    
    case "$1" in
        purge|remove)
               update-alternatives --remove converter /usr/bin/converter || true 
        ;;
        
        upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
        ;;
    
        *)
            echo "postrm called with unknown argument \`$1'" >&2
            exit 1
        ;;
    esac
    
    exit 0
    

    gpl-3.0.txt

    • copy gpl-3.0.txt from converter.jlink/src/main/resources/gpl-3.0.txt

    converter_32.png

    • copy converter.svg from converter.jlink/src/main/resources/converter.svg

    Please note that jpackage --icon does not accept svg(converter.svg), so we must convert svg to png file.

    My method for converting svg files to png files:

    # install tool: inkscape
    sudo apt install inkscape
    
    # convert `converter.svg` to `converter_32.png`
    
    inkscape converter.svg \
      --export-width=32 \
      --export-height=32 \
      --export-png=converter_32.png
    
    
    • delete converter.svg only keep converter_32.png

    put converter_32.png in converter.app/src/main/resources-extra/images

    pom.xml

    <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns="http://maven.apache.org/POM/4.0.0"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>converter.app</artifactId>
    
        <parent>
            <groupId>ca.footeware.swing</groupId>
            <artifactId>converter.parent</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <relativePath>../converter.parent</relativePath>
        </parent>
    
        <properties>
            <maven.compiler.source>17</maven.compiler.source>
            <maven.compiler.target>17</maven.compiler.target>
            <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        </properties>
    
        <licenses>
            <license>
                <name>GNU General Public License (GPL) version 3.0</name>
                <url>http://www.gnu.org/licenses/gpl-3.0.txt</url>
                <distribution>repo</distribution>
            </license>
        </licenses>
    
        <dependencies>
            <dependency>
                <groupId>ca.footeware.swing</groupId>
                <artifactId>converter.spi</artifactId>
                <version>0.0.1-SNAPSHOT</version>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>license-maven-plugin</artifactId>
                    <version>2.4.0</version>
                </plugin>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.1</version>
                    <configuration>
                        <compilerArgs>
                            <arg>-Xlint:all</arg>
                            <!--<arg>-verbose</arg> -->
                            <!--<arg>-Xlint:all,-options,-path</arg> -->
                        </compilerArgs>
                    </configuration>
                </plugin>
                <plugin>
                    <artifactId>maven-jar-plugin</artifactId>
                    <version>3.4.2</version>
                    <configuration>
                        <archive>
                            <manifest>
                                <addClasspath>true</addClasspath>
                                <mainClass>converter.app.Converter</mainClass>
                            </manifest>
                            <manifestEntries>
                                <built-by/>
                                <!-- add empty for not add user name -->
                                <Class-Path>.</Class-Path>
                                <App-Version>${project.version}</App-Version>
                            </manifestEntries>
                        </archive>
                        <excludes>
                            <exclude>**/jpackage-files/**</exclude>
                            <exclude>**/images/**</exclude>
                        </excludes>
                    </configuration>
                </plugin>
    
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>3.2.0</version>
                    <executions>
                        <execution>
                            <id>copy-resources</id>
                            <phase>process-resources</phase>
                            <goals>
                                <goal>copy-resources</goal>
                            </goals>
                            <configuration>
                                <outputDirectory>${project.build.directory}/appassembler/lib</outputDirectory>
                                <resources>
                                    <resource>
                                        <directory>src/main/resources-extra</directory>
                                        <includes>
                                            <include>**/*</include>
                                        </includes>
                                    </resource>
                                </resources>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
    
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>appassembler-maven-plugin</artifactId>
                    <version>2.1.0</version>
                    <executions>
                        <execution>
                            <phase>package</phase>
                            <goals>
                                <goal>assemble</goal>
                            </goals>
                        </execution>
                    </executions>
                    <configuration>
                        <programs>
                            <program>
                                <mainClass>converter.app.Converter</mainClass>
                                <id>converterapp</id>
                            </program>
                        </programs>
                        <extraJvmArguments>
                            -Duser.language=en
                            -Duser.country=US
                            -Dfile.encoding=UTF-8
                            -Xms128M
                            -Xmx756M
                        </extraJvmArguments>
                        <repositoryLayout>flat</repositoryLayout>
                        <useWildcardClassPath>true</useWildcardClassPath>
                        <binFileExtensions>
                            <!--<unix>.sh</unix> -->
                        </binFileExtensions>
                        <repositoryName>lib</repositoryName>
                    </configuration>
                </plugin>
    
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>exec-maven-plugin</artifactId>
                    <version>3.0.0</version>
                    <executions>
                        <execution>
                            <id>jpackage-linux-deb</id>
                            <phase>pre-integration-test</phase>
                            <goals>
                                <goal>exec</goal>
                            </goals>
                            <configuration>
                                <executable>jpackage</executable>
                                <arguments>
                                    <argument>@${project.basedir}/src/main/jpackage-data/converter.app.jpackage.settings
                                    </argument>
                                    <argument>--name</argument>
                                    <argument>converter</argument>
                                    <argument>--input</argument>
                                    <argument>${project.build.directory}/appassembler/lib</argument>
                                    <argument>--license-file</argument>
                                    <argument>${project.build.directory}/appassembler/lib/gpl-3.0.txt</argument>
                                    <argument>--icon</argument>
                                    <argument>${project.build.directory}/appassembler/lib/images/converter_32.png</argument>
                                    <argument>--main-jar</argument>
                                    <argument>converter.app-0.0.1-SNAPSHOT.jar</argument>
                                    <argument>--description</argument>
                                    <argument>An application with a set of tab panels each doing some sort of conversion.
                                    </argument>
                                    <argument>--app-version</argument>
                                    <argument>0.0.1</argument>
                                    <argument>--linux-app-release</argument>
                                    <argument>snapshot-1</argument>
                                    <argument>--add-modules</argument>
                                    <argument>java.base,java.desktop</argument>
                                    <argument>--file-associations</argument>
                                    <argument>${project.basedir}/src/main/jpackage-data/converter.mime.properties</argument>
                                    <argument>--java-options</argument>
                                    <argument>-ms64m</argument>
                                    <argument>--java-options</argument>
                                    <argument>-mx512m</argument>
                                    <argument>--linux-shortcut</argument>
                                    <argument>--linux-app-category</argument>
                                    <argument>Utility</argument>
                                    <argument>--linux-menu-group</argument>
                                    <argument>Utility</argument>
                                    <argument>--about-url</argument>
                                    <argument>http://Footeware.ca</argument>
                                    <argument>--resource-dir</argument>
                                    <argument>${project.basedir}/src/main/jpackage-data/linuxOverride</argument>
    
                                </arguments>
                                <workingDirectory>${project.build.directory}</workingDirectory>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
    
            </plugins>
    
        </build>
    
    </project>
    

    Build

    mvn clean package exec:exec@jpackage-linux-deb
    

    Now you can find output file in target\converter_0.0.1-snapshot-1_amd64.deb

    Install deb

    sudo dpkg -i converter_0.0.1-snapshot-1_amd64.deb
    

    Check install (For Ubuntu Desktop UI)

    Check Desktop UI

    • In your app start point , you can find converter Icon.

    • (relate to converter.desktop file)

    001.png

    then you can click and run.

    Terminal Check you can call it from any directory

    # in home (`~/`)
    ~$ converter
    
    # in Downloads (`~/Downloads`)
    ~$ cd Downloads
    ~/Downloads$ converter
    

    008.png

    Check Open With

    In File Explorer , Select XXX.txt , mouse Right Click , popup menu Open With Other Application

    003.png

    Find your application in List

    004.png

    009.png

    Select converter, then click Select

    Remove your app

    sudo apt remove -y converter
    

    My Package

    converter.app/target/appassembler
    ├── bin (NOT IMPORTANT)
    │   ├── converterapp
    │   └── converterapp.bat
    └── lib (YOUR APP)
        ├── converter.app-0.0.1-SNAPSHOT.jar
        ├── converter.spi-0.0.1-SNAPSHOT.jar
        ├── gpl-3.0.txt
        └── images
            └── converter_32.png
    

    pom.xml - plugin maven-jar-plugin

    • set jar as executable jar (set mainClass)
    • add classpath (other dependency jar) to jar

    pom.xml - plugin maven-resources-plugin

    • copy gpl-3.0.txt to /target/appassembler/lib
    • copy converter_32.png to /target/appassembler/lib/images

    pom.xml - plugin appassembler-maven-plugin

    • create target/appassembler
    • we will only use then target/appassembler/lib
    target/appassembler
    ├── bin
    │   ├── converterapp
    │   └── converterapp.bat
    └── lib
        ├── converter.app-0.0.1-SNAPSHOT.jar
        ├── converter.spi-0.0.1-SNAPSHOT.jar
        ├── gpl-3.0.txt
        └── images
            └── converter_32.png
    

    pom.xml - plugin exec-maven-plugin

    • run jpackage command

    Same command like this:

    jpackage \
      --name converter \
      --input target/appassembler/lib \
      --license-file "target/appassembler/lib/gpl-3.0.txt" \
      --icon         "target/appassembler/lib/images/converter_32.png" \
      --main-jar converter.app-0.0.1-SNAPSHOT.jar \
      --description "An application with a set of tab panels each doing some sort of conversion." \
      --vendor "Craig Foote <[email protected]>" \
      --copyright "Copyright (c) 2024 Craig Foote <[email protected]>" \
      --app-version 0.0.1 \
      --linux-app-release snapshot-1 \
      --add-modules java.base,java.desktop \
      --file-associations src/main/jpackage-data/converter.mime.properties \
      --java-options "-ms64m" \
      --java-options "-mx512m" \
      --linux-shortcut \
      --linux-app-category "Utility" \
      --linux-menu-group "Utility" \
      --about-url "http://Footeware.ca" \
      --resource-dir src/main/jpackage-data/linuxOverride
    

    pom.xml use jpackage-maven-plugin

    use jpackage-maven-plugin

    <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns="http://maven.apache.org/POM/4.0.0"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>converter.app</artifactId>
    
        <parent>
            <groupId>ca.footeware.swing</groupId>
            <artifactId>converter.parent</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <relativePath>../converter.parent</relativePath>
        </parent>
    
        <properties>
            <maven.compiler.source>17</maven.compiler.source>
            <maven.compiler.target>17</maven.compiler.target>
            <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        </properties>
    
        <licenses>
            <license>
                <name>GNU General Public License (GPL) version 3.0</name>
                <url>http://www.gnu.org/licenses/gpl-3.0.txt</url>
                <distribution>repo</distribution>
            </license>
        </licenses>
    
        <dependencies>
            <dependency>
                <groupId>ca.footeware.swing</groupId>
                <artifactId>converter.spi</artifactId>
                <version>0.0.1-SNAPSHOT</version>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>license-maven-plugin</artifactId>
                    <version>2.4.0</version>
                </plugin>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.1</version>
                    <configuration>
                        <compilerArgs>
                            <arg>-Xlint:all</arg>
                            <!--<arg>-verbose</arg> -->
                            <!--<arg>-Xlint:all,-options,-path</arg> -->
                        </compilerArgs>
                    </configuration>
                </plugin>
                <plugin>
                    <artifactId>maven-jar-plugin</artifactId>
                    <version>3.4.2</version>
                    <configuration>
                        <archive>
                            <manifest>
                                <addClasspath>true</addClasspath>
                                <mainClass>converter.app.Converter</mainClass>
                            </manifest>
                            <manifestEntries>
                                <built-by/>
                                <!-- add empty for not add user name -->
                                <Class-Path>.</Class-Path>
                                <App-Version>${project.version}</App-Version>
                            </manifestEntries>
                        </archive>
                        <excludes>
                            <exclude>**/jpackage-files/**</exclude>
                            <exclude>**/images/**</exclude>
                        </excludes>
                    </configuration>
                </plugin>
    
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>3.2.0</version>
                    <executions>
                        <execution>
                            <id>copy-resources</id>
                            <phase>process-resources</phase>
                            <goals>
                                <goal>copy-resources</goal>
                            </goals>
                            <configuration>
                                <outputDirectory>${project.build.directory}/appassembler/lib</outputDirectory>
                                <resources>
                                    <resource>
                                        <directory>src/main/resources-extra</directory>
                                        <includes>
                                            <include>**/*</include>
                                        </includes>
                                    </resource>
                                </resources>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
    
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>appassembler-maven-plugin</artifactId>
                    <version>2.1.0</version>
                    <executions>
                        <execution>
                            <phase>package</phase>
                            <goals>
                                <goal>assemble</goal>
                            </goals>
                        </execution>
                    </executions>
                    <configuration>
                        <programs>
                            <program>
                                <mainClass>converter.app.Converter</mainClass>
                                <id>converterapp</id>
                            </program>
                        </programs>
                        <extraJvmArguments>
                            -Duser.language=en
                            -Duser.country=US
                            -Dfile.encoding=UTF-8
                            -Xms128M
                            -Xmx756M
                        </extraJvmArguments>
                        <repositoryLayout>flat</repositoryLayout>
                        <useWildcardClassPath>true</useWildcardClassPath>
                        <binFileExtensions>
                            <!--<unix>.sh</unix> -->
                        </binFileExtensions>
                        <repositoryName>lib</repositoryName>
                    </configuration>
                </plugin>
    
              <plugin>
                <groupId>com.github.akman</groupId>
                <artifactId>jpackage-maven-plugin</artifactId>
                <version>0.1.5</version>            
                            <configuration>
                            <name>converter</name>
                            <dest>${project.build.directory}/</dest>
                            <input>${project.build.directory}/appassembler/lib</input>
                            <licensefile>${project.build.directory}/appassembler/lib/gpl-3.0.txt</licensefile>
                            <icon>${project.build.directory}/appassembler/lib/images/converter.png</icon>
                            <mainjar>converter.app-0.0.1-SNAPSHOT.jar</mainjar>
                            <argument>--</argument>
                            <description>An application with a set of tab panels each doing some sort of conversion.</description>
                            <appversion>0.0.1</appversion>
                            <linuxapprelease>snapshot-1</linuxapprelease>
                            <addmodules>java.base,java.desktop</addmodules>
    
                            <fileassociations>${project.basedir}/src/main/jpackage-data/converter.mime.properties</fileassociations>
                            <javaoptions>-Dfile.encoding=UTF-8 -ms64m -mx512m</javaoptions>
                            <linuxshortcut></linuxshortcut>
                            <linuxappcategory>Utility</linuxappcategory>
                            <linuxmenugroup>Utility</linuxmenugroup>
                            <abouturl>http://Footeware.ca</abouturl>
                            <resourcedir>${project.basedir}/src/main/jpackage-data/linuxOverride</resourcedir>
                            <vendor>Craig Foote &lt;[email protected]&gt;</vendor>
                            <copyright>Copyright (c) 2024 Craig Foote &lt;[email protected]&gt;</copyright>
    
                            </configuration>
    
                 </plugin>                   
                 
            </plugins>
    
        </build>
    
    </project>
    

    build

    mvn clean package jpackage:jpackage
    

    Check mapping to jpackage command

    mvn -e -X clean package jpackage:jpackage
    

    it will show command , you can check

    [DEBUG] 
    # jpackage
    --dest /your-path/ca.footeware.swing.converter-master/converter.app/target
    --app-version '0.0.1'
    --copyright 'Copyright (c) 2024 Craig Foote <[email protected]>'
    --description 'An application with a set of tab panels each doing some sort of conversion.'
    --name 'converter'
    --vendor 'Craig Foote <[email protected]>'
    --icon /your-path/ca.footeware.swing.converter-master/converter.app/target/appassembler/lib/images/converter.png
    --input /your-path/ca.footeware.swing.converter-master/converter.app/target/appassembler/lib
    --main-jar 'converter.app-0.0.1-SNAPSHOT.jar'
    --java-options '-Dfile.encoding=UTF-8 -ms64m -mx512m'
    --file-associations /your-path/ca.footeware.swing.converter-master/converter.app/src/main/jpackage-data/converter.mime.properties
    --license-file /your-path/ca.footeware.swing.converter-master/converter.app/target/appassembler/lib/gpl-3.0.txt
    --resource-dir /your-path/ca.footeware.swing.converter-master/converter.app/src/main/jpackage-data/linuxOverride
    --linux-menu-group 'Utility'
    --linux-app-release 'snapshot-1'
    --linux-app-category 'Utility'
    --add-modules java.base,java.desktop
    
    

    Now you can use maven command:

    in converter.app

    # version 1 pom.xml - use exec plugin
    mvn clean package exec:exec@jpackage-linux-deb
    
    # version 2 pom.xml -use jpackage plugin
    mvn clean package jpackage:jpackage
    
    

    And you don't need converter.jlink

    I still have to remind you again why I recommend using the command line command jpackage to test. After the test command is successful, you can switch to the pom.xml exec plugin setting. Only when you use the command do you find that jpackage --icon does not accept svg files.

    Please note that some file names are standardized and must be consistent with your launcher name. (this example: launcher name is converter) Please refer to the documentation https://docs.oracle.com/en/java/javase/21/jpackage/packaging-tool-user-guide.pdf (Packaging Tool User's Guide).