From e9c9cd44cd382b5eee37c2bbd17260f8f03a5f1c Mon Sep 17 00:00:00 2001 From: Christopher Schnick Date: Mon, 5 Dec 2022 00:50:58 +0100 Subject: [PATCH] Rework on shells --- .../java/io/xpipe/core/process/OsType.java | 17 ++++ .../core/process/ShellProcessControl.java | 6 ++ .../java/io/xpipe/core/process/ShellType.java | 6 ++ .../io/xpipe/core/process/ShellTypes.java | 97 ++++++++++++++++--- .../xpipe/core/store/DataStoreFormatter.java | 30 ------ .../io/xpipe/core/util/CoreJacksonModule.java | 2 +- .../extension/DataStoreActionProvider.java | 4 + .../extension/prefs/PrefsChoiceValue.java | 9 +- .../extension/util/DataStoreFormatter.java | 63 ++++++++++++ 9 files changed, 189 insertions(+), 45 deletions(-) delete mode 100644 core/src/main/java/io/xpipe/core/store/DataStoreFormatter.java create mode 100644 extension/src/main/java/io/xpipe/extension/util/DataStoreFormatter.java diff --git a/core/src/main/java/io/xpipe/core/process/OsType.java b/core/src/main/java/io/xpipe/core/process/OsType.java index 5322d286b..8ca26305a 100644 --- a/core/src/main/java/io/xpipe/core/process/OsType.java +++ b/core/src/main/java/io/xpipe/core/process/OsType.java @@ -11,6 +11,8 @@ public interface OsType { Linux LINUX = new Linux(); Mac MAC = new Mac(); + String getScriptFileEnding(); + String getName(); String getTempDirectory(ShellProcessControl pc) throws Exception; @@ -40,6 +42,11 @@ public interface OsType { static class Windows implements OsType { + @Override + public String getScriptFileEnding() { + return "bat"; + } + @Override public String getName() { return "Windows"; @@ -98,6 +105,11 @@ public interface OsType { return String.join("/", file.split("[\\\\/]+")); } + @Override + public String getScriptFileEnding() { + return "sh"; + } + @Override public String getName() { return "Linux"; @@ -168,6 +180,11 @@ public interface OsType { return String.join("/", file.split("[\\\\/]+")); } + @Override + public String getScriptFileEnding() { + return "sh"; + } + @Override public String getName() { return "Mac"; diff --git a/core/src/main/java/io/xpipe/core/process/ShellProcessControl.java b/core/src/main/java/io/xpipe/core/process/ShellProcessControl.java index a474d76a4..0bc2ec2a5 100644 --- a/core/src/main/java/io/xpipe/core/process/ShellProcessControl.java +++ b/core/src/main/java/io/xpipe/core/process/ShellProcessControl.java @@ -11,6 +11,12 @@ import java.util.stream.Collectors; public interface ShellProcessControl extends ProcessControl { + default String prepareOpen() throws Exception { + return prepareOpen(null); + } + + String prepareOpen(String content) throws Exception; + default String executeSimpleCommand(String command) throws Exception { try (CommandProcessControl c = command(command).start()) { return c.readOrThrow(); diff --git a/core/src/main/java/io/xpipe/core/process/ShellType.java b/core/src/main/java/io/xpipe/core/process/ShellType.java index 1e20577e3..ae80fcc3a 100644 --- a/core/src/main/java/io/xpipe/core/process/ShellType.java +++ b/core/src/main/java/io/xpipe/core/process/ShellType.java @@ -10,6 +10,10 @@ import java.util.stream.Collectors; @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") public interface ShellType { + String createInitFileContent(String command); + + List getOpenWithInitFileCommand(String file); + default String flatten(List command) { return command.stream().map(s -> s.contains(" ") ? "\"" + s + "\"" : s).collect(Collectors.joining(" ")); } @@ -65,5 +69,7 @@ public interface ShellType { String getDisplayName(); + String getExecutable(); + boolean echoesInput(); } diff --git a/core/src/main/java/io/xpipe/core/process/ShellTypes.java b/core/src/main/java/io/xpipe/core/process/ShellTypes.java index ab08e75bc..574e914ff 100644 --- a/core/src/main/java/io/xpipe/core/process/ShellTypes.java +++ b/core/src/main/java/io/xpipe/core/process/ShellTypes.java @@ -2,6 +2,7 @@ package io.xpipe.core.process; import com.fasterxml.jackson.annotation.JsonTypeName; import io.xpipe.core.charsetter.NewLine; +import lombok.EqualsAndHashCode; import lombok.Value; import java.io.BufferedReader; @@ -17,6 +18,7 @@ public class ShellTypes { public static final ShellType POWERSHELL = new PowerShell(); public static final ShellType CMD = new Cmd(); public static final ShellType SH = new Sh(); + public static final ShellType BASH = new Bash(); public static ShellType getRecommendedDefault() { if (System.getProperty("os.name").startsWith("Windows")) { @@ -39,7 +41,7 @@ public class ShellTypes { } public static ShellType[] getLinuxShells() { - return new ShellType[] {SH}; + return new ShellType[] {BASH, SH}; } @JsonTypeName("cmd") @@ -79,11 +81,21 @@ public class ShellTypes { return "&"; } + @Override + public List getOpenWithInitFileCommand(String file) { + return List.of(getExecutable(), "/V:on", "/K", file); + } + @Override public String escape(String input) { return input; } + @Override + public String createInitFileContent(String command) { + return "@echo off\n" + command; + } + @Override public void elevate(ShellProcessControl control, String command, String displayCommand) throws Exception { try (CommandProcessControl c = control.command("net session >NUL 2>NUL")) { @@ -163,6 +175,11 @@ public class ShellTypes { return "cmd"; } + @Override + public String getExecutable() { + return "C:\\Windows\\System32\\cmd.exe"; + } + @Override public boolean echoesInput() { return true; @@ -173,6 +190,11 @@ public class ShellTypes { @Value public static class PowerShell implements ShellType { + @Override + public String getExecutable() { + return "C:\\Windows\\System32\\powershell.exe"; + } + @Override public String getPrintVariableCommand(String name) { return "echo %" + name + "%"; @@ -205,6 +227,16 @@ public class ShellTypes { return true; } + @Override + public String createInitFileContent(String command) { + return "@echo off\n" + command; + } + + @Override + public List getOpenWithInitFileCommand(String file) { + return List.of("powershell.exe", "-NoExit", "-ExecutionPolicy", "Bypass", "-File", file); + } + @Override public String escape(String input) { return input; @@ -298,9 +330,14 @@ public class ShellTypes { } } - @JsonTypeName("sh") - @Value - public static class Sh implements ShellType { + public abstract static class PosixBase implements ShellType { + + public abstract String getName(); + + @Override + public String createInitFileContent(String command) { + return "echo a\n" + command + "\necho b"; + } @Override public String getPrintVariableCommand(String name) { @@ -317,9 +354,14 @@ public class ShellTypes { return ";"; } + @Override + public List getOpenWithInitFileCommand(String file) { + return List.of(getExecutable(), "--init-file", file, "-i", "-l"); + } + @Override public String escape(String input) { - return input.replace("$","\\$"); + return input.replace("$", "\\$"); } @Override @@ -344,7 +386,6 @@ public class ShellTypes { return "echo " + s + (toErrorStream ? " 1>&2" : ""); } - @Override public String queryShellProcessId(ShellProcessControl control) throws Exception { try (CommandProcessControl c = control.command("echo $$").start()) { @@ -362,12 +403,12 @@ public class ShellTypes { @Override public List openCommand() { - return List.of("sh", "-i", "-l"); + return List.of(getName(), "-i", "-l"); } @Override public String switchTo(String cmd) { - return "sh -c \"" + cmd + "\""; + return getName() + " -c \"" + cmd + "\""; } @Override @@ -401,8 +442,19 @@ public class ShellTypes { } @Override - public String getName() { - return "sh"; + public boolean echoesInput() { + return false; + } + } + + @JsonTypeName("sh") + @Value + @EqualsAndHashCode(callSuper = false) + public static class Sh extends PosixBase { + + @Override + public String getExecutable() { + return "/bin/sh"; } @Override @@ -411,8 +463,29 @@ public class ShellTypes { } @Override - public boolean echoesInput() { - return false; + public String getName() { + return "sh"; + } + } + + @JsonTypeName("bash") + @Value + @EqualsAndHashCode(callSuper = false) + public static class Bash extends PosixBase { + + @Override + public String getExecutable() { + return "/bin/bash"; + } + + @Override + public String getDisplayName() { + return "/bin/bash"; + } + + @Override + public String getName() { + return "bash"; } } } diff --git a/core/src/main/java/io/xpipe/core/store/DataStoreFormatter.java b/core/src/main/java/io/xpipe/core/store/DataStoreFormatter.java deleted file mode 100644 index b3779a9f6..000000000 --- a/core/src/main/java/io/xpipe/core/store/DataStoreFormatter.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.xpipe.core.store; - -public class DataStoreFormatter { - - public static String ellipsis(String input, int length) { - if (input == null) { - return ""; - } - - var end = Math.min(input.length(), length); - if (end < input.length()) { - return input.substring(0, end) + "..."; - } - return input; - } - - public static String specialFormatHostName(String input) { - if (input.contains(":")) { - input = input.split(":")[0]; - } - - if (input.endsWith(".rds.amazonaws.com")) { - var split = input.split("\\."); - var name = split[0]; - var region = split[2]; - return String.format("RDS %s @ %s", name, region); - } - return null; - } -} diff --git a/core/src/main/java/io/xpipe/core/util/CoreJacksonModule.java b/core/src/main/java/io/xpipe/core/util/CoreJacksonModule.java index 2f73771db..5d65b9ea5 100644 --- a/core/src/main/java/io/xpipe/core/util/CoreJacksonModule.java +++ b/core/src/main/java/io/xpipe/core/util/CoreJacksonModule.java @@ -46,7 +46,7 @@ public class CoreJacksonModule extends SimpleModule { new NamedType(WildcardType.class), new NamedType(ShellTypes.Cmd.class), new NamedType(ShellTypes.PowerShell.class), - new NamedType(ShellTypes.Sh.class), + new NamedType(ShellTypes.PosixBase.class), new NamedType(BaseQueryElement.class), new NamedType(ChoiceElement.class), new NamedType(BusyElement.class), diff --git a/extension/src/main/java/io/xpipe/extension/DataStoreActionProvider.java b/extension/src/main/java/io/xpipe/extension/DataStoreActionProvider.java index 3eb0db74b..7f1cb58c7 100644 --- a/extension/src/main/java/io/xpipe/extension/DataStoreActionProvider.java +++ b/extension/src/main/java/io/xpipe/extension/DataStoreActionProvider.java @@ -31,6 +31,10 @@ public interface DataStoreActionProvider { Class getApplicableClass(); + default boolean isMajor() { + return false; + } + default boolean isActive() throws Exception { return true; } diff --git a/extension/src/main/java/io/xpipe/extension/prefs/PrefsChoiceValue.java b/extension/src/main/java/io/xpipe/extension/prefs/PrefsChoiceValue.java index ac2787daa..12722bfa8 100644 --- a/extension/src/main/java/io/xpipe/extension/prefs/PrefsChoiceValue.java +++ b/extension/src/main/java/io/xpipe/extension/prefs/PrefsChoiceValue.java @@ -30,11 +30,16 @@ public interface PrefsChoiceValue extends Translatable { } @SuppressWarnings("unchecked") - static List getSupported(Class type) { + static List getSupported(Class type) { try { return (List) type.getDeclaredField("SUPPORTED").get(null); } catch (IllegalAccessException | NoSuchFieldException e) { - return getAll(type).stream().filter(t -> t.isSupported()).toList(); + var all = getAll(type); + if (all == null) { + throw new AssertionError(); + } + + return all.stream().filter(t -> ((PrefsChoiceValue)t).isSupported()).toList(); } } diff --git a/extension/src/main/java/io/xpipe/extension/util/DataStoreFormatter.java b/extension/src/main/java/io/xpipe/extension/util/DataStoreFormatter.java new file mode 100644 index 000000000..437d8fdd2 --- /dev/null +++ b/extension/src/main/java/io/xpipe/extension/util/DataStoreFormatter.java @@ -0,0 +1,63 @@ +package io.xpipe.extension.util; + +import io.xpipe.core.store.DataStore; +import io.xpipe.core.store.ShellStore; +import io.xpipe.extension.DataStoreProviders; + +import java.util.function.IntFunction; + +public class DataStoreFormatter { + + public static String formatAtHost(IntFunction func, DataStore at, int length) { + var atString = at instanceof ShellStore shellStore && !ShellStore.isLocal(shellStore) + ? DataStoreProviders.byStore(at).toSummaryString(at, length) + : null; + if (atString == null) { + return func.apply(length); + } + + var fileString = func.apply(length - atString.length() - 3); + return String.format("%s @ %s", fileString, atString); + } + + public static String format(DataStore input, int length) { + var named = XPipeDaemon.getInstance().getStoreName(input); + if (named.isPresent()) { + return cut(named.get(), length); + } + + return DataStoreProviders.byStore(input).toSummaryString(input, length); + } + + public static String cut(String input, int length) { + if (input == null) { + return ""; + } + + var end = Math.min(input.length(), length); + if (end < input.length()) { + return input.substring(0, end) + "..."; + } + return input; + } + + public static String formatHostName(String input, int length) { + // Remove port + if (input.contains(":")) { + input = input.split(":")[0]; + } + + // Check for amazon web services + if (input.endsWith(".rds.amazonaws.com")) { + var split = input.split("\\."); + var name = split[0]; + var region = split[2]; + var lengthShare = (length - 3) / 2; + return String.format( + "%s @ %s", + DataStoreFormatter.cut(name, lengthShare), DataStoreFormatter.cut(region, length - lengthShare)); + } + + return cut(input, length); + } +}