mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-25 00:50:31 +00:00
Improvements and refactor for shell connections
This commit is contained in:
parent
d5a7e2fb64
commit
d879c13aa4
38 changed files with 700 additions and 191 deletions
|
@ -132,7 +132,7 @@ application {
|
|||
|
||||
run {
|
||||
systemProperty 'io.xpipe.app.mode', 'gui'
|
||||
systemProperty 'io.xpipe.app.dataDir', "$projectDir/local_stage/"
|
||||
systemProperty 'io.xpipe.app.dataDir', "$projectDir/local7/"
|
||||
systemProperty 'io.xpipe.app.writeLogs', "true"
|
||||
systemProperty 'io.xpipe.app.writeSysOut', "true"
|
||||
systemProperty 'io.xpipe.app.developerMode', "true"
|
||||
|
|
|
@ -7,7 +7,7 @@ import io.xpipe.app.ext.DataSourceProvider;
|
|||
import io.xpipe.app.util.*;
|
||||
import io.xpipe.core.impl.FileStore;
|
||||
import io.xpipe.core.process.OsType;
|
||||
import io.xpipe.core.process.ShellProcessControl;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
import io.xpipe.core.store.FileSystem;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.scene.control.ContextMenu;
|
||||
|
@ -73,7 +73,7 @@ final class FileContextMenu extends ContextMenu {
|
|||
var execute = new MenuItem("Run in terminal");
|
||||
execute.setOnAction(event -> {
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
ShellProcessControl pc =
|
||||
ShellControl pc =
|
||||
model.getFileSystem().getShell().orElseThrow();
|
||||
pc.executeBooleanSimpleCommand(pc.getShellDialect().getMakeExecutableCommand(entry.getPath()));
|
||||
var cmd = pc.command("\"" + entry.getPath() + "\"").prepareTerminalOpen();
|
||||
|
@ -86,7 +86,7 @@ final class FileContextMenu extends ContextMenu {
|
|||
var executeInBackground = new MenuItem("Run in background");
|
||||
executeInBackground.setOnAction(event -> {
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
ShellProcessControl pc =
|
||||
ShellControl pc =
|
||||
model.getFileSystem().getShell().orElseThrow();
|
||||
pc.executeBooleanSimpleCommand(pc.getShellDialect().getMakeExecutableCommand(entry.getPath()));
|
||||
var cmd = ScriptHelper.createDetachCommand(pc, "\"" + entry.getPath() + "\"");
|
||||
|
|
|
@ -178,9 +178,9 @@ final class OpenFileSystemModel {
|
|||
|
||||
var current = !(fileSystem instanceof LocalStore) && fs instanceof ConnectionFileSystem connectionFileSystem
|
||||
? connectionFileSystem
|
||||
.getShellProcessControl()
|
||||
.getShellControl()
|
||||
.executeStringSimpleCommand(connectionFileSystem
|
||||
.getShellProcessControl()
|
||||
.getShellControl()
|
||||
.getShellDialect()
|
||||
.getPrintWorkingDirectoryCommand())
|
||||
: null;
|
||||
|
@ -199,7 +199,7 @@ final class OpenFileSystemModel {
|
|||
ThreadHelper.runFailableAsync(() -> {
|
||||
BusyProperty.execute(busy, () -> {
|
||||
if (store.getValue() instanceof ShellStore s) {
|
||||
var connection = ((ConnectionFileSystem) fileSystem).getShellProcessControl();
|
||||
var connection = ((ConnectionFileSystem) fileSystem).getShellControl();
|
||||
var command = s.create()
|
||||
.initWith(List.of(connection.getShellDialect().getCdCommand(directory)))
|
||||
.prepareTerminalOpen();
|
||||
|
|
|
@ -8,6 +8,7 @@ import io.xpipe.app.fxcomps.util.PlatformThread;
|
|||
import javafx.application.Platform;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
|
@ -16,7 +17,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class ListBoxViewComp<T> extends Comp<CompStructure<VBox>> {
|
||||
public class ListBoxViewComp<T> extends Comp<CompStructure<ScrollPane>> {
|
||||
|
||||
private final ObservableList<T> shown;
|
||||
private final ObservableList<T> all;
|
||||
|
@ -29,7 +30,7 @@ public class ListBoxViewComp<T> extends Comp<CompStructure<VBox>> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public CompStructure<VBox> createBase() {
|
||||
public CompStructure<ScrollPane> createBase() {
|
||||
Map<T, Region> cache = new HashMap<>();
|
||||
|
||||
VBox listView = new VBox();
|
||||
|
@ -46,7 +47,11 @@ public class ListBoxViewComp<T> extends Comp<CompStructure<VBox>> {
|
|||
cache.keySet().retainAll(c.getList());
|
||||
});
|
||||
|
||||
return new SimpleCompStructure<>(listView);
|
||||
var scroll = new ScrollPane(listView);
|
||||
scroll.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
|
||||
scroll.setFitToWidth(true);
|
||||
|
||||
return new SimpleCompStructure<>(scroll);
|
||||
}
|
||||
|
||||
private void refresh(VBox listView, List<? extends T> c, Map<T, Region> cache, boolean asynchronous) {
|
||||
|
|
|
@ -24,6 +24,7 @@ public class ListSelectorComp<T> extends SimpleComp {
|
|||
@Override
|
||||
protected Region createSimple() {
|
||||
var vbox = new VBox();
|
||||
vbox.setSpacing(8);
|
||||
vbox.getStyleClass().add("content");
|
||||
for (var v : values) {
|
||||
var cb = new CheckBox(null);
|
||||
|
|
|
@ -25,7 +25,6 @@ import io.xpipe.app.util.*;
|
|||
import io.xpipe.core.store.DataStore;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.*;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.Separator;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
|
@ -160,10 +159,11 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
|
|||
}
|
||||
|
||||
private Region createStoreProperties(Comp<?> comp, Validator propVal) {
|
||||
return new DynamicOptionsBuilder(false)
|
||||
.addComp((ObservableValue<String>) null, comp, input)
|
||||
.addTitle(AppI18n.observable("properties"))
|
||||
.addString(AppI18n.observable("name"), name, false)
|
||||
return new OptionsBuilder()
|
||||
.addComp(comp, input)
|
||||
.name("connectionName")
|
||||
.description("connectionNameDescription")
|
||||
.addString(name, false)
|
||||
.nonNull(propVal)
|
||||
.bind(
|
||||
() -> {
|
||||
|
@ -218,6 +218,11 @@ public class GuiDsStoreCreator extends MultiStepComp.Step<CompStructure<?>> {
|
|||
return new LoadingOverlayComp(Comp.of(() -> layout), busy).createStructure();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onContinue() {
|
||||
ScanAlert.showIfNeeded(entry.getValue().getStore());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canContinue() {
|
||||
if (provider.getValue() != null) {
|
||||
|
|
|
@ -66,7 +66,7 @@ public class AppGreetings {
|
|||
}
|
||||
|
||||
public static void showIfNeeded() {
|
||||
//TODO
|
||||
// TODO
|
||||
if (!AppProperties.get().isImage() || true) {
|
||||
return;
|
||||
}
|
||||
|
@ -113,6 +113,7 @@ public class AppGreetings {
|
|||
var button = alert.getDialogPane().lookupButton(buttonType);
|
||||
button.disableProperty().bind(accepted.not());
|
||||
},
|
||||
null,
|
||||
r -> r.filter(b -> b.getButtonData().isDefaultButton() && accepted.get())
|
||||
.ifPresentOrElse(
|
||||
t -> {
|
||||
|
|
|
@ -7,6 +7,7 @@ import io.xpipe.app.issue.TrackEvent;
|
|||
import io.xpipe.app.prefs.AppPrefs;
|
||||
import io.xpipe.app.prefs.SupportedLocale;
|
||||
import io.xpipe.app.util.DynamicOptionsBuilder;
|
||||
import io.xpipe.app.util.OptionsBuilder;
|
||||
import io.xpipe.app.util.Translatable;
|
||||
import io.xpipe.core.util.ModuleHelper;
|
||||
import javafx.beans.binding.Bindings;
|
||||
|
@ -131,6 +132,7 @@ private static AppI18n INSTANCE = new AppI18n();
|
|||
|| caller.equals(FancyTooltipAugment.class)
|
||||
|| caller.equals(PrefsChoiceValue.class)
|
||||
|| caller.equals(Translatable.class)
|
||||
|| caller.equals(OptionsBuilder.class)
|
||||
|| caller.equals(DynamicOptionsBuilder.class)) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ public class AppWindowHelper {
|
|||
childStage.setY(stage.getY() + stage.getHeight() / 2 - childStage.getHeight() / 2);
|
||||
}
|
||||
|
||||
public static void showAlert(Consumer<Alert> c, Consumer<Optional<ButtonType>> bt) {
|
||||
public static void showAlert(Consumer<Alert> c, ObservableValue<Boolean> loading, Consumer<Optional<ButtonType>> bt) {
|
||||
ThreadHelper.runAsync(() -> {
|
||||
var r = showBlockingAlert(c);
|
||||
if (bt != null) {
|
||||
|
|
49
app/src/main/java/io/xpipe/app/ext/ScanProvider.java
Normal file
49
app/src/main/java/io/xpipe/app/ext/ScanProvider.java
Normal file
|
@ -0,0 +1,49 @@
|
|||
package io.xpipe.app.ext;
|
||||
|
||||
import io.xpipe.core.store.DataStore;
|
||||
import io.xpipe.core.util.ModuleLayerLoader;
|
||||
import lombok.Value;
|
||||
import org.apache.commons.lang3.function.FailableRunnable;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public abstract class ScanProvider {
|
||||
|
||||
@Value
|
||||
public static class ScanOperation {
|
||||
String nameKey;
|
||||
FailableRunnable<Exception> scanner;
|
||||
}
|
||||
|
||||
private static List<ScanProvider> ALL;
|
||||
|
||||
public static class Loader implements ModuleLayerLoader {
|
||||
|
||||
@Override
|
||||
public void init(ModuleLayer layer) {
|
||||
ALL = ServiceLoader.load(layer, ScanProvider.class).stream()
|
||||
.map(ServiceLoader.Provider::get)
|
||||
.sorted(Comparator.comparing(scanProvider -> scanProvider.getClass().getName()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requiresFullDaemon() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean prioritizeLoading() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<ScanProvider> getAll() {
|
||||
return ALL;
|
||||
}
|
||||
|
||||
public abstract ScanOperation create(DataStore store);
|
||||
}
|
163
app/src/main/java/io/xpipe/app/fxcomps/impl/OptionsComp.java
Normal file
163
app/src/main/java/io/xpipe/app/fxcomps/impl/OptionsComp.java
Normal file
|
@ -0,0 +1,163 @@
|
|||
package io.xpipe.app.fxcomps.impl;
|
||||
|
||||
import atlantafx.base.controls.Popover;
|
||||
import atlantafx.base.controls.Spacer;
|
||||
import io.xpipe.app.core.AppFont;
|
||||
import io.xpipe.app.fxcomps.Comp;
|
||||
import io.xpipe.app.fxcomps.CompStructure;
|
||||
import io.xpipe.app.fxcomps.SimpleCompStructure;
|
||||
import io.xpipe.app.fxcomps.util.PlatformThread;
|
||||
import javafx.beans.Observable;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.geometry.Orientation;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class OptionsComp extends Comp<CompStructure<Pane>> {
|
||||
|
||||
private final List<OptionsComp.Entry> entries;
|
||||
|
||||
public OptionsComp(List<OptionsComp.Entry> entries) {
|
||||
this.entries = entries;
|
||||
}
|
||||
|
||||
public OptionsComp.Entry queryEntry(String key) {
|
||||
return entries.stream()
|
||||
.filter(entry -> entry.key != null && entry.key.equals(key))
|
||||
.findAny()
|
||||
.orElseThrow();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompStructure<Pane> createBase() {
|
||||
Pane pane;
|
||||
var content = new VBox();
|
||||
content.setSpacing(7);
|
||||
pane = content;
|
||||
pane.getStyleClass().add("options-comp");
|
||||
|
||||
var nameRegions = new ArrayList<Region>();
|
||||
var compRegions = new ArrayList<Region>();
|
||||
|
||||
for (var entry : getEntries()) {
|
||||
Region compRegion = null;
|
||||
if (entry.comp() != null) {
|
||||
compRegion = entry.comp().createRegion();
|
||||
}
|
||||
|
||||
if (entry.name() != null && entry.description() != null) {
|
||||
var line = new VBox();
|
||||
line.prefWidthProperty().bind(pane.widthProperty());
|
||||
line.setSpacing(5);
|
||||
|
||||
var name = new Label();
|
||||
name.getStyleClass().add("name");
|
||||
name.textProperty().bind(entry.name());
|
||||
name.setMinWidth(Region.USE_PREF_SIZE);
|
||||
name.setAlignment(Pos.CENTER_LEFT);
|
||||
if (compRegion != null) {
|
||||
name.visibleProperty().bind(PlatformThread.sync(compRegion.visibleProperty()));
|
||||
name.managedProperty().bind(PlatformThread.sync(compRegion.managedProperty()));
|
||||
}
|
||||
line.getChildren().add(name);
|
||||
|
||||
var description = new Label();
|
||||
description.setWrapText(true);
|
||||
description.getStyleClass().add("description");
|
||||
description.textProperty().bind(entry.description());
|
||||
description.setAlignment(Pos.CENTER_LEFT);
|
||||
if (compRegion != null) {
|
||||
description.visibleProperty().bind(PlatformThread.sync(compRegion.visibleProperty()));
|
||||
description.managedProperty().bind(PlatformThread.sync(compRegion.managedProperty()));
|
||||
}
|
||||
|
||||
if (entry.longDescription() != null) {
|
||||
var popover = new Popover(new Label(entry.longDescription().getValue()));
|
||||
popover.setCloseButtonEnabled(false);
|
||||
popover.setHeaderAlwaysVisible(false);
|
||||
popover.setDetachable(true);
|
||||
AppFont.small(popover.getContentNode());
|
||||
|
||||
var descriptionHover = new Label("?");
|
||||
AppFont.header(descriptionHover);
|
||||
descriptionHover.setOnMouseClicked(e -> popover.show(descriptionHover));
|
||||
|
||||
var descriptionBox = new HBox(description, new Spacer(Orientation.HORIZONTAL), descriptionHover);
|
||||
HBox.setHgrow(descriptionBox, Priority.ALWAYS);
|
||||
descriptionBox.setAlignment(Pos.CENTER_LEFT);
|
||||
line.getChildren().add(descriptionBox);
|
||||
}else {
|
||||
line.getChildren().add(description);
|
||||
}
|
||||
|
||||
if (compRegion != null) {
|
||||
line.getChildren().add(compRegion);
|
||||
}
|
||||
|
||||
pane.getChildren().add(line);
|
||||
}
|
||||
|
||||
else if (entry.name() != null) {
|
||||
var line = new HBox();
|
||||
line.setFillHeight(true);
|
||||
line.prefWidthProperty().bind(pane.widthProperty());
|
||||
line.setSpacing(8);
|
||||
|
||||
var name = new Label();
|
||||
name.textProperty().bind(entry.name());
|
||||
name.prefHeightProperty().bind(line.heightProperty());
|
||||
name.setMinWidth(Region.USE_PREF_SIZE);
|
||||
name.setAlignment(Pos.CENTER_LEFT);
|
||||
if (compRegion != null) {
|
||||
name.visibleProperty().bind(PlatformThread.sync(compRegion.visibleProperty()));
|
||||
name.managedProperty().bind(PlatformThread.sync(compRegion.managedProperty()));
|
||||
}
|
||||
nameRegions.add(name);
|
||||
line.getChildren().add(name);
|
||||
|
||||
if (compRegion != null) {
|
||||
compRegions.add(compRegion);
|
||||
line.getChildren().add(compRegion);
|
||||
HBox.setHgrow(compRegion, Priority.ALWAYS);
|
||||
}
|
||||
|
||||
pane.getChildren().add(line);
|
||||
} else {
|
||||
if (compRegion != null) {
|
||||
compRegions.add(compRegion);
|
||||
pane.getChildren().add(compRegion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (entries.stream().anyMatch(entry -> entry.name() != null && entry.description() == null)) {
|
||||
var nameWidthBinding = Bindings.createDoubleBinding(
|
||||
() -> {
|
||||
if (nameRegions.stream().anyMatch(r -> r.getWidth() == 0)) {
|
||||
return Region.USE_COMPUTED_SIZE;
|
||||
}
|
||||
|
||||
var m = nameRegions.stream()
|
||||
.map(Region::getWidth)
|
||||
.max(Double::compareTo)
|
||||
.orElse(0.0);
|
||||
return m;
|
||||
},
|
||||
nameRegions.stream().map(Region::widthProperty).toList().toArray(new Observable[0]));
|
||||
nameRegions.forEach(r -> r.prefWidthProperty().bind(nameWidthBinding));
|
||||
}
|
||||
|
||||
return new SimpleCompStructure<>(pane);
|
||||
}
|
||||
|
||||
public List<OptionsComp.Entry> getEntries() {
|
||||
return entries;
|
||||
}
|
||||
|
||||
public record Entry(String key, ObservableValue<String> description, ObservableValue<String> longDescription, ObservableValue<String> name, Comp<?> comp) {}
|
||||
}
|
|
@ -4,7 +4,7 @@ import io.xpipe.app.ext.PrefsChoiceValue;
|
|||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import io.xpipe.core.impl.LocalStore;
|
||||
import io.xpipe.core.process.OsType;
|
||||
import io.xpipe.core.process.ShellProcessControl;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
@ -37,7 +37,7 @@ public abstract class ExternalApplicationType implements PrefsChoiceValue {
|
|||
}
|
||||
|
||||
protected Optional<Path> getApplicationPath() {
|
||||
try (ShellProcessControl pc = LocalStore.getShell().start()) {
|
||||
try (ShellControl pc = LocalStore.getShell().start()) {
|
||||
try (var c = pc.command(String.format(
|
||||
"/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister "
|
||||
+ "-dump | grep -o \"/.*%s.app\" | grep -v -E \"Caches|TimeMachine|Temporary|/Volumes/%s\" | uniq",
|
||||
|
@ -76,7 +76,7 @@ public abstract class ExternalApplicationType implements PrefsChoiceValue {
|
|||
}
|
||||
|
||||
public boolean isAvailable() {
|
||||
try (ShellProcessControl pc = LocalStore.getShell()) {
|
||||
try (ShellControl pc = LocalStore.getShell()) {
|
||||
return pc.executeBooleanSimpleCommand(pc.getShellDialect().getWhichCommand(executable));
|
||||
} catch (Exception e) {
|
||||
ErrorEvent.fromThrowable(e).omit().handle();
|
||||
|
|
|
@ -6,7 +6,7 @@ import io.xpipe.app.util.ApplicationHelper;
|
|||
import io.xpipe.app.util.MacOsPermissions;
|
||||
import io.xpipe.core.impl.LocalStore;
|
||||
import io.xpipe.core.process.OsType;
|
||||
import io.xpipe.core.process.ShellProcessControl;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -133,7 +133,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
|
||||
@Override
|
||||
public void launch(String name, String command) throws Exception {
|
||||
try (ShellProcessControl pc = LocalStore.getShell()) {
|
||||
try (ShellControl pc = LocalStore.getShell()) {
|
||||
var suffix = command.equals(pc.getShellDialect().getNormalOpenCommand())
|
||||
? "\"\""
|
||||
: "\"" + command.replaceAll("\"", "\\\\\"") + "\"";
|
||||
|
@ -187,7 +187,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
|
||||
@Override
|
||||
public void launch(String name, String command) throws Exception {
|
||||
try (ShellProcessControl pc = LocalStore.getShell()) {
|
||||
try (ShellControl pc = LocalStore.getShell()) {
|
||||
var cmd = String.format(
|
||||
"""
|
||||
osascript - "$@" <<EOF
|
||||
|
@ -225,7 +225,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
return;
|
||||
}
|
||||
|
||||
try (ShellProcessControl pc = LocalStore.getShell()) {
|
||||
try (ShellControl pc = LocalStore.getShell()) {
|
||||
var cmd = String.format(
|
||||
"""
|
||||
osascript - "$@" <<EOF
|
||||
|
@ -258,7 +258,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
|
||||
@Override
|
||||
public void launch(String name, String command) throws Exception {
|
||||
try (ShellProcessControl pc = LocalStore.getShell()) {
|
||||
try (ShellControl pc = LocalStore.getShell()) {
|
||||
ApplicationHelper.checkSupport(pc, executable, displayName);
|
||||
|
||||
var toExecute = executable + " " + toCommand(name, command);
|
||||
|
@ -274,7 +274,7 @@ public interface ExternalTerminalType extends PrefsChoiceValue {
|
|||
protected abstract String toCommand(String name, String command);
|
||||
|
||||
public boolean isAvailable() {
|
||||
try (ShellProcessControl pc = LocalStore.getShell()) {
|
||||
try (ShellControl pc = LocalStore.getShell()) {
|
||||
return pc.executeBooleanSimpleCommand(pc.getShellDialect().getWhichCommand(executable));
|
||||
} catch (Exception e) {
|
||||
ErrorEvent.fromThrowable(e).omit().handle();
|
||||
|
|
|
@ -53,6 +53,8 @@ public abstract class DataStorage {
|
|||
INSTANCE = shouldPersist() ? new StandardStorage() : new ImpersistentStorage();
|
||||
INSTANCE.load();
|
||||
|
||||
INSTANCE.storeEntries.forEach(entry -> entry.simpleRefresh());
|
||||
|
||||
DataStoreProviders.getAll().forEach(dataStoreProvider -> {
|
||||
try {
|
||||
dataStoreProvider.storageInit();
|
||||
|
@ -115,6 +117,21 @@ public abstract class DataStorage {
|
|||
return createUniqueSourceEntryName(col, typeName);
|
||||
}
|
||||
|
||||
private String createUniqueStoreEntryName(String base) {
|
||||
if (DataStorage.get().getStoreIfPresent(base).isEmpty()) {
|
||||
return base;
|
||||
}
|
||||
|
||||
int counter = 1;
|
||||
while (true) {
|
||||
var name = base + counter;
|
||||
if (DataStorage.get().getStoreIfPresent(name).isEmpty()) {
|
||||
return name;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
private String createUniqueSourceEntryName(DataSourceCollection col, String base) {
|
||||
base = DataSourceId.cleanString(base);
|
||||
var id = DataSourceId.create(col != null ? col.getName() : null, base);
|
||||
|
@ -345,7 +362,7 @@ public abstract class DataStorage {
|
|||
}
|
||||
|
||||
public DataStoreEntry addStore(@NonNull String name, DataStore store) {
|
||||
var e = DataStoreEntry.createNew(UUID.randomUUID(), name, store);
|
||||
var e = DataStoreEntry.createNew(UUID.randomUUID(), createUniqueStoreEntryName(name), store);
|
||||
addStore(e);
|
||||
return e;
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@ import com.fasterxml.jackson.annotation.JsonTypeName;
|
|||
import io.xpipe.app.util.ScriptHelper;
|
||||
import io.xpipe.app.util.TerminalHelper;
|
||||
import io.xpipe.core.impl.FileNames;
|
||||
import io.xpipe.core.process.CommandProcessControl;
|
||||
import io.xpipe.core.process.CommandControl;
|
||||
import io.xpipe.core.process.OsType;
|
||||
import io.xpipe.core.process.ShellProcessControl;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
import io.xpipe.core.process.ShellDialects;
|
||||
import io.xpipe.core.store.ShellStore;
|
||||
import io.xpipe.core.util.XPipeInstallation;
|
||||
|
@ -22,7 +22,7 @@ import java.util.List;
|
|||
|
||||
public class AppInstaller {
|
||||
|
||||
public static void installOnRemoteMachine(ShellProcessControl s, String version) throws Exception {
|
||||
public static void installOnRemoteMachine(ShellControl s, String version) throws Exception {
|
||||
var asset = getSuitablePlatformAsset(s);
|
||||
var file = AppDownloads.downloadInstaller(asset, version);
|
||||
installFile(s, asset, file);
|
||||
|
@ -32,14 +32,14 @@ public class AppInstaller {
|
|||
asset.installLocal(localFile.toString());
|
||||
}
|
||||
|
||||
public static void installFile(ShellProcessControl s, InstallerAssetType asset, Path localFile) throws Exception {
|
||||
public static void installFile(ShellControl s, InstallerAssetType asset, Path localFile) throws Exception {
|
||||
String targetFile = null;
|
||||
if (s.isLocal()) {
|
||||
targetFile = localFile.toString();
|
||||
} else {
|
||||
targetFile = FileNames.join(
|
||||
s.getTemporaryDirectory(), localFile.getFileName().toString());
|
||||
try (CommandProcessControl c = s.getShellDialect().getStreamFileWriteCommand(s, targetFile)
|
||||
try (CommandControl c = s.getShellDialect().getStreamFileWriteCommand(s, targetFile)
|
||||
.start()) {
|
||||
c.discardOut();
|
||||
c.discardErr();
|
||||
|
@ -73,13 +73,13 @@ public class AppInstaller {
|
|||
throw new AssertionError();
|
||||
}
|
||||
|
||||
public static InstallerAssetType getSuitablePlatformAsset(ShellProcessControl p) throws Exception {
|
||||
public static InstallerAssetType getSuitablePlatformAsset(ShellControl p) throws Exception {
|
||||
if (p.getOsType().equals(OsType.WINDOWS)) {
|
||||
return new InstallerAssetType.Msi();
|
||||
}
|
||||
|
||||
if (p.getOsType().equals(OsType.LINUX)) {
|
||||
try (CommandProcessControl c = p.command(p.getShellDialect().getFileExistsCommand("/etc/debian_version"))
|
||||
try (CommandControl c = p.command(p.getShellDialect().getFileExistsCommand("/etc/debian_version"))
|
||||
.start()) {
|
||||
return c.discardAndCheckExit() ? new InstallerAssetType.Debian() : new InstallerAssetType.Rpm();
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ public class AppInstaller {
|
|||
})
|
||||
public abstract static class InstallerAssetType {
|
||||
|
||||
public abstract void installRemote(ShellProcessControl pc, String file) throws Exception;
|
||||
public abstract void installRemote(ShellControl pc, String file) throws Exception;
|
||||
|
||||
public abstract void installLocal(String file) throws Exception;
|
||||
|
||||
|
@ -121,11 +121,11 @@ public class AppInstaller {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void installRemote(ShellProcessControl shellProcessControl, String file) throws Exception {
|
||||
public void installRemote(ShellControl shellControl, String file) throws Exception {
|
||||
var exec = XPipeInstallation.getInstallationExecutable(
|
||||
shellProcessControl,
|
||||
XPipeInstallation.getDefaultInstallationBasePath(shellProcessControl, false));
|
||||
var logsDir = FileNames.join(XPipeInstallation.getDataBasePath(shellProcessControl), "logs");
|
||||
shellControl,
|
||||
XPipeInstallation.getDefaultInstallationBasePath(shellControl, false));
|
||||
var logsDir = FileNames.join(XPipeInstallation.getDataBasePath(shellControl), "logs");
|
||||
var cmd = new ArrayList<>(java.util.List.of(
|
||||
"start",
|
||||
"/wait",
|
||||
|
@ -139,7 +139,7 @@ public class AppInstaller {
|
|||
exec
|
||||
// "/qf"
|
||||
));
|
||||
try (CommandProcessControl c = shellProcessControl.command(cmd).start()) {
|
||||
try (CommandControl c = shellControl.command(cmd).start()) {
|
||||
c.discardOrThrow();
|
||||
}
|
||||
}
|
||||
|
@ -177,14 +177,14 @@ public class AppInstaller {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void installRemote(ShellProcessControl shellProcessControl, String file) throws Exception {
|
||||
try (var pc = shellProcessControl.subShell(ShellDialects.BASH).start()) {
|
||||
try (CommandProcessControl c = pc.command("DEBIAN_FRONTEND=noninteractive apt-get remove -qy xpipe")
|
||||
public void installRemote(ShellControl shellControl, String file) throws Exception {
|
||||
try (var pc = shellControl.subShell(ShellDialects.BASH).start()) {
|
||||
try (CommandControl c = pc.command("DEBIAN_FRONTEND=noninteractive apt-get remove -qy xpipe")
|
||||
.elevated()
|
||||
.start()) {
|
||||
c.discardOrThrow();
|
||||
}
|
||||
try (CommandProcessControl c = pc.command(
|
||||
try (CommandControl c = pc.command(
|
||||
"DEBIAN_FRONTEND=noninteractive apt-get install -qy \"" + file + "\"")
|
||||
.elevated()
|
||||
.start()) {
|
||||
|
@ -214,9 +214,9 @@ public class AppInstaller {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void installRemote(ShellProcessControl shellProcessControl, String file) throws Exception {
|
||||
try (var pc = shellProcessControl.subShell(ShellDialects.BASH).start()) {
|
||||
try (CommandProcessControl c = pc.command("rpm -U -v --force \"" + file + "\"")
|
||||
public void installRemote(ShellControl shellControl, String file) throws Exception {
|
||||
try (var pc = shellControl.subShell(ShellDialects.BASH).start()) {
|
||||
try (CommandControl c = pc.command("rpm -U -v --force \"" + file + "\"")
|
||||
.elevated()
|
||||
.start()) {
|
||||
c.discardOrThrow();
|
||||
|
@ -244,9 +244,9 @@ public class AppInstaller {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void installRemote(ShellProcessControl shellProcessControl, String file) throws Exception {
|
||||
try (var pc = shellProcessControl.subShell(ShellDialects.BASH).start()) {
|
||||
try (CommandProcessControl c = pc.command(
|
||||
public void installRemote(ShellControl shellControl, String file) throws Exception {
|
||||
try (var pc = shellControl.subShell(ShellDialects.BASH).start()) {
|
||||
try (CommandControl c = pc.command(
|
||||
"installer -verboseR -allowUntrusted -pkg \"" + file + "\" -target /")
|
||||
.elevated()
|
||||
.start()) {
|
||||
|
|
|
@ -38,7 +38,7 @@ public class UpdateChangelogAlert {
|
|||
alert.getDialogPane().setContent(markdown);
|
||||
|
||||
alert.getButtonTypes().add(new ButtonType(AppI18n.get("gotIt"), ButtonBar.ButtonData.OK_DONE));
|
||||
},
|
||||
},null,
|
||||
r -> r.filter(b -> b.getButtonData().isDefaultButton()).ifPresent(t -> {}));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ 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.ShellProcessControl;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
@ -30,12 +30,12 @@ public class ApplicationHelper {
|
|||
}
|
||||
}
|
||||
|
||||
public static boolean isInPath(ShellProcessControl processControl, String executable) throws Exception {
|
||||
public static boolean isInPath(ShellControl processControl, String executable) throws Exception {
|
||||
return processControl.executeBooleanSimpleCommand(
|
||||
processControl.getShellDialect().getWhichCommand(executable));
|
||||
}
|
||||
|
||||
public static void checkSupport(ShellProcessControl processControl, String executable, String displayName)
|
||||
public static void checkSupport(ShellControl processControl, String executable, String displayName)
|
||||
throws Exception {
|
||||
if (!isInPath(processControl, executable)) {
|
||||
throw new IOException(displayName + " executable " + executable + " not found in PATH");
|
||||
|
|
|
@ -38,7 +38,7 @@ public class MacOsPermissions {
|
|||
a.getDialogPane().setContent(AppWindowHelper.alertContentText(AppI18n.get("permissionsAlertTitleContent")));
|
||||
a.getButtonTypes().clear();
|
||||
alert.set(a);
|
||||
}, buttonType -> {
|
||||
}, null, buttonType -> {
|
||||
alert.get().close();
|
||||
if (buttonType.isEmpty() || !buttonType.get().getButtonData().isDefaultButton()) {
|
||||
state.set(false);
|
||||
|
|
166
app/src/main/java/io/xpipe/app/util/OptionsBuilder.java
Normal file
166
app/src/main/java/io/xpipe/app/util/OptionsBuilder.java
Normal file
|
@ -0,0 +1,166 @@
|
|||
package io.xpipe.app.util;
|
||||
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.fxcomps.Comp;
|
||||
import io.xpipe.app.fxcomps.impl.*;
|
||||
import io.xpipe.core.util.SecretValue;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.Region;
|
||||
import net.synedra.validatorfx.Check;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class OptionsBuilder {
|
||||
|
||||
private final List<OptionsComp.Entry> entries = new ArrayList<>();
|
||||
private final List<Property<?>> props = new ArrayList<>();
|
||||
|
||||
private ObservableValue<String> name;
|
||||
private ObservableValue<String> description;
|
||||
private ObservableValue<String> longDescription;
|
||||
private Comp<?> comp;
|
||||
|
||||
private void finishCurrent() {
|
||||
if (comp == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var entry = new OptionsComp.Entry(null, description, longDescription, name, comp);
|
||||
description = null;
|
||||
longDescription = null;
|
||||
name = null;
|
||||
comp = null;
|
||||
entries.add(entry);
|
||||
}
|
||||
|
||||
public OptionsBuilder addTitle(String titleKey) {
|
||||
finishCurrent();
|
||||
entries.add(new OptionsComp.Entry(
|
||||
titleKey, null, null, null, new LabelComp(AppI18n.observable(titleKey)).styleClass("title-header")));
|
||||
return this;
|
||||
}
|
||||
|
||||
public OptionsBuilder addTitle(ObservableValue<String> title) {
|
||||
finishCurrent();
|
||||
entries.add(new OptionsComp.Entry(
|
||||
null, null, null, null, Comp.of(() -> new Label(title.getValue())).styleClass("title-header")));
|
||||
return this;
|
||||
}
|
||||
|
||||
public OptionsBuilder decorate(Check c) {
|
||||
comp.apply(s -> c.decorates(s.get()));
|
||||
return this;
|
||||
}
|
||||
|
||||
public OptionsBuilder nonNull(Validator v) {
|
||||
var e = name;
|
||||
var p = props.get(props.size() - 1);
|
||||
return decorate(Validator.nonNull(v, e, p));
|
||||
}
|
||||
|
||||
private void pushComp(Comp<?> comp) {
|
||||
finishCurrent();
|
||||
this.comp = comp;
|
||||
}
|
||||
|
||||
public OptionsBuilder stringArea(Property<String> prop, boolean lazy) {
|
||||
var comp = new TextAreaComp(prop, lazy);
|
||||
pushComp(comp);
|
||||
props.add(prop);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OptionsBuilder addInteger(Property<Integer> prop) {
|
||||
var comp = new IntFieldComp(prop);
|
||||
pushComp(comp);
|
||||
props.add(prop);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OptionsBuilder addString(Property<String> prop) {
|
||||
return addString(prop, false);
|
||||
}
|
||||
public OptionsBuilder addString(Property<String> prop, boolean lazy) {
|
||||
var comp = new TextFieldComp(prop, lazy);
|
||||
pushComp(comp);
|
||||
props.add(prop);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public OptionsBuilder name(String nameKey) {
|
||||
finishCurrent();
|
||||
name = AppI18n.observable(nameKey);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OptionsBuilder description(String descriptionKey) {
|
||||
finishCurrent();
|
||||
description = AppI18n.observable(descriptionKey);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OptionsBuilder longDescription(String descriptionKey) {
|
||||
finishCurrent();
|
||||
longDescription = AppI18n.observable(descriptionKey);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OptionsBuilder addComp(Comp<?> comp) {
|
||||
pushComp(comp);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OptionsBuilder addComp(Comp<?> comp, Property<?> prop) {
|
||||
pushComp(comp);
|
||||
props.add(prop);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OptionsBuilder addSecret(Property<SecretValue> prop) {
|
||||
var comp = new SecretFieldComp(prop);
|
||||
pushComp(comp);
|
||||
props.add(prop);
|
||||
return this;
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public final <T, V extends T> OptionsBuilder bind(Supplier<V> creator, Property<T>... toSet) {
|
||||
props.forEach(prop -> {
|
||||
prop.addListener((c, o, n) -> {
|
||||
for (Property<T> p : toSet) {
|
||||
p.setValue(creator.get());
|
||||
}
|
||||
});
|
||||
});
|
||||
for (Property<T> p : toSet) {
|
||||
p.setValue(creator.get());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public final <T, V extends T> OptionsBuilder bindChoice(
|
||||
Supplier<Property<? extends V>> creator, Property<T> toSet) {
|
||||
props.forEach(prop -> {
|
||||
prop.addListener((c, o, n) -> {
|
||||
toSet.unbind();
|
||||
toSet.bind(creator.get());
|
||||
});
|
||||
});
|
||||
toSet.bind(creator.get());
|
||||
return this;
|
||||
}
|
||||
|
||||
public OptionsComp buildComp() {
|
||||
finishCurrent();
|
||||
return new OptionsComp(entries);
|
||||
}
|
||||
|
||||
public Region build() {
|
||||
return buildComp().createRegion();
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ import io.xpipe.app.prefs.AppPrefs;
|
|||
import io.xpipe.app.update.AppDownloads;
|
||||
import io.xpipe.app.update.AppInstaller;
|
||||
import io.xpipe.core.impl.FileNames;
|
||||
import io.xpipe.core.process.ShellProcessControl;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
import io.xpipe.core.util.ModuleHelper;
|
||||
import io.xpipe.core.util.ProxyManagerProvider;
|
||||
import io.xpipe.core.util.XPipeInstallation;
|
||||
|
@ -31,7 +31,7 @@ public class ProxyManagerProviderImpl extends ProxyManagerProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> checkCompatibility(ShellProcessControl s) throws Exception {
|
||||
public Optional<String> checkCompatibility(ShellControl s) throws Exception {
|
||||
var version = ModuleHelper.isImage() ? AppProperties.get().getVersion() : AppDownloads.getLatestVersion();
|
||||
|
||||
if (AppPrefs.get().developerDisableConnectorInstallationVersionCheck().get()) {
|
||||
|
@ -54,7 +54,7 @@ public class ProxyManagerProviderImpl extends ProxyManagerProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean setup(ShellProcessControl s) throws Exception {
|
||||
public boolean setup(ShellControl s) throws Exception {
|
||||
var message = checkCompatibility(s);
|
||||
if (message.isPresent()) {
|
||||
if (showAlert()) {
|
||||
|
|
64
app/src/main/java/io/xpipe/app/util/ScanAlert.java
Normal file
64
app/src/main/java/io/xpipe/app/util/ScanAlert.java
Normal file
|
@ -0,0 +1,64 @@
|
|||
package io.xpipe.app.util;
|
||||
|
||||
import io.xpipe.app.comp.base.ListSelectorComp;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.core.AppWindowHelper;
|
||||
import io.xpipe.app.ext.ScanProvider;
|
||||
import io.xpipe.app.fxcomps.impl.LabelComp;
|
||||
import io.xpipe.app.fxcomps.impl.VerticalComp;
|
||||
import io.xpipe.app.issue.ErrorEvent;
|
||||
import io.xpipe.core.store.DataStore;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.property.SimpleListProperty;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.ButtonType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ScanAlert {
|
||||
|
||||
public static void showIfNeeded(DataStore store) {
|
||||
var providers = ScanProvider.getAll();
|
||||
var applicable = providers.stream()
|
||||
.map(scanProvider -> scanProvider.create(store))
|
||||
.filter(scanOperation -> scanOperation != null)
|
||||
.toList();
|
||||
if (applicable.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var selected = new SimpleListProperty<ScanProvider.ScanOperation>(
|
||||
FXCollections.observableList(new ArrayList<>(applicable)));
|
||||
var busy = new SimpleBooleanProperty();
|
||||
AppWindowHelper.showAlert(
|
||||
alert -> {
|
||||
alert.setAlertType(Alert.AlertType.NONE);
|
||||
alert.setTitle(AppI18n.get("scanAlertTitle"));
|
||||
alert.setWidth(300);
|
||||
var content = new VerticalComp(List.of(
|
||||
new LabelComp(AppI18n.get("scanAlertHeader")).apply(struc -> struc.get().setWrapText(true)),
|
||||
new ListSelectorComp<>(
|
||||
applicable, scanOperation -> AppI18n.get(scanOperation.getNameKey()), selected)))
|
||||
.apply(struc -> struc.get().setSpacing(15))
|
||||
.styleClass("window-content")
|
||||
.createRegion();
|
||||
alert.getButtonTypes().add(ButtonType.OK);
|
||||
alert.getDialogPane().setContent(content);
|
||||
},
|
||||
busy,
|
||||
buttonType -> {
|
||||
if (buttonType.isPresent()
|
||||
&& buttonType.get().getButtonData().isDefaultButton()) {
|
||||
try (var ignored = new BusyProperty(busy)) {
|
||||
for (var a : applicable) {
|
||||
a.getScanner().run();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
ErrorEvent.fromThrowable(ex).handle();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ import io.xpipe.core.impl.LocalStore;
|
|||
import io.xpipe.core.process.OsType;
|
||||
import io.xpipe.core.process.ShellDialect;
|
||||
import io.xpipe.core.process.ShellDialects;
|
||||
import io.xpipe.core.process.ShellProcessControl;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
import io.xpipe.core.util.SecretValue;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
|
@ -15,7 +15,7 @@ import java.util.Random;
|
|||
|
||||
public class ScriptHelper {
|
||||
|
||||
public static String createDefaultOpenCommand(ShellProcessControl pc, String file) {
|
||||
public static String createDefaultOpenCommand(ShellControl pc, String file) {
|
||||
if (pc.getOsType().equals(OsType.WINDOWS)) {
|
||||
return "\"" + file + "\"";
|
||||
} else if (pc.getOsType().equals(OsType.LINUX)){
|
||||
|
@ -25,7 +25,7 @@ public class ScriptHelper {
|
|||
}
|
||||
}
|
||||
|
||||
public static String createDetachCommand(ShellProcessControl pc, String command) {
|
||||
public static String createDetachCommand(ShellControl pc, String command) {
|
||||
if (pc.getOsType().equals(OsType.WINDOWS)) {
|
||||
return "start \"\" " + command;
|
||||
} else {
|
||||
|
@ -123,7 +123,7 @@ public class ScriptHelper {
|
|||
}
|
||||
|
||||
public static String constructOpenWithInitScriptCommand(
|
||||
ShellProcessControl processControl, List<String> init, String toExecuteInShell) {
|
||||
ShellControl processControl, List<String> init, String toExecuteInShell) {
|
||||
ShellDialect t = processControl.getShellDialect();
|
||||
if (init.size() == 0 && toExecuteInShell == null) {
|
||||
return t.getNormalOpenCommand();
|
||||
|
@ -168,12 +168,12 @@ public class ScriptHelper {
|
|||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static String getExecScriptFile(ShellProcessControl processControl) {
|
||||
public static String getExecScriptFile(ShellControl processControl) {
|
||||
return getExecScriptFile(processControl, processControl.getShellDialect().getScriptFileEnding());
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static String getExecScriptFile(ShellProcessControl processControl, String fileEnding) {
|
||||
public static String getExecScriptFile(ShellControl processControl, String fileEnding) {
|
||||
var fileName = "exec-" + getScriptId();
|
||||
var temp = processControl.getTemporaryDirectory();
|
||||
var file = FileNames.join(temp, fileName + "." + fileEnding);
|
||||
|
@ -181,7 +181,7 @@ public class ScriptHelper {
|
|||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static String createExecScript(ShellProcessControl processControl, String content) {
|
||||
public static String createExecScript(ShellControl processControl, String content) {
|
||||
var fileName = "exec-" + getScriptId();
|
||||
ShellDialect type = processControl.getShellDialect();
|
||||
var temp = processControl.getTemporaryDirectory();
|
||||
|
@ -190,7 +190,7 @@ public class ScriptHelper {
|
|||
}
|
||||
|
||||
@SneakyThrows
|
||||
private static String createExecScript(ShellProcessControl processControl, String file, String content) {
|
||||
private static String createExecScript(ShellControl processControl, String file, String content) {
|
||||
ShellDialect type = processControl.getShellDialect();
|
||||
content = type.prepareScriptContent(content);
|
||||
|
||||
|
@ -207,7 +207,7 @@ public class ScriptHelper {
|
|||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static String createAskPassScript(SecretValue pass, ShellProcessControl parent, ShellDialect type) {
|
||||
public static String createAskPassScript(SecretValue pass, ShellControl parent, ShellDialect type) {
|
||||
var content = type.getScriptEchoCommand(pass.getSecretValue());
|
||||
var temp = parent.getTemporaryDirectory();
|
||||
var file = FileNames.join(temp, "askpass-" + getScriptId() + "." + type.getScriptFileEnding());
|
||||
|
|
|
@ -117,11 +117,13 @@ open module io.xpipe.app {
|
|||
uses XPipeDaemon;
|
||||
uses ProxyFunction;
|
||||
uses ModuleLayerLoader;
|
||||
uses ScanProvider;
|
||||
|
||||
provides ModuleLayerLoader with
|
||||
DataSourceTarget.Loader,
|
||||
ActionProvider.Loader,
|
||||
PrefsProvider.Loader;
|
||||
PrefsProvider.Loader,
|
||||
ScanProvider.Loader;
|
||||
provides DataStateProvider with
|
||||
DataStateProviderImpl;
|
||||
provides ProxyManagerProvider with
|
||||
|
|
|
@ -10,7 +10,11 @@ mustNotBeEmpty=$NAME$ must not be empty
|
|||
null=$VALUE$ must be not null
|
||||
hostFeatureUnsupported=Host does not support the feature $FEATURE$
|
||||
missingStore=$NAME$ does not exist
|
||||
connectionName=Connection name
|
||||
connectionNameDescription=Give this connection a custom name
|
||||
unknown=Unknown
|
||||
scanAlertTitle=Connection detection
|
||||
scanAlertHeader=Select types of connections you want to automatically detect on the host system:
|
||||
namedHostFeatureUnsupported=$HOST$ does not support this feature
|
||||
namedHostNotActive=$HOST$ is not active
|
||||
noInformationAvailable=No information available
|
||||
|
|
|
@ -10,4 +10,13 @@
|
|||
|
||||
.choice-pane-comp {
|
||||
-fx-spacing: 7px;
|
||||
}
|
||||
|
||||
.options-comp .name {
|
||||
-fx-padding: 9px 0 0 0;
|
||||
-fx-font-size: 1.1em;
|
||||
}
|
||||
|
||||
.options-comp .description {
|
||||
-fx-opacity: 0.75;
|
||||
}
|
|
@ -3,7 +3,7 @@ package io.xpipe.core.impl;
|
|||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||
import io.xpipe.core.process.ProcessControlProvider;
|
||||
import io.xpipe.core.process.ShellDialects;
|
||||
import io.xpipe.core.process.ShellProcessControl;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
import io.xpipe.core.store.ConnectionFileSystem;
|
||||
import io.xpipe.core.store.FileSystem;
|
||||
import io.xpipe.core.store.FileSystemStore;
|
||||
|
@ -15,12 +15,12 @@ import java.nio.file.Path;
|
|||
@JsonTypeName("local")
|
||||
public class LocalStore extends JacksonizedValue implements ShellStore {
|
||||
|
||||
private static ShellProcessControl local;
|
||||
private static ShellControl local;
|
||||
private static FileSystem localFileSystem;
|
||||
|
||||
public static ShellProcessControl getShell() throws Exception {
|
||||
public static ShellControl getShell() throws Exception {
|
||||
if (local == null) {
|
||||
local = new LocalStore().create().start();
|
||||
local = ProcessControlProvider.createLocal(false).start();
|
||||
}
|
||||
|
||||
return local;
|
||||
|
@ -128,7 +128,7 @@ public class LocalStore extends JacksonizedValue implements ShellStore {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ShellProcessControl createControl() {
|
||||
return ProcessControlProvider.createLocal();
|
||||
public ShellControl createControl() {
|
||||
return ProcessControlProvider.createLocal(true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package io.xpipe.core.process;
|
||||
|
||||
import io.xpipe.core.charsetter.Charsetter;
|
||||
import io.xpipe.core.util.FailableFunction;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
@ -8,18 +9,18 @@ import java.io.OutputStream;
|
|||
import java.nio.charset.Charset;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public interface CommandProcessControl extends ProcessControl {
|
||||
public interface CommandControl extends ProcessControl {
|
||||
|
||||
public CommandProcessControl doesNotObeyReturnValueConvention();
|
||||
public CommandControl doesNotObeyReturnValueConvention();
|
||||
|
||||
@Override
|
||||
public CommandProcessControl sensitive();
|
||||
public CommandControl sensitive();
|
||||
|
||||
CommandProcessControl complex();
|
||||
CommandControl complex();
|
||||
|
||||
CommandProcessControl workingDirectory(String directory);
|
||||
CommandControl workingDirectory(String directory);
|
||||
|
||||
ShellProcessControl getParent();
|
||||
ShellControl getParent();
|
||||
|
||||
InputStream startExternalStdout() throws Exception;
|
||||
|
||||
|
@ -27,16 +28,20 @@ public interface CommandProcessControl extends ProcessControl {
|
|||
|
||||
public boolean waitFor();
|
||||
|
||||
CommandProcessControl customCharset(Charset charset);
|
||||
CommandControl customCharset(Charset charset);
|
||||
|
||||
int getExitCode();
|
||||
|
||||
CommandProcessControl elevated();
|
||||
default CommandControl elevated() {
|
||||
return elevated((v) -> true);
|
||||
}
|
||||
|
||||
CommandControl elevated(FailableFunction<ShellControl, Boolean, Exception> elevationFunction);
|
||||
|
||||
@Override
|
||||
CommandProcessControl start() throws Exception;
|
||||
CommandControl start() throws Exception;
|
||||
|
||||
CommandProcessControl exitTimeout(Integer timeout);
|
||||
CommandControl exitTimeout(Integer timeout);
|
||||
|
||||
public void withStdoutOrThrow(Charsetter.FailableConsumer<InputStreamReader, Exception> c) throws Exception;
|
||||
String readOnlyStdout() throws Exception;
|
|
@ -22,25 +22,32 @@ public interface OsType {
|
|||
}
|
||||
}
|
||||
|
||||
String getHomeDirectory(ShellControl pc) throws Exception;
|
||||
|
||||
String getName();
|
||||
|
||||
String getTempDirectory(ShellProcessControl pc) throws Exception;
|
||||
String getTempDirectory(ShellControl pc) throws Exception;
|
||||
|
||||
String normalizeFileName(String file);
|
||||
|
||||
Map<String, String> getProperties(ShellProcessControl pc) throws Exception;
|
||||
Map<String, String> getProperties(ShellControl pc) throws Exception;
|
||||
|
||||
String determineOperatingSystemName(ShellProcessControl pc) throws Exception;
|
||||
String determineOperatingSystemName(ShellControl pc) throws Exception;
|
||||
|
||||
static class Windows implements OsType {
|
||||
|
||||
@Override
|
||||
public String getHomeDirectory(ShellControl pc) throws Exception {
|
||||
return pc.executeStringSimpleCommand(pc.getShellDialect().getPrintEnvironmentVariableCommand("USERPROFILE"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Windows";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTempDirectory(ShellProcessControl pc) throws Exception {
|
||||
public String getTempDirectory(ShellControl pc) throws Exception {
|
||||
return pc.executeStringSimpleCommand(pc.getShellDialect().getPrintEnvironmentVariableCommand("TEMP"));
|
||||
}
|
||||
|
||||
|
@ -50,15 +57,15 @@ public interface OsType {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getProperties(ShellProcessControl pc) throws Exception {
|
||||
try (CommandProcessControl c = pc.command("systeminfo").start()) {
|
||||
public Map<String, String> getProperties(ShellControl pc) throws Exception {
|
||||
try (CommandControl c = pc.command("systeminfo").start()) {
|
||||
var text = c.readOrThrow();
|
||||
return PropertiesFormatsParser.parse(text, ":");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String determineOperatingSystemName(ShellProcessControl pc) throws Exception {
|
||||
public String determineOperatingSystemName(ShellControl pc) throws Exception {
|
||||
var properties = getProperties(pc);
|
||||
return properties.get("OS Name") + " "
|
||||
+ properties.get("OS Version").split(" ")[0];
|
||||
|
@ -68,7 +75,12 @@ public interface OsType {
|
|||
static class Linux implements OsType {
|
||||
|
||||
@Override
|
||||
public String getTempDirectory(ShellProcessControl pc) throws Exception {
|
||||
public String getHomeDirectory(ShellControl pc) throws Exception {
|
||||
return pc.executeStringSimpleCommand(pc.getShellDialect().getPrintEnvironmentVariableCommand("HOME"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTempDirectory(ShellControl pc) throws Exception {
|
||||
return "/tmp/";
|
||||
}
|
||||
|
||||
|
@ -83,20 +95,20 @@ public interface OsType {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getProperties(ShellProcessControl pc) throws Exception {
|
||||
public Map<String, String> getProperties(ShellControl pc) throws Exception {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String determineOperatingSystemName(ShellProcessControl pc) throws Exception {
|
||||
try (CommandProcessControl c = pc.command("lsb_release -a").start()) {
|
||||
public String determineOperatingSystemName(ShellControl pc) throws Exception {
|
||||
try (CommandControl c = pc.command("lsb_release -a").start()) {
|
||||
var text = c.readOnlyStdout();
|
||||
if (c.getExitCode() == 0) {
|
||||
return PropertiesFormatsParser.parse(text, ":").getOrDefault("Description", null);
|
||||
}
|
||||
}
|
||||
|
||||
try (CommandProcessControl c = pc.command("cat /etc/*release").start()) {
|
||||
try (CommandControl c = pc.command("cat /etc/*release").start()) {
|
||||
var text = c.readOnlyStdout();
|
||||
if (c.getExitCode() == 0) {
|
||||
return PropertiesFormatsParser.parse(text, "=").getOrDefault("PRETTY_NAME", null);
|
||||
|
@ -104,7 +116,7 @@ public interface OsType {
|
|||
}
|
||||
|
||||
String type = "Unknown";
|
||||
try (CommandProcessControl c = pc.command("uname -o").start()) {
|
||||
try (CommandControl c = pc.command("uname -o").start()) {
|
||||
var text = c.readOnlyStdout();
|
||||
if (c.getExitCode() == 0) {
|
||||
type = text.strip();
|
||||
|
@ -112,7 +124,7 @@ public interface OsType {
|
|||
}
|
||||
|
||||
String version = "?";
|
||||
try (CommandProcessControl c = pc.command("uname -r").start()) {
|
||||
try (CommandControl c = pc.command("uname -r").start()) {
|
||||
var text = c.readOnlyStdout();
|
||||
if (c.getExitCode() == 0) {
|
||||
version = text.strip();
|
||||
|
@ -126,7 +138,12 @@ public interface OsType {
|
|||
static class MacOs implements OsType {
|
||||
|
||||
@Override
|
||||
public String getTempDirectory(ShellProcessControl pc) throws Exception {
|
||||
public String getHomeDirectory(ShellControl pc) throws Exception {
|
||||
return pc.executeStringSimpleCommand(pc.getShellDialect().getPrintEnvironmentVariableCommand("HOME"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTempDirectory(ShellControl pc) throws Exception {
|
||||
return pc.executeStringSimpleCommand(pc.getShellDialect().getPrintVariableCommand("TMPDIR"));
|
||||
}
|
||||
|
||||
|
@ -141,8 +158,8 @@ public interface OsType {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getProperties(ShellProcessControl pc) throws Exception {
|
||||
try (CommandProcessControl c =
|
||||
public Map<String, String> getProperties(ShellControl pc) throws Exception {
|
||||
try (CommandControl c =
|
||||
pc.subShell(ShellDialects.BASH).command("sw_vers").start()) {
|
||||
var text = c.readOrThrow();
|
||||
return PropertiesFormatsParser.parse(text, ":");
|
||||
|
@ -150,7 +167,7 @@ public interface OsType {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String determineOperatingSystemName(ShellProcessControl pc) throws Exception {
|
||||
public String determineOperatingSystemName(ShellControl pc) throws Exception {
|
||||
var properties = getProperties(pc);
|
||||
var name = pc.executeStringSimpleCommand(
|
||||
"awk '/SOFTWARE LICENSE AGREEMENT FOR macOS/' '/System/Library/CoreServices/Setup "
|
||||
|
|
|
@ -18,18 +18,18 @@ public abstract class ProcessControlProvider {
|
|||
.toList();
|
||||
}
|
||||
|
||||
public static ShellProcessControl createLocal() {
|
||||
public static ShellControl createLocal(boolean stoppable) {
|
||||
return INSTANCES.stream()
|
||||
.map(localProcessControlProvider -> localProcessControlProvider.createLocalProcessControl())
|
||||
.map(localProcessControlProvider -> localProcessControlProvider.createLocalProcessControl(stoppable))
|
||||
.filter(Objects::nonNull)
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
}
|
||||
|
||||
public static ShellProcessControl createSub(
|
||||
ShellProcessControl parent,
|
||||
@NonNull FailableFunction<ShellProcessControl, String, Exception> commandFunction,
|
||||
FailableBiFunction<ShellProcessControl, String, String, Exception> terminalCommand) {
|
||||
public static ShellControl createSub(
|
||||
ShellControl parent,
|
||||
@NonNull FailableFunction<ShellControl, String, Exception> commandFunction,
|
||||
FailableBiFunction<ShellControl, String, String, Exception> terminalCommand) {
|
||||
return INSTANCES.stream()
|
||||
.map(localProcessControlProvider ->
|
||||
localProcessControlProvider.sub(parent, commandFunction, terminalCommand))
|
||||
|
@ -38,10 +38,10 @@ public abstract class ProcessControlProvider {
|
|||
.orElseThrow();
|
||||
}
|
||||
|
||||
public static CommandProcessControl createCommand(
|
||||
ShellProcessControl parent,
|
||||
@NonNull FailableFunction<ShellProcessControl, String, Exception> command,
|
||||
FailableFunction<ShellProcessControl, String, Exception> terminalCommand) {
|
||||
public static CommandControl createCommand(
|
||||
ShellControl parent,
|
||||
@NonNull FailableFunction<ShellControl, String, Exception> command,
|
||||
FailableFunction<ShellControl, String, Exception> terminalCommand) {
|
||||
return INSTANCES.stream()
|
||||
.map(localProcessControlProvider ->
|
||||
localProcessControlProvider.command(parent, command, terminalCommand))
|
||||
|
@ -50,7 +50,7 @@ public abstract class ProcessControlProvider {
|
|||
.orElse(null);
|
||||
}
|
||||
|
||||
public static ShellProcessControl createSsh(Object sshStore) {
|
||||
public static ShellControl createSsh(Object sshStore) {
|
||||
return INSTANCES.stream()
|
||||
.map(localProcessControlProvider -> localProcessControlProvider.createSshControl(sshStore))
|
||||
.filter(Objects::nonNull)
|
||||
|
@ -58,17 +58,17 @@ public abstract class ProcessControlProvider {
|
|||
.orElseThrow();
|
||||
}
|
||||
|
||||
public abstract ShellProcessControl sub(
|
||||
ShellProcessControl parent,
|
||||
@NonNull FailableFunction<ShellProcessControl, String, Exception> commandFunction,
|
||||
FailableBiFunction<ShellProcessControl, String, String, Exception> terminalCommand);
|
||||
public abstract ShellControl sub(
|
||||
ShellControl parent,
|
||||
@NonNull FailableFunction<ShellControl, String, Exception> commandFunction,
|
||||
FailableBiFunction<ShellControl, String, String, Exception> terminalCommand);
|
||||
|
||||
public abstract CommandProcessControl command(
|
||||
ShellProcessControl parent,
|
||||
@NonNull FailableFunction<ShellProcessControl, String, Exception> command,
|
||||
FailableFunction<ShellProcessControl, String, Exception> terminalCommand);
|
||||
public abstract CommandControl command(
|
||||
ShellControl parent,
|
||||
@NonNull FailableFunction<ShellControl, String, Exception> command,
|
||||
FailableFunction<ShellControl, String, Exception> terminalCommand);
|
||||
|
||||
public abstract ShellProcessControl createLocalProcessControl();
|
||||
public abstract ShellControl createLocalProcessControl(boolean stoppable);
|
||||
|
||||
public abstract ShellProcessControl createSshControl(Object sshStore);
|
||||
public abstract ShellControl createSshControl(Object sshStore);
|
||||
}
|
||||
|
|
|
@ -9,13 +9,12 @@ import java.io.IOException;
|
|||
import java.util.List;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public interface ShellProcessControl extends ProcessControl {
|
||||
public interface ShellControl extends ProcessControl {
|
||||
|
||||
Semaphore getCommandLock();
|
||||
|
||||
void onInit(Consumer<ShellProcessControl> pc);
|
||||
void onInit(Consumer<ShellControl> pc);
|
||||
|
||||
String prepareTerminalOpen() throws Exception;
|
||||
|
||||
|
@ -26,25 +25,25 @@ public interface ShellProcessControl extends ProcessControl {
|
|||
public void checkRunning() throws Exception;
|
||||
|
||||
default String executeStringSimpleCommand(String command) throws Exception {
|
||||
try (CommandProcessControl c = command(command).start()) {
|
||||
try (CommandControl c = command(command).start()) {
|
||||
return c.readOrThrow();
|
||||
}
|
||||
}
|
||||
|
||||
default boolean executeBooleanSimpleCommand(String command) throws Exception {
|
||||
try (CommandProcessControl c = command(command).start()) {
|
||||
try (CommandControl c = command(command).start()) {
|
||||
return c.discardAndCheckExit();
|
||||
}
|
||||
}
|
||||
|
||||
default void executeSimpleCommand(String command) throws Exception {
|
||||
try (CommandProcessControl c = command(command).start()) {
|
||||
try (CommandControl c = command(command).start()) {
|
||||
c.discardOrThrow();
|
||||
}
|
||||
}
|
||||
|
||||
default void executeSimpleCommand(String command, String failMessage) throws Exception {
|
||||
try (CommandProcessControl c = command(command).start()) {
|
||||
try (CommandControl c = command(command).start()) {
|
||||
c.discardOrThrow();
|
||||
} catch (ProcessOutputException out) {
|
||||
throw ProcessOutputException.of(failMessage, out);
|
||||
|
@ -63,52 +62,52 @@ public interface ShellProcessControl extends ProcessControl {
|
|||
|
||||
OsType getOsType();
|
||||
|
||||
ShellProcessControl elevated(Predicate<ShellProcessControl> elevationFunction);
|
||||
ShellControl elevated(FailableFunction<ShellControl, Boolean, Exception> elevationFunction);
|
||||
|
||||
ShellProcessControl elevation(SecretValue value);
|
||||
ShellControl elevationPassword(SecretValue value);
|
||||
|
||||
ShellProcessControl initWith(List<String> cmds);
|
||||
ShellControl initWith(List<String> cmds);
|
||||
|
||||
SecretValue getElevationPassword();
|
||||
|
||||
default ShellProcessControl subShell(@NonNull ShellDialect type) {
|
||||
default ShellControl subShell(@NonNull ShellDialect type) {
|
||||
return subShell(p -> type.getNormalOpenCommand(), (shellProcessControl, s) -> {
|
||||
return s == null ? type.getNormalOpenCommand() : type.executeCommandWithShell(s);
|
||||
})
|
||||
.elevation(getElevationPassword());
|
||||
.elevationPassword(getElevationPassword());
|
||||
}
|
||||
|
||||
default ShellProcessControl subShell(@NonNull List<String> command) {
|
||||
default ShellControl subShell(@NonNull List<String> command) {
|
||||
return subShell(
|
||||
shellProcessControl -> shellProcessControl.getShellDialect().flatten(command), null);
|
||||
}
|
||||
|
||||
default ShellProcessControl subShell(@NonNull String command) {
|
||||
default ShellControl subShell(@NonNull String command) {
|
||||
return subShell(processControl -> command, null);
|
||||
}
|
||||
|
||||
ShellProcessControl subShell(
|
||||
FailableFunction<ShellProcessControl, String, Exception> command,
|
||||
FailableBiFunction<ShellProcessControl, String, String, Exception> terminalCommand);
|
||||
ShellControl subShell(
|
||||
FailableFunction<ShellControl, String, Exception> command,
|
||||
FailableBiFunction<ShellControl, String, String, Exception> terminalCommand);
|
||||
|
||||
void executeLine(String command) throws Exception;
|
||||
|
||||
void cd(String directory) throws Exception;
|
||||
|
||||
@Override
|
||||
ShellProcessControl start() throws Exception;
|
||||
ShellControl start() throws Exception;
|
||||
|
||||
CommandProcessControl command(FailableFunction<ShellProcessControl, String, Exception> command);
|
||||
CommandControl command(FailableFunction<ShellControl, String, Exception> command);
|
||||
|
||||
CommandProcessControl command(
|
||||
FailableFunction<ShellProcessControl, String, Exception> command,
|
||||
FailableFunction<ShellProcessControl, String, Exception> terminalCommand);
|
||||
CommandControl command(
|
||||
FailableFunction<ShellControl, String, Exception> command,
|
||||
FailableFunction<ShellControl, String, Exception> terminalCommand);
|
||||
|
||||
default CommandProcessControl command(String command) {
|
||||
default CommandControl command(String command) {
|
||||
return command(shellProcessControl -> command);
|
||||
}
|
||||
|
||||
default CommandProcessControl command(List<String> command) {
|
||||
default CommandControl command(List<String> command) {
|
||||
return command(shellProcessControl -> shellProcessControl.getShellDialect().flatten(command));
|
||||
}
|
||||
|
|
@ -29,9 +29,9 @@ public interface ShellDialect {
|
|||
|
||||
String addInlineVariablesToCommand(Map<String, String> variables, String command);
|
||||
|
||||
Stream<FileSystem.FileEntry> listFiles(FileSystem fs, ShellProcessControl control, String dir) throws Exception;
|
||||
Stream<FileSystem.FileEntry> listFiles(FileSystem fs, ShellControl control, String dir) throws Exception;
|
||||
|
||||
Stream<String> listRoots(ShellProcessControl control) throws Exception;
|
||||
Stream<String> listRoots(ShellControl control) throws Exception;
|
||||
|
||||
String getPauseCommand();
|
||||
|
||||
|
@ -101,7 +101,7 @@ public interface ShellDialect {
|
|||
|
||||
String getFileMoveCommand(String oldFile, String newFile);
|
||||
|
||||
CommandProcessControl getStreamFileWriteCommand(ShellProcessControl processControl, String file);
|
||||
CommandControl getStreamFileWriteCommand(ShellControl processControl, String file);
|
||||
|
||||
String getTextFileWriteCommand(String content, String file);
|
||||
|
||||
|
@ -113,7 +113,7 @@ public interface ShellDialect {
|
|||
|
||||
String getWhichCommand(String executable);
|
||||
|
||||
Charset determineCharset(ShellProcessControl control) throws Exception;
|
||||
Charset determineCharset(ShellControl control) throws Exception;
|
||||
|
||||
NewLine getNewLine();
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package io.xpipe.core.store;
|
||||
|
||||
import io.xpipe.core.process.CommandProcessControl;
|
||||
import io.xpipe.core.process.CommandControl;
|
||||
|
||||
public interface CommandExecutionStore extends DataStore, LaunchableStore {
|
||||
|
||||
|
@ -9,5 +9,5 @@ public interface CommandExecutionStore extends DataStore, LaunchableStore {
|
|||
return create().prepareTerminalOpen();
|
||||
}
|
||||
|
||||
CommandProcessControl create() throws Exception;
|
||||
CommandControl create() throws Exception;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package io.xpipe.core.store;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import io.xpipe.core.process.ShellProcessControl;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -15,19 +15,19 @@ import java.util.stream.Stream;
|
|||
public class ConnectionFileSystem implements FileSystem {
|
||||
|
||||
@JsonIgnore
|
||||
private final ShellProcessControl shellProcessControl;
|
||||
private final ShellControl shellControl;
|
||||
|
||||
@JsonIgnore
|
||||
private final ShellStore store;
|
||||
|
||||
public ConnectionFileSystem(ShellProcessControl shellProcessControl, ShellStore store) {
|
||||
this.shellProcessControl = shellProcessControl;
|
||||
public ConnectionFileSystem(ShellControl shellControl, ShellStore store) {
|
||||
this.shellControl = shellControl;
|
||||
this.store = store;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> listRoots() throws Exception {
|
||||
return shellProcessControl.getShellDialect().listRoots(shellProcessControl).toList();
|
||||
return shellControl.getShellDialect().listRoots(shellControl).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -35,7 +35,7 @@ public class ConnectionFileSystem implements FileSystem {
|
|||
|
||||
@Override
|
||||
public Stream<FileEntry> listFiles(String file) throws Exception {
|
||||
return shellProcessControl.getShellDialect().listFiles(this, shellProcessControl, file);
|
||||
return shellControl.getShellDialect().listFiles(this, shellControl, file);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -44,33 +44,33 @@ public class ConnectionFileSystem implements FileSystem {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Optional<ShellProcessControl> getShell() {
|
||||
return Optional.of(shellProcessControl);
|
||||
public Optional<ShellControl> getShell() {
|
||||
return Optional.of(shellControl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileSystem open() throws Exception {
|
||||
shellProcessControl.start();
|
||||
shellControl.start();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream openInput(String file) throws Exception {
|
||||
return shellProcessControl.command(proc ->
|
||||
return shellControl.command(proc ->
|
||||
proc.getShellDialect().getFileReadCommand(proc.getOsType().normalizeFileName(file)))
|
||||
.startExternalStdout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream openOutput(String file) throws Exception {
|
||||
return shellProcessControl.getShellDialect()
|
||||
.getStreamFileWriteCommand(shellProcessControl, shellProcessControl.getOsType().normalizeFileName(file))
|
||||
return shellControl.getShellDialect()
|
||||
.getStreamFileWriteCommand(shellControl, shellControl.getOsType().normalizeFileName(file))
|
||||
.startExternalStdin();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(String file) throws Exception {
|
||||
try (var pc = shellProcessControl.command(proc -> proc.getShellDialect()
|
||||
try (var pc = shellControl.command(proc -> proc.getShellDialect()
|
||||
.getFileExistsCommand(proc.getOsType().normalizeFileName(file)))
|
||||
.start()) {
|
||||
return pc.discardAndCheckExit();
|
||||
|
@ -79,7 +79,7 @@ public class ConnectionFileSystem implements FileSystem {
|
|||
|
||||
@Override
|
||||
public void delete(String file) throws Exception {
|
||||
try (var pc = shellProcessControl.command(proc -> proc.getShellDialect()
|
||||
try (var pc = shellControl.command(proc -> proc.getShellDialect()
|
||||
.getFileDeleteCommand(proc.getOsType().normalizeFileName(file)))
|
||||
.start()) {
|
||||
pc.discardOrThrow();
|
||||
|
@ -88,7 +88,7 @@ public class ConnectionFileSystem implements FileSystem {
|
|||
|
||||
@Override
|
||||
public void copy(String file, String newFile) throws Exception {
|
||||
try (var pc = shellProcessControl.command(proc -> proc.getShellDialect()
|
||||
try (var pc = shellControl.command(proc -> proc.getShellDialect()
|
||||
.getFileCopyCommand(proc.getOsType().normalizeFileName(file), proc.getOsType().normalizeFileName(newFile))).complex()
|
||||
.start()) {
|
||||
pc.discardOrThrow();
|
||||
|
@ -97,7 +97,7 @@ public class ConnectionFileSystem implements FileSystem {
|
|||
|
||||
@Override
|
||||
public void move(String file, String newFile) throws Exception {
|
||||
try (var pc = shellProcessControl.command(proc -> proc.getShellDialect()
|
||||
try (var pc = shellControl.command(proc -> proc.getShellDialect()
|
||||
.getFileMoveCommand(proc.getOsType().normalizeFileName(file), proc.getOsType().normalizeFileName(newFile))).complex()
|
||||
.start()) {
|
||||
pc.discardOrThrow();
|
||||
|
@ -106,7 +106,7 @@ public class ConnectionFileSystem implements FileSystem {
|
|||
|
||||
@Override
|
||||
public boolean mkdirs(String file) throws Exception {
|
||||
try (var pc = shellProcessControl.command(proc -> proc.getShellDialect()
|
||||
try (var pc = shellControl.command(proc -> proc.getShellDialect()
|
||||
.flatten(proc.getShellDialect()
|
||||
.getMkdirsCommand(proc.getOsType().normalizeFileName(file))))
|
||||
.start()) {
|
||||
|
@ -116,7 +116,7 @@ public class ConnectionFileSystem implements FileSystem {
|
|||
|
||||
@Override
|
||||
public void touch(String file) throws Exception {
|
||||
try (var pc = shellProcessControl.command(proc -> proc.getShellDialect()
|
||||
try (var pc = shellControl.command(proc -> proc.getShellDialect()
|
||||
.getFileTouchCommand(proc.getOsType().normalizeFileName(file))).complex()
|
||||
.start()) {
|
||||
pc.discardOrThrow();
|
||||
|
@ -125,6 +125,6 @@ public class ConnectionFileSystem implements FileSystem {
|
|||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
shellProcessControl.close();
|
||||
shellControl.close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package io.xpipe.core.store;
|
||||
|
||||
import io.xpipe.core.impl.FileNames;
|
||||
import io.xpipe.core.process.ShellProcessControl;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
import lombok.NonNull;
|
||||
import lombok.Value;
|
||||
|
||||
|
@ -44,7 +44,7 @@ public interface FileSystem extends Closeable, AutoCloseable {
|
|||
|
||||
FileSystemStore getStore();
|
||||
|
||||
Optional<ShellProcessControl> getShell();
|
||||
Optional<ShellControl> getShell();
|
||||
|
||||
FileSystem open() throws Exception;
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ package io.xpipe.core.store;
|
|||
import io.xpipe.core.impl.LocalStore;
|
||||
import io.xpipe.core.process.OsType;
|
||||
import io.xpipe.core.process.ShellDialect;
|
||||
import io.xpipe.core.process.ShellProcessControl;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
|
@ -27,7 +27,7 @@ public interface ShellStore extends DataStore, StatefulDataStore, LaunchableStor
|
|||
return create().prepareTerminalOpen();
|
||||
}
|
||||
|
||||
default ShellProcessControl create() {
|
||||
default ShellControl create() {
|
||||
var pc = createControl();
|
||||
pc.onInit(processControl -> {
|
||||
setState("type", processControl.getShellDialect());
|
||||
|
@ -49,7 +49,7 @@ public interface ShellStore extends DataStore, StatefulDataStore, LaunchableStor
|
|||
return getState("charset", Charset.class, null);
|
||||
}
|
||||
|
||||
ShellProcessControl createControl();
|
||||
ShellControl createControl();
|
||||
|
||||
public default ShellDialect determineType() throws Exception {
|
||||
try (var pc = create().start()) {
|
||||
|
@ -59,7 +59,7 @@ public interface ShellStore extends DataStore, StatefulDataStore, LaunchableStor
|
|||
|
||||
@Override
|
||||
default void validate() throws Exception {
|
||||
try (ShellProcessControl pc = create().start()) {}
|
||||
try (ShellControl pc = create().start()) {}
|
||||
}
|
||||
|
||||
public default String queryMachineName() throws Exception {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package io.xpipe.core.util;
|
||||
|
||||
import io.xpipe.core.process.ShellProcessControl;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.ServiceLoader;
|
||||
|
@ -19,7 +19,7 @@ public abstract class ProxyManagerProvider {
|
|||
return INSTANCE;
|
||||
}
|
||||
|
||||
public abstract Optional<String> checkCompatibility(ShellProcessControl pc) throws Exception;
|
||||
public abstract Optional<String> checkCompatibility(ShellControl pc) throws Exception;
|
||||
|
||||
public abstract boolean setup(ShellProcessControl pc) throws Exception;
|
||||
public abstract boolean setup(ShellControl pc) throws Exception;
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package io.xpipe.core.util;
|
||||
|
||||
import io.xpipe.core.impl.FileNames;
|
||||
import io.xpipe.core.process.CommandProcessControl;
|
||||
import io.xpipe.core.process.CommandControl;
|
||||
import io.xpipe.core.process.OsType;
|
||||
import io.xpipe.core.process.ProcessOutputException;
|
||||
import io.xpipe.core.process.ShellProcessControl;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
@ -153,21 +153,21 @@ public class XPipeInstallation {
|
|||
return v;
|
||||
}
|
||||
|
||||
public static String queryInstallationVersion(ShellProcessControl p, String exec) throws Exception {
|
||||
try (CommandProcessControl c = p.command(List.of(exec, "version")).start()) {
|
||||
public static String queryInstallationVersion(ShellControl p, String exec) throws Exception {
|
||||
try (CommandControl c = p.command(List.of(exec, "version")).start()) {
|
||||
return c.readOrThrow();
|
||||
} catch (ProcessOutputException ex) {
|
||||
return "?";
|
||||
}
|
||||
}
|
||||
|
||||
public static String getInstallationExecutable(ShellProcessControl p, String installation) throws Exception {
|
||||
public static String getInstallationExecutable(ShellControl p, String installation) throws Exception {
|
||||
var executable = getDaemonExecutablePath(p.getOsType());
|
||||
var file = FileNames.join(installation, executable);
|
||||
return file;
|
||||
}
|
||||
|
||||
public static String getDataBasePath(ShellProcessControl p) throws Exception {
|
||||
public static String getDataBasePath(ShellControl p) throws Exception {
|
||||
if (p.getOsType().equals(OsType.WINDOWS)) {
|
||||
var base = p.executeStringSimpleCommand(p.getShellDialect().getPrintVariableCommand("userprofile"));
|
||||
return FileNames.join(base, ".xpipe");
|
||||
|
@ -218,7 +218,7 @@ public class XPipeInstallation {
|
|||
return path;
|
||||
}
|
||||
|
||||
public static String getDefaultInstallationBasePath(ShellProcessControl p, boolean acceptPortable)
|
||||
public static String getDefaultInstallationBasePath(ShellControl p, boolean acceptPortable)
|
||||
throws Exception {
|
||||
if (acceptPortable) {
|
||||
var customHome = p.executeStringSimpleCommand(p.getShellDialect().getPrintVariableCommand("XPIPE_HOME"));
|
||||
|
|
|
@ -2,7 +2,7 @@ package io.xpipe.core.util;
|
|||
|
||||
import io.xpipe.core.impl.FileNames;
|
||||
import io.xpipe.core.process.OsType;
|
||||
import io.xpipe.core.process.ShellProcessControl;
|
||||
import io.xpipe.core.process.ShellControl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
@ -19,7 +19,7 @@ public class XPipeTempDirectory {
|
|||
}
|
||||
}
|
||||
|
||||
public static String get(ShellProcessControl proc) throws Exception {
|
||||
public static String get(ShellControl proc) throws Exception {
|
||||
var base = proc.getOsType().getTempDirectory(proc);
|
||||
var dir = FileNames.join(base, "xpipe");
|
||||
|
||||
|
@ -36,7 +36,7 @@ public class XPipeTempDirectory {
|
|||
return dir;
|
||||
}
|
||||
|
||||
public static void clear(ShellProcessControl proc) throws Exception {
|
||||
public static void clear(ShellControl proc) throws Exception {
|
||||
var dir = get(proc);
|
||||
if (!proc.executeBooleanSimpleCommand(proc.getShellDialect().getFileDeleteCommand(dir))) {
|
||||
throw new IOException("Unable to delete temporary directory " + dir);
|
||||
|
|
Loading…
Reference in a new issue