mirror of
https://github.com/xpipe-io/xpipe.git
synced 2026-09-26 18:35:43 +00:00
Rework install
This commit is contained in:
@@ -7,7 +7,6 @@ import io.xpipe.app.util.DocumentationLink;
|
||||
import io.xpipe.beacon.BeaconConfig;
|
||||
import io.xpipe.beacon.BeaconInterface;
|
||||
import io.xpipe.core.OsType;
|
||||
import io.xpipe.core.XPipeInstallation;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpServer;
|
||||
@@ -54,7 +53,7 @@ public class AppBeaconServer {
|
||||
port = BeaconConfig.getUsedPort();
|
||||
propertyPort = true;
|
||||
} else {
|
||||
port = XPipeInstallation.getDefaultBeaconPort();
|
||||
port = BeaconConfig.getDefaultBeaconPort();
|
||||
propertyPort = false;
|
||||
}
|
||||
INSTANCE = new AppBeaconServer(port, propertyPort);
|
||||
@@ -120,7 +119,7 @@ public class AppBeaconServer {
|
||||
}
|
||||
|
||||
private void initAuthSecret() throws IOException {
|
||||
var file = XPipeInstallation.getLocalBeaconAuthFile();
|
||||
var file = BeaconConfig.getLocalBeaconAuthFile();
|
||||
var id = UUID.randomUUID().toString();
|
||||
Files.writeString(file, id);
|
||||
if (OsType.getLocal() != OsType.WINDOWS) {
|
||||
@@ -130,7 +129,7 @@ public class AppBeaconServer {
|
||||
}
|
||||
|
||||
private void deleteAuthSecret() {
|
||||
var file = XPipeInstallation.getLocalBeaconAuthFile();
|
||||
var file = BeaconConfig.getLocalBeaconAuthFile();
|
||||
try {
|
||||
Files.delete(file);
|
||||
} catch (IOException ignored) {
|
||||
|
||||
@@ -34,7 +34,7 @@ public class OpenFileWithActionProvider implements BrowserActionProvider {
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(BrowserFileSystemTabModel model, List<BrowserEntry> entries) {
|
||||
return OsType.getLocal().equals(OsType.WINDOWS)
|
||||
return OsType.getLocal() == OsType.WINDOWS
|
||||
&& entries.size() == 1
|
||||
&& entries.stream().allMatch(entry -> entry.getRawFileEntry().getKind() == FileKind.FILE);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ public class BrowserFileSystemHelper {
|
||||
return path;
|
||||
}
|
||||
|
||||
if (shell.get().getOsType().equals(OsType.WINDOWS) && path.length() == 2 && path.endsWith(":")) {
|
||||
if (shell.get().getOsType() == OsType.WINDOWS && path.length() == 2 && path.endsWith(":")) {
|
||||
return path + "\\";
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ public class OpenFileWithMenuProvider implements BrowserMenuLeafProvider {
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(BrowserFileSystemTabModel model, List<BrowserEntry> entries) {
|
||||
return OsType.getLocal().equals(OsType.WINDOWS)
|
||||
return OsType.getLocal() == OsType.WINDOWS
|
||||
&& entries.size() == 1
|
||||
&& entries.stream().allMatch(entry -> entry.getRawFileEntry().getKind() == FileKind.FILE);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ public class RunFileMenuProvider extends MultiExecuteMenuProvider {
|
||||
}
|
||||
|
||||
var os = shell.get().getOsType();
|
||||
if (os.equals(OsType.WINDOWS)
|
||||
if (os == OsType.WINDOWS
|
||||
&& Stream.of("exe", "bat", "ps1", "cmd")
|
||||
.anyMatch(s -> e.getPath().toString().endsWith(s))) {
|
||||
return true;
|
||||
|
||||
+1
-1
@@ -66,6 +66,6 @@ public abstract class BaseUnzipUnixMenuProvider implements BrowserMenuLeafProvid
|
||||
return entries.stream()
|
||||
.allMatch(entry ->
|
||||
entry.getRawFileEntry().getPath().toString().endsWith(".zip"))
|
||||
&& !model.getFileSystem().getShell().orElseThrow().getOsType().equals(OsType.WINDOWS);
|
||||
&& model.getFileSystem().getShell().orElseThrow().getOsType() != OsType.WINDOWS;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -60,6 +60,6 @@ public abstract class BaseUnzipWindowsActionProvider implements BrowserMenuLeafP
|
||||
return entries.stream()
|
||||
.allMatch(entry ->
|
||||
entry.getRawFileEntry().getPath().toString().endsWith(".zip"))
|
||||
&& model.getFileSystem().getShell().orElseThrow().getOsType().equals(OsType.WINDOWS);
|
||||
&& model.getFileSystem().getShell().orElseThrow().getOsType() == OsType.WINDOWS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ public class AppDesktopIntegration {
|
||||
|
||||
// This will initialize the toolkit on macOS and create the dock icon
|
||||
// macOS does not like applications that run fully in the background, so always do it
|
||||
if (OsType.getLocal().equals(OsType.MACOS) && Desktop.isDesktopSupported()) {
|
||||
if (OsType.getLocal() == OsType.MACOS && Desktop.isDesktopSupported()) {
|
||||
Desktop.getDesktop().setPreferencesHandler(e -> {
|
||||
if (PlatformState.getCurrent() != PlatformState.RUNNING) {
|
||||
return;
|
||||
|
||||
@@ -6,8 +6,6 @@ import io.xpipe.app.issue.ErrorEventFactory;
|
||||
import io.xpipe.app.issue.TrackEvent;
|
||||
import io.xpipe.app.util.ModuleAccess;
|
||||
import io.xpipe.core.ModuleLayerLoader;
|
||||
import io.xpipe.core.OsType;
|
||||
import io.xpipe.core.XPipeInstallation;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@@ -70,15 +68,16 @@ public class AppExtensionManager {
|
||||
|
||||
private void determineExtensionDirectories() throws Exception {
|
||||
if (!AppProperties.get().isFullVersion()) {
|
||||
var localInstallation = XPipeInstallation.getLocalDefaultInstallationBasePath(
|
||||
AppProperties.get().isStaging() || AppProperties.get().isLocatePtb());
|
||||
Path p = localInstallation;
|
||||
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 XPipe installation was not found but is required for development. See https://github.com/xpipe-io/xpipe/blob/master/CONTRIBUTING.md#development-setup");
|
||||
}
|
||||
|
||||
var iv = getLocalInstallVersion();
|
||||
var iv = getLocalInstallVersion(localInstallation);
|
||||
var installVersion = AppVersion.parse(iv)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Invalid installation version: " + iv));
|
||||
var sv = !AppProperties.get().isImage()
|
||||
@@ -92,14 +91,13 @@ public class AppExtensionManager {
|
||||
+ "\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 = XPipeInstallation.getLocalExtensionsDirectory(p);
|
||||
var extensions = localInstallation.getExtensionsPath();
|
||||
extensionBaseDirectories.add(extensions);
|
||||
}
|
||||
}
|
||||
|
||||
private static String getLocalInstallVersion() throws Exception {
|
||||
var localInstallation = XPipeInstallation.getLocalDefaultInstallationBasePath();
|
||||
var exec = localInstallation.resolve(XPipeInstallation.getDaemonExecutablePath(OsType.getLocal()));
|
||||
private static String getLocalInstallVersion(AppInstallation localInstallation) throws Exception {
|
||||
var exec = localInstallation.getDaemonExecutablePath();
|
||||
var fc = new ProcessBuilder(exec.toString(), "version").redirectError(ProcessBuilder.Redirect.DISCARD);
|
||||
var proc = fc.start();
|
||||
var out = new String(proc.getInputStream().readAllBytes());
|
||||
|
||||
@@ -3,7 +3,6 @@ package io.xpipe.app.core;
|
||||
import io.xpipe.app.issue.ErrorEventFactory;
|
||||
import io.xpipe.app.issue.TrackEvent;
|
||||
import io.xpipe.app.prefs.SupportedLocale;
|
||||
import io.xpipe.core.XPipeInstallation;
|
||||
|
||||
import lombok.Value;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
@@ -59,7 +58,7 @@ public class AppI18nData {
|
||||
|
||||
var translations = new HashMap<String, String>();
|
||||
{
|
||||
var basePath = XPipeInstallation.getLangPath().resolve("strings");
|
||||
var basePath = AppInstallation.ofCurrent().getLangPath().resolve("strings");
|
||||
AtomicInteger fileCounter = new AtomicInteger();
|
||||
AtomicInteger lineCounter = new AtomicInteger();
|
||||
Files.walkFileTree(basePath, new SimpleFileVisitor<>() {
|
||||
@@ -94,7 +93,7 @@ public class AppI18nData {
|
||||
|
||||
var markdownDocumentations = new HashMap<String, String>();
|
||||
{
|
||||
var basePath = XPipeInstallation.getLangPath().resolve("texts");
|
||||
var basePath = AppInstallation.ofCurrent().getLangPath().resolve("texts");
|
||||
Files.walkFileTree(basePath, new SimpleFileVisitor<>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
|
||||
|
||||
@@ -0,0 +1,312 @@
|
||||
package io.xpipe.app.core;
|
||||
|
||||
import io.xpipe.core.OsType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public abstract class AppInstallation {
|
||||
|
||||
private static final Windows WINDOWS = new Windows(determineCurrentInstallationBasePath(AppProperties.get().isStaging()));
|
||||
private static final Linux LINUX = new Linux(determineCurrentInstallationBasePath(AppProperties.get().isStaging()));
|
||||
private static final MacOs MACOS = new MacOs(determineCurrentInstallationBasePath(AppProperties.get().isStaging()));
|
||||
|
||||
private AppInstallation(Path base) {this.base = base;}
|
||||
|
||||
public static AppInstallation ofCurrent() {
|
||||
return switch (OsType.getLocal()) {
|
||||
case OsType.Windows ignored -> WINDOWS;
|
||||
case OsType.Linux ignored -> LINUX;
|
||||
case OsType.MacOs ignored -> MACOS;
|
||||
default -> throw new IllegalStateException();
|
||||
};
|
||||
}
|
||||
|
||||
public static AppInstallation ofDefault() {
|
||||
return ofDefault(AppProperties.get().isStaging());
|
||||
}
|
||||
|
||||
public static AppInstallation ofDefault(boolean stage) {
|
||||
var def = determineDefaultInstallationBasePath(stage);
|
||||
return switch (OsType.getLocal()) {
|
||||
case OsType.Windows ignored -> new Windows(def);
|
||||
case OsType.Linux ignored -> new Linux(def);
|
||||
case OsType.MacOs ignored -> new MacOs(def);
|
||||
default -> throw new IllegalStateException();
|
||||
};
|
||||
}
|
||||
|
||||
private static Path determineDefaultInstallationBasePath(boolean stage) {
|
||||
return switch (OsType.getLocal()) {
|
||||
case OsType.Linux linux -> {
|
||||
yield Path.of(stage ? "/opt/xpipe-ptb" : "/opt/xpipe");
|
||||
}
|
||||
case OsType.MacOs macOs -> {
|
||||
yield Path.of(stage ? "/Applications/XPipe PTB.app" : "/Applications/XPipe.app");
|
||||
}
|
||||
case OsType.Windows windows -> {
|
||||
var pg = AppLocations.getWindows().getProgramFiles();
|
||||
var systemPath = pg.resolve(stage ? "XPipe PTB" : "XPipe");
|
||||
if (Files.exists(systemPath)) {
|
||||
yield systemPath;
|
||||
}
|
||||
|
||||
var ad = AppLocations.getWindows().getLocalAppData();
|
||||
yield ad.resolve(stage ? "XPipe PTB" : "XPipe");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static Path determineCurrentInstallationBasePath(boolean stage) {
|
||||
var command = ProcessHandle.current().info().command();
|
||||
// We should always have a command associated with the current process, otherwise something went seriously wrong
|
||||
if (command.isEmpty()) {
|
||||
var javaHome = System.getProperty("java.home");
|
||||
var javaExec = toRealPathIfPossible(Path.of(javaHome, "bin", "java"));
|
||||
var path = getInstallationBasePathForJavaExecutable(javaExec);
|
||||
return path;
|
||||
}
|
||||
|
||||
// Resolve any possible links to a real path
|
||||
Path path = toRealPathIfPossible(Path.of(command.get()));
|
||||
// Check if the process was started using a relative path, and adapt it if necessary
|
||||
if (!path.isAbsolute()) {
|
||||
path = toRealPathIfPossible(Path.of(System.getProperty("user.dir")).resolve(path));
|
||||
}
|
||||
|
||||
var name = path.getFileName().toString();
|
||||
// Check if we launched the JVM via a start script instead of the native executable
|
||||
if (name.endsWith("java") || name.endsWith("java.exe")) {
|
||||
// If we are not an image, we are probably running in a development environment where we want to use the
|
||||
// working directory
|
||||
var isImage = AppProperties.get().isImage();
|
||||
if (!isImage) {
|
||||
return Path.of(System.getProperty("user.dir"));
|
||||
}
|
||||
return getInstallationBasePathForJavaExecutable(path);
|
||||
} else {
|
||||
return getInstallationBasePathForDaemonExecutable(path);
|
||||
}
|
||||
}
|
||||
|
||||
private static Path getInstallationBasePathForDaemonExecutable(Path executable) {
|
||||
// Resolve root path of installation relative to executable in a JPackage installation
|
||||
return switch (OsType.getLocal()) {
|
||||
case OsType.Linux linux -> {
|
||||
yield executable.getParent().getParent();
|
||||
}
|
||||
case OsType.MacOs macOs -> {
|
||||
yield executable.getParent().getParent().getParent();
|
||||
}
|
||||
case OsType.Windows windows -> {
|
||||
yield executable.getParent();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static Path getInstallationBasePathForJavaExecutable(Path executable) {
|
||||
// Resolve root path of installation relative to executable in a JPackage installation
|
||||
return switch (OsType.getLocal()) {
|
||||
case OsType.Linux linux -> {
|
||||
yield executable.getParent().getParent().getParent().getParent();
|
||||
}
|
||||
case OsType.MacOs macOs -> {
|
||||
yield executable
|
||||
.getParent()
|
||||
.getParent()
|
||||
.getParent()
|
||||
.getParent()
|
||||
.getParent()
|
||||
.getParent();
|
||||
}
|
||||
case OsType.Windows windows -> {
|
||||
yield executable.getParent().getParent();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private final Path base;
|
||||
|
||||
public Path getBaseInstallationPath() {
|
||||
return base;
|
||||
}
|
||||
|
||||
private static Path toRealPathIfPossible(Path p) {
|
||||
try {
|
||||
// Under certain conditions, e.g. when running on a ramdisk, path resolution might fail.
|
||||
// This is however not a big problem in that case, so we ignore it
|
||||
return p.toRealPath();
|
||||
} catch (IOException e) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract Path getDaemonDebugScriptPath();
|
||||
|
||||
public abstract Path getBundledFontsPath();
|
||||
|
||||
public abstract Path getLangPath();
|
||||
|
||||
public abstract Path getCliExecutablePath();
|
||||
|
||||
public abstract Path getDaemonExecutablePath();
|
||||
|
||||
public abstract Path getExtensionsPath();
|
||||
|
||||
public abstract Path getLogoPath();
|
||||
|
||||
public static class Windows extends AppInstallation {
|
||||
|
||||
private Windows(Path base) {
|
||||
super(base);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getDaemonDebugScriptPath() {
|
||||
return getBaseInstallationPath().resolve("scripts", "xpiped_debug.bat");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getBundledFontsPath() {
|
||||
if (!AppProperties.get().isImage()) {
|
||||
return getBaseInstallationPath().resolve("dist", "fonts");
|
||||
}
|
||||
|
||||
return getBaseInstallationPath().resolve("fonts");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getLangPath() {
|
||||
return getBaseInstallationPath().resolve("lang");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getCliExecutablePath() {
|
||||
return getBaseInstallationPath().resolve("bin", "xpipe.exe");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getDaemonExecutablePath() {
|
||||
return getBaseInstallationPath().resolve("xpiped.exe");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getExtensionsPath() {
|
||||
return getBaseInstallationPath().resolve("extensions");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getLogoPath() {
|
||||
if (!AppProperties.get().isImage()) {
|
||||
return getBaseInstallationPath().resolve("dist").resolve("logo").resolve("logo.ico");
|
||||
}
|
||||
|
||||
return getBaseInstallationPath().resolve("logo.ico");
|
||||
}
|
||||
}
|
||||
|
||||
public static class Linux extends AppInstallation {
|
||||
|
||||
private Linux(Path base) {
|
||||
super(base);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getDaemonDebugScriptPath() {
|
||||
return getBaseInstallationPath().resolve("scripts", "xpiped_debug.sh");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getBundledFontsPath() {
|
||||
if (!AppProperties.get().isImage()) {
|
||||
return getBaseInstallationPath().resolve("dist", "fonts");
|
||||
}
|
||||
|
||||
return getBaseInstallationPath().resolve("fonts");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getLangPath() {
|
||||
return getBaseInstallationPath().resolve("lang");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getCliExecutablePath() {
|
||||
return getBaseInstallationPath().resolve("bin", "xpipe");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getDaemonExecutablePath() {
|
||||
return getBaseInstallationPath().resolve("bin", "xpiped");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getExtensionsPath() {
|
||||
return getBaseInstallationPath().resolve("extensions");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getLogoPath() {
|
||||
if (!AppProperties.get().isImage()) {
|
||||
return getBaseInstallationPath().resolve("dist").resolve("logo").resolve("logo.png");
|
||||
}
|
||||
|
||||
return getBaseInstallationPath().resolve("logo.png");
|
||||
}
|
||||
}
|
||||
|
||||
public static class MacOs extends AppInstallation {
|
||||
|
||||
private MacOs(Path base) {
|
||||
super(base);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getDaemonDebugScriptPath() {
|
||||
return getBaseInstallationPath().resolve("Contents", "Resources", "scripts", "xpiped_debug.sh");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getBundledFontsPath() {
|
||||
if (!AppProperties.get().isImage()) {
|
||||
return getBaseInstallationPath().resolve("dist", "fonts");
|
||||
}
|
||||
|
||||
return getBaseInstallationPath().resolve("Contents", "Resources", "fonts");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getLangPath() {
|
||||
if (!AppProperties.get().isImage()) {
|
||||
return getBaseInstallationPath().resolve("lang");
|
||||
}
|
||||
|
||||
return getBaseInstallationPath().resolve("Contents", "Resources", "lang");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getCliExecutablePath() {
|
||||
return getBaseInstallationPath().resolve("Contents", "MacOS", "xpipe");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getDaemonExecutablePath() {
|
||||
return getBaseInstallationPath().resolve("Contents", "MacOS", "xpiped");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getExtensionsPath() {
|
||||
return getBaseInstallationPath().resolve("Contents", "Resources", "extensions");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getLogoPath() {
|
||||
if (!AppProperties.get().isImage()) {
|
||||
return getBaseInstallationPath().resolve("dist").resolve("logo").resolve("logo.icns");
|
||||
}
|
||||
|
||||
return getBaseInstallationPath().resolve("Contents").resolve("Resources").resolve("xpipe.icns");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,6 @@ import io.xpipe.beacon.BeaconServer;
|
||||
import io.xpipe.beacon.api.DaemonFocusExchange;
|
||||
import io.xpipe.beacon.api.DaemonOpenExchange;
|
||||
import io.xpipe.core.OsType;
|
||||
import io.xpipe.core.XPipeInstallation;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.List;
|
||||
@@ -82,7 +81,7 @@ public class AppInstance {
|
||||
return;
|
||||
}
|
||||
|
||||
var cli = XPipeInstallation.getLocalDefaultCliExecutable();
|
||||
var cli = AppInstallation.ofCurrent().getCliExecutablePath();
|
||||
ErrorEventFactory.fromThrowable(
|
||||
"Unable to connect to existing running daemon instance as it did not respond."
|
||||
+ " Either try to kill the process xpiped manually or use the command \""
|
||||
@@ -94,7 +93,7 @@ public class AppInstance {
|
||||
.handle();
|
||||
}
|
||||
|
||||
if (OsType.getLocal().equals(OsType.MACOS)) {
|
||||
if (OsType.getLocal() == OsType.MACOS) {
|
||||
Desktop.getDesktop().setOpenURIHandler(e -> {
|
||||
try {
|
||||
client.get()
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
package io.xpipe.app.core;
|
||||
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public interface AppLocations {
|
||||
|
||||
Windows WINDOWS = new Windows();
|
||||
Linux LINUX = new Linux();
|
||||
MacOs MACOS = new MacOs();
|
||||
|
||||
static Windows getWindows() {
|
||||
return WINDOWS;
|
||||
}
|
||||
|
||||
static Linux getLinux() {
|
||||
return LINUX;
|
||||
}
|
||||
|
||||
static MacOs getMacOs() {
|
||||
return MACOS;
|
||||
}
|
||||
|
||||
private static Path parsePath(String path) {
|
||||
if (path == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return Path.of(path);
|
||||
} catch (InvalidPathException ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
final class Windows implements AppLocations {
|
||||
|
||||
private Path userHome;
|
||||
|
||||
public Path getProgramFiles() {
|
||||
var env = AppLocations.parsePath(System.getenv("ProgramFiles"));
|
||||
if (env != null) {
|
||||
return env;
|
||||
}
|
||||
|
||||
var def = Path.of("C:\\ProgramFiles");
|
||||
return def;
|
||||
}
|
||||
|
||||
public Path getLocalAppData() {
|
||||
var env = AppLocations.parsePath(System.getenv("LOCALAPPDATA"));
|
||||
if (env != null) {
|
||||
return env;
|
||||
}
|
||||
|
||||
var def = getUserHome().resolve("AppData").resolve("Local");
|
||||
return def;
|
||||
}
|
||||
|
||||
public Path getUserHome() {
|
||||
if (userHome != null) {
|
||||
return userHome;
|
||||
}
|
||||
|
||||
var dir = AppLocations.parsePath(System.getenv("USERPROFILE"));
|
||||
if (dir == null) {
|
||||
dir = AppLocations.parsePath(System.getProperty("user.home"));
|
||||
}
|
||||
if (dir == null) {
|
||||
var username = System.getenv("USERNAME");
|
||||
if (username == null) {
|
||||
username = System.getProperty("user.name");
|
||||
}
|
||||
if (username == null) {
|
||||
username = "User";
|
||||
}
|
||||
dir = Path.of("C:\\Users\\" + username);
|
||||
}
|
||||
|
||||
try {
|
||||
// Replace 8.3 filename
|
||||
userHome = dir.toRealPath();
|
||||
} catch (Exception ignored) {
|
||||
userHome = dir;
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
}
|
||||
|
||||
class Linux implements AppLocations {
|
||||
|
||||
}
|
||||
|
||||
final class MacOs implements AppLocations {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import io.xpipe.app.process.ShellDialect;
|
||||
import io.xpipe.app.process.ShellDialects;
|
||||
import io.xpipe.app.util.LocalShell;
|
||||
import io.xpipe.core.OsType;
|
||||
import io.xpipe.core.XPipeInstallation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -14,17 +13,17 @@ public class AppRestart {
|
||||
|
||||
private static String createTerminalLaunchCommand(List<String> arguments, ShellDialect dialect) {
|
||||
var loc = AppProperties.get().isDevelopmentEnvironment()
|
||||
? XPipeInstallation.getLocalDefaultInstallationBasePath()
|
||||
: XPipeInstallation.getCurrentInstallationBasePath();
|
||||
? AppInstallation.ofDefault()
|
||||
: AppInstallation.ofCurrent();
|
||||
var suffix = (arguments.size() > 0 ? " " + String.join(" ", arguments) : "");
|
||||
if (OsType.getLocal().equals(OsType.LINUX)) {
|
||||
var exec = loc.resolve(XPipeInstallation.getRelativeCliExecutablePath(OsType.getLocal()));
|
||||
if (OsType.getLocal() == OsType.LINUX) {
|
||||
var exec = loc.getCliExecutablePath();
|
||||
return "\"" + exec + "\" open" + suffix;
|
||||
} else if (OsType.getLocal().equals(OsType.MACOS)) {
|
||||
var exec = loc.resolve(XPipeInstallation.getRelativeCliExecutablePath(OsType.getLocal()));
|
||||
} else if (OsType.getLocal() == OsType.MACOS) {
|
||||
var exec = loc.getCliExecutablePath();
|
||||
return "\"" + exec + "\" open" + suffix;
|
||||
} else {
|
||||
var exe = loc.resolve(XPipeInstallation.getDaemonExecutablePath(OsType.getLocal()));
|
||||
var exe = loc.getDaemonDebugScriptPath();
|
||||
if (ShellDialects.isPowershell(dialect)) {
|
||||
var escapedList =
|
||||
arguments.stream().map(s -> s.replaceAll("\"", "`\"")).toList();
|
||||
@@ -39,15 +38,15 @@ public class AppRestart {
|
||||
|
||||
private static String createBackgroundLaunchCommand(List<String> arguments, ShellDialect dialect) {
|
||||
var loc = AppProperties.get().isDevelopmentEnvironment()
|
||||
? XPipeInstallation.getLocalDefaultInstallationBasePath()
|
||||
: XPipeInstallation.getCurrentInstallationBasePath();
|
||||
? AppInstallation.ofDefault()
|
||||
: AppInstallation.ofCurrent();
|
||||
var suffix = (arguments.size() > 0 ? " " + String.join(" ", arguments) : "");
|
||||
if (OsType.getLocal().equals(OsType.LINUX)) {
|
||||
return "nohup \"" + loc + "/bin/xpiped\"" + suffix + " </dev/null >/dev/null 2>&1 & disown";
|
||||
} else if (OsType.getLocal().equals(OsType.MACOS)) {
|
||||
return "(sleep 1;open \"" + loc + "\" --args" + suffix + " </dev/null &>/dev/null) & disown";
|
||||
if (OsType.getLocal() == OsType.LINUX) {
|
||||
return "nohup \"" + loc.getDaemonExecutablePath() + "\"" + suffix + " </dev/null >/dev/null 2>&1 & disown";
|
||||
} else if (OsType.getLocal() == OsType.MACOS) {
|
||||
return "(sleep 1;open \"" + loc.getBaseInstallationPath() + "\" --args" + suffix + " </dev/null &>/dev/null) & disown";
|
||||
} else {
|
||||
var exe = loc.resolve(XPipeInstallation.getDaemonExecutablePath(OsType.getLocal()));
|
||||
var exe = loc.getDaemonExecutablePath();
|
||||
if (ShellDialects.isPowershell(dialect)) {
|
||||
var escapedList =
|
||||
arguments.stream().map(s -> s.replaceAll("\"", "`\"")).toList();
|
||||
|
||||
@@ -15,7 +15,7 @@ public class AppSid {
|
||||
private static boolean hasSetsid;
|
||||
|
||||
public static void init() {
|
||||
if (OsType.getLocal().equals(OsType.WINDOWS)) {
|
||||
if (OsType.getLocal() == OsType.WINDOWS) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ public class AppTrayIcon {
|
||||
}
|
||||
|
||||
public void showErrorMessage(String title, String message) {
|
||||
if (OsType.getLocal().equals(OsType.MACOS)) {
|
||||
if (OsType.getLocal() == OsType.MACOS) {
|
||||
showMacAlert(title, message, "Error");
|
||||
} else {
|
||||
EventQueue.invokeLater(() -> this.trayIcon.displayMessage(title, message, TrayIcon.MessageType.ERROR));
|
||||
|
||||
@@ -26,7 +26,7 @@ public class AppCertutilCheck {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!OsType.getLocal().equals(OsType.WINDOWS)) {
|
||||
if (OsType.getLocal() != OsType.WINDOWS) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ public class AppHomebrewCoreutilsCheck {
|
||||
}
|
||||
|
||||
public static void check() {
|
||||
if (!OsType.getLocal().equals(OsType.MACOS)) {
|
||||
if (OsType.getLocal() != OsType.MACOS) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.xpipe.app.core.check;
|
||||
|
||||
import io.xpipe.app.core.AppInstallation;
|
||||
import io.xpipe.core.OsType;
|
||||
import io.xpipe.core.XPipeInstallation;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -17,7 +17,7 @@ public class AppSystemFontCheck {
|
||||
}
|
||||
|
||||
System.setProperty(
|
||||
"prism.fontdir", XPipeInstallation.getBundledFontsPath().toString());
|
||||
"prism.fontdir", AppInstallation.ofCurrent().getBundledFontsPath().toString());
|
||||
System.setProperty("prism.embeddedfonts", "true");
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ public class AppTempCheck {
|
||||
}
|
||||
|
||||
public static void check() {
|
||||
if (!OsType.getLocal().equals(OsType.WINDOWS)) {
|
||||
if (OsType.getLocal() != OsType.WINDOWS) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
package io.xpipe.app.core.check;
|
||||
|
||||
import io.xpipe.app.core.AppInstallation;
|
||||
import io.xpipe.app.process.ProcessOutputException;
|
||||
import io.xpipe.app.util.LocalShell;
|
||||
import io.xpipe.core.OsType;
|
||||
import io.xpipe.core.XPipeInstallation;
|
||||
|
||||
public class AppTestCommandCheck {
|
||||
|
||||
public static void check() throws Exception {
|
||||
if (OsType.getLocal().equals(OsType.WINDOWS)) {
|
||||
if (OsType.getLocal() == OsType.WINDOWS) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ public class AppTestCommandCheck {
|
||||
sc.getShellDialect()
|
||||
.directoryExists(
|
||||
sc,
|
||||
XPipeInstallation.getCurrentInstallationBasePath()
|
||||
AppInstallation.ofCurrent().getBaseInstallationPath()
|
||||
.toString())
|
||||
.execute();
|
||||
} catch (ProcessOutputException ex) {
|
||||
|
||||
@@ -11,7 +11,7 @@ public class TrayMode extends PlatformMode {
|
||||
|
||||
@Override
|
||||
public boolean isSupported() {
|
||||
return OsType.getLocal().equals(OsType.WINDOWS)
|
||||
return OsType.getLocal()== OsType.WINDOWS
|
||||
&& super.isSupported()
|
||||
&& Desktop.isDesktopSupported()
|
||||
&& SystemTray.isSupported();
|
||||
|
||||
@@ -298,7 +298,7 @@ public class AppMainWindow {
|
||||
}
|
||||
});
|
||||
|
||||
if (OsType.getLocal().equals(OsType.LINUX) || OsType.getLocal().equals(OsType.MACOS)) {
|
||||
if (OsType.getLocal() == OsType.LINUX || OsType.getLocal() == OsType.MACOS) {
|
||||
stage.getScene().addEventHandler(KeyEvent.KEY_PRESSED, event -> {
|
||||
if (new KeyCodeCombination(KeyCode.W, KeyCombination.SHORTCUT_DOWN).match(event)) {
|
||||
OperationMode.onWindowClose();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.xpipe.app.ext;
|
||||
|
||||
import io.xpipe.core.XPipeInstallation;
|
||||
import io.xpipe.app.core.AppInstallation;
|
||||
|
||||
public class ExtensionException extends RuntimeException {
|
||||
|
||||
@@ -24,7 +24,7 @@ public class ExtensionException extends RuntimeException {
|
||||
|
||||
public static ExtensionException corrupt(String message, Throwable cause) {
|
||||
try {
|
||||
var loc = XPipeInstallation.getCurrentInstallationBasePath();
|
||||
var loc = AppInstallation.ofCurrent().getBaseInstallationPath();
|
||||
var full =
|
||||
message + ".\n\n" + "Please check whether the XPipe installation data at " + loc + " is corrupted.";
|
||||
return new ExtensionException(full, cause);
|
||||
|
||||
@@ -80,7 +80,7 @@ public interface ExternalApplicationType extends PrefsValue {
|
||||
|
||||
@Override
|
||||
default boolean isSelectable() {
|
||||
return OsType.getLocal().equals(OsType.MACOS);
|
||||
return OsType.getLocal() == OsType.MACOS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ public interface ExternalApplicationType extends PrefsValue {
|
||||
|
||||
@Override
|
||||
default boolean isSelectable() {
|
||||
return OsType.getLocal().equals(OsType.WINDOWS);
|
||||
return OsType.getLocal() == OsType.WINDOWS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -515,13 +515,13 @@ public interface ExternalEditorType extends PrefsChoiceValue {
|
||||
@SuppressWarnings("TrivialFunctionalExpressionUsage")
|
||||
List<ExternalEditorType> ALL = ((Supplier<List<ExternalEditorType>>) () -> {
|
||||
var all = new ArrayList<ExternalEditorType>();
|
||||
if (OsType.getLocal().equals(OsType.WINDOWS)) {
|
||||
if (OsType.getLocal() == OsType.WINDOWS) {
|
||||
all.addAll(WINDOWS_EDITORS);
|
||||
}
|
||||
if (OsType.getLocal().equals(OsType.LINUX)) {
|
||||
if (OsType.getLocal() == OsType.LINUX) {
|
||||
all.addAll(LINUX_EDITORS);
|
||||
}
|
||||
if (OsType.getLocal().equals(OsType.MACOS)) {
|
||||
if (OsType.getLocal() == OsType.MACOS) {
|
||||
all.addAll(MACOS_EDITORS);
|
||||
}
|
||||
all.addAll(CROSS_PLATFORM_EDITORS);
|
||||
@@ -536,21 +536,21 @@ public interface ExternalEditorType extends PrefsChoiceValue {
|
||||
return existing;
|
||||
}
|
||||
|
||||
if (OsType.getLocal().equals(OsType.WINDOWS)) {
|
||||
if (OsType.getLocal() == OsType.WINDOWS) {
|
||||
return WINDOWS_EDITORS.stream()
|
||||
.filter(PrefsChoiceValue::isAvailable)
|
||||
.findFirst()
|
||||
.orElse(NOTEPAD);
|
||||
}
|
||||
|
||||
if (OsType.getLocal().equals(OsType.LINUX)) {
|
||||
if (OsType.getLocal() == OsType.LINUX) {
|
||||
return LINUX_EDITORS.stream()
|
||||
.filter(ExternalApplicationType.PathApplication::isAvailable)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
if (OsType.getLocal().equals(OsType.MACOS)) {
|
||||
if (OsType.getLocal() == OsType.MACOS) {
|
||||
return MACOS_EDITORS.stream()
|
||||
.filter(PrefsChoiceValue::isAvailable)
|
||||
.findFirst()
|
||||
@@ -655,7 +655,7 @@ public interface ExternalEditorType extends PrefsChoiceValue {
|
||||
|
||||
@Override
|
||||
public boolean isSelectable() {
|
||||
return OsType.getLocal().equals(OsType.LINUX);
|
||||
return OsType.getLocal() == OsType.LINUX;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import io.xpipe.app.comp.Comp;
|
||||
import io.xpipe.app.comp.base.ModalOverlay;
|
||||
import io.xpipe.app.comp.base.TileButtonComp;
|
||||
import io.xpipe.app.core.AppCache;
|
||||
import io.xpipe.app.core.AppInstallation;
|
||||
import io.xpipe.app.core.AppLogs;
|
||||
import io.xpipe.app.core.AppProperties;
|
||||
import io.xpipe.app.core.mode.OperationMode;
|
||||
@@ -18,7 +19,6 @@ import io.xpipe.app.update.AppDistributionType;
|
||||
import io.xpipe.app.util.*;
|
||||
import io.xpipe.core.FilePath;
|
||||
import io.xpipe.core.OsType;
|
||||
import io.xpipe.core.XPipeInstallation;
|
||||
|
||||
import com.sun.management.HotSpotDiagnosticMXBean;
|
||||
import lombok.SneakyThrows;
|
||||
@@ -61,10 +61,7 @@ public class TroubleshootCategory extends AppPrefsCategory {
|
||||
.addComp(
|
||||
new TileButtonComp("launchDebugMode", "launchDebugModeDescription", "mdmz-refresh", e -> {
|
||||
OperationMode.executeAfterShutdown(() -> {
|
||||
var script = FilePath.of(
|
||||
XPipeInstallation.getCurrentInstallationBasePath()
|
||||
.toString(),
|
||||
XPipeInstallation.getDaemonDebugScriptPath(OsType.getLocal()));
|
||||
var script = AppInstallation.ofCurrent().getDaemonDebugScriptPath();
|
||||
TerminalLaunch.builder()
|
||||
.title("XPipe Debug")
|
||||
.localScript(sc -> new ShellScript(
|
||||
@@ -98,8 +95,7 @@ public class TroubleshootCategory extends AppPrefsCategory {
|
||||
"openInstallationDirectoryDescription",
|
||||
"mdomz-snippet_folder",
|
||||
e -> {
|
||||
DesktopHelper.browsePathLocal(
|
||||
XPipeInstallation.getCurrentInstallationBasePath());
|
||||
DesktopHelper.browsePathLocal(AppInstallation.ofCurrent().getBaseInstallationPath());
|
||||
e.consume();
|
||||
})
|
||||
.grow(true, false),
|
||||
@@ -165,7 +161,7 @@ public class TroubleshootCategory extends AppPrefsCategory {
|
||||
"uninstallApplicationDescription",
|
||||
"mdi2d-dump-truck",
|
||||
e -> {
|
||||
var file = XPipeInstallation.getCurrentInstallationBasePath()
|
||||
var file = AppInstallation.ofCurrent().getBaseInstallationPath()
|
||||
.resolve("Contents")
|
||||
.resolve("Resources")
|
||||
.resolve("scripts")
|
||||
|
||||
@@ -3,12 +3,13 @@ package io.xpipe.app.prefs;
|
||||
import io.xpipe.app.comp.base.ModalButton;
|
||||
import io.xpipe.app.comp.base.ModalOverlay;
|
||||
import io.xpipe.app.core.AppFontSizes;
|
||||
import io.xpipe.app.core.AppInstallation;
|
||||
import io.xpipe.app.core.AppProperties;
|
||||
import io.xpipe.app.core.mode.OperationMode;
|
||||
import io.xpipe.app.issue.ErrorEventFactory;
|
||||
import io.xpipe.app.util.*;
|
||||
import io.xpipe.core.OsType;
|
||||
import io.xpipe.core.XPipeInstallation;
|
||||
|
||||
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
|
||||
@@ -44,9 +45,7 @@ public class WorkspaceCreationDialog {
|
||||
var file =
|
||||
switch (OsType.getLocal()) {
|
||||
case OsType.Windows w -> {
|
||||
var exec = XPipeInstallation.getCurrentInstallationBasePath()
|
||||
.resolve(XPipeInstallation.getDaemonExecutablePath(w))
|
||||
.toString();
|
||||
var exec = AppInstallation.ofCurrent().getDaemonExecutablePath().toString();
|
||||
yield DesktopShortcuts.create(
|
||||
exec,
|
||||
"-Dio.xpipe.app.dataDir=\""
|
||||
@@ -54,8 +53,7 @@ public class WorkspaceCreationDialog {
|
||||
shortcutName);
|
||||
}
|
||||
default -> {
|
||||
var exec = XPipeInstallation.getCurrentInstallationBasePath()
|
||||
.resolve(XPipeInstallation.getRelativeCliExecutablePath(OsType.getLocal()))
|
||||
var exec = AppInstallation.ofCurrent().getCliExecutablePath()
|
||||
.toString();
|
||||
yield DesktopShortcuts.create(
|
||||
exec,
|
||||
|
||||
@@ -41,13 +41,13 @@ public interface ExternalRdpClient extends PrefsChoiceValue {
|
||||
@SuppressWarnings("TrivialFunctionalExpressionUsage")
|
||||
List<ExternalRdpClient> ALL = ((Supplier<List<ExternalRdpClient>>) () -> {
|
||||
var all = new ArrayList<ExternalRdpClient>();
|
||||
if (OsType.getLocal().equals(OsType.WINDOWS)) {
|
||||
if (OsType.getLocal() == OsType.WINDOWS) {
|
||||
all.addAll(WINDOWS_CLIENTS);
|
||||
}
|
||||
if (OsType.getLocal().equals(OsType.LINUX)) {
|
||||
if (OsType.getLocal() == OsType.LINUX) {
|
||||
all.addAll(LINUX_CLIENTS);
|
||||
}
|
||||
if (OsType.getLocal().equals(OsType.MACOS)) {
|
||||
if (OsType.getLocal() == OsType.MACOS) {
|
||||
all.addAll(MACOS_CLIENTS);
|
||||
}
|
||||
all.add(CUSTOM);
|
||||
|
||||
@@ -35,7 +35,7 @@ public class CmdTerminalType
|
||||
}
|
||||
|
||||
private CommandBuilder toCommand(TerminalLaunchConfiguration configuration) {
|
||||
if (configuration.getScriptDialect().equals(ShellDialects.CMD)) {
|
||||
if (configuration.getScriptDialect() == ShellDialects.CMD) {
|
||||
return CommandBuilder.of().add("/c").addFile(configuration.getScriptFile());
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ public class CustomTerminalType implements ExternalApplicationType, ExternalTerm
|
||||
var toExecute = ExternalApplicationHelper.replaceVariableArgument(
|
||||
format, "CMD", configuration.getScriptFile().toString());
|
||||
// We can't be sure whether the command is blocking or not, so always make it not blocking
|
||||
if (pc.getOsType().equals(OsType.WINDOWS)) {
|
||||
if (pc.getOsType() == OsType.WINDOWS) {
|
||||
toExecute = "start \"" + configuration.getCleanTitle() + "\" " + toExecute;
|
||||
} else {
|
||||
toExecute = "nohup " + toExecute + " </dev/null &>/dev/null & disown";
|
||||
|
||||
@@ -606,13 +606,13 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
||||
|
||||
static List<ExternalTerminalType> getTypes(OsType osType, boolean custom) {
|
||||
var all = new ArrayList<ExternalTerminalType>();
|
||||
if (osType == null || osType.equals(OsType.WINDOWS)) {
|
||||
if (osType == null || osType == OsType.WINDOWS) {
|
||||
all.addAll(WINDOWS_TERMINALS);
|
||||
}
|
||||
if (osType == null || osType.equals(OsType.LINUX)) {
|
||||
if (osType == null || osType == OsType.LINUX) {
|
||||
all.addAll(LINUX_TERMINALS);
|
||||
}
|
||||
if (osType == null || osType.equals(OsType.MACOS)) {
|
||||
if (osType == null || osType == OsType.MACOS) {
|
||||
all.addAll(MACOS_TERMINALS);
|
||||
}
|
||||
// Prefer recommended
|
||||
@@ -626,7 +626,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
||||
static ExternalTerminalType determineDefault(ExternalTerminalType existing) {
|
||||
// Check for incompatibility with fallback shell
|
||||
if (ExternalTerminalType.CMD.equals(existing)
|
||||
&& !ProcessControlProvider.get().getEffectiveLocalDialect().equals(ShellDialects.CMD)) {
|
||||
&& ProcessControlProvider.get().getEffectiveLocalDialect() != ShellDialects.CMD) {
|
||||
return ExternalTerminalType.POWERSHELL;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.xpipe.app.terminal;
|
||||
|
||||
import io.xpipe.app.core.AppInstallation;
|
||||
import io.xpipe.app.ext.ProcessControlProvider;
|
||||
import io.xpipe.app.issue.ErrorEventFactory;
|
||||
import io.xpipe.app.prefs.ExternalApplicationType;
|
||||
@@ -11,7 +12,7 @@ import io.xpipe.app.util.LocalShell;
|
||||
import io.xpipe.app.util.ShellTemp;
|
||||
import io.xpipe.app.util.ThreadHelper;
|
||||
import io.xpipe.core.FilePath;
|
||||
import io.xpipe.core.XPipeInstallation;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
|
||||
|
||||
@@ -38,7 +39,7 @@ public interface KittyTerminalType extends ExternalTerminalType, TrackableTermin
|
||||
payload.put("type", "tab");
|
||||
payload.put("logo_alpha", 0.01);
|
||||
payload.put(
|
||||
"logo", XPipeInstallation.getLocalDefaultInstallationIcon().toString());
|
||||
"logo", AppInstallation.ofCurrent().getLogoPath().toString());
|
||||
|
||||
var json = JsonNodeFactory.instance.objectNode();
|
||||
json.put("cmd", "launch");
|
||||
|
||||
@@ -42,7 +42,7 @@ public class PowerShellTerminalType implements ExternalApplicationType.PathAppli
|
||||
}
|
||||
|
||||
protected CommandBuilder toCommand(TerminalLaunchConfiguration configuration) {
|
||||
if (configuration.getScriptDialect().equals(ShellDialects.POWERSHELL)) {
|
||||
if (configuration.getScriptDialect() == ShellDialects.POWERSHELL) {
|
||||
return CommandBuilder.of()
|
||||
.add("-ExecutionPolicy", "Bypass")
|
||||
.add("-File")
|
||||
|
||||
@@ -66,7 +66,7 @@ public interface TabbyTerminalType extends ExternalTerminalType, TrackableTermin
|
||||
@Override
|
||||
public void launch(TerminalLaunchConfiguration configuration) throws Exception {
|
||||
// Tabby has a very weird handling of output, even detaching with start does not prevent it from printing
|
||||
if (configuration.getScriptDialect().equals(ShellDialects.CMD)) {
|
||||
if (configuration.getScriptDialect() == ShellDialects.CMD) {
|
||||
// It also freezes with any other input than .bat files, why?
|
||||
launch(CommandBuilder.of()
|
||||
.add("run")
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.xpipe.app.terminal;
|
||||
|
||||
import io.xpipe.app.core.AppInstallation;
|
||||
import io.xpipe.app.core.AppProperties;
|
||||
import io.xpipe.app.ext.ProcessControlProvider;
|
||||
import io.xpipe.app.issue.ErrorEventFactory;
|
||||
@@ -17,7 +18,6 @@ import io.xpipe.app.util.LocalShell;
|
||||
import io.xpipe.app.util.ScriptHelper;
|
||||
import io.xpipe.core.FilePath;
|
||||
import io.xpipe.core.OsType;
|
||||
import io.xpipe.core.XPipeInstallation;
|
||||
|
||||
import lombok.*;
|
||||
import lombok.experimental.NonFinal;
|
||||
@@ -127,7 +127,7 @@ public class TerminalLaunchConfiguration {
|
||||
var cliExecutable = TerminalProxyManager.getProxy()
|
||||
.orElse(LocalShell.getShell())
|
||||
.getLocalSystemAccess()
|
||||
.translateFromLocalSystemPath(FilePath.of(XPipeInstallation.getLocalDefaultCliExecutable()));
|
||||
.translateFromLocalSystemPath(FilePath.of(AppInstallation.ofCurrent().getCliExecutablePath()));
|
||||
var scriptCommand = sc.getOsType() == OsType.MACOS || sc.getOsType() == OsType.BSD
|
||||
? "script -e -q '%s' \"%s\"".formatted(logFile, command)
|
||||
: "script --quiet --command '%s' \"%s\"".formatted(command, logFile);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.xpipe.app.terminal;
|
||||
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.core.AppInstallation;
|
||||
import io.xpipe.app.ext.ProcessControlProvider;
|
||||
import io.xpipe.app.issue.ErrorEventFactory;
|
||||
import io.xpipe.app.prefs.AppPrefs;
|
||||
@@ -11,7 +12,7 @@ import io.xpipe.app.util.LocalShell;
|
||||
import io.xpipe.app.util.ScriptHelper;
|
||||
import io.xpipe.core.FailableFunction;
|
||||
import io.xpipe.core.FilePath;
|
||||
import io.xpipe.core.XPipeInstallation;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
@@ -192,7 +193,7 @@ public class TerminalLauncher {
|
||||
}
|
||||
|
||||
private static String getTerminalRegisterCommand(UUID request) throws Exception {
|
||||
var exec = XPipeInstallation.getLocalDefaultCliExecutable();
|
||||
var exec = AppInstallation.ofCurrent().getCliExecutablePath();
|
||||
return CommandBuilder.of()
|
||||
.addFile(exec)
|
||||
.add("terminal-register", "--request", request.toString())
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package io.xpipe.app.terminal;
|
||||
|
||||
import io.xpipe.app.core.AppInstallation;
|
||||
import io.xpipe.app.issue.ErrorEventFactory;
|
||||
import io.xpipe.app.process.CommandBuilder;
|
||||
import io.xpipe.app.util.CommandSupport;
|
||||
import io.xpipe.app.util.LocalShell;
|
||||
import io.xpipe.core.XPipeInstallation;
|
||||
|
||||
|
||||
public interface WaveTerminalType extends ExternalTerminalType, TrackableTerminalType {
|
||||
|
||||
@@ -65,7 +66,7 @@ public interface WaveTerminalType extends ExternalTerminalType, TrackableTermina
|
||||
.formatted(
|
||||
inPath
|
||||
? "xpipe open"
|
||||
: XPipeInstallation.getLocalDefaultCliExecutable() + " open");
|
||||
: "\"" + AppInstallation.ofCurrent().getCliExecutablePath() + "\" open");
|
||||
throw ErrorEventFactory.expected(new IllegalStateException(msg));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
package io.xpipe.app.terminal;
|
||||
|
||||
import io.xpipe.app.core.AppCache;
|
||||
import io.xpipe.app.core.AppInstallation;
|
||||
import io.xpipe.app.core.AppProperties;
|
||||
import io.xpipe.app.issue.ErrorEventFactory;
|
||||
import io.xpipe.app.process.CommandBuilder;
|
||||
import io.xpipe.app.util.LocalShell;
|
||||
import io.xpipe.core.FilePath;
|
||||
import io.xpipe.core.JacksonMapper;
|
||||
import io.xpipe.core.XPipeInstallation;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
|
||||
|
||||
@@ -91,8 +92,8 @@ public interface WindowsTerminalType extends ExternalTerminalType, TrackableTerm
|
||||
newProfile.put("suppressApplicationTitle", true);
|
||||
newProfile.put("elevate", false);
|
||||
if (!AppProperties.get().isDevelopmentEnvironment()) {
|
||||
var dir = XPipeInstallation.getLocalDefaultInstallationIcon();
|
||||
newProfile.put("icon", dir.toString());
|
||||
var logoFile = AppInstallation.ofCurrent().getLogoPath();
|
||||
newProfile.put("icon", logoFile.toString());
|
||||
}
|
||||
profiles.add(newProfile);
|
||||
JacksonMapper.getDefault().writeValue(getConfigFile().toFile(), config);
|
||||
|
||||
@@ -15,7 +15,7 @@ public class LocalExtensionTest extends ExtensionTest {
|
||||
return;
|
||||
}
|
||||
|
||||
var mode = OsType.getLocal().equals(OsType.WINDOWS) ? "tray" : "background";
|
||||
var mode = OsType.getLocal() == OsType.WINDOWS ? "tray" : "background";
|
||||
OperationMode.init(new String[] {"-Dio.xpipe.app.mode=" + mode});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import io.xpipe.app.process.ShellScript;
|
||||
import io.xpipe.app.util.LocalExec;
|
||||
import io.xpipe.app.util.Translatable;
|
||||
import io.xpipe.core.OsType;
|
||||
import io.xpipe.core.XPipeInstallation;
|
||||
|
||||
|
||||
import javafx.beans.value.ObservableValue;
|
||||
|
||||
@@ -110,9 +110,7 @@ public enum AppDistributionType implements Translatable {
|
||||
|
||||
private static boolean isDifferentDaemonExecutable() {
|
||||
var cached = AppCache.getNonNull("daemonExecutable", String.class, () -> null);
|
||||
var current = XPipeInstallation.getCurrentInstallationBasePath()
|
||||
.resolve(XPipeInstallation.getDaemonExecutablePath(OsType.getLocal()))
|
||||
.toString();
|
||||
var current = AppInstallation.ofCurrent().getDaemonExecutablePath().toString();
|
||||
if (current.equals(cached)) {
|
||||
return false;
|
||||
}
|
||||
@@ -130,9 +128,9 @@ public enum AppDistributionType implements Translatable {
|
||||
}
|
||||
|
||||
public static AppDistributionType determine() {
|
||||
var base = XPipeInstallation.getCurrentInstallationBasePath();
|
||||
if (OsType.getLocal().equals(OsType.MACOS)) {
|
||||
if (!base.equals(XPipeInstallation.getLocalDefaultInstallationBasePath())) {
|
||||
var base = AppInstallation.ofCurrent().getBaseInstallationPath();
|
||||
if (OsType.getLocal() == OsType.MACOS) {
|
||||
if (!base.equals(AppInstallation.ofDefault().getBaseInstallationPath())) {
|
||||
return PORTABLE;
|
||||
}
|
||||
|
||||
@@ -163,7 +161,7 @@ public enum AppDistributionType implements Translatable {
|
||||
return WEBTOP;
|
||||
}
|
||||
|
||||
if (OsType.getLocal().equals(OsType.WINDOWS) && !AppProperties.get().isStaging()) {
|
||||
if (OsType.getLocal() == OsType.WINDOWS && !AppProperties.get().isStaging()) {
|
||||
var chocoOut = LocalExec.readStdoutIfPossible("choco", "list", "xpipe");
|
||||
if (chocoOut.isPresent()) {
|
||||
if (chocoOut.get().contains("xpipe")
|
||||
@@ -182,7 +180,7 @@ public enum AppDistributionType implements Translatable {
|
||||
// }
|
||||
}
|
||||
|
||||
if (OsType.getLocal().equals(OsType.MACOS)) {
|
||||
if (OsType.getLocal() == OsType.MACOS) {
|
||||
var out = LocalExec.readStdoutIfPossible("/opt/homebrew/bin/brew", "list", "--casks", "--versions");
|
||||
if (out.isPresent()) {
|
||||
if (out.get().lines().anyMatch(s -> {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.xpipe.app.update;
|
||||
|
||||
import io.xpipe.app.core.AppInstallation;
|
||||
import io.xpipe.app.core.AppLogs;
|
||||
import io.xpipe.app.core.AppRestart;
|
||||
import io.xpipe.app.core.mode.OperationMode;
|
||||
@@ -14,7 +15,7 @@ import io.xpipe.app.util.ThreadHelper;
|
||||
import io.xpipe.core.FailableRunnable;
|
||||
import io.xpipe.core.FilePath;
|
||||
import io.xpipe.core.OsType;
|
||||
import io.xpipe.core.XPipeInstallation;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
@@ -27,17 +28,17 @@ import java.nio.file.Path;
|
||||
public class AppInstaller {
|
||||
|
||||
public static InstallerAssetType getSuitablePlatformAsset() {
|
||||
if (OsType.getLocal().equals(OsType.WINDOWS)) {
|
||||
if (OsType.getLocal() == OsType.WINDOWS) {
|
||||
return new InstallerAssetType.Msi();
|
||||
}
|
||||
|
||||
if (OsType.getLocal().equals(OsType.LINUX)) {
|
||||
if (OsType.getLocal() == OsType.LINUX) {
|
||||
return Files.exists(Path.of("/etc/debian_version"))
|
||||
? new InstallerAssetType.Debian()
|
||||
: new InstallerAssetType.Rpm();
|
||||
}
|
||||
|
||||
if (OsType.getLocal().equals(OsType.MACOS)) {
|
||||
if (OsType.getLocal() == OsType.MACOS) {
|
||||
return new InstallerAssetType.Pkg();
|
||||
}
|
||||
|
||||
@@ -69,7 +70,7 @@ public class AppInstaller {
|
||||
FilePath.of(logsDir, "installer_" + file.getFileName().toString() + ".log");
|
||||
var systemWide = isSystemWide();
|
||||
var cmdScript =
|
||||
ProcessControlProvider.get().getEffectiveLocalDialect().equals(ShellDialects.CMD)
|
||||
ProcessControlProvider.get().getEffectiveLocalDialect() == ShellDialects.CMD
|
||||
&& !systemWide;
|
||||
var command = cmdScript
|
||||
? getCmdCommand(file.toString(), logFile.toString())
|
||||
@@ -101,8 +102,7 @@ public class AppInstaller {
|
||||
}
|
||||
|
||||
private boolean isSystemWide() {
|
||||
return Files.exists(
|
||||
XPipeInstallation.getCurrentInstallationBasePath().resolve("system"));
|
||||
return Files.exists(AppInstallation.ofCurrent().getBaseInstallationPath().resolve("system"));
|
||||
}
|
||||
|
||||
private String getCmdCommand(String file, String logFile) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.xpipe.app.update;
|
||||
|
||||
import io.xpipe.app.comp.base.ModalButton;
|
||||
import io.xpipe.app.core.AppCache;
|
||||
import io.xpipe.app.core.AppInstallation;
|
||||
import io.xpipe.app.core.AppProperties;
|
||||
import io.xpipe.app.core.AppRestart;
|
||||
import io.xpipe.app.core.mode.OperationMode;
|
||||
@@ -13,7 +14,7 @@ import io.xpipe.app.terminal.TerminalLaunch;
|
||||
import io.xpipe.app.terminal.TerminalLauncher;
|
||||
import io.xpipe.app.util.Hyperlinks;
|
||||
import io.xpipe.app.util.LocalShell;
|
||||
import io.xpipe.core.XPipeInstallation;
|
||||
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.time.Instant;
|
||||
@@ -120,8 +121,7 @@ public class ChocoUpdater extends UpdateHandler {
|
||||
var performedUpdate = new PerformedUpdate(p.getVersion(), p.getBody(), p.getVersion());
|
||||
AppCache.update("performedUpdate", performedUpdate);
|
||||
OperationMode.executeAfterShutdown(() -> {
|
||||
var systemWide = Files.exists(
|
||||
XPipeInstallation.getCurrentInstallationBasePath().resolve("system"));
|
||||
var systemWide = Files.exists(AppInstallation.ofCurrent().getBaseInstallationPath().resolve("system"));
|
||||
var propertiesArguments = systemWide ? ", --install-arguments=\"'ALLUSERS=1'\"" : "";
|
||||
TerminalLaunch.builder().title("XPipe Updater").localScript(sc -> {
|
||||
var pkg = "xpipe";
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.xpipe.app.update;
|
||||
|
||||
import io.xpipe.app.comp.base.ModalButton;
|
||||
import io.xpipe.app.core.AppCache;
|
||||
import io.xpipe.app.core.AppInstallation;
|
||||
import io.xpipe.app.core.AppProperties;
|
||||
import io.xpipe.app.core.AppRestart;
|
||||
import io.xpipe.app.core.mode.OperationMode;
|
||||
@@ -12,7 +13,7 @@ import io.xpipe.app.terminal.TerminalLaunch;
|
||||
import io.xpipe.app.terminal.TerminalLauncher;
|
||||
import io.xpipe.app.util.Hyperlinks;
|
||||
import io.xpipe.app.util.LocalShell;
|
||||
import io.xpipe.core.XPipeInstallation;
|
||||
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.time.Instant;
|
||||
@@ -121,8 +122,7 @@ public class WingetUpdater extends UpdateHandler {
|
||||
AppCache.update("performedUpdate", performedUpdate);
|
||||
OperationMode.executeAfterShutdown(() -> {
|
||||
TerminalLaunch.builder().title("XPipe Updater").localScript(sc -> {
|
||||
var systemWide = Files.exists(
|
||||
XPipeInstallation.getCurrentInstallationBasePath().resolve("system"));
|
||||
var systemWide = Files.exists(AppInstallation.ofCurrent().getBaseInstallationPath().resolve("system"));
|
||||
var pkgId = "xpipe-io.xpipe";
|
||||
if (systemWide) {
|
||||
return ShellScript.lines(
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package io.xpipe.app.util;
|
||||
|
||||
import io.xpipe.app.core.AppInstallation;
|
||||
import io.xpipe.app.process.CommandBuilder;
|
||||
import io.xpipe.app.process.OsFileSystem;
|
||||
import io.xpipe.core.FilePath;
|
||||
import io.xpipe.core.OsType;
|
||||
import io.xpipe.core.XPipeInstallation;
|
||||
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
@@ -20,7 +21,7 @@ public class DesktopShortcuts {
|
||||
return shortcutPath;
|
||||
}
|
||||
|
||||
var icon = XPipeInstallation.getLocalDefaultInstallationIcon();
|
||||
var icon = AppInstallation.ofCurrent().getLogoPath();
|
||||
var content = String.format(
|
||||
"""
|
||||
$TARGET="%s"
|
||||
@@ -42,7 +43,7 @@ public class DesktopShortcuts {
|
||||
private static Path createLinuxShortcut(String executable, String args, String name) throws Exception {
|
||||
// Linux .desktop names are very restrictive
|
||||
var fixedName = name.replaceAll("[^\\w _]", "");
|
||||
var icon = XPipeInstallation.getLocalDefaultInstallationIcon();
|
||||
var icon = AppInstallation.ofCurrent().getLogoPath();
|
||||
var content = String.format(
|
||||
"""
|
||||
[Desktop Entry]
|
||||
@@ -72,7 +73,7 @@ public class DesktopShortcuts {
|
||||
}
|
||||
|
||||
private static Path createMacOSShortcut(String executable, String args, String name) throws Exception {
|
||||
var icon = XPipeInstallation.getLocalDefaultInstallationIcon();
|
||||
var icon = AppInstallation.ofCurrent().getLogoPath();
|
||||
var assets = icon.getParent().resolve("Assets.car");
|
||||
var base = DesktopHelper.getDesktopDirectory().resolve(name + ".app");
|
||||
var content = String.format(
|
||||
@@ -116,15 +117,15 @@ public class DesktopShortcuts {
|
||||
}
|
||||
|
||||
public static Path createCliOpen(String action, String name) throws Exception {
|
||||
var exec = XPipeInstallation.getLocalDefaultCliExecutable();
|
||||
var exec = AppInstallation.ofCurrent().getCliExecutablePath().toString();
|
||||
return create(exec, "open " + action, name);
|
||||
}
|
||||
|
||||
public static Path create(String executable, String args, String name) throws Exception {
|
||||
var compat = OsFileSystem.ofLocal().makeFileSystemCompatible(name);
|
||||
if (OsType.getLocal().equals(OsType.WINDOWS)) {
|
||||
if (OsType.getLocal() == OsType.WINDOWS) {
|
||||
return createWindowsShortcut(executable, args, compat);
|
||||
} else if (OsType.getLocal().equals(OsType.LINUX)) {
|
||||
} else if (OsType.getLocal() == OsType.LINUX) {
|
||||
return createLinuxShortcut(executable, args, compat);
|
||||
} else {
|
||||
return createMacOSShortcut(executable, args, compat);
|
||||
|
||||
@@ -74,14 +74,14 @@ public class FileOpener {
|
||||
|
||||
public static void openInDefaultApplication(String localFile) {
|
||||
try (var pc = LocalShell.getShell().start()) {
|
||||
if (pc.getOsType().equals(OsType.WINDOWS)) {
|
||||
if (pc.getOsType() == OsType.WINDOWS) {
|
||||
if (pc.getShellDialect() == ShellDialects.POWERSHELL) {
|
||||
pc.command(CommandBuilder.of().add("Invoke-Item").addFile(localFile))
|
||||
.execute();
|
||||
} else {
|
||||
pc.executeSimpleCommand("start \"\" \"" + localFile + "\"");
|
||||
}
|
||||
} else if (pc.getOsType().equals(OsType.LINUX)) {
|
||||
} else if (pc.getOsType() == OsType.LINUX) {
|
||||
pc.executeSimpleCommand("xdg-open \"" + localFile + "\"");
|
||||
} else {
|
||||
pc.executeSimpleCommand("open \"" + localFile + "\"");
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package io.xpipe.app.util;
|
||||
|
||||
import io.xpipe.app.core.AppInstallation;
|
||||
import io.xpipe.app.core.AppProperties;
|
||||
import io.xpipe.app.issue.ErrorEventFactory;
|
||||
import io.xpipe.core.OsType;
|
||||
import io.xpipe.core.XPipeInstallation;
|
||||
|
||||
import com.sun.jna.Library;
|
||||
import com.sun.jna.Native;
|
||||
@@ -35,7 +35,7 @@ public class NativeBridge {
|
||||
try {
|
||||
System.setProperty(
|
||||
"jna.library.path",
|
||||
XPipeInstallation.getCurrentInstallationBasePath()
|
||||
AppInstallation.ofCurrent().getBaseInstallationPath()
|
||||
.resolve("Contents")
|
||||
.resolve("runtime")
|
||||
.resolve("Contents")
|
||||
|
||||
@@ -65,7 +65,7 @@ public class ScriptHelper {
|
||||
|
||||
// Fix for powershell as there are permission issues when executing a powershell askpass script
|
||||
if (forceExecutable && ShellDialects.isPowershell(parent)) {
|
||||
scriptType = parent.getOsType().equals(OsType.WINDOWS) ? ShellDialects.CMD : ShellDialects.SH;
|
||||
scriptType = parent.getOsType() == OsType.WINDOWS ? ShellDialects.CMD : ShellDialects.SH;
|
||||
}
|
||||
|
||||
return createTerminalPreparedAskpassScript(pass, parent, scriptType);
|
||||
|
||||
@@ -19,7 +19,7 @@ public class ShellTemp {
|
||||
var temp = FileUtils.getTempDirectory().toPath().resolve("xpipe");
|
||||
// On Windows and macOS, we already have user specific temp directories
|
||||
// Even on macOS as root we will have a unique directory (in contrast to shell controls)
|
||||
if (OsType.getLocal().equals(OsType.LINUX)) {
|
||||
if (OsType.getLocal() == OsType.LINUX) {
|
||||
var user = System.getenv("USER");
|
||||
temp = temp.resolve(user != null ? user : "user");
|
||||
|
||||
@@ -39,7 +39,7 @@ public class ShellTemp {
|
||||
FilePath base;
|
||||
// On Windows and macOS, we already have user specific temp directories
|
||||
// Even on macOS as root it is technically unique as only root will use /tmp
|
||||
if (!proc.getOsType().equals(OsType.WINDOWS) && !proc.getOsType().equals(OsType.MACOS)) {
|
||||
if (proc.getOsType() != OsType.WINDOWS && proc.getOsType() != OsType.MACOS) {
|
||||
var temp = proc.getSystemTemporaryDirectory();
|
||||
base = temp.join("xpipe");
|
||||
proc.command(proc.getShellDialect().getMkdirsCommand(base.toString()))
|
||||
@@ -84,7 +84,7 @@ public class ShellTemp {
|
||||
}
|
||||
|
||||
private static boolean checkDirectoryPermissions(ShellControl proc, String dir) throws Exception {
|
||||
if (proc.getOsType().equals(OsType.WINDOWS)) {
|
||||
if (proc.getOsType() == OsType.WINDOWS) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.xpipe.app.util;
|
||||
|
||||
import io.xpipe.app.beacon.AppBeaconServer;
|
||||
import io.xpipe.app.core.AppInstallation;
|
||||
import io.xpipe.app.core.AppProperties;
|
||||
import io.xpipe.app.ext.ProcessControlProvider;
|
||||
import io.xpipe.app.issue.ErrorEventFactory;
|
||||
@@ -8,7 +9,7 @@ import io.xpipe.app.process.CommandBuilder;
|
||||
import io.xpipe.app.process.ShellControl;
|
||||
import io.xpipe.app.process.ShellDialects;
|
||||
import io.xpipe.core.FilePath;
|
||||
import io.xpipe.core.XPipeInstallation;
|
||||
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@@ -173,7 +174,7 @@ public class SshLocalBridge {
|
||||
}
|
||||
|
||||
private String getRemoteCommand(ShellControl sc) {
|
||||
var command = "\"" + XPipeInstallation.getLocalDefaultCliExecutable() + "\" ssh-launch "
|
||||
var command = "\"" + AppInstallation.ofCurrent().getCliExecutablePath() + "\" ssh-launch "
|
||||
+ sc.getShellDialect().environmentVariable("SSH_ORIGINAL_COMMAND");
|
||||
var p = Pattern.compile("\".+?\\\\Users\\\\([^\\\\]+)\\\\(.+)\"");
|
||||
var matcher = p.matcher(command);
|
||||
|
||||
@@ -50,7 +50,7 @@ public class StoreStateFormat {
|
||||
.format();
|
||||
}
|
||||
|
||||
if (s.getShellDialect().equals(ShellDialects.NO_INTERACTION)) {
|
||||
if (s.getShellDialect() == ShellDialects.NO_INTERACTION) {
|
||||
return new StoreStateFormat(null, null, info).format();
|
||||
}
|
||||
|
||||
|
||||
@@ -29,26 +29,8 @@ For a full documentation, see the [OpenAPI spec](https://docs.xpipe.io/api)
|
||||
The default port can be changed by passing the property `io.xpipe.beacon.port=<port>` to the daemon.
|
||||
Note that if both sides do not have the same port setting, they won't be able to reach each other.
|
||||
|
||||
#### Custom launch command
|
||||
|
||||
The beacon API also supports launching the daemon automatically in case it is not started yet.
|
||||
By default, it launches the daemon of the local XPipe installation.
|
||||
It is possible to pass a custom launch command with the property `io.xpipe.beacon.customDaemonCommand=<cmd>`
|
||||
and pass arguments to it using the property `io.xpipe.beacon.daemonArgs=<args>`.
|
||||
This allows for a custom launch behaviour in a testing/development environment.
|
||||
Note that the `<cmd>` value has to be a single property string, which can be prone to formatting errors
|
||||
|
||||
#### Verbose output
|
||||
|
||||
By passing the property `io.xpipe.beacon.printMessages=true`, it is possible to print debug information
|
||||
about the underlying communications.
|
||||
In case the `io.xpipe.beacon.printDaemonOutput` property is set, the output of the daemon can also be
|
||||
printed by passing the property `io.xpipe.beacon.debugExecOutput=true`.
|
||||
|
||||
#### Daemon debug mode
|
||||
|
||||
In case the daemon is started by the beacon, it is possible to customize in which mode the daemon will start up.
|
||||
By passing the property `io.xpipe.beacon.launchDebugDaemon=true`, the daemon is started in debug mode,
|
||||
i.e. will log more information and enable a few other options.
|
||||
By passing the property `io.xpipe.beacon.attachDebuggerToDaemon=true`, it is possible to launch a daemon
|
||||
in a mode where it is waiting to attach to a debugger first prior to starting up.
|
||||
|
||||
@@ -2,7 +2,6 @@ package io.xpipe.beacon;
|
||||
|
||||
import io.xpipe.beacon.api.HandshakeExchange;
|
||||
import io.xpipe.core.JacksonMapper;
|
||||
import io.xpipe.core.XPipeInstallation;
|
||||
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import lombok.SneakyThrows;
|
||||
@@ -26,7 +25,7 @@ public class BeaconClient {
|
||||
|
||||
public static BeaconClient establishConnection(int port, BeaconClientInformation information) throws Exception {
|
||||
var client = new BeaconClient(port);
|
||||
var auth = Files.readString(XPipeInstallation.getLocalBeaconAuthFile());
|
||||
var auth = Files.readString(BeaconConfig.getLocalBeaconAuthFile());
|
||||
HandshakeExchange.Response response = client.performRequest(HandshakeExchange.Request.builder()
|
||||
.client(information)
|
||||
.auth(BeaconAuthMethod.Local.builder().authFileContent(auth).build())
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
package io.xpipe.beacon;
|
||||
|
||||
import io.xpipe.core.XPipeInstallation;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Optional;
|
||||
|
||||
@UtilityClass
|
||||
public class BeaconConfig {
|
||||
|
||||
public static final String BEACON_PORT_PROP = "io.xpipe.beacon.port";
|
||||
public static final String DAEMON_ARGUMENTS_PROP = "io.xpipe.beacon.daemonArgs";
|
||||
private static final String PRINT_MESSAGES_PROPERTY = "io.xpipe.beacon.printMessages";
|
||||
private static final String LAUNCH_DAEMON_IN_DEBUG_PROP = "io.xpipe.beacon.launchDebugDaemon";
|
||||
private static final String ATTACH_DEBUGGER_PROP = "io.xpipe.beacon.attachDebuggerToDaemon";
|
||||
private static final String EXEC_DEBUG_PROP = "io.xpipe.beacon.printDaemonOutput";
|
||||
private static final String EXEC_PROCESS_PROP = "io.xpipe.beacon.customDaemonCommand";
|
||||
|
||||
public static boolean printMessages() {
|
||||
if (System.getProperty(PRINT_MESSAGES_PROPERTY) != null) {
|
||||
@@ -22,27 +19,6 @@ public class BeaconConfig {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean launchDaemonInDebugMode() {
|
||||
if (System.getProperty(LAUNCH_DAEMON_IN_DEBUG_PROP) != null) {
|
||||
return Boolean.parseBoolean(System.getProperty(LAUNCH_DAEMON_IN_DEBUG_PROP));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean attachDebuggerToDaemon() {
|
||||
if (System.getProperty(ATTACH_DEBUGGER_PROP) != null) {
|
||||
return Boolean.parseBoolean(System.getProperty(ATTACH_DEBUGGER_PROP));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean printDaemonOutput() {
|
||||
if (System.getProperty(EXEC_DEBUG_PROP) != null) {
|
||||
return Boolean.parseBoolean(System.getProperty(EXEC_DEBUG_PROP));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static int getUsedPort() {
|
||||
var beaconPort = System.getenv("BEACON_PORT");
|
||||
if (beaconPort != null && !beaconPort.isBlank()) {
|
||||
@@ -53,22 +29,21 @@ public class BeaconConfig {
|
||||
return Integer.parseInt(System.getProperty(BEACON_PORT_PROP));
|
||||
}
|
||||
|
||||
return XPipeInstallation.getDefaultBeaconPort();
|
||||
return getDefaultBeaconPort();
|
||||
}
|
||||
|
||||
public static String getCustomDaemonCommand() {
|
||||
if (System.getProperty(EXEC_PROCESS_PROP) != null) {
|
||||
return System.getProperty(EXEC_PROCESS_PROP);
|
||||
}
|
||||
|
||||
return null;
|
||||
public static int getDefaultBeaconPort() {
|
||||
var staging = Optional.ofNullable(System.getProperty("io.xpipe.app.staging"))
|
||||
.map(Boolean::parseBoolean)
|
||||
.orElse(false);
|
||||
var offset = staging ? 1 : 0;
|
||||
return 21721 + offset;
|
||||
}
|
||||
|
||||
public static String getDaemonArguments() {
|
||||
if (System.getProperty(DAEMON_ARGUMENTS_PROP) != null) {
|
||||
return System.getProperty(DAEMON_ARGUMENTS_PROP);
|
||||
}
|
||||
|
||||
return null;
|
||||
public static Path getLocalBeaconAuthFile() {
|
||||
var staging = Optional.ofNullable(System.getProperty("io.xpipe.app.staging"))
|
||||
.map(Boolean::parseBoolean)
|
||||
.orElse(false);
|
||||
return Path.of(System.getProperty("java.io.tmpdir"), staging ? "xpipe_ptb_auth" : "xpipe_auth");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
package io.xpipe.beacon;
|
||||
|
||||
import io.xpipe.beacon.api.DaemonStopExchange;
|
||||
import io.xpipe.core.FilePath;
|
||||
import io.xpipe.core.OsType;
|
||||
import io.xpipe.core.XPipeDaemonMode;
|
||||
import io.xpipe.core.XPipeInstallation;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
@@ -14,11 +10,10 @@ import java.net.Inet4Address;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Contains basic functionality to start, communicate, and stop a remote beacon server.
|
||||
*/
|
||||
public class BeaconServer {
|
||||
|
||||
@SneakyThrows
|
||||
@@ -42,109 +37,9 @@ public class BeaconServer {
|
||||
}
|
||||
}
|
||||
|
||||
private static List<String> toProcessCommand(String toExec) {
|
||||
// Having the trailing space is very important to force cmd to not interpret surrounding spaces and removing
|
||||
// them
|
||||
return OsType.getLocal().equals(OsType.WINDOWS)
|
||||
? List.of("cmd", "/c", toExec + " ")
|
||||
: List.of("sh", "-c", toExec);
|
||||
}
|
||||
|
||||
public static Process tryStartCustom() throws Exception {
|
||||
var custom = BeaconConfig.getCustomDaemonCommand();
|
||||
if (custom != null) {
|
||||
var toExec =
|
||||
custom + (BeaconConfig.getDaemonArguments() != null ? " " + BeaconConfig.getDaemonArguments() : "");
|
||||
var command = toProcessCommand(toExec);
|
||||
Process process = Runtime.getRuntime().exec(command.toArray(String[]::new));
|
||||
printDaemonOutput(process, command);
|
||||
return process;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Process start(String installationBase, XPipeDaemonMode mode) throws Exception {
|
||||
String command;
|
||||
if (!BeaconConfig.launchDaemonInDebugMode()) {
|
||||
command = XPipeInstallation.createExternalAsyncLaunchCommand(
|
||||
installationBase, mode, BeaconConfig.getDaemonArguments(), false);
|
||||
} else {
|
||||
command = XPipeInstallation.createExternalLaunchCommand(
|
||||
getDaemonDebugExecutable(installationBase), BeaconConfig.getDaemonArguments(), mode);
|
||||
}
|
||||
|
||||
var fullCommand = toProcessCommand(command);
|
||||
Process process = new ProcessBuilder(fullCommand).start();
|
||||
printDaemonOutput(process, fullCommand);
|
||||
return process;
|
||||
}
|
||||
|
||||
private static void printDaemonOutput(Process proc, List<String> command) {
|
||||
boolean print = BeaconConfig.printDaemonOutput();
|
||||
if (print) {
|
||||
System.out.println("Starting daemon: " + command);
|
||||
}
|
||||
|
||||
var out = new Thread(
|
||||
null,
|
||||
() -> {
|
||||
try {
|
||||
InputStreamReader isr = new InputStreamReader(proc.getInputStream());
|
||||
BufferedReader br = new BufferedReader(isr);
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
if (print) {
|
||||
System.out.println("[xpiped] " + line);
|
||||
}
|
||||
}
|
||||
} catch (Exception ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
},
|
||||
"daemon sysout");
|
||||
out.setDaemon(true);
|
||||
out.start();
|
||||
|
||||
var err = new Thread(
|
||||
null,
|
||||
() -> {
|
||||
try {
|
||||
InputStreamReader isr = new InputStreamReader(proc.getErrorStream());
|
||||
BufferedReader br = new BufferedReader(isr);
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
if (print) {
|
||||
System.err.println("[xpiped] " + line);
|
||||
}
|
||||
}
|
||||
} catch (Exception ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
},
|
||||
"daemon syserr");
|
||||
err.setDaemon(true);
|
||||
err.start();
|
||||
}
|
||||
|
||||
public static boolean tryStop(BeaconClient client) throws Exception {
|
||||
DaemonStopExchange.Response res =
|
||||
client.performRequest(DaemonStopExchange.Request.builder().build());
|
||||
return res.isSuccess();
|
||||
}
|
||||
|
||||
public static String getDaemonDebugExecutable(String installationBase) {
|
||||
var osType = OsType.getLocal();
|
||||
var debug = BeaconConfig.launchDaemonInDebugMode();
|
||||
if (!debug) {
|
||||
throw new IllegalStateException();
|
||||
} else {
|
||||
if (BeaconConfig.attachDebuggerToDaemon()) {
|
||||
return FilePath.of(installationBase, XPipeInstallation.getDaemonDebugAttachScriptPath(osType))
|
||||
.toString();
|
||||
} else {
|
||||
return FilePath.of(installationBase, XPipeInstallation.getDaemonDebugScriptPath(osType))
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
package io.xpipe.beacon.test;
|
||||
|
||||
import io.xpipe.beacon.BeaconClient;
|
||||
import io.xpipe.beacon.BeaconClientInformation;
|
||||
import io.xpipe.beacon.BeaconConfig;
|
||||
import io.xpipe.beacon.BeaconServer;
|
||||
import io.xpipe.core.XPipeDaemonMode;
|
||||
import io.xpipe.core.XPipeInstallation;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class BeaconDaemonController {
|
||||
|
||||
private static boolean alreadyStarted;
|
||||
|
||||
public static void start(XPipeDaemonMode mode) throws Exception {
|
||||
if (BeaconServer.isReachable(BeaconConfig.getUsedPort())) {
|
||||
alreadyStarted = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var custom = false;
|
||||
Process process;
|
||||
if ((process = BeaconServer.tryStartCustom()) != null) {
|
||||
custom = true;
|
||||
} else {
|
||||
var defaultBase = XPipeInstallation.getLocalDefaultInstallationBasePath();
|
||||
process = BeaconServer.start(defaultBase.toString(), mode);
|
||||
}
|
||||
|
||||
waitForStartup(process, custom);
|
||||
if (!BeaconServer.isReachable(BeaconConfig.getUsedPort())) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
public static void stop() throws Exception {
|
||||
if (alreadyStarted) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!BeaconServer.isReachable(BeaconConfig.getUsedPort())) {
|
||||
return;
|
||||
}
|
||||
|
||||
var client = BeaconClient.establishConnection(
|
||||
BeaconConfig.getUsedPort(),
|
||||
BeaconClientInformation.Api.builder()
|
||||
.name("Beacon daemon controller")
|
||||
.build());
|
||||
if (!BeaconServer.tryStop(client)) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
waitForShutdown();
|
||||
}
|
||||
|
||||
private static void waitForStartup(Process process, boolean custom) throws IOException {
|
||||
for (int i = 0; i < 160; i++) {
|
||||
// Breaks when using nohup & disown
|
||||
// if (process != null && !custom && !process.isAlive()) {
|
||||
// throw new IOException("Daemon start failed");
|
||||
// }
|
||||
|
||||
if (process != null && custom && !process.isAlive() && process.exitValue() != 0) {
|
||||
throw new IOException("Custom launch command failed");
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
|
||||
var s = BeaconClient.tryEstablishConnection(
|
||||
BeaconConfig.getUsedPort(),
|
||||
BeaconClientInformation.Api.builder()
|
||||
.name("Beacon daemon controller")
|
||||
.build());
|
||||
if (s.isPresent()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IOException("Wait for daemon start up timed out");
|
||||
}
|
||||
|
||||
private static void waitForShutdown() {
|
||||
for (int i = 0; i < 40; i++) {
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
|
||||
var r = BeaconServer.isReachable(BeaconConfig.getUsedPort());
|
||||
if (!r) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package io.xpipe.beacon.test;
|
||||
|
||||
import io.xpipe.core.ModuleLayerLoader;
|
||||
import io.xpipe.core.OsType;
|
||||
import io.xpipe.core.XPipeDaemonMode;
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
|
||||
public class BeaconDaemonExtensionTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void setup() throws Exception {
|
||||
ModuleLayerLoader.loadAll(ModuleLayer.boot(), throwable -> throwable.printStackTrace());
|
||||
BeaconDaemonController.start(
|
||||
OsType.getLocal().equals(OsType.WINDOWS) ? XPipeDaemonMode.TRAY : XPipeDaemonMode.BACKGROUND);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void teardown() throws Exception {
|
||||
BeaconDaemonController.stop();
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import com.fasterxml.jackson.databind.Module;
|
||||
|
||||
open module io.xpipe.beacon {
|
||||
exports io.xpipe.beacon;
|
||||
exports io.xpipe.beacon.test;
|
||||
exports io.xpipe.beacon.api;
|
||||
|
||||
requires com.fasterxml.jackson.core;
|
||||
|
||||
@@ -63,7 +63,7 @@ public class Deobfuscator {
|
||||
var file = Files.createTempFile("xpipe_stracktrace", null);
|
||||
Files.writeString(file, stackTrace);
|
||||
var proc = new ProcessBuilder(
|
||||
"retrace." + (OsType.getLocal().equals(OsType.WINDOWS) ? "bat" : "sh"),
|
||||
"retrace." + (OsType.getLocal() == OsType.WINDOWS ? "bat" : "sh"),
|
||||
System.getenv("XPIPE_MAPPING"),
|
||||
file.toString())
|
||||
.redirectErrorStream(true);
|
||||
|
||||
@@ -1,298 +0,0 @@
|
||||
package io.xpipe.core;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Optional;
|
||||
|
||||
public class XPipeInstallation {
|
||||
|
||||
private static final String STAGING_PROP = "io.xpipe.app.staging";
|
||||
|
||||
@Getter
|
||||
private static final boolean staging = Optional.ofNullable(System.getProperty(STAGING_PROP))
|
||||
.map(Boolean::parseBoolean)
|
||||
.orElse(false);
|
||||
|
||||
public static int getDefaultBeaconPort() {
|
||||
var offset = isStaging() ? 1 : 0;
|
||||
return 21721 + offset;
|
||||
}
|
||||
|
||||
public static Path getLocalBeaconAuthFile() {
|
||||
return Path.of(System.getProperty("java.io.tmpdir"), isStaging() ? "xpipe_ptb_auth" : "xpipe_auth");
|
||||
}
|
||||
|
||||
public static String createExternalAsyncLaunchCommand(
|
||||
String installationBase, XPipeDaemonMode mode, String arguments, boolean restart) {
|
||||
var suffix = (arguments != null ? " " + arguments : "");
|
||||
var modeOption = mode != null ? " -Dio.xpipe.app.mode=" + mode.getDisplayName() : "";
|
||||
if (OsType.getLocal().equals(OsType.LINUX)) {
|
||||
return "nohup \"" + installationBase + "/bin/xpiped\"" + modeOption + suffix
|
||||
+ "</dev/null >/dev/null 2>&1 & disown";
|
||||
} else if (OsType.getLocal().equals(OsType.MACOS)) {
|
||||
if (restart) {
|
||||
return "(sleep 1;open \"" + installationBase + "\" --args" + modeOption + suffix
|
||||
+ "</dev/null &>/dev/null) & disown";
|
||||
} else {
|
||||
return "open \"" + installationBase + "\" --args" + modeOption + suffix;
|
||||
}
|
||||
}
|
||||
|
||||
return "\"" + FilePath.of(installationBase, XPipeInstallation.getDaemonExecutablePath(OsType.getLocal())) + "\""
|
||||
+ modeOption + suffix;
|
||||
}
|
||||
|
||||
public static String createExternalLaunchCommand(String command, String arguments, XPipeDaemonMode mode) {
|
||||
var suffix = (arguments != null ? " " + arguments : "");
|
||||
var modeOption = mode != null ? " -Dio.xpipe.app.mode=" + mode.getDisplayName() : "";
|
||||
return "\"" + command + "\"" + modeOption + suffix;
|
||||
}
|
||||
|
||||
private static boolean isImage() {
|
||||
return XPipeInstallation.class
|
||||
.getProtectionDomain()
|
||||
.getCodeSource()
|
||||
.getLocation()
|
||||
.getProtocol()
|
||||
.equals("jrt");
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static Path getCurrentInstallationBasePath() {
|
||||
var command = ProcessHandle.current().info().command();
|
||||
// We should always have a command associated with the current process, otherwise something went seriously wrong
|
||||
if (command.isEmpty()) {
|
||||
var javaHome = System.getProperty("java.home");
|
||||
var javaExec = toRealPathIfPossible(Path.of(javaHome, "bin", "java"));
|
||||
var path = getLocalInstallationBasePathForJavaExecutable(javaExec);
|
||||
return path;
|
||||
}
|
||||
|
||||
// Resolve any possible links to a real path
|
||||
Path path = toRealPathIfPossible(Path.of(command.get()));
|
||||
// Check if the process was started using a relative path, and adapt it if necessary
|
||||
if (!path.isAbsolute()) {
|
||||
path = toRealPathIfPossible(Path.of(System.getProperty("user.dir")).resolve(path));
|
||||
}
|
||||
|
||||
var name = path.getFileName().toString();
|
||||
// Check if we launched the JVM via a start script instead of the native executable
|
||||
if (name.endsWith("java") || name.endsWith("java.exe")) {
|
||||
// If we are not an image, we are probably running in a development environment where we want to use the
|
||||
// working directory
|
||||
var isImage = isImage();
|
||||
if (!isImage) {
|
||||
return Path.of(System.getProperty("user.dir"));
|
||||
}
|
||||
return getLocalInstallationBasePathForJavaExecutable(path);
|
||||
} else {
|
||||
return getLocalInstallationBasePathForDaemonExecutable(path);
|
||||
}
|
||||
}
|
||||
|
||||
private static Path toRealPathIfPossible(Path p) {
|
||||
try {
|
||||
// Under certain conditions, e.g. when running on a ramdisk, path resolution might fail.
|
||||
// This is however not a big problem in that case, so we ignore it
|
||||
return p.toRealPath();
|
||||
} catch (IOException e) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
public static Path getLocalExtensionsDirectory(Path path) {
|
||||
return OsType.getLocal().equals(OsType.MACOS)
|
||||
? path.resolve("Contents").resolve("Resources").resolve("extensions")
|
||||
: path.resolve("extensions");
|
||||
}
|
||||
|
||||
private static Path getLocalInstallationBasePathForJavaExecutable(Path executable) {
|
||||
// Resolve root path of installation relative to the java executable in a JPackage installation
|
||||
if (OsType.getLocal().equals(OsType.MACOS)) {
|
||||
return executable
|
||||
.getParent()
|
||||
.getParent()
|
||||
.getParent()
|
||||
.getParent()
|
||||
.getParent()
|
||||
.getParent();
|
||||
} else if (OsType.getLocal().equals(OsType.LINUX)) {
|
||||
return executable.getParent().getParent().getParent().getParent();
|
||||
} else {
|
||||
return executable.getParent().getParent().getParent();
|
||||
}
|
||||
}
|
||||
|
||||
private static Path getLocalInstallationBasePathForDaemonExecutable(Path executable) {
|
||||
// Resolve root path of installation relative to executable in a JPackage installation
|
||||
if (OsType.getLocal().equals(OsType.MACOS)) {
|
||||
return executable.getParent().getParent().getParent();
|
||||
} else if (OsType.getLocal().equals(OsType.LINUX)) {
|
||||
return executable.getParent().getParent();
|
||||
} else {
|
||||
return executable.getParent();
|
||||
}
|
||||
}
|
||||
|
||||
public static Path getLocalInstallationBasePathForCLI(String cliExecutable) {
|
||||
var defaultInstallation = getLocalDefaultInstallationBasePath();
|
||||
|
||||
// Can be empty in development mode
|
||||
if (cliExecutable == null) {
|
||||
return defaultInstallation;
|
||||
}
|
||||
|
||||
if (OsType.getLocal().equals(OsType.LINUX) && cliExecutable.equals("/usr/bin/xpipe")) {
|
||||
return defaultInstallation;
|
||||
}
|
||||
|
||||
var path = Path.of(cliExecutable);
|
||||
if (OsType.getLocal().equals(OsType.MACOS)) {
|
||||
return path.getParent().getParent().getParent();
|
||||
} else if (OsType.getLocal().equals(OsType.LINUX)) {
|
||||
return path.getParent().getParent();
|
||||
} else {
|
||||
return path.getParent().getParent();
|
||||
}
|
||||
}
|
||||
|
||||
public static String queryLocalInstallationVersion(String exec) throws Exception {
|
||||
var process = new ProcessBuilder(exec, "version")
|
||||
.redirectError(ProcessBuilder.Redirect.DISCARD)
|
||||
.start();
|
||||
var v = new String(process.getInputStream().readAllBytes(), StandardCharsets.US_ASCII);
|
||||
process.waitFor();
|
||||
return v;
|
||||
}
|
||||
|
||||
public static String getLocalDefaultCliExecutable() {
|
||||
Path path = isImage() ? getCurrentInstallationBasePath() : getLocalDefaultInstallationBasePath();
|
||||
return path.resolve(getRelativeCliExecutablePath(OsType.getLocal())).toString();
|
||||
}
|
||||
|
||||
public static Path getLocalDefaultInstallationIcon() {
|
||||
Path path = getCurrentInstallationBasePath();
|
||||
|
||||
// Check for development environment
|
||||
if (!isImage()) {
|
||||
if (OsType.getLocal().equals(OsType.WINDOWS)) {
|
||||
return path.resolve("dist").resolve("logo").resolve("logo.ico");
|
||||
} else if (OsType.getLocal().equals(OsType.LINUX)) {
|
||||
return path.resolve("dist").resolve("logo").resolve("logo.png");
|
||||
} else {
|
||||
return path.resolve("dist").resolve("logo").resolve("logo.icns");
|
||||
}
|
||||
}
|
||||
|
||||
if (OsType.getLocal().equals(OsType.WINDOWS)) {
|
||||
return path.resolve("logo.ico");
|
||||
} else if (OsType.getLocal().equals(OsType.LINUX)) {
|
||||
return path.resolve("logo.png");
|
||||
} else {
|
||||
return path.resolve("Contents").resolve("Resources").resolve("xpipe.icns");
|
||||
}
|
||||
}
|
||||
|
||||
public static Path getLocalDefaultInstallationBasePath() {
|
||||
return getLocalDefaultInstallationBasePath(staging);
|
||||
}
|
||||
|
||||
public static Path getLocalDefaultInstallationBasePath(boolean stage) {
|
||||
Path path;
|
||||
if (OsType.getLocal().equals(OsType.WINDOWS)) {
|
||||
var pg = System.getenv("ProgramFiles");
|
||||
var systemPath = Path.of(pg, stage ? "XPipe PTB" : "XPipe");
|
||||
if (Files.exists(systemPath)) {
|
||||
return systemPath;
|
||||
}
|
||||
|
||||
var base = Path.of(System.getenv("LOCALAPPDATA"));
|
||||
path = base.resolve(stage ? "XPipe PTB" : "XPipe");
|
||||
} else if (OsType.getLocal().equals(OsType.LINUX)) {
|
||||
path = Path.of(stage ? "/opt/xpipe-ptb" : "/opt/xpipe");
|
||||
} else {
|
||||
path = Path.of(stage ? "/Applications/XPipe PTB.app" : "/Applications/XPipe.app");
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
public static Path getLangPath() {
|
||||
if (!isImage()) {
|
||||
return getCurrentInstallationBasePath().resolve("lang");
|
||||
}
|
||||
|
||||
var install = getCurrentInstallationBasePath();
|
||||
var type = OsType.getLocal();
|
||||
if (type.equals(OsType.WINDOWS)) {
|
||||
return install.resolve("lang");
|
||||
} else if (type.equals(OsType.LINUX)) {
|
||||
return install.resolve("lang");
|
||||
} else {
|
||||
return install.resolve("Contents").resolve("Resources").resolve("lang");
|
||||
}
|
||||
}
|
||||
|
||||
public static Path getBundledFontsPath() {
|
||||
if (!isImage()) {
|
||||
return Path.of("dist", "fonts");
|
||||
}
|
||||
|
||||
var install = getCurrentInstallationBasePath();
|
||||
var type = OsType.getLocal();
|
||||
if (type.equals(OsType.WINDOWS)) {
|
||||
return install.resolve("fonts");
|
||||
} else if (type.equals(OsType.LINUX)) {
|
||||
return install.resolve("fonts");
|
||||
} else {
|
||||
return install.resolve("Contents").resolve("Resources").resolve("fonts");
|
||||
}
|
||||
}
|
||||
|
||||
public static String getDaemonDebugScriptPath(OsType.Local type) {
|
||||
if (type.equals(OsType.WINDOWS)) {
|
||||
return FilePath.of("scripts", "xpiped_debug.bat").toString();
|
||||
} else if (type.equals(OsType.LINUX)) {
|
||||
return FilePath.of("scripts", "xpiped_debug.sh").toString();
|
||||
} else {
|
||||
return FilePath.of("Contents", "Resources", "scripts", "xpiped_debug.sh")
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public static String getDaemonDebugAttachScriptPath(OsType.Local type) {
|
||||
if (type.equals(OsType.WINDOWS)) {
|
||||
return FilePath.of("scripts", "xpiped_debug_attach.bat").toString();
|
||||
} else if (type.equals(OsType.LINUX)) {
|
||||
return FilePath.of("scripts", "xpiped_debug_attach.sh").toString();
|
||||
} else {
|
||||
return FilePath.of("Contents", "Resources", "scripts", "xpiped_debug_attach.sh")
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public static String getDaemonExecutablePath(OsType.Local type) {
|
||||
if (type.equals(OsType.WINDOWS)) {
|
||||
return FilePath.of("xpiped.exe").toString();
|
||||
} else if (type.equals(OsType.LINUX)) {
|
||||
return FilePath.of("bin", "xpiped").toString();
|
||||
} else {
|
||||
return FilePath.of("Contents", "MacOS", "xpiped").toString();
|
||||
}
|
||||
}
|
||||
|
||||
public static String getRelativeCliExecutablePath(OsType.Local type) {
|
||||
if (type.equals(OsType.WINDOWS)) {
|
||||
return FilePath.of("bin", "xpipe.exe").toString();
|
||||
} else if (type.equals(OsType.LINUX)) {
|
||||
return FilePath.of("bin", "xpipe").toString();
|
||||
} else {
|
||||
return FilePath.of("Contents", "MacOS", "xpipe").toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -67,7 +67,7 @@ public class SshIdentityStateManager {
|
||||
event.customAction(shutdown).handle();
|
||||
|
||||
if (r.get()) {
|
||||
if (sc.getShellDialect().equals(ShellDialects.CMD)) {
|
||||
if (sc.getShellDialect() == ShellDialects.CMD) {
|
||||
sc.command(
|
||||
"powershell -Command \"Start-Process cmd -Wait -ArgumentList /c, sc, stop, ssh-agent -Verb runAs\"")
|
||||
.executeAndCheck();
|
||||
|
||||
@@ -136,7 +136,7 @@ public interface SshIdentityStrategy {
|
||||
|
||||
@Override
|
||||
public void prepareParent(ShellControl parent) throws Exception {
|
||||
if (!parent.getOsType().equals(OsType.WINDOWS)) {
|
||||
if (parent.getOsType() != OsType.WINDOWS) {
|
||||
var out = parent.executeSimpleStringCommand("pageant -l");
|
||||
if (out.isBlank()) {
|
||||
throw ErrorEventFactory.expected(
|
||||
@@ -157,7 +157,7 @@ public interface SshIdentityStrategy {
|
||||
@Override
|
||||
public void buildCommand(CommandBuilder builder) {
|
||||
builder.environment("SSH_AUTH_SOCK", parent -> {
|
||||
if (parent.getOsType().equals(OsType.WINDOWS)) {
|
||||
if (parent.getOsType() == OsType.WINDOWS) {
|
||||
return getPageantWindowsPipe(parent);
|
||||
}
|
||||
|
||||
@@ -332,7 +332,7 @@ public interface SshIdentityStrategy {
|
||||
+ " is marked to be a public key file, SSH authentication requires the private key"));
|
||||
}
|
||||
|
||||
if ((parent.getOsType().equals(OsType.LINUX) || parent.getOsType().equals(OsType.MACOS))) {
|
||||
if ((parent.getOsType() == OsType.LINUX || parent.getOsType() == OsType.MACOS)) {
|
||||
// Try to preserve the same permission set
|
||||
parent.command(CommandBuilder.of()
|
||||
.add("test", "-w")
|
||||
|
||||
@@ -26,10 +26,8 @@ testing {
|
||||
dependsOn(project.allExtensions.stream().map(p -> p.getTasksByName('jar', true)[0]).toList())
|
||||
|
||||
systemProperty 'io.xpipe.app.fullVersion', "true"
|
||||
systemProperty 'io.xpipe.beacon.printDaemonOutput', "false"
|
||||
systemProperty 'io.xpipe.app.useVirtualThreads', "false"
|
||||
systemProperty "io.xpipe.beacon.port", "21723"
|
||||
systemProperty "io.xpipe.beacon.launchDebugDaemon", "true"
|
||||
systemProperty "io.xpipe.app.dataDir", "$projectDir/local/"
|
||||
systemProperty "io.xpipe.app.logLevel", "trace"
|
||||
systemProperty "io.xpipe.app.writeSysOut", "true"
|
||||
|
||||
@@ -35,9 +35,7 @@ testing {
|
||||
" -Dio.xpipe.beacon.printMessages=true" +
|
||||
" -Dio.xpipe.app.logLevel=trace"
|
||||
|
||||
systemProperty 'io.xpipe.beacon.printDaemonOutput', "true"
|
||||
systemProperty "io.xpipe.beacon.port", "21723"
|
||||
systemProperty "io.xpipe.beacon.launchDebugDaemon", "true"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user