
com.akathist.maven.plugins.launch4j.Launch4jMojo Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of launch4j-maven-plugin Show documentation
Show all versions of launch4j-maven-plugin Show documentation
This plugin creates Windows executables from Java jar files using the Launch4j utility.
The newest version!
/*
* Maven Launch4j Plugin
* Copyright (c) 2006 Paul Jungwirth
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.akathist.maven.plugins.launch4j;
import net.sf.launch4j.Builder;
import net.sf.launch4j.BuilderException;
import net.sf.launch4j.config.Config;
import net.sf.launch4j.config.ConfigPersister;
import net.sf.launch4j.config.ConfigPersisterException;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.artifact.DefaultArtifact;
import org.eclipse.aether.impl.ArtifactResolver;
import org.eclipse.aether.repository.LocalArtifactRequest;
import org.eclipse.aether.repository.LocalArtifactResult;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.resolution.ArtifactRequest;
import org.eclipse.aether.resolution.ArtifactResolutionException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Collectors;
/**
* Wraps a jar in a Windows executable.
*/
@Mojo(
name = "launch4j",
defaultPhase = LifecyclePhase.PACKAGE,
requiresDependencyResolution = ResolutionScope.RUNTIME,
threadSafe = true
)
public class Launch4jMojo extends AbstractMojo {
@Parameter(defaultValue = "launch4j", required = true)
private String launch4jArtifactId;
@Parameter(defaultValue = "net.sf.launch4j", required = true)
private String launch4jGroupId;
// intentionally non-static non-final so it can be hacked with reflection if someone really needs to
private String DEF_REQADMMAN_RES = "META-INF/resources/manifest-requireAdminRights-v1.xml";
// intentionally non-static non-final so it can be hacked with reflection if someone really needs to
private String DEF_REQADMMAN_FILE = "target/classes/META-INF/manifest-requireAdminRights.xml";
/**
* Maven Session.
*/
@Parameter(defaultValue = "${session}", required = true, readonly = true)
private MavenSession session;
@Parameter(defaultValue = "${project.remoteProjectRepositories}", required = true, readonly = true)
private List repositories;
/**
* The dependencies required by the project.
*/
@Parameter(defaultValue = "${project.artifacts}", required = true, readonly = true)
private Set dependencies;
/**
* The user's current project.
*/
@Parameter(defaultValue = "${project}", required = true, readonly = true)
private MavenProject project;
/**
* Used to look up Artifacts in the remote repository.
*/
@Component(role = RepositorySystem.class)
private RepositorySystem repositorySystem;
/**
* The user's local repository.
*/
@Parameter(defaultValue = "${repositorySystemSession}", required = true, readonly = true)
private RepositorySystemSession repositorySystemSession;
/**
* The artifact resolver used to grab the binary bits that launch4j needs.
*/
@Component(role = ArtifactResolver.class)
private ArtifactResolver resolver;
/**
* The dependencies of this plugin.
* Used to get the Launch4j artifact version.
*/
@Parameter(defaultValue = "${plugin.artifacts}")
private List oldPluginArtifacts;
/**
* The base of the current project.
*/
@Parameter(defaultValue = "${project.basedir}", required = true, readonly = true)
private File basedir;
/**
* Whether you want a gui or console app.
* Valid values are "gui" and "console."
* If you say gui, then launch4j will run your app from javaw instead of java
* in order to avoid opening a DOS window.
* Choosing gui also enables other options like taskbar icon and a splash screen.
*/
@Parameter(defaultValue = "console", required = true)
private String headerType;
/**
* The name of the Launch4j native configuration file
* The path, if relative, is relative to the pom.xml.
*/
@Parameter
private File infile;
/**
* The name of the executable you want launch4j to produce.
* The path, if relative, is relative to the pom.xml.
*/
@Parameter(defaultValue = "${project.build.directory}/${project.artifactId}.exe")
private File outfile;
/**
* The jar to bundle inside the executable.
* The path, if relative, is relative to the pom.xml.
*
* If you don't want to wrap the jar, then this value should be the runtime path
* to the jar relative to the executable. You should also set dontWrapJar to true.
*
* You can only bundle a single jar. Therefore, you should either create a jar that contains
* your own code plus all your dependencies, or you should distribute your dependencies alongside
* the executable.
*/
@Parameter(defaultValue = "${project.build.directory}/${project.build.finalName}.jar")
private String jar;
/**
* Whether the executable should wrap the jar or not.
*/
@Parameter(defaultValue = "false")
private boolean dontWrapJar;
/**
* The title of the error popup if something goes wrong trying to run your program,
* like if java can't be found. If this is a console app and not a gui, then this value
* is used to prefix any error messages, as in ${errTitle}: ${errorMessage}.
*/
@Parameter(defaultValue = "${project.name}")
private String errTitle;
/**
* downloadUrl (?).
*/
@Parameter
private String downloadUrl;
/**
* supportUrl (?).
*/
@Parameter
private String supportUrl;
/**
* Constant command line arguments to pass to your program's main method.
* Actual command line arguments entered by the user will appear after these.
*/
@Parameter
private String cmdLine;
/**
* Changes to the given directory, relative to the executable, before running your jar.
* If set to .
the current directory will be where the executable is.
* If omitted, the directory will not be changed.
*/
@Parameter
private String chdir;
/**
* Priority class of windows process.
* Valid values are "normal" (default), "idle" and "high".
*
* @see MSDN: Scheduling Priorities
*/
@Parameter(defaultValue = "normal")
private String priority;
/**
* If true, the executable waits for the java application to finish before returning its exit code.
* Defaults to false for gui applications. Has no effect for console applications, which always wait.
*/
@Parameter(defaultValue = "false")
private boolean stayAlive;
/**
* If true, when the application exits, any exit code other than 0 is considered a crash and
* the application will be started again.
*/
@Parameter(defaultValue = "false")
private boolean restartOnCrash;
/**
* The icon to use in the taskbar. Must be in ico format.
*/
@Parameter
private File icon;
/**
* Whether the executable should ask for admin rights (Windows only).
*/
@Parameter(defaultValue = "false")
private boolean requireAdminRights;
/**
* Object files to include. Used for custom headers only.
*/
@Parameter
private List objs;
/**
* Win32 libraries to include. Used for custom headers only.
*/
@Parameter
private List libs;
/**
* Variables to set.
*/
@Parameter
private List vars;
/**
* Details about the supported jres.
*/
@Parameter
private Jre jre;
/**
* Details about the classpath your application should have.
* This is required if you are not wrapping a jar.
*/
@Parameter
private ClassPath classPath;
/**
* Details about whether to run as a single instance.
*/
@Parameter
private SingleInstance singleInstance;
/**
* Details about the splash screen.
*/
@Parameter
private Splash splash;
/**
* Lots of information you can attach to the windows process.
*/
@Parameter
private VersionInfo versionInfo;
/**
* If set to true, it will prevent filling out the VersionInfo params with default values.
*/
@Parameter(defaultValue = "false")
private boolean disableVersionInfoDefaults;
/**
* Various messages you can display.
*/
@Parameter
private Messages messages;
/**
* Windows manifest file (a XML file) with the same name as .exe file (myapp.exe.manifest)
*/
@Parameter
private File manifest;
/**
* If set to true it will save final config into a XML file
*/
@Parameter(defaultValue = "false")
private boolean saveConfig = false;
/**
* If {@link #saveConfig} is set to true, config will be written to this file
*/
@Parameter(defaultValue = "${project.build.directory}/launch4j-config.xml")
private File configOutfile;
/**
* If set to true, a synchronized block will be used to protect resources
*/
@Parameter(defaultValue = "false")
private boolean parallelExecution = false;
/**
* If set to true, execution of the plugin will be skipped
*/
@Parameter(defaultValue = "false")
private boolean skip = false;
private File getJar() {
return new File(jar);
}
@Override
public void execute() throws MojoExecutionException {
if (parallelExecution) {
synchronized (Launch4jMojo.class) {
doExecute();
}
} else {
doExecute();
}
}
private void doExecute() throws MojoExecutionException {
if (this.skipExecution()) {
getLog().debug("Skipping execution of the plugin");
return;
}
processRequireAdminRights();
fillSensibleJreDefaults();
if (!disableVersionInfoDefaults) {
try {
if(versionInfo == null) {
versionInfo = new VersionInfo();
}
versionInfo.setLog(getLog());
versionInfo.tryFillOutByDefaults(project, outfile);
} catch (RuntimeException exception) {
throw new MojoExecutionException("Cannot fill out VersionInfo by defaults", exception);
}
}
final File workDir = setupBuildEnvironment();
if (infile != null) {
if (infile.exists()) {
try {
if (getLog().isDebugEnabled()) {
getLog().debug("Trying to load Launch4j native configuration using file=" + infile.getAbsolutePath());
}
// load launch4j config file from
ConfigPersister.getInstance().load(infile);
// overwrite several properties analogous to the ANT task
// https://sourceforge.net/p/launch4j/git/ci/master/tree/src/net/sf/launch4j/ant/Launch4jTask.java#l84
// retrieve the loaded configuration for manipulation
Config c = ConfigPersister.getInstance().getConfig();
String jarDefaultValue = project.getBuild().getDirectory() + "/" + project.getBuild().getFinalName() + ".jar";
if (jar != null && !jar.equals(jarDefaultValue)) {
getLog().debug("Overwriting config file property 'jar' (='" + c.getJar().getAbsolutePath() + "') with local value '" + getJar().getAbsolutePath() + "'");
// only overwrite when != defaultValue (should be != null anytime because of the default value)
c.setJar(getJar());
}
File outFileDefaultValue = new File(project.getBuild().getDirectory() + "/" + project.getArtifactId() + ".exe");
if (outfile != null && !outfile.getAbsolutePath().equals(outFileDefaultValue.getAbsolutePath())) {
// only overwrite when != defaultValue (should be != null anytime because of the default value)
getLog().debug("Overwriting config file property 'outfile' (='" + c.getOutfile().getAbsolutePath() + "') with local value '" + outfile.getAbsolutePath() + "'");
c.setOutfile(outfile);
}
if (icon != null) {
c.setIcon(icon);
}
if (versionInfo != null) {
if (versionInfo.fileVersion != null) {
getLog().debug("Overwriting config file property 'versionInfo.fileVersion' (='" + c.getVersionInfo().getFileVersion() + "') with local value '" + versionInfo.fileVersion + "'");
c.getVersionInfo().setFileVersion(versionInfo.fileVersion);
}
if (versionInfo.txtFileVersion != null) {
getLog().debug("Overwriting config file property 'versionInfo.txtFileVersion' (='" + c.getVersionInfo().getTxtFileVersion() + "') with local value '" + versionInfo.txtFileVersion + "'");
c.getVersionInfo().setTxtFileVersion(versionInfo.txtFileVersion);
}
if (versionInfo.productVersion != null) {
getLog().debug("Overwriting config file property 'versionInfo.productVersion' (='" + c.getVersionInfo().getProductVersion() + "') with local value '" + versionInfo.productVersion + "'");
c.getVersionInfo().setProductVersion(versionInfo.productVersion);
}
if (versionInfo.txtProductVersion != null) {
getLog().debug("Overwriting config file property 'versionInfo.txtProductVersion' (='" + c.getVersionInfo().getTxtProductVersion() + "') with local value '" + versionInfo.txtProductVersion + "'");
c.getVersionInfo().setTxtProductVersion(versionInfo.txtProductVersion);
}
}
ConfigPersister.getInstance().setAntConfig(c, infile.getParentFile());
} catch (ConfigPersisterException e) {
getLog().error(e);
throw new MojoExecutionException("Could not load Launch4j native configuration file", e);
}
} else {
throw new MojoExecutionException("Launch4j native configuration file [" + infile.getAbsolutePath() + "] does not exist!");
}
} else {
final Config c = new Config();
c.setHeaderType(headerType);
c.setOutfile(outfile);
c.setJar(getJar());
c.setDontWrapJar(dontWrapJar);
c.setErrTitle(errTitle);
c.setDownloadUrl(downloadUrl);
c.setSupportUrl(supportUrl);
c.setCmdLine(cmdLine);
c.setChdir(chdir);
c.setPriority(priority);
c.setStayAlive(stayAlive);
c.setRestartOnCrash(restartOnCrash);
c.setManifest(manifest);
c.setIcon(icon);
c.setHeaderObjects(relativizeAndCopy(workDir, objs));
c.setLibs(relativizeAndCopy(workDir, libs));
c.setVariables(vars);
if (classPath != null) {
c.setClassPath(classPath.toL4j(dependencies));
}
if (jre != null) {
jre.deprecationWarning(getLog());
c.setJre(jre.toL4j());
}
if (singleInstance != null) {
c.setSingleInstance(singleInstance.toL4j());
}
if (splash != null) {
c.setSplash(splash.toL4j());
}
if (versionInfo != null) {
c.setVersionInfo(versionInfo.toL4j());
}
if (messages != null) {
if (messages.bundledJreErr != null) {
getLog().warn(" is deprecated, use instead!");
}
c.setMessages(messages.toL4j());
}
ConfigPersister.getInstance().setAntConfig(c, getBaseDir());
}
if (getLog().isDebugEnabled()) {
printState();
}
final Builder builder = new Builder(new MavenLog(getLog()), workDir);
try {
builder.build();
} catch (BuilderException e) {
getLog().error(e);
throw new MojoExecutionException("Failed to build the executable; please verify your configuration.", e);
}
if (saveConfig) {
try {
ConfigPersister.getInstance().save(configOutfile);
} catch (ConfigPersisterException e) {
throw new MojoExecutionException("Cannot save config into a XML file", e);
}
}
}
private void fillSensibleJreDefaults() throws MojoExecutionException {
if (jre == null) {
jre = new Jre();
}
if (jre.path == null) {
String pathDef = "%JAVA_HOME%;%PATH%";
getLog().warn("jre.path not set, defaulting to \"" + pathDef + "\"");
jre.path = pathDef;
}
}
private void processRequireAdminRights() throws MojoExecutionException {
if (requireAdminRights) {
getLog().warn("Modifying the resulting exe to always require Admin rights.");
getLog().warn("Make sure it's necessary. Consider writing your own manifest file.");
if (manifest != null) {
getLog().warn("manifest param is already set, overriding. Make sure that's what's intended.");
}
try {
File metaInfDir = new File(basedir, "target/classes/META-INF");
metaInfDir.mkdir();
File manFile = new File(basedir, DEF_REQADMMAN_FILE);
byte[] manBytes = FileUtils.readResourceAsBytes(DEF_REQADMMAN_RES);
FileUtils.writeBytesIfDiff(manFile, manBytes);
byte[] savedBytes = FileUtils.readBytes(manFile);
if (Arrays.equals(manBytes, savedBytes)) {
getLog().info("Manifest file written to " + manFile);
}
manifest = manFile;
} catch (Exception e) {
getLog().error(e);
throw new MojoExecutionException(e);
}
}
}
/**
* Prepares a little directory for launch4j to do its thing. Launch4j needs a bunch of object files
* (in the w32api and head directories) and the ld and windres binaries (in the bin directory).
* The tricky part is that launch4j picks this directory based on where its own jar is sitting.
* In our case, the jar is going to be sitting in the user's ~/.m2 repository. That's okay: we know
* maven is allowed to write there. So we'll just add our things to that directory.
*
* This approach is not without flaws.
* It risks two processes writing to the directory at the same time.
* But fortunately, once the binary bits are in place, we don't do any more writing there,
* and launch4j doesn't write there either.
* Usually ~/.m2 will only be one system or another.
* But if it's an NFS mount shared by several system types, this approach will break.
*
* Okay, so here is a better proposal: package the plugin without these varying binary files,
* and put each set of binaries in its own tarball. Download the tarball you need to ~/.m2 and
* unpack it. Then different systems won't contend for the same space. But then I'll need to hack
* the l4j code so it permits passing in a work directory and doesn't always base it on
* the location of its own jarfile.
*
* @return the work directory.
*/
private File setupBuildEnvironment() throws MojoExecutionException {
createParentFolder();
Artifact binaryBits = chooseBinaryBits();
if (retrieveBinaryBits(binaryBits)) {
return unpackWorkDir(binaryBits);
} else {
throw new MojoExecutionException("Artifact: " + binaryBits + " is not available!");
}
}
private void createParentFolder() {
if (outfile != null) {
File parent = outfile.getParentFile();
if (!parent.exists()) {
getLog().debug("Parent " + parent.getPath() + " does not exist, creating it!");
boolean created = parent.mkdirs();
if (created) {
getLog().debug("Parent " + parent.getPath() + " has been created!");
} else {
getLog().warn("Cannot create parent " + parent.getPath() + "!");
}
}
}
}
/**
* Unzips the given artifact in-place and returns the newly-unzipped top-level directory.
* Writes a marker file to prevent unzipping more than once.
*/
private File unpackWorkDir(Artifact artifact) throws MojoExecutionException {
getLog().debug("Trying normal search first, all-repo search if normal fails");
LocalArtifactRequest request = new LocalArtifactRequest(artifact, null, null);
LocalArtifactResult localArtifact = repositorySystemSession.getLocalRepositoryManager().find(repositorySystemSession, request);
if (localArtifact == null || localArtifact.getFile() == null) {
getLog().warn("Cannot obtain file path to " + artifact + ", trying all-repo search");
request = new LocalArtifactRequest(artifact, repositories, null);
localArtifact = repositorySystemSession.getLocalRepositoryManager().find(repositorySystemSession, request);
if (localArtifact == null || localArtifact.getFile() == null) {
String err = "Cannot obtain file path to " + artifact + " with both normal and all-repo search";
getLog().error(err);
throw new MojoExecutionException(err);
}
}
boolean artifactIsSnapshot = !artifact.getVersion().equals(artifact.getBaseVersion());
getLog().debug("Unpacking " + localArtifact + " into " + localArtifact.getFile());
File platJar = localArtifact.getFile();
File dest = platJar.getParentFile();
File marker = new File(dest, platJar.getName() + ".unpacked");
String n = platJar.getName();
File workdir = new File(dest, n.substring(0, n.length() - 4));
// If the artifact is a SNAPSHOT, then a.getVersion() will report the long timestamp,
// but getFile() will be 1.1-SNAPSHOT.
// Since getFile() doesn't use the timestamp, all timestamps wind up in the same place.
// WRONG. getFile returns names like
// "lbfork-launch4j-3.53-20240105.004437-1-workdir-win32.jar" as of
// 2024-01-05.
// QUESTION: maybe it depends on Maven's version? Need to support both.
// FIX: if it contains expanded version replace it back by expandable version.
if (artifactIsSnapshot && workdir.toString().contains(artifact.getVersion())) {
String oldWorkdirStr = workdir.toString();
String newWorkdirStr = oldWorkdirStr.replace(artifact.getVersion(), artifact.getBaseVersion());
getLog().info("Unexpected workdir, correcting from " + oldWorkdirStr + " to " + newWorkdirStr);
workdir = new File(newWorkdirStr);
}
// Therefore we need to expand the jar every time, if the marker file is stale.
if (marker.exists() && marker.lastModified() > platJar.lastModified()) {
// if (marker.exists() && marker.platJar.getName().indexOf("SNAPSHOT") == -1) {
getLog().info("Platform-specific work directory already exists: " + workdir.getAbsolutePath());
} else {
// trying to use plexus-archiver here is a miserable waste of time:
try (JarFile jf = new JarFile(platJar)) {
Enumeration en = jf.entries();
while (en.hasMoreElements()) {
JarEntry je = en.nextElement();
File outFile = new File(dest, je.getName());
if (!outFile.toPath().normalize().startsWith(dest.toPath().normalize())) {
throw new RuntimeException("Bad zip entry");
}
File parent = outFile.getParentFile();
if (parent != null) parent.mkdirs();
if (je.isDirectory()) {
outFile.mkdirs();
} else {
try (InputStream in = jf.getInputStream(je)) {
try (FileOutputStream fout = new FileOutputStream(outFile)) {
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) >= 0) {
fout.write(buf, 0, len);
}
}
}
outFile.setLastModified(je.getTime());
}
}
} catch (IOException e) {
throw new MojoExecutionException("Error unarchiving " + platJar, e);
}
try {
marker.createNewFile();
marker.setLastModified(new Date().getTime());
} catch (IOException e) {
getLog().warn("Trouble creating marker file " + marker, e);
}
}
setPermissions(workdir);
getLog().info("Using workdir " + workdir);
return workdir;
}
/**
* Chmods the helper executables ld and windres on systems where that is necessary.
*/
private void setPermissions(File workdir) {
if (!System.getProperty("os.name").startsWith("Windows")) {
try {
new ProcessBuilder("chmod", "755", workdir + "/bin/ld").start().waitFor();
new ProcessBuilder("chmod", "755", workdir + "/bin/windres").start().waitFor();
} catch (InterruptedException e) {
getLog().warn("Interrupted while chmodding platform-specific binaries", e);
} catch (IOException e) {
getLog().warn("Unable to set platform-specific binaries to 755", e);
}
}
}
/**
* If custom header objects or libraries shall be linked, they need to sit inside the launch4j working dir.
*/
private List relativizeAndCopy(File workdir, List paths) throws MojoExecutionException {
if (paths == null) return null;
List result = new ArrayList<>();
for (String path : paths) {
Path source = basedir.toPath().resolve(path);
Path dest = workdir.toPath().resolve(basedir.toPath().relativize(source));
if (!source.startsWith(basedir.toPath())) {
throw new MojoExecutionException("File must reside in the project directory: " + path);
}
if (Files.exists(source)) {
try {
Files.createDirectories(dest.getParent());
Path target = Files.copy(source, dest, StandardCopyOption.REPLACE_EXISTING);
result.add(workdir.toPath().relativize(target).toString());
} catch (IOException e) {
throw new MojoExecutionException("Can't copy file to workdir", e);
}
} else {
result.add(path);
}
}
return result;
}
/**
* Downloads the platform-specific parts, if necessary.
*/
private boolean retrieveBinaryBits(Artifact a) throws MojoExecutionException {
getLog().debug("Retrieving artifact: " + a + " stored in " + a.getFile());
try {
ArtifactRequest request = new ArtifactRequest(a, repositories, null);
return repositorySystem.resolveArtifact(repositorySystemSession, request).isResolved();
} catch (IllegalArgumentException e) {
throw new MojoExecutionException("Illegal Argument Exception", e);
} catch (ArtifactResolutionException e) {
throw new MojoExecutionException("Can't retrieve platform-specific components", e);
}
}
/**
* Decides which platform-specific bundle we need, based on the current operating system.
*/
private Artifact chooseBinaryBits() throws MojoExecutionException {
String plat;
String os = System.getProperty("os.name");
String arch = System.getProperty("os.arch");
getLog().debug("OS = " + os);
getLog().debug("Architecture = " + arch);
// See here for possible values of os.name:
// http://lopica.sourceforge.net/os.html
if (os.startsWith("Windows")) {
plat = "win32";
} else if ("Linux".equals(os)) {
if ("amd64".equals(arch)) {
plat = "linux64";
} else {
plat = "linux";
}
} else if ("Solaris".equals(os) || "SunOS".equals(os)) {
plat = "solaris";
} else if ("Mac OS X".equals(os) || "Darwin".equals(os)) {
plat = "mac";
} else {
throw new MojoExecutionException("Sorry, Launch4j doesn't support the '" + os + "' OS.");
}
Artifact artifact = new DefaultArtifact(launch4jGroupId, launch4jArtifactId, "workdir-" + plat, "jar", getLaunch4jVersion());
try {
ArtifactRequest request = new ArtifactRequest(artifact, repositories, null);
return repositorySystem.resolveArtifact(repositorySystemSession, request).getArtifact();
} catch (ArtifactResolutionException e) {
throw new MojoExecutionException(e);
}
}
private File getBaseDir() {
return basedir;
}
/**
* Just prints out how we were configured.
*/
private void printState() {
Log log = getLog();
Config c = ConfigPersister.getInstance().getConfig();
log.debug("headerType = " + c.getHeaderType());
log.debug("outfile = " + c.getOutfile());
log.debug("jar = " + c.getJar());
log.debug("dontWrapJar = " + c.isDontWrapJar());
log.debug("errTitle = " + c.getErrTitle());
log.debug("downloadUrl = " + c.getDownloadUrl());
log.debug("supportUrl = " + c.getSupportUrl());
log.debug("cmdLine = " + c.getCmdLine());
log.debug("chdir = " + c.getChdir());
log.debug("priority = " + c.getPriority());
log.debug("stayAlive = " + c.isStayAlive());
log.debug("restartOnCrash = " + c.isRestartOnCrash());
log.debug("icon = " + c.getIcon());
log.debug("objs = " + c.getHeaderObjects());
log.debug("libs = " + c.getLibs());
log.debug("vars = " + c.getVariables());
if (c.getSingleInstance() != null) {
log.debug("singleInstance.mutexName = " + c.getSingleInstance().getMutexName());
log.debug("singleInstance.windowTitle = " + c.getSingleInstance().getWindowTitle());
} else {
log.debug("singleInstance = null");
}
if (c.getJre() != null) {
log.debug("jre.path = " + c.getJre().getPath());
log.debug("jre.minVersion = " + c.getJre().getMinVersion());
log.debug("jre.maxVersion = " + c.getJre().getMaxVersion());
log.debug("jre.requiresJdk = " + c.getJre().getRequiresJdk());
log.debug("jre.requires64Bit = " + c.getJre().getRequires64Bit());
log.debug("jre.initialHeapSize = " + c.getJre().getInitialHeapSize());
log.debug("jre.initialHeapPercent = " + c.getJre().getInitialHeapPercent());
log.debug("jre.maxHeapSize = " + c.getJre().getMaxHeapSize());
log.debug("jre.maxHeapPercent = " + c.getJre().getMaxHeapPercent());
log.debug("jre.opts = " + c.getJre().getOptions());
} else {
log.debug("jre = null");
}
if (c.getClassPath() != null) {
log.debug("classPath.mainClass = " + c.getClassPath().getMainClass());
}
if (classPath != null) {
log.debug("classPath.addDependencies = " + classPath.addDependencies);
log.debug("classPath.jarLocation = " + classPath.jarLocation);
log.debug("classPath.preCp = " + classPath.preCp);
log.debug("classPath.postCp = " + classPath.postCp);
} else {
log.info("classpath = null");
}
if (c.getSplash() != null) {
log.debug("splash.file = " + c.getSplash().getFile());
log.debug("splash.waitForWindow = " + c.getSplash().getWaitForWindow());
log.debug("splash.timeout = " + c.getSplash().getTimeout());
log.debug("splash.timoutErr = " + c.getSplash().isTimeoutErr());
} else {
log.debug("splash = null");
}
if (c.getVersionInfo() != null) {
log.debug("versionInfo.fileVersion = " + c.getVersionInfo().getFileVersion());
log.debug("versionInfo.txtFileVersion = " + c.getVersionInfo().getTxtFileVersion());
log.debug("versionInfo.fileDescription = " + c.getVersionInfo().getFileDescription());
log.debug("versionInfo.copyright = " + c.getVersionInfo().getCopyright());
log.debug("versionInfo.productVersion = " + c.getVersionInfo().getProductVersion());
log.debug("versionInfo.txtProductVersion = " + c.getVersionInfo().getTxtProductVersion());
log.debug("versionInfo.productName = " + c.getVersionInfo().getProductName());
log.debug("versionInfo.companyName = " + c.getVersionInfo().getCompanyName());
log.debug("versionInfo.internalName = " + c.getVersionInfo().getInternalName());
log.debug("versionInfo.originalFilename = " + c.getVersionInfo().getOriginalFilename());
log.debug("versionInfo.language = " + c.getVersionInfo().getLanguage());
log.debug("versionInfo.languageIndex = " + c.getVersionInfo().getLanguageIndex());
log.debug("versionInfo.trademarks = " + c.getVersionInfo().getTrademarks());
} else {
log.debug("versionInfo = null");
}
if (c.getMessages() != null) {
log.debug("messages.startupErr = " + c.getMessages().getStartupErr());
log.debug("messages.jreNotFoundErr = " + c.getMessages().getJreNotFoundErr());
log.debug("messages.jreVersionErr = " + c.getMessages().getJreVersionErr());
log.debug("messages.launcherErr = " + c.getMessages().getLauncherErr());
log.debug("messages.instanceAlreadyExistsMsg = " + c.getMessages().getInstanceAlreadyExistsMsg());
} else {
log.debug("messages = null");
}
}
/**
* A version of the Launch4j used by the plugin.
* We want to download the platform-specific bundle whose version matches the Launch4j version,
* so we have to figure out what version the plugin is using.
*
* @return version of Launch4j
* @throws MojoExecutionException when version is null
*/
private String getLaunch4jVersion() throws MojoExecutionException {
String version = null;
Set pluginArtifacts = oldPluginArtifacts.stream().map(old ->
new DefaultArtifact(old.getGroupId(), old.getArtifactId(), old.getClassifier(), null, old.getVersion())
).collect(Collectors.toSet());
for (Artifact artifact : pluginArtifacts) {
if (launch4jGroupId.equals(artifact.getGroupId()) &&
launch4jArtifactId.equals(artifact.getArtifactId())
&& "core".equals(artifact.getClassifier())) {
version = artifact.getVersion();
getLog().info("Found launch4j version " + version);
break;
}
}
if (version == null) {
throw new MojoExecutionException("Impossible to find which Launch4j version to use, no compatible version found in classpath");
}
return version;
}
/**
* Checks if execution of the plugin should be skipped
*
* @return true to skip execution
*/
private boolean skipExecution() {
getLog().debug("skip = " + this.skip);
getLog().debug("skipLaunch4j = " + System.getProperty("skipLaunch4j"));
return skip || System.getProperty("skipLaunch4j") != null;
}
@Override
public String toString() {
return "Launch4jMojo{" +
"headerType='" + headerType + '\'' +
", infile=" + infile +
", outfile=" + outfile +
", jar='" + jar + '\'' +
", dontWrapJar=" + dontWrapJar +
", errTitle='" + errTitle + '\'' +
", downloadUrl='" + downloadUrl + '\'' +
", supportUrl='" + supportUrl + '\'' +
", cmdLine='" + cmdLine + '\'' +
", chdir='" + chdir + '\'' +
", priority='" + priority + '\'' +
", stayAlive=" + stayAlive +
", restartOnCrash=" + restartOnCrash +
", icon=" + icon +
", requireAdminRights=" + requireAdminRights +
", objs=" + objs +
", libs=" + libs +
", vars=" + vars +
", jre=" + jre +
", classPath=" + classPath +
", singleInstance=" + singleInstance +
", splash=" + splash +
", versionInfo=" + versionInfo +
", disableVersionInfoDefaults=" + disableVersionInfoDefaults +
", messages=" + messages +
", manifest=" + manifest +
", saveConfig=" + saveConfig +
", configOutfile=" + configOutfile +
", parallelExecution=" + parallelExecution +
", skip=" + skip +
'}';
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy