diff --git a/.github/workflows/nightly-artifacts.yml b/.github/workflows/nightly-artifacts.yml
index 4809147..5daba82 100644
--- a/.github/workflows/nightly-artifacts.yml
+++ b/.github/workflows/nightly-artifacts.yml
@@ -63,6 +63,8 @@ jobs:
shell: pwsh
run: |
New-Item -ItemType Directory -Force -Path dist | Out-Null
+ $addModules = & java packaging/AddModules.java
+ if ($LASTEXITCODE -ne 0) { throw "Failed to resolve --add-modules from module-info.java" }
jpackage `
--type app-image `
--name praktiKST `
@@ -71,7 +73,7 @@ jobs:
--main-jar app.jar `
--main-class kst4contest.view.Kst4ContestApplication `
--module-path target/dist-libs `
- --add-modules javafx.controls,javafx.graphics,javafx.fxml,javafx.web,javafx.media,java.sql,java.net.http,jdk.crypto.ec,jdk.net `
+ --add-modules $addModules `
--dest dist
- name: Create Windows ZIP
@@ -120,6 +122,7 @@ jobs:
- name: Build app-image with jpackage
run: |
mkdir -p dist
+ ADD_MODULES="$(java packaging/AddModules.java)"
jpackage \
--type app-image \
--name KST4Contest \
@@ -128,7 +131,7 @@ jobs:
--main-jar app.jar \
--main-class kst4contest.view.Kst4ContestApplication \
--module-path target/dist-libs \
- --add-modules javafx.controls,javafx.graphics,javafx.fxml,javafx.web,javafx.media,java.sql,java.net.http,jdk.crypto.ec,jdk.net \
+ --add-modules "$ADD_MODULES" \
--dest dist
- name: Create AppDir metadata
@@ -206,6 +209,7 @@ jobs:
- name: Build Debian package
run: |
mkdir -p dist
+ ADD_MODULES="$(java packaging/AddModules.java)"
jpackage \
--type deb \
--name KST4Contest \
@@ -214,7 +218,7 @@ jobs:
--main-jar app.jar \
--main-class kst4contest.view.Kst4ContestApplication \
--module-path target/dist-libs \
- --add-modules javafx.controls,javafx.graphics,javafx.fxml,javafx.web,javafx.media,java.sql,java.net.http,jdk.crypto.ec,jdk.net \
+ --add-modules "$ADD_MODULES" \
--linux-package-deps "libgstreamer1.0-0,libgstreamer-plugins-base1.0-0,gstreamer1.0-plugins-good" \
--dest dist
DEB="$(ls dist/*.deb | head -n 1)"
@@ -266,6 +270,7 @@ jobs:
- name: Build Fedora package
run: |
mkdir -p dist
+ ADD_MODULES="$(java packaging/AddModules.java)"
jpackage \
--type rpm \
--name KST4Contest \
@@ -274,7 +279,7 @@ jobs:
--main-jar app.jar \
--main-class kst4contest.view.Kst4ContestApplication \
--module-path target/dist-libs \
- --add-modules javafx.controls,javafx.graphics,javafx.fxml,javafx.web,javafx.media,java.sql,java.net.http,jdk.crypto.ec,jdk.net \
+ --add-modules "$ADD_MODULES" \
--linux-package-deps "gstreamer1,gstreamer1-plugins-base,gstreamer1-plugins-good" \
--dest dist
RPM="$(ls dist/*.rpm | head -n 1)"
@@ -328,6 +333,7 @@ jobs:
- name: Build app-image with jpackage
run: |
mkdir -p dist
+ ADD_MODULES="$(java packaging/AddModules.java)"
jpackage \
--type app-image \
--name KST4Contest \
@@ -336,7 +342,7 @@ jobs:
--main-jar app.jar \
--main-class kst4contest.view.Kst4ContestApplication \
--module-path target/dist-libs \
- --add-modules javafx.controls,javafx.graphics,javafx.fxml,javafx.web,javafx.media,java.sql,java.net.http,jdk.crypto.ec,jdk.net \
+ --add-modules "$ADD_MODULES" \
--dest dist
- name: Build Arch Linux package artifact
@@ -447,6 +453,7 @@ jobs:
./mvnw -B -DskipTests package dependency:copy-dependencies -DincludeScope=runtime -DoutputDirectory=target/dist-libs
cp "$(ls -t target/praktiKST-*.jar | head -n 1)" target/dist-libs/app.jar
mkdir -p target/flatpak-src
+ ADD_MODULES="$(java packaging/AddModules.java)"
jpackage \
--type app-image \
--name KST4Contest \
@@ -455,7 +462,7 @@ jobs:
--main-jar app.jar \
--main-class kst4contest.view.Kst4ContestApplication \
--module-path target/dist-libs \
- --add-modules javafx.controls,javafx.graphics,javafx.fxml,javafx.web,javafx.media,java.sql,java.net.http,jdk.crypto.ec,jdk.net \
+ --add-modules "$ADD_MODULES" \
--dest target/flatpak-src
- name: Create Flatpak manifest
@@ -635,6 +642,7 @@ jobs:
- name: Build macOS DMG with jpackage
run: |
mkdir -p dist
+ ADD_MODULES="$(java packaging/AddModules.java)"
jpackage \
--type dmg \
--name KST4Contest \
@@ -643,7 +651,7 @@ jobs:
--main-jar app.jar \
--main-class kst4contest.view.Kst4ContestApplication \
--module-path target/dist-libs \
- --add-modules javafx.controls,javafx.graphics,javafx.fxml,javafx.web,javafx.media,java.sql,java.net.http,jdk.crypto.ec,jdk.net \
+ --add-modules "$ADD_MODULES" \
--dest dist
env:
diff --git a/.github/workflows/pr-compile-check.yml b/.github/workflows/pr-compile-check.yml
index 9a11928..fd3228d 100644
--- a/.github/workflows/pr-compile-check.yml
+++ b/.github/workflows/pr-compile-check.yml
@@ -27,5 +27,8 @@ jobs:
- name: Ensure mvnw is executable
run: chmod +x mvnw
+ - name: Verify packaging module list matches module-info.java
+ run: java packaging/AddModules.java --verify-pom
+
- name: Compile
run: ./mvnw -B -DskipTests compile
diff --git a/.github/workflows/tagged-release.yml b/.github/workflows/tagged-release.yml
index 5e0b82e..56e3a4c 100644
--- a/.github/workflows/tagged-release.yml
+++ b/.github/workflows/tagged-release.yml
@@ -48,6 +48,8 @@ jobs:
shell: pwsh
run: |
New-Item -ItemType Directory -Force -Path dist | Out-Null
+ $addModules = & java packaging/AddModules.java
+ if ($LASTEXITCODE -ne 0) { throw "Failed to resolve --add-modules from module-info.java" }
jpackage `
--type app-image `
--name praktiKST `
@@ -56,7 +58,7 @@ jobs:
--main-jar app.jar `
--main-class kst4contest.view.Kst4ContestApplication `
--module-path target/dist-libs `
- --add-modules javafx.controls,javafx.graphics,javafx.fxml,javafx.web,javafx.media,java.sql,java.net.http,jdk.crypto.ec,jdk.net `
+ --add-modules $addModules `
--dest dist
- name: Create Windows ZIP
@@ -98,6 +100,7 @@ jobs:
- name: Build app-image with jpackage
run: |
mkdir -p dist
+ ADD_MODULES="$(java packaging/AddModules.java)"
jpackage \
--type app-image \
--name KST4Contest \
@@ -106,7 +109,7 @@ jobs:
--main-jar app.jar \
--main-class kst4contest.view.Kst4ContestApplication \
--module-path target/dist-libs \
- --add-modules javafx.controls,javafx.graphics,javafx.fxml,javafx.web,javafx.media,java.sql,java.net.http,jdk.crypto.ec,jdk.net \
+ --add-modules "$ADD_MODULES" \
--dest dist
- name: Create AppDir metadata
@@ -177,6 +180,7 @@ jobs:
- name: Build Debian package
run: |
mkdir -p dist
+ ADD_MODULES="$(java packaging/AddModules.java)"
jpackage \
--type deb \
--name KST4Contest \
@@ -185,7 +189,7 @@ jobs:
--main-jar app.jar \
--main-class kst4contest.view.Kst4ContestApplication \
--module-path target/dist-libs \
- --add-modules javafx.controls,javafx.graphics,javafx.fxml,javafx.web,javafx.media,java.sql,java.net.http,jdk.crypto.ec,jdk.net \
+ --add-modules "$ADD_MODULES" \
--linux-package-deps "libgstreamer1.0-0,libgstreamer-plugins-base1.0-0,gstreamer1.0-plugins-good" \
--dest dist
DEB="$(ls dist/*.deb | head -n 1)"
@@ -230,6 +234,7 @@ jobs:
- name: Build Fedora package
run: |
mkdir -p dist
+ ADD_MODULES="$(java packaging/AddModules.java)"
jpackage \
--type rpm \
--name KST4Contest \
@@ -238,7 +243,7 @@ jobs:
--main-jar app.jar \
--main-class kst4contest.view.Kst4ContestApplication \
--module-path target/dist-libs \
- --add-modules javafx.controls,javafx.graphics,javafx.fxml,javafx.web,javafx.media,java.sql,java.net.http,jdk.crypto.ec,jdk.net \
+ --add-modules "$ADD_MODULES" \
--linux-package-deps "gstreamer1,gstreamer1-plugins-base,gstreamer1-plugins-good" \
--dest dist
RPM="$(ls dist/*.rpm | head -n 1)"
@@ -283,6 +288,7 @@ jobs:
- name: Build app-image with jpackage
run: |
mkdir -p dist
+ ADD_MODULES="$(java packaging/AddModules.java)"
jpackage \
--type app-image \
--name KST4Contest \
@@ -291,7 +297,7 @@ jobs:
--main-jar app.jar \
--main-class kst4contest.view.Kst4ContestApplication \
--module-path target/dist-libs \
- --add-modules javafx.controls,javafx.graphics,javafx.fxml,javafx.web,javafx.media,java.sql,java.net.http,jdk.crypto.ec,jdk.net \
+ --add-modules "$ADD_MODULES" \
--dest dist
- name: Build Arch Linux package artifact
@@ -393,6 +399,7 @@ jobs:
./mvnw -B -DskipTests package dependency:copy-dependencies -DincludeScope=runtime -DoutputDirectory=target/dist-libs
cp "$(ls -t target/praktiKST-*.jar | head -n 1)" target/dist-libs/app.jar
mkdir -p target/flatpak-src
+ ADD_MODULES="$(java packaging/AddModules.java)"
jpackage \
--type app-image \
--name KST4Contest \
@@ -401,7 +408,7 @@ jobs:
--main-jar app.jar \
--main-class kst4contest.view.Kst4ContestApplication \
--module-path target/dist-libs \
- --add-modules javafx.controls,javafx.graphics,javafx.fxml,javafx.web,javafx.media,java.sql,java.net.http,jdk.crypto.ec,jdk.net \
+ --add-modules "$ADD_MODULES" \
--dest target/flatpak-src
- name: Create Flatpak manifest
@@ -523,6 +530,7 @@ jobs:
- name: Build macOS DMG with jpackage
run: |
mkdir -p dist
+ ADD_MODULES="$(java packaging/AddModules.java)"
jpackage \
--type dmg \
--name KST4Contest \
@@ -531,7 +539,7 @@ jobs:
--main-jar app.jar \
--main-class kst4contest.view.Kst4ContestApplication \
--module-path target/dist-libs \
- --add-modules javafx.controls,javafx.graphics,javafx.fxml,javafx.web,javafx.media,java.sql,java.net.http,jdk.crypto.ec,jdk.net \
+ --add-modules "$ADD_MODULES" \
--dest dist
env:
diff --git a/packaging/AddModules.java b/packaging/AddModules.java
new file mode 100644
index 0000000..e3d8f2b
--- /dev/null
+++ b/packaging/AddModules.java
@@ -0,0 +1,128 @@
+/*
+ * Derives the jpackage --add-modules list from module-info.java so that the
+ * packaging scripts never drift from the module descriptor again.
+ *
+ * Run as a single file source program, which behaves identically on the Linux,
+ * macOS and Windows runners:
+ *
+ * java packaging/AddModules.java print the module list
+ * java packaging/AddModules.java --verify-pom fail if pom.xml drifted
+ *
+ * Only platform modules are emitted. Third party requires such as jlayer are
+ * skipped because they are supplied as ordinary jars on the class path, and
+ * automatic modules cannot be linked into a runtime image at all. Test only
+ * requires such as org.junit.jupiter.api are skipped for the same reason.
+ */
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public final class AddModules {
+
+ private static final Path DESCRIPTOR =
+ Path.of("src", "main", "java", "module-info.java");
+
+ private static final Path POM = Path.of("pom.xml");
+
+ /** Matches "requires [transitive] [static] some.module;" in any order. */
+ private static final Pattern REQUIRES = Pattern.compile(
+ "requires\\s+((?:transitive\\s+|static\\s+)*)([A-Za-z0-9_.]+)\\s*;");
+
+ private static final Pattern ADD_MODULE =
+ Pattern.compile("\\s*([A-Za-z0-9_.]+)\\s*");
+
+ private static final Pattern BLOCK_COMMENT =
+ Pattern.compile("/\\*.*?\\*/", Pattern.DOTALL);
+
+ private static final Pattern LINE_COMMENT = Pattern.compile("//[^\\n]*");
+
+ private AddModules() {
+ }
+
+ public static void main(String[] args) throws IOException {
+ boolean verifyPom = args.length > 0 && "--verify-pom".equals(args[0]);
+
+ Set required = platformModules(read(DESCRIPTOR));
+ if (required.isEmpty()) {
+ fail("No platform modules found in " + DESCRIPTOR);
+ }
+
+ if (!verifyPom) {
+ System.out.println(String.join(",", required));
+ return;
+ }
+
+ Set declared = new TreeSet<>();
+ Matcher matcher = ADD_MODULE.matcher(read(POM));
+ while (matcher.find()) {
+ declared.add(matcher.group(1));
+ }
+
+ if (declared.equals(required)) {
+ System.out.println("pom.xml matches module-info.java ("
+ + required.size() + " modules)");
+ return;
+ }
+
+ Set missing = new TreeSet<>(required);
+ missing.removeAll(declared);
+ Set extra = new TreeSet<>(declared);
+ extra.removeAll(required);
+
+ System.err.println("pom.xml drifted from module-info.java.");
+ if (!missing.isEmpty()) {
+ System.err.println(" missing in pom.xml: " + String.join(", ", missing));
+ }
+ if (!extra.isEmpty()) {
+ System.err.println(" not required by module-info.java: "
+ + String.join(", ", extra));
+ }
+ System.err.println(" expected: " + String.join(",", required));
+ System.exit(1);
+ }
+
+ /** Returns the platform modules required by the given descriptor, sorted. */
+ static Set platformModules(String source) {
+ String stripped = LINE_COMMENT.matcher(
+ BLOCK_COMMENT.matcher(source).replaceAll(" ")).replaceAll(" ");
+
+ Set modules = new TreeSet<>();
+ Matcher matcher = REQUIRES.matcher(stripped);
+ while (matcher.find()) {
+ // "requires static" is a compile time only dependency and must not
+ // be linked into the shipped runtime image.
+ if (matcher.group(1).contains("static")) {
+ continue;
+ }
+ String module = matcher.group(2);
+ if (isPlatformModule(module)) {
+ modules.add(module);
+ }
+ }
+ return modules;
+ }
+
+ private static boolean isPlatformModule(String module) {
+ return module.startsWith("java.")
+ || module.startsWith("jdk.")
+ || module.startsWith("javafx.");
+ }
+
+ private static String read(Path path) throws IOException {
+ if (!Files.isRegularFile(path)) {
+ fail("Not found: " + path.toAbsolutePath()
+ + " (run this from the repository root)");
+ }
+ return Files.readString(path);
+ }
+
+ private static void fail(String message) {
+ System.err.println(message);
+ System.exit(2);
+ }
+}
diff --git a/packaging/aur/kst4contest-git/PKGBUILD b/packaging/aur/kst4contest-git/PKGBUILD
index ca3fb74..4452949 100644
--- a/packaging/aur/kst4contest-git/PKGBUILD
+++ b/packaging/aur/kst4contest-git/PKGBUILD
@@ -33,6 +33,7 @@ build() {
cp "$(ls -t target/praktiKST-*.jar | head -n 1)" target/dist-libs/app.jar
mkdir -p dist
+ ADD_MODULES="$(java packaging/AddModules.java)"
jpackage \
--type app-image \
--name KST4Contest \
@@ -40,7 +41,7 @@ build() {
--main-jar app.jar \
--main-class kst4contest.view.Kst4ContestApplication \
--module-path target/dist-libs \
- --add-modules javafx.controls,javafx.graphics,javafx.fxml,javafx.web,javafx.media,java.sql,java.net.http,jdk.crypto.ec,jdk.net \
+ --add-modules "$ADD_MODULES" \
--dest dist
}
diff --git a/packaging/aur/kst4contest/PKGBUILD b/packaging/aur/kst4contest/PKGBUILD
index 467b08b..7ce00d8 100644
--- a/packaging/aur/kst4contest/PKGBUILD
+++ b/packaging/aur/kst4contest/PKGBUILD
@@ -26,6 +26,14 @@ build() {
cp "$(ls -t target/praktiKST-*.jar | head -n 1)" target/dist-libs/app.jar
mkdir -p dist
+ # This PKGBUILD builds from a released source tarball, which may predate
+ # packaging/AddModules.java. Older tarballs carry the same list in pom.xml,
+ # which the build keeps in sync with module-info.java from v1.42.0 onwards.
+ if [ -f packaging/AddModules.java ]; then
+ ADD_MODULES="$(java packaging/AddModules.java)"
+ else
+ ADD_MODULES="$(sed -n 's:.*\(.*\).*:\1:p' pom.xml | paste -sd,)"
+ fi
jpackage \
--type app-image \
--name KST4Contest \
@@ -33,7 +41,7 @@ build() {
--main-jar app.jar \
--main-class kst4contest.view.Kst4ContestApplication \
--module-path target/dist-libs \
- --add-modules javafx.controls,javafx.graphics,javafx.fxml,javafx.web,javafx.media,java.sql,java.net.http,jdk.crypto.ec,jdk.net \
+ --add-modules "$ADD_MODULES" \
--dest dist
}
diff --git a/pom.xml b/pom.xml
index a167eb8..eca17aa 100644
--- a/pom.xml
+++ b/pom.xml
@@ -56,6 +56,7 @@
0.0.8
4.9.8.2
4.9.8
+ 3.1.0
UTF-8
@@ -208,6 +209,36 @@
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ ${exec.maven.plugin}
+
+
+ verify-packaging-module-list
+ validate
+
+ exec
+
+
+ ${java.home}/bin/java
+ ${project.basedir}
+
+ packaging/AddModules.java
+ --verify-pom
+
+
+
+
+
+
org.apache.maven.plugins
maven-compiler-plugin
@@ -436,16 +467,26 @@
+
- javafx.controls
- javafx.graphics
- javafx.fxml
- javafx.web
- javafx.media
- java.sql
+ java.desktop
java.net.http
+ java.sql
+ javafx.controls
+ javafx.fxml
+ javafx.media
+ javafx.web
jdk.crypto.ec
+ jdk.jsobject
jdk.net
+ jdk.xml.dom
${main.class}
${project.build.directory}/modules