This commit is contained in:
crschnick
2025-08-10 16:19:53 +00:00
parent ab90a94468
commit b0d41a0213
49 changed files with 272 additions and 251 deletions
@@ -1,5 +1,6 @@
package io.xpipe.app.beacon.mcp;
import io.xpipe.app.core.AppNames;
import io.xpipe.app.core.AppProperties;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.app.prefs.AppPrefs;
@@ -36,7 +37,7 @@ public class AppMcpServer {
new ObjectMapper(), "/mcp", false, (req, context) -> context, null);
McpSyncServer syncServer = io.modelcontextprotocol.server.McpServer.sync(transportProvider)
.serverInfo("XPipe", AppProperties.get().getVersion())
.serverInfo(AppNames.ofCurrent().getName(), AppProperties.get().getVersion())
.capabilities(McpSchema.ServerCapabilities.builder()
.resources(true, true)
.tools(true)
@@ -73,18 +73,18 @@ public class CompressMenuProvider implements BrowserMenuBranchProvider {
return List.of(
new ZipActionProvider(false),
new TarBasedActionProvider(false, false) {
@Override
protected String getExtension() {
return "tar";
}
},
new TarBasedActionProvider(false, true) {
@Override
protected String getExtension() {
return "tar.gz";
}
},
new TarBasedActionProvider(false, false) {
@Override
protected String getExtension() {
return "tar";
}
});
}
@@ -113,18 +113,18 @@ public class CompressMenuProvider implements BrowserMenuBranchProvider {
BrowserFileSystemTabModel model, List<BrowserEntry> entries) {
return List.of(
new ZipActionProvider(directory),
new TarBasedActionProvider(directory, false) {
@Override
protected String getExtension() {
return "tar";
}
},
new TarBasedActionProvider(directory, true) {
@Override
protected String getExtension() {
return "tar.gz";
}
},
new TarBasedActionProvider(directory, false) {
@Override
protected String getExtension() {
return "tar";
}
});
}
}
@@ -82,7 +82,7 @@ public class AppMainWindowContentComp extends SimpleComp {
loadingIcon.setImage(AppImages.loadImage(image));
});
var version = new LabelComp((AppProperties.get().isStaging() ? "XPipe PTB" : "XPipe") + " "
var version = new LabelComp((AppNames.ofCurrent().getName()) + " "
+ AppProperties.get().getVersion());
version.apply(struc -> {
AppFontSizes.apply(struc.get(), appFontSizes -> "15");
@@ -60,14 +60,14 @@ public abstract class AppInstallation {
yield Path.of(stage ? "/Applications/XPipe PTB.app" : "/Applications/XPipe.app");
}
case OsType.Windows ignored -> {
var pg = AppLocations.getWindows().getProgramFiles();
var systemPath = pg.resolve(stage ? "XPipe PTB" : "XPipe");
var pg = AppSystemInfo.getWindows().getProgramFiles();
var systemPath = pg.resolve(AppNames.ofCurrent().getName());
if (Files.exists(systemPath)) {
yield systemPath;
}
var ad = AppLocations.getWindows().getLocalAppData();
yield ad.resolve(stage ? "XPipe PTB" : "XPipe");
var ad = AppSystemInfo.getWindows().getLocalAppData();
yield ad.resolve(AppNames.ofCurrent().getName());
}
};
}
@@ -135,7 +135,7 @@ public abstract class AppInstallation {
.getParent();
}
case OsType.Windows ignored -> {
yield executable.getParent().getParent();
yield executable.getParent().getParent().getParent();
}
};
}
@@ -1,5 +1,6 @@
package io.xpipe.app.core;
import io.xpipe.app.beacon.AppBeaconServer;
import io.xpipe.app.browser.BrowserFullSessionComp;
import io.xpipe.app.browser.BrowserFullSessionModel;
import io.xpipe.app.comp.Comp;
@@ -25,6 +26,7 @@ import lombok.Getter;
import lombok.Value;
import lombok.extern.jackson.Jacksonized;
import javax.print.Doc;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
@@ -154,13 +156,6 @@ public class AppLayoutModel {
null,
() -> Hyperlinks.open(Hyperlinks.DISCORD),
null)));
// new Entry(
// AppI18n.observable("api"),
// new LabelGraphic.IconGraphic("mdi2c-code-json"),
// null,
// () -> Hyperlinks.open(
// "http://localhost:" + AppBeaconServer.get().getPort()),
// null),);
if (AppDistributionType.get() != AppDistributionType.WEBTOP) {
l.add(new Entry(
AppI18n.observable("webtop"),
@@ -169,6 +164,12 @@ public class AppLayoutModel {
() -> Hyperlinks.open(Hyperlinks.GITHUB_WEBTOP),
null));
}
l.add(new Entry(
AppI18n.observable("mcp"),
new LabelGraphic.IconGraphic("mdi2c-code-json"),
null,
() -> DocumentationLink.MCP.open(),
null));
return l;
}
@@ -1,119 +0,0 @@
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 || path.isEmpty()) {
return null;
}
try {
return Path.of(path);
} catch (InvalidPathException ignored) {
return null;
}
}
final class Windows implements AppLocations {
private Path userHome;
public Path getSystemRoot() {
var root = AppLocations.parsePath(System.getenv("SystemRoot"));
if (root == null) {
return Path.of("C:\\Windows");
}
return root;
}
public Path getTemp() {
var env = AppLocations.parsePath(System.getenv("TEMP"));
if (env == null) {
env = AppLocations.parsePath(System.getenv("TMP"));
}
if (env == null) {
return getLocalAppData().resolve("Temp");
}
// Don't use system temp dir
if (env.startsWith(Path.of("C:\\Windows"))) {
return getLocalAppData().resolve("Temp");
}
return env;
}
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 {}
}
@@ -138,7 +138,7 @@ public class AppLogs {
if (shouldLogToFile) {
try {
FileUtils.forceMkdir(usedLogsDir.toFile());
var file = usedLogsDir.resolve("xpipe.log");
var file = usedLogsDir.resolve(AppNames.ofMain().getName() + "xpipe.log");
var fos = new FileOutputStream(file.toFile(), true);
var buf = new BufferedOutputStream(fos);
outFileStream = new PrintStream(buf, false);
@@ -0,0 +1,58 @@
package io.xpipe.app.core;
public abstract class AppNames {
public static AppNames ofMain() {
return new Main();
}
public static AppNames ofCurrent() {
if (AppProperties.get().isStaging()) {
return new Ptb();
} else {
return new Main();
}
}
public abstract String getName();
public abstract String getKebapName();
public abstract String getSnakeName();
private static class Main extends AppNames {
@Override
public String getName() {
return "XPipe";
}
@Override
public String getKebapName() {
return "xpipe";
}
@Override
public String getSnakeName() {
return "xpipe";
}
}
private static class Ptb extends AppNames {
@Override
public String getName() {
return "XPipe PTB";
}
@Override
public String getKebapName() {
return "xpipe-ptb";
}
@Override
public String getSnakeName() {
return "xpipe_ptb";
}
}
}
@@ -23,7 +23,7 @@ public class AppPreloader extends Preloader {
var c = Class.forName(
ModuleLayer.boot().findModule("javafx.graphics").orElseThrow(), "com.sun.glass.ui.Application");
var m = c.getDeclaredMethod("setName", String.class);
m.invoke(c.getMethod("GetApplication").invoke(null), AppProperties.get().isStaging() ? "XPipe PTB" : "XPipe");
m.invoke(c.getMethod("GetApplication").invoke(null), AppNames.ofCurrent().getName());
TrackEvent.info("Application preloader run");
}
}
@@ -19,20 +19,12 @@ public class AppProperties {
private static AppProperties INSTANCE;
boolean fullVersion;
@Getter
String version;
@Getter
String build;
UUID buildUuid;
String sentryUrl;
String arch;
@Getter
boolean image;
boolean staging;
boolean useVirtualThreads;
boolean debugThreads;
@@ -48,9 +40,6 @@ public class AppProperties {
UUID uuid;
boolean initialLaunch;
boolean restarted;
/**
* Unique identifier that resets on every XPipe restart.
*/
UUID sessionId;
boolean newBuildSession;
@@ -3,18 +3,129 @@ package io.xpipe.app.core;
import io.xpipe.core.OsType;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
public class AppSystemInfo {
public static class Windows {}
private static final Windows WINDOWS = new Windows();
private static final Linux LINUX = new Linux();
private static final MacOs MACOS = new MacOs();
public static Linux linux() {
public static Windows getWindows() {
if (OsType.getLocal() != OsType.WINDOWS) {
throw new IllegalStateException();
}
return WINDOWS;
}
public static Linux getLinux() {
if (OsType.getLocal() != OsType.LINUX) {
throw new IllegalStateException();
}
return new Linux();
return LINUX;
}
public static MacOs getMacOs() {
if (OsType.getLocal() != OsType.MACOS) {
throw new IllegalStateException();
}
return MACOS;
}
private static Path parsePath(String path) {
if (path == null || path.isEmpty()) {
return null;
}
try {
return Path.of(path);
} catch (InvalidPathException ignored) {
return null;
}
}
public static final class Windows {
private Path userHome;
public Path getSystemRoot() {
var root = AppSystemInfo.parsePath(System.getenv("SystemRoot"));
if (root == null) {
return Path.of("C:\\Windows");
}
return root;
}
public Path getTemp() {
var env = AppSystemInfo.parsePath(System.getenv("TEMP"));
if (env == null) {
env = AppSystemInfo.parsePath(System.getenv("TMP"));
}
if (env == null) {
return getLocalAppData().resolve("Temp");
}
// Don't use system temp dir
if (env.startsWith(Path.of("C:\\Windows"))) {
return getLocalAppData().resolve("Temp");
}
return env;
}
public Path getProgramFiles() {
var env = AppSystemInfo.parsePath(System.getenv("ProgramFiles"));
if (env != null) {
return env;
}
var def = Path.of("C:\\ProgramFiles");
return def;
}
public Path getLocalAppData() {
var env = AppSystemInfo.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 = AppSystemInfo.parsePath(System.getenv("USERPROFILE"));
if (dir == null) {
dir = AppSystemInfo.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;
}
}
public static class Linux {
@@ -24,5 +135,5 @@ public class AppSystemInfo {
}
}
public static class MacOS {}
public static class MacOs {}
}
@@ -30,7 +30,7 @@ public class AppTrayIcon {
PopupMenu popupMenu = new PopupMenu();
this.trayIcon =
new TrayIcon(loadImageFromURL(url), App.getApp().getStage().getTitle(), popupMenu);
this.trayIcon.setToolTip("XPipe");
this.trayIcon.setToolTip(AppNames.ofCurrent().getName());
this.trayIcon.setImageAutoSize(true);
{
@@ -1,6 +1,6 @@
package io.xpipe.app.core.check;
import io.xpipe.app.core.AppLocations;
import io.xpipe.app.core.AppSystemInfo;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.process.ShellDialects;
import io.xpipe.app.util.LocalShell;
@@ -11,7 +11,7 @@ import java.util.concurrent.TimeUnit;
public class AppCertutilCheck {
private static boolean getResult() {
var fc = new ProcessBuilder(AppLocations.getWindows().getSystemRoot().resolve("\\System32\\certutil").toString()).redirectErrorStream(true);
var fc = new ProcessBuilder(AppSystemInfo.getWindows().getSystemRoot().resolve("\\System32\\certutil").toString()).redirectErrorStream(true);
try {
var proc = fc.start();
var out = new String(proc.getInputStream().readAllBytes());
@@ -1,5 +1,6 @@
package io.xpipe.app.core.check;
import io.xpipe.app.core.AppNames;
import io.xpipe.app.ext.ProcessControlProvider;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.app.process.ProcessOutputException;
@@ -62,7 +63,7 @@ public abstract class AppShellChecker {
var fallback = !ProcessControlProvider.get()
.getEffectiveLocalDialect()
.equals(ProcessControlProvider.get().getFallbackDialect())
? "XPipe will now attempt to fall back to another shell."
? AppNames.ofCurrent().getName() + " will now attempt to fall back to another shell."
: "";
return """
Shell self-test failed for %s:
@@ -1,6 +1,6 @@
package io.xpipe.app.core.check;
import io.xpipe.app.core.AppLocations;
import io.xpipe.app.core.AppSystemInfo;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.core.OsType;
@@ -34,6 +34,6 @@ public class AppTempCheck {
return;
}
checkTemp(AppLocations.getWindows().getTemp().toString());
checkTemp(AppSystemInfo.getWindows().getTemp().toString());
}
}
@@ -312,7 +312,7 @@ public class AppMainWindow {
if (AppProperties.get().isShowcase() && event.getCode().equals(KeyCode.F12)) {
var image = stage.getScene().snapshot(null);
var awt = AppImages.toAwtImage(image);
var file = Path.of(System.getProperty("user.home"), "Desktop", "xpipe-screenshot.png");
var file = Path.of(System.getProperty("user.home"), "Desktop", AppNames.ofCurrent().getKebapName() + "-screenshot.png");
try {
ImageIO.write(awt, "png", file.toFile());
} catch (IOException e) {
@@ -1,6 +1,7 @@
package io.xpipe.app.core.window;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppNames;
import io.xpipe.app.core.AppProperties;
import io.xpipe.app.update.AppDistributionType;
import io.xpipe.app.util.LicenseProvider;
@@ -40,7 +41,7 @@ public class AppWindowTitle {
var t = LicenseProvider.get() != null
? " " + LicenseProvider.get().licenseTitle().getValue()
: "";
var base = String.format("XPipe%s (%s)", t, AppProperties.get().getVersion());
var base = String.format(AppNames.ofMain().getName() + "%s (%s)", t, AppProperties.get().getVersion());
var prefix = AppProperties.get().isStaging() ? "[Public Test Build, Not a proper release] " : "";
var dist = AppDistributionType.get();
if (dist != AppDistributionType.UNKNOWN) {
@@ -4,6 +4,7 @@ import io.xpipe.app.comp.Comp;
import io.xpipe.app.comp.base.LabelComp;
import io.xpipe.app.comp.base.VerticalComp;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.core.AppNames;
import io.xpipe.app.core.AppProperties;
import io.xpipe.app.update.AppDistributionType;
import io.xpipe.app.util.JfxHelper;
@@ -11,6 +12,7 @@ import io.xpipe.app.util.LabelGraphic;
import io.xpipe.app.util.OptionsBuilder;
import io.xpipe.core.OsType;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.beans.property.SimpleStringProperty;
import javafx.geometry.Insets;
@@ -49,7 +51,7 @@ public class AboutCategory extends AppPrefsCategory {
private Comp<?> createProperties() {
var title = Comp.of(() -> {
return JfxHelper.createNamedEntry(
AppI18n.observable("xPipeClient"),
new ReadOnlyStringWrapper(AppNames.ofCurrent().getName() + " Desktop"),
new SimpleStringProperty("Version " + AppProperties.get().getVersion() + " ("
+ AppProperties.get().getArch() + ")"),
"logo/logo.png");
@@ -4,7 +4,7 @@ import io.xpipe.app.beacon.AppBeaconServer;
import io.xpipe.app.comp.Comp;
import io.xpipe.app.comp.base.TextAreaComp;
import io.xpipe.app.comp.base.TextFieldComp;
import io.xpipe.app.core.AppProperties;
import io.xpipe.app.core.AppNames;
import io.xpipe.app.util.LabelGraphic;
import io.xpipe.app.util.OptionsBuilder;
@@ -44,7 +44,7 @@ public class ApiCategory extends AppPrefsCategory {
}
""";
return template.formatted(
AppProperties.get().isStaging() ? "xpipe-ptb" : "xpipe",
AppNames.ofCurrent().getKebapName(),
AppBeaconServer.get().getPort(),
prefs.apiKey().get() != null
? prefs.apiKey().get()
@@ -1,6 +1,6 @@
package io.xpipe.app.prefs;
import io.xpipe.app.core.AppLocations;
import io.xpipe.app.core.AppSystemInfo;
import io.xpipe.app.ext.PrefsChoiceValue;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.app.process.CommandBuilder;
@@ -47,7 +47,7 @@ public interface ExternalEditorType extends PrefsChoiceValue {
@Override
public Optional<Path> determineInstallation() {
return Optional.of(AppLocations.getWindows().getSystemRoot().resolve("\\System32\\notepad.exe"));
return Optional.of(AppSystemInfo.getWindows().getSystemRoot().resolve("\\System32\\notepad.exe"));
}
};
@@ -75,7 +75,7 @@ public interface ExternalEditorType extends PrefsChoiceValue {
@Override
public Optional<Path> determineInstallation() {
return Optional.of(AppLocations.getWindows().getLocalAppData()
return Optional.of(AppSystemInfo.getWindows().getLocalAppData()
.resolve("Programs")
.resolve("VSCodium")
.resolve("bin")
@@ -108,7 +108,7 @@ public interface ExternalEditorType extends PrefsChoiceValue {
@Override
public Optional<Path> determineInstallation() {
return Optional.of(AppLocations.getWindows().getLocalAppData()
return Optional.of(AppSystemInfo.getWindows().getLocalAppData()
.resolve("Programs")
.resolve("cursor")
.resolve("Cursor.exe"))
@@ -140,7 +140,7 @@ public interface ExternalEditorType extends PrefsChoiceValue {
@Override
public Optional<Path> determineInstallation() {
return Optional.of(AppLocations.getWindows().getProgramFiles()
return Optional.of(AppSystemInfo.getWindows().getProgramFiles()
.resolve("Void")
.resolve("Void.exe"))
.filter(path -> Files.exists(path));
@@ -171,7 +171,7 @@ public interface ExternalEditorType extends PrefsChoiceValue {
@Override
public Optional<Path> determineInstallation() {
return Optional.of(AppLocations.getWindows().getLocalAppData()
return Optional.of(AppSystemInfo.getWindows().getLocalAppData()
.resolve("Programs")
.resolve("Windsurf")
.resolve("bin")
@@ -204,7 +204,7 @@ public interface ExternalEditorType extends PrefsChoiceValue {
@Override
public Optional<Path> determineInstallation() {
return Optional.of(AppLocations.getWindows().getLocalAppData()
return Optional.of(AppSystemInfo.getWindows().getLocalAppData()
.resolve("Programs")
.resolve("Kiro")
.resolve("bin")
@@ -238,7 +238,7 @@ public interface ExternalEditorType extends PrefsChoiceValue {
@Override
public Optional<Path> determineInstallation() {
return Optional.of(AppLocations.getWindows().getLocalAppData()
return Optional.of(AppSystemInfo.getWindows().getLocalAppData()
.resolve("Programs")
.resolve("TheiaIDE")
.resolve("TheiaIDE.exe"))
@@ -270,7 +270,7 @@ public interface ExternalEditorType extends PrefsChoiceValue {
@Override
public Optional<Path> determineInstallation() {
return Optional.of(AppLocations.getWindows().getLocalAppData()
return Optional.of(AppSystemInfo.getWindows().getLocalAppData()
.resolve("Programs")
.resolve("Trae")
.resolve("bin")
@@ -303,7 +303,7 @@ public interface ExternalEditorType extends PrefsChoiceValue {
@Override
public Optional<Path> determineInstallation() {
return Optional.of(AppLocations.getWindows().getLocalAppData()
return Optional.of(AppSystemInfo.getWindows().getLocalAppData()
.resolve("Programs")
.resolve("Microsoft VS Code")
.resolve("bin")
@@ -336,7 +336,7 @@ public interface ExternalEditorType extends PrefsChoiceValue {
@Override
public Optional<Path> determineInstallation() {
return Optional.of(AppLocations.getWindows().getLocalAppData()
return Optional.of(AppSystemInfo.getWindows().getLocalAppData()
.resolve("Programs")
.resolve("Microsoft VS Code Insiders")
.resolve("bin")
@@ -3,10 +3,7 @@ package io.xpipe.app.prefs;
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.*;
import io.xpipe.app.core.mode.OperationMode;
import io.xpipe.app.core.window.AppDialog;
import io.xpipe.app.ext.ProcessControlProvider;
@@ -61,7 +58,7 @@ public class TroubleshootCategory extends AppPrefsCategory {
OperationMode.executeAfterShutdown(() -> {
var script = AppInstallation.ofCurrent().getDaemonDebugScriptPath();
TerminalLaunch.builder()
.title("XPipe Debug")
.title(AppNames.ofCurrent().getName() + " Debug")
.localScript(sc -> new ShellScript(
sc.getShellDialect().runScriptCommand(sc, script.toString())))
.launch();
@@ -1,6 +1,7 @@
package io.xpipe.app.terminal;
import io.xpipe.app.core.AppInstallation;
import io.xpipe.app.core.AppNames;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.app.prefs.ExternalApplicationType;
import io.xpipe.app.process.CommandBuilder;
@@ -23,7 +24,7 @@ public interface KittyTerminalType extends ExternalTerminalType, TrackableTermin
try (var sc = LocalShell.getShell().start()) {
var temp = ShellTemp.createUserSpecificTempDataDirectory(sc, null);
sc.executeSimpleCommand(sc.getShellDialect().getMkdirsCommand(temp.toString()));
return temp.join("xpipe_kitty");
return temp.join(AppNames.ofCurrent().getSnakeName() + "_kitty");
}
}
@@ -1,10 +1,8 @@
package io.xpipe.app.terminal;
import io.xpipe.app.core.AppLocations;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.app.core.AppSystemInfo;
import io.xpipe.app.prefs.ExternalApplicationType;
import io.xpipe.app.process.CommandBuilder;
import io.xpipe.app.util.LocalShell;
import io.xpipe.app.util.SshLocalBridge;
import java.nio.file.Files;
@@ -30,7 +28,7 @@ public class SecureCrtTerminalType implements ExternalApplicationType.WindowsTyp
@Override
public Optional<Path> determineInstallation() {
var file = AppLocations.getWindows().getProgramFiles().resolve("VanDyke Software\\SecureCRT\\SecureCRT.exe");
var file = AppSystemInfo.getWindows().getProgramFiles().resolve("VanDyke Software\\SecureCRT\\SecureCRT.exe");
if (!Files.exists(file)) {
return Optional.empty();
}
@@ -1,6 +1,7 @@
package io.xpipe.app.terminal;
import io.xpipe.app.core.AppInstallation;
import io.xpipe.app.core.AppNames;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.app.prefs.AppPrefs;
import io.xpipe.app.process.*;
@@ -251,13 +252,13 @@ public class TerminalLauncher {
.get()
.prepareIntermediateTerminalOpen(
TerminalInitFunction.fixed(proxyMultiplexerCommand),
TerminalInitScriptConfig.ofName("XPipe"),
TerminalInitScriptConfig.ofName(AppNames.ofCurrent().getName()),
WorkingDirectoryFunction.none());
// Restart for the next time
proxyControl.get().start();
var fullLocalCommand = getTerminalRegisterCommand(request) + "\n" + proxyLaunchCommand;
return Optional.of(new TerminalLaunchConfiguration(
null, "XPipe", "XPipe", false, fullLocalCommand, LocalShell.getDialect()));
null, AppNames.ofCurrent().getName(), AppNames.ofCurrent().getName(), false, fullLocalCommand, LocalShell.getDialect()));
} else {
var multiplexerCommand = multiplexer
.get()
@@ -266,11 +267,11 @@ public class TerminalLauncher {
var launchCommand = LocalShell.getShell()
.prepareIntermediateTerminalOpen(
TerminalInitFunction.fixed(multiplexerCommand),
TerminalInitScriptConfig.ofName("XPipe"),
TerminalInitScriptConfig.ofName(AppNames.ofCurrent().getName()),
WorkingDirectoryFunction.none());
var fullLocalCommand = getTerminalRegisterCommand(request) + "\n" + launchCommand;
return Optional.of(new TerminalLaunchConfiguration(
null, "XPipe", "XPipe", false, fullLocalCommand, LocalShell.getDialect()));
null, AppNames.ofCurrent().getName(), AppNames.ofCurrent().getName(), false, fullLocalCommand, LocalShell.getDialect()));
}
}
@@ -286,7 +287,7 @@ public class TerminalLauncher {
.get()
.prepareIntermediateTerminalOpen(
TerminalInitFunction.fixed(openCommand),
TerminalInitScriptConfig.ofName("XPipe"),
TerminalInitScriptConfig.ofName(AppNames.ofCurrent().getName()),
WorkingDirectoryFunction.none());
// Restart for the next time
proxyControl.get().start();
@@ -2,7 +2,7 @@ package io.xpipe.app.terminal;
import io.xpipe.app.core.AppCache;
import io.xpipe.app.core.AppInstallation;
import io.xpipe.app.core.AppLocations;
import io.xpipe.app.core.AppSystemInfo;
import io.xpipe.app.core.AppProperties;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.app.process.CommandBuilder;
@@ -149,12 +149,12 @@ public interface WindowsTerminalType extends ExternalTerminalType, TrackableTerm
}
private Path getPath() {
return AppLocations.getWindows().getLocalAppData().resolve("Microsoft\\WindowsApps\\Microsoft.WindowsTerminal_8wekyb3d8bbwe\\wt.exe");
return AppSystemInfo.getWindows().getLocalAppData().resolve("Microsoft\\WindowsApps\\Microsoft.WindowsTerminal_8wekyb3d8bbwe\\wt.exe");
}
@Override
public Path getConfigFile() {
return AppLocations.getWindows().getLocalAppData()
return AppSystemInfo.getWindows().getLocalAppData()
.resolve("Packages\\Microsoft.WindowsTerminal_8wekyb3d8bbwe\\LocalState\\settings.json");
}
}
@@ -180,7 +180,7 @@ public interface WindowsTerminalType extends ExternalTerminalType, TrackableTerm
}
private Path getPath() {
return AppLocations.getWindows().getLocalAppData()
return AppSystemInfo.getWindows().getLocalAppData()
.resolve("Microsoft\\WindowsApps\\Microsoft.WindowsTerminalPreview_8wekyb3d8bbwe\\wt.exe");
}
@@ -197,7 +197,7 @@ public interface WindowsTerminalType extends ExternalTerminalType, TrackableTerm
@Override
public Path getConfigFile() {
return AppLocations.getWindows().getLocalAppData()
return AppSystemInfo.getWindows().getLocalAppData()
.resolve("Packages\\Microsoft.WindowsTerminalPreview_8wekyb3d8bbwe\\LocalState\\settings.json");
}
}
@@ -223,7 +223,7 @@ public interface WindowsTerminalType extends ExternalTerminalType, TrackableTerm
}
private Path getPath() {
return AppLocations.getWindows().getLocalAppData()
return AppSystemInfo.getWindows().getLocalAppData()
.resolve("Microsoft\\WindowsApps\\Microsoft.WindowsTerminalCanary_8wekyb3d8bbwe\\wt.exe");
}
@@ -240,7 +240,7 @@ public interface WindowsTerminalType extends ExternalTerminalType, TrackableTerm
@Override
public Path getConfigFile() {
return AppLocations.getWindows().getLocalAppData()
return AppSystemInfo.getWindows().getLocalAppData()
.resolve("Packages\\Microsoft.WindowsTerminalCanary_8wekyb3d8bbwe\\LocalState\\settings.json");
}
}
@@ -23,12 +23,12 @@ public enum AppDistributionType implements Translatable {
PORTABLE("portable", false, () -> new PortableUpdater(true)),
NATIVE_INSTALLATION("install", true, () -> new GitHubUpdater(true)),
HOMEBREW("homebrew", true, () -> {
var pkg = AppProperties.get().isStaging() ? "xpipe-ptb" : "xpipe";
var pkg = AppNames.ofCurrent().getKebapName();
return new CommandUpdater(
ShellScript.lines("brew upgrade --cask xpipe-io/tap/" + pkg, AppRestart.getTerminalRestartCommand()));
}),
APT_REPO("apt", true, () -> {
var pkg = AppProperties.get().isStaging() ? "xpipe-ptb" : "xpipe";
var pkg = AppNames.ofCurrent().getKebapName();
return new CommandUpdater(ShellScript.lines(
"echo \"+ sudo apt update && sudo apt install -y " + pkg + "\"",
"sudo apt update",
@@ -36,14 +36,14 @@ public enum AppDistributionType implements Translatable {
AppRestart.getTerminalRestartCommand()));
}),
RPM_REPO("rpm", true, () -> {
var pkg = AppProperties.get().isStaging() ? "xpipe-ptb" : "xpipe";
var pkg = AppNames.ofCurrent().getKebapName();
return new CommandUpdater(ShellScript.lines(
"echo \"+ sudo yum upgrade " + pkg + " --refresh -y\"",
"sudo yum upgrade " + pkg + " --refresh -y",
AppRestart.getTerminalRestartCommand()));
}),
AUR("aur", true, () -> {
var pkg = AppProperties.get().isStaging() ? "xpipe-ptb" : "xpipe";
var pkg = AppNames.ofCurrent().getKebapName();
return new CommandUpdater(ShellScript.lines(
"echo \"+ git clone https://aur.archlinux.org/" + pkg + " . && makepkg -si\"",
"cd $(mktemp -d) && git clone https://aur.archlinux.org/" + pkg + " . && makepkg -si --noconfirm",
@@ -137,7 +137,7 @@ public enum AppDistributionType implements Translatable {
var r = LocalExec.readStdoutIfPossible(
"pkgutil",
"--pkg-info",
AppProperties.get().isStaging() ? "io.xpipe.xpipe-ptb" : "io.xpipe.xpipe");
"io.xpipe." + AppNames.ofCurrent().getKebapName());
if (r.isEmpty()) {
return PORTABLE;
}
@@ -168,15 +168,6 @@ public enum AppDistributionType implements Translatable {
return CHOCO;
}
}
// var wingetOut = LocalExec.readStdoutIfPossible("winget", "show", "--id", "xpipe-io.xpipe",
// "--source", "--winget");
// if (wingetOut.isPresent()) {
// if (wingetOut.get().contains("xpipe-io.xpipe") &&
// wingetOut.get().contains(AppProperties.get().getVersion())) {
// return WINGET;
// }
// }
}
if (OsType.getLocal() == OsType.MACOS) {
@@ -185,7 +176,7 @@ public enum AppDistributionType implements Translatable {
if (out.get().lines().anyMatch(s -> {
var split = s.split(" ");
return split.length == 2
&& split[0].equals(AppProperties.get().isStaging() ? "xpipe-ptb" : "xpipe")
&& split[0].equals(AppNames.ofCurrent().getKebapName())
&& split[1].equals(AppProperties.get().getVersion());
})) {
return HOMEBREW;
@@ -2,6 +2,7 @@ package io.xpipe.app.update;
import io.xpipe.app.core.AppInstallation;
import io.xpipe.app.core.AppLogs;
import io.xpipe.app.core.AppNames;
import io.xpipe.app.core.AppRestart;
import io.xpipe.app.core.mode.OperationMode;
import io.xpipe.app.process.ShellDialects;
@@ -73,14 +74,14 @@ public class AppInstaller {
try (var sc = LocalShell.getShell().start()) {
String toRun;
if (cmdScript) {
toRun = "start \"XPipe Updater\" /min cmd /c \""
toRun = "start \"" + AppNames.ofCurrent().getName() + " Updater\" /min cmd /c \""
+ ScriptHelper.createExecScript(ShellDialects.CMD, sc, command) + "\"";
} else {
toRun = sc.getShellDialect() == ShellDialects.POWERSHELL
? "Start-Process -WindowStyle Minimized -FilePath powershell -ArgumentList \"-ExecutionPolicy\", \"Bypass\", \"-File\", \"`\""
+ ScriptHelper.createExecScript(ShellDialects.POWERSHELL, sc, command)
+ "`\"\""
: "start \"XPipe Updater\" /min powershell -ExecutionPolicy Bypass -File \""
: "start \"" + AppNames.ofCurrent().getName() + " Updater\" /min powershell -ExecutionPolicy Bypass -File \""
+ ScriptHelper.createExecScript(ShellDialects.POWERSHELL, sc, command)
+ "\"";
}
@@ -167,7 +168,7 @@ public class AppInstaller {
file, file, AppRestart.getTerminalRestartCommand()));
OperationMode.executeAfterShutdown(() -> {
TerminalLaunch.builder()
.title("XPipe Updater")
.title(AppNames.ofCurrent().getName() + " Updater")
.localScript(command)
.launch();
});
@@ -203,7 +204,7 @@ public class AppInstaller {
file, file, AppRestart.getTerminalRestartCommand()));
OperationMode.executeAfterShutdown(() -> {
TerminalLaunch.builder()
.title("XPipe Updater")
.title(AppNames.ofCurrent().getName() + " Updater")
.localScript(command)
.launch();
});
@@ -239,7 +240,7 @@ public class AppInstaller {
file, file, AppRestart.getTerminalRestartCommand()));
OperationMode.executeAfterShutdown(() -> {
TerminalLaunch.builder()
.title("XPipe Updater")
.title(AppNames.ofCurrent().getName() + " Updater")
.localScript(command)
.launch();
});
@@ -1,5 +1,6 @@
package io.xpipe.app.update;
import io.xpipe.app.core.AppNames;
import io.xpipe.app.core.AppProperties;
import io.xpipe.core.OsType;
@@ -19,9 +20,9 @@ public class AppRelease {
var arch = AppProperties.get().getArch();
var name = "xpipe-installer-%s-%s.%s".formatted(os, arch, type.getExtension());
var url = "https://github.com/xpipe-io/%s/releases/download/%s/%s"
.formatted(AppProperties.get().isStaging() ? "xpipe-ptb" : "xpipe", tag, name);
.formatted(AppNames.ofCurrent().getKebapName(), tag, name);
var browser = "https://github.com/xpipe-io/%s/releases/%s"
.formatted(AppProperties.get().isStaging() ? "xpipe-ptb" : "xpipe", tag);
.formatted(AppNames.ofCurrent().getKebapName(), tag);
return new AppRelease(tag, url, browser, name);
}
@@ -81,7 +81,8 @@ public enum DocumentationLink {
TERMINAL_PROMPT("guide/terminals#prompts"),
TEAM_VAULTS("guide/sync#team-vaults"),
SSH_TROUBLESHOOT("guide/ssh#troubleshooting"),
NO_EXEC("troubleshooting/noexec");
NO_EXEC("troubleshooting/noexec"),
MCP("guide/mcp");
private final String page;
@@ -1,6 +1,6 @@
package io.xpipe.app.vnc;
import io.xpipe.app.core.AppLocations;
import io.xpipe.app.core.AppSystemInfo;
import io.xpipe.app.prefs.ExternalApplicationType;
import io.xpipe.app.process.CommandBuilder;
@@ -57,7 +57,7 @@ public abstract class RealVncClient implements ExternalVncClient {
@Override
public Optional<Path> determineInstallation() {
return Optional.of(AppLocations.getWindows().getProgramFiles()
return Optional.of(AppSystemInfo.getWindows().getProgramFiles()
.resolve("RealVNC")
.resolve("VNC Viewer")
.resolve("vncviewer.exe"))
@@ -1,6 +1,6 @@
package io.xpipe.app.vnc;
import io.xpipe.app.core.AppLocations;
import io.xpipe.app.core.AppSystemInfo;
import io.xpipe.app.issue.ErrorEventFactory;
import io.xpipe.app.prefs.ExternalApplicationType;
import io.xpipe.app.process.CommandBuilder;
@@ -56,7 +56,7 @@ public abstract class TigerVncClient implements ExternalVncClient {
@Override
public Optional<Path> determineInstallation() {
return Optional.of(AppLocations.getWindows().getProgramFiles()
return Optional.of(AppSystemInfo.getWindows().getProgramFiles()
.resolve("TigerVNC")
.resolve("vncviewer.exe"))
.filter(path -> Files.exists(path));
@@ -1,6 +1,6 @@
package io.xpipe.app.vnc;
import io.xpipe.app.core.AppLocations;
import io.xpipe.app.core.AppSystemInfo;
import io.xpipe.app.prefs.ExternalApplicationType;
import io.xpipe.app.process.CommandBuilder;
import io.xpipe.app.util.LocalShell;
@@ -35,7 +35,7 @@ public class TightVncClient implements ExternalApplicationType.InstallLocationTy
@Override
public Optional<Path> determineInstallation() {
return Optional.of(AppLocations.getWindows().getProgramFiles()
return Optional.of(AppSystemInfo.getWindows().getProgramFiles()
.resolve("TightVNC")
.resolve("tvnviewer.exe"))
.filter(path -> Files.exists(path));
+1
View File
@@ -71,6 +71,7 @@ tryPtb=XPipe Public Test Build
zed=Zed
windowsCredentialManager=Windows credential manager
webtop=Webtop
mcp=MCP server
keeper=Keeper
windowsApp=Windows App.app
chmod=Chmod
-1
View File
@@ -185,7 +185,6 @@ slackDescription=Deltag i Slack-arbejdsområdet
support=Støtte
githubDescription=Tjek GitHub-arkivet ud
openSourceNotices=Meddelelser om open source
xPipeClient=XPipe Desktop
checkForUpdates=Tjek for opdateringer
#custom
checkForUpdatesDescription=Download en opdatering, hvis der er en.
-1
View File
@@ -188,7 +188,6 @@ slackDescription=Dem Slack-Arbeitsbereich beitreten
support=Unterstützung
githubDescription=Schau dir das GitHub-Repository an
openSourceNotices=Open-Source-Hinweise
xPipeClient=XPipe Desktop
checkForUpdates=Nach Updates suchen
checkForUpdatesDescription=Ein Update herunterladen, wenn es eins gibt
lastChecked=Zuletzt geprüft
-1
View File
@@ -192,7 +192,6 @@ slackDescription=Join the Slack workspace
support=Support
githubDescription=Check out the GitHub repository
openSourceNotices=Open Source Notices
xPipeClient=XPipe Desktop
checkForUpdates=Check for updates
checkForUpdatesDescription=Download an update if there is one
lastChecked=Last checked
-1
View File
@@ -180,7 +180,6 @@ slackDescription=Únete al espacio de trabajo Slack
support=Soporte
githubDescription=Consulta el repositorio de GitHub
openSourceNotices=Avisos de código abierto
xPipeClient=Escritorio XPipe
checkForUpdates=Buscar actualizaciones
checkForUpdatesDescription=Descargar una actualización si la hay
lastChecked=Última comprobación
-1
View File
@@ -185,7 +185,6 @@ slackDescription=Rejoins l'espace de travail Slack
support=Support
githubDescription=Jette un coup d'œil au dépôt GitHub
openSourceNotices=Avis Open Source
xPipeClient=XPipe Desktop
checkForUpdates=Vérifier les mises à jour
checkForUpdatesDescription=Télécharger une mise à jour s'il y en a une
lastChecked=Dernière vérification
-1
View File
@@ -180,7 +180,6 @@ slackDescription=Bergabung dengan ruang kerja Slack
support=Dukungan
githubDescription=Lihat repositori GitHub
openSourceNotices=Pemberitahuan Sumber Terbuka
xPipeClient=Desktop XPipe
checkForUpdates=Memeriksa pembaruan
checkForUpdatesDescription=Mengunduh pembaruan jika ada
lastChecked=Terakhir diperiksa
-1
View File
@@ -180,7 +180,6 @@ slackDescription=Partecipa allo spazio di lavoro Slack
support=Supporto
githubDescription=Consulta il repository GitHub
openSourceNotices=Avvisi Open Source
xPipeClient=XPipe Desktop
checkForUpdates=Controlla gli aggiornamenti
checkForUpdatesDescription=Scaricare un aggiornamento, se presente
lastChecked=Ultimo controllo
-1
View File
@@ -180,7 +180,6 @@ slackDescription=Slackワークスペースに参加する
support=サポート
githubDescription=GitHub リポジトリをチェックする
openSourceNotices=オープンソースのお知らせ
xPipeClient=XPipeデスクトップ
checkForUpdates=アップデートを確認する
checkForUpdatesDescription=アップデートがあればダウンロードする
lastChecked=最終チェック
-1
View File
@@ -180,7 +180,6 @@ slackDescription=Slack 워크스페이스에 참여
support=지원
githubDescription=GitHub 리포지토리를 확인하세요
openSourceNotices=오픈 소스 공지
xPipeClient=XPipe 데스크톱
checkForUpdates=업데이트 확인
checkForUpdatesDescription=업데이트가 있는 경우 다운로드
lastChecked=마지막 확인
-1
View File
@@ -180,7 +180,6 @@ slackDescription=Word lid van de Slack werkruimte
support=Ondersteuning
githubDescription=Bekijk de GitHub repository
openSourceNotices=Open Source Mededelingen
xPipeClient=XPipe Desktop
checkForUpdates=Controleren op updates
checkForUpdatesDescription=Download een update als die er is
lastChecked=Laatst gecontroleerd
-1
View File
@@ -180,7 +180,6 @@ slackDescription=Dołącz do obszaru roboczego Slack
support=Wsparcie
githubDescription=Sprawdź repozytorium GitHub
openSourceNotices=Powiadomienia Open Source
xPipeClient=XPipe Desktop
checkForUpdates=Sprawdź aktualizacje
checkForUpdatesDescription=Pobierz aktualizację, jeśli jest dostępna
lastChecked=Ostatnio sprawdzane
-1
View File
@@ -180,7 +180,6 @@ slackDescription=Junta-te ao espaço de trabalho do Slack
support=Apoia
githubDescription=Consulta o repositório do GitHub
openSourceNotices=Avisos de código aberto
xPipeClient=XPipe Desktop
checkForUpdates=Verifica se há actualizações
checkForUpdatesDescription=Descarrega uma atualização, se existir uma
lastChecked=Verificado pela última vez
-1
View File
@@ -180,7 +180,6 @@ slackDescription=Присоединяйтесь к рабочему простр
support=Поддержите
githubDescription=Загляни в репозиторий GitHub
openSourceNotices=Уведомления об открытом исходном коде
xPipeClient=XPipe Desktop
checkForUpdates=Проверьте наличие обновлений
checkForUpdatesDescription=Загрузите обновление, если оно есть
lastChecked=Последняя проверка
-1
View File
@@ -180,7 +180,6 @@ slackDescription=Gå med i arbetsytan Slack
support=Stöd för
githubDescription=Kolla in GitHub-förvaret
openSourceNotices=Meddelanden om öppen källkod
xPipeClient=XPipe skrivbord
checkForUpdates=Sök efter uppdateringar
checkForUpdatesDescription=Ladda ner en uppdatering om det finns en
lastChecked=Senast kontrollerad
-1
View File
@@ -180,7 +180,6 @@ slackDescription=Slack çalışma alanına katılın
support=Destek
githubDescription=GitHub deposuna göz atın
openSourceNotices=Açık Kaynak Bildirimleri
xPipeClient=XPipe Masaüstü
checkForUpdates=Güncellemeleri kontrol edin
checkForUpdatesDescription=Varsa bir güncelleme indirin
lastChecked=Son kontrol
-1
View File
@@ -219,7 +219,6 @@ slackDescription=加入 Slack 工作区
support=支持
githubDescription=查看 GitHub 代码库
openSourceNotices=开放源代码公告
xPipeClient=XPipe 桌面
checkForUpdates=检查更新
#custom
checkForUpdatesDescription=检查并下载可用更新