All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.dongliu.jpackage.JPackageMojo Maven / Gradle / Ivy

The newest version!
package net.dongliu.jpackage;

import net.dongliu.jpackage.model.JPackageLauncher;
import net.dongliu.jpackage.model.LinuxPackageSetting;
import net.dongliu.jpackage.model.MacPackageSetting;
import net.dongliu.jpackage.model.WindowsPackageSetting;
import net.dongliu.jpackage.util.ModuleInfo;
import net.dongliu.jpackage.util.ProcessResult;
import net.dongliu.jpackage.util.ProcessUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.*;
import org.apache.maven.project.MavenProject;
import org.apache.maven.toolchain.Toolchain;
import org.apache.maven.toolchain.ToolchainManager;
import org.codehaus.plexus.util.Os;

import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * JPackage mojo, require jdk 14+, Only support modular apps
 *
 * @author dongliu
 */
@Mojo(name = "package", defaultPhase = LifecyclePhase.PACKAGE, requiresDependencyResolution =
        ResolutionScope.COMPILE_PLUS_RUNTIME)
public class JPackageMojo extends AbstractMojo {
    @Parameter(defaultValue = "${project}", readonly = true)
    private MavenProject project;
    @Parameter(defaultValue = "${project.build.directory}/${project.build.finalName}.${project.packaging}")
    private File projectArtifact;
    @Component
    private ToolchainManager toolchainManager;
    @Parameter(defaultValue = "${session}", readonly = true)
    private MavenSession mavenSession;
    /**
     * Name of the application and/or package
     */
    @Parameter(defaultValue = "${project.name}")
    private String name;
    @Parameter(required = true)
    private String type;
    @Parameter(defaultValue = "${project.version}")
    private String appVersion;
    @Parameter(defaultValue = "${project.description}")
    private String description;
    @Parameter
    private String copyright;
    @Parameter
    private String licenseFile;
    @Parameter(defaultValue = "${project.build.directory}")
    private String destination;
    @Parameter(defaultValue = "${project.groupId}")
    private String vendor;
    @Parameter
    private boolean verbose;
    @Parameter
    private boolean bindServices;
    @Parameter
    private List addModules;
    @Parameter
    private List modulePaths;
    @Parameter
    private String runtimeImage;
    /**
     * Jlink options. default is --strip-native-commands --strip-debug --no-man-pages --no-header-files
     */
    @Parameter
    private List jlinkOptions;
    @Parameter
    private String icon;
    @Parameter
    private String resourceDir;
    @Parameter
    private List launchers;
    @Parameter
    private List fileAssociations;
    @Parameter
    private List arguments;
    @Parameter
    private List javaOptions;

    /**
     * If is modular application, default false.
     */
    @Parameter(defaultValue = "false")
    private boolean modular;

    /**
     * The main module name, used for modular application. If not set, use default project artifact's module
     */
    @Parameter
    private String module;
    /**
     * The main jar, used for non-modular application. If not set, use default project artifact
     */
    @Parameter
    private String mainJar;
    /**
     * The input dir, for non-modular application
     */
    @Parameter(defaultValue = "${project.build.directory}/jars")
    private String inputDir;
    /**
     * main class name. If empty, will try to get class name from main module / main jar
     */
    @Parameter
    private String mainClass;

    // mac parameters
    @Parameter(name = "mac")
    private MacPackageSetting macPackageSetting;
    // linux parameters
    @Parameter(name = "linux")
    private LinuxPackageSetting linuxPackageSetting;
    @Parameter(name = "win")
    private WindowsPackageSetting windowsPackageSetting;


    @Parameter(defaultValue = "${project.build.directory}/jars")
    private File jarsDirectory;

    @Override
    public void execute() throws MojoExecutionException {
        String packaging = project.getModel().getPackaging();
        if (!packaging.equalsIgnoreCase("jar")) {
            getLog().error("require packaging type to be jar or jmod, '" + packaging + " not supported'");
            return;
        }

        if (modular) {
            DescribeModule describeModule = new DescribeModule(getTools("jar"), getTools("jmod"), projectArtifact.toPath());
            if (module == null || mainClass == null) {
                ModuleInfo projectModuleInfo = describeModule.describe();
                if (projectModuleInfo != null && projectModuleInfo.mainClass() != null) {
                    module = projectModuleInfo.name();
                    mainClass = projectModuleInfo.mainClass();
                    getLog().info("using main module: " + module + "/" + mainClass);
                }
            }
            if (module == null) {
                throw new RuntimeException("main module required");
            }
        } else {
            if (mainJar == null) {
                mainJar = projectArtifact.toPath().toString();
            }
        }

        getLog().info("creating jpackage image at " + destination + File.separator + name);
        runJPackage();
    }


    private Path getTools(String toolName) {
        Toolchain toolchain = toolchainManager.getToolchainFromBuildContext("jdk", mavenSession);
        Path toolPath;
        if (toolchain != null) {
            String toolPathStr = toolchain.findTool(toolName);
            if (toolPathStr != null) {
                toolPath = Paths.get(toolPathStr);
            } else {
                throw new RuntimeException("tools not found in tool chain: " + toolchain);
            }
        } else {
            String javaHome = System.getProperty("java.home");
            if (Os.isFamily(Os.FAMILY_WINDOWS)) {
                toolName = toolName + ".exe";
            }
            toolPath = Paths.get(javaHome, "bin", toolName);
        }
        return toolPath;
    }

    private void runJPackage() throws AssertionError {
        List command = new ArrayList<>();
        command.add(getTools("jpackage").toString());

        command.add("--name");
        command.add(name);
        command.add("--type");
        command.add(type);
        command.add("--app-version");
        command.add(appVersion);
        command.add("--dest");
        command.add(destination);
        command.add("--vendor");
        command.add(vendor);

        if (description != null) {
            command.add("--description");
            command.add(description);
        }
        if (copyright != null) {
            command.add("--copyright");
            command.add(copyright);
        }
        if (licenseFile != null) {
            command.add("-license-file");
            command.add(licenseFile);
        }

        if (icon != null) {
            command.add("--icon");
            command.add(icon);
        }

        if (resourceDir == null) {
            Path defaultResourceDir;
            if (Os.isFamily(Os.FAMILY_MAC)) {
                defaultResourceDir = project.getBasedir().toPath().resolve("src/main/deploy/osx");
            } else if (Os.isFamily(Os.FAMILY_UNIX)) {
                defaultResourceDir = project.getBasedir().toPath().resolve("src/main/deploy/linux");
            } else if (Os.isFamily(Os.FAMILY_WINDOWS)) {
                defaultResourceDir = project.getBasedir().toPath().resolve("src/main/deploy/osx");
            } else {
                defaultResourceDir = null;
            }
            if (defaultResourceDir != null && Files.exists(defaultResourceDir)) {
                resourceDir = defaultResourceDir.toString();
            }
        }

        if (resourceDir != null) {
            getLog().info("using resource dir: " + resourceDir);
            command.add("--resource-dir");
            command.add(resourceDir);
        }

        if (verbose) {
            command.add("--verbose");
        }

        if (jlinkOptions != null && !jlinkOptions.isEmpty()) {
            command.add("--jlink-options");
            command.add(String.join(" ", jlinkOptions));
        }

        if (modular) {
            command.add("--module");
            command.add(module + "/" + mainClass);
        } else {
            command.add("--main-jar");
            command.add(mainJar);
            if (mainClass != null) {
                command.add("--main-class");
                command.add(mainClass);
            }
        }

        if (bindServices) {
            command.add("--bind-services");
        }

        if (addModules != null && !addModules.isEmpty()) {
            command.add("--add-modules");
            command.add(String.join(",", addModules));
        }

        if (modular) {
            if (modulePaths != null && !modulePaths.isEmpty()) {
                command.add("--module-path");
                command.add(String.join(":", modulePaths));
            }
        } else {
            command.add("--input");
            command.add(inputDir);
        }

        if (runtimeImage != null) {
            command.add("--runtime-image");
            command.add(runtimeImage);
        }

        if (arguments != null && !arguments.isEmpty()) {
            for (String argument : arguments) {
                command.add("--arguments");
                command.add(argument);
            }
        }
        if (javaOptions != null && !javaOptions.isEmpty()) {
            for (String javaOption : javaOptions) {
                command.add("--java-options");
                command.add(javaOption);
            }
        }

        if (fileAssociations != null && !fileAssociations.isEmpty()) {
            for (File fileAssociation : fileAssociations) {
                command.add("--file-associations");
                command.add(fileAssociation.toString());
            }
        }

        if (launchers != null && !launchers.isEmpty()) {
            for (JPackageLauncher launcher : launchers) {
                command.add("--add-launcher");
                command.add(String.format("%s=%s", launcher.getName(), launcher.getFile()));
            }
        }

        if (Os.isFamily(Os.FAMILY_MAC) && macPackageSetting != null) {
            addMacParameters(command);
        }

        if (Os.isFamily(Os.FAMILY_UNIX) && linuxPackageSetting != null) {
            addLinuxParameters(command);
        }

        if (Os.isFamily(Os.FAMILY_WINDOWS) && windowsPackageSetting != null) {
            addWindowsParameters(command);
        }

        copyArtifacts();

        getLog().info("run jpackage: " + String.join(" ", command));
        ProcessResult result = ProcessUtils.execute(command.toArray(String[]::new));
        if (result.exitCode() != 0) {
            String message = result.stderr().isEmpty() ? result.stdout() : result.stderr();
            getLog().error("jpackage error: " + message);
        }
    }

    private void addWindowsParameters(List command) {
        if (windowsPackageSetting.isConsole()) {
            command.add("--win-console");
        }
        if (windowsPackageSetting.isDirChooser()) {
            command.add("--win-dir-chooser");
        }
        if (windowsPackageSetting.isMenu()) {
            command.add("--win-menu");
        }
        if (windowsPackageSetting.getMenuGroup() != null) {
            command.add("--win-menu-group");
            command.add(windowsPackageSetting.getMenuGroup());
        }
        if (windowsPackageSetting.isPerUserInstall()) {
            command.add("--win-per-user-install");
        }
        if (windowsPackageSetting.isShortcut()) {
            command.add("--win-shortcut");
        }
        if (windowsPackageSetting.getUpgradeUuid() != null) {
            command.add("--win-upgrade-uuid");
            command.add(windowsPackageSetting.getUpgradeUuid());
        }
        if (windowsPackageSetting.getInstallDir() != null) {
            command.add("--install-dir");
            command.add(windowsPackageSetting.getInstallDir());
        }
    }

    private void addLinuxParameters(List command) {
        if (linuxPackageSetting.getPackageName() != null) {
            command.add("--linux-package-name");
            command.add(linuxPackageSetting.getPackageName());
        }
        if (linuxPackageSetting.getDebMaintainer() != null) {
            command.add("--linux-deb-maintainer");
            command.add(linuxPackageSetting.getDebMaintainer());
        }
        if (linuxPackageSetting.getMenuGroup() != null) {
            command.add("--linux-menu-group");
            command.add(linuxPackageSetting.getMenuGroup());
        }
        if (linuxPackageSetting.getPackageDeps() != null) {
            command.add("--linux-package-deps");
            command.add(linuxPackageSetting.getPackageDeps());
        }
        if (linuxPackageSetting.getRpmLicenseType() != null) {
            command.add("--linux-rpm-license-type");
            command.add(linuxPackageSetting.getRpmLicenseType());
        }
        if (linuxPackageSetting.getAppRelease() != null) {
            command.add("--linux-app-release");
            command.add(linuxPackageSetting.getAppRelease());
        }
        if (linuxPackageSetting.getAppCategory() != null) {
            command.add("--linux-app-category");
            command.add(linuxPackageSetting.getAppCategory());
        }
        if (linuxPackageSetting.isShortcut()) {
            command.add("--linux-shortcut");
        }
        if (linuxPackageSetting.getInstallDir() != null) {
            command.add("--install-dir");
            command.add(linuxPackageSetting.getInstallDir());
        }
    }

    private void addMacParameters(List command) {
        if (macPackageSetting.getPackageIdentifier() != null) {
            command.add("--mac-package-identifier");
            command.add(macPackageSetting.getPackageIdentifier());
        }

        if (macPackageSetting.getPackageName() != null) {
            command.add("--mac-package-name");
            command.add(macPackageSetting.getPackageName());
        }

        if (macPackageSetting.getPackageSigningPrefix() != null) {
            command.add("--mac-package-signing-prefix");
            command.add(macPackageSetting.getPackageSigningPrefix());
        }

        if (macPackageSetting.isSign()) {
            command.add("--mac-sign");
        }

        if (macPackageSetting.getSigningKeychain() != null) {
            command.add("--mac-signing-keychain");
            command.add(macPackageSetting.getSigningKeychain());
        }

        if (macPackageSetting.getSigningKeyUserName() != null) {
            command.add("--mac-signing-key-user-name");
            command.add(macPackageSetting.getSigningKeyUserName());
        }
        if (macPackageSetting.getInstallDir() != null) {
            command.add("--install-dir");
            command.add(macPackageSetting.getInstallDir());
        }
    }


    private void copyArtifacts() {
        Path outputPath = jarsDirectory.toPath();

        if (!jarsDirectory.exists()) {
            jarsDirectory.mkdir();
        }

        Set dependencies = project.getArtifacts();
        for (Artifact artifact : dependencies) {
            String scope = artifact.getScope();
            if (!scope.equals("compile") && !scope.equals("runtime")) {
                continue;
            }

            Path inputFile = artifact.getFile().toPath();
            Path outputJar = jarsDirectory.toPath().resolve(inputFile.getFileName());
            try {
                Files.copy(inputFile, outputJar, StandardCopyOption.REPLACE_EXISTING);
            } catch (IOException e) {
                throw new UncheckedIOException("Couldn't copy JAR file", e);
            }

        }

        Path projectJarPath = projectArtifact.toPath();
        Path outputJar = jarsDirectory.toPath().resolve(projectJarPath.getFileName());
        try {
            Files.copy(projectJarPath, outputJar, StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException e) {
            throw new UncheckedIOException("Couldn't copy JAR file", e);
        }
    }


}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy