More work for processes and shells

This commit is contained in:
Christopher Schnick 2022-11-22 05:18:05 +01:00
parent 9d0da32e4f
commit 54bfcd2478
8 changed files with 115 additions and 48 deletions

View file

@ -33,6 +33,8 @@ public interface CommandProcessControl extends ProcessControl {
} }
} }
public boolean waitFor();
CommandProcessControl customCharset(Charset charset); CommandProcessControl customCharset(Charset charset);
int getExitCode(); int getExitCode();
@ -70,7 +72,7 @@ public interface CommandProcessControl extends ProcessControl {
} }
} }
Thread discardOut(); void discardOut();
Thread discardErr(); void discardErr();
} }

View file

@ -1,7 +1,5 @@
package io.xpipe.core.store; package io.xpipe.core.store;
import io.xpipe.core.util.SupportedOs;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
@ -19,7 +17,7 @@ public interface MachineStore extends FileSystemStore, ShellStore {
public default String queryMachineName() throws Exception { public default String queryMachineName() throws Exception {
try (var pc = create().start()) { try (var pc = create().start()) {
var operatingSystem = SupportedOs.determine(pc); var operatingSystem = pc.getOsType();
return operatingSystem.determineOperatingSystemName(pc); return operatingSystem.determineOperatingSystemName(pc);
} }
} }

View file

@ -13,8 +13,6 @@ public interface ProcessControl extends AutoCloseable {
void writeLine(String line) throws IOException; void writeLine(String line) throws IOException;
void typeLine(String line);
@Override @Override
void close() throws IOException; void close() throws IOException;
void kill() throws Exception; void kill() throws Exception;
@ -23,8 +21,6 @@ public interface ProcessControl extends AutoCloseable {
ProcessControl start() throws Exception; ProcessControl start() throws Exception;
boolean waitFor() throws Exception;
InputStream getStdout(); InputStream getStdout();
OutputStream getStdin(); OutputStream getStdin();

View file

@ -1,5 +1,6 @@
package io.xpipe.core.store; package io.xpipe.core.store;
import io.xpipe.core.util.OsType;
import io.xpipe.core.util.SecretValue; import io.xpipe.core.util.SecretValue;
import lombok.NonNull; import lombok.NonNull;
@ -11,6 +12,10 @@ import java.util.stream.Collectors;
public interface ShellProcessControl extends ProcessControl { public interface ShellProcessControl extends ProcessControl {
int getProcessId();
OsType getOsType();
ShellProcessControl elevated(Predicate<ShellProcessControl> elevationFunction); ShellProcessControl elevated(Predicate<ShellProcessControl> elevationFunction);
ShellProcessControl elevation(SecretValue value); ShellProcessControl elevation(SecretValue value);
@ -23,6 +28,10 @@ public interface ShellProcessControl extends ProcessControl {
return shell(type.openCommand()); return shell(type.openCommand());
} }
default CommandProcessControl command(@NonNull ShellType type, String command) {
return command(type.switchTo(command));
}
default ShellProcessControl shell(@NonNull List<String> command) { default ShellProcessControl shell(@NonNull List<String> command) {
return shell( return shell(
command.stream().map(s -> s.contains(" ") ? "\"" + s + "\"" : s).collect(Collectors.joining(" "))); 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; void executeCommand(String command) throws Exception;
default void executeCommand(List<String> command) throws Exception {
executeCommand(
command.stream().map(s -> s.contains(" ") ? "\"" + s + "\"" : s).collect(Collectors.joining(" ")));
}
@Override @Override
ShellProcessControl start() throws Exception; ShellProcessControl start() throws Exception;
@ -59,5 +63,5 @@ public interface ShellProcessControl extends ProcessControl {
command.stream().map(s -> s.contains(" ") ? "\"" + s + "\"" : s).collect(Collectors.joining(" "))); command.stream().map(s -> s.contains(" ") ? "\"" + s + "\"" : s).collect(Collectors.joining(" ")));
} }
void exit() throws IOException; void exitAndWait() throws IOException;
} }

View file

@ -27,6 +27,8 @@ public interface ShellType {
String getEchoCommand(String s, boolean toErrorStream); String getEchoCommand(String s, boolean toErrorStream);
String queryShellProcessId(ShellProcessControl control) throws Exception;
List<String> openCommand(); List<String> openCommand();
String switchTo(String cmd); String switchTo(String cmd);

View file

@ -5,6 +5,7 @@ import io.xpipe.core.charsetter.NewLine;
import lombok.Value; import lombok.Value;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -50,6 +51,19 @@ public class ShellTypes {
return toErrorStream ? "(echo " + s + ")1>&2" : "echo " + s; 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 @Override
public String getConcatenationOperator() { public String getConcatenationOperator() {
return "&"; return "&";
@ -144,6 +158,23 @@ public class ShellTypes {
@Value @Value
public static class PowerShell implements ShellType { 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 @Override
public boolean echoesInput() { public boolean echoesInput() {
return true; return true;
@ -169,7 +200,11 @@ public class ShellTypes {
@Override @Override
public String getEchoCommand(String s, boolean toErrorStream) { 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 @Override
@ -204,12 +239,17 @@ public class ShellTypes {
@Override @Override
public Charset determineCharset(ShellProcessControl control) throws Exception { public Charset determineCharset(ShellProcessControl control) throws Exception {
try (CommandProcessControl c = control.command("chcp").start()) { control.writeLine("chcp");
var output = c.readOrThrow().strip();
var matcher = Pattern.compile("\\d+").matcher(output); var r = new BufferedReader(new InputStreamReader(control.getStdout(), StandardCharsets.US_ASCII));
matcher.find(); // Read echo of command
return Charset.forName("ibm" + matcher.group()); 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 @Override
@ -264,6 +304,16 @@ public class ShellTypes {
return "echo " + s + (toErrorStream ? " 1>&2" : ""); 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 @Override
public List<String> openCommand() { public List<String> openCommand() {
return List.of("sh", "-i", "-l"); return List.of("sh", "-i", "-l");
@ -291,7 +341,7 @@ public class ShellTypes {
@Override @Override
public List<String> createFileExistsCommand(String file) { public List<String> createFileExistsCommand(String file) {
return List.of("test", "-f", file, "||", "test", "-d", file); return List.of("(", "test", "-f", file, "||", "test", "-d", file, ")");
} }
@Override @Override

View file

@ -1,36 +1,37 @@
package io.xpipe.core.util; package io.xpipe.core.util;
import io.xpipe.core.store.*; import io.xpipe.core.store.CommandProcessControl;
import lombok.SneakyThrows; 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.nio.file.Path;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
public interface SupportedOs { public interface OsType {
Windows WINDOWS = new Windows(); Windows WINDOWS = new Windows();
Linux LINUX = new Linux(); Linux LINUX = new Linux();
Mac MAC = new Mac(); Mac MAC = new Mac();
static SupportedOs determine(ShellProcessControl pc) throws Exception { String getName();
try (CommandProcessControl c = pc.command(pc.getShellType().createFileExistsCommand("C:\\pagefile.sys")).start()) {
if (c.discardAndCheckExit()) {
return WINDOWS;
}
}
return LINUX;
}
Map<String, String> getProperties(ShellProcessControl pc) throws Exception; Map<String, String> getProperties(ShellProcessControl pc) throws Exception;
String determineOperatingSystemName(ShellProcessControl pc) throws Exception; String determineOperatingSystemName(ShellProcessControl pc) throws Exception;
@SneakyThrows public static OsType getLocal() {
public static SupportedOs getLocal() { String osName = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH);
try (ShellProcessControl pc = ShellStore.local().create().start()) { if ((osName.contains("mac")) || (osName.contains("darwin"))) {
return determine(pc); 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; UUID getSystemUUID(ShellProcessControl pc) throws Exception;
static class Windows implements SupportedOs { static class Windows implements OsType {
@Override
public String getName() {
return "Windows";
}
@Override @Override
public Map<String, String> getProperties(ShellProcessControl pc) throws Exception { public Map<String, String> 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 @Override
public Map<String, String> getProperties(ShellProcessControl pc) throws Exception { public Map<String, String> getProperties(ShellProcessControl pc) throws Exception {
@ -81,7 +92,7 @@ public interface SupportedOs {
@Override @Override
public String determineOperatingSystemName(ShellProcessControl pc) throws Exception { public String determineOperatingSystemName(ShellProcessControl pc) throws Exception {
try (CommandProcessControl c = try (CommandProcessControl c =
pc.shell(ShellTypes.SH).command("lsb_release -a").start()) { pc.command(ShellTypes.SH, "lsb_release -a").start()) {
var text = c.readOnlyStdout(); var text = c.readOnlyStdout();
if (c.getExitCode() == 0) { if (c.getExitCode() == 0) {
return PropertiesFormatsParser.parse(text, ":").getOrDefault("Description", null); return PropertiesFormatsParser.parse(text, ":").getOrDefault("Description", null);
@ -89,7 +100,7 @@ public interface SupportedOs {
} }
try (CommandProcessControl c = try (CommandProcessControl c =
pc.shell(ShellTypes.SH).command("cat /etc/*release").start()) { pc.command(ShellTypes.SH, "cat /etc/*release").start()) {
var text = c.readOnlyStdout(); var text = c.readOnlyStdout();
if (c.getExitCode() == 0) { if (c.getExitCode() == 0) {
return PropertiesFormatsParser.parse(text, "=").getOrDefault("PRETTY_NAME", null); return PropertiesFormatsParser.parse(text, "=").getOrDefault("PRETTY_NAME", null);
@ -97,8 +108,7 @@ public interface SupportedOs {
} }
String type = "Unknown"; String type = "Unknown";
try (CommandProcessControl c = try (CommandProcessControl c = pc.command(ShellTypes.SH, "uname -o").start()) {
pc.shell(ShellTypes.SH).command("uname -o").start()) {
var text = c.readOnlyStdout(); var text = c.readOnlyStdout();
if (c.getExitCode() == 0) { if (c.getExitCode() == 0) {
type = text.strip(); type = text.strip();
@ -106,8 +116,7 @@ public interface SupportedOs {
} }
String version = "?"; String version = "?";
try (CommandProcessControl c = try (CommandProcessControl c = pc.command(ShellTypes.SH, "uname -r").start()) {
pc.shell(ShellTypes.SH).command("uname -r").start()) {
var text = c.readOnlyStdout(); var text = c.readOnlyStdout();
if (c.getExitCode() == 0) { if (c.getExitCode() == 0) {
version = text.strip(); 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 @Override
public Map<String, String> getProperties(ShellProcessControl pc) throws Exception { public Map<String, String> getProperties(ShellProcessControl pc) throws Exception {

View file

@ -18,6 +18,7 @@ public abstract class EventHandler {
cat = "log"; cat = "log";
} }
System.out.println("[" + cat + "] " + te.toString()); System.out.println("[" + cat + "] " + te.toString());
System.out.flush();
} }
@Override @Override