diff --git a/core/src/main/java/io/xpipe/core/store/CommandProcessControl.java b/core/src/main/java/io/xpipe/core/store/CommandProcessControl.java index d5aa6f2a..1bbaa986 100644 --- a/core/src/main/java/io/xpipe/core/store/CommandProcessControl.java +++ b/core/src/main/java/io/xpipe/core/store/CommandProcessControl.java @@ -33,6 +33,8 @@ public interface CommandProcessControl extends ProcessControl { } } + public boolean waitFor(); + CommandProcessControl customCharset(Charset charset); int getExitCode(); @@ -70,7 +72,7 @@ public interface CommandProcessControl extends ProcessControl { } } - Thread discardOut(); + void discardOut(); - Thread discardErr(); + void discardErr(); } diff --git a/core/src/main/java/io/xpipe/core/store/MachineStore.java b/core/src/main/java/io/xpipe/core/store/MachineStore.java index f6b8274a..756ed1c1 100644 --- a/core/src/main/java/io/xpipe/core/store/MachineStore.java +++ b/core/src/main/java/io/xpipe/core/store/MachineStore.java @@ -1,7 +1,5 @@ package io.xpipe.core.store; -import io.xpipe.core.util.SupportedOs; - import java.io.InputStream; import java.io.OutputStream; @@ -19,7 +17,7 @@ public interface MachineStore extends FileSystemStore, ShellStore { public default String queryMachineName() throws Exception { try (var pc = create().start()) { - var operatingSystem = SupportedOs.determine(pc); + var operatingSystem = pc.getOsType(); return operatingSystem.determineOperatingSystemName(pc); } } diff --git a/core/src/main/java/io/xpipe/core/store/ProcessControl.java b/core/src/main/java/io/xpipe/core/store/ProcessControl.java index 49ed3c7d..f795e815 100644 --- a/core/src/main/java/io/xpipe/core/store/ProcessControl.java +++ b/core/src/main/java/io/xpipe/core/store/ProcessControl.java @@ -13,8 +13,6 @@ public interface ProcessControl extends AutoCloseable { void writeLine(String line) throws IOException; - void typeLine(String line); - @Override void close() throws IOException; void kill() throws Exception; @@ -23,8 +21,6 @@ public interface ProcessControl extends AutoCloseable { ProcessControl start() throws Exception; - boolean waitFor() throws Exception; - InputStream getStdout(); OutputStream getStdin(); diff --git a/core/src/main/java/io/xpipe/core/store/ShellProcessControl.java b/core/src/main/java/io/xpipe/core/store/ShellProcessControl.java index 5dc31d5b..c86709d6 100644 --- a/core/src/main/java/io/xpipe/core/store/ShellProcessControl.java +++ b/core/src/main/java/io/xpipe/core/store/ShellProcessControl.java @@ -1,5 +1,6 @@ package io.xpipe.core.store; +import io.xpipe.core.util.OsType; import io.xpipe.core.util.SecretValue; import lombok.NonNull; @@ -11,6 +12,10 @@ import java.util.stream.Collectors; public interface ShellProcessControl extends ProcessControl { + int getProcessId(); + + OsType getOsType(); + ShellProcessControl elevated(Predicate elevationFunction); ShellProcessControl elevation(SecretValue value); @@ -23,6 +28,10 @@ public interface ShellProcessControl extends ProcessControl { return shell(type.openCommand()); } + default CommandProcessControl command(@NonNull ShellType type, String command) { + return command(type.switchTo(command)); + } + default ShellProcessControl shell(@NonNull List command) { return shell( command.stream().map(s -> s.contains(" ") ? "\"" + s + "\"" : s).collect(Collectors.joining(" "))); @@ -36,11 +45,6 @@ public interface ShellProcessControl extends ProcessControl { void executeCommand(String command) throws Exception; - default void executeCommand(List command) throws Exception { - executeCommand( - command.stream().map(s -> s.contains(" ") ? "\"" + s + "\"" : s).collect(Collectors.joining(" "))); - } - @Override ShellProcessControl start() throws Exception; @@ -59,5 +63,5 @@ public interface ShellProcessControl extends ProcessControl { command.stream().map(s -> s.contains(" ") ? "\"" + s + "\"" : s).collect(Collectors.joining(" "))); } - void exit() throws IOException; + void exitAndWait() throws IOException; } diff --git a/core/src/main/java/io/xpipe/core/store/ShellType.java b/core/src/main/java/io/xpipe/core/store/ShellType.java index c45da28a..50d7cad6 100644 --- a/core/src/main/java/io/xpipe/core/store/ShellType.java +++ b/core/src/main/java/io/xpipe/core/store/ShellType.java @@ -27,6 +27,8 @@ public interface ShellType { String getEchoCommand(String s, boolean toErrorStream); + String queryShellProcessId(ShellProcessControl control) throws Exception; + List openCommand(); String switchTo(String cmd); diff --git a/core/src/main/java/io/xpipe/core/store/ShellTypes.java b/core/src/main/java/io/xpipe/core/store/ShellTypes.java index e6aa54ae..32f6350d 100644 --- a/core/src/main/java/io/xpipe/core/store/ShellTypes.java +++ b/core/src/main/java/io/xpipe/core/store/ShellTypes.java @@ -5,6 +5,7 @@ import io.xpipe.core.charsetter.NewLine; import lombok.Value; import java.io.BufferedReader; +import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; @@ -50,6 +51,19 @@ public class ShellTypes { return toErrorStream ? "(echo " + s + ")1>&2" : "echo " + s; } + @Override + public String queryShellProcessId(ShellProcessControl control) throws IOException { + control.writeLine("powershell (Get-WmiObject Win32_Process -Filter ProcessId=$PID).ParentProcessId"); + + var r = new BufferedReader(new InputStreamReader(control.getStdout(), StandardCharsets.US_ASCII)); + // Read echo of command + r.readLine(); + // Read actual output + var line = r.readLine(); + r.readLine(); + return line; + } + @Override public String getConcatenationOperator() { return "&"; @@ -144,6 +158,23 @@ public class ShellTypes { @Value public static class PowerShell implements ShellType { + @Override + public String queryShellProcessId(ShellProcessControl control) throws IOException { + control.writeLine("powershell (Get-WmiObject Win32_Process -Filter ProcessId=$PID).ParentProcessId"); + + var r = new BufferedReader(new InputStreamReader(control.getStdout(), StandardCharsets.US_ASCII)); + // Read echo of command + r.readLine(); + // Read actual output + var line = r.readLine(); + return line; + } + + @Override + public String getConcatenationOperator() { + return ";"; + } + @Override public boolean echoesInput() { return true; @@ -169,7 +200,11 @@ public class ShellTypes { @Override public String getEchoCommand(String s, boolean toErrorStream) { - return String.format("%s \"%s\"", toErrorStream ? "Write-Error" : "Write-Output", s); + if (toErrorStream) { + return String.format("$host.ui.WriteErrorLine('%s')", s); + } + + return String.format("%s \"%s\"", "Write-Output", s); } @Override @@ -204,12 +239,17 @@ public class ShellTypes { @Override public Charset determineCharset(ShellProcessControl control) throws Exception { - try (CommandProcessControl c = control.command("chcp").start()) { - var output = c.readOrThrow().strip(); - var matcher = Pattern.compile("\\d+").matcher(output); - matcher.find(); - return Charset.forName("ibm" + matcher.group()); - } + control.writeLine("chcp"); + + var r = new BufferedReader(new InputStreamReader(control.getStdout(), StandardCharsets.US_ASCII)); + // Read echo of command + r.readLine(); + // Read actual output + var line = r.readLine(); + + var matcher = Pattern.compile("\\d+").matcher(line); + matcher.find(); + return Charset.forName("ibm" + matcher.group()); } @Override @@ -264,6 +304,16 @@ public class ShellTypes { return "echo " + s + (toErrorStream ? " 1>&2" : ""); } + + @Override + public String queryShellProcessId(ShellProcessControl control) throws Exception { + try (CommandProcessControl c = control.command("echo $$").start()) { + var out = c.readOnlyStdout(); + var matcher = Pattern.compile("\\d+$").matcher(out); + matcher.find(); + return matcher.group(0); + } + } @Override public List openCommand() { return List.of("sh", "-i", "-l"); @@ -291,7 +341,7 @@ public class ShellTypes { @Override public List createFileExistsCommand(String file) { - return List.of("test", "-f", file, "||", "test", "-d", file); + return List.of("(", "test", "-f", file, "||", "test", "-d", file, ")"); } @Override diff --git a/core/src/main/java/io/xpipe/core/util/SupportedOs.java b/core/src/main/java/io/xpipe/core/util/OsType.java similarity index 72% rename from core/src/main/java/io/xpipe/core/util/SupportedOs.java rename to core/src/main/java/io/xpipe/core/util/OsType.java index 33f6ce9b..830f8fbe 100644 --- a/core/src/main/java/io/xpipe/core/util/SupportedOs.java +++ b/core/src/main/java/io/xpipe/core/util/OsType.java @@ -1,36 +1,37 @@ package io.xpipe.core.util; -import io.xpipe.core.store.*; -import lombok.SneakyThrows; +import io.xpipe.core.store.CommandProcessControl; +import io.xpipe.core.store.PropertiesFormatsParser; +import io.xpipe.core.store.ShellProcessControl; +import io.xpipe.core.store.ShellTypes; import java.nio.file.Path; +import java.util.Locale; import java.util.Map; import java.util.UUID; -public interface SupportedOs { +public interface OsType { Windows WINDOWS = new Windows(); Linux LINUX = new Linux(); Mac MAC = new Mac(); - static SupportedOs determine(ShellProcessControl pc) throws Exception { - try (CommandProcessControl c = pc.command(pc.getShellType().createFileExistsCommand("C:\\pagefile.sys")).start()) { - if (c.discardAndCheckExit()) { - return WINDOWS; - } - } - - return LINUX; - } + String getName(); Map getProperties(ShellProcessControl pc) throws Exception; String determineOperatingSystemName(ShellProcessControl pc) throws Exception; - @SneakyThrows - public static SupportedOs getLocal() { - try (ShellProcessControl pc = ShellStore.local().create().start()) { - return determine(pc); + public static OsType getLocal() { + String osName = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH); + if ((osName.contains("mac")) || (osName.contains("darwin"))) { + return MAC; + } else if (osName.contains("win")) { + return WINDOWS; + } else if (osName.contains("nux")) { + return LINUX; + } else { + throw new UnsupportedOperationException("Unknown operating system"); } } @@ -38,7 +39,12 @@ public interface SupportedOs { UUID getSystemUUID(ShellProcessControl pc) throws Exception; - static class Windows implements SupportedOs { + static class Windows implements OsType { + + @Override + public String getName() { + return "Windows"; + } @Override public Map getProperties(ShellProcessControl pc) throws Exception { @@ -71,7 +77,12 @@ public interface SupportedOs { } } - static class Linux implements SupportedOs { + static class Linux implements OsType { + + @Override + public String getName() { + return "Linux"; + } @Override public Map getProperties(ShellProcessControl pc) throws Exception { @@ -81,7 +92,7 @@ public interface SupportedOs { @Override public String determineOperatingSystemName(ShellProcessControl pc) throws Exception { try (CommandProcessControl c = - pc.shell(ShellTypes.SH).command("lsb_release -a").start()) { + pc.command(ShellTypes.SH, "lsb_release -a").start()) { var text = c.readOnlyStdout(); if (c.getExitCode() == 0) { return PropertiesFormatsParser.parse(text, ":").getOrDefault("Description", null); @@ -89,7 +100,7 @@ public interface SupportedOs { } try (CommandProcessControl c = - pc.shell(ShellTypes.SH).command("cat /etc/*release").start()) { + pc.command(ShellTypes.SH, "cat /etc/*release").start()) { var text = c.readOnlyStdout(); if (c.getExitCode() == 0) { return PropertiesFormatsParser.parse(text, "=").getOrDefault("PRETTY_NAME", null); @@ -97,8 +108,7 @@ public interface SupportedOs { } String type = "Unknown"; - try (CommandProcessControl c = - pc.shell(ShellTypes.SH).command("uname -o").start()) { + try (CommandProcessControl c = pc.command(ShellTypes.SH, "uname -o").start()) { var text = c.readOnlyStdout(); if (c.getExitCode() == 0) { type = text.strip(); @@ -106,8 +116,7 @@ public interface SupportedOs { } String version = "?"; - try (CommandProcessControl c = - pc.shell(ShellTypes.SH).command("uname -r").start()) { + try (CommandProcessControl c = pc.command(ShellTypes.SH, "uname -r").start()) { var text = c.readOnlyStdout(); if (c.getExitCode() == 0) { version = text.strip(); @@ -128,7 +137,12 @@ public interface SupportedOs { } } - static class Mac implements SupportedOs { + static class Mac implements OsType { + + @Override + public String getName() { + return "Mac"; + } @Override public Map getProperties(ShellProcessControl pc) throws Exception { diff --git a/extension/src/main/java/io/xpipe/extension/event/EventHandler.java b/extension/src/main/java/io/xpipe/extension/event/EventHandler.java index 4e1ee8ff..0e6097d5 100644 --- a/extension/src/main/java/io/xpipe/extension/event/EventHandler.java +++ b/extension/src/main/java/io/xpipe/extension/event/EventHandler.java @@ -18,6 +18,7 @@ public abstract class EventHandler { cat = "log"; } System.out.println("[" + cat + "] " + te.toString()); + System.out.flush(); } @Override