diff --git a/app/build.gradle b/app/build.gradle index fba2aa01f..0b900d792 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -97,7 +97,7 @@ jar { application { mainModule = groupName + '.app' mainClass = groupName + '.app.Main' - applicationDefaultJvmArgs = jvmRunArgs + applicationDefaultJvmArgs = daemonJvmRunArgs } run { @@ -136,7 +136,7 @@ tasks.register('runAttachedDebugger', JavaExec) { mainModule = groupName + '.app' mainClass = groupName + '.app.Main' modularity.inferModulePath = true - jvmArgs += jvmRunArgs + jvmArgs += daemonJvmRunArgs jvmArgs += List.of( "-javaagent:${System.getProperty("user.home")}/.attachme/attachme-agent-1.2.9.jar=port:7857,host:localhost".toString(), "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=127.0.0.1:0" diff --git a/app/src/main/java/io/xpipe/app/action/ActionProvider.java b/app/src/main/java/io/xpipe/app/action/ActionProvider.java index 3abeb1f44..5b50442d3 100644 --- a/app/src/main/java/io/xpipe/app/action/ActionProvider.java +++ b/app/src/main/java/io/xpipe/app/action/ActionProvider.java @@ -59,5 +59,10 @@ public interface ActionProvider { .map(p -> p.get()) .toList()); } + + @Override + public boolean initForCli() { + return false; + } } } diff --git a/app/src/main/java/io/xpipe/app/beacon/AppBeaconServer.java b/app/src/main/java/io/xpipe/app/beacon/AppBeaconServer.java index 332e33a70..1cc25af2d 100644 --- a/app/src/main/java/io/xpipe/app/beacon/AppBeaconServer.java +++ b/app/src/main/java/io/xpipe/app/beacon/AppBeaconServer.java @@ -57,7 +57,7 @@ public class AppBeaconServer { public static void init() { try { // We already queried the beacon port at this point, so this will always work - INSTANCE = new AppBeaconServer(AppProperties.get().queryEffectiveBeaconPort(false).orElse(AppProperties.get().getDefaultBeaconPort())); + INSTANCE = new AppBeaconServer(AppProperties.get().queryEffectiveBeaconPort(false).orElseThrow()); INSTANCE.initAuthSecret(); INSTANCE.start(); TrackEvent.withInfo("Started http server") diff --git a/app/src/main/java/io/xpipe/app/core/AppArguments.java b/app/src/main/java/io/xpipe/app/core/AppArguments.java index 476532412..870a5de18 100644 --- a/app/src/main/java/io/xpipe/app/core/AppArguments.java +++ b/app/src/main/java/io/xpipe/app/core/AppArguments.java @@ -20,13 +20,15 @@ public class AppArguments { private static final Pattern PROPERTY_PATTERN = Pattern.compile("^-[DP](.+)=(.+)$"); List rawArgs; List resolvedArgs; - List openArgs; + List daemonOpenArgs; public static AppArguments init(String[] args) { var rawArgs = Arrays.asList(args); var resolvedArgs = Arrays.asList(parseProperties(args)); - var command = LauncherCommand.resolveLauncher(resolvedArgs.toArray(String[]::new)); - return new AppArguments(rawArgs, resolvedArgs, command.inputs); + var isDaemon = Boolean.getBoolean("io.xpipe.app.isDaemon"); + var openArgs = !isDaemon ? List.of() : + LauncherCommand.resolveLauncher(resolvedArgs.toArray(String[]::new)).inputs; + return new AppArguments(rawArgs, resolvedArgs, openArgs); } private static String[] parseProperties(String[] args) { diff --git a/app/src/main/java/io/xpipe/app/core/AppInstance.java b/app/src/main/java/io/xpipe/app/core/AppInstance.java index c0da8143e..a2a0cc2b2 100644 --- a/app/src/main/java/io/xpipe/app/core/AppInstance.java +++ b/app/src/main/java/io/xpipe/app/core/AppInstance.java @@ -71,7 +71,7 @@ public class AppInstance { } try { - var inputs = AppProperties.get().getArguments().getOpenArgs(); + var inputs = AppProperties.get().getArguments().getDaemonOpenArgs(); // Assume that we want to open the GUI if we launched again client.get().performRequest(DaemonFocusExchange.Request.builder().build()); if (!inputs.isEmpty()) { diff --git a/app/src/main/java/io/xpipe/app/core/AppOpenArguments.java b/app/src/main/java/io/xpipe/app/core/AppOpenArguments.java index 4d8e0a8b2..c7e157fcd 100644 --- a/app/src/main/java/io/xpipe/app/core/AppOpenArguments.java +++ b/app/src/main/java/io/xpipe/app/core/AppOpenArguments.java @@ -21,7 +21,7 @@ public class AppOpenArguments { private static final List bufferedArguments = new ArrayList<>(); public static synchronized void init() { - handleImpl(AppProperties.get().getArguments().getOpenArgs()); + handleImpl(AppProperties.get().getArguments().getDaemonOpenArgs()); handleImpl(bufferedArguments); bufferedArguments.clear(); } diff --git a/app/src/main/java/io/xpipe/app/core/AppProperties.java b/app/src/main/java/io/xpipe/app/core/AppProperties.java index 4142dc222..010b87f5e 100644 --- a/app/src/main/java/io/xpipe/app/core/AppProperties.java +++ b/app/src/main/java/io/xpipe/app/core/AppProperties.java @@ -97,6 +97,7 @@ public class AppProperties { .getLocation() .getProtocol() .equals("jrt"); + arguments = AppArguments.init(args); fullVersion = Optional.ofNullable(System.getProperty(AppNames.propertyName("fullVersion"))) .map(Boolean::parseBoolean) .orElse(false); @@ -178,7 +179,6 @@ public class AppProperties { isDaemon = Optional.ofNullable(System.getProperty(AppNames.propertyName("isDaemon"))) .map(Boolean::parseBoolean) .orElse(!isCli); - arguments = AppArguments.init(isDaemon ? args : new String[0]); // We require the user dir from here AppDirectoryPermissionsCheck.checkDirectory(dataDir); @@ -211,24 +211,25 @@ public class AppProperties { } public OptionalInt queryEffectiveBeaconPort(boolean reachable) { + if (effectiveBeaconPort != null) { + return OptionalInt.of(effectiveBeaconPort); + } + if (!reachable) { effectiveBeaconPort = getDefaultBeaconPort(); return OptionalInt.of(effectiveBeaconPort); } var authFile = getBeaconAuthFile(); - if (!Files.exists(authFile)) { + if (Files.exists(authFile)) { effectiveBeaconPort = getDefaultBeaconPort(); return OptionalInt.of(effectiveBeaconPort); } - if (effectiveBeaconPort != null) { - return OptionalInt.of(effectiveBeaconPort); - } - var hasEnv = System.getenv("BEACON_PORT") != null || System.getenv("XPIPE_BEACON_PORT") != null; if (hasEnv) { - return OptionalInt.empty(); + effectiveBeaconPort = getDefaultBeaconPort(); + return OptionalInt.of(effectiveBeaconPort); } var start = 21723; @@ -330,7 +331,7 @@ public class AppProperties { TrackEvent.withInfo("Received arguments") .tag("raw", arguments.getRawArgs()) .tag("resolved", arguments.getResolvedArgs()) - .tag("resolvedCommand", arguments.getOpenArgs()) + .tag("resolvedCommand", arguments.getDaemonOpenArgs()) .handle(); for (var e : System.getProperties().entrySet()) { diff --git a/app/src/main/java/io/xpipe/app/core/mode/AppOperationMode.java b/app/src/main/java/io/xpipe/app/core/mode/AppOperationMode.java index 8d5f62a24..12ae9f6a9 100644 --- a/app/src/main/java/io/xpipe/app/core/mode/AppOperationMode.java +++ b/app/src/main/java/io/xpipe/app/core/mode/AppOperationMode.java @@ -20,6 +20,7 @@ import io.xpipe.app.storage.DataStorage; import io.xpipe.app.update.AppDistributionType; import io.xpipe.app.util.*; import io.xpipe.core.FailableRunnable; +import io.xpipe.core.ModuleLayerLoader; import io.xpipe.core.XPipeDaemonMode; import javafx.application.Platform; @@ -115,12 +116,12 @@ public abstract class AppOperationMode { AppProperties.init(args); if (AppProperties.get().isCli()) { - CliProvider.init(ModuleLayer.boot()); + ModuleLayerLoader.loadAll(ModuleLayer.boot(), throwable -> throwable.printStackTrace()); var cli = CliProvider.get(); if (cli == null) { throw ExtensionException.corrupt("Missing cli module"); } - var r = cli.execute(args); + var r = cli.execute(AppProperties.get().getArguments().getResolvedArgs().toArray(String[]::new)); if (AppProperties.get().isAotTrainMode()) { r = 0; } diff --git a/app/src/main/java/io/xpipe/app/ext/CliProvider.java b/app/src/main/java/io/xpipe/app/ext/CliProvider.java index 3efd54fc3..9195013c2 100644 --- a/app/src/main/java/io/xpipe/app/ext/CliProvider.java +++ b/app/src/main/java/io/xpipe/app/ext/CliProvider.java @@ -1,22 +1,35 @@ package io.xpipe.app.ext; +import io.xpipe.beacon.BeaconInterface; +import io.xpipe.core.ModuleLayerLoader; + import java.util.OptionalInt; import java.util.ServiceLoader; +import java.util.stream.Collectors; public abstract class CliProvider { private static CliProvider INSTANCE; - public static void init(ModuleLayer layer) { - INSTANCE = ServiceLoader.load(layer, CliProvider.class).stream() - .map(p -> p.get()) - .findFirst() - .orElse(null); - } - public static CliProvider get() { return INSTANCE; } public abstract int execute(String[] args); + + public static class Loader implements ModuleLayerLoader { + + @Override + public void init(ModuleLayer layer) { + INSTANCE = ServiceLoader.load(layer, CliProvider.class).stream() + .map(p -> p.get()) + .findFirst() + .orElse(null); + } + + @Override + public boolean initForCli() { + return true; + } + } } diff --git a/app/src/main/java/io/xpipe/app/ext/CloudSetupProvider.java b/app/src/main/java/io/xpipe/app/ext/CloudSetupProvider.java index 68f7aa003..811be3927 100644 --- a/app/src/main/java/io/xpipe/app/ext/CloudSetupProvider.java +++ b/app/src/main/java/io/xpipe/app/ext/CloudSetupProvider.java @@ -32,5 +32,10 @@ public interface CloudSetupProvider { .map(p -> p.get()) .toList()); } + + @Override + public boolean initForCli() { + return false; + } } } diff --git a/app/src/main/java/io/xpipe/app/ext/DataStorageExtensionProvider.java b/app/src/main/java/io/xpipe/app/ext/DataStorageExtensionProvider.java index 855a615a5..3affad520 100644 --- a/app/src/main/java/io/xpipe/app/ext/DataStorageExtensionProvider.java +++ b/app/src/main/java/io/xpipe/app/ext/DataStorageExtensionProvider.java @@ -27,5 +27,10 @@ public abstract class DataStorageExtensionProvider { scanProvider -> scanProvider.getClass().getName())) .collect(Collectors.toList()); } + + @Override + public boolean initForCli() { + return false; + } } } diff --git a/app/src/main/java/io/xpipe/app/ext/DataStoreProviders.java b/app/src/main/java/io/xpipe/app/ext/DataStoreProviders.java index 9b3f7304b..18847b89c 100644 --- a/app/src/main/java/io/xpipe/app/ext/DataStoreProviders.java +++ b/app/src/main/java/io/xpipe/app/ext/DataStoreProviders.java @@ -90,5 +90,10 @@ public class DataStoreProviders { }); } } + + @Override + public boolean initForCli() { + return false; + } } } diff --git a/app/src/main/java/io/xpipe/app/ext/PrefsProvider.java b/app/src/main/java/io/xpipe/app/ext/PrefsProvider.java index 62e214b48..95b2346b7 100644 --- a/app/src/main/java/io/xpipe/app/ext/PrefsProvider.java +++ b/app/src/main/java/io/xpipe/app/ext/PrefsProvider.java @@ -36,5 +36,10 @@ public abstract class PrefsProvider { .map(ServiceLoader.Provider::get) .collect(Collectors.toList()); } + + @Override + public boolean initForCli() { + return false; + } } } diff --git a/app/src/main/java/io/xpipe/app/ext/ScanProvider.java b/app/src/main/java/io/xpipe/app/ext/ScanProvider.java index 4dd8a2ba4..0346000d6 100644 --- a/app/src/main/java/io/xpipe/app/ext/ScanProvider.java +++ b/app/src/main/java/io/xpipe/app/ext/ScanProvider.java @@ -43,6 +43,11 @@ public abstract class ScanProvider { scanProvider -> scanProvider.getClass().getName())) .collect(Collectors.toList()); } + + @Override + public boolean initForCli() { + return false; + } } @Value diff --git a/app/src/main/java/io/xpipe/app/process/ShellDialects.java b/app/src/main/java/io/xpipe/app/process/ShellDialects.java index d7fd61f64..d8a450642 100644 --- a/app/src/main/java/io/xpipe/app/process/ShellDialects.java +++ b/app/src/main/java/io/xpipe/app/process/ShellDialects.java @@ -71,9 +71,7 @@ public class ShellDialects { @Override public void init(ModuleLayer layer) { - var services = layer != null - ? ServiceLoader.load(layer, ShellDialect.class) - : ServiceLoader.load(ShellDialect.class); + var services = ServiceLoader.load(layer, ShellDialect.class); services.stream().forEach(moduleLayerLoaderProvider -> { ALL.add(moduleLayerLoaderProvider.get()); }); @@ -108,5 +106,10 @@ public class ShellDialects { HETZNER_BOX = byId("hetznerBox"); SFTP = byId("sftp"); } + + @Override + public boolean initForCli() { + return false; + } } } diff --git a/app/src/main/java/io/xpipe/app/update/UpdateAvailableDialog.java b/app/src/main/java/io/xpipe/app/update/UpdateAvailableDialog.java index eb816b36a..8ff7fb409 100644 --- a/app/src/main/java/io/xpipe/app/update/UpdateAvailableDialog.java +++ b/app/src/main/java/io/xpipe/app/update/UpdateAvailableDialog.java @@ -3,11 +3,16 @@ package io.xpipe.app.update; import io.xpipe.app.comp.RegionBuilder; import io.xpipe.app.comp.base.MarkdownComp; import io.xpipe.app.comp.base.ModalOverlay; +import io.xpipe.app.core.AppProperties; import io.xpipe.app.issue.TrackEvent; public class UpdateAvailableDialog { public static boolean showIfNeeded(boolean wait) { + if (AppProperties.get().isAotTrainMode()) { + return false; + } + UpdateHandler uh = AppDistributionType.get().getUpdateHandler(); if (uh.getPreparedUpdate().getValue() == null) { return false; diff --git a/app/src/main/java/io/xpipe/app/util/LicenseProvider.java b/app/src/main/java/io/xpipe/app/util/LicenseProvider.java index db0b5984f..d52f193cf 100644 --- a/app/src/main/java/io/xpipe/app/util/LicenseProvider.java +++ b/app/src/main/java/io/xpipe/app/util/LicenseProvider.java @@ -1,6 +1,7 @@ package io.xpipe.app.util; import io.xpipe.app.comp.BaseRegionBuilder; +import io.xpipe.app.core.AppProperties; import io.xpipe.app.ext.ExtensionException; import io.xpipe.core.ModuleLayerLoader; @@ -49,5 +50,10 @@ public abstract class LicenseProvider { .findFirst() .orElseThrow(() -> ExtensionException.corrupt("Missing license provider")); } + + @Override + public boolean initForCli() { + return false; + } } } diff --git a/app/src/main/java/module-info.java b/app/src/main/java/module-info.java index f82464b39..6088877dc 100644 --- a/app/src/main/java/module-info.java +++ b/app/src/main/java/module-info.java @@ -217,7 +217,8 @@ open module io.xpipe.app { LicenseProvider.Loader, ScanProvider.Loader, ShellDialects.Loader, - CloudSetupProvider.Loader; + CloudSetupProvider.Loader, + CliProvider.Loader; provides SLF4JServiceProvider with AppLogs.Slf4jProvider; provides EventHandler with diff --git a/beacon/src/main/java/io/xpipe/beacon/BeaconInterface.java b/beacon/src/main/java/io/xpipe/beacon/BeaconInterface.java index 8ab336566..162d9e16e 100644 --- a/beacon/src/main/java/io/xpipe/beacon/BeaconInterface.java +++ b/beacon/src/main/java/io/xpipe/beacon/BeaconInterface.java @@ -78,9 +78,7 @@ public abstract class BeaconInterface { @Override public void init(ModuleLayer layer) { - var services = layer != null - ? ServiceLoader.load(layer, BeaconInterface.class) - : ServiceLoader.load(BeaconInterface.class); + var services = ServiceLoader.load(layer, BeaconInterface.class); ALL = services.stream() .map(ServiceLoader.Provider::get) .map(beaconInterface -> (BeaconInterface) beaconInterface) @@ -90,5 +88,10 @@ public abstract class BeaconInterface { .anyMatch(other -> !other.equals(beaconInterface) && beaconInterface.getClass().isAssignableFrom(other.getClass()))); } + + @Override + public boolean initForCli() { + return true; + } } } diff --git a/beacon/src/main/resources/META-INF/services/io.xpipe.core.ModuleLayerLoader b/beacon/src/main/resources/META-INF/services/io.xpipe.core.ModuleLayerLoader deleted file mode 100644 index c70568c84..000000000 --- a/beacon/src/main/resources/META-INF/services/io.xpipe.core.ModuleLayerLoader +++ /dev/null @@ -1 +0,0 @@ -io.xpipe.beacon.BeaconInterface$Loader \ No newline at end of file diff --git a/build.gradle b/build.gradle index 1a134f89c..52bd05699 100644 --- a/build.gradle +++ b/build.gradle @@ -101,14 +101,18 @@ static def getPlatformName() { return platform } -def getJvmArgs() { +def getBaseJvmArgs() { def os = DefaultNativePlatform.currentOperatingSystem - def jvmRunArgs = [ - "-Dfile.encoding=UTF-8", - "-Dvisualvm.display.name=$productName", - "-Djavafx.preloader=" + packageName("core.AppPreloader"), - "-Djdk.virtualThreadScheduler.parallelism=8" - ] + def jvmRunArgs = [] + + // Force UTF8 encoding. This isn't really necessary anymore in JDK25+ + jvmRunArgs += ["-Dfile.encoding=UTF-8"] + + // Make the app show up nicely in VisualVM + jvmRunArgs += ["-Dvisualvm.display.name=$productName"] + + // Make virtual threads behave the same, independently of CPU core count + jvmRunArgs += ["-Djdk.virtualThreadScheduler.parallelism=8"] // Virtual threads cause crashes on Windows ARM if (os.isWindows() && arch == "arm64") { @@ -119,9 +123,6 @@ def getJvmArgs() { // Disable JDK24 warnings jvmRunArgs += [ - "--enable-native-access=com.sun.jna", - "--enable-native-access=javafx.graphics", - "--enable-native-access=javafx.web", "--sun-misc-unsafe-memory-access=allow", ] @@ -130,10 +131,50 @@ def getJvmArgs() { jvmRunArgs += [ "--add-opens", "java.base/java.lang=$appPackage", "--add-opens", "java.base/java.net=$appPackage", - "--add-opens", "net.synedra.validatorfx/net.synedra.validatorfx=$appPackage", "--add-opens", "java.base/java.nio.file=$appPackage", - "--add-exports", "javafx.graphics/com.sun.javafx.tk=$appPackage", "--add-exports", "jdk.zipfs/jdk.nio.zipfs=io.xpipe.modulefs", + ] + + // Use project liliput + jvmRunArgs += ['-XX:+UseCompactObjectHeaders'] + + // Reduce heap usage with deduplication + jvmRunArgs += ['-XX:+UseStringDeduplication'] + + // Why is this not on by default? ... + // https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/net/doc-files/net-properties.html + // https://stackoverflow.com/questions/53333556/proxy-authentication-with-jdk-11-httpclient + // https://stackoverflow.com/questions/75150081/ioexception-too-many-authentication-attempts-limit-3-when-using-jdk-httpcli + jvmRunArgs += [ + '-Djava.net.useSystemProxies=true', + '-Djdk.http.auth.proxying.disabledSchemes=""', + '-Djdk.http.auth.tunneling.disabledSchemes=""', + '-Djdk.httpclient.auth.retrylimit=1' + ] + + + return jvmRunArgs +} + +def getDaemonJvmArgs() { + def os = DefaultNativePlatform.currentOperatingSystem + def jvmRunArgs = ["-Dio.xpipe.app.isDaemon=true"] + + // Use custom JavaFX preloader + jvmRunArgs += ["-Djavafx.preloader=" + packageName("core.AppPreloader")] + + // Disable JDK24 warnings + jvmRunArgs += [ + "--enable-native-access=com.sun.jna", + "--enable-native-access=javafx.graphics", + "--enable-native-access=javafx.web" + ] + + // Module access fixes + def appPackage = packageName(null) + jvmRunArgs += [ + "--add-opens", "net.synedra.validatorfx/net.synedra.validatorfx=$appPackage", + "--add-exports", "javafx.graphics/com.sun.javafx.tk=$appPackage", "--add-opens", "javafx.graphics/com.sun.glass.ui=$appPackage", "--add-opens", "javafx.graphics/javafx.stage=$appPackage", "--add-opens", "javafx.controls/javafx.scene.control.skin=$appPackage", @@ -148,12 +189,6 @@ def getJvmArgs() { ] } - // Use project liliput - jvmRunArgs += ['-XX:+UseCompactObjectHeaders'] - - // Reduce heap usage with deduplication - jvmRunArgs += ['-XX:+UseStringDeduplication'] - // GC config jvmRunArgs += [ '-XX:+UseG1GC', @@ -166,17 +201,6 @@ def getJvmArgs() { '-XX:G1HeapRegionSize=4m' ] - // Why is this not on by default? ... - // https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/net/doc-files/net-properties.html - // https://stackoverflow.com/questions/53333556/proxy-authentication-with-jdk-11-httpclient - // https://stackoverflow.com/questions/75150081/ioexception-too-many-authentication-attempts-limit-3-when-using-jdk-httpcli - jvmRunArgs += [ - '-Djava.net.useSystemProxies=true', - '-Djdk.http.auth.proxying.disabledSchemes=""', - '-Djdk.http.auth.tunneling.disabledSchemes=""', - '-Djdk.httpclient.auth.retrylimit=1' - ] - // Fix platform theme detection on macOS if (os.isMacOsX()) { jvmRunArgs += ["-Dapple.awt.application.appearance=system"] @@ -196,6 +220,69 @@ def getJvmArgs() { jvmRunArgs.addAll("--add-opens", "java.desktop/sun.awt.X11=" + packageName(null)) } + return getBaseJvmArgs() + jvmRunArgs +} + +def getCliJvmArgs() { + def jvmRunArgs = ["-Dio.xpipe.app.isCli=true"] + + // GC config + jvmRunArgs += [ + '-XX:+UseG1GC', + '-Xms50m', + '-Xmx250m', + // The default makes GC pauses longer for some reason + '-XX:G1HeapRegionSize=4m' + ] + + return getBaseJvmArgs() + jvmRunArgs +} + +def getDaemonJPackageReleaseJvmArgs() { + def jvmRunArgs = getDaemonJvmArgs() + + jvmRunArgs += [ + "-D" + propertyName("version") + "=" + versionString, + "-D" + propertyName("build") + "=$versionString/${new Date().format('yyyy-MM-dd-HH-mm')}", + "-D" + propertyName("buildId") + "=" + buildId, + "-D" + propertyName("fullVersion") + "=" + fullVersion, + "-D" + propertyName("staging") + "=" + isStage, + "-D" + propertyName("sentryUrl") + "=" + sentryUrl + ] + + jvmRunArgs += [ + '-Djna.nosys=false', + '-Djna.nounpack=true', + '-Djna.noclasspath=true' + ] + + if (os.isMacOsX()) { + jvmRunArgs += "-Xdock:name=$productName" + } + + if (isFullRelease || isStage) { + jvmRunArgs += "-XX:+DisableAttachMechanism" + } + + return jvmRunArgs +} + +def getCliJPackageReleaseJvmArgs() { + def jvmRunArgs = getCliJvmArgs() + + jvmRunArgs += [ + "-D" + propertyName("version") + "=" + versionString, + "-D" + propertyName("build") + "=$versionString/${new Date().format('yyyy-MM-dd-HH-mm')}", + "-D" + propertyName("buildId") + "=" + buildId, + "-D" + propertyName("fullVersion") + "=" + fullVersion, + "-D" + propertyName("staging") + "=" + isStage, + "-D" + propertyName("sentryUrl") + "=" + sentryUrl + ] + + if (isFullRelease || isStage) { + jvmRunArgs += "-XX:+DisableAttachMechanism" + } + return jvmRunArgs } @@ -274,30 +361,16 @@ project.ext { groupName = 'io.xpipe' artifactName = 'app' arch = getArchName() - jvmRunArgs = getJvmArgs() + daemonJvmRunArgs = getDaemonJvmArgs() + cliJvmRunArgs = getCliJvmArgs() useBundledJna = fullVersion sentryUrl = "https://fd5f67ff10764b7e8a704bec9558c8fe@o1084459.ingest.sentry.io/6094279" // JPackage config jpackageExecutableName = "xpiped" jpackageMacOsBundleName = isStage ? groupName + '.ptb-app' : groupName + '.app' - jpackageReleaseArguments = jvmRunArgs + [ - "-D" + propertyName("version") + "=" + versionString, - "-D" + propertyName("build") + "=$versionString/${new Date().format('yyyy-MM-dd-HH-mm')}", - "-D" + propertyName("buildId") + "=" + buildId, - "-D" + propertyName("fullVersion") + "=" + fullVersion, - "-D" + propertyName("staging") + "=" + isStage, - "-D" + propertyName("sentryUrl") + "=" + sentryUrl, - '-Djna.nosys=false', - '-Djna.nounpack=true', - '-Djna.noclasspath=true' - ] - if (os.isMacOsX()) { - jpackageReleaseArguments += "-Xdock:name=$productName" - } - if (isFullRelease || isStage) { - jpackageReleaseArguments += "-XX:+DisableAttachMechanism" - } + jpackageReleaseDaemonArguments = getDaemonJPackageReleaseJvmArgs() + jpackageReleaseCliArguments = getCliJPackageReleaseJvmArgs() // JavaFX config devJavafxVersion = '27-ea+4' diff --git a/core/src/main/java/io/xpipe/core/JacksonMapper.java b/core/src/main/java/io/xpipe/core/JacksonMapper.java index e4a6058fc..762f7b9c4 100644 --- a/core/src/main/java/io/xpipe/core/JacksonMapper.java +++ b/core/src/main/java/io/xpipe/core/JacksonMapper.java @@ -54,8 +54,7 @@ public class JacksonMapper { private static List findModules(ModuleLayer layer) { ArrayList modules = new ArrayList<>(); - ServiceLoader loader = - layer != null ? ServiceLoader.load(layer, Module.class) : ServiceLoader.load(Module.class); + ServiceLoader loader = ServiceLoader.load(layer, Module.class); for (Module module : loader) { modules.add(module); } @@ -150,5 +149,10 @@ public class JacksonMapper { INSTANCE.registerModules(modules); init = true; } + + @Override + public boolean initForCli() { + return true; + } } } diff --git a/core/src/main/java/io/xpipe/core/ModuleLayerLoader.java b/core/src/main/java/io/xpipe/core/ModuleLayerLoader.java index 695000a74..32865ba49 100644 --- a/core/src/main/java/io/xpipe/core/ModuleLayerLoader.java +++ b/core/src/main/java/io/xpipe/core/ModuleLayerLoader.java @@ -6,10 +6,8 @@ import java.util.function.Consumer; public interface ModuleLayerLoader { static void loadAll(ModuleLayer layer, Consumer errorHandler) { - var loaded = layer != null - ? ServiceLoader.load(layer, ModuleLayerLoader.class) - : ServiceLoader.load(ModuleLayerLoader.class); - loaded.stream().forEach(moduleLayerLoaderProvider -> { + var loaded = ServiceLoader.load(layer, ModuleLayerLoader.class); + loaded.stream().map(ServiceLoader.Provider::get).filter(p -> p.initForCli() || !AppPro).forEach(moduleLayerLoaderProvider -> { var instance = moduleLayerLoaderProvider.get(); try { instance.init(layer); @@ -20,4 +18,6 @@ public interface ModuleLayerLoader { } default void init(ModuleLayer layer) {} + + boolean initForCli(); } diff --git a/core/src/main/resources/META-INF/services/com.fasterxml.jackson.databind.Module b/core/src/main/resources/META-INF/services/com.fasterxml.jackson.databind.Module deleted file mode 100644 index 97cd2a927..000000000 --- a/core/src/main/resources/META-INF/services/com.fasterxml.jackson.databind.Module +++ /dev/null @@ -1 +0,0 @@ -io.xpipe.core.CoreJacksonModule \ No newline at end of file diff --git a/core/src/main/resources/META-INF/services/io.xpipe.core.ModuleLayerLoader b/core/src/main/resources/META-INF/services/io.xpipe.core.ModuleLayerLoader deleted file mode 100644 index bf6de11bf..000000000 --- a/core/src/main/resources/META-INF/services/io.xpipe.core.ModuleLayerLoader +++ /dev/null @@ -1 +0,0 @@ -io.xpipe.core.JacksonMapper$Loader \ No newline at end of file diff --git a/dist/jpackage.gradle b/dist/jpackage.gradle index 9d7100068..039ae5665 100644 --- a/dist/jpackage.gradle +++ b/dist/jpackage.gradle @@ -78,14 +78,14 @@ jlink { moduleName = packageName(null) mainClass = packageName('Main') name = jpackageExecutableName - jvmArgs = jpackageReleaseArguments + ["-Dio.xpipe.app.isDaemon=true"] + jvmArgs = jpackageReleaseDaemonArguments } secondaryLauncher { moduleName = packageName(null) mainClass = packageName('Main') name = "xpipe" - jvmArgs = jpackageReleaseArguments + ["-Dio.xpipe.app.isCli=true"] + jvmArgs = jpackageReleaseCliArguments } jpackage { diff --git a/gradle/gradle_scripts/local_junit_suite.gradle b/gradle/gradle_scripts/local_junit_suite.gradle index ea93a93ee..ad9cfa4cb 100644 --- a/gradle/gradle_scripts/local_junit_suite.gradle +++ b/gradle/gradle_scripts/local_junit_suite.gradle @@ -18,7 +18,7 @@ testing { testTask.configure { workingDir = rootDir - jvmArgs += jvmRunArgs + jvmArgs += daemonJvmRunArgs def exts = files(project.allExtensions.stream().map(p -> p.getTasksByName('jar', true)[0].outputs.files.singleFile).toList()) classpath += exts diff --git a/gradle/gradle_scripts/remote_junit_suite.gradle b/gradle/gradle_scripts/remote_junit_suite.gradle index e0bf66c5c..77d365bc9 100644 --- a/gradle/gradle_scripts/remote_junit_suite.gradle +++ b/gradle/gradle_scripts/remote_junit_suite.gradle @@ -18,7 +18,7 @@ testing { testTask.configure { workingDir = projectDir - jvmArgs += jvmRunArgs + jvmArgs += daemonJvmRunArgs def daemonArgs = Map.of( propertyName("dataDir"), "$projectDir/local/",