mirror of
https://github.com/xpipe-io/xpipe.git
synced 2026-04-24 00:21:11 -04:00
Squash merge branch 15-release into master
This commit is contained in:
@@ -43,22 +43,22 @@ public class CommandBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandBuilder fixedEnvrironment(String k, String v) {
|
||||
public CommandBuilder fixedEnvironment(String k, String v) {
|
||||
environmentVariables.put(k, new Fixed(v));
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandBuilder envrironment(String k, Element v) {
|
||||
public CommandBuilder environment(String k, Element v) {
|
||||
environmentVariables.put(k, v);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandBuilder fixedEnvrironment(Map<String, String> map) {
|
||||
map.forEach((s, s2) -> fixedEnvrironment(s, s2));
|
||||
public CommandBuilder fixedEnvironment(Map<String, String> map) {
|
||||
map.forEach((s, s2) -> fixedEnvironment(s, s2));
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandBuilder envrironment(Map<String, Element> map) {
|
||||
public CommandBuilder environment(Map<String, Element> map) {
|
||||
environmentVariables.putAll(map);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -52,4 +52,8 @@ public class CountDown {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public synchronized long getMillisecondsElapsed() {
|
||||
return maxMillis - millisecondsLeft;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ public interface OsType {
|
||||
FileNames.join(home, "Downloads"),
|
||||
FileNames.join(home, "Documents"),
|
||||
"/etc",
|
||||
"/tmp",
|
||||
pc.getSystemTemporaryDirectory().toString(),
|
||||
"/var"));
|
||||
var parentHome = FileNames.getParent(home);
|
||||
if (parentHome != null && !parentHome.equals("/")) {
|
||||
|
||||
@@ -38,7 +38,7 @@ public class ProcessOutputException extends Exception {
|
||||
public static ProcessOutputException of(long exitCode, String... messages) {
|
||||
var combinedError = Arrays.stream(messages)
|
||||
.filter(s -> s != null && !s.isBlank())
|
||||
.map(s -> s.strip())
|
||||
.map(s -> s.trim())
|
||||
.collect(Collectors.joining("\n\n"))
|
||||
.replaceAll("\r\n", "\n");
|
||||
var hasMessage = !combinedError.isBlank();
|
||||
|
||||
@@ -18,6 +18,10 @@ import java.util.function.Function;
|
||||
|
||||
public interface ShellControl extends ProcessControl {
|
||||
|
||||
void setDumbOpen(ShellOpenFunction openFunction);
|
||||
|
||||
void setTerminalOpen(ShellOpenFunction openFunction);
|
||||
|
||||
void writeLine(String line) throws IOException;
|
||||
|
||||
void writeLine(String line, boolean log) throws IOException;
|
||||
@@ -197,12 +201,14 @@ public interface ShellControl extends ProcessControl {
|
||||
return CommandBuilder.ofString(command);
|
||||
}
|
||||
};
|
||||
var s = singularSubShell(o);
|
||||
var s = subShell();
|
||||
s.setDumbOpen(o);
|
||||
s.setTerminalOpen(o);
|
||||
s.setParentSystemAccess(ParentSystemAccess.identity());
|
||||
return s;
|
||||
}
|
||||
|
||||
default ShellControl identicalSubShell() {
|
||||
default ShellControl identicalDialectSubShell() {
|
||||
var o = new ShellOpenFunction() {
|
||||
|
||||
@Override
|
||||
@@ -216,7 +222,9 @@ public interface ShellControl extends ProcessControl {
|
||||
return CommandBuilder.ofString(command);
|
||||
}
|
||||
};
|
||||
var sc = singularSubShell(o);
|
||||
var sc = subShell();
|
||||
sc.setDumbOpen(o);
|
||||
sc.setTerminalOpen(o);
|
||||
sc.withSourceStore(getSourceStore().orElse(null));
|
||||
sc.setParentSystemAccess(ParentSystemAccess.identity());
|
||||
return sc;
|
||||
@@ -224,7 +232,7 @@ public interface ShellControl extends ProcessControl {
|
||||
|
||||
default ShellControl elevateIfNeeded(ElevationFunction function) throws Exception {
|
||||
if (function.apply(this)) {
|
||||
return identicalSubShell().elevated(ElevationFunction.elevated(function.getPrefix()));
|
||||
return identicalDialectSubShell().elevated(ElevationFunction.elevated(function.getPrefix()));
|
||||
} else {
|
||||
return new StubShellControl(this);
|
||||
}
|
||||
@@ -241,9 +249,7 @@ public interface ShellControl extends ProcessControl {
|
||||
}
|
||||
}
|
||||
|
||||
ShellControl subShell(ShellOpenFunction command, ShellOpenFunction terminalCommand);
|
||||
|
||||
ShellControl singularSubShell(ShellOpenFunction command);
|
||||
ShellControl subShell();
|
||||
|
||||
void cd(String directory) throws Exception;
|
||||
|
||||
@@ -251,6 +257,10 @@ public interface ShellControl extends ProcessControl {
|
||||
return command(CommandBuilder.ofFunction(shellProcessControl -> command));
|
||||
}
|
||||
|
||||
default CommandControl command(ShellScript command) {
|
||||
return command(CommandBuilder.of().add(command.getValue()));
|
||||
}
|
||||
|
||||
default CommandControl command(Consumer<CommandBuilder> builder) {
|
||||
var b = CommandBuilder.of();
|
||||
builder.accept(b);
|
||||
|
||||
@@ -30,10 +30,6 @@ public interface ShellDialect {
|
||||
|
||||
String getExecutableName();
|
||||
|
||||
default boolean isSelectable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
default boolean isCompatibleTo(ShellDialect other) {
|
||||
return other.equals(this);
|
||||
}
|
||||
@@ -136,7 +132,7 @@ public interface ShellDialect {
|
||||
|
||||
CommandBuilder getOpenScriptCommand(String file);
|
||||
|
||||
String prepareTerminalInitFileOpenCommand(ShellDialect parentDialect, ShellControl sc, String file, boolean exit);
|
||||
String terminalInitCommand(ShellControl shellControl, String file, boolean exit);
|
||||
|
||||
String runScriptCommand(ShellControl parent, String file);
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ public interface ShellInitCommand {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean canPotentiallyRunInDialect(ShellDialect dialect);
|
||||
|
||||
default boolean runInTerminal() {
|
||||
return false;
|
||||
}
|
||||
@@ -36,12 +38,15 @@ public interface ShellInitCommand {
|
||||
@NonNull
|
||||
private final String content;
|
||||
|
||||
private final ShellDialect dialect;
|
||||
|
||||
private final boolean dumb;
|
||||
|
||||
private final boolean terminal;
|
||||
|
||||
public Simple(@NonNull String content, boolean dumb, boolean terminal) {
|
||||
public Simple(@NonNull String content, ShellDialect dialect, boolean dumb, boolean terminal) {
|
||||
this.content = content;
|
||||
this.dialect = dialect;
|
||||
this.dumb = dumb;
|
||||
this.terminal = terminal;
|
||||
}
|
||||
@@ -61,6 +66,11 @@ public interface ShellInitCommand {
|
||||
return dumb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPotentiallyRunInDialect(ShellDialect dialect) {
|
||||
return this.dialect.isCompatibleTo(dialect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean runInTerminal() {
|
||||
return terminal;
|
||||
|
||||
@@ -18,20 +18,6 @@ public interface ShellOpenFunction {
|
||||
};
|
||||
}
|
||||
|
||||
static ShellOpenFunction of(CommandBuilder b, boolean append) {
|
||||
return new ShellOpenFunction() {
|
||||
@Override
|
||||
public CommandBuilder prepareWithoutInitCommand() {
|
||||
return b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandBuilder prepareWithInitCommand(@NonNull String command) {
|
||||
return CommandBuilder.ofFunction(sc -> (append ? b.buildFull(sc) + " " : "") + command);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
CommandBuilder prepareWithoutInitCommand() throws Exception;
|
||||
|
||||
CommandBuilder prepareWithInitCommand(@NonNull String command) throws Exception;
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package io.xpipe.core.process;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
@Value
|
||||
public class ShellScript {
|
||||
|
||||
String value;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package io.xpipe.core.process;
|
||||
|
||||
import lombok.experimental.StandardException;
|
||||
|
||||
@StandardException
|
||||
public class ShellSpawnException extends Exception {}
|
||||
@@ -0,0 +1,11 @@
|
||||
package io.xpipe.core.process;
|
||||
|
||||
public interface TerminalLaunchCommandFunction {
|
||||
|
||||
CommandBuilder apply(
|
||||
ShellControl shellControl,
|
||||
boolean requiresExecutableFirst,
|
||||
boolean supportsRawArguments,
|
||||
String file,
|
||||
boolean exit);
|
||||
}
|
||||
@@ -15,9 +15,9 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Getter
|
||||
public class WrapperShellControl implements ShellControl {
|
||||
|
||||
@Getter
|
||||
protected final ShellControl parent;
|
||||
|
||||
public WrapperShellControl(ShellControl parent) {
|
||||
@@ -215,6 +215,16 @@ public class WrapperShellControl implements ShellControl {
|
||||
return parent.getShellDialect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDumbOpen(ShellOpenFunction openFunction) {
|
||||
parent.setDumbOpen(openFunction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTerminalOpen(ShellOpenFunction openFunction) {
|
||||
parent.setTerminalOpen(openFunction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeLine(String line) throws IOException {
|
||||
parent.writeLine(line);
|
||||
@@ -329,13 +339,8 @@ public class WrapperShellControl implements ShellControl {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShellControl subShell(ShellOpenFunction command, ShellOpenFunction terminalCommand) {
|
||||
return parent.subShell(command, terminalCommand);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShellControl singularSubShell(ShellOpenFunction command) {
|
||||
return parent.singularSubShell(command);
|
||||
public ShellControl subShell() {
|
||||
return parent.subShell();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,178 +0,0 @@
|
||||
package io.xpipe.core.store;
|
||||
|
||||
import io.xpipe.core.process.CommandBuilder;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Getter
|
||||
public class ConnectionFileSystem implements FileSystem {
|
||||
|
||||
@JsonIgnore
|
||||
protected final ShellControl shellControl;
|
||||
|
||||
public ConnectionFileSystem(ShellControl shellControl) {
|
||||
this.shellControl = shellControl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFileSize(String file) throws Exception {
|
||||
return Long.parseLong(
|
||||
shellControl.getShellDialect().queryFileSize(shellControl, file).readStdoutOrThrow());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ShellControl> getShell() {
|
||||
return Optional.of(shellControl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileSystem open() throws Exception {
|
||||
shellControl.start();
|
||||
|
||||
var d = shellControl.getShellDialect().getDumbMode();
|
||||
if (!d.supportsAnyPossibleInteraction()) {
|
||||
shellControl.close();
|
||||
d.throwIfUnsupported();
|
||||
}
|
||||
|
||||
if (!shellControl.getTtyState().isPreservesOutput()
|
||||
|| !shellControl.getTtyState().isSupportsInput()) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Shell has a PTY allocated and as a result does not support file system operations");
|
||||
}
|
||||
|
||||
shellControl.checkLicenseOrThrow();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream openInput(String file) throws Exception {
|
||||
return shellControl
|
||||
.getShellDialect()
|
||||
.getFileReadCommand(shellControl, file)
|
||||
.startExternalStdout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream openOutput(String file, long totalBytes) throws Exception {
|
||||
var cmd = shellControl.getShellDialect().createStreamFileWriteCommand(shellControl, file, totalBytes);
|
||||
cmd.setExitTimeout(Duration.ofMillis(Long.MAX_VALUE));
|
||||
return cmd.startExternalStdin();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean fileExists(String file) throws Exception {
|
||||
try (var pc = shellControl
|
||||
.getShellDialect()
|
||||
.createFileExistsCommand(shellControl, file)
|
||||
.start()) {
|
||||
return pc.discardAndCheckExit();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String file) throws Exception {
|
||||
try (var pc = shellControl
|
||||
.getShellDialect()
|
||||
.deleteFileOrDirectory(shellControl, file)
|
||||
.start()) {
|
||||
pc.discardOrThrow();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copy(String file, String newFile) throws Exception {
|
||||
try (var pc = shellControl
|
||||
.getShellDialect()
|
||||
.getFileCopyCommand(shellControl, file, newFile)
|
||||
.start()) {
|
||||
pc.discardOrThrow();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move(String file, String newFile) throws Exception {
|
||||
try (var pc = shellControl
|
||||
.getShellDialect()
|
||||
.getFileMoveCommand(shellControl, file, newFile)
|
||||
.start()) {
|
||||
pc.discardOrThrow();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mkdirs(String file) throws Exception {
|
||||
try (var pc = shellControl
|
||||
.command(
|
||||
CommandBuilder.ofFunction(proc -> proc.getShellDialect().getMkdirsCommand(file)))
|
||||
.start()) {
|
||||
pc.discardOrThrow();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void touch(String file) throws Exception {
|
||||
try (var pc = shellControl
|
||||
.getShellDialect()
|
||||
.getFileTouchCommand(shellControl, file)
|
||||
.start()) {
|
||||
pc.discardOrThrow();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void symbolicLink(String linkFile, String targetFile) throws Exception {
|
||||
try (var pc = shellControl
|
||||
.getShellDialect()
|
||||
.symbolicLink(shellControl, linkFile, targetFile)
|
||||
.start()) {
|
||||
pc.discardOrThrow();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean directoryExists(String file) throws Exception {
|
||||
return shellControl
|
||||
.getShellDialect()
|
||||
.directoryExists(shellControl, file)
|
||||
.executeAndCheck();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void directoryAccessible(String file) throws Exception {
|
||||
var current = shellControl.executeSimpleStringCommand(
|
||||
shellControl.getShellDialect().getPrintWorkingDirectoryCommand());
|
||||
shellControl.command(shellControl.getShellDialect().getCdCommand(file));
|
||||
shellControl.command(shellControl.getShellDialect().getCdCommand(current));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<FileEntry> listFiles(String file) throws Exception {
|
||||
return shellControl.getShellDialect().listFiles(this, shellControl, file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> listRoots() throws Exception {
|
||||
return shellControl.getShellDialect().listRoots(shellControl).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
// In case the shell control is already in an invalid state, this operation might fail
|
||||
// Since we are only closing, just swallow all exceptions
|
||||
try {
|
||||
shellControl.close();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,8 +27,13 @@ public class NetworkTunnelSessionChain extends NetworkTunnelSession {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return sessions.stream().allMatch(session -> session.isRunning());
|
||||
public boolean isRunning() throws Exception {
|
||||
for (NetworkTunnelSession session : sessions) {
|
||||
if (!session.isRunning()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,7 +16,7 @@ public abstract class Session implements AutoCloseable {
|
||||
};
|
||||
}
|
||||
|
||||
public abstract boolean isRunning();
|
||||
public abstract boolean isRunning() throws Exception;
|
||||
|
||||
public abstract void start() throws Exception;
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import io.xpipe.core.dialog.HeaderElement;
|
||||
import io.xpipe.core.process.OsType;
|
||||
import io.xpipe.core.process.ShellDialect;
|
||||
import io.xpipe.core.process.ShellDialects;
|
||||
import io.xpipe.core.process.ShellScript;
|
||||
import io.xpipe.core.store.FilePath;
|
||||
import io.xpipe.core.store.StorePath;
|
||||
|
||||
@@ -65,12 +66,31 @@ public class CoreJacksonModule extends SimpleModule {
|
||||
addDeserializer(OsType.Local.class, new OsTypeLocalDeserializer());
|
||||
addDeserializer(OsType.Any.class, new OsTypeAnyDeserializer());
|
||||
|
||||
addSerializer(ShellScript.class, new ShellScriptSerializer());
|
||||
addDeserializer(ShellScript.class, new ShellScriptDeserializer());
|
||||
|
||||
context.setMixInAnnotations(Throwable.class, ThrowableTypeMixIn.class);
|
||||
|
||||
context.addSerializers(_serializers);
|
||||
context.addDeserializers(_deserializers);
|
||||
}
|
||||
|
||||
public static class ShellScriptSerializer extends JsonSerializer<ShellScript> {
|
||||
|
||||
@Override
|
||||
public void serialize(ShellScript value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
|
||||
jgen.writeString(value.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
public static class ShellScriptDeserializer extends JsonDeserializer<ShellScript> {
|
||||
|
||||
@Override
|
||||
public ShellScript deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
|
||||
return new ShellScript(p.getValueAsString());
|
||||
}
|
||||
}
|
||||
|
||||
public static class StorePathSerializer extends JsonSerializer<StorePath> {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package io.xpipe.core.util;
|
||||
|
||||
import com.fasterxml.jackson.databind.*;
|
||||
|
||||
public interface JacksonExtension {
|
||||
|
||||
Class<?> getType();
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
package io.xpipe.core.util;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import com.fasterxml.jackson.databind.node.TextNode;
|
||||
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
|
||||
import lombok.Getter;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
@Getter
|
||||
public abstract class ProxyFunction {
|
||||
|
||||
private static ModuleLayer layer;
|
||||
|
||||
public static void init(ModuleLayer l) {
|
||||
layer = l;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public ProxyFunction callAndCopy() {
|
||||
// var proxyStore = ProxyProvider.get().getProxy(getProxyBase());
|
||||
// if (proxyStore != null) {
|
||||
// return ProxyProvider.get().call(this, proxyStore);
|
||||
// } else {
|
||||
// callLocal();
|
||||
// return this;
|
||||
// }
|
||||
return null;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
protected Object getProxyBase() {
|
||||
var first = Arrays.stream(getClass().getDeclaredFields()).findFirst().orElseThrow();
|
||||
first.setAccessible(true);
|
||||
return first.get(this);
|
||||
}
|
||||
|
||||
public abstract void callLocal();
|
||||
|
||||
public static class Serializer extends StdSerializer<ProxyFunction> {
|
||||
|
||||
protected Serializer() {
|
||||
super(ProxyFunction.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(ProxyFunction value, JsonGenerator gen, SerializerProvider provider) throws IOException {
|
||||
var node = (ObjectNode) JacksonMapper.getDefault().valueToTree(value);
|
||||
node.set("module", new TextNode(value.getClass().getModule().getName()));
|
||||
node.set("class", new TextNode(value.getClass().getName()));
|
||||
gen.writeTree(node);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Deserializer extends StdDeserializer<ProxyFunction> {
|
||||
|
||||
protected Deserializer() {
|
||||
super(ProxyFunction.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public ProxyFunction deserialize(JsonParser p, DeserializationContext ctxt) {
|
||||
var tree = (ObjectNode) JacksonMapper.getDefault().readTree(p);
|
||||
var moduleReference = tree.remove("module").asText();
|
||||
var classReference = tree.remove("class").asText();
|
||||
var module = layer.findModule(moduleReference).orElseThrow();
|
||||
var targetClass = Class.forName(module, classReference);
|
||||
if (targetClass == null) {
|
||||
throw new IllegalArgumentException("Named function class not found: " + classReference);
|
||||
}
|
||||
return (ProxyFunction) JacksonMapper.getDefault().treeToValue(tree, targetClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package io.xpipe.core.util;
|
||||
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
public abstract class ProxyManagerProvider {
|
||||
|
||||
private static ProxyManagerProvider INSTANCE;
|
||||
|
||||
public static ProxyManagerProvider get() {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = ServiceLoader.load(ModuleLayer.boot(), ProxyManagerProvider.class)
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
}
|
||||
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public abstract Optional<String> checkCompatibility(ShellControl pc);
|
||||
|
||||
public abstract boolean setup(ShellControl pc);
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package io.xpipe.core.util;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
public abstract class SimpleProxyFunction<T> extends ProxyFunction {
|
||||
|
||||
@SneakyThrows
|
||||
@SuppressWarnings("unchecked")
|
||||
public T getResult() {
|
||||
var fields = getClass().getDeclaredFields();
|
||||
var last = fields[fields.length - 1];
|
||||
last.setAccessible(true);
|
||||
return (T) last.get(this);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@SuppressWarnings("unchecked")
|
||||
public T callAndGet() {
|
||||
var result = callAndCopy();
|
||||
return ((SimpleProxyFunction<T>) result).getResult();
|
||||
}
|
||||
}
|
||||
@@ -27,10 +27,6 @@ public class XPipeInstallation {
|
||||
return 21721 + offset;
|
||||
}
|
||||
|
||||
private static String getPkgId() {
|
||||
return isStaging() ? "io.xpipe.xpipe-ptb" : "io.xpipe.xpipe";
|
||||
}
|
||||
|
||||
public static Path getLocalBeaconAuthFile() {
|
||||
return Path.of(System.getProperty("java.io.tmpdir"), isStaging() ? "xpipe_ptb_auth" : "xpipe_auth");
|
||||
}
|
||||
@@ -40,7 +36,7 @@ public class XPipeInstallation {
|
||||
var suffix = (arguments != null ? " " + arguments : "");
|
||||
var modeOption = mode != null ? " --mode " + mode.getDisplayName() : "";
|
||||
if (OsType.getLocal().equals(OsType.LINUX)) {
|
||||
return "nohup \"" + installationBase + "/app/bin/xpiped\"" + modeOption + suffix + " & disown";
|
||||
return "nohup \"" + installationBase + "/bin/xpiped\"" + modeOption + suffix + " & disown";
|
||||
} else if (OsType.getLocal().equals(OsType.MACOS)) {
|
||||
if (restart) {
|
||||
return "(sleep 1;open \"" + installationBase + "\" --args" + modeOption + suffix
|
||||
@@ -96,48 +92,10 @@ public class XPipeInstallation {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isInstallationDistribution() {
|
||||
var base = getCurrentInstallationBasePath();
|
||||
if (OsType.getLocal().equals(OsType.MACOS)) {
|
||||
if (!base.toString().equals(getLocalDefaultInstallationBasePath())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
var process = new ProcessBuilder("pkgutil", "--pkg-info", getPkgId())
|
||||
.redirectOutput(ProcessBuilder.Redirect.DISCARD)
|
||||
.redirectError(ProcessBuilder.Redirect.DISCARD)
|
||||
.start();
|
||||
process.waitFor();
|
||||
return process.exitValue() == 0;
|
||||
} catch (Exception ex) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
var file = base.resolve("installation");
|
||||
return Files.exists(file);
|
||||
}
|
||||
}
|
||||
|
||||
public static Path getLocalDynamicLibraryDirectory() {
|
||||
Path path = getCurrentInstallationBasePath();
|
||||
if (OsType.getLocal().equals(OsType.WINDOWS)) {
|
||||
return path.resolve("app").resolve("runtime").resolve("bin");
|
||||
} else if (OsType.getLocal().equals(OsType.LINUX)) {
|
||||
return path.resolve("app").resolve("lib").resolve("runtime").resolve("lib");
|
||||
} else {
|
||||
return path.resolve("Contents")
|
||||
.resolve("runtime")
|
||||
.resolve("Contents")
|
||||
.resolve("Home")
|
||||
.resolve("lib");
|
||||
}
|
||||
}
|
||||
|
||||
public static Path getLocalExtensionsDirectory(Path path) {
|
||||
return OsType.getLocal().equals(OsType.MACOS)
|
||||
? path.resolve("Contents").resolve("Resources").resolve("extensions")
|
||||
: path.resolve("app").resolve("extensions");
|
||||
: path.resolve("extensions");
|
||||
}
|
||||
|
||||
private static Path getLocalInstallationBasePathForJavaExecutable(Path executable) {
|
||||
@@ -151,9 +109,9 @@ public class XPipeInstallation {
|
||||
.getParent()
|
||||
.getParent();
|
||||
} else if (OsType.getLocal().equals(OsType.LINUX)) {
|
||||
return executable.getParent().getParent().getParent().getParent().getParent();
|
||||
} else {
|
||||
return executable.getParent().getParent().getParent().getParent();
|
||||
} else {
|
||||
return executable.getParent().getParent().getParent();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,9 +120,9 @@ public class XPipeInstallation {
|
||||
if (OsType.getLocal().equals(OsType.MACOS)) {
|
||||
return executable.getParent().getParent().getParent();
|
||||
} else if (OsType.getLocal().equals(OsType.LINUX)) {
|
||||
return executable.getParent().getParent().getParent();
|
||||
} else {
|
||||
return executable.getParent().getParent();
|
||||
} else {
|
||||
return executable.getParent();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,9 +142,9 @@ public class XPipeInstallation {
|
||||
if (OsType.getLocal().equals(OsType.MACOS)) {
|
||||
return path.getParent().getParent().getParent().toString();
|
||||
} else if (OsType.getLocal().equals(OsType.LINUX)) {
|
||||
return path.getParent().getParent().getParent().toString();
|
||||
return path.getParent().getParent().toString();
|
||||
} else {
|
||||
return path.getParent().getParent().getParent().toString();
|
||||
return path.getParent().getParent().toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,9 +172,9 @@ public class XPipeInstallation {
|
||||
}
|
||||
|
||||
if (OsType.getLocal().equals(OsType.WINDOWS)) {
|
||||
return path.resolve("app").resolve("bundled");
|
||||
return path.resolve("bundled");
|
||||
} else if (OsType.getLocal().equals(OsType.LINUX)) {
|
||||
return path.resolve("app").resolve("bundled");
|
||||
return path.resolve("bundled");
|
||||
} else {
|
||||
return path.resolve("Contents").resolve("Resources").resolve("bundled");
|
||||
}
|
||||
@@ -244,7 +202,7 @@ public class XPipeInstallation {
|
||||
}
|
||||
|
||||
if (OsType.getLocal().equals(OsType.WINDOWS)) {
|
||||
return path.resolve("app").resolve("logo.ico");
|
||||
return path.resolve("logo.ico");
|
||||
} else if (OsType.getLocal().equals(OsType.LINUX)) {
|
||||
return path.resolve("logo.png");
|
||||
} else {
|
||||
@@ -284,9 +242,9 @@ public class XPipeInstallation {
|
||||
var install = getCurrentInstallationBasePath();
|
||||
var type = OsType.getLocal();
|
||||
if (type.equals(OsType.WINDOWS)) {
|
||||
return install.resolve("app").resolve("lang");
|
||||
return install.resolve("lang");
|
||||
} else if (type.equals(OsType.LINUX)) {
|
||||
return install.resolve("app").resolve("lang");
|
||||
return install.resolve("lang");
|
||||
} else {
|
||||
return install.resolve("Contents").resolve("Resources").resolve("lang");
|
||||
}
|
||||
@@ -300,9 +258,9 @@ public class XPipeInstallation {
|
||||
var install = getCurrentInstallationBasePath();
|
||||
var type = OsType.getLocal();
|
||||
if (type.equals(OsType.WINDOWS)) {
|
||||
return install.resolve("app").resolve("fonts");
|
||||
return install.resolve("fonts");
|
||||
} else if (type.equals(OsType.LINUX)) {
|
||||
return install.resolve("app").resolve("fonts");
|
||||
return install.resolve("fonts");
|
||||
} else {
|
||||
return install.resolve("Contents").resolve("Resources").resolve("fonts");
|
||||
}
|
||||
@@ -310,9 +268,9 @@ public class XPipeInstallation {
|
||||
|
||||
public static String getDaemonDebugScriptPath(OsType.Local type) {
|
||||
if (type.equals(OsType.WINDOWS)) {
|
||||
return FileNames.join("app", "scripts", "xpiped_debug.bat");
|
||||
return FileNames.join("scripts", "xpiped_debug.bat");
|
||||
} else if (type.equals(OsType.LINUX)) {
|
||||
return FileNames.join("app", "scripts", "xpiped_debug.sh");
|
||||
return FileNames.join("scripts", "xpiped_debug.sh");
|
||||
} else {
|
||||
return FileNames.join("Contents", "Resources", "scripts", "xpiped_debug.sh");
|
||||
}
|
||||
@@ -320,9 +278,9 @@ public class XPipeInstallation {
|
||||
|
||||
public static String getDaemonDebugAttachScriptPath(OsType.Local type) {
|
||||
if (type.equals(OsType.WINDOWS)) {
|
||||
return FileNames.join("app", "scripts", "xpiped_debug_attach.bat");
|
||||
return FileNames.join("scripts", "xpiped_debug_attach.bat");
|
||||
} else if (type.equals(OsType.LINUX)) {
|
||||
return FileNames.join("app", "scripts", "xpiped_debug_attach.sh");
|
||||
return FileNames.join("scripts", "xpiped_debug_attach.sh");
|
||||
} else {
|
||||
return FileNames.join("Contents", "Resources", "scripts", "xpiped_debug_attach.sh");
|
||||
}
|
||||
@@ -330,9 +288,9 @@ public class XPipeInstallation {
|
||||
|
||||
public static String getDaemonExecutablePath(OsType.Local type) {
|
||||
if (type.equals(OsType.WINDOWS)) {
|
||||
return FileNames.join("app", "xpiped.exe");
|
||||
return FileNames.join("xpiped.exe");
|
||||
} else if (type.equals(OsType.LINUX)) {
|
||||
return FileNames.join("app", "bin", "xpiped");
|
||||
return FileNames.join("bin", "xpiped");
|
||||
} else {
|
||||
return FileNames.join("Contents", "MacOS", "xpiped");
|
||||
}
|
||||
@@ -340,9 +298,9 @@ public class XPipeInstallation {
|
||||
|
||||
public static String getRelativeCliExecutablePath(OsType.Local type) {
|
||||
if (type.equals(OsType.WINDOWS)) {
|
||||
return FileNames.join("cli", "bin", "xpipe.exe");
|
||||
return FileNames.join("bin", "xpipe.exe");
|
||||
} else if (type.equals(OsType.LINUX)) {
|
||||
return FileNames.join("cli", "bin", "xpipe");
|
||||
return FileNames.join("bin", "xpipe");
|
||||
} else {
|
||||
return FileNames.join("Contents", "MacOS", "xpipe");
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ open module io.xpipe.core {
|
||||
requires static lombok;
|
||||
|
||||
uses com.fasterxml.jackson.databind.Module;
|
||||
uses io.xpipe.core.util.ProxyManagerProvider;
|
||||
uses io.xpipe.core.util.DataStateProvider;
|
||||
uses ModuleLayerLoader;
|
||||
uses ShellDialect;
|
||||
|
||||
Reference in New Issue
Block a user