mirror of
https://github.com/xpipe-io/xpipe.git
synced 2026-09-26 02:15:47 +00:00
Rework
This commit is contained in:
@@ -21,8 +21,7 @@ public class FsScriptExchangeImpl extends FsScriptExchange {
|
||||
data = new String(in.readAllBytes(), StandardCharsets.UTF_8);
|
||||
}
|
||||
data = shell.getControl().getShellDialect().prepareScriptContent(data);
|
||||
var file = ScriptHelper.getExecScriptFile(shell.getControl());
|
||||
shell.getControl().view().writeScriptFile(file, data);
|
||||
var file = ScriptHelper.createExecScript(shell.getControl(), data);
|
||||
return Response.builder().path(file).build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,9 +85,8 @@ public abstract class AppShellChecker {
|
||||
|
||||
private Optional<FailureResult> selfTestErrorCheck() {
|
||||
try (var sc = LocalShell.getShell().start()) {
|
||||
var scriptFile = ScriptHelper.getExecScriptFile(sc);
|
||||
var scriptContent = sc.getShellDialect().prepareScriptContent("echo test");
|
||||
sc.view().writeScriptFile(scriptFile, scriptContent);
|
||||
var scriptContent = "echo test";
|
||||
var scriptFile = ScriptHelper.createExecScript(sc, scriptContent);
|
||||
var out = sc.command(sc.getShellDialect().runScriptCommand(sc, scriptFile.toString()))
|
||||
.readStdoutOrThrow();
|
||||
if (!out.equals("test")) {
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
package io.xpipe.app.terminal;
|
||||
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import io.xpipe.app.util.LocalShell;
|
||||
import io.xpipe.app.util.ScriptHelper;
|
||||
import io.xpipe.app.util.SshLocalBridge;
|
||||
import io.xpipe.app.util.WindowsRegistry;
|
||||
import io.xpipe.app.util.*;
|
||||
import io.xpipe.core.process.CommandBuilder;
|
||||
|
||||
import java.nio.file.Files;
|
||||
@@ -69,7 +66,7 @@ public class MobaXTermTerminalType extends ExternalTerminalType.WindowsType {
|
||||
.add("" + b.getPort());
|
||||
// Don't use local shell to build as it uses cygwin
|
||||
var rawCommand = command.buildSimple();
|
||||
var script = ScriptHelper.getExecScriptFile(sc, "sh");
|
||||
var script = ShellTemp.getLocalTempDataDirectory("mobaxpipe.sh");
|
||||
Files.writeString(Path.of(script.toString()), "#!/usr/bin/env bash\n" + rawCommand);
|
||||
var fixedFile = script.toString().replaceAll("\\\\", "/").replaceAll("\\s", "\\$0");
|
||||
sc.command(CommandBuilder.of()
|
||||
|
||||
@@ -14,11 +14,8 @@ import java.util.stream.Collectors;
|
||||
|
||||
public class ScriptHelper {
|
||||
|
||||
public static int getScriptId() {
|
||||
// A deterministic approach can cause permission problems when two different users execute the same command on a
|
||||
// system
|
||||
// Therefore, use a random approach
|
||||
return new Random().nextInt(Integer.MAX_VALUE);
|
||||
public static int getScriptHash(String content) {
|
||||
return Math.abs(content.hashCode());
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@@ -73,20 +70,9 @@ public class ScriptHelper {
|
||||
content += nl + t.getPassthroughExitCommand();
|
||||
}
|
||||
|
||||
return createExecScript(t, processControl, FilePath.of(t.initFileName(processControl)), content);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static FilePath getExecScriptFile(ShellControl processControl) {
|
||||
return getExecScriptFile(
|
||||
processControl, processControl.getShellDialect().getScriptFileEnding());
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static FilePath getExecScriptFile(ShellControl processControl, String fileEnding) {
|
||||
var fileName = "xpipe-" + getScriptId();
|
||||
var temp = processControl.getSystemTemporaryDirectory();
|
||||
return temp.join(fileName + "." + fileEnding);
|
||||
var hash = getScriptHash(content);
|
||||
var file = t.getInitFileName(processControl, hash);
|
||||
return createExecScript(t, processControl, file, content);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@@ -96,15 +82,14 @@ public class ScriptHelper {
|
||||
|
||||
@SneakyThrows
|
||||
public static FilePath createExecScript(ShellDialect type, ShellControl processControl, String content) {
|
||||
var fileName = "xpipe-" + getScriptId();
|
||||
var fileName = "xpipe-" + getScriptHash(content);
|
||||
var temp = processControl.getSystemTemporaryDirectory();
|
||||
var file = temp.join(fileName + "." + type.getScriptFileEnding());
|
||||
return createExecScript(type, processControl, file, content);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static FilePath createExecScript(
|
||||
ShellDialect type, ShellControl processControl, FilePath file, String content) {
|
||||
public static FilePath createExecScript(ShellDialect type, ShellControl processControl, FilePath file, String content) {
|
||||
content = type.prepareScriptContent(content);
|
||||
|
||||
TrackEvent.withTrace("Writing exec script")
|
||||
@@ -125,18 +110,21 @@ public class ScriptHelper {
|
||||
type = parent.getOsType().equals(OsType.WINDOWS) ? ShellDialects.CMD : ShellDialects.SH;
|
||||
}
|
||||
|
||||
var fileName = "xpipe-" + getScriptId() + "." + type.getScriptFileEnding();
|
||||
var temp = parent.getSystemTemporaryDirectory();
|
||||
var file = temp.join(fileName);
|
||||
if (type != parent.getShellDialect()) {
|
||||
try (var sub = parent.subShell(type).start()) {
|
||||
var content =
|
||||
sub.getShellDialect().getAskpass().prepareStderrPassthroughContent(sub, requestId, prefix);
|
||||
var fileName = "xpipe-" + getScriptHash(content) + "." + type.getScriptFileEnding();
|
||||
var temp = parent.getSystemTemporaryDirectory();
|
||||
var file = temp.join(fileName);
|
||||
return createExecScript(sub.getShellDialect(), sub, file, content);
|
||||
}
|
||||
} else {
|
||||
var content =
|
||||
parent.getShellDialect().getAskpass().prepareStderrPassthroughContent(parent, requestId, prefix);
|
||||
var fileName = "xpipe-" + getScriptHash(content) + "." + type.getScriptFileEnding();
|
||||
var temp = parent.getSystemTemporaryDirectory();
|
||||
var file = temp.join(fileName);
|
||||
return createExecScript(parent.getShellDialect(), parent, file, content);
|
||||
}
|
||||
}
|
||||
@@ -160,31 +148,31 @@ public class ScriptHelper {
|
||||
|
||||
private static FilePath createTerminalPreparedAskpassScript(
|
||||
List<SecretValue> pass, ShellControl parent, ShellDialect type) throws Exception {
|
||||
var fileName = "xpipe-" + getScriptId() + "." + type.getScriptFileEnding();
|
||||
var fileName = "xpipe-" + new Random().nextInt();
|
||||
var temp = parent.getSystemTemporaryDirectory();
|
||||
var file = temp.join(fileName);
|
||||
var fileBase = temp.join(fileName);
|
||||
if (type != parent.getShellDialect()) {
|
||||
try (var sub = parent.subShell(type).start()) {
|
||||
var content = sub.getShellDialect()
|
||||
.getAskpass()
|
||||
.prepareFixedContent(
|
||||
sub,
|
||||
file.toString(),
|
||||
fileBase.toString(),
|
||||
pass.stream()
|
||||
.map(secretValue -> secretValue.getSecretValue())
|
||||
.toList());
|
||||
return createExecScript(sub.getShellDialect(), sub, file, content);
|
||||
return createExecScript(sub.getShellDialect(), sub, content);
|
||||
}
|
||||
} else {
|
||||
var content = parent.getShellDialect()
|
||||
.getAskpass()
|
||||
.prepareFixedContent(
|
||||
parent,
|
||||
file.toString(),
|
||||
fileBase.toString(),
|
||||
pass.stream()
|
||||
.map(secretValue -> secretValue.getSecretValue())
|
||||
.toList());
|
||||
return createExecScript(parent.getShellDialect(), parent, file, content);
|
||||
return createExecScript(parent.getShellDialect(), parent, content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,14 +96,11 @@ public class ShellTemp {
|
||||
.formatted(d.fileArgument(dir), d.fileArgument(dir), d.fileArgument(dir)));
|
||||
}
|
||||
|
||||
public static String getSubDirectory(ShellControl proc, String... sub) throws Exception {
|
||||
public static FilePath getSubDirectory(ShellControl proc, String... sub) throws Exception {
|
||||
var base = proc.getSystemTemporaryDirectory();
|
||||
var arr = Stream.concat(Stream.of(base.toString()), Arrays.stream(sub)).toArray(String[]::new);
|
||||
var dir = FileNames.join(arr);
|
||||
|
||||
var dir = base.join(sub);
|
||||
// We assume that this directory does not exist yet and therefore don't perform any checks
|
||||
proc.getShellDialect().prepareUserTempDirectory(proc, dir).execute();
|
||||
|
||||
proc.getShellDialect().prepareUserTempDirectory(proc, dir.toString()).execute();
|
||||
return dir;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public interface ShellDialect {
|
||||
|
||||
CommandControl prepareUserTempDirectory(ShellControl shellControl, String directory);
|
||||
|
||||
String initFileName(ShellControl sc) throws Exception;
|
||||
FilePath getInitFileName(ShellControl sc, int hash) throws Exception;
|
||||
|
||||
CommandControl directoryExists(ShellControl shellControl, String directory);
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import java.util.function.Predicate;
|
||||
public class ScriptHierarchy {
|
||||
|
||||
public static ScriptHierarchy buildEnabledHierarchy(Predicate<DataStoreEntryRef<SimpleScriptStore>> include) {
|
||||
var all = new HashSet<>(ScriptStore.getEnabledScripts());
|
||||
var all = new HashSet<>(ScriptStoreSetup.getEnabledScripts());
|
||||
|
||||
// Add individual children of groups
|
||||
// This is not recursive
|
||||
|
||||
@@ -1,14 +1,7 @@
|
||||
package io.xpipe.ext.base.script;
|
||||
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
import io.xpipe.app.storage.DataStoreEntry;
|
||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||
import io.xpipe.app.util.ShellTemp;
|
||||
import io.xpipe.app.util.Validators;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
import io.xpipe.core.process.ShellDialect;
|
||||
import io.xpipe.core.process.ShellInitCommand;
|
||||
import io.xpipe.core.store.*;
|
||||
|
||||
import lombok.*;
|
||||
@@ -30,165 +23,6 @@ public abstract class ScriptStore implements DataStore, StatefulDataStore<Enable
|
||||
|
||||
protected final String description;
|
||||
|
||||
public static ShellControl controlWithDefaultScripts(ShellControl pc) {
|
||||
return controlWithScripts(pc, getEnabledScripts());
|
||||
}
|
||||
|
||||
public static ShellControl controlWithScripts(
|
||||
ShellControl pc, List<DataStoreEntryRef<ScriptStore>> enabledScripts) {
|
||||
try {
|
||||
// Don't copy scripts if we don't want to modify the file system
|
||||
if (!pc.getEffectiveSecurityPolicy().permitTempScriptCreation()) {
|
||||
return pc;
|
||||
}
|
||||
|
||||
var initFlattened = flatten(enabledScripts).stream()
|
||||
.filter(store -> store.getStore().isInitScript())
|
||||
.toList();
|
||||
var bringFlattened = flatten(enabledScripts).stream()
|
||||
.filter(store -> store.getStore().isShellScript())
|
||||
.toList();
|
||||
|
||||
// Optimize if we have nothing to do
|
||||
if (initFlattened.isEmpty() && bringFlattened.isEmpty()) {
|
||||
return pc;
|
||||
}
|
||||
|
||||
initFlattened.forEach(simpleScriptStore -> {
|
||||
pc.withInitSnippet(simpleScriptStore.getStore());
|
||||
});
|
||||
if (!bringFlattened.isEmpty()) {
|
||||
pc.withInitSnippet(new ShellInitCommand() {
|
||||
|
||||
String dir;
|
||||
|
||||
@Override
|
||||
public Optional<String> terminalContent(ShellControl shellControl) throws Exception {
|
||||
if (dir == null) {
|
||||
dir = initScriptsDirectory(shellControl, bringFlattened);
|
||||
}
|
||||
|
||||
if (dir == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Optional.ofNullable(
|
||||
shellControl.getShellDialect().addToPathVariableCommand(List.of(dir), true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPotentiallyRunInDialect(ShellDialect dialect) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean runInTerminal() {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
return pc;
|
||||
} catch (StackOverflowError t) {
|
||||
throw ErrorEvent.expected(
|
||||
new RuntimeException("Unable to set up scripts. Is there a circular script dependency?", t));
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException("Unable to set up scripts", t);
|
||||
}
|
||||
}
|
||||
|
||||
private static String initScriptsDirectory(ShellControl proc, List<DataStoreEntryRef<SimpleScriptStore>> refs)
|
||||
throws Exception {
|
||||
if (refs.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var applicable = refs.stream()
|
||||
.filter(simpleScriptStore ->
|
||||
simpleScriptStore.getStore().getMinimumDialect().isCompatibleTo(proc.getShellDialect()))
|
||||
.toList();
|
||||
if (applicable.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var hash = refs.stream()
|
||||
.mapToInt(value ->
|
||||
value.get().getName().hashCode() + value.getStore().hashCode())
|
||||
.sum();
|
||||
var targetDir = ShellTemp.createUserSpecificTempDataDirectory(proc, "scripts")
|
||||
.join(proc.getShellDialect().getId())
|
||||
.toString();
|
||||
var hashFile = FileNames.join(targetDir, "hash");
|
||||
var d = proc.getShellDialect();
|
||||
if (d.createFileExistsCommand(proc, hashFile).executeAndCheck()) {
|
||||
var read = d.getFileReadCommand(proc, hashFile).readStdoutOrThrow();
|
||||
try {
|
||||
var readHash = Integer.parseInt(read);
|
||||
if (hash == readHash) {
|
||||
return targetDir;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
ErrorEvent.fromThrowable(e).expected().omit().handle();
|
||||
}
|
||||
}
|
||||
|
||||
if (d.directoryExists(proc, targetDir).executeAndCheck()) {
|
||||
d.deleteFileOrDirectory(proc, targetDir).execute();
|
||||
}
|
||||
proc.executeSimpleCommand(d.getMkdirsCommand(targetDir));
|
||||
|
||||
for (DataStoreEntryRef<SimpleScriptStore> scriptStore : refs) {
|
||||
var content = d.prepareScriptContent(scriptStore.getStore().getCommands());
|
||||
var fileName = proc.getOsType()
|
||||
.makeFileSystemCompatible(
|
||||
scriptStore.get().getName().toLowerCase(Locale.ROOT).replaceAll(" ", "_"));
|
||||
var scriptFile = FileNames.join(targetDir, fileName + "." + d.getScriptFileEnding());
|
||||
proc.view().writeScriptFile(FilePath.of(scriptFile), content);
|
||||
}
|
||||
|
||||
proc.view().writeTextFile(FilePath.of(hashFile), String.valueOf(hash));
|
||||
return targetDir;
|
||||
}
|
||||
|
||||
public static List<DataStoreEntryRef<ScriptStore>> getEnabledScripts() {
|
||||
return DataStorage.get().getStoreEntries().stream()
|
||||
.filter(dataStoreEntry -> dataStoreEntry.getValidity().isUsable()
|
||||
&& dataStoreEntry.getStore() instanceof ScriptStore scriptStore
|
||||
&& scriptStore.getState().isEnabled())
|
||||
.map(DataStoreEntry::<ScriptStore>ref)
|
||||
.toList();
|
||||
}
|
||||
|
||||
public static List<DataStoreEntryRef<SimpleScriptStore>> flatten(List<DataStoreEntryRef<ScriptStore>> scripts) {
|
||||
var seen = new LinkedHashSet<DataStoreEntryRef<SimpleScriptStore>>();
|
||||
scripts.stream()
|
||||
.filter(scriptStoreDataStoreEntryRef ->
|
||||
scriptStoreDataStoreEntryRef.get().getValidity().isUsable())
|
||||
.forEach(scriptStoreDataStoreEntryRef ->
|
||||
scriptStoreDataStoreEntryRef.getStore().queryFlattenedScripts(seen));
|
||||
|
||||
var dependencies =
|
||||
new HashMap<DataStoreEntryRef<? extends ScriptStore>, Set<DataStoreEntryRef<SimpleScriptStore>>>();
|
||||
seen.forEach(ref -> {
|
||||
var f = new HashSet<>(ref.getStore().queryFlattenedScripts());
|
||||
f.remove(ref);
|
||||
dependencies.put(ref, f);
|
||||
});
|
||||
|
||||
var sorted = new ArrayList<>(seen);
|
||||
sorted.sort((o1, o2) -> {
|
||||
if (dependencies.get(o1).contains(o2)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (dependencies.get(o2).contains(o1)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
return sorted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<EnabledStoreState> getStateClass() {
|
||||
return EnabledStoreState.class;
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
package io.xpipe.ext.base.script;
|
||||
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import io.xpipe.app.storage.DataStorage;
|
||||
import io.xpipe.app.storage.DataStoreEntry;
|
||||
import io.xpipe.app.storage.DataStoreEntryRef;
|
||||
import io.xpipe.app.util.ShellTemp;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
import io.xpipe.core.process.ShellDialect;
|
||||
import io.xpipe.core.process.ShellInitCommand;
|
||||
import io.xpipe.core.store.FileNames;
|
||||
import io.xpipe.core.store.FilePath;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class ScriptStoreSetup {
|
||||
|
||||
public static ShellControl controlWithDefaultScripts(ShellControl pc) {
|
||||
return controlWithScripts(pc, getEnabledScripts());
|
||||
}
|
||||
|
||||
public static ShellControl controlWithScripts(
|
||||
ShellControl pc, List<DataStoreEntryRef<ScriptStore>> enabledScripts) {
|
||||
try {
|
||||
// Don't copy scripts if we don't want to modify the file system
|
||||
if (!pc.getEffectiveSecurityPolicy().permitTempScriptCreation()) {
|
||||
return pc;
|
||||
}
|
||||
|
||||
var initFlattened = flatten(enabledScripts).stream()
|
||||
.filter(store -> store.getStore().isInitScript())
|
||||
.toList();
|
||||
var bringFlattened = flatten(enabledScripts).stream()
|
||||
.filter(store -> store.getStore().isShellScript())
|
||||
.toList();
|
||||
|
||||
// Optimize if we have nothing to do
|
||||
if (initFlattened.isEmpty() && bringFlattened.isEmpty()) {
|
||||
return pc;
|
||||
}
|
||||
|
||||
initFlattened.forEach(simpleScriptStore -> {
|
||||
pc.withInitSnippet(simpleScriptStore.getStore());
|
||||
});
|
||||
if (!bringFlattened.isEmpty()) {
|
||||
pc.withInitSnippet(new ShellInitCommand() {
|
||||
|
||||
String dir;
|
||||
|
||||
@Override
|
||||
public Optional<String> terminalContent(ShellControl shellControl) throws Exception {
|
||||
if (dir == null) {
|
||||
dir = initScriptsDirectory(shellControl, bringFlattened);
|
||||
}
|
||||
|
||||
if (dir == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Optional.ofNullable(
|
||||
shellControl.getShellDialect().addToPathVariableCommand(List.of(dir), true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPotentiallyRunInDialect(ShellDialect dialect) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean runInTerminal() {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
return pc;
|
||||
} catch (StackOverflowError t) {
|
||||
throw ErrorEvent.expected(
|
||||
new RuntimeException("Unable to set up scripts. Is there a circular script dependency?", t));
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException("Unable to set up scripts", t);
|
||||
}
|
||||
}
|
||||
|
||||
private static String initScriptsDirectory(ShellControl proc, List<DataStoreEntryRef<SimpleScriptStore>> refs)
|
||||
throws Exception {
|
||||
if (refs.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var applicable = refs.stream()
|
||||
.filter(simpleScriptStore ->
|
||||
simpleScriptStore.getStore().getMinimumDialect().isCompatibleTo(proc.getShellDialect()))
|
||||
.toList();
|
||||
if (applicable.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var hash = refs.stream()
|
||||
.mapToInt(value ->
|
||||
value.get().getName().hashCode() + value.getStore().hashCode())
|
||||
.sum();
|
||||
var targetDir = ShellTemp.createUserSpecificTempDataDirectory(proc, "scripts")
|
||||
.join(proc.getShellDialect().getId())
|
||||
.toString();
|
||||
var hashFile = FileNames.join(targetDir, "hash");
|
||||
var d = proc.getShellDialect();
|
||||
if (d.createFileExistsCommand(proc, hashFile).executeAndCheck()) {
|
||||
var read = d.getFileReadCommand(proc, hashFile).readStdoutOrThrow();
|
||||
try {
|
||||
var readHash = Integer.parseInt(read);
|
||||
if (hash == readHash) {
|
||||
return targetDir;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
ErrorEvent.fromThrowable(e).expected().omit().handle();
|
||||
}
|
||||
}
|
||||
|
||||
if (d.directoryExists(proc, targetDir).executeAndCheck()) {
|
||||
d.deleteFileOrDirectory(proc, targetDir).execute();
|
||||
}
|
||||
proc.executeSimpleCommand(d.getMkdirsCommand(targetDir));
|
||||
|
||||
for (DataStoreEntryRef<SimpleScriptStore> scriptStore : refs) {
|
||||
var content = d.prepareScriptContent(scriptStore.getStore().getCommands());
|
||||
var fileName = proc.getOsType()
|
||||
.makeFileSystemCompatible(
|
||||
scriptStore.get().getName().toLowerCase(Locale.ROOT).replaceAll(" ", "_"));
|
||||
var scriptFile = FileNames.join(targetDir, fileName + "." + d.getScriptFileEnding());
|
||||
proc.view().writeScriptFile(FilePath.of(scriptFile), content);
|
||||
}
|
||||
|
||||
proc.view().writeTextFile(FilePath.of(hashFile), String.valueOf(hash));
|
||||
return targetDir;
|
||||
}
|
||||
|
||||
public static List<DataStoreEntryRef<ScriptStore>> getEnabledScripts() {
|
||||
return DataStorage.get().getStoreEntries().stream()
|
||||
.filter(dataStoreEntry -> dataStoreEntry.getValidity().isUsable()
|
||||
&& dataStoreEntry.getStore() instanceof ScriptStore scriptStore
|
||||
&& scriptStore.getState().isEnabled())
|
||||
.map(DataStoreEntry::<ScriptStore>ref)
|
||||
.toList();
|
||||
}
|
||||
|
||||
public static List<DataStoreEntryRef<SimpleScriptStore>> flatten(List<DataStoreEntryRef<ScriptStore>> scripts) {
|
||||
var seen = new LinkedHashSet<DataStoreEntryRef<SimpleScriptStore>>();
|
||||
scripts.stream()
|
||||
.filter(scriptStoreDataStoreEntryRef ->
|
||||
scriptStoreDataStoreEntryRef.get().getValidity().isUsable())
|
||||
.forEach(scriptStoreDataStoreEntryRef ->
|
||||
scriptStoreDataStoreEntryRef.getStore().queryFlattenedScripts(seen));
|
||||
|
||||
var dependencies =
|
||||
new HashMap<DataStoreEntryRef<? extends ScriptStore>, Set<DataStoreEntryRef<SimpleScriptStore>>>();
|
||||
seen.forEach(ref -> {
|
||||
var f = new HashSet<>(ref.getStore().queryFlattenedScripts());
|
||||
f.remove(ref);
|
||||
dependencies.put(ref, f);
|
||||
});
|
||||
|
||||
var sorted = new ArrayList<>(seen);
|
||||
sorted.sort((o1, o2) -> {
|
||||
if (dependencies.get(o1).contains(o2)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (dependencies.get(o2).contains(o1)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
return sorted;
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,8 @@ import io.xpipe.app.storage.DataStorage;
|
||||
import io.xpipe.app.storage.DataStoreEntry;
|
||||
import io.xpipe.app.terminal.TerminalLauncher;
|
||||
import io.xpipe.app.util.ShellStoreFormat;
|
||||
import io.xpipe.ext.base.script.ScriptStore;
|
||||
|
||||
import io.xpipe.ext.base.script.ScriptStoreSetup;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
|
||||
@@ -25,7 +25,7 @@ public interface ShellStoreProvider extends DataStoreProvider {
|
||||
public void execute() throws Exception {
|
||||
var replacement = ProcessControlProvider.get().replace(entry.ref());
|
||||
ShellStore store = replacement.getStore().asNeeded();
|
||||
var control = ScriptStore.controlWithDefaultScripts(store.tempControl());
|
||||
var control = ScriptStoreSetup.controlWithDefaultScripts(store.tempControl());
|
||||
TerminalLauncher.open(
|
||||
replacement.get(),
|
||||
DataStorage.get().getStoreEntryDisplayName(replacement.get()),
|
||||
|
||||
Reference in New Issue
Block a user