Shell handling improvements

This commit is contained in:
crschnick 2023-03-17 04:52:57 +00:00
parent 1230a22969
commit ae2b7289cc
10 changed files with 40 additions and 123 deletions

View file

@ -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)

View file

@ -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

View file

@ -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();

View file

@ -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();

View file

@ -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);

View file

@ -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:

View file

@ -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();
}

View file

@ -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");
}

View file

@ -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();
}

View file

@ -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)) {