This commit is contained in:
crschnick
2026-06-18 06:32:21 +00:00
parent 135f437125
commit 1dd1c46cab
5 changed files with 80 additions and 49 deletions
+4 -2
View File
@@ -55,7 +55,7 @@ dependencies {
api "io.projectreactor:reactor-core:3.7.9"
api "org.reactivestreams:reactive-streams:1.0.4"
api ("com.networknt:json-schema-validator:1.5.8") {
api ("com.networknt:json-schema-validator:2.0.0") {
exclude group: "com.ethlo.time", module: "itu"
exclude group: "com.fasterxml.jackson.dataformat", module: "jackson-dataformat-yaml"
}
@@ -79,7 +79,9 @@ dependencies {
api 'io.xpipe:modulefs:0.1.8'
api 'net.synedra:validatorfx:0.4.2'
api files("$rootDir/gradle/gradle_scripts/atlantafx-base-2.0.2.jar")
api("com.dlsc.atlantafx:themes:1.9.0")
api("com.dlsc.atlantafx:themes:1.9.0") {
exclude group: "io.github.mkpaz", module: "atlantafx-base"
}
api("org.int4.fx:fx-values:0.4")
api files("$rootDir/gradle/gradle_scripts/fx-builders-1.0.0-SNAPSHOT.jar")
@@ -10,8 +10,12 @@ import io.xpipe.app.util.ModuleLayerLoader;
import lombok.Getter;
import java.io.IOException;
import java.lang.module.Configuration;
import java.lang.module.ModuleFinder;
import java.net.URI;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
@@ -23,7 +27,9 @@ public class AppExtensionManager {
private static AppExtensionManager INSTANCE;
private final List<Module> loadedModules = new ArrayList<>();
private final List<ModuleLayer> leafModuleLayers = new ArrayList<>();
private final List<Path> extensionBaseDirectories = new ArrayList<>();
private FileSystem externalModules;
private ModuleLayer baseLayer = ModuleLayer.boot();
@Getter
@@ -35,7 +41,6 @@ public class AppExtensionManager {
}
INSTANCE = new AppExtensionManager();
INSTANCE.determineExtensionDirectories();
INSTANCE.loadBaseExtension();
INSTANCE.loadAllExtensions();
try {
@@ -49,6 +54,15 @@ public class AppExtensionManager {
}
public static void reset() {
if (INSTANCE.externalModules != null) {
try {
INSTANCE.externalModules.close();
} catch (IOException e) {
ErrorEventFactory.fromThrowable(e).handle();
}
INSTANCE.externalModules = null;
}
INSTANCE = null;
}
@@ -77,43 +91,6 @@ public class AppExtensionManager {
loadedModules.add(baseModule.get());
}
private void determineExtensionDirectories() throws Exception {
if (!AppProperties.get().isFullVersion()) {
var localInstallation =
!AppProperties.get().isStaging() && AppProperties.get().isLocatePtb()
? AppInstallation.ofDefault(true)
: AppInstallation.ofCurrent();
Path p = localInstallation.getBaseInstallationPath();
if (!Files.exists(p)) {
throw new IllegalStateException(
"Required local " + AppNames.ofCurrent().getName()
+ " installation was not found but is required for development. See https://github"
+ ".com/xpipe-io/xpipe/blob/master/CONTRIBUTING.md#development-setup");
}
if (AppProperties.get().isLocatorVersionCheck()) {
var iv = getLocalInstallVersion(localInstallation);
var installVersion = AppVersion.parse(iv)
.orElseThrow(() -> new IllegalArgumentException("Invalid installation version: " + iv));
var sv = !AppProperties.get().isImage()
? Files.readString(Path.of("version")).strip()
: AppProperties.get().getVersion();
var sourceVersion = AppVersion.parse(sv)
.orElseThrow(() -> new IllegalArgumentException("Invalid source version: " + sv));
if (!installVersion.equals(sourceVersion)) {
throw new IllegalStateException("Incompatible development version. Source: " + sv
+ ", Installation: "
+ iv
+ "\n\nPlease try to check out the matching release version in the repository. See https://github"
+ ".com/xpipe-io/xpipe/blob/master/CONTRIBUTING.md#development-setup");
}
}
var extensions = localInstallation.getExtensionsPath();
extensionBaseDirectories.add(extensions);
}
}
public Set<Module> getContentModules() {
return Stream.concat(
Stream.of(ModuleLayer.boot()
@@ -157,12 +134,47 @@ public class AppExtensionManager {
return inModulePath;
}
for (Path extensionBaseDirectory : extensionBaseDirectories) {
var extensionDir = extensionBaseDirectory.resolve(name);
var found = parseExtensionDirectory(extensionDir, parent);
if (found.isPresent()) {
TrackEvent.info("Loaded extension " + name + " from module " + extensionDir);
return found;
if (!AppProperties.get().isFullVersion()) {
try {
if (externalModules == null) {
var localInstallation = !AppProperties.get().isStaging() && AppProperties.get().isLocatePtb() ?
AppInstallation.ofDefault(true) :
AppInstallation.ofCurrent();
Path p = localInstallation.getBaseInstallationPath();
if (!Files.exists(p)) {
throw new IllegalStateException("Required local " +
AppNames.ofCurrent().getName() +
" installation was not found but is required for development. See https://github" +
".com/xpipe-io/xpipe/blob/master/CONTRIBUTING.md#development-setup");
}
if (AppProperties.get().isLocatorVersionCheck()) {
var iv = getLocalInstallVersion(localInstallation);
var installVersion = AppVersion.parse(iv).orElseThrow(
() -> new IllegalArgumentException("Invalid installation version: " + iv));
var sv = !AppProperties.get().isImage() ? Files.readString(Path.of("version")).strip() : AppProperties.get().getVersion();
var sourceVersion = AppVersion.parse(sv).orElseThrow(() -> new IllegalArgumentException("Invalid source version: " + sv));
if (!installVersion.equals(sourceVersion)) {
throw new IllegalStateException("Incompatible development version. Source: " +
sv +
", Installation: " +
iv +
"\n\nPlease try to check out the matching release version in the repository. See https://github" +
".com/xpipe-io/xpipe/blob/master/CONTRIBUTING.md#development-setup");
}
}
externalModules = FileSystems.newFileSystem(URI.create("jrt:/"), Map.of("java.home", localInstallation.getRuntimePath()));
}
var basePath = externalModules.getPath("modules", "io.xpipe.ext." + name);
var found = parseExtensionDirectory(basePath, parent);
if (found.isPresent()) {
TrackEvent.info("Loaded extension " + name + " from module " + basePath);
return found;
}
} catch (Throwable t) {
ErrorEventFactory.fromThrowable(t).handle();
}
}
@@ -172,6 +172,8 @@ public abstract class AppInstallation {
public abstract Path getLogoPath();
public abstract Path getRuntimePath();
public static class Windows extends AppInstallation {
private Windows(Path base) {
@@ -208,6 +210,11 @@ public abstract class AppInstallation {
public Path getLogoPath() {
return getBaseInstallationPath().resolve("logo.ico");
}
@Override
public Path getRuntimePath() {
return getBaseInstallationPath().resolve("runtime");
}
}
public static class WindowsDev extends Windows {
@@ -236,6 +243,11 @@ public abstract class AppInstallation {
super(base);
}
@Override
public Path getRuntimePath() {
return getBaseInstallationPath().resolve("lib", "runtime");
}
@Override
public Path getDaemonDebugScriptPath() {
return getBaseInstallationPath()
@@ -293,6 +305,11 @@ public abstract class AppInstallation {
super(base);
}
@Override
public Path getRuntimePath() {
return getBaseInstallationPath().resolve("Contents", "runtime", "Contents", "Home");
}
@Override
public Path getDaemonDebugScriptPath() {
return getBaseInstallationPath()
@@ -175,7 +175,7 @@ public class AppProperties {
.orElse("info");
loginTarget = Optional.ofNullable(System.getProperty(AppNames.propertyName("login")))
.orElse(null);
localWebtopDockerfile = Optional.of(System.getProperty(AppNames.propertyName("localWebtopDockerfile")))
localWebtopDockerfile = Optional.ofNullable(System.getProperty(AppNames.propertyName("localWebtopDockerfile")))
.map(s -> FilePath.parse(s)).orElse(null);
isCli = Optional.ofNullable(System.getProperty(AppNames.propertyName("isCli")))
.map(Boolean::parseBoolean)
@@ -28,7 +28,7 @@ public interface TerminalPrompt {
String getDocsLink();
default FilePath getConfigurationDirectory(ShellControl sc) throws Exception {
var d = ShellTemp.createUserSpecificTempDataDirectory(sc, "prompt").join(getId());
var d = ShellTemp.createUserSpecificTempDataDirectory(sc, null).join(getId());
sc.view().mkdir(d);
return d;
}