Shell refactoring

This commit is contained in:
crschnick 2023-02-20 09:49:10 +00:00
parent 211b516b7b
commit f304b66055
34 changed files with 165 additions and 66 deletions

View file

@ -76,15 +76,12 @@ https://user-images.githubusercontent.com/72509152/218265431-27bf34ad-03f8-43b7-
The following for modules make up the X-Pipe API and a licensed under the MIT license: The following for modules make up the X-Pipe API and a licensed under the MIT license:
- [core](core) - Shared core classes of the X-Pipe Java API, X-Pipe extensions, and the X-Pipe daemon implementation - [core](core) - Shared core classes of the X-Pipe Java API, X-Pipe extensions, and the X-Pipe daemon implementation
- [API](api) - The API that can be used to interact with X-Pipe from any JVM-based language.
For setup instructions, see the [X-Pipe Java API Usage](https://xpipe-io.readthedocs.io/en/latest/dev/api/java.html) section.
- [beacon](beacon) - The X-Pipe beacon component is responsible for handling all communications between the X-Pipe daemon - [beacon](beacon) - The X-Pipe beacon component is responsible for handling all communications between the X-Pipe daemon
and the client applications, for example the various programming language APIs and the CLI and the client applications, for example the various programming language APIs and the CLI
- [extension](extension) - An API to create all different kinds of extensions for the X-Pipe platform
For setup instructions, see the [X-Pipe extension development](https://xpipe-io.readthedocs.io/en/latest/dev/extensions/index.html) section.
The other modules make up the X-Pipe implementation and are licensed under GPL: The other modules make up the X-Pipe implementation and are licensed under GPL:
- [app](app) - Contains the X-Pipe daemon implementation and the X-Pipe desktop application code - [app](app) - Contains the X-Pipe daemon implementation, the X-Pipe desktop application, and an
API to create all different kinds of extensions for the X-Pipe platform
- [dist](dist) - Tools to create a distributable package of X-Pipe - [dist](dist) - Tools to create a distributable package of X-Pipe
- [ext](ext) - Available X-Pipe extensions. Essentially every feature is implemented as an extension - [ext](ext) - Available X-Pipe extensions. Essentially every feature is implemented as an extension
@ -92,7 +89,7 @@ The other modules make up the X-Pipe implementation and are licensed under GPL:
X-Pipe utilizes an open core model, which essentially means that X-Pipe utilizes an open core model, which essentially means that
the main application core is open source while certain other components are not. the main application core is open source while certain other components are not.
In this case these non open source components are planned to be future parts of a potential commercialization. In this case these non open source components are planned to be future parts of a potential commercialization (got to make a living somehow).
Furthermore, some tests and especially test environments and that run on private servers Furthermore, some tests and especially test environments and that run on private servers
are also not included in this repository (Don't want to leak server information). are also not included in this repository (Don't want to leak server information).
Finally, scripts and workflows to create signed executables and installers Finally, scripts and workflows to create signed executables and installers
@ -119,6 +116,14 @@ many IDEs still have problems building this project properly.
For example, you can't build this project in eclipse or vscode as it will complain about missing modules. For example, you can't build this project in eclipse or vscode as it will complain about missing modules.
The tested and recommended IDE is intellij. The tested and recommended IDE is intellij.
### Setup
You need to have an up-to-date version of X-Pipe installed on your local system in order to properly
run X-Pipe in a development environment.
This is due to the fact that some components are only included in the release version and not in this repository.
X-pipe is able to automatically detect your installation and fetch the required
components from it when it is run in a development environment.
### Building and Running ### Building and Running
You can use the gradle wrapper to build and run the project: You can use the gradle wrapper to build and run the project:

View file

@ -132,7 +132,7 @@ application {
run { run {
systemProperty 'io.xpipe.app.mode', 'gui' systemProperty 'io.xpipe.app.mode', 'gui'
systemProperty 'io.xpipe.app.dataDir', "$projectDir/local_stage/" systemProperty 'io.xpipe.app.dataDir', "$projectDir/local8/"
systemProperty 'io.xpipe.app.writeLogs', "true" systemProperty 'io.xpipe.app.writeLogs', "true"
systemProperty 'io.xpipe.app.writeSysOut', "true" systemProperty 'io.xpipe.app.writeSysOut', "true"
systemProperty 'io.xpipe.app.developerMode', "true" systemProperty 'io.xpipe.app.developerMode', "true"

View file

@ -72,7 +72,12 @@ public class AppExtensionManager {
if (!AppProperties.get().isFullVersion()) { if (!AppProperties.get().isFullVersion()) {
var localInstallation = XPipeInstallation.getLocalDefaultInstallationBasePath(true); var localInstallation = XPipeInstallation.getLocalDefaultInstallationBasePath(true);
var extensions = XPipeInstallation.getLocalExtensionsDirectory(Path.of(localInstallation)); Path p = Path.of(localInstallation);
if (!Files.exists(p)) {
throw new IllegalStateException("Required local X-Pipe installation not found");
}
var extensions = XPipeInstallation.getLocalExtensionsDirectory(p);
extensionBaseDirectories.add(extensions); extensionBaseDirectories.add(extensions);
} }

View file

@ -66,6 +66,10 @@ public class AppGreetings {
} }
public static void showIfNeeded() { public static void showIfNeeded() {
if (!AppProperties.get().isImage()) {
return;
}
boolean set = AppCache.get("legalAccepted", Boolean.class, () -> false); boolean set = AppCache.get("legalAccepted", Boolean.class, () -> false);
if (set) { if (set) {
return; return;
@ -95,8 +99,11 @@ public class AppGreetings {
.createRegion(); .createRegion();
var layout = new BorderPane(); var layout = new BorderPane();
layout.getStyleClass().add("window-content");
layout.setCenter(accordion); layout.setCenter(accordion);
layout.setBottom(acceptanceBox); layout.setBottom(acceptanceBox);
layout.setPrefWidth(700);
layout.setPrefHeight(600);
alert.getDialogPane().setContent(layout); alert.getDialogPane().setContent(layout);

View file

@ -1,7 +1,7 @@
package io.xpipe.app.ext; package io.xpipe.app.ext;
import io.xpipe.app.issue.ErrorEvent; import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.util.ModuleLayerLoader; import io.xpipe.core.util.ModuleLayerLoader;
import io.xpipe.core.source.DataSource; import io.xpipe.core.source.DataSource;
import io.xpipe.core.store.DataStore; import io.xpipe.core.store.DataStore;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;

View file

@ -1,6 +1,6 @@
package io.xpipe.app.ext; package io.xpipe.app.ext;
import io.xpipe.app.util.ModuleLayerLoader; import io.xpipe.core.util.ModuleLayerLoader;
import io.xpipe.app.util.Validator; import io.xpipe.app.util.Validator;
import io.xpipe.core.source.DataSource; import io.xpipe.core.source.DataSource;
import io.xpipe.core.source.DataSourceId; import io.xpipe.core.source.DataSourceId;

View file

@ -1,7 +1,7 @@
package io.xpipe.app.ext; package io.xpipe.app.ext;
import com.dlsc.formsfx.model.structure.Field; import com.dlsc.formsfx.model.structure.Field;
import io.xpipe.app.util.ModuleLayerLoader; import io.xpipe.core.util.ModuleLayerLoader;
import javafx.beans.value.ObservableBooleanValue; import javafx.beans.value.ObservableBooleanValue;
import java.util.ServiceLoader; import java.util.ServiceLoader;

View file

@ -1,8 +1,9 @@
package io.xpipe.app.ext; package io.xpipe.app.ext;
import com.fasterxml.jackson.databind.jsontype.NamedType; import com.fasterxml.jackson.databind.jsontype.NamedType;
import io.xpipe.app.issue.ErrorEvent;
import io.xpipe.app.issue.TrackEvent; import io.xpipe.app.issue.TrackEvent;
import io.xpipe.app.util.ModuleLayerLoader; import io.xpipe.core.util.ModuleLayerLoader;
import io.xpipe.app.util.XPipeDaemon; import io.xpipe.app.util.XPipeDaemon;
import io.xpipe.core.process.ProcessControlProvider; import io.xpipe.core.process.ProcessControlProvider;
import io.xpipe.core.util.JacksonMapper; import io.xpipe.core.util.JacksonMapper;
@ -12,7 +13,9 @@ public class XPipeServiceProviders {
public static void load(ModuleLayer layer) { public static void load(ModuleLayer layer) {
var hasDaemon = XPipeDaemon.getInstanceIfPresent().isPresent(); var hasDaemon = XPipeDaemon.getInstanceIfPresent().isPresent();
ModuleLayerLoader.loadAll(layer, hasDaemon, true); ModuleLayerLoader.loadAll(layer, hasDaemon, true, t -> {
ErrorEvent.fromThrowable(t).handle();
});
ProcessControlProvider.init(layer); ProcessControlProvider.init(layer);
TrackEvent.info("Loading extension providers ..."); TrackEvent.info("Loading extension providers ...");
@ -34,7 +37,9 @@ public class XPipeServiceProviders {
}); });
} }
ModuleLayerLoader.loadAll(layer, hasDaemon, false); ModuleLayerLoader.loadAll(layer, hasDaemon, false, t -> {
ErrorEvent.fromThrowable(t).handle();
});
if (hasDaemon) { if (hasDaemon) {
ProxyFunction.init(layer); ProxyFunction.init(layer);

View file

@ -4,7 +4,7 @@ import io.xpipe.app.ext.PrefsChoiceValue;
import io.xpipe.app.util.ApplicationHelper; import io.xpipe.app.util.ApplicationHelper;
import io.xpipe.app.util.WindowsRegistry; import io.xpipe.app.util.WindowsRegistry;
import io.xpipe.core.process.OsType; import io.xpipe.core.process.OsType;
import io.xpipe.core.process.ShellTypes; import io.xpipe.core.process.ShellDialects;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
@ -112,7 +112,7 @@ public interface ExternalEditorType extends PrefsChoiceValue {
@Override @Override
public void launch(Path file) throws IOException { public void launch(Path file) throws IOException {
var list = ShellTypes.getPlatformDefault().executeCommandListWithShell(executable + " \"" + file + "\""); var list = ShellDialects.getPlatformDefault().executeCommandListWithShell(executable + " \"" + file + "\"");
new ProcessBuilder(list).start(); new ProcessBuilder(list).start();
} }

View file

@ -9,7 +9,7 @@ import io.xpipe.core.impl.FileNames;
import io.xpipe.core.process.CommandProcessControl; import io.xpipe.core.process.CommandProcessControl;
import io.xpipe.core.process.OsType; import io.xpipe.core.process.OsType;
import io.xpipe.core.process.ShellProcessControl; import io.xpipe.core.process.ShellProcessControl;
import io.xpipe.core.process.ShellTypes; import io.xpipe.core.process.ShellDialects;
import io.xpipe.core.store.ShellStore; import io.xpipe.core.store.ShellStore;
import io.xpipe.core.util.XPipeInstallation; import io.xpipe.core.util.XPipeInstallation;
import lombok.Getter; import lombok.Getter;
@ -151,7 +151,7 @@ public class AppInstaller {
shellProcessControl, shellProcessControl,
XPipeInstallation.getDefaultInstallationBasePath(shellProcessControl, false)); XPipeInstallation.getDefaultInstallationBasePath(shellProcessControl, false));
var logsDir = FileNames.join(XPipeInstallation.getDataBasePath(shellProcessControl), "logs"); var logsDir = FileNames.join(XPipeInstallation.getDataBasePath(shellProcessControl), "logs");
var installer = ShellTypes.getPlatformDefault() var installer = ShellDialects.getPlatformDefault()
.flatten(List.of( .flatten(List.of(
"start", "start",
"/wait", "/wait",
@ -161,7 +161,7 @@ public class AppInstaller {
"/l*", "/l*",
FileNames.join(logsDir.toString(), "installer_" + FileNames.getFileName(file) + ".log"), FileNames.join(logsDir.toString(), "installer_" + FileNames.getFileName(file) + ".log"),
"/qb")); "/qb"));
var start = ShellTypes.getPlatformDefault().flatten(List.of("start", "\"\"", exec)); var start = ShellDialects.getPlatformDefault().flatten(List.of("start", "\"\"", exec));
var command = installer + "\r\n" + start; var command = installer + "\r\n" + start;
var script = ScriptHelper.createExecScript(shellProcessControl, command); var script = ScriptHelper.createExecScript(shellProcessControl, command);
shellProcessControl.executeSimpleCommand("start /min " + script); shellProcessControl.executeSimpleCommand("start /min " + script);
@ -178,7 +178,7 @@ public class AppInstaller {
@Override @Override
public void installRemote(ShellProcessControl shellProcessControl, String file) throws Exception { public void installRemote(ShellProcessControl shellProcessControl, String file) throws Exception {
try (var pc = shellProcessControl.subShell(ShellTypes.BASH).start()) { try (var pc = shellProcessControl.subShell(ShellDialects.BASH).start()) {
try (CommandProcessControl c = pc.command("DEBIAN_FRONTEND=noninteractive apt-get remove -qy xpipe") try (CommandProcessControl c = pc.command("DEBIAN_FRONTEND=noninteractive apt-get remove -qy xpipe")
.elevated() .elevated()
.start()) { .start()) {
@ -212,7 +212,7 @@ public class AppInstaller {
@Override @Override
public void installRemote(ShellProcessControl shellProcessControl, String file) throws Exception { public void installRemote(ShellProcessControl shellProcessControl, String file) throws Exception {
try (var pc = shellProcessControl.subShell(ShellTypes.BASH).start()) { try (var pc = shellProcessControl.subShell(ShellDialects.BASH).start()) {
try (CommandProcessControl c = pc.command("rpm -U -v --force \"" + file + "\"") try (CommandProcessControl c = pc.command("rpm -U -v --force \"" + file + "\"")
.elevated() .elevated()
.start()) { .start()) {
@ -238,7 +238,7 @@ public class AppInstaller {
@Override @Override
public void installRemote(ShellProcessControl shellProcessControl, String file) throws Exception { public void installRemote(ShellProcessControl shellProcessControl, String file) throws Exception {
try (var pc = shellProcessControl.subShell(ShellTypes.BASH).start()) { try (var pc = shellProcessControl.subShell(ShellDialects.BASH).start()) {
try (CommandProcessControl c = pc.command( try (CommandProcessControl c = pc.command(
"installer -verboseR -allowUntrusted -pkg \"" + file + "\" -target /") "installer -verboseR -allowUntrusted -pkg \"" + file + "\" -target /")
.elevated() .elevated()

View file

@ -2,7 +2,7 @@ package io.xpipe.app.util;
import io.xpipe.app.issue.TrackEvent; import io.xpipe.app.issue.TrackEvent;
import io.xpipe.core.process.ShellProcessControl; import io.xpipe.core.process.ShellProcessControl;
import io.xpipe.core.process.ShellTypes; import io.xpipe.core.process.ShellDialects;
import io.xpipe.core.store.ShellStore; import io.xpipe.core.store.ShellStore;
import java.io.IOException; import java.io.IOException;
@ -11,7 +11,7 @@ import java.util.List;
public class ApplicationHelper { public class ApplicationHelper {
public static void executeLocalApplication(String s) throws Exception { public static void executeLocalApplication(String s) throws Exception {
var args = ShellTypes.getPlatformDefault().executeCommandListWithShell(s); var args = ShellDialects.getPlatformDefault().executeCommandListWithShell(s);
TrackEvent.withDebug("proc", "Executing local application") TrackEvent.withDebug("proc", "Executing local application")
.elements(args) .elements(args)
.handle(); .handle();
@ -21,7 +21,7 @@ public class ApplicationHelper {
} }
public static void executeLocalApplication(List<String> s) throws Exception { public static void executeLocalApplication(List<String> s) throws Exception {
var args = ShellTypes.getPlatformDefault().executeCommandListWithShell(s); var args = ShellDialects.getPlatformDefault().executeCommandListWithShell(s);
TrackEvent.withDebug("proc", "Executing local application") TrackEvent.withDebug("proc", "Executing local application")
.elements(args) .elements(args)
.handle(); .handle();

View file

@ -3,13 +3,12 @@ package io.xpipe.app.util;
import io.xpipe.app.issue.TrackEvent; import io.xpipe.app.issue.TrackEvent;
import io.xpipe.core.impl.FileNames; import io.xpipe.core.impl.FileNames;
import io.xpipe.core.process.ShellProcessControl; import io.xpipe.core.process.ShellProcessControl;
import io.xpipe.core.process.ShellType; import io.xpipe.core.process.ShellDialect;
import io.xpipe.core.process.ShellTypes; import io.xpipe.core.process.ShellDialects;
import io.xpipe.core.store.ShellStore; import io.xpipe.core.store.ShellStore;
import io.xpipe.core.util.SecretValue; import io.xpipe.core.util.SecretValue;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
@ -106,7 +105,7 @@ public class ScriptHelper {
public static String constructOpenWithInitScriptCommand( public static String constructOpenWithInitScriptCommand(
ShellProcessControl processControl, List<String> init, String toExecuteInShell) { ShellProcessControl processControl, List<String> init, String toExecuteInShell) {
ShellType t = processControl.getShellType(); ShellDialect t = processControl.getShellType();
if (init.size() == 0 && toExecuteInShell == null) { if (init.size() == 0 && toExecuteInShell == null) {
return t.getNormalOpenCommand(); return t.getNormalOpenCommand();
} }
@ -120,7 +119,7 @@ public class ScriptHelper {
} }
// Check for special case of the command being a shell command // Check for special case of the command being a shell command
if (Arrays.stream(ShellTypes.getAllShellTypes()) if (ShellDialects.ALL.stream()
.anyMatch(shellType -> cmd.equals(shellType.getNormalOpenCommand()))) { .anyMatch(shellType -> cmd.equals(shellType.getNormalOpenCommand()))) {
return cmd; return cmd;
} }
@ -129,7 +128,7 @@ public class ScriptHelper {
String nl = t.getNewLine().getNewLineString(); String nl = t.getNewLine().getNewLineString();
var content = String.join(nl, init) + nl; var content = String.join(nl, init) + nl;
if (t.equals(ShellTypes.BASH)) { if (t.equals(ShellDialects.BASH)) {
content = "if [ -f ~/.bashrc ]; then . ~/.bashrc; fi\n" + content; content = "if [ -f ~/.bashrc ]; then . ~/.bashrc; fi\n" + content;
} }
@ -141,7 +140,7 @@ public class ScriptHelper {
var initFile = createExecScript(processControl, content); var initFile = createExecScript(processControl, content);
if (t.equals(ShellTypes.ZSH)) { if (t.equals(ShellDialects.ZSH)) {
var zshiFile = createExecScript(processControl, ZSHI); var zshiFile = createExecScript(processControl, ZSHI);
return t.getNormalOpenCommand() + " \"" + zshiFile + "\" \"" + initFile + "\""; return t.getNormalOpenCommand() + " \"" + zshiFile + "\" \"" + initFile + "\"";
} }
@ -152,7 +151,7 @@ public class ScriptHelper {
@SneakyThrows @SneakyThrows
public static String createExecScript(ShellProcessControl processControl, String content) { public static String createExecScript(ShellProcessControl processControl, String content) {
var fileName = "exec-" + getScriptId(); var fileName = "exec-" + getScriptId();
ShellType type = processControl.getShellType(); ShellDialect type = processControl.getShellType();
var temp = processControl.getTemporaryDirectory(); var temp = processControl.getTemporaryDirectory();
var file = FileNames.join(temp, fileName + "." + type.getScriptFileEnding()); var file = FileNames.join(temp, fileName + "." + type.getScriptFileEnding());
return createExecScript(processControl, file, content); return createExecScript(processControl, file, content);
@ -160,7 +159,7 @@ public class ScriptHelper {
@SneakyThrows @SneakyThrows
private static String createExecScript(ShellProcessControl processControl, String file, String content) { private static String createExecScript(ShellProcessControl processControl, String file, String content) {
ShellType type = processControl.getShellType(); ShellDialect type = processControl.getShellType();
content = type.prepareScriptContent(content); content = type.prepareScriptContent(content);
TrackEvent.withTrace("proc", "Writing exec script") TrackEvent.withTrace("proc", "Writing exec script")
@ -176,7 +175,7 @@ public class ScriptHelper {
} }
@SneakyThrows @SneakyThrows
public static String createAskPassScript(SecretValue pass, ShellProcessControl parent, ShellType type) { public static String createAskPassScript(SecretValue pass, ShellProcessControl parent, ShellDialect type) {
var content = type.getScriptEchoCommand(pass.getSecretValue()); var content = type.getScriptEchoCommand(pass.getSecretValue());
var temp = parent.getTemporaryDirectory(); var temp = parent.getTemporaryDirectory();
var file = FileNames.join(temp, "askpass-" + getScriptId() + "." + type.getScriptFileEnding()); var file = FileNames.join(temp, "askpass-" + getScriptId() + "." + type.getScriptFileEnding());

View file

@ -8,6 +8,7 @@ import io.xpipe.app.issue.EventHandlerImpl;
import io.xpipe.app.storage.DataStateProviderImpl; import io.xpipe.app.storage.DataStateProviderImpl;
import io.xpipe.app.util.*; import io.xpipe.app.util.*;
import io.xpipe.core.util.DataStateProvider; import io.xpipe.core.util.DataStateProvider;
import io.xpipe.core.util.ModuleLayerLoader;
import io.xpipe.core.util.ProxyFunction; import io.xpipe.core.util.ProxyFunction;
import io.xpipe.core.util.ProxyManagerProvider; import io.xpipe.core.util.ProxyManagerProvider;
import org.slf4j.spi.SLF4JServiceProvider; import org.slf4j.spi.SLF4JServiceProvider;

View file

@ -11,6 +11,10 @@
-fx-border-radius: 2px; -fx-border-radius: 2px;
} }
.radio-button {
-fx-background-color:transparent;
}
.icon-button-comp { .icon-button-comp {
-fx-padding: 0.05em; -fx-padding: 0.05em;
} }

View file

@ -3,7 +3,7 @@ package io.xpipe.beacon;
import io.xpipe.beacon.exchange.StopExchange; import io.xpipe.beacon.exchange.StopExchange;
import io.xpipe.core.impl.FileNames; import io.xpipe.core.impl.FileNames;
import io.xpipe.core.process.OsType; import io.xpipe.core.process.OsType;
import io.xpipe.core.process.ShellTypes; import io.xpipe.core.process.ShellDialects;
import io.xpipe.core.util.XPipeDaemonMode; import io.xpipe.core.util.XPipeDaemonMode;
import io.xpipe.core.util.XPipeInstallation; import io.xpipe.core.util.XPipeInstallation;
@ -28,7 +28,7 @@ public class BeaconServer {
public static Process tryStartCustom() throws Exception { public static Process tryStartCustom() throws Exception {
var custom = BeaconConfig.getCustomDaemonCommand(); var custom = BeaconConfig.getCustomDaemonCommand();
if (custom != null) { if (custom != null) {
var command = ShellTypes.getPlatformDefault() var command = ShellDialects.getPlatformDefault()
.executeCommandListWithShell(custom .executeCommandListWithShell(custom
+ (BeaconConfig.getDaemonArguments() != null + (BeaconConfig.getDaemonArguments() != null
? " " + BeaconConfig.getDaemonArguments() ? " " + BeaconConfig.getDaemonArguments()
@ -50,7 +50,7 @@ public class BeaconServer {
getDaemonDebugExecutable(installationBase), BeaconConfig.getDaemonArguments(), mode); getDaemonDebugExecutable(installationBase), BeaconConfig.getDaemonArguments(), mode);
} }
var fullCommand = ShellTypes.getPlatformDefault().executeCommandListWithShell(command); var fullCommand = ShellDialects.getPlatformDefault().executeCommandListWithShell(command);
Process process = new ProcessBuilder(fullCommand).start(); Process process = new ProcessBuilder(fullCommand).start();
printDaemonOutput(process, fullCommand); printDaemonOutput(process, fullCommand);
return process; return process;

View file

@ -143,7 +143,7 @@ public interface OsType {
@Override @Override
public Map<String, String> getProperties(ShellProcessControl pc) throws Exception { public Map<String, String> getProperties(ShellProcessControl pc) throws Exception {
try (CommandProcessControl c = try (CommandProcessControl c =
pc.subShell(ShellTypes.BASH).command("sw_vers").start()) { pc.subShell(ShellDialects.BASH).command("sw_vers").start()) {
var text = c.readOrThrow(); var text = c.readOrThrow();
return PropertiesFormatsParser.parse(text, ":"); return PropertiesFormatsParser.parse(text, ":");
} }

View file

@ -18,7 +18,7 @@ public interface ProcessControl extends Closeable, AutoCloseable {
boolean isRunning(); boolean isRunning();
ShellType getShellType(); ShellDialect getShellType();
void writeLine(String line) throws IOException; void writeLine(String line) throws IOException;

View file

@ -11,7 +11,7 @@ import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
public interface ShellType { public interface ShellDialect {
default String getCdCommand(String directory){ default String getCdCommand(String directory){
return "cd \"" + directory + "\""; return "cd \"" + directory + "\"";
@ -109,7 +109,7 @@ public interface ShellType {
NewLine getNewLine(); NewLine getNewLine();
String getName(); String getId();
String getDisplayName(); String getDisplayName();

View file

@ -0,0 +1,60 @@
package io.xpipe.core.process;
import io.xpipe.core.util.ModuleLayerLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.ServiceLoader;
public class ShellDialects {
public static final List<ShellDialect> ALL = new ArrayList<>();
public static ShellDialect POWERSHELL;
public static ShellDialect CMD;
public static ShellDialect SH;
public static ShellDialect BASH;
public static ShellDialect ZSH;
public static class Loader implements ModuleLayerLoader {
@Override
public void init(ModuleLayer layer) {
ServiceLoader.load(layer, ShellDialect.class).stream().forEach(moduleLayerLoaderProvider -> {
ALL.add(moduleLayerLoaderProvider.get());
});
CMD = byName("cmd");
POWERSHELL = byName("powershell");
SH = byName("sh");
BASH = byName("bash");
ZSH = byName("zsh");
}
@Override
public boolean requiresFullDaemon() {
return false;
}
@Override
public boolean prioritizeLoading() {
return false;
}
}
private static ShellDialect byName(String name) {
return ALL.stream()
.filter(shellType -> shellType.getId().equals(name))
.findFirst()
.orElseThrow();
}
public static ShellDialect getPlatformDefault() {
if (OsType.getLocal().equals(OsType.WINDOWS)) {
return CMD;
} else if (OsType.getLocal().equals(OsType.LINUX)) {
return BASH;
} else {
return ZSH;
}
}
}

View file

@ -49,7 +49,7 @@ public interface ShellProcessControl extends ProcessControl {
} }
} }
default String executeStringSimpleCommand(ShellType type, String command) throws Exception { default String executeStringSimpleCommand(ShellDialect type, String command) throws Exception {
try (var sub = subShell(type).start()) { try (var sub = subShell(type).start()) {
return sub.executeStringSimpleCommand(command); return sub.executeStringSimpleCommand(command);
} }
@ -69,7 +69,7 @@ public interface ShellProcessControl extends ProcessControl {
SecretValue getElevationPassword(); SecretValue getElevationPassword();
default ShellProcessControl subShell(@NonNull ShellType type) { default ShellProcessControl subShell(@NonNull ShellDialect type) {
return subShell(p -> type.getNormalOpenCommand(), (shellProcessControl, s) -> { return subShell(p -> type.getNormalOpenCommand(), (shellProcessControl, s) -> {
return s == null ? type.getNormalOpenCommand() : type.executeCommandWithShell(s); return s == null ? type.getNormalOpenCommand() : type.executeCommandWithShell(s);
}) })

View file

@ -4,7 +4,7 @@ import io.xpipe.core.charsetter.Charsetter;
import io.xpipe.core.impl.LocalStore; import io.xpipe.core.impl.LocalStore;
import io.xpipe.core.process.OsType; import io.xpipe.core.process.OsType;
import io.xpipe.core.process.ShellProcessControl; import io.xpipe.core.process.ShellProcessControl;
import io.xpipe.core.process.ShellType; import io.xpipe.core.process.ShellDialect;
import java.nio.charset.Charset; import java.nio.charset.Charset;
@ -44,8 +44,8 @@ public interface ShellStore extends DataStore, StatefulDataStore, LaunchableStor
return pc; return pc;
} }
default ShellType getShellType() { default ShellDialect getShellType() {
return getState("type", ShellType.class, null); return getState("type", ShellDialect.class, null);
} }
default OsType getOsType() { default OsType getOsType() {
@ -58,7 +58,7 @@ public interface ShellStore extends DataStore, StatefulDataStore, LaunchableStor
ShellProcessControl createControl(); ShellProcessControl createControl();
public default ShellType determineType() throws Exception { public default ShellDialect determineType() throws Exception {
try (var pc = create().start()) { try (var pc = create().start()) {
return pc.getShellType(); return pc.getShellType();
} }

View file

@ -23,8 +23,8 @@ import io.xpipe.core.dialog.BusyElement;
import io.xpipe.core.dialog.ChoiceElement; import io.xpipe.core.dialog.ChoiceElement;
import io.xpipe.core.dialog.HeaderElement; import io.xpipe.core.dialog.HeaderElement;
import io.xpipe.core.impl.*; import io.xpipe.core.impl.*;
import io.xpipe.core.process.ShellType; import io.xpipe.core.process.ShellDialect;
import io.xpipe.core.process.ShellTypes; import io.xpipe.core.process.ShellDialects;
import io.xpipe.core.source.DataSource; import io.xpipe.core.source.DataSource;
import io.xpipe.core.source.DataSourceReference; import io.xpipe.core.source.DataSourceReference;
@ -51,7 +51,7 @@ public class CoreJacksonModule extends SimpleModule {
new NamedType(BusyElement.class), new NamedType(BusyElement.class),
new NamedType(HeaderElement.class)); new NamedType(HeaderElement.class));
for (ShellType t : ShellTypes.getAllShellTypes()) { for (ShellDialect t : ShellDialects.ALL) {
context.registerSubtypes(new NamedType(t.getClass())); context.registerSubtypes(new NamedType(t.getClass()));
} }

View file

@ -2,7 +2,7 @@ package io.xpipe.core.util;
import io.xpipe.core.charsetter.NewLine; import io.xpipe.core.charsetter.NewLine;
import io.xpipe.core.process.OsType; import io.xpipe.core.process.OsType;
import io.xpipe.core.process.ShellTypes; import io.xpipe.core.process.ShellDialects;
import io.xpipe.core.store.ShellStore; import io.xpipe.core.store.ShellStore;
import java.io.PrintWriter; import java.io.PrintWriter;
@ -105,7 +105,7 @@ public class Deobfuscator {
return false; return false;
} }
var t = ShellTypes.getPlatformDefault(); var t = ShellDialects.getPlatformDefault();
return ShellStore.local() return ShellStore.local()
.create() .create()
.executeBooleanSimpleCommand(t.getWhichCommand("retrace." + t.getScriptFileEnding())); .executeBooleanSimpleCommand(t.getWhichCommand("retrace." + t.getScriptFileEnding()));

View file

@ -1,13 +1,12 @@
package io.xpipe.app.util; package io.xpipe.core.util;
import io.xpipe.app.issue.ErrorEvent;
import java.util.ServiceLoader; import java.util.ServiceLoader;
import java.util.function.Consumer;
public interface ModuleLayerLoader { public interface ModuleLayerLoader {
public static void loadAll(ModuleLayer layer, boolean hasDaemon, boolean prioritization) { public static void loadAll(ModuleLayer layer, boolean hasDaemon, boolean prioritization, Consumer<Throwable> errorHandler) {
ServiceLoader.load(layer, ModuleLayerLoader.class).stream().forEach(moduleLayerLoaderProvider -> { ServiceLoader.load(layer, ModuleLayerLoader.class).stream().forEach(moduleLayerLoaderProvider -> {
var instance = moduleLayerLoaderProvider.get(); var instance = moduleLayerLoaderProvider.get();
try { try {
@ -21,7 +20,7 @@ public interface ModuleLayerLoader {
instance.init(layer); instance.init(layer);
} catch (Throwable t) { } catch (Throwable t) {
ErrorEvent.fromThrowable(t).handle(); errorHandler.accept(t);
} }
}); });
} }

View file

@ -1,6 +1,9 @@
import io.xpipe.core.process.ProcessControlProvider; import io.xpipe.core.process.ProcessControlProvider;
import io.xpipe.core.process.ShellDialect;
import io.xpipe.core.process.ShellDialects;
import io.xpipe.core.source.WriteMode; import io.xpipe.core.source.WriteMode;
import io.xpipe.core.util.CoreJacksonModule; import io.xpipe.core.util.CoreJacksonModule;
import io.xpipe.core.util.ModuleLayerLoader;
open module io.xpipe.core { open module io.xpipe.core {
exports io.xpipe.core.store; exports io.xpipe.core.store;
@ -29,6 +32,10 @@ open module io.xpipe.core {
uses io.xpipe.core.util.ProxyManagerProvider; uses io.xpipe.core.util.ProxyManagerProvider;
uses io.xpipe.core.util.DataStateProvider; uses io.xpipe.core.util.DataStateProvider;
uses io.xpipe.core.util.SecretProvider; uses io.xpipe.core.util.SecretProvider;
uses ModuleLayerLoader;
uses ShellDialect;
provides ModuleLayerLoader with ShellDialects.Loader;
provides WriteMode with provides WriteMode with
WriteMode.Replace, WriteMode.Replace,

View file

@ -1,10 +1,10 @@
module io.xpipe.ext.text.test { module io.xpipe.ext.base.test {
requires io.xpipe.ext.base; requires io.xpipe.ext.base;
requires org.junit.jupiter.api; requires org.junit.jupiter.api;
requires org.junit.jupiter.params; requires org.junit.jupiter.params;
requires io.xpipe.core; requires io.xpipe.core;
requires io.xpipe.api; requires io.xpipe.api;
requires io.xpipe.extension; requires io.xpipe.app;
exports test; exports test;
} }

View file

@ -1,11 +1,11 @@
package test; package test;
import io.xpipe.api.DataSource; import io.xpipe.api.DataSource;
import io.xpipe.app.test.DaemonExtensionTest;
import io.xpipe.core.charsetter.NewLine; import io.xpipe.core.charsetter.NewLine;
import io.xpipe.core.charsetter.StreamCharset; import io.xpipe.core.charsetter.StreamCharset;
import io.xpipe.core.impl.FileStore; import io.xpipe.core.impl.FileStore;
import io.xpipe.core.impl.TextSource; import io.xpipe.core.impl.TextSource;
import io.xpipe.extension.test.DaemonExtensionTest;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;

View file

@ -1,11 +1,11 @@
package io.xpipe.ext.csv.test; package io.xpipe.ext.csv.test;
import io.xpipe.app.test.DaemonExtensionTest;
import io.xpipe.core.data.node.TupleNode; import io.xpipe.core.data.node.TupleNode;
import io.xpipe.core.data.node.ValueNode; import io.xpipe.core.data.node.ValueNode;
import io.xpipe.ext.csv.CsvDelimiter; import io.xpipe.ext.csv.CsvDelimiter;
import io.xpipe.ext.csv.CsvHeaderState; import io.xpipe.ext.csv.CsvHeaderState;
import io.xpipe.ext.csv.CsvSource; import io.xpipe.ext.csv.CsvSource;
import io.xpipe.extension.test.DaemonExtensionTest;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;

View file

@ -7,6 +7,6 @@ module io.xpipe.csv.test {
requires org.junit.jupiter.api; requires org.junit.jupiter.api;
requires org.junit.jupiter.params; requires org.junit.jupiter.params;
requires io.xpipe.core; requires io.xpipe.core;
requires io.xpipe.extension; requires io.xpipe.app;
requires io.xpipe.api; requires io.xpipe.api;
} }

5
ext/proc/build.gradle Normal file
View file

@ -0,0 +1,5 @@
plugins { id 'java'
id 'org.moditect.gradleplugin' version '1.0.0-rc3'
}
apply from: "$rootDir/gradle/gradle_scripts/java.gradle"
apply from: "$rootDir/gradle/gradle_scripts/extension.gradle"

View file

@ -0,0 +1 @@
module io.xpipe.ext.proc {}

View file

@ -43,6 +43,7 @@ dependencies {
if (project != project(':base')) { if (project != project(':base')) {
compileOnly project(':base') compileOnly project(':base')
testImplementation project(':base')
} }
testImplementation project(':app') testImplementation project(':app')

View file

@ -2,11 +2,10 @@ import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform
apply from: "$buildscript.sourceFile/../junit.gradle" apply from: "$buildscript.sourceFile/../junit.gradle"
def useExtension = System.getProperty('excludeExtensionLibrary') == null
dependencies { dependencies {
testImplementation project(':api') testImplementation project(':api')
testImplementation project(':core') testImplementation project(':core')
testImplementation project(':app')
testImplementation "org.openjfx:javafx-base:19:win" testImplementation "org.openjfx:javafx-base:19:win"
testImplementation "org.openjfx:javafx-controls:19:win" testImplementation "org.openjfx:javafx-controls:19:win"
@ -24,6 +23,7 @@ test {
// Daemon properties // Daemon properties
systemProperty "io.xpipe.beacon.daemonArgs", systemProperty "io.xpipe.beacon.daemonArgs",
" -Dio.xpipe.beacon.port=21723" + " -Dio.xpipe.beacon.port=21723" +
" -Dio.xpipe.app.mode=tray" +
" -Dio.xpipe.app.dataDir=$projectDir/local/" + " -Dio.xpipe.app.dataDir=$projectDir/local/" +
" -Dio.xpipe.storage.persist=false" + " -Dio.xpipe.storage.persist=false" +
" -Dio.xpipe.app.writeSysOut=true" + " -Dio.xpipe.app.writeSysOut=true" +

View file

@ -1 +1 @@
0.4.30 0.5.0