mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-25 00:50:31 +00:00
Shell handling improvements
This commit is contained in:
parent
1230a22969
commit
ae2b7289cc
10 changed files with 40 additions and 123 deletions
|
@ -3,12 +3,16 @@ package io.xpipe.app.comp.about;
|
|||
import io.xpipe.app.comp.base.ButtonComp;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.core.AppLogs;
|
||||
import io.xpipe.app.core.mode.OperationMode;
|
||||
import io.xpipe.app.fxcomps.SimpleComp;
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import io.xpipe.app.issue.UserReportComp;
|
||||
import io.xpipe.app.util.DesktopHelper;
|
||||
import io.xpipe.app.util.DynamicOptionsBuilder;
|
||||
import io.xpipe.app.util.FileOpener;
|
||||
import io.xpipe.app.util.ScriptHelper;
|
||||
import io.xpipe.core.impl.FileNames;
|
||||
import io.xpipe.core.store.ShellStore;
|
||||
import io.xpipe.core.util.XPipeInstallation;
|
||||
import javafx.scene.layout.Region;
|
||||
|
||||
|
@ -37,8 +41,14 @@ public class BrowseDirectoryComp extends SimpleComp {
|
|||
}),
|
||||
null)
|
||||
.addComp(
|
||||
"logFiles",
|
||||
new ButtonComp(AppI18n.observable("openLogsDirectory"), () -> {
|
||||
"launchDebugMode",
|
||||
new ButtonComp(AppI18n.observable("launchDebugMode"), () -> {
|
||||
OperationMode.executeAfterShutdown(() -> {
|
||||
try (var sc = ShellStore.createLocal().create().start()) {
|
||||
var script = FileNames.join(XPipeInstallation.getCurrentInstallationBasePath().toString(), XPipeInstallation.getDaemonDebugScriptPath(sc.getOsType()));
|
||||
sc.executeSimpleCommand(ScriptHelper.createDetachCommand(sc, script));
|
||||
}
|
||||
});
|
||||
DesktopHelper.browsePath(AppLogs.get().getSessionLogsDirectory());
|
||||
}),
|
||||
null)
|
||||
|
|
|
@ -4,7 +4,6 @@ import io.xpipe.app.ext.PrefsChoiceValue;
|
|||
import io.xpipe.app.util.ApplicationHelper;
|
||||
import io.xpipe.app.util.WindowsRegistry;
|
||||
import io.xpipe.core.process.OsType;
|
||||
import io.xpipe.core.process.ShellDialects;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
@ -112,8 +111,7 @@ public interface ExternalEditorType extends PrefsChoiceValue {
|
|||
|
||||
@Override
|
||||
public void launch(Path file) throws IOException {
|
||||
var list = ShellDialects.getPlatformDefault().executeCommandListWithShell(executable + " \"" + file + "\"");
|
||||
new ProcessBuilder(list).start();
|
||||
new ProcessBuilder(List.of(executable, file.toString())).start();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -2,7 +2,6 @@ package io.xpipe.app.util;
|
|||
|
||||
import io.xpipe.app.issue.TrackEvent;
|
||||
import io.xpipe.core.impl.LocalStore;
|
||||
import io.xpipe.core.process.ShellDialects;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -11,7 +10,6 @@ import java.util.List;
|
|||
public class ApplicationHelper {
|
||||
|
||||
public static void executeLocalApplication(String s) throws Exception {
|
||||
var args = ShellDialects.getPlatformDefault().executeCommandListWithShell(s);
|
||||
TrackEvent.withDebug("proc", "Executing local application")
|
||||
.tag("command", s)
|
||||
.handle();
|
||||
|
|
|
@ -54,10 +54,8 @@ public class DesktopShortcuts {
|
|||
target);
|
||||
|
||||
try (var pc = LocalStore.getShell()) {
|
||||
pc.executeSimpleCommand(
|
||||
pc.getShellDialect().flatten(pc.getShellDialect().getMkdirsCommand(base + "/Contents/MacOS")));
|
||||
pc.executeSimpleCommand(
|
||||
pc.getShellDialect().flatten(pc.getShellDialect().getMkdirsCommand(base + "/Contents/Resources")));
|
||||
pc.executeSimpleCommand(pc.getShellDialect().getMkdirsCommand(base + "/Contents/MacOS"));
|
||||
pc.executeSimpleCommand(pc.getShellDialect().getMkdirsCommand(base + "/Contents/Resources"));
|
||||
|
||||
var executable = base + "/Contents/MacOS/" + name;
|
||||
pc.getShellDialect().createTextFileWriteCommand(pc, content, executable).execute();
|
||||
|
|
|
@ -4,9 +4,9 @@ import io.xpipe.app.issue.TrackEvent;
|
|||
import io.xpipe.core.impl.FileNames;
|
||||
import io.xpipe.core.impl.LocalStore;
|
||||
import io.xpipe.core.process.OsType;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
import io.xpipe.core.process.ShellDialect;
|
||||
import io.xpipe.core.process.ShellDialects;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
import io.xpipe.core.util.SecretValue;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
|
@ -15,16 +15,6 @@ import java.util.Random;
|
|||
|
||||
public class ScriptHelper {
|
||||
|
||||
public static String createDefaultOpenCommand(ShellControl pc, String file) {
|
||||
if (pc.getOsType().equals(OsType.WINDOWS)) {
|
||||
return "\"" + file + "\"";
|
||||
} else if (pc.getOsType().equals(OsType.LINUX)){
|
||||
return "xdg-open \"" + file + "\"";
|
||||
} else {
|
||||
return "open \"" + file + "\"";
|
||||
}
|
||||
}
|
||||
|
||||
public static String createDetachCommand(ShellControl pc, String command) {
|
||||
if (pc.getOsType().equals(OsType.WINDOWS)) {
|
||||
return "start \"\" " + command;
|
||||
|
@ -47,69 +37,6 @@ public class ScriptHelper {
|
|||
}
|
||||
}
|
||||
|
||||
private static final String ZSHI =
|
||||
"""
|
||||
#!/usr/bin/env zsh
|
||||
|
||||
emulate -L zsh -o no_unset
|
||||
|
||||
if (( ARGC == 0 )); then
|
||||
print -ru2 -- 'Usage: zshi <init-command> [zsh-flag]...
|
||||
The same as plain `zsh [zsh-flag]...` except that an additional
|
||||
<init-command> gets executed after all standard Zsh startup files
|
||||
have been sourced.'
|
||||
return 1
|
||||
fi
|
||||
|
||||
() {
|
||||
local init=$1
|
||||
shift
|
||||
local tmp
|
||||
{
|
||||
tmp=$(mktemp -d ${TMPDIR:-/tmp}/zsh.XXXXXXXXXX) || return
|
||||
local rc
|
||||
for rc in .zshenv .zprofile .zshrc .zlogin; do
|
||||
>$tmp/$rc <<<'{
|
||||
if (( ${+_zshi_global_rcs} )); then
|
||||
"builtin" "set" "-o" "global_rcs"
|
||||
"builtin" "unset" "_zshi_global_rcs"
|
||||
fi
|
||||
ZDOTDIR="$_zshi_zdotdir"
|
||||
# Not .zshenv because /etc/zshenv has already been read
|
||||
if [[ -o global_rcs && "'$rc'" != ".zshenv" && -f "/etc/'${rc:1}'" && -r "/etc/'${rc:1}'" ]]; then
|
||||
"builtin" "source" "--" "/etc/'${rc:1}'"
|
||||
fi
|
||||
if [[ -f "$ZDOTDIR/'$rc'" && -r "$ZDOTDIR/'$rc'" ]]; then
|
||||
"builtin" "source" "--" "$ZDOTDIR/'$rc'"
|
||||
fi
|
||||
} always {
|
||||
if [[ -o "no_rcs" ||
|
||||
-o "login" && "'$rc'" == ".zlogin" ||
|
||||
-o "no_login" && "'$rc'" == ".zshrc" ||
|
||||
-o "no_login" && -o "no_interactive" && "'$rc'" == ".zshenv" ]]; then
|
||||
if (( ${+_zshi_global_rcs} )); then
|
||||
set -o global_rcs
|
||||
fi
|
||||
"builtin" "unset" "_zshi_rcs" "_zshi_zdotdir"
|
||||
"builtin" "command" "rm" "-rf" "--" '${(q)tmp}'
|
||||
"builtin" "eval" '${(q)init}'
|
||||
else
|
||||
if [[ -o global_rcs ]]; then
|
||||
_zshi_global_rcs=
|
||||
fi
|
||||
set -o no_global_rcs
|
||||
_zshi_zdotdir=${ZDOTDIR:-~}
|
||||
ZDOTDIR='${(q)tmp}'
|
||||
fi
|
||||
}' || return
|
||||
done
|
||||
_zshi_zdotdir=${ZDOTDIR:-~} ZDOTDIR=$tmp zsh "$@"
|
||||
} always {
|
||||
[[ -e $tmp ]] && rm -rf -- $tmp
|
||||
}
|
||||
} "$@"
|
||||
""";
|
||||
|
||||
public static String unquote(String input) {
|
||||
if (input.startsWith("\"") && input.endsWith("\"")) {
|
||||
return input.substring(1, input.length() - 1);
|
||||
|
@ -122,33 +49,26 @@ public class ScriptHelper {
|
|||
return input;
|
||||
}
|
||||
|
||||
public static String constructOpenWithInitScriptCommand(
|
||||
public static String constructInitFile(
|
||||
ShellControl processControl, List<String> init, String toExecuteInShell) {
|
||||
ShellDialect t = processControl.getShellDialect();
|
||||
if (init.size() == 0 && toExecuteInShell == null) {
|
||||
return t.getNormalOpenCommand();
|
||||
return null;
|
||||
}
|
||||
|
||||
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 (ShellDialects.ALL.stream()
|
||||
.anyMatch(shellType -> cmd.equals(shellType.getNormalOpenCommand()))) {
|
||||
return cmd;
|
||||
if (toExecuteInShell.endsWith(".sh") || toExecuteInShell.endsWith(".bat")) {
|
||||
return toExecuteInShell;
|
||||
}
|
||||
}
|
||||
|
||||
String nl = t.getNewLine().getNewLineString();
|
||||
var content = String.join(nl, init) + nl;
|
||||
|
||||
if (t.equals(ShellDialects.BASH)) {
|
||||
content = "if [ -f ~/.bashrc ]; then . ~/.bashrc; fi\n" + content;
|
||||
var applyCommand = t.applyRcFileCommand();
|
||||
if (applyCommand != null) {
|
||||
content = applyCommand + "\n" + content;
|
||||
}
|
||||
|
||||
if (toExecuteInShell != null) {
|
||||
|
@ -158,13 +78,7 @@ public class ScriptHelper {
|
|||
}
|
||||
|
||||
var initFile = createExecScript(processControl, content);
|
||||
|
||||
if (t.equals(ShellDialects.ZSH)) {
|
||||
var zshiFile = createExecScript(processControl, ZSHI);
|
||||
return t.getNormalOpenCommand() + " \"" + zshiFile + "\" \"" + initFile + "\"";
|
||||
}
|
||||
|
||||
return t.getInitFileOpenCommand(initFile);
|
||||
return initFile;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
|
@ -218,7 +132,7 @@ public class ScriptHelper {
|
|||
}
|
||||
|
||||
private static String createAskPassScript(SecretValue pass, ShellControl parent, ShellDialect type) throws Exception {
|
||||
var content = type.getScriptEchoCommand(pass.getSecretValue());
|
||||
var content = type.getSelfdeleteScriptEchoCommand(pass.getSecretValue());
|
||||
var temp = parent.getTemporaryDirectory();
|
||||
var file = FileNames.join(temp, "askpass-" + getScriptId() + "." + type.getScriptFileEnding());
|
||||
return createExecScript(parent, file, content);
|
||||
|
|
|
@ -174,6 +174,7 @@ openCurrentLogFile=Open current log file
|
|||
openLogsDirectory=Open logs directory
|
||||
installationFiles=Installation Files
|
||||
openInstallationDirectory=Open installation directory
|
||||
launchDebugMode=Launch debug mode
|
||||
extensionInstallTitle=Download
|
||||
extensionInstallDescription=This action requires additional third party libraries that are not distributed by X-Pipe. You can automatically install them here. The components are then downloaded from the vendor website:
|
||||
extensionInstallLicenseNote=By performing the download and automatic installation you agree to the terms of the third party licenses:
|
||||
|
|
|
@ -13,6 +13,12 @@ import java.util.stream.Stream;
|
|||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
|
||||
public interface ShellDialect {
|
||||
|
||||
String argument(String s);
|
||||
|
||||
default String applyRcFileCommand() {
|
||||
return null;
|
||||
}
|
||||
|
||||
CommandControl createStreamFileWriteCommand(ShellControl shellControl, String file);
|
||||
|
||||
default String getCdCommand(String directory){
|
||||
|
@ -53,8 +59,6 @@ public interface ShellDialect {
|
|||
return "exit";
|
||||
}
|
||||
|
||||
String getExitCodeVariable();
|
||||
|
||||
String environmentVariable(String name);
|
||||
|
||||
default String getConcatenationOperator() {
|
||||
|
@ -67,7 +71,7 @@ public interface ShellDialect {
|
|||
|
||||
String getMakeExecutableCommand(String file);
|
||||
|
||||
default String getScriptEchoCommand(String s) {
|
||||
default String getSelfdeleteScriptEchoCommand(String s) {
|
||||
return getEchoCommand(s, false);
|
||||
}
|
||||
|
||||
|
@ -85,15 +89,11 @@ public interface ShellDialect {
|
|||
|
||||
String getNormalOpenCommand();
|
||||
|
||||
String getInitFileOpenCommand(String file);
|
||||
String prepareInitFileOpenCommand(ShellControl parent, String file);
|
||||
|
||||
String executeCommandWithShell(String cmd);
|
||||
|
||||
List<String> executeCommandListWithShell(String cmd);
|
||||
|
||||
List<String> executeCommandListWithShell(List<String> cmd);
|
||||
|
||||
List<String> getMkdirsCommand(String dirs);
|
||||
String getMkdirsCommand(String dirs);
|
||||
|
||||
String getFileReadCommand(String file);
|
||||
|
||||
|
@ -121,7 +121,5 @@ public interface ShellDialect {
|
|||
|
||||
String getDisplayName();
|
||||
|
||||
String getExecutable();
|
||||
|
||||
boolean doesRepeatInput();
|
||||
boolean doesEchoInput();
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ public class ShellDialects {
|
|||
public static ShellDialect POWERSHELL;
|
||||
public static ShellDialect CMD;
|
||||
public static ShellDialect SH;
|
||||
public static ShellDialect DASH;
|
||||
public static ShellDialect BASH;
|
||||
public static ShellDialect ZSH;
|
||||
|
||||
|
@ -26,6 +27,7 @@ public class ShellDialects {
|
|||
CMD = byName("cmd");
|
||||
POWERSHELL = byName("powershell");
|
||||
SH = byName("sh");
|
||||
DASH = byName("dash");
|
||||
BASH = byName("bash");
|
||||
ZSH = byName("zsh");
|
||||
}
|
||||
|
|
|
@ -107,8 +107,7 @@ public class ConnectionFileSystem implements FileSystem {
|
|||
@Override
|
||||
public boolean mkdirs(String file) throws Exception {
|
||||
try (var pc = shellControl.command(proc -> proc.getShellDialect()
|
||||
.flatten(proc.getShellDialect()
|
||||
.getMkdirsCommand(proc.getOsType().normalizeFileName(file))))
|
||||
.getMkdirsCommand(proc.getOsType().normalizeFileName(file)))
|
||||
.start()) {
|
||||
return pc.discardAndCheckExit();
|
||||
}
|
||||
|
|
|
@ -24,8 +24,7 @@ public class XPipeTempDirectory {
|
|||
var dir = FileNames.join(base, "xpipe");
|
||||
|
||||
if (!proc.executeBooleanSimpleCommand(proc.getShellDialect().getFileExistsCommand(dir))) {
|
||||
proc.executeSimpleCommand(
|
||||
proc.getShellDialect().flatten(proc.getShellDialect().getMkdirsCommand(dir)),
|
||||
proc.executeSimpleCommand(proc.getShellDialect().getMkdirsCommand(dir),
|
||||
"Unable to access or create temporary directory " + dir);
|
||||
|
||||
if (proc.getOsType().equals(OsType.LINUX) || proc.getOsType().equals(OsType.MACOS)) {
|
||||
|
|
Loading…
Reference in a new issue