diff --git a/app/src/main/java/io/xpipe/app/prefs/TroubleshootCategory.java b/app/src/main/java/io/xpipe/app/prefs/TroubleshootCategory.java index 08714fce7..867c26be6 100644 --- a/app/src/main/java/io/xpipe/app/prefs/TroubleshootCategory.java +++ b/app/src/main/java/io/xpipe/app/prefs/TroubleshootCategory.java @@ -60,6 +60,7 @@ public class TroubleshootCategory extends AppPrefsCategory { "openCurrentLogFileDescription", "mdmz-text_snippet", e -> { + AppLogs.get().flush(); FileOpener.openInTextEditor(AppLogs.get() .getSessionLogsDirectory() .resolve("xpipe.log") diff --git a/app/src/main/java/io/xpipe/app/terminal/ExternalTerminalType.java b/app/src/main/java/io/xpipe/app/terminal/ExternalTerminalType.java index 2523f8cb9..3b388ec48 100644 --- a/app/src/main/java/io/xpipe/app/terminal/ExternalTerminalType.java +++ b/app/src/main/java/io/xpipe/app/terminal/ExternalTerminalType.java @@ -10,6 +10,7 @@ import io.xpipe.app.util.LocalShell; import io.xpipe.app.util.MacOsPermissions; import io.xpipe.app.util.WindowsRegistry; import io.xpipe.core.process.*; +import io.xpipe.core.store.FilePath; import lombok.Getter; import lombok.Value; import lombok.With; @@ -131,7 +132,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue { .add("-e") .add("cmd") .add("/c") - .addQuoted(configuration.getScriptFile().replaceAll(" ", "^$0")); + .addQuoted(configuration.getScriptFile().toString().replaceAll(" ", "^$0")); } }; ExternalTerminalType TABBY_WINDOWS = new WindowsType("app.tabby", "Tabby") { @@ -311,28 +312,12 @@ public interface ExternalTerminalType extends PrefsChoiceValue { protected CommandBuilder toCommand(LaunchConfiguration configuration) { return CommandBuilder.of() .add("-e") - .addQuoted(configuration.getScriptFile()) + .addFile(configuration.getScriptFile()) .add("-T") .addQuoted(configuration.getColoredTitle()) .add("--new-tab"); } }; - ExternalTerminalType KITTY_LINUX = new SimplePathType("app.kitty", "kitty") { - - @Override - public boolean supportsTabs() { - return false; - } - - @Override - protected CommandBuilder toCommand(LaunchConfiguration configuration) { - return CommandBuilder.of() - .add("-1") - .add("-T") - .addQuoted(configuration.getColoredTitle()) - .addQuoted(configuration.getScriptFile()); - } - }; ExternalTerminalType TERMINOLOGY = new SimplePathType("app.terminology", "terminology") { @Override @@ -347,7 +332,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue { .addQuoted(configuration.getColoredTitle()) .add("-2") .add("-e") - .addQuoted(configuration.getScriptFile()); + .addFile(configuration.getScriptFile()); } }; ExternalTerminalType COOL_RETRO_TERM = new SimplePathType("app.coolRetroTerm", "cool-retro-term") { @@ -363,7 +348,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue { .add("-T") .addQuoted(configuration.getColoredTitle()) .add("-e") - .addQuoted(configuration.getScriptFile()); + .addFile(configuration.getScriptFile()); } }; ExternalTerminalType GUAKE = new SimplePathType("app.guake", "guake") { @@ -380,7 +365,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue { .add("-r") .addQuoted(configuration.getColoredTitle()) .add("-e") - .addQuoted(configuration.getScriptFile()); + .addFile(configuration.getScriptFile()); } }; ExternalTerminalType ALACRITTY_LINUX = new SimplePathType("app.alacritty", "alacritty") { @@ -401,7 +386,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue { .add("-t") .addQuoted(configuration.getCleanTitle()) .add("-e") - .addQuoted(configuration.getScriptFile()); + .addFile(configuration.getScriptFile()); } }; ExternalTerminalType TILDA = new SimplePathType("app.tilda", "tilda") { @@ -413,7 +398,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue { @Override protected CommandBuilder toCommand(LaunchConfiguration configuration) { - return CommandBuilder.of().add("-c").addQuoted(configuration.getScriptFile()); + return CommandBuilder.of().add("-c").addFile(configuration.getScriptFile()); } }; ExternalTerminalType XTERM = new SimplePathType("app.xterm", "xterm") { @@ -429,7 +414,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue { .add("-title") .addQuoted(configuration.getColoredTitle()) .add("-e") - .addQuoted(configuration.getScriptFile()); + .addFile(configuration.getScriptFile()); } }; ExternalTerminalType DEEPIN_TERMINAL = new SimplePathType("app.deepinTerminal", "deepin-terminal") { @@ -441,7 +426,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue { @Override protected CommandBuilder toCommand(LaunchConfiguration configuration) { - return CommandBuilder.of().add("-C").addQuoted(configuration.getScriptFile()); + return CommandBuilder.of().add("-C").addFile(configuration.getScriptFile()); } }; ExternalTerminalType Q_TERMINAL = new SimplePathType("app.qTerminal", "qterminal") { @@ -465,7 +450,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue { @Override public void launch(LaunchConfiguration configuration) throws Exception { try (ShellControl pc = LocalShell.getShell()) { - var suffix = "\"" + configuration.getScriptFile().replaceAll("\"", "\\\\\"") + "\""; + var suffix = "\"" + configuration.getScriptFile().toString().replaceAll("\"", "\\\\\"") + "\""; pc.osascriptCommand(String.format( """ activate application "Terminal" @@ -508,7 +493,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue { create window with default profile command "%s" end tell """, - a, a, a, a, configuration.getScriptFile().replaceAll("\"", "\\\\\""))) + a, a, a, a, configuration.getScriptFile().toString().replaceAll("\"", "\\\\\""))) .execute(); } } @@ -633,7 +618,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue { end tell end tell """, - configuration.getScriptFile().replaceAll("\"", "\\\\\""))) + configuration.getScriptFile().toString().replaceAll("\"", "\\\\\""))) .execute(); } } @@ -656,7 +641,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue { GNOME_TERMINAL, TILIX, TERMINATOR, - KITTY_LINUX, + KittyTerminalType.KITTY_LINUX, TERMINOLOGY, COOL_RETRO_TERM, GUAKE, @@ -747,12 +732,12 @@ public interface ExternalTerminalType extends PrefsChoiceValue { String cleanTitle; @With - String scriptFile; + FilePath scriptFile; ShellDialect scriptDialect; public CommandBuilder getDialectLaunchCommand() { - var open = scriptDialect.getOpenScriptCommand(scriptFile); + var open = scriptDialect.getOpenScriptCommand(scriptFile.toString()); return open; } @@ -783,7 +768,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue { var format = custom.toLowerCase(Locale.ROOT).contains("$cmd") ? custom : custom + " $CMD"; try (var pc = LocalShell.getShell()) { - var toExecute = ApplicationHelper.replaceFileArgument(format, "CMD", configuration.getScriptFile()); + var toExecute = ApplicationHelper.replaceFileArgument(format, "CMD", configuration.getScriptFile().toString()); // We can't be sure whether the command is blocking or not, so always make it not blocking if (pc.getOsType().equals(OsType.WINDOWS)) { toExecute = "start \"" + configuration.getCleanTitle() + "\" " + toExecute; diff --git a/app/src/main/java/io/xpipe/app/terminal/KittyTerminalType.java b/app/src/main/java/io/xpipe/app/terminal/KittyTerminalType.java new file mode 100644 index 000000000..2fe552e87 --- /dev/null +++ b/app/src/main/java/io/xpipe/app/terminal/KittyTerminalType.java @@ -0,0 +1,66 @@ +package io.xpipe.app.terminal; + +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import io.xpipe.app.util.LocalShell; +import io.xpipe.core.process.CommandBuilder; +import io.xpipe.core.store.FilePath; +import io.xpipe.core.util.XPipeInstallation; + +public class KittyTerminalType { + + public static final ExternalTerminalType KITTY_LINUX = new ExternalTerminalType() { + + @Override + public String getId() { + return "app.tabby"; + } + + @Override + public boolean supportsTabs() { + return true; + } + + @Override + public void launch(LaunchConfiguration configuration) throws Exception { + launchInstanceIfNeeded(); + open(configuration); + } + }; + + private static FilePath getSocket() throws Exception { + try (var sc = LocalShell.getShell().start()) { + var temp = sc.getSystemTemporaryDirectory(); + return temp.join("xpipe_kitty"); + } + } + + private static void launchInstanceIfNeeded() throws Exception { + var socket = getSocket(); + try (var sc = LocalShell.getShell().start()) { + if (sc.getShellDialect().createFileExistsCommand(sc,socket.toString()).executeAndCheck()) { + return; + } + + sc.executeSimpleCommand(CommandBuilder.of().add("kitty").add("-o", "allow_remote_control=socket-only", "--listen-on", "unix:" + getSocket(), "--detach")); + } + } + + private static void open(ExternalTerminalType.LaunchConfiguration configuration) throws Exception { + try (var sc = LocalShell.getShell().start()) { + var payload = JsonNodeFactory.instance.objectNode(); + payload.put("args", configuration.getDialectLaunchCommand().buildString(sc)); + payload.put("tab_title",configuration.getColoredTitle()); + payload.put("type", "tab"); + payload.put("logo_alpha", 0.01); + payload.put("logo", XPipeInstallation.getLocalDefaultInstallationIcon().toString()); + + var json = JsonNodeFactory.instance.objectNode(); + json.put("cmd", "launch"); + json.set("payload", payload); + var jsonString = json.toString(); + var echoString = "'\\eP@kitty-cmd" + jsonString + "\\e\\\\'"; + + sc.executeSimpleCommand(CommandBuilder.of().add("echo", "-en", echoString, "|", "socat", "-").addFile(getSocket())); + } + } +} diff --git a/app/src/main/java/io/xpipe/app/terminal/WindowsTerminalType.java b/app/src/main/java/io/xpipe/app/terminal/WindowsTerminalType.java index d9845321e..037211a02 100644 --- a/app/src/main/java/io/xpipe/app/terminal/WindowsTerminalType.java +++ b/app/src/main/java/io/xpipe/app/terminal/WindowsTerminalType.java @@ -75,7 +75,7 @@ public class WindowsTerminalType { ? CommandBuilder.of().addFile(configuration.getScriptFile()) : CommandBuilder.of() .add("powershell", "-ExecutionPolicy", "Bypass", "-File") - .addQuoted(configuration.getScriptFile()); + .addFile(configuration.getScriptFile()); var cmd = CommandBuilder.of().add("-w", "1", "nt"); if (configuration.getColor() != null) { diff --git a/app/src/main/java/io/xpipe/app/util/ApplicationHelper.java b/app/src/main/java/io/xpipe/app/util/ApplicationHelper.java index a1fb94efc..de685092b 100644 --- a/app/src/main/java/io/xpipe/app/util/ApplicationHelper.java +++ b/app/src/main/java/io/xpipe/app/util/ApplicationHelper.java @@ -42,7 +42,7 @@ public class ApplicationHelper { return String.format( "Start-Process -FilePath %s -ArgumentList \"-NoProfile\", \"-File\", %s", pc.getShellDialect().getExecutableName(), - pc.getShellDialect().fileArgument(script)); + pc.getShellDialect().fileArgument(script.toString())); } if (pc.getOsType().equals(OsType.WINDOWS)) { diff --git a/app/src/main/java/io/xpipe/app/util/ScriptHelper.java b/app/src/main/java/io/xpipe/app/util/ScriptHelper.java index d5931d884..4318f18bb 100644 --- a/app/src/main/java/io/xpipe/app/util/ScriptHelper.java +++ b/app/src/main/java/io/xpipe/app/util/ScriptHelper.java @@ -2,7 +2,7 @@ package io.xpipe.app.util; import io.xpipe.app.issue.TrackEvent; import io.xpipe.core.process.*; -import io.xpipe.core.store.FileNames; +import io.xpipe.core.store.FilePath; import io.xpipe.core.util.FailableFunction; import io.xpipe.core.util.SecretValue; import lombok.SneakyThrows; @@ -21,13 +21,13 @@ public class ScriptHelper { } @SneakyThrows - public static String createLocalExecScript(String content) { + public static FilePath createLocalExecScript(String content) { try (var l = LocalShell.getShell().start()) { return createExecScript(l, content); } } - public static String constructTerminalInitFile( + public static FilePath constructTerminalInitFile( ShellDialect t, ShellControl processControl, FailableFunction workingDirectory, @@ -74,37 +74,37 @@ public class ScriptHelper { content += nl + t.getPassthroughExitCommand() + nl; } - return createExecScript(t, processControl, t.initFileName(processControl), content); + return createExecScript(t, processControl, new FilePath(t.initFileName(processControl)), content); } @SneakyThrows - public static String getExecScriptFile(ShellControl processControl) { + public static FilePath getExecScriptFile(ShellControl processControl) { return getExecScriptFile( processControl, processControl.getShellDialect().getScriptFileEnding()); } @SneakyThrows - public static String getExecScriptFile(ShellControl processControl, String fileEnding) { + public static FilePath getExecScriptFile(ShellControl processControl, String fileEnding) { var fileName = "exec-" + getScriptId(); var temp = processControl.getSystemTemporaryDirectory(); - return FileNames.join(temp, fileName + "." + fileEnding); + return temp.join(fileName + "." + fileEnding); } @SneakyThrows - public static String createExecScript(ShellControl processControl, String content) { + public static FilePath createExecScript(ShellControl processControl, String content) { return createExecScript(processControl.getShellDialect(), processControl, content); } @SneakyThrows - public static String createExecScript(ShellDialect type, ShellControl processControl, String content) { + public static FilePath createExecScript(ShellDialect type, ShellControl processControl, String content) { var fileName = "exec-" + getScriptId(); var temp = processControl.getSystemTemporaryDirectory(); - var file = FileNames.join(temp, fileName + "." + type.getScriptFileEnding()); + var file = temp.join(fileName + "." + type.getScriptFileEnding()); return createExecScript(type, processControl, file, content); } @SneakyThrows - public static String createExecScript(ShellDialect type, ShellControl processControl, String file, String content) { + public static FilePath createExecScript(ShellDialect type, ShellControl processControl, FilePath file, String content) { content = type.prepareScriptContent(content); TrackEvent.withTrace("Writing exec script") @@ -114,12 +114,12 @@ public class ScriptHelper { processControl .getShellDialect() - .createScriptTextFileWriteCommand(processControl, content, file) + .createScriptTextFileWriteCommand(processControl, content, file.toString()) .execute(); return file; } - public static String createRemoteAskpassScript(ShellControl parent, UUID requestId, String prefix) + public static FilePath createRemoteAskpassScript(ShellControl parent, UUID requestId, String prefix) throws Exception { var type = parent.getShellDialect(); @@ -130,7 +130,7 @@ public class ScriptHelper { var fileName = "exec-" + getScriptId() + "." + type.getScriptFileEnding(); var temp = parent.getSystemTemporaryDirectory(); - var file = FileNames.join(temp, fileName); + var file = temp.join(fileName); if (type != parent.getShellDialect()) { try (var sub = parent.subShell(type).start()) { var content = @@ -144,12 +144,12 @@ public class ScriptHelper { } } - public static String createTerminalPreparedAskpassScript( + public static FilePath createTerminalPreparedAskpassScript( SecretValue pass, ShellControl parent, boolean forceExecutable) throws Exception { return createTerminalPreparedAskpassScript(pass != null ? List.of(pass) : List.of(), parent, forceExecutable); } - public static String createTerminalPreparedAskpassScript( + public static FilePath createTerminalPreparedAskpassScript( List pass, ShellControl parent, boolean forceExecutable) throws Exception { var scriptType = parent.getShellDialect(); @@ -161,18 +161,18 @@ public class ScriptHelper { return createTerminalPreparedAskpassScript(pass, parent, scriptType); } - private static String createTerminalPreparedAskpassScript( + private static FilePath createTerminalPreparedAskpassScript( List pass, ShellControl parent, ShellDialect type) throws Exception { var fileName = "exec-" + getScriptId() + "." + type.getScriptFileEnding(); var temp = parent.getSystemTemporaryDirectory(); - var file = FileNames.join(temp, fileName); + var file = temp.join(fileName); if (type != parent.getShellDialect()) { try (var sub = parent.subShell(type).start()) { var content = sub.getShellDialect() .getAskpass() .prepareFixedContent( sub, - file, + file.toString(), pass.stream() .map(secretValue -> secretValue.getSecretValue()) .toList()); @@ -183,7 +183,7 @@ public class ScriptHelper { .getAskpass() .prepareFixedContent( parent, - file, + file.toString(), pass.stream() .map(secretValue -> secretValue.getSecretValue()) .toList()); diff --git a/app/src/main/java/io/xpipe/app/util/ShellTemp.java b/app/src/main/java/io/xpipe/app/util/ShellTemp.java index ba78ac4c6..0cf01faa2 100644 --- a/app/src/main/java/io/xpipe/app/util/ShellTemp.java +++ b/app/src/main/java/io/xpipe/app/util/ShellTemp.java @@ -4,6 +4,7 @@ import io.xpipe.app.issue.ErrorEvent; import io.xpipe.core.process.OsType; import io.xpipe.core.process.ShellControl; import io.xpipe.core.store.FileNames; +import io.xpipe.core.store.FilePath; import org.apache.commons.io.FileUtils; import java.io.IOException; @@ -34,37 +35,37 @@ public class ShellTemp { return temp.resolve(sub); } - public static String getUserSpecificTempDataDirectory(ShellControl proc, String sub) throws Exception { - String base; + public static FilePath getUserSpecificTempDataDirectory(ShellControl proc, String sub) throws Exception { + FilePath base; // On Windows and macOS, we already have user specific temp directories // Even on macOS as root it is technically unique as only root will use /tmp if (!proc.getOsType().equals(OsType.WINDOWS) && !proc.getOsType().equals(OsType.MACOS)) { var temp = proc.getSystemTemporaryDirectory(); - base = FileNames.join(temp, "xpipe"); + base = temp.join("xpipe"); // We have to make sure that also other users can create files here // This command should work in all shells proc.command("chmod 777 " + proc.getShellDialect().fileArgument(base)) .executeAndCheck(); var user = proc.getShellDialect().printUsernameCommand(proc).readStdoutOrThrow(); - base = FileNames.join(base, user); + base = temp.join(user); } else { var temp = proc.getSystemTemporaryDirectory(); - base = FileNames.join(temp, "xpipe"); + base = temp.join("xpipe"); } - return FileNames.join(base, sub); + return base.join(sub); } public static void checkTempDirectory(ShellControl proc) throws Exception { var d = proc.getShellDialect(); var systemTemp = proc.getSystemTemporaryDirectory(); - if (!d.directoryExists(proc, systemTemp).executeAndCheck() || !checkDirectoryPermissions(proc, systemTemp)) { + if (!d.directoryExists(proc, systemTemp.toString()).executeAndCheck() || !checkDirectoryPermissions(proc, systemTemp.toString())) { throw ErrorEvent.expected(new IOException("No permissions to access %s".formatted(systemTemp))); } // Always delete legacy directory and do not care whether it partially fails // This system xpipe temp directory might contain other files on the local machine, so only clear the exec - d.deleteFileOrDirectory(proc, FileNames.join(systemTemp, "xpipe", "exec")) + d.deleteFileOrDirectory(proc, systemTemp.join("xpipe", "exec").toString()) .executeAndCheck(); var home = proc.getOsType().getHomeDirectory(proc); d.deleteFileOrDirectory(proc, FileNames.join(home, ".xpipe", "temp")).executeAndCheck(); diff --git a/app/src/main/java/io/xpipe/app/util/TerminalLauncherManager.java b/app/src/main/java/io/xpipe/app/util/TerminalLauncherManager.java index 8be2aafea..fa88d9ac2 100644 --- a/app/src/main/java/io/xpipe/app/util/TerminalLauncherManager.java +++ b/app/src/main/java/io/xpipe/app/util/TerminalLauncherManager.java @@ -36,7 +36,7 @@ public class TerminalLauncherManager { try { var file = ScriptHelper.createLocalExecScript(processControl.prepareTerminalOpen(config, workingDirectory)); - entry.setResult(new ResultSuccess(Path.of(file))); + entry.setResult(new ResultSuccess(Path.of(file.toString()))); } catch (Exception e) { entry.setResult(new ResultFailure(e)); } diff --git a/core/src/main/java/io/xpipe/core/process/CommandBuilder.java b/core/src/main/java/io/xpipe/core/process/CommandBuilder.java index 3fb6b6be4..86898b2c8 100644 --- a/core/src/main/java/io/xpipe/core/process/CommandBuilder.java +++ b/core/src/main/java/io/xpipe/core/process/CommandBuilder.java @@ -1,5 +1,6 @@ package io.xpipe.core.process; +import io.xpipe.core.store.FilePath; import io.xpipe.core.util.FailableConsumer; import io.xpipe.core.util.FailableFunction; import lombok.Getter; @@ -185,6 +186,10 @@ public class CommandBuilder { return this; } + public CommandBuilder addFile(FilePath s) { + return addFile(shellControl -> shellControl.getShellDialect().fileArgument(s)); + } + public CommandBuilder addLiteral(String s) { elements.add(sc -> { if (s == null) { diff --git a/core/src/main/java/io/xpipe/core/process/ShellControl.java b/core/src/main/java/io/xpipe/core/process/ShellControl.java index 6cc6fd577..164660fd8 100644 --- a/core/src/main/java/io/xpipe/core/process/ShellControl.java +++ b/core/src/main/java/io/xpipe/core/process/ShellControl.java @@ -1,5 +1,6 @@ package io.xpipe.core.process; +import io.xpipe.core.store.FilePath; import io.xpipe.core.store.ShellStore; import io.xpipe.core.store.StatefulDataStore; import io.xpipe.core.util.FailableConsumer; @@ -92,7 +93,7 @@ public interface ShellControl extends ProcessControl { FailableFunction workingDirectory) throws Exception; - String getSystemTemporaryDirectory(); + FilePath getSystemTemporaryDirectory(); default CommandControl osascriptCommand(String script) { return command(String.format( diff --git a/core/src/main/java/io/xpipe/core/process/ShellDialect.java b/core/src/main/java/io/xpipe/core/process/ShellDialect.java index 57b5b5b8a..b63686940 100644 --- a/core/src/main/java/io/xpipe/core/process/ShellDialect.java +++ b/core/src/main/java/io/xpipe/core/process/ShellDialect.java @@ -1,6 +1,7 @@ package io.xpipe.core.process; import com.fasterxml.jackson.annotation.JsonTypeInfo; +import io.xpipe.core.store.FilePath; import io.xpipe.core.store.FileSystem; import io.xpipe.core.util.NewLine; import io.xpipe.core.util.SecretValue; @@ -51,6 +52,10 @@ public interface ShellDialect { String fileArgument(String s); + default String fileArgument(FilePath s) { + return fileArgument(s.toString()); + } + String quoteArgument(String s); String prepareTerminalEnvironmentCommands(); diff --git a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptStore.java b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptStore.java index 2b9cc54b5..9aff81447 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptStore.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/script/ScriptStore.java @@ -114,9 +114,7 @@ public abstract class ScriptStore extends JacksonizedValue implements DataStore, .mapToInt(value -> value.get().getName().hashCode() + value.getStore().hashCode()) .sum(); - var targetDir = FileNames.join( - ShellTemp.getUserSpecificTempDataDirectory(proc, "scripts"), - proc.getShellDialect().getId()); + var targetDir = ShellTemp.getUserSpecificTempDataDirectory(proc, "scripts").join(proc.getShellDialect().getId()).toString(); var hashFile = FileNames.join(targetDir, "hash"); var d = proc.getShellDialect(); if (d.createFileExistsCommand(proc, hashFile).executeAndCheck()) { diff --git a/ext/base/src/main/java/io/xpipe/ext/base/script/SimpleScriptStore.java b/ext/base/src/main/java/io/xpipe/ext/base/script/SimpleScriptStore.java index d8647d3ac..8f4b4034c 100644 --- a/ext/base/src/main/java/io/xpipe/ext/base/script/SimpleScriptStore.java +++ b/ext/base/src/main/java/io/xpipe/ext/base/script/SimpleScriptStore.java @@ -39,7 +39,7 @@ public class SimpleScriptStore extends ScriptStore implements ScriptSnippet { .collect(Collectors.joining( shellControl.getShellDialect().getNewLine().getNewLineString())); var script = ScriptHelper.createExecScript(targetType, shellControl, fixedCommands); - return targetType.sourceScriptCommand(shellControl, script); + return targetType.sourceScriptCommand(shellControl, script.toString()); } return null;