This commit is contained in:
crschnick 2023-05-02 18:55:35 +00:00
parent e0678aaf74
commit 78a51f5f52
29 changed files with 179 additions and 59 deletions

View file

@ -81,7 +81,7 @@ final class FileContextMenu extends ContextMenu {
ShellControl pc = model.getFileSystem().getShell().orElseThrow(); ShellControl pc = model.getFileSystem().getShell().orElseThrow();
var e = pc.getShellDialect().getMakeExecutableCommand(entry.getPath()); var e = pc.getShellDialect().getMakeExecutableCommand(entry.getPath());
if (e != null) { if (e != null) {
pc.executeBooleanSimpleCommand(e); pc.executeSimpleBooleanCommand(e);
} }
var cmd = pc.command("\"" + entry.getPath() + "\"").prepareTerminalOpen(); var cmd = pc.command("\"" + entry.getPath() + "\"").prepareTerminalOpen();
TerminalHelper.open(FilenameUtils.getBaseName(entry.getPath()), cmd); TerminalHelper.open(FilenameUtils.getBaseName(entry.getPath()), cmd);
@ -96,10 +96,10 @@ final class FileContextMenu extends ContextMenu {
ShellControl pc = model.getFileSystem().getShell().orElseThrow(); ShellControl pc = model.getFileSystem().getShell().orElseThrow();
var e = pc.getShellDialect().getMakeExecutableCommand(entry.getPath()); var e = pc.getShellDialect().getMakeExecutableCommand(entry.getPath());
if (e != null) { if (e != null) {
pc.executeBooleanSimpleCommand(e); pc.executeSimpleBooleanCommand(e);
} }
var cmd = ScriptHelper.createDetachCommand(pc, "\"" + entry.getPath() + "\""); var cmd = ScriptHelper.createDetachCommand(pc, "\"" + entry.getPath() + "\"");
pc.executeBooleanSimpleCommand(cmd); pc.executeSimpleBooleanCommand(cmd);
}); });
event.consume(); event.consume();
}); });

View file

@ -24,7 +24,7 @@ public class FileSystemHelper {
var current = !(model.getStore().getValue() instanceof LocalStore) var current = !(model.getStore().getValue() instanceof LocalStore)
? fileSystem ? fileSystem
.getShellControl() .getShellControl()
.executeStringSimpleCommand( .executeSimpleStringCommand(
fileSystem.getShellControl().getShellDialect().getPrintWorkingDirectoryCommand()) fileSystem.getShellControl().getShellDialect().getPrintWorkingDirectoryCommand())
: fileSystem : fileSystem
.getShell() .getShell()

View file

@ -275,7 +275,7 @@ final class OpenFileSystemModel {
BusyProperty.execute(busy, () -> { BusyProperty.execute(busy, () -> {
if (store.getValue() instanceof ShellStore s) { if (store.getValue() instanceof ShellStore s) {
var connection = ((ConnectionFileSystem) fileSystem).getShellControl(); var connection = ((ConnectionFileSystem) fileSystem).getShellControl();
var command = s.create() var command = s.control()
.initWith(connection.getShellDialect().getCdCommand(directory)) .initWith(connection.getShellDialect().getCdCommand(directory))
.prepareTerminalOpen(); .prepareTerminalOpen();
TerminalHelper.open(directory, command); TerminalHelper.open(directory, command);

View file

@ -44,7 +44,7 @@ public class BrowseDirectoryComp extends SimpleComp {
"launchDebugMode", "launchDebugMode",
new ButtonComp(AppI18n.observable("launchDebugMode"), () -> { new ButtonComp(AppI18n.observable("launchDebugMode"), () -> {
OperationMode.executeAfterShutdown(() -> { OperationMode.executeAfterShutdown(() -> {
try (var sc = ShellStore.createLocal().create().start()) { try (var sc = ShellStore.createLocal().control().start()) {
var script = FileNames.join( var script = FileNames.join(
XPipeInstallation.getCurrentInstallationBasePath() XPipeInstallation.getCurrentInstallationBasePath()
.toString(), .toString(),

View file

@ -45,7 +45,7 @@ public interface ActionProvider {
interface Action { interface Action {
boolean requiresPlatform(); boolean requiresJavaFXPlatform();
void execute() throws Exception; void execute() throws Exception;
} }

View file

@ -31,14 +31,14 @@ public abstract class LauncherInput {
} }
}); });
var requiresPlatform = all.stream().anyMatch(launcherInput -> launcherInput.requiresPlatform()); var requiresPlatform = all.stream().anyMatch(launcherInput -> launcherInput.requiresJavaFXPlatform());
if (requiresPlatform) { if (requiresPlatform) {
OperationMode.switchTo(OperationMode.GUI); OperationMode.switchTo(OperationMode.GUI);
} }
var hasGui = OperationMode.get() == OperationMode.GUI; var hasGui = OperationMode.get() == OperationMode.GUI;
all.forEach(launcherInput -> { all.forEach(launcherInput -> {
if (!hasGui && launcherInput.requiresPlatform()) { if (!hasGui && launcherInput.requiresJavaFXPlatform()) {
return; return;
} }
@ -118,7 +118,7 @@ public abstract class LauncherInput {
} }
@Override @Override
public boolean requiresPlatform() { public boolean requiresJavaFXPlatform() {
return true; return true;
} }
} }

View file

@ -77,7 +77,7 @@ public abstract class ExternalApplicationType implements PrefsChoiceValue {
public boolean isAvailable() { public boolean isAvailable() {
try (ShellControl pc = LocalStore.getShell()) { try (ShellControl pc = LocalStore.getShell()) {
return pc.executeBooleanSimpleCommand(pc.getShellDialect().getWhichCommand(executable)); return pc.executeSimpleBooleanCommand(pc.getShellDialect().getWhichCommand(executable));
} catch (Exception e) { } catch (Exception e) {
ErrorEvent.fromThrowable(e).omit().handle(); ErrorEvent.fromThrowable(e).omit().handle();
return false; return false;

View file

@ -332,7 +332,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
public boolean isAvailable() { public boolean isAvailable() {
try (ShellControl pc = LocalStore.getShell()) { try (ShellControl pc = LocalStore.getShell()) {
return pc.executeBooleanSimpleCommand(pc.getShellDialect().getWhichCommand(executable)); return pc.executeSimpleBooleanCommand(pc.getShellDialect().getWhichCommand(executable));
} catch (Exception e) { } catch (Exception e) {
ErrorEvent.fromThrowable(e).omit().handle(); ErrorEvent.fromThrowable(e).omit().handle();
return false; return false;

View file

@ -141,7 +141,7 @@ public class AppInstaller {
@Override @Override
public void installLocal(String file) throws Exception { public void installLocal(String file) throws Exception {
var shellProcessControl = ShellStore.createLocal().create().start(); var shellProcessControl = ShellStore.createLocal().control().start();
var exec = XPipeInstallation.getInstallationExecutable( var exec = XPipeInstallation.getInstallationExecutable(
shellProcessControl, shellProcessControl,
XPipeInstallation.getDefaultInstallationBasePath(shellProcessControl, false)); XPipeInstallation.getDefaultInstallationBasePath(shellProcessControl, false));
@ -187,7 +187,7 @@ public class AppInstaller {
@Override @Override
public void installLocal(String file) throws Exception { public void installLocal(String file) throws Exception {
var command = ShellStore.createLocal() var command = ShellStore.createLocal()
.create() .control()
.subShell(ShellDialects.BASH) .subShell(ShellDialects.BASH)
.command(String.format( .command(String.format(
""" """
@ -228,7 +228,7 @@ public class AppInstaller {
@Override @Override
public void installLocal(String file) throws Exception { public void installLocal(String file) throws Exception {
var command = ShellStore.createLocal().create().subShell(ShellDialects.BASH).command(String.format( var command = ShellStore.createLocal().control().subShell(ShellDialects.BASH).command(String.format(
""" """
function exec { function exec {
echo "+ sudo rpm -U -v --force \\"%s\\"" echo "+ sudo rpm -U -v --force \\"%s\\""
@ -266,7 +266,7 @@ public class AppInstaller {
@Override @Override
public void installLocal(String file) throws Exception { public void installLocal(String file) throws Exception {
var command = ShellStore.createLocal().create().subShell(ShellDialects.BASH).command(String.format( var command = ShellStore.createLocal().control().subShell(ShellDialects.BASH).command(String.format(
""" """
function exec { function exec {
echo "+ sudo installer -verboseR -allowUntrusted -pkg \\"%s\\" -target /" echo "+ sudo installer -verboseR -allowUntrusted -pkg \\"%s\\" -target /"

View file

@ -30,8 +30,8 @@ public class ChocoUpdater extends UpdateHandler {
} }
public AvailableRelease refreshUpdateCheckImpl() throws Exception { public AvailableRelease refreshUpdateCheckImpl() throws Exception {
try (var sc = ShellStore.createLocal().create().start()) { try (var sc = ShellStore.createLocal().control().start()) {
var latest = sc.executeStringSimpleCommand( var latest = sc.executeSimpleStringCommand(
"choco outdated -r --nocolor").lines().filter(s -> s.startsWith("xpipe")).findAny().orElseThrow().split("\\|")[2]; "choco outdated -r --nocolor").lines().filter(s -> s.startsWith("xpipe")).findAny().orElseThrow().split("\\|")[2];
var isUpdate = isUpdate(latest); var isUpdate = isUpdate(latest);
var rel = new AvailableRelease( var rel = new AvailableRelease(

View file

@ -35,7 +35,7 @@ public class XPipeInstanceHelper {
} }
public static boolean isSupported(ShellStore host) { public static boolean isSupported(ShellStore host) {
try (var pc = host.create().start(); try (var pc = host.control().start();
var cmd = pc.command(List.of("xpipe"))) { var cmd = pc.command(List.of("xpipe"))) {
cmd.discardOrThrow(); cmd.discardOrThrow();
return true; return true;

View file

@ -23,7 +23,7 @@ public class ApplicationHelper {
} }
public static boolean isInPath(ShellControl processControl, String executable) throws Exception { public static boolean isInPath(ShellControl processControl, String executable) throws Exception {
return processControl.executeBooleanSimpleCommand( return processControl.executeSimpleBooleanCommand(
processControl.getShellDialect().getWhichCommand(executable)); processControl.getShellDialect().getWhichCommand(executable));
} }

View file

@ -17,7 +17,7 @@ public class MacOsPermissions {
var state = new SimpleBooleanProperty(true); var state = new SimpleBooleanProperty(true);
try (var pc = LocalStore.getShell().start()) { try (var pc = LocalStore.getShell().start()) {
while (state.get()) { while (state.get()) {
var success = pc.executeBooleanSimpleCommand( var success = pc.executeSimpleBooleanCommand(
"osascript -e 'tell application \"System Events\" to keystroke \"t\"'"); "osascript -e 'tell application \"System Events\" to keystroke \"t\"'");
if (success) { if (success) {
Platform.runLater(() -> { Platform.runLater(() -> {

View file

@ -53,7 +53,7 @@ public class BeaconClient implements AutoCloseable {
} }
public static BeaconClient connectProxy(ShellStore proxy) throws Exception { public static BeaconClient connectProxy(ShellStore proxy) throws Exception {
var control = proxy.create().start(); var control = proxy.control().start();
if (!ProxyManagerProvider.get().setup(control)) { if (!ProxyManagerProvider.get().setup(control)) {
throw new IOException("X-Pipe connector required to perform operation"); throw new IOException("X-Pipe connector required to perform operation");
} }

View file

@ -36,7 +36,7 @@ public class LocalStore extends JacksonizedValue implements ShellStore {
@Override @Override
public FileSystem createFileSystem() { public FileSystem createFileSystem() {
return new ConnectionFileSystem(ShellStore.createLocal().create(), LocalStore.this) { return new ConnectionFileSystem(ShellStore.createLocal().control(), LocalStore.this) {
@Override @Override
public FileSystemStore getStore() { public FileSystemStore getStore() {
@ -128,7 +128,7 @@ public class LocalStore extends JacksonizedValue implements ShellStore {
} }
@Override @Override
public ShellControl createControl() { public ShellControl createBasicControl() {
return ProcessControlProvider.createLocal(true); return ProcessControlProvider.createLocal(true);
} }
} }

View file

@ -37,7 +37,7 @@ public interface OsType {
@Override @Override
public String getHomeDirectory(ShellControl pc) throws Exception { public String getHomeDirectory(ShellControl pc) throws Exception {
return pc.executeStringSimpleCommand( return pc.executeSimpleStringCommand(
pc.getShellDialect().getPrintEnvironmentVariableCommand("USERPROFILE")); pc.getShellDialect().getPrintEnvironmentVariableCommand("USERPROFILE"));
} }
@ -48,7 +48,7 @@ public interface OsType {
@Override @Override
public String getTempDirectory(ShellControl pc) throws Exception { public String getTempDirectory(ShellControl pc) throws Exception {
return pc.executeStringSimpleCommand(pc.getShellDialect().getPrintEnvironmentVariableCommand("TEMP")); return pc.executeSimpleStringCommand(pc.getShellDialect().getPrintEnvironmentVariableCommand("TEMP"));
} }
@Override @Override
@ -62,13 +62,13 @@ public interface OsType {
@Override @Override
public String determineOperatingSystemName(ShellControl pc) throws Exception { public String determineOperatingSystemName(ShellControl pc) throws Exception {
try { try {
return pc.executeStringSimpleCommand("wmic os get Caption") return pc.executeSimpleStringCommand("wmic os get Caption")
.lines() .lines()
.skip(1) .skip(1)
.collect(Collectors.joining()) .collect(Collectors.joining())
.trim() .trim()
+ " " + " "
+ pc.executeStringSimpleCommand("wmic os get Version") + pc.executeSimpleStringCommand("wmic os get Version")
.lines() .lines()
.skip(1) .skip(1)
.collect(Collectors.joining()) .collect(Collectors.joining())
@ -84,7 +84,7 @@ public interface OsType {
@Override @Override
public String getHomeDirectory(ShellControl pc) throws Exception { public String getHomeDirectory(ShellControl pc) throws Exception {
return pc.executeStringSimpleCommand(pc.getShellDialect().getPrintEnvironmentVariableCommand("HOME")); return pc.executeSimpleStringCommand(pc.getShellDialect().getPrintEnvironmentVariableCommand("HOME"));
} }
@Override @Override
@ -142,12 +142,12 @@ public interface OsType {
@Override @Override
public String getHomeDirectory(ShellControl pc) throws Exception { public String getHomeDirectory(ShellControl pc) throws Exception {
return pc.executeStringSimpleCommand(pc.getShellDialect().getPrintEnvironmentVariableCommand("HOME")); return pc.executeSimpleStringCommand(pc.getShellDialect().getPrintEnvironmentVariableCommand("HOME"));
} }
@Override @Override
public String getTempDirectory(ShellControl pc) throws Exception { public String getTempDirectory(ShellControl pc) throws Exception {
var found = pc.executeStringSimpleCommand(pc.getShellDialect().getPrintVariableCommand("TMPDIR")); var found = pc.executeSimpleStringCommand(pc.getShellDialect().getPrintVariableCommand("TMPDIR"));
// This variable is not defined for root users, so manually fix it. Why? ... // This variable is not defined for root users, so manually fix it. Why? ...
if (found.isBlank()) { if (found.isBlank()) {
@ -174,7 +174,7 @@ public interface OsType {
@Override @Override
public String determineOperatingSystemName(ShellControl pc) throws Exception { public String determineOperatingSystemName(ShellControl pc) throws Exception {
var properties = getProperties(pc); var properties = getProperties(pc);
var name = pc.executeStringSimpleCommand( var name = pc.executeSimpleStringCommand(
"awk '/SOFTWARE LICENSE AGREEMENT FOR macOS/' '/System/Library/CoreServices/Setup " "awk '/SOFTWARE LICENSE AGREEMENT FOR macOS/' '/System/Library/CoreServices/Setup "
+ "Assistant.app/Contents/Resources/en.lproj/OSXSoftwareLicense.rtf' | " + "Assistant.app/Contents/Resources/en.lproj/OSXSoftwareLicense.rtf' | "
+ "awk -F 'macOS ' '{print $NF}' | awk '{print substr($0, 0, length($0)-1)}'"); + "awk -F 'macOS ' '{print $NF}' | awk '{print substr($0, 0, length($0)-1)}'");

View file

@ -29,13 +29,13 @@ public interface ShellControl extends ProcessControl {
public void checkRunning() throws Exception; public void checkRunning() throws Exception;
default String executeStringSimpleCommand(String command) throws Exception { default String executeSimpleStringCommand(String command) throws Exception {
try (CommandControl c = command(command).start()) { try (CommandControl c = command(command).start()) {
return c.readOrThrow(); return c.readOrThrow();
} }
} }
default boolean executeBooleanSimpleCommand(String command) throws Exception { default boolean executeSimpleBooleanCommand(String command) throws Exception {
try (CommandControl c = command(command).start()) { try (CommandControl c = command(command).start()) {
return c.discardAndCheckExit(); return c.discardAndCheckExit();
} }
@ -55,9 +55,9 @@ public interface ShellControl extends ProcessControl {
} }
} }
default String executeStringSimpleCommand(ShellDialect type, String command) throws Exception { default String executeSimpleStringCommand(ShellDialect type, String command) throws Exception {
try (var sub = subShell(type).start()) { try (var sub = subShell(type).start()) {
return sub.executeStringSimpleCommand(command); return sub.executeSimpleStringCommand(command);
} }
} }

View file

@ -5,8 +5,8 @@ import io.xpipe.core.process.ShellControl;
public interface DelegateShellStore extends ShellStore { public interface DelegateShellStore extends ShellStore {
@Override @Override
default ShellControl createControl() { default ShellControl createBasicControl() {
return getDelegateHost().create(); return getDelegateHost().control();
} }
ShellStore getDelegateHost(); ShellStore getDelegateHost();

View file

@ -19,16 +19,16 @@ public interface ShellStore extends DataStore, StatefulDataStore, LaunchableStor
@Override @Override
default FileSystem createFileSystem() { default FileSystem createFileSystem() {
return new ConnectionFileSystem(create(), this); return new ConnectionFileSystem(control(), this);
} }
@Override @Override
default String prepareLaunchCommand() throws Exception { default String prepareLaunchCommand() throws Exception {
return create().prepareTerminalOpen(); return control().prepareTerminalOpen();
} }
default ShellControl create() { default ShellControl control() {
var pc = createControl(); var pc = createBasicControl();
pc.onInit(processControl -> { pc.onInit(processControl -> {
setState("type", processControl.getShellDialect()); setState("type", processControl.getShellDialect());
setState("os", processControl.getOsType()); setState("os", processControl.getOsType());
@ -49,21 +49,21 @@ public interface ShellStore extends DataStore, StatefulDataStore, LaunchableStor
return getState("charset", Charset.class, null); return getState("charset", Charset.class, null);
} }
ShellControl createControl(); ShellControl createBasicControl();
public default ShellDialect determineType() throws Exception { public default ShellDialect determineType() throws Exception {
try (var pc = create().start()) { try (var pc = control().start()) {
return pc.getShellDialect(); return pc.getShellDialect();
} }
} }
@Override @Override
default void validate() throws Exception { default void validate() throws Exception {
try (ShellControl pc = create().start()) {} try (ShellControl pc = control().start()) {}
} }
public default String queryMachineName() throws Exception { public default String queryMachineName() throws Exception {
try (var pc = create().start()) { try (var pc = control().start()) {
var operatingSystem = pc.getOsType(); var operatingSystem = pc.getOsType();
return operatingSystem.determineOperatingSystemName(pc); return operatingSystem.determineOperatingSystemName(pc);
} }

View file

@ -170,7 +170,7 @@ public class XPipeInstallation {
public static String getDataBasePath(ShellControl p) throws Exception { public static String getDataBasePath(ShellControl p) throws Exception {
if (p.getOsType().equals(OsType.WINDOWS)) { if (p.getOsType().equals(OsType.WINDOWS)) {
var base = p.executeStringSimpleCommand(p.getShellDialect().getPrintVariableCommand("userprofile")); var base = p.executeSimpleStringCommand(p.getShellDialect().getPrintVariableCommand("userprofile"));
return FileNames.join(base, ".xpipe"); return FileNames.join(base, ".xpipe");
} else { } else {
return FileNames.join("~", ".xpipe"); return FileNames.join("~", ".xpipe");
@ -222,7 +222,7 @@ public class XPipeInstallation {
public static String getDefaultInstallationBasePath(ShellControl p, boolean acceptPortable) public static String getDefaultInstallationBasePath(ShellControl p, boolean acceptPortable)
throws Exception { throws Exception {
if (acceptPortable) { if (acceptPortable) {
var customHome = p.executeStringSimpleCommand(p.getShellDialect().getPrintVariableCommand("XPIPE_HOME")); var customHome = p.executeSimpleStringCommand(p.getShellDialect().getPrintVariableCommand("XPIPE_HOME"));
if (!customHome.isEmpty()) { if (!customHome.isEmpty()) {
return customHome; return customHome;
} }
@ -230,7 +230,7 @@ public class XPipeInstallation {
String path = null; String path = null;
if (p.getOsType().equals(OsType.WINDOWS)) { if (p.getOsType().equals(OsType.WINDOWS)) {
var base = p.executeStringSimpleCommand(p.getShellDialect().getPrintVariableCommand("LOCALAPPDATA")); var base = p.executeSimpleStringCommand(p.getShellDialect().getPrintVariableCommand("LOCALAPPDATA"));
path = FileNames.join(base, "X-Pipe"); path = FileNames.join(base, "X-Pipe");
} else if (p.getOsType().equals(OsType.LINUX)) { } else if (p.getOsType().equals(OsType.LINUX)) {
path = "/opt/xpipe"; path = "/opt/xpipe";

View file

@ -22,7 +22,7 @@ public class XPipeTempDirectory {
"Unable to access or create temporary directory " + dir); "Unable to access or create temporary directory " + dir);
if (proc.getOsType().equals(OsType.LINUX) || proc.getOsType().equals(OsType.MACOS)) { if (proc.getOsType().equals(OsType.LINUX) || proc.getOsType().equals(OsType.MACOS)) {
proc.executeBooleanSimpleCommand("chmod 777 \"" + dir + "\""); proc.executeSimpleBooleanCommand("chmod 777 \"" + dir + "\"");
} }
} }
@ -31,7 +31,7 @@ public class XPipeTempDirectory {
public static void clearSubDirectory(ShellControl proc) throws Exception { public static void clearSubDirectory(ShellControl proc) throws Exception {
var dir = getSubDirectory(proc); var dir = getSubDirectory(proc);
if (!proc.executeBooleanSimpleCommand(proc.getShellDialect().getFileDeleteCommand(dir))) { if (!proc.executeSimpleBooleanCommand(proc.getShellDialect().getFileDeleteCommand(dir))) {
throw new IOException("Unable to delete temporary directory " + dir); throw new IOException("Unable to delete temporary directory " + dir);
} }
} }

View file

@ -18,7 +18,7 @@ public class AddStoreAction implements ActionProvider {
DataStore store; DataStore store;
@Override @Override
public boolean requiresPlatform() { public boolean requiresJavaFXPlatform() {
return true; return true;
} }

View file

@ -16,7 +16,7 @@ public class DeleteStoreChildrenAction implements ActionProvider {
DataStoreEntry store; DataStoreEntry store;
@Override @Override
public boolean requiresPlatform() { public boolean requiresJavaFXPlatform() {
return false; return false;
} }

View file

@ -17,7 +17,7 @@ public class EditStoreAction implements ActionProvider {
DataStoreEntry store; DataStoreEntry store;
@Override @Override
public boolean requiresPlatform() { public boolean requiresJavaFXPlatform() {
return true; return true;
} }

View file

@ -19,7 +19,7 @@ public class FileBrowseAction implements ActionProvider {
FileStore store; FileStore store;
@Override @Override
public boolean requiresPlatform() { public boolean requiresJavaFXPlatform() {
return false; return false;
} }

View file

@ -17,7 +17,7 @@ public class FileEditAction implements ActionProvider {
FileStore store; FileStore store;
@Override @Override
public boolean requiresPlatform() { public boolean requiresJavaFXPlatform() {
return false; return false;
} }

View file

@ -0,0 +1,120 @@
package io.xpipe.ext.base.actions;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.ext.ActionProvider;
import io.xpipe.app.storage.DataStorage;
import io.xpipe.app.storage.DataStoreEntry;
import io.xpipe.core.process.CommandControl;
import io.xpipe.core.process.ShellControl;
import io.xpipe.core.store.ShellStore;
import javafx.beans.value.ObservableValue;
import lombok.Value;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class SampleAction implements ActionProvider {
@Value
static class Action implements ActionProvider.Action {
DataStoreEntry entry;
@Override
public boolean requiresJavaFXPlatform() {
// Do we require the JavaFX platform to be running?
return false;
}
@Override
public void execute() throws Exception {
// Start a shell control from the shell connection store
try (ShellControl sc = ((ShellStore) entry.getStore()).control().start()) {
// Simple commands can be executed in one line
// The shell dialects also provide the proper command syntax for common commands like echo
String echoOut =
sc.executeSimpleStringCommand(sc.getShellDialect().getEchoCommand("hello!", false));
// You can also implement custom handling for more complex commands
try (CommandControl cc = sc.command("ls").start()) {
// Discard stderr
cc.discardErr();
// Read the stdout lines as a stream
BufferedReader reader = new BufferedReader(new InputStreamReader(cc.getStdout(), cc.getCharset()));
reader.lines().filter(s -> s != null).forEach(s -> {
System.out.println(s);
});
// Waits for command completion and returns exit code
if (cc.getExitCode() != 0) {
// Handle failure
}
}
// Commands can also be more complex and span multiple lines.
// In this case, X-Pipe will internally write a command to a script file and then execute the script
try (CommandControl cc = sc.command(
"""
VAR = "value"
echo "$VAR"
"""
).start()) {
var output = cc.readOrThrow();
}
// More customization options
// If the command should be run as root, the command will be executed with
// sudo and the optional sudo password automatically provided by X-Pipe.
// You can also set a custom working directory
try (CommandControl cc = sc.command("kill <pid>").elevated().workingDirectory("/").start()) {
// Discard any output but throw an exception the exit code is not 0
cc.discardOrThrow();
}
// Start a bash sub shell. Useful if the login shell is different
try (ShellControl bash = sc.subShell("bash").start()) {
// ...
}
}
}
}
@Override
public DataStoreCallSite<?> getDataStoreCallSite() {
// Call sites represent different ways of invoking the action.
// In this case, this represents a button that is shown for all stored shell connections.
return new DataStoreCallSite<ShellStore>() {
@Override
public Action createAction(ShellStore store) {
return new Action(DataStorage.get().getStoreEntry(store));
}
@Override
public Class<ShellStore> getApplicableClass() {
// For which general type of connection store to make this action available.
return ShellStore.class;
}
@Override
public boolean isApplicable(ShellStore o) throws Exception {
// Allows you to individually check whether this action should be available for the specific store.
// In this case it should only be available for remote shell connections, not local ones.
return !ShellStore.isLocal(o);
}
@Override
public ObservableValue<String> getName(ShellStore store) {
// The displayed name of the action, allows you to use translation keys.
return AppI18n.observable("installConnector");
}
@Override
public String getIcon(ShellStore store) {
// The ikonli icon of the button.
return "mdi2c-code-greater-than";
}
};
}
}

View file

@ -21,7 +21,7 @@ public class ShareStoreAction implements ActionProvider {
DataStore store; DataStore store;
@Override @Override
public boolean requiresPlatform() { public boolean requiresJavaFXPlatform() {
return false; return false;
} }

View file

@ -22,7 +22,7 @@ public class StreamExportAction implements ActionProvider {
StreamDataStore store; StreamDataStore store;
@Override @Override
public boolean requiresPlatform() { public boolean requiresJavaFXPlatform() {
return true; return true;
} }