Make JAR packaging portable across desktop systems
This commit is contained in:
@@ -29,7 +29,6 @@
|
|||||||
<atlantafx.version>2.0.1</atlantafx.version>
|
<atlantafx.version>2.0.1</atlantafx.version>
|
||||||
<ikonli.version>12.4.0</ikonli.version>
|
<ikonli.version>12.4.0</ikonli.version>
|
||||||
<!-- 指定 JDK 17 路径(系统默认 JDK 8 时启用) -->
|
<!-- 指定 JDK 17 路径(系统默认 JDK 8 时启用) -->
|
||||||
<jdk17.home>C:\Program Files\Java\jdk-17</jdk17.home>
|
|
||||||
</properties>
|
</properties>
|
||||||
<repositories>
|
<repositories>
|
||||||
<!-- AtlantaFX Maven 仓库 -->
|
<!-- AtlantaFX Maven 仓库 -->
|
||||||
@@ -214,9 +213,6 @@
|
|||||||
<configuration>
|
<configuration>
|
||||||
<release>17</release>
|
<release>17</release>
|
||||||
<verbose>true</verbose>
|
<verbose>true</verbose>
|
||||||
<fork>true</fork>
|
|
||||||
<executable>${jdk17.home}\bin\javac</executable>
|
|
||||||
<compilerVersion>17</compilerVersion>
|
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
@@ -234,36 +230,6 @@
|
|||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
<plugin>
|
|
||||||
<groupId>com.akathist.maven.plugins.launch4j</groupId>
|
|
||||||
<artifactId>launch4j-maven-plugin</artifactId>
|
|
||||||
<version>2.5.3</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>l4j-exe</id>
|
|
||||||
<phase>package</phase>
|
|
||||||
<goals><goal>launch4j</goal></goals>
|
|
||||||
<configuration>
|
|
||||||
<headerType>gui</headerType>
|
|
||||||
<jar>${project.build.directory}/${project.build.finalName}.jar</jar>
|
|
||||||
<outfile>${project.build.directory}/workutils.exe</outfile>
|
|
||||||
<icon>${project.basedir}/src/main/resources/app_icon.ico</icon>
|
|
||||||
<dontWrapJar>false</dontWrapJar>
|
|
||||||
<classPath>
|
|
||||||
<mainClass>org.springframework.boot.loader.JarLauncher</mainClass>
|
|
||||||
</classPath>
|
|
||||||
<jre>
|
|
||||||
<path>jre</path>
|
|
||||||
<minVersion>17</minVersion>
|
|
||||||
<opts>
|
|
||||||
<opt>-Dfile.encoding=UTF-8</opt>
|
|
||||||
</opts>
|
|
||||||
</jre>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
<!-- 复制启动脚本到 target 目录 -->
|
<!-- 复制启动脚本到 target 目录 -->
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
@@ -280,7 +246,7 @@
|
|||||||
<resource>
|
<resource>
|
||||||
<directory>${basedir}/scripts</directory>
|
<directory>${basedir}/scripts</directory>
|
||||||
<includes>
|
<includes>
|
||||||
<include>start.bat</include>
|
<include>start.sh</include>
|
||||||
</includes>
|
</includes>
|
||||||
</resource>
|
</resource>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -294,15 +260,62 @@
|
|||||||
|
|
||||||
<profiles>
|
<profiles>
|
||||||
<profile>
|
<profile>
|
||||||
<id>jdk17-home-env</id>
|
<id>windows-package</id>
|
||||||
<activation>
|
<activation>
|
||||||
<property>
|
<os><family>Windows</family></os>
|
||||||
<name>env.JDK17_HOME</name>
|
|
||||||
</property>
|
|
||||||
</activation>
|
</activation>
|
||||||
<properties>
|
<build>
|
||||||
<jdk17.home>${env.JDK17_HOME}</jdk17.home>
|
<plugins>
|
||||||
</properties>
|
<plugin>
|
||||||
|
<groupId>com.akathist.maven.plugins.launch4j</groupId>
|
||||||
|
<artifactId>launch4j-maven-plugin</artifactId>
|
||||||
|
<version>2.5.3</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>l4j-exe</id>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals><goal>launch4j</goal></goals>
|
||||||
|
<configuration>
|
||||||
|
<headerType>gui</headerType>
|
||||||
|
<jar>${project.build.directory}/${project.build.finalName}.jar</jar>
|
||||||
|
<outfile>${project.build.directory}/workutils.exe</outfile>
|
||||||
|
<icon>${project.basedir}/src/main/resources/app_icon.ico</icon>
|
||||||
|
<dontWrapJar>false</dontWrapJar>
|
||||||
|
<classPath>
|
||||||
|
<mainClass>org.springframework.boot.loader.JarLauncher</mainClass>
|
||||||
|
</classPath>
|
||||||
|
<jre>
|
||||||
|
<path>jre</path>
|
||||||
|
<minVersion>17</minVersion>
|
||||||
|
<opts><opt>-Dfile.encoding=UTF-8</opt></opts>
|
||||||
|
</jre>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-resources-plugin</artifactId>
|
||||||
|
<version>3.2.0</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>copy-windows-start-script</id>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals><goal>copy-resources</goal></goals>
|
||||||
|
<configuration>
|
||||||
|
<outputDirectory>${project.build.directory}</outputDirectory>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>${basedir}/scripts</directory>
|
||||||
|
<includes><include>start.bat</include></includes>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
</profile>
|
</profile>
|
||||||
</profiles>
|
</profiles>
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -52,5 +52,5 @@ echo Java: %JAVA_VER% ^( %JAVA_EXE% ^)
|
|||||||
echo ====================================
|
echo ====================================
|
||||||
echo.
|
echo.
|
||||||
|
|
||||||
"%JAVA_EXE%" -Dfile.encoding=UTF-8 -jar "%JAR%" %*
|
"%JAVA_EXE%" -Dfile.encoding=UTF-8 "-Dworkutils.home=%CD%" -jar "%JAR%" %*
|
||||||
if %errorlevel% neq 0 pause
|
if %errorlevel% neq 0 pause
|
||||||
|
|||||||
@@ -0,0 +1,109 @@
|
|||||||
|
package com.example.workutils.system.support;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
import org.w3c.dom.Node;
|
||||||
|
import org.w3c.dom.NodeList;
|
||||||
|
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
class BuildPortabilityTest {
|
||||||
|
|
||||||
|
private final Path projectRoot = Path.of("").toAbsolutePath().normalize();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void compilerUsesTheMavenJdkWithoutAnExternalExecutable() throws Exception {
|
||||||
|
Document pom = parsePom();
|
||||||
|
Element compiler = pluginUnder(directChild(element(pom, "project"), "build"),
|
||||||
|
"maven-compiler-plugin");
|
||||||
|
|
||||||
|
assertEquals("17", childText(directChild(compiler, "configuration"), "release"));
|
||||||
|
assertFalse(hasDirectChild(directChild(compiler, "configuration"), "executable"));
|
||||||
|
assertFalse(hasDirectChild(directChild(compiler, "configuration"), "fork"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void launch4jOnlyBelongsToTheWindowsProfile() throws Exception {
|
||||||
|
Document pom = parsePom();
|
||||||
|
Element project = element(pom, "project");
|
||||||
|
assertFalse(hasPlugin(directChild(project, "build"), "launch4j-maven-plugin"));
|
||||||
|
|
||||||
|
Element windowsProfile = profile(project, "windows-package");
|
||||||
|
assertEquals("Windows", childText(directChild(directChild(windowsProfile, "activation"), "os"), "family"));
|
||||||
|
assertTrue(hasPlugin(directChild(windowsProfile, "build"), "launch4j-maven-plugin"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void portableShellLauncherIsShippedByTheDefaultBuild() throws Exception {
|
||||||
|
assertTrue(Files.isRegularFile(projectRoot.resolve(Path.of("scripts", "start.sh"))));
|
||||||
|
Document pom = parsePom();
|
||||||
|
Element resourcesPlugin = pluginUnder(
|
||||||
|
directChild(element(parsePom(), "project"), "build"), "maven-resources-plugin");
|
||||||
|
assertTrue(resourcesPlugin.getTextContent().contains("start.sh"));
|
||||||
|
assertFalse(resourcesPlugin.getTextContent().contains("start.bat"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Document parsePom() throws Exception {
|
||||||
|
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||||
|
factory.setNamespaceAware(false);
|
||||||
|
return factory.newDocumentBuilder().parse(projectRoot.resolve("pom.xml").toFile());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Element element(Document document, String name) {
|
||||||
|
return (Element) document.getElementsByTagName(name).item(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Element directChild(Element parent, String name) {
|
||||||
|
for (Node node = parent.getFirstChild(); node != null; node = node.getNextSibling()) {
|
||||||
|
if (node instanceof Element child && name.equals(child.getTagName())) return child;
|
||||||
|
}
|
||||||
|
throw new AssertionError("Missing element " + name + " under " + parent.getTagName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean hasDirectChild(Element parent, String name) {
|
||||||
|
for (Node node = parent.getFirstChild(); node != null; node = node.getNextSibling()) {
|
||||||
|
if (node instanceof Element child && name.equals(child.getTagName())) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String childText(Element parent, String name) {
|
||||||
|
return directChild(parent, name).getTextContent().trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Element pluginUnder(Element build, String artifactId) {
|
||||||
|
Element plugins = directChild(build, "plugins");
|
||||||
|
NodeList nodes = plugins.getElementsByTagName("plugin");
|
||||||
|
for (int i = 0; i < nodes.getLength(); i++) {
|
||||||
|
Element plugin = (Element) nodes.item(i);
|
||||||
|
if (artifactId.equals(childText(plugin, "artifactId"))) return plugin;
|
||||||
|
}
|
||||||
|
throw new AssertionError("Missing plugin " + artifactId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean hasPlugin(Element build, String artifactId) {
|
||||||
|
try {
|
||||||
|
pluginUnder(build, artifactId);
|
||||||
|
return true;
|
||||||
|
} catch (AssertionError ignored) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Element profile(Element project, String id) {
|
||||||
|
Element profiles = directChild(project, "profiles");
|
||||||
|
NodeList nodes = profiles.getElementsByTagName("profile");
|
||||||
|
for (int i = 0; i < nodes.getLength(); i++) {
|
||||||
|
Element profile = (Element) nodes.item(i);
|
||||||
|
if (id.equals(childText(profile, "id"))) return profile;
|
||||||
|
}
|
||||||
|
throw new AssertionError("Missing profile " + id);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user