From 5efa2a49d67b3751fd0d4f10255c7618196e8385 Mon Sep 17 00:00:00 2001 From: crschnick Date: Thu, 9 Feb 2023 21:06:58 +0000 Subject: [PATCH] Migrate all actions, fix various bugs --- .../comp/storage/store/StoreEntryComp.java | 15 ++- .../app/storage/DataStateProviderImpl.java | 8 ++ .../io/xpipe/app/storage/DataStorage.java | 8 +- .../io/xpipe/app/util/TerminalProvider.java | 2 +- app/src/main/java/module-info.java | 3 + .../java/io/xpipe/core/process/OsType.java | 4 +- .../core/process/ProcessControlProvider.java | 23 ++--- .../core/process/ShellProcessControl.java | 12 +-- .../java/io/xpipe/core/process/ShellType.java | 6 +- .../io/xpipe/core/process/ShellTypes.java | 35 +++++-- .../xpipe/core/util/FailableBiFunction.java | 7 ++ .../io/xpipe/core/util/FailableFunction.java | 7 ++ .../ext/base/actions/FileBrowseAction.java | 61 ++++++++---- .../ext/base/actions/FileEditAction.java | 75 +++++++++----- .../ext/base/actions/ShareStoreAction.java | 84 ++++++++++------ .../ext/base/actions/StreamExportAction.java | 98 ++++++++++++------- ext/base/src/main/java/module-info.java | 4 +- ext/proc/build.gradle | 1 + .../io/xpipe/ext/proc/CommandControlImpl.java | 10 +- .../ext/proc/LocalCommandControlImpl.java | 5 +- .../xpipe/ext/proc/LocalShellControlImpl.java | 4 +- .../java/io/xpipe/ext/proc/ProcProvider.java | 15 ++- .../io/xpipe/ext/proc/ShellControlImpl.java | 19 ++-- .../xpipe/ext/proc/action/LaunchAction.java | 5 + .../proc/augment/CmdCommandAugmentation.java | 4 +- .../ext/proc/augment/CommandAugmentation.java | 32 +++++- .../proc/augment/NoCommandAugmentation.java | 4 +- .../PosixShellCommandAugmentation.java | 4 +- .../PowershellCommandAugmentation.java | 4 +- .../proc/augment/SshCommandAugmentation.java | 16 ++- ext/proc/src/main/java/module-info.java | 3 +- .../src/test/java/test/CommandStoreTest.java | 2 +- .../java/test/item/ShellCheckTestItem.java | 5 +- .../extension/DataStoreActionProvider.java | 59 ----------- .../io/xpipe/extension/util/ScriptHelper.java | 27 +++++ extension/src/main/java/module-info.java | 2 - 36 files changed, 412 insertions(+), 261 deletions(-) create mode 100644 core/src/main/java/io/xpipe/core/util/FailableBiFunction.java create mode 100644 core/src/main/java/io/xpipe/core/util/FailableFunction.java delete mode 100644 extension/src/main/java/io/xpipe/extension/DataStoreActionProvider.java diff --git a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryComp.java b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryComp.java index 79ac4e4d..df2b6f4e 100644 --- a/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryComp.java +++ b/app/src/main/java/io/xpipe/app/comp/storage/store/StoreEntryComp.java @@ -171,13 +171,18 @@ public class StoreEntryComp extends SimpleComp { var button = new IconButtonComp( actionProvider.getIcon(entry.getEntry().getStore().asNeeded()), () -> { ThreadHelper.runFailableAsync(() -> { - var action = actionProvider.createAction(entry.getEntry().getStore().asNeeded()); + var action = actionProvider.createAction( + entry.getEntry().getStore().asNeeded()); action.execute(); }); }); button.apply(new FancyTooltipAugment<>( actionProvider.getName(entry.getEntry().getStore().asNeeded()))); - button.disable(Bindings.not(p.getValue())); + if (!actionProvider.showIfDisabled()) { + button.hide(Bindings.not(p.getValue())); + } else { + button.disable(Bindings.not(p.getValue())); + } list.add(button); } @@ -227,7 +232,8 @@ public class StoreEntryComp extends SimpleComp { var item = new MenuItem(null, new FontIcon(icon)); item.setOnAction(event -> { ThreadHelper.runFailableAsync(() -> { - var action = actionProvider.createAction(entry.getEntry().getStore().asNeeded()); + var action = actionProvider.createAction( + entry.getEntry().getStore().asNeeded()); action.execute(); }); }); @@ -245,7 +251,8 @@ public class StoreEntryComp extends SimpleComp { if (AppPrefs.get().developerMode().getValue()) { var browse = new MenuItem(I18n.get("browse"), new FontIcon("mdi2f-folder-open-outline")); - browse.setOnAction(event -> DesktopHelper.browsePath(entry.getEntry().getDirectory())); + browse.setOnAction( + event -> DesktopHelper.browsePath(entry.getEntry().getDirectory())); contextMenu.getItems().add(browse); } diff --git a/app/src/main/java/io/xpipe/app/storage/DataStateProviderImpl.java b/app/src/main/java/io/xpipe/app/storage/DataStateProviderImpl.java index 6db006fd..f50b2446 100644 --- a/app/src/main/java/io/xpipe/app/storage/DataStateProviderImpl.java +++ b/app/src/main/java/io/xpipe/app/storage/DataStateProviderImpl.java @@ -11,6 +11,10 @@ public class DataStateProviderImpl extends DataStateProvider { @Override public void putState(DataStore store, String key, Object value) { + if (DataStorage.get() == null) { + return; + } + var entry = DataStorage.get().getEntryByStore(store); if (entry.isEmpty()) { return; @@ -22,6 +26,10 @@ public class DataStateProviderImpl extends DataStateProvider { @Override public T getState(DataStore store, String key, Class c, Supplier def) { + if (DataStorage.get() == null) { + return def.get(); + } + var entry = DataStorage.get().getEntryByStore(store); if (entry.isEmpty()) { return def.get(); diff --git a/app/src/main/java/io/xpipe/app/storage/DataStorage.java b/app/src/main/java/io/xpipe/app/storage/DataStorage.java index c4fc7ccc..26c73c2c 100644 --- a/app/src/main/java/io/xpipe/app/storage/DataStorage.java +++ b/app/src/main/java/io/xpipe/app/storage/DataStorage.java @@ -74,10 +74,6 @@ public abstract class DataStorage { } public static DataStorage get() { - if (INSTANCE == null) { - throw new IllegalStateException("Not initialized"); - } - return INSTANCE; } @@ -175,6 +171,10 @@ public abstract class DataStorage { } public Optional getCollectionForName(String name) { + if (name == null) { + return Optional.ofNullable(getInternalCollection()); + } + return sourceCollections.stream() .filter(c -> name.equalsIgnoreCase(c.getName())) .findAny(); diff --git a/app/src/main/java/io/xpipe/app/util/TerminalProvider.java b/app/src/main/java/io/xpipe/app/util/TerminalProvider.java index 517e5395..46b551cb 100644 --- a/app/src/main/java/io/xpipe/app/util/TerminalProvider.java +++ b/app/src/main/java/io/xpipe/app/util/TerminalProvider.java @@ -13,7 +13,7 @@ public abstract class TerminalProvider { @Override public void init(ModuleLayer layer) { - ServiceLoader.load(layer, TerminalProvider.class).findFirst().orElseThrow(); + INSTANCE = ServiceLoader.load(layer, TerminalProvider.class).findFirst().orElseThrow(); } @Override diff --git a/app/src/main/java/module-info.java b/app/src/main/java/module-info.java index 726b2513..493c2ffe 100644 --- a/app/src/main/java/module-info.java +++ b/app/src/main/java/module-info.java @@ -7,12 +7,14 @@ import io.xpipe.app.exchange.cli.*; import io.xpipe.app.issue.EventHandlerImpl; import io.xpipe.app.storage.DataStateProviderImpl; import io.xpipe.app.util.ProxyManagerProviderImpl; +import io.xpipe.app.util.TerminalProvider; import io.xpipe.app.util.XPipeDaemonProvider; import io.xpipe.core.util.DataStateProvider; import io.xpipe.core.util.ProxyManagerProvider; import io.xpipe.extension.Cache; import io.xpipe.extension.I18n; import io.xpipe.extension.event.EventHandler; +import io.xpipe.extension.util.ModuleLayerLoader; import io.xpipe.extension.util.XPipeDaemon; import org.slf4j.spi.SLF4JServiceProvider; @@ -99,6 +101,7 @@ open module io.xpipe.app { uses MessageExchangeImpl; uses io.xpipe.app.util.TerminalProvider; + provides ModuleLayerLoader with TerminalProvider.Loader; provides DataStateProvider with DataStateProviderImpl; provides ProxyManagerProvider with 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 236beb61..c62ab09e 100644 --- a/core/src/main/java/io/xpipe/core/process/OsType.java +++ b/core/src/main/java/io/xpipe/core/process/OsType.java @@ -41,7 +41,7 @@ public interface OsType { @Override public String getTempDirectory(ShellProcessControl pc) throws Exception { - return pc.executeStringSimpleCommand(ShellTypes.CMD, ShellTypes.CMD.getPrintVariableCommand("TEMP")); + return pc.executeStringSimpleCommand(pc.getShellType().getPrintEnvironmentVariableCommand("TEMP")); } @Override @@ -52,7 +52,7 @@ public interface OsType { @Override public Map getProperties(ShellProcessControl pc) throws Exception { try (CommandProcessControl c = - pc.subShell(ShellTypes.CMD).command("systeminfo").start()) { + pc.command("systeminfo").start()) { var text = c.readOrThrow(); return PropertiesFormatsParser.parse(text, ":"); } diff --git a/core/src/main/java/io/xpipe/core/process/ProcessControlProvider.java b/core/src/main/java/io/xpipe/core/process/ProcessControlProvider.java index 903ecaa9..25b916ff 100644 --- a/core/src/main/java/io/xpipe/core/process/ProcessControlProvider.java +++ b/core/src/main/java/io/xpipe/core/process/ProcessControlProvider.java @@ -1,12 +1,12 @@ package io.xpipe.core.process; +import io.xpipe.core.util.FailableBiFunction; +import io.xpipe.core.util.FailableFunction; import lombok.NonNull; import java.util.List; import java.util.Objects; import java.util.ServiceLoader; -import java.util.function.BiFunction; -import java.util.function.Function; public abstract class ProcessControlProvider { @@ -18,21 +18,22 @@ public abstract class ProcessControlProvider { } public static ShellProcessControl createLocal() { - return INSTANCES.stream().map(localProcessControlProvider -> localProcessControlProvider.createLocalProcessControl()).findFirst().orElseThrow(); + return INSTANCES.stream().map(localProcessControlProvider -> localProcessControlProvider.createLocalProcessControl()).filter( + Objects::nonNull).findFirst().orElseThrow(); } public static ShellProcessControl createSub( ShellProcessControl parent, - @NonNull Function commandFunction, - BiFunction terminalCommand) { + @NonNull FailableFunction commandFunction, + FailableBiFunction terminalCommand) { return INSTANCES.stream().map(localProcessControlProvider -> localProcessControlProvider.sub(parent, commandFunction, terminalCommand)).filter( Objects::nonNull).findFirst().orElseThrow(); } public static CommandProcessControl createCommand( ShellProcessControl parent, - @NonNull Function command, - Function terminalCommand) { + @NonNull FailableFunction command, + FailableFunction terminalCommand) { return INSTANCES.stream().map(localProcessControlProvider -> localProcessControlProvider.command(parent, command, terminalCommand)).filter( Objects::nonNull).findFirst().orElseThrow(); } @@ -44,13 +45,13 @@ public abstract class ProcessControlProvider { public abstract ShellProcessControl sub( ShellProcessControl parent, - @NonNull Function commandFunction, - BiFunction terminalCommand); + @NonNull FailableFunction commandFunction, + FailableBiFunction terminalCommand); public abstract CommandProcessControl command( ShellProcessControl parent, - @NonNull Function command, - Function terminalCommand); + @NonNull FailableFunction command, + FailableFunction terminalCommand); public abstract ShellProcessControl createLocalProcessControl(); 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 3e789fa8..83e75d5d 100644 --- a/core/src/main/java/io/xpipe/core/process/ShellProcessControl.java +++ b/core/src/main/java/io/xpipe/core/process/ShellProcessControl.java @@ -1,13 +1,13 @@ package io.xpipe.core.process; +import io.xpipe.core.util.FailableBiFunction; +import io.xpipe.core.util.FailableFunction; import io.xpipe.core.util.SecretValue; import lombok.NonNull; import java.io.IOException; import java.util.List; -import java.util.function.BiFunction; import java.util.function.Consumer; -import java.util.function.Function; import java.util.function.Predicate; public interface ShellProcessControl extends ProcessControl { @@ -87,18 +87,18 @@ public interface ShellProcessControl extends ProcessControl { } ShellProcessControl subShell( - @NonNull Function command, - BiFunction terminalCommand); + FailableFunction command, + FailableBiFunction terminalCommand); void executeLine(String command) throws Exception; @Override ShellProcessControl start() throws Exception; - CommandProcessControl command(Function command); + CommandProcessControl command(FailableFunction command); CommandProcessControl command( - Function command, Function terminalCommand); + FailableFunction command, FailableFunction terminalCommand); default CommandProcessControl command(String command) { return command(shellProcessControl -> command); 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 5de37ffc..8d27ab76 100644 --- a/core/src/main/java/io/xpipe/core/process/ShellType.java +++ b/core/src/main/java/io/xpipe/core/process/ShellType.java @@ -60,11 +60,9 @@ public interface ShellType { String getEchoCommand(String s, boolean toErrorStream); - default String getPrintVariableCommand(String name) { - return getPrintVariableCommand("", name); - } + String getPrintVariableCommand(String name); - String getPrintVariableCommand(String prefix, String name); + String getPrintExitCodeCommand(String prefix); default String getPrintEnvironmentVariableCommand(String name) { return getPrintVariableCommand(name); 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 ca194efe..9ab41215 100644 --- a/core/src/main/java/io/xpipe/core/process/ShellTypes.java +++ b/core/src/main/java/io/xpipe/core/process/ShellTypes.java @@ -59,12 +59,17 @@ public class ShellTypes { @Override public String getSetEnvironmentVariableCommand(String variableName, String value) { - return ("set \"" + variableName + "=" + value.replaceAll("\"", "^$0") + "\""); + return ("set \"" + variableName + "=" + value.replaceAll("[&^|<>\"]", "^$0") + "\""); } @Override - public String getPrintVariableCommand(String prefix, String name) { - return "call echo " + prefix + "^%" + name + "^%"; + public String getPrintExitCodeCommand(String prefix) { + return "call echo " + prefix + "^%" + getExitCodeVariable() + "^%"; + } + + @Override + public String getPrintVariableCommand(String name) { + return "call echo ^%" + name + "^%"; } @Override @@ -276,8 +281,13 @@ public class ShellTypes { } @Override - public String getPrintVariableCommand(String prefix, String name) { - return "echo \"" + escapeStringValue(prefix) + "$" + escapeStringValue(name) + "\""; + public String getPrintExitCodeCommand(String prefix) { + return "echo \"" + prefix + "$(If ($?) {0} Else {1})\""; + } + + @Override + public String getPrintVariableCommand(String name) { + return "echo \"" + "$" + escapeStringValue(name) + "\""; } @Override @@ -428,7 +438,7 @@ public class ShellTypes { @Override public List executeCommandListWithShell(List cmd) { - return List.of(getExecutable(), "-c", flatten(cmd)); + return List.of(getName(), "-c", flatten(cmd)); } @Override @@ -448,7 +458,7 @@ public class ShellTypes { @Override public List executeCommandListWithShell(String cmd) { - return List.of(getExecutable(), "-c", cmd); + return List.of(getName(), "-c", cmd); } public String getScriptEchoCommand(String s) { @@ -494,12 +504,17 @@ public class ShellTypes { @Override public String prepareScriptContent(String content) { - return content; + return "#!" + getExecutable() + "\n" + content; } @Override - public String getPrintVariableCommand(String prefix, String name) { - return "echo " + prefix + "$" + name; + public String getPrintExitCodeCommand(String prefix) { + return "echo " + prefix + "$" + getExitCodeVariable(); + } + + @Override + public String getPrintVariableCommand(String name) { + return "echo \"$" + name + "\""; } @Override diff --git a/core/src/main/java/io/xpipe/core/util/FailableBiFunction.java b/core/src/main/java/io/xpipe/core/util/FailableBiFunction.java new file mode 100644 index 00000000..0fec7f0f --- /dev/null +++ b/core/src/main/java/io/xpipe/core/util/FailableBiFunction.java @@ -0,0 +1,7 @@ +package io.xpipe.core.util; + +@FunctionalInterface +public interface FailableBiFunction { + + R apply(T1 var1, T2 var2) throws E; +} diff --git a/core/src/main/java/io/xpipe/core/util/FailableFunction.java b/core/src/main/java/io/xpipe/core/util/FailableFunction.java new file mode 100644 index 00000000..0f453b64 --- /dev/null +++ b/core/src/main/java/io/xpipe/core/util/FailableFunction.java @@ -0,0 +1,7 @@ +package io.xpipe.core.util; + +@FunctionalInterface +public interface FailableFunction { + + R apply(T var1) throws E; +} diff --git a/ext/base/src/main/java/io/xpipe/ext/base/actions/FileBrowseAction.java b/ext/base/src/main/java/io/xpipe/ext/base/actions/FileBrowseAction.java index 5ead7869..17fd8302 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/actions/FileBrowseAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/actions/FileBrowseAction.java @@ -2,38 +2,61 @@ package io.xpipe.ext.base.actions; import io.xpipe.core.impl.FileStore; import io.xpipe.core.impl.LocalStore; -import io.xpipe.extension.DataStoreActionProvider; import io.xpipe.extension.I18n; +import io.xpipe.extension.util.ActionProvider; import io.xpipe.extension.util.DesktopHelper; import javafx.beans.value.ObservableValue; +import lombok.Value; import java.nio.file.Files; import java.nio.file.Path; -public class FileBrowseAction implements DataStoreActionProvider { +public class FileBrowseAction implements ActionProvider { - @Override - public Class getApplicableClass() { - return FileStore.class; + @Value + static class Action implements ActionProvider.Action { + + FileStore store; + + @Override + public boolean requiresPlatform() { + return false; + } + + @Override + public void execute() throws Exception { + DesktopHelper.browseFileInDirectory(Path.of(store.getFile())); + } } @Override - public boolean isApplicable(FileStore o) throws Exception { - return o.getFileSystem().equals(new LocalStore()) && Files.exists(Path.of(o.getFile())); - } + public DataStoreCallSite getDataStoreCallSite() { + return new DataStoreCallSite() { - @Override - public ObservableValue getName(FileStore store) { - return I18n.observable("base.browseFile"); - } + @Override + public ActionProvider.Action createAction(FileStore store) { + return new Action(store); + } - @Override - public String getIcon(FileStore store) { - return "mdi2f-folder-open-outline"; - } + @Override + public Class getApplicableClass() { + return FileStore.class; + } - @Override - public void execute(FileStore store) throws Exception { - DesktopHelper.browseFileInDirectory(Path.of(store.getFile())); + @Override + public boolean isApplicable(FileStore o) throws Exception { + return o.getFileSystem().equals(new LocalStore()) && Files.exists(Path.of(o.getFile())); + } + + @Override + public ObservableValue getName(FileStore store) { + return I18n.observable("base.browseFile"); + } + + @Override + public String getIcon(FileStore store) { + return "mdi2f-folder-open-outline"; + } + }; } } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/actions/FileEditAction.java b/ext/base/src/main/java/io/xpipe/ext/base/actions/FileEditAction.java index be7c93f8..c55d926e 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/actions/FileEditAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/actions/FileEditAction.java @@ -4,39 +4,62 @@ import io.xpipe.app.util.ExternalEditor; import io.xpipe.core.impl.FileStore; import io.xpipe.core.impl.LocalStore; import io.xpipe.core.store.DataFlow; -import io.xpipe.extension.DataStoreActionProvider; import io.xpipe.extension.I18n; +import io.xpipe.extension.util.ActionProvider; import javafx.beans.value.ObservableValue; +import lombok.Value; -public class FileEditAction implements DataStoreActionProvider { +public class FileEditAction implements ActionProvider { - @Override - public Class getApplicableClass() { - return FileStore.class; - } + @Value + static class Action implements ActionProvider.Action { - @Override - public boolean isApplicable(FileStore o) throws Exception { - return o.getFlow().equals(DataFlow.INPUT_OUTPUT); - } + FileStore store; - @Override - public ObservableValue getName(FileStore store) { - return I18n.observable("base.editFile"); - } + @Override + public boolean requiresPlatform() { + return false; + } - @Override - public String getIcon(FileStore store) { - return "mdal-edit"; - } - - @Override - public void execute(FileStore store) throws Exception { - if (store.getFileSystem().equals(new LocalStore())) { - ExternalEditor.get().openInEditor(store.getFile()); - } else { - ExternalEditor.get() - .startEditing(store.getFileName(), store.getFileExtension(), store, () -> store.openInput(), () -> store.openOutput()); + @Override + public void execute() throws Exception { + if (store.getFileSystem().equals(new LocalStore())) { + ExternalEditor.get().openInEditor(store.getFile()); + } else { + ExternalEditor.get() + .startEditing(store.getFileName(), store.getFileExtension(), store, () -> store.openInput(), () -> store.openOutput()); + } } } + + @Override + public DataStoreCallSite getDataStoreCallSite() { + return new DataStoreCallSite() { + + @Override + public ActionProvider.Action createAction(FileStore store) { + return new Action(store); + } + + @Override + public Class getApplicableClass() { + return FileStore.class; + } + + @Override + public boolean isApplicable(FileStore o) throws Exception { + return o.getFlow().equals(DataFlow.INPUT_OUTPUT); + } + + @Override + public ObservableValue getName(FileStore store) { + return I18n.observable("base.editFile"); + } + + @Override + public String getIcon(FileStore store) { + return "mdal-edit"; + } + }; + } } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/actions/ShareStoreAction.java b/ext/base/src/main/java/io/xpipe/ext/base/actions/ShareStoreAction.java index d5c610a7..5d195b93 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/actions/ShareStoreAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/actions/ShareStoreAction.java @@ -3,52 +3,76 @@ package io.xpipe.ext.base.actions; import io.xpipe.app.core.AppActionLinkDetector; import io.xpipe.core.store.DataStore; import io.xpipe.core.util.SecretValue; -import io.xpipe.extension.DataStoreActionProvider; import io.xpipe.extension.DataStoreProviders; import io.xpipe.extension.I18n; +import io.xpipe.extension.util.ActionProvider; import javafx.beans.value.ObservableValue; +import lombok.Value; import java.awt.*; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.StringSelection; -public class ShareStoreAction implements DataStoreActionProvider { +public class ShareStoreAction implements ActionProvider { - @Override - public boolean showIfDisabled() { - return false; + @Value + static class Action implements ActionProvider.Action { + + DataStore store; + + @Override + public boolean requiresPlatform() { + return false; + } + + public static String create(DataStore store) { + return "xpipe://add/store/" + SecretValue.encrypt(store.toString()).getEncryptedValue(); + } + + @Override + public void execute() throws Exception { + var string = create(store); + var selection = new StringSelection(string); + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + AppActionLinkDetector.setLastDetectedAction(string); + clipboard.setContents(selection, selection); + } } @Override - public Class getApplicableClass() { - return DataStore.class; - } + public DataStoreCallSite getDataStoreCallSite() { + return new DataStoreCallSite() { - @Override - public boolean isApplicable(DataStore o) throws Exception { - return DataStoreProviders.byStore(o).isShareable(); - } - @Override - public ObservableValue getName(DataStore store) { - return I18n.observable("base.copyShareLink"); - } + @Override + public boolean showIfDisabled() { + return false; + } - @Override - public String getIcon(DataStore store) { - return "mdi2c-clipboard-list-outline"; - } + @Override + public ActionProvider.Action createAction(DataStore store) { + return new Action(store); + } - public static String create(DataStore store) { - return "xpipe://add/store/" + SecretValue.encrypt(store.toString()).getEncryptedValue(); - } + @Override + public Class getApplicableClass() { + return DataStore.class; + } - @Override - public void execute(DataStore store) throws Exception { - var string = create(store); - var selection = new StringSelection(string); - Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); - AppActionLinkDetector.setLastDetectedAction(string); - clipboard.setContents(selection, selection); + @Override + public boolean isApplicable(DataStore o) throws Exception { + return DataStoreProviders.byStore(o).isShareable(); + } + + @Override + public ObservableValue getName(DataStore store) { + return I18n.observable("base.copyShareLink"); + } + + @Override + public String getIcon(DataStore store) { + return "mdi2c-clipboard-list-outline"; + } + }; } } diff --git a/ext/base/src/main/java/io/xpipe/ext/base/actions/StreamExportAction.java b/ext/base/src/main/java/io/xpipe/ext/base/actions/StreamExportAction.java index 5eef2658..f939acc6 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/actions/StreamExportAction.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/actions/StreamExportAction.java @@ -1,58 +1,84 @@ package io.xpipe.ext.base.actions; import io.xpipe.core.store.StreamDataStore; -import io.xpipe.extension.DataStoreActionProvider; import io.xpipe.extension.I18n; import io.xpipe.extension.event.ErrorEvent; +import io.xpipe.extension.util.ActionProvider; import io.xpipe.extension.util.DesktopHelper; import io.xpipe.extension.util.ThreadHelper; import javafx.beans.value.ObservableValue; import javafx.stage.FileChooser; +import lombok.Value; import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Files; -public class StreamExportAction implements DataStoreActionProvider { - @Override - public Class getApplicableClass() { - return StreamDataStore.class; - } +public class StreamExportAction implements ActionProvider { - @Override - public boolean isApplicable(StreamDataStore o) throws Exception { - return o.getFlow() != null && o.getFlow().hasInput(); - } + @Value + static class Action implements ActionProvider.Action { - @Override - public ObservableValue getName(StreamDataStore store) { - return I18n.observable("base.exportStream"); - } + StreamDataStore store; - @Override - public String getIcon(StreamDataStore store) { - return "mdi2f-file-export-outline"; - } - - @Override - public void execute(StreamDataStore store) throws Exception { - FileChooser fileChooser = new FileChooser(); - fileChooser.setTitle(I18n.get("browseFileTitle")); - fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(I18n.get("anyFile"), ".")); - var outputFile = fileChooser.showSaveDialog(null); - if (outputFile == null) { - return; + @Override + public boolean requiresPlatform() { + return false; } - ThreadHelper.runAsync(() -> { - try (InputStream inputStream = store.openInput()) { - try (OutputStream outputStream = Files.newOutputStream(outputFile.toPath())) { - inputStream.transferTo(outputStream); - } - DesktopHelper.browseFileInDirectory(outputFile.toPath()); - } catch (Exception e) { - ErrorEvent.fromThrowable(e).handle(); + @Override + public void execute() throws Exception { + FileChooser fileChooser = new FileChooser(); + fileChooser.setTitle(I18n.get("browseFileTitle")); + fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(I18n.get("anyFile"), ".")); + var outputFile = fileChooser.showSaveDialog(null); + if (outputFile == null) { + return; } - }); + + ThreadHelper.runAsync(() -> { + try (InputStream inputStream = store.openInput()) { + try (OutputStream outputStream = Files.newOutputStream(outputFile.toPath())) { + inputStream.transferTo(outputStream); + } + DesktopHelper.browseFileInDirectory(outputFile.toPath()); + } catch (Exception e) { + ErrorEvent.fromThrowable(e).handle(); + } + }); + } + } + + @Override + public DataStoreCallSite getDataStoreCallSite() { + return new DataStoreCallSite() { + + @Override + public Action createAction(StreamDataStore store) { + return new Action(store); + } + + @Override + public boolean isApplicable(StreamDataStore o) throws Exception { + return o.getFlow() != null && o.getFlow().hasInput(); + } + + @Override + public Class getApplicableClass() { + return StreamDataStore.class; + } + + + @Override + public ObservableValue getName(StreamDataStore store) { + return I18n.observable("base.exportStream"); + } + + @Override + public String getIcon(StreamDataStore store) { + return "mdi2f-file-export-outline"; + } + + }; } } diff --git a/ext/base/src/main/java/module-info.java b/ext/base/src/main/java/module-info.java index e2b8f050..3b8ce660 100644 --- a/ext/base/src/main/java/module-info.java +++ b/ext/base/src/main/java/module-info.java @@ -2,7 +2,6 @@ import io.xpipe.ext.base.*; import io.xpipe.ext.base.actions.*; import io.xpipe.ext.base.apps.*; import io.xpipe.extension.DataSourceProvider; -import io.xpipe.extension.DataStoreActionProvider; import io.xpipe.extension.DataStoreProvider; import io.xpipe.extension.DataSourceTarget; import io.xpipe.extension.util.ActionProvider; @@ -22,8 +21,7 @@ open module io.xpipe.ext.base { requires static net.synedra.validatorfx; requires static io.xpipe.app; - provides ActionProvider with AddStoreAction; - provides DataStoreActionProvider with + provides ActionProvider with AddStoreAction, StreamExportAction, ShareStoreAction, FileBrowseAction, diff --git a/ext/proc/build.gradle b/ext/proc/build.gradle index 00c3d687..77dcba17 100644 --- a/ext/proc/build.gradle +++ b/ext/proc/build.gradle @@ -24,6 +24,7 @@ configurations { dependencies { compileOnly project(':app') testImplementation project(':app') + testImplementation project(':procx') testImplementation 'org.apache.commons:commons-lang3:3.12.0' implementation 'org.apache.commons:commons-exec:1.3' compileOnly group: 'com.dlsc.preferencesfx', name: 'preferencesfx-core', version: '11.15.0' diff --git a/ext/proc/src/main/java/io/xpipe/ext/proc/CommandControlImpl.java b/ext/proc/src/main/java/io/xpipe/ext/proc/CommandControlImpl.java index 9f3fe628..4f984239 100644 --- a/ext/proc/src/main/java/io/xpipe/ext/proc/CommandControlImpl.java +++ b/ext/proc/src/main/java/io/xpipe/ext/proc/CommandControlImpl.java @@ -4,6 +4,7 @@ import io.xpipe.core.process.CommandProcessControl; import io.xpipe.core.process.ProcessOutputException; import io.xpipe.core.process.ShellProcessControl; import io.xpipe.core.process.ShellType; +import io.xpipe.core.util.FailableFunction; import io.xpipe.extension.event.TrackEvent; import lombok.NonNull; @@ -16,7 +17,6 @@ import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; -import java.util.function.Function; public abstract class CommandControlImpl extends ProcessControlImpl implements CommandProcessControl { @@ -39,8 +39,8 @@ public abstract class CommandControlImpl extends ProcessControlImpl implements C protected final ShellProcessControl parent; @NonNull - protected final Function command; - protected final Function terminalCommand; + protected final FailableFunction command; + protected final FailableFunction terminalCommand; protected boolean elevated; protected int exitCode = -1; protected String timedOutError; @@ -50,8 +50,8 @@ public abstract class CommandControlImpl extends ProcessControlImpl implements C public CommandControlImpl( ShellProcessControl parent, - @NonNull Function command, - Function terminalCommand) { + @NonNull FailableFunction command, + FailableFunction terminalCommand) { this.command = command; this.parent = parent; this.terminalCommand = terminalCommand; diff --git a/ext/proc/src/main/java/io/xpipe/ext/proc/LocalCommandControlImpl.java b/ext/proc/src/main/java/io/xpipe/ext/proc/LocalCommandControlImpl.java index ad001e53..45010772 100644 --- a/ext/proc/src/main/java/io/xpipe/ext/proc/LocalCommandControlImpl.java +++ b/ext/proc/src/main/java/io/xpipe/ext/proc/LocalCommandControlImpl.java @@ -2,6 +2,7 @@ package io.xpipe.ext.proc; import io.xpipe.core.process.CommandProcessControl; import io.xpipe.core.process.ShellProcessControl; +import io.xpipe.core.util.FailableFunction; import io.xpipe.extension.util.ScriptHelper; import lombok.NonNull; @@ -17,8 +18,8 @@ public class LocalCommandControlImpl extends CommandControlImpl { public LocalCommandControlImpl( ShellProcessControl parent, - @NonNull Function command, - Function terminalCommand + @NonNull FailableFunction command, + FailableFunction terminalCommand ) { super(parent, command, terminalCommand); } diff --git a/ext/proc/src/main/java/io/xpipe/ext/proc/LocalShellControlImpl.java b/ext/proc/src/main/java/io/xpipe/ext/proc/LocalShellControlImpl.java index f0da5c6d..d955ac7f 100644 --- a/ext/proc/src/main/java/io/xpipe/ext/proc/LocalShellControlImpl.java +++ b/ext/proc/src/main/java/io/xpipe/ext/proc/LocalShellControlImpl.java @@ -2,6 +2,7 @@ package io.xpipe.ext.proc; import io.xpipe.core.process.ProcessControlProvider; import io.xpipe.core.process.*; +import io.xpipe.core.util.FailableFunction; import io.xpipe.extension.event.TrackEvent; import io.xpipe.extension.prefs.PrefsProvider; import io.xpipe.extension.util.ScriptHelper; @@ -14,7 +15,6 @@ import java.util.ArrayList; import java.util.List; import java.util.UUID; import java.util.concurrent.TimeUnit; -import java.util.function.Function; import java.util.function.Predicate; public class LocalShellControlImpl extends ShellControlImpl { @@ -25,7 +25,7 @@ public class LocalShellControlImpl extends ShellControlImpl { @Override public CommandProcessControl command( - Function command, Function terminalCommand) { + FailableFunction command, FailableFunction terminalCommand) { var control = ProcessControlProvider.createCommand(this, command, terminalCommand); if (control != null) { return control; diff --git a/ext/proc/src/main/java/io/xpipe/ext/proc/ProcProvider.java b/ext/proc/src/main/java/io/xpipe/ext/proc/ProcProvider.java index 15ebbca6..2df2a33c 100644 --- a/ext/proc/src/main/java/io/xpipe/ext/proc/ProcProvider.java +++ b/ext/proc/src/main/java/io/xpipe/ext/proc/ProcProvider.java @@ -1,27 +1,26 @@ package io.xpipe.ext.proc; -import io.xpipe.core.process.ProcessControlProvider; import io.xpipe.core.process.CommandProcessControl; +import io.xpipe.core.process.ProcessControlProvider; import io.xpipe.core.process.ShellProcessControl; +import io.xpipe.core.util.FailableBiFunction; +import io.xpipe.core.util.FailableFunction; import lombok.NonNull; -import java.util.function.BiFunction; -import java.util.function.Function; - public class ProcProvider extends ProcessControlProvider { @Override public ShellProcessControl sub( - ShellProcessControl parent, @NonNull Function commandFunction, - BiFunction terminalCommand + ShellProcessControl parent, @NonNull FailableFunction commandFunction, + FailableBiFunction terminalCommand ) { return null; } @Override public CommandProcessControl command( - ShellProcessControl parent, @NonNull Function command, - Function terminalCommand + ShellProcessControl parent, @NonNull FailableFunction command, + FailableFunction terminalCommand ) { return null; } diff --git a/ext/proc/src/main/java/io/xpipe/ext/proc/ShellControlImpl.java b/ext/proc/src/main/java/io/xpipe/ext/proc/ShellControlImpl.java index 7f9e0016..3dc0730b 100644 --- a/ext/proc/src/main/java/io/xpipe/ext/proc/ShellControlImpl.java +++ b/ext/proc/src/main/java/io/xpipe/ext/proc/ShellControlImpl.java @@ -1,22 +1,17 @@ package io.xpipe.ext.proc; -import io.xpipe.core.process.ProcessControlProvider; -import io.xpipe.core.process.CommandProcessControl; -import io.xpipe.core.process.OsType; -import io.xpipe.core.process.ShellProcessControl; -import io.xpipe.core.process.ShellType; +import io.xpipe.core.process.*; +import io.xpipe.core.util.FailableBiFunction; +import io.xpipe.core.util.FailableFunction; import io.xpipe.core.util.SecretValue; import io.xpipe.core.util.XPipeTempDirectory; import lombok.Getter; -import lombok.NonNull; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.UUID; -import java.util.function.BiFunction; import java.util.function.Consumer; -import java.util.function.Function; public abstract class ShellControlImpl extends ProcessControlImpl implements ShellProcessControl { @@ -78,19 +73,19 @@ public abstract class ShellControlImpl extends ProcessControlImpl implements She @Override public ShellProcessControl subShell( - @NonNull Function command, - BiFunction terminalCommand) { + FailableFunction command, + FailableBiFunction terminalCommand) { return ProcessControlProvider.createSub(this, command, terminalCommand); } @Override - public CommandProcessControl command(Function command) { + public CommandProcessControl command(FailableFunction command) { return command(command, command); } @Override public CommandProcessControl command( - Function command, Function terminalCommand) { + FailableFunction command, FailableFunction terminalCommand) { var control = ProcessControlProvider.createCommand(this, command, terminalCommand); return control; } diff --git a/ext/proc/src/main/java/io/xpipe/ext/proc/action/LaunchAction.java b/ext/proc/src/main/java/io/xpipe/ext/proc/action/LaunchAction.java index 61206e08..36c6669b 100644 --- a/ext/proc/src/main/java/io/xpipe/ext/proc/action/LaunchAction.java +++ b/ext/proc/src/main/java/io/xpipe/ext/proc/action/LaunchAction.java @@ -55,6 +55,11 @@ public class LaunchAction implements ActionProvider { public DataStoreCallSite getDataStoreCallSite() { return new DataStoreCallSite() { + @Override + public boolean showIfDisabled() { + return false; + } + @Override public boolean isApplicable(DataStore o) throws Exception { return o instanceof ShellStore; diff --git a/ext/proc/src/main/java/io/xpipe/ext/proc/augment/CmdCommandAugmentation.java b/ext/proc/src/main/java/io/xpipe/ext/proc/augment/CmdCommandAugmentation.java index 0f19d5d6..3b02641b 100644 --- a/ext/proc/src/main/java/io/xpipe/ext/proc/augment/CmdCommandAugmentation.java +++ b/ext/proc/src/main/java/io/xpipe/ext/proc/augment/CmdCommandAugmentation.java @@ -1,5 +1,7 @@ package io.xpipe.ext.proc.augment; +import io.xpipe.core.process.ShellProcessControl; + import java.util.List; public class CmdCommandAugmentation extends CommandAugmentation { @@ -9,7 +11,7 @@ public class CmdCommandAugmentation extends CommandAugmentation { } @Override - protected void prepareBaseCommand(List baseCommand) { + protected void prepareBaseCommand(ShellProcessControl processControl, List baseCommand) { remove(baseCommand, "/C"); } diff --git a/ext/proc/src/main/java/io/xpipe/ext/proc/augment/CommandAugmentation.java b/ext/proc/src/main/java/io/xpipe/ext/proc/augment/CommandAugmentation.java index e1d901c9..44d97657 100644 --- a/ext/proc/src/main/java/io/xpipe/ext/proc/augment/CommandAugmentation.java +++ b/ext/proc/src/main/java/io/xpipe/ext/proc/augment/CommandAugmentation.java @@ -10,6 +10,18 @@ public abstract class CommandAugmentation { private static final Set ALL = new HashSet<>(); + public static String unquote(String input) { + if (input.startsWith("\"") && input.endsWith("\"")) { + return input.substring(1, input.length() - 1); + } + + if (input.startsWith("'") && input.endsWith("'")) { + return input.substring(1, input.length() - 1); + } + + return input; + } + public static CommandAugmentation get(String cmd) { var parsed = CommandLine.parse(cmd); var executable = parsed.getExecutable().toLowerCase(Locale.ROOT).replaceAll("\\.exe$", ""); @@ -36,6 +48,16 @@ public abstract class CommandAugmentation { public abstract boolean matches(String executable); + protected Optional getParameter(List baseCommand, String... args) { + for (String arg : args) { + var index = baseCommand.indexOf(arg); + if (index != -1) { + return Optional.of(unquote(baseCommand.get(index + 1))); + } + } + return Optional.empty(); + } + protected void addIfNeeded(List baseCommand, String arg) { if (!baseCommand.contains(arg)) { baseCommand.add(1, arg); @@ -48,21 +70,21 @@ public abstract class CommandAugmentation { } } - public String prepareTerminalCommand(ShellProcessControl proc, String cmd, String subCommand) { + public String prepareTerminalCommand(ShellProcessControl proc, String cmd, String subCommand) throws Exception { var split = split(cmd); - prepareBaseCommand(split); + prepareBaseCommand(proc, split); modifyTerminalCommand(split, subCommand != null); return proc.getShellType().flatten(split) + (subCommand != null ? " " + subCommand : ""); } - public String prepareNonTerminalCommand(ShellProcessControl proc, String cmd) { + public String prepareNonTerminalCommand(ShellProcessControl proc, String cmd) throws Exception { var split = split(cmd); - prepareBaseCommand(split); + prepareBaseCommand(proc, split); modifyNonTerminalCommand(split); return proc.getShellType().flatten(split); } - protected abstract void prepareBaseCommand(List baseCommand); + protected abstract void prepareBaseCommand(ShellProcessControl processControl, List baseCommand) throws Exception; protected abstract void modifyTerminalCommand(List baseCommand, boolean hasSubCommand); diff --git a/ext/proc/src/main/java/io/xpipe/ext/proc/augment/NoCommandAugmentation.java b/ext/proc/src/main/java/io/xpipe/ext/proc/augment/NoCommandAugmentation.java index 55611c77..8770d1b5 100644 --- a/ext/proc/src/main/java/io/xpipe/ext/proc/augment/NoCommandAugmentation.java +++ b/ext/proc/src/main/java/io/xpipe/ext/proc/augment/NoCommandAugmentation.java @@ -1,5 +1,7 @@ package io.xpipe.ext.proc.augment; +import io.xpipe.core.process.ShellProcessControl; + import java.util.List; public class NoCommandAugmentation extends CommandAugmentation { @@ -10,7 +12,7 @@ public class NoCommandAugmentation extends CommandAugmentation { } @Override - protected void prepareBaseCommand(List baseCommand) {} + protected void prepareBaseCommand(ShellProcessControl processControl, List baseCommand) {} @Override protected void modifyTerminalCommand(List baseCommand, boolean hasSubCommand) {} diff --git a/ext/proc/src/main/java/io/xpipe/ext/proc/augment/PosixShellCommandAugmentation.java b/ext/proc/src/main/java/io/xpipe/ext/proc/augment/PosixShellCommandAugmentation.java index 2eaca8fa..b7469e45 100644 --- a/ext/proc/src/main/java/io/xpipe/ext/proc/augment/PosixShellCommandAugmentation.java +++ b/ext/proc/src/main/java/io/xpipe/ext/proc/augment/PosixShellCommandAugmentation.java @@ -1,5 +1,7 @@ package io.xpipe.ext.proc.augment; +import io.xpipe.core.process.ShellProcessControl; + import java.util.List; public class PosixShellCommandAugmentation extends CommandAugmentation { @@ -9,7 +11,7 @@ public class PosixShellCommandAugmentation extends CommandAugmentation { } @Override - protected void prepareBaseCommand(List baseCommand) { + protected void prepareBaseCommand(ShellProcessControl processControl, List baseCommand) { remove(baseCommand, "-l", "--login"); remove(baseCommand, "-i"); remove(baseCommand, "-c"); diff --git a/ext/proc/src/main/java/io/xpipe/ext/proc/augment/PowershellCommandAugmentation.java b/ext/proc/src/main/java/io/xpipe/ext/proc/augment/PowershellCommandAugmentation.java index 5910c066..ede893de 100644 --- a/ext/proc/src/main/java/io/xpipe/ext/proc/augment/PowershellCommandAugmentation.java +++ b/ext/proc/src/main/java/io/xpipe/ext/proc/augment/PowershellCommandAugmentation.java @@ -1,5 +1,7 @@ package io.xpipe.ext.proc.augment; +import io.xpipe.core.process.ShellProcessControl; + import java.util.List; public class PowershellCommandAugmentation extends CommandAugmentation { @@ -9,7 +11,7 @@ public class PowershellCommandAugmentation extends CommandAugmentation { } @Override - protected void prepareBaseCommand(List baseCommand) { + protected void prepareBaseCommand(ShellProcessControl processControl, List baseCommand) { remove(baseCommand, "-Command"); remove(baseCommand, "-NonInteractive"); } diff --git a/ext/proc/src/main/java/io/xpipe/ext/proc/augment/SshCommandAugmentation.java b/ext/proc/src/main/java/io/xpipe/ext/proc/augment/SshCommandAugmentation.java index f2fdb1ea..b821fa30 100644 --- a/ext/proc/src/main/java/io/xpipe/ext/proc/augment/SshCommandAugmentation.java +++ b/ext/proc/src/main/java/io/xpipe/ext/proc/augment/SshCommandAugmentation.java @@ -1,5 +1,8 @@ package io.xpipe.ext.proc.augment; +import io.xpipe.core.process.OsType; +import io.xpipe.core.process.ShellProcessControl; + import java.util.List; public class SshCommandAugmentation extends CommandAugmentation { @@ -10,7 +13,7 @@ public class SshCommandAugmentation extends CommandAugmentation { } @Override - protected void prepareBaseCommand(List baseCommand) { + protected void prepareBaseCommand(ShellProcessControl processControl, List baseCommand) throws Exception { baseCommand.removeIf(s -> s.equals("-T")); baseCommand.removeIf(s -> s.equals("-t")); baseCommand.removeIf(s -> s.equals("-tt")); @@ -18,6 +21,17 @@ public class SshCommandAugmentation extends CommandAugmentation { addIfNeeded(baseCommand, "-oStrictHostKeyChecking=no"); // addIfNeeded(baseCommand,"-oPasswordAuthentication=no"); + + // Ensure proper permissions for keys + var key = getParameter(baseCommand, "-i"); + if (key.isPresent() && (processControl.getOsType().equals(OsType.LINUX) || processControl.getOsType().equals(OsType.MACOS)) ){ + processControl.executeSimpleCommand("chmod 400 \"" + key.get() + "\""); + } + + // Start agent on windows + if (processControl.getOsType().equals(OsType.WINDOWS)) { + processControl.executeBooleanSimpleCommand("ssh-agent start"); + } } @Override diff --git a/ext/proc/src/main/java/module-info.java b/ext/proc/src/main/java/module-info.java index 980e3840..eae485bc 100644 --- a/ext/proc/src/main/java/module-info.java +++ b/ext/proc/src/main/java/module-info.java @@ -1,3 +1,4 @@ +import io.xpipe.app.util.TerminalProvider; import io.xpipe.core.process.ProcessControlProvider; import io.xpipe.ext.proc.*; import io.xpipe.ext.proc.action.InstallConnectorAction; @@ -21,12 +22,12 @@ open module io.xpipe.ext.proc { requires static javafx.controls; requires io.xpipe.core; requires com.fasterxml.jackson.databind; - requires static com.jcraft.jsch; requires static io.xpipe.extension; requires static io.xpipe.app; requires static commons.exec; requires static com.dlsc.preferencesfx; + provides TerminalProvider with TerminalProviderImpl; provides PrefsProvider with ProcPrefs; provides CommandAugmentation with diff --git a/ext/proc/src/test/java/test/CommandStoreTest.java b/ext/proc/src/test/java/test/CommandStoreTest.java index fce61d91..f551ec54 100644 --- a/ext/proc/src/test/java/test/CommandStoreTest.java +++ b/ext/proc/src/test/java/test/CommandStoreTest.java @@ -56,7 +56,7 @@ public class CommandStoreTest extends LocalExtensionTest { .elevation(SecretValue.encrypt("123")) .start()) { try (var command = pc.command(List.of("echo", "hi")).elevated().start()) { - var read = command.readOnlyStdout(); + var read = command.readOrThrow(); Assertions.assertEquals("hi", read); } } diff --git a/ext/proc/src/test/java/test/item/ShellCheckTestItem.java b/ext/proc/src/test/java/test/item/ShellCheckTestItem.java index 405f41cb..984fbc8b 100644 --- a/ext/proc/src/test/java/test/item/ShellCheckTestItem.java +++ b/ext/proc/src/test/java/test/item/ShellCheckTestItem.java @@ -2,7 +2,6 @@ package test.item; import io.xpipe.core.impl.FileNames; import io.xpipe.core.process.ShellProcessControl; -import io.xpipe.ext.proc.util.ShellHelper; import lombok.Getter; import org.apache.commons.lang3.function.FailableConsumer; import org.junit.jupiter.api.Assertions; @@ -13,7 +12,7 @@ import java.util.UUID; @Getter public enum ShellCheckTestItem { OS_NAME(shellProcessControl -> { - var os = ShellHelper.determineOsType(shellProcessControl); + var os = shellProcessControl.getOsType(); os.determineOperatingSystemName(shellProcessControl); }), @@ -101,7 +100,7 @@ public enum ShellCheckTestItem { }), ECHO(shellProcessControl -> { - ShellHelper.determineOsType(shellProcessControl); + shellProcessControl.executeSimpleCommand(shellProcessControl.getShellType().getEchoCommand("test", false)); }); private final FailableConsumer shellCheck; diff --git a/extension/src/main/java/io/xpipe/extension/DataStoreActionProvider.java b/extension/src/main/java/io/xpipe/extension/DataStoreActionProvider.java deleted file mode 100644 index 21ea4b82..00000000 --- a/extension/src/main/java/io/xpipe/extension/DataStoreActionProvider.java +++ /dev/null @@ -1,59 +0,0 @@ -package io.xpipe.extension; - -import io.xpipe.core.store.DataStore; -import io.xpipe.extension.event.ErrorEvent; -import javafx.beans.value.ObservableValue; -import javafx.scene.layout.Region; - -import java.util.ArrayList; -import java.util.List; -import java.util.ServiceLoader; - -public interface DataStoreActionProvider { - - static List> ALL = new ArrayList<>(); - - public static void init(ModuleLayer layer) { - if (ALL.size() == 0) { - ALL.addAll(ServiceLoader.load(layer, DataStoreActionProvider.class).stream() - .map(p -> (DataStoreActionProvider) p.get()) - .filter(provider -> { - try { - return provider.isActive(); - } catch (Throwable e) { - ErrorEvent.fromThrowable(e).handle(); - return false; - } - }) - .toList()); - } - } - - Class getApplicableClass(); - - default boolean isMajor() { - return false; - } - - default boolean isActive() throws Exception { - return true; - } - - default boolean isApplicable(T o) throws Exception { - return true; - } - - default void applyToRegion(T store, Region region) { - } - - ObservableValue getName(T store); - - String getIcon(T store); - - default void execute(T store) throws Exception { - } - - default boolean showIfDisabled() { - return true; - } -} diff --git a/extension/src/main/java/io/xpipe/extension/util/ScriptHelper.java b/extension/src/main/java/io/xpipe/extension/util/ScriptHelper.java index 3ab59a01..fbd55c96 100644 --- a/extension/src/main/java/io/xpipe/extension/util/ScriptHelper.java +++ b/extension/src/main/java/io/xpipe/extension/util/ScriptHelper.java @@ -9,6 +9,7 @@ import io.xpipe.core.util.SecretValue; import io.xpipe.extension.event.TrackEvent; import lombok.SneakyThrows; +import java.util.Arrays; import java.util.List; import java.util.Random; @@ -91,6 +92,18 @@ public class ScriptHelper { } "$@" """; + public static String unquote(String input) { + if (input.startsWith("\"") && input.endsWith("\"")) { + return input.substring(1, input.length() - 1); + } + + if (input.startsWith("'") && input.endsWith("'")) { + return input.substring(1, input.length() - 1); + } + + return input; + } + public static String constructOpenWithInitScriptCommand( ShellProcessControl processControl, List init, String toExecuteInShell) { ShellType t = processControl.getShellType(); @@ -98,6 +111,20 @@ public class ScriptHelper { return t.getNormalOpenCommand(); } + if (init.size() == 0) { + var cmd = unquote(toExecuteInShell); + + // Check for special case of the command to be executed just being another shell script + if (cmd.endsWith(".sh") || cmd.endsWith(".bat")) { + return t.executeCommandWithShell(cmd); + } + + // Check for special case of the command being a shell command + if (Arrays.stream(ShellTypes.getAllShellTypes()).anyMatch(shellType -> cmd.equals(shellType.getNormalOpenCommand()))) { + return cmd; + } + } + String nl = t.getNewLine().getNewLineString(); var content = String.join(nl, init) + nl; diff --git a/extension/src/main/java/module-info.java b/extension/src/main/java/module-info.java index 93e7d11b..3a89582e 100644 --- a/extension/src/main/java/module-info.java +++ b/extension/src/main/java/module-info.java @@ -1,6 +1,5 @@ import io.xpipe.core.util.ProxyFunction; import io.xpipe.extension.DataSourceProvider; -import io.xpipe.extension.DataStoreActionProvider; import io.xpipe.extension.DataSourceTarget; import io.xpipe.extension.prefs.PrefsProvider; import io.xpipe.extension.util.ActionProvider; @@ -45,7 +44,6 @@ open module io.xpipe.extension { uses DataSourceProvider; uses DataSourceTarget; - uses DataStoreActionProvider; uses io.xpipe.extension.I18n; uses io.xpipe.extension.event.EventHandler; uses io.xpipe.extension.prefs.PrefsProvider;