mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-10-01 09:40:35 +13:00
Small shell changes and move some comps to extension module
This commit is contained in:
parent
0d65db95f9
commit
40df1a3233
11 changed files with 245 additions and 17 deletions
|
@ -125,6 +125,17 @@ public class BeaconClient implements AutoCloseable {
|
||||||
var command = control.command("xpipe beacon --raw").start();
|
var command = control.command("xpipe beacon --raw").start();
|
||||||
command.discardErr();
|
command.discardErr();
|
||||||
return new BeaconClient(command, command.getStdout(), command.getStdin()) {
|
return new BeaconClient(command, command.getStdout(), command.getStdin()) {
|
||||||
|
|
||||||
|
// {
|
||||||
|
// new Thread(() -> {
|
||||||
|
// while (true) {
|
||||||
|
// if (!control.isRunning()) {
|
||||||
|
// close();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T extends ResponseMessage> T receiveResponse()
|
public <T extends ResponseMessage> T receiveResponse()
|
||||||
throws ConnectorException, ClientException, ServerException {
|
throws ConnectorException, ClientException, ServerException {
|
||||||
|
|
|
@ -5,15 +5,9 @@ import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public interface ProcessControl extends Closeable, AutoCloseable {
|
public interface ProcessControl extends Closeable, AutoCloseable {
|
||||||
|
|
||||||
static String join(List<String> command) {
|
|
||||||
return command.stream().map(s -> s.contains(" ") ? "\"" + s + "\"" : s).collect(Collectors.joining(" "));
|
|
||||||
}
|
|
||||||
|
|
||||||
void closeStdin() throws IOException;
|
void closeStdin() throws IOException;
|
||||||
|
|
||||||
boolean isStdinClosed();
|
boolean isStdinClosed();
|
||||||
|
|
|
@ -71,18 +71,17 @@ public interface ShellProcessControl extends ProcessControl {
|
||||||
ShellProcessControl start() throws Exception;
|
ShellProcessControl start() throws Exception;
|
||||||
|
|
||||||
default CommandProcessControl commandListFunction(Function<ShellProcessControl, List<String>> command) {
|
default CommandProcessControl commandListFunction(Function<ShellProcessControl, List<String>> command) {
|
||||||
return commandFunction(shellProcessControl -> command.apply(shellProcessControl).stream()
|
return commandFunction(shellProcessControl -> shellProcessControl.getShellType().flatten(command.apply(shellProcessControl)));
|
||||||
.map(s -> s.contains(" ") ? "\"" + s + "\"" : s)
|
|
||||||
.collect(Collectors.joining(" ")));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CommandProcessControl commandFunction(Function<ShellProcessControl, String> command);
|
CommandProcessControl commandFunction(Function<ShellProcessControl, String> command);
|
||||||
|
|
||||||
CommandProcessControl command(String command);
|
default CommandProcessControl command(String command){
|
||||||
|
return commandFunction(shellProcessControl -> command);
|
||||||
|
}
|
||||||
|
|
||||||
default CommandProcessControl command(List<String> command) {
|
default CommandProcessControl command(List<String> command) {
|
||||||
return command(
|
return commandFunction(shellProcessControl -> shellProcessControl.getShellType().flatten(command));
|
||||||
command.stream().map(s -> s.contains(" ") ? "\"" + s + "\"" : s).collect(Collectors.joining(" ")));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void exitAndWait() throws IOException;
|
void exitAndWait() throws IOException;
|
||||||
|
|
|
@ -5,10 +5,16 @@ import io.xpipe.core.charsetter.NewLine;
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
|
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
|
||||||
public interface ShellType {
|
public interface ShellType {
|
||||||
|
|
||||||
|
default String flatten(List<String> command) {
|
||||||
|
return command.stream().map(s -> s.contains(" ") ? "\"" + s + "\"" : s).collect(Collectors.joining(" "));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
default String joinCommands(String... s) {
|
default String joinCommands(String... s) {
|
||||||
return String.join(getConcatenationOperator(), s);
|
return String.join(getConcatenationOperator(), s);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,11 @@ import io.xpipe.core.impl.FileNames;
|
||||||
import io.xpipe.core.impl.LocalStore;
|
import io.xpipe.core.impl.LocalStore;
|
||||||
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.ProcessOutputException;
|
||||||
import io.xpipe.core.process.ShellProcessControl;
|
import io.xpipe.core.process.ShellProcessControl;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class XPipeInstallation {
|
public class XPipeInstallation {
|
||||||
|
|
||||||
public static String getInstallationBasePathForCLI(ShellProcessControl p, String cliExecutable) throws Exception {
|
public static String getInstallationBasePathForCLI(ShellProcessControl p, String cliExecutable) throws Exception {
|
||||||
|
@ -22,8 +25,10 @@ public class XPipeInstallation {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String queryInstallationVersion(ShellProcessControl p, String exec) throws Exception {
|
public static String queryInstallationVersion(ShellProcessControl p, String exec) throws Exception {
|
||||||
try (CommandProcessControl c = p.command(exec + " version").start()) {
|
try (CommandProcessControl c = p.command(List.of(exec, "version")).start()) {
|
||||||
return c.readOrThrow();
|
return c.readOrThrow();
|
||||||
|
} catch (ProcessOutputException ex) {
|
||||||
|
return "?";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +39,7 @@ public class XPipeInstallation {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
try (CommandProcessControl c = p.command(executable + " version").start()) {
|
try (CommandProcessControl c = p.command(List.of(executable, "version")).start()) {
|
||||||
return c.readOrThrow().equals(version);
|
return c.readOrThrow().equals(version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,25 @@ public abstract class EventHandler {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public static final EventHandler OMIT = new EventHandler() {
|
||||||
|
@Override
|
||||||
|
public List<TrackEvent> snapshotEvents() {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(TrackEvent te) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(ErrorEvent ee) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static void set(EventHandler handler) {
|
||||||
|
INSTANCE = handler;
|
||||||
|
}
|
||||||
|
|
||||||
private static EventHandler INSTANCE;
|
private static EventHandler INSTANCE;
|
||||||
|
|
||||||
private static void init() {
|
private static void init() {
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
package io.xpipe.extension.fxcomps.impl;
|
||||||
|
|
||||||
|
import io.xpipe.core.impl.FileStore;
|
||||||
|
import io.xpipe.core.impl.LocalStore;
|
||||||
|
import io.xpipe.core.store.FileSystemStore;
|
||||||
|
import io.xpipe.core.store.MachineStore;
|
||||||
|
import io.xpipe.extension.I18n;
|
||||||
|
import io.xpipe.extension.fxcomps.SimpleComp;
|
||||||
|
import javafx.beans.property.Property;
|
||||||
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
|
import javafx.scene.layout.HBox;
|
||||||
|
import javafx.scene.layout.Priority;
|
||||||
|
import javafx.scene.layout.Region;
|
||||||
|
import javafx.stage.FileChooser;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class FileStoreChoiceComp extends SimpleComp {
|
||||||
|
|
||||||
|
private final List<MachineStore> availableFileSystems;
|
||||||
|
private final Property<FileStore> selected;
|
||||||
|
|
||||||
|
public FileStoreChoiceComp(List<MachineStore> availableFileSystems, Property<FileStore> selected) {
|
||||||
|
this.availableFileSystems = availableFileSystems;
|
||||||
|
this.selected = selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setSelected(FileSystemStore fileSystemStore, String file) {
|
||||||
|
selected.setValue(fileSystemStore != null && file != null ? new FileStore(fileSystemStore, file) : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Region createSimple() {
|
||||||
|
var fileProperty = new SimpleStringProperty(
|
||||||
|
selected.getValue() != null ? selected.getValue().getFile() : null);
|
||||||
|
var fileSystemProperty = new SimpleObjectProperty<>(
|
||||||
|
selected.getValue() != null ? selected.getValue().getFileSystem() : availableFileSystems.get(0));
|
||||||
|
|
||||||
|
fileProperty.addListener((observable, oldValue, newValue) -> {
|
||||||
|
setSelected(fileSystemProperty.get(), fileProperty.get());
|
||||||
|
});
|
||||||
|
fileSystemProperty.addListener((observable, oldValue, newValue) -> {
|
||||||
|
setSelected(fileSystemProperty.get(), fileProperty.get());
|
||||||
|
});
|
||||||
|
|
||||||
|
var fileSystemChoiceComp = new FileSystemStoreChoiceComp(fileSystemProperty);
|
||||||
|
if (availableFileSystems.size() == 1) {
|
||||||
|
fileSystemChoiceComp.hide(new SimpleBooleanProperty(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileNameComp = new TextFieldComp(fileProperty).apply(struc -> HBox.setHgrow(struc.get(), Priority.ALWAYS));
|
||||||
|
var fileBrowseButton = new IconButtonComp("mdi2f-folder-open-outline", () -> {
|
||||||
|
if (fileSystemProperty.get() != null && fileSystemProperty.get() instanceof LocalStore) {
|
||||||
|
var fileChooser = createChooser();
|
||||||
|
File file = fileChooser.showOpenDialog(null);
|
||||||
|
if (file != null && file.exists()) {
|
||||||
|
fileProperty.setValue(file.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.hide(fileSystemProperty.isNotEqualTo(new LocalStore()));
|
||||||
|
|
||||||
|
var layout = new HorizontalComp(List.of(fileSystemChoiceComp, fileNameComp, fileBrowseButton));
|
||||||
|
|
||||||
|
return layout.createRegion();
|
||||||
|
}
|
||||||
|
|
||||||
|
private FileChooser createChooser() {
|
||||||
|
FileChooser fileChooser = new FileChooser();
|
||||||
|
fileChooser.setTitle(I18n.get("browseFileTitle"));
|
||||||
|
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(I18n.get("anyFile"), "*"));
|
||||||
|
return fileChooser;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
package io.xpipe.extension.fxcomps.impl;
|
||||||
|
|
||||||
|
import io.xpipe.core.impl.LocalStore;
|
||||||
|
import io.xpipe.core.store.FileSystemStore;
|
||||||
|
import io.xpipe.extension.DataStoreProviders;
|
||||||
|
import io.xpipe.extension.I18n;
|
||||||
|
import io.xpipe.extension.fxcomps.SimpleComp;
|
||||||
|
import io.xpipe.extension.util.CustomComboBoxBuilder;
|
||||||
|
import io.xpipe.extension.util.XPipeDaemon;
|
||||||
|
import javafx.beans.property.Property;
|
||||||
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.control.ComboBox;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.layout.Region;
|
||||||
|
|
||||||
|
public class FileSystemStoreChoiceComp extends SimpleComp {
|
||||||
|
|
||||||
|
private final Property<FileSystemStore> selected;
|
||||||
|
|
||||||
|
public FileSystemStoreChoiceComp(Property<FileSystemStore> selected) {
|
||||||
|
this.selected = selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getName(FileSystemStore store) {
|
||||||
|
var name = XPipeDaemon.getInstance().getNamedStores().stream()
|
||||||
|
.filter(e -> e.equals(store))
|
||||||
|
.findAny()
|
||||||
|
.map(e -> XPipeDaemon.getInstance().getStoreName(e).orElse("?"))
|
||||||
|
.orElse(I18n.get("localMachine"));
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Region createGraphic(FileSystemStore s) {
|
||||||
|
var provider = DataStoreProviders.byStore(s);
|
||||||
|
var img = new PrettyImageComp(new SimpleStringProperty(provider.getDisplayIconFileName()), 16, 16);
|
||||||
|
return new Label(getName(s), img.createRegion());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Region createSimple() {
|
||||||
|
var comboBox = new CustomComboBoxBuilder<>(selected, this::createGraphic, null, v -> true);
|
||||||
|
comboBox.addFilter((v, s) -> getName(v).toLowerCase().contains(s));
|
||||||
|
comboBox.add(new LocalStore());
|
||||||
|
XPipeDaemon.getInstance().getNamedStores().stream()
|
||||||
|
.filter(e -> e instanceof FileSystemStore)
|
||||||
|
.map(e -> (FileSystemStore) e)
|
||||||
|
.forEach(comboBox::add);
|
||||||
|
ComboBox<Node> cb = comboBox.build();
|
||||||
|
cb.getStyleClass().add("choice-comp");
|
||||||
|
return cb;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
package io.xpipe.extension.fxcomps.impl;
|
||||||
|
|
||||||
|
import com.jfoenix.controls.JFXButton;
|
||||||
|
import io.xpipe.extension.fxcomps.Comp;
|
||||||
|
import io.xpipe.extension.fxcomps.CompStructure;
|
||||||
|
import io.xpipe.extension.fxcomps.SimpleCompStructure;
|
||||||
|
import io.xpipe.extension.fxcomps.util.PlatformThread;
|
||||||
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
|
import javafx.beans.value.ObservableValue;
|
||||||
|
import javafx.css.Size;
|
||||||
|
import javafx.css.SizeUnits;
|
||||||
|
import org.kordamp.ikonli.javafx.FontIcon;
|
||||||
|
|
||||||
|
public class IconButtonComp extends Comp<CompStructure<JFXButton>> {
|
||||||
|
|
||||||
|
private final ObservableValue<String> icon;
|
||||||
|
private final Runnable listener;
|
||||||
|
|
||||||
|
public IconButtonComp(String defaultVal) {
|
||||||
|
this(new SimpleObjectProperty<>(defaultVal), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IconButtonComp(String defaultVal, Runnable listener) {
|
||||||
|
this(new SimpleObjectProperty<>(defaultVal), listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IconButtonComp(ObservableValue<String> icon, Runnable listener) {
|
||||||
|
this.icon = PlatformThread.sync(icon);
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompStructure<JFXButton> createBase() {
|
||||||
|
var button = new JFXButton();
|
||||||
|
|
||||||
|
var fi = new FontIcon(icon.getValue());
|
||||||
|
icon.addListener((c, o, n) -> {
|
||||||
|
fi.setIconLiteral(n);
|
||||||
|
});
|
||||||
|
fi.setIconSize((int) new Size(fi.getFont().getSize(), SizeUnits.PT).pixels());
|
||||||
|
button.fontProperty().addListener((c, o, n) -> {
|
||||||
|
fi.setIconSize((int) new Size(n.getSize(), SizeUnits.PT).pixels());
|
||||||
|
});
|
||||||
|
fi.iconColorProperty().bind(button.textFillProperty());
|
||||||
|
button.setGraphic(fi);
|
||||||
|
button.setOnAction(e -> {
|
||||||
|
if (listener != null) {
|
||||||
|
listener.run();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
button.getStyleClass().add("icon-button-comp");
|
||||||
|
return new SimpleCompStructure<>(button);
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,7 +15,7 @@ public class DaemonExtensionTest extends ExtensionTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DataSource getSource(String type, String file) {
|
public static DataSource getSource(String type, String file) {
|
||||||
return DataSource.create(null, type, getResource(file));
|
return DataSource.create(null, type, getResourceStore(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DataSource getSource(io.xpipe.core.source.DataSource<?> source) {
|
public static DataSource getSource(io.xpipe.core.source.DataSource<?> source) {
|
||||||
|
|
|
@ -9,8 +9,18 @@ import java.nio.file.Path;
|
||||||
public class ExtensionTest {
|
public class ExtensionTest {
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public static DataStore getResource(String name) {
|
public static Path getResourcePath(Class<?> c, String name) {
|
||||||
var url = DaemonExtensionTest.class.getClassLoader().getResource(name);
|
var url = c.getResource(name);
|
||||||
|
if (url == null) {
|
||||||
|
throw new IllegalArgumentException(String.format("File %s does not exist", name));
|
||||||
|
}
|
||||||
|
var file = Path.of(url.toURI());
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public static DataStore getResourceStore(String name) {
|
||||||
|
var url = ExtensionTest.class.getClassLoader().getResource(name);
|
||||||
if (url == null) {
|
if (url == null) {
|
||||||
throw new IllegalArgumentException(String.format("File %s does not exist", name));
|
throw new IllegalArgumentException(String.format("File %s does not exist", name));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue