mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-09-04 11:41:32 +12:00
Try to fix push
This commit is contained in:
parent
07563bb059
commit
fd2e6f968b
28 changed files with 516 additions and 113 deletions
|
@ -132,7 +132,7 @@ application {
|
||||||
|
|
||||||
run {
|
run {
|
||||||
systemProperty 'io.xpipe.app.mode', 'gui'
|
systemProperty 'io.xpipe.app.mode', 'gui'
|
||||||
systemProperty 'io.xpipe.app.dataDir', "$projectDir/local3/"
|
systemProperty 'io.xpipe.app.dataDir', "$projectDir/local_stage/"
|
||||||
systemProperty 'io.xpipe.app.writeLogs', "true"
|
systemProperty 'io.xpipe.app.writeLogs', "true"
|
||||||
systemProperty 'io.xpipe.app.writeSysOut', "true"
|
systemProperty 'io.xpipe.app.writeSysOut', "true"
|
||||||
systemProperty 'io.xpipe.app.developerMode', "true"
|
systemProperty 'io.xpipe.app.developerMode', "true"
|
||||||
|
|
|
@ -80,8 +80,8 @@ public class AppLayoutComp extends Comp<CompStructure<BorderPane>> {
|
||||||
pane.setCenter(r);
|
pane.setCenter(r);
|
||||||
});
|
});
|
||||||
pane.setCenter(selected.getValue().comp().createRegion());
|
pane.setCenter(selected.getValue().comp().createRegion());
|
||||||
pane.setPrefWidth(1200);
|
pane.setPrefWidth(1280);
|
||||||
pane.setPrefHeight(700);
|
pane.setPrefHeight(720);
|
||||||
AppFont.normal(pane);
|
AppFont.normal(pane);
|
||||||
return new SimpleCompStructure<>(pane);
|
return new SimpleCompStructure<>(pane);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,16 +5,12 @@ import io.xpipe.extension.fxcomps.Comp;
|
||||||
import io.xpipe.extension.fxcomps.CompStructure;
|
import io.xpipe.extension.fxcomps.CompStructure;
|
||||||
import io.xpipe.extension.fxcomps.util.PlatformThread;
|
import io.xpipe.extension.fxcomps.util.PlatformThread;
|
||||||
import io.xpipe.extension.fxcomps.util.SimpleChangeListener;
|
import io.xpipe.extension.fxcomps.util.SimpleChangeListener;
|
||||||
import javafx.animation.Animation;
|
|
||||||
import javafx.animation.PauseTransition;
|
|
||||||
import javafx.beans.property.Property;
|
import javafx.beans.property.Property;
|
||||||
import javafx.beans.property.SimpleStringProperty;
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
import javafx.event.EventHandler;
|
import javafx.event.EventHandler;
|
||||||
import javafx.scene.input.KeyCode;
|
import javafx.scene.input.KeyCode;
|
||||||
import javafx.scene.input.KeyEvent;
|
import javafx.scene.input.KeyEvent;
|
||||||
import javafx.scene.input.MouseEvent;
|
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.util.Duration;
|
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
|
|
||||||
|
@ -80,17 +76,6 @@ public class LazyTextFieldComp extends Comp<LazyTextFieldComp.Structure> {
|
||||||
currentValue.setValue(newValue);
|
currentValue.setValue(newValue);
|
||||||
});
|
});
|
||||||
|
|
||||||
Animation delay = new PauseTransition(Duration.millis(800));
|
|
||||||
delay.setOnFinished(e -> {
|
|
||||||
r.setDisable(false);
|
|
||||||
r.requestFocus();
|
|
||||||
});
|
|
||||||
sp.addEventFilter(MouseEvent.MOUSE_ENTERED, e -> {
|
|
||||||
delay.playFromStart();
|
|
||||||
});
|
|
||||||
sp.addEventFilter(MouseEvent.MOUSE_EXITED, e -> {
|
|
||||||
delay.stop();
|
|
||||||
});
|
|
||||||
r.focusedProperty().addListener((c, o, n) -> {
|
r.focusedProperty().addListener((c, o, n) -> {
|
||||||
if (!n) {
|
if (!n) {
|
||||||
r.setDisable(true);
|
r.setDisable(true);
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
package io.xpipe.app.comp.base;
|
||||||
|
|
||||||
|
import io.xpipe.extension.fxcomps.Comp;
|
||||||
|
import io.xpipe.extension.fxcomps.CompStructure;
|
||||||
|
import io.xpipe.extension.fxcomps.SimpleCompStructure;
|
||||||
|
import io.xpipe.extension.fxcomps.util.BindingsHelper;
|
||||||
|
import io.xpipe.extension.fxcomps.util.PlatformThread;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.collections.ListChangeListener;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.scene.layout.Region;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class ListBoxViewComp<T> extends Comp<CompStructure<VBox>> {
|
||||||
|
|
||||||
|
private final ObservableList<T> shown;
|
||||||
|
private final ObservableList<T> all;
|
||||||
|
private final Function<T, Comp<?>> compFunction;
|
||||||
|
|
||||||
|
public ListBoxViewComp(
|
||||||
|
ObservableList<T> shown, ObservableList<T> all, Function<T, Comp<?>> compFunction) {
|
||||||
|
this.shown = PlatformThread.sync(shown);
|
||||||
|
this.all = PlatformThread.sync(all);
|
||||||
|
this.compFunction = compFunction;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompStructure<VBox> createBase() {
|
||||||
|
Map<T, Region> cache = new HashMap<>();
|
||||||
|
|
||||||
|
VBox listView = new VBox();
|
||||||
|
listView.setFocusTraversable(false);
|
||||||
|
|
||||||
|
refresh(listView, shown, cache, false);
|
||||||
|
listView.requestLayout();
|
||||||
|
|
||||||
|
shown.addListener((ListChangeListener<? super T>) (c) -> {
|
||||||
|
refresh(listView, c.getList(), cache, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
all.addListener((ListChangeListener<? super T>) c -> {
|
||||||
|
cache.keySet().retainAll(c.getList());
|
||||||
|
});
|
||||||
|
|
||||||
|
return new SimpleCompStructure<>(listView);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refresh(VBox listView, List<? extends T> c, Map<T, Region> cache, boolean asynchronous) {
|
||||||
|
Runnable update = () -> {
|
||||||
|
var newShown = c.stream()
|
||||||
|
.map(v -> {
|
||||||
|
if (!cache.containsKey(v)) {
|
||||||
|
cache.put(v, compFunction.apply(v).createRegion());
|
||||||
|
}
|
||||||
|
|
||||||
|
return cache.get(v);
|
||||||
|
})
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
if (!listView.getChildren().equals(newShown)) {
|
||||||
|
BindingsHelper.setContent(listView.getChildren(), newShown);
|
||||||
|
listView.layout();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (asynchronous) {
|
||||||
|
Platform.runLater(update);
|
||||||
|
} else {
|
||||||
|
PlatformThread.runLaterIfNeeded(update);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
package io.xpipe.app.comp.storage.store;
|
package io.xpipe.app.comp.storage.store;
|
||||||
|
|
||||||
|
import com.jfoenix.controls.JFXButton;
|
||||||
import io.xpipe.app.comp.base.LazyTextFieldComp;
|
import io.xpipe.app.comp.base.LazyTextFieldComp;
|
||||||
import io.xpipe.app.comp.base.LoadingOverlayComp;
|
import io.xpipe.app.comp.base.LoadingOverlayComp;
|
||||||
import io.xpipe.app.core.AppFont;
|
import io.xpipe.app.core.AppFont;
|
||||||
|
@ -10,6 +11,7 @@ import io.xpipe.extension.I18n;
|
||||||
import io.xpipe.extension.event.ErrorEvent;
|
import io.xpipe.extension.event.ErrorEvent;
|
||||||
import io.xpipe.extension.fxcomps.Comp;
|
import io.xpipe.extension.fxcomps.Comp;
|
||||||
import io.xpipe.extension.fxcomps.SimpleComp;
|
import io.xpipe.extension.fxcomps.SimpleComp;
|
||||||
|
import io.xpipe.extension.fxcomps.SimpleCompStructure;
|
||||||
import io.xpipe.extension.fxcomps.augment.GrowAugment;
|
import io.xpipe.extension.fxcomps.augment.GrowAugment;
|
||||||
import io.xpipe.extension.fxcomps.augment.PopupMenuAugment;
|
import io.xpipe.extension.fxcomps.augment.PopupMenuAugment;
|
||||||
import io.xpipe.extension.fxcomps.impl.FancyTooltipAugment;
|
import io.xpipe.extension.fxcomps.impl.FancyTooltipAugment;
|
||||||
|
@ -100,6 +102,9 @@ public class StoreEntryComp extends SimpleComp {
|
||||||
var imageComp = new PrettyImageComp(new SimpleStringProperty(img), 55, 45);
|
var imageComp = new PrettyImageComp(new SimpleStringProperty(img), 55, 45);
|
||||||
var storeIcon = imageComp.createRegion();
|
var storeIcon = imageComp.createRegion();
|
||||||
storeIcon.getStyleClass().add("icon");
|
storeIcon.getStyleClass().add("icon");
|
||||||
|
if (entry.getState().getValue().isUsable()) {
|
||||||
|
new FancyTooltipAugment<>(new SimpleStringProperty(entry.getEntry().getProvider().getDisplayName())).augment(storeIcon);
|
||||||
|
}
|
||||||
return storeIcon;
|
return storeIcon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,6 +122,7 @@ public class StoreEntryComp extends SimpleComp {
|
||||||
|
|
||||||
var storeIcon = createIcon();
|
var storeIcon = createIcon();
|
||||||
|
|
||||||
|
|
||||||
grid.getColumnConstraints()
|
grid.getColumnConstraints()
|
||||||
.addAll(
|
.addAll(
|
||||||
createShareConstraint(grid, STORE_TYPE_WIDTH), createShareConstraint(grid, NAME_WIDTH),
|
createShareConstraint(grid, STORE_TYPE_WIDTH), createShareConstraint(grid, NAME_WIDTH),
|
||||||
|
@ -133,7 +139,7 @@ public class StoreEntryComp extends SimpleComp {
|
||||||
AppFont.small(size);
|
AppFont.small(size);
|
||||||
AppFont.small(date);
|
AppFont.small(date);
|
||||||
|
|
||||||
grid.getStyleClass().add("store-entry-comp");
|
grid.getStyleClass().add("store-entry-grid");
|
||||||
|
|
||||||
grid.setOnMouseClicked(event -> {
|
grid.setOnMouseClicked(event -> {
|
||||||
if (entry.getEditable().get()) {
|
if (entry.getEditable().get()) {
|
||||||
|
@ -143,7 +149,12 @@ public class StoreEntryComp extends SimpleComp {
|
||||||
|
|
||||||
applyState(grid);
|
applyState(grid);
|
||||||
|
|
||||||
return grid;
|
var button = new JFXButton();
|
||||||
|
button.setGraphic(grid);
|
||||||
|
GrowAugment.create(true, false).augment(new SimpleCompStructure<>(grid));
|
||||||
|
button.getStyleClass().add("store-entry-comp");
|
||||||
|
button.setMaxWidth(2000);
|
||||||
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Comp<?> createButtonBar() {
|
private Comp<?> createButtonBar() {
|
||||||
|
|
|
@ -4,7 +4,6 @@ import io.xpipe.app.comp.base.ListViewComp;
|
||||||
import io.xpipe.app.comp.base.MultiContentComp;
|
import io.xpipe.app.comp.base.MultiContentComp;
|
||||||
import io.xpipe.extension.fxcomps.Comp;
|
import io.xpipe.extension.fxcomps.Comp;
|
||||||
import io.xpipe.extension.fxcomps.SimpleComp;
|
import io.xpipe.extension.fxcomps.SimpleComp;
|
||||||
import io.xpipe.extension.fxcomps.augment.GrowAugment;
|
|
||||||
import io.xpipe.extension.fxcomps.util.BindingsHelper;
|
import io.xpipe.extension.fxcomps.util.BindingsHelper;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.value.ObservableBooleanValue;
|
import javafx.beans.value.ObservableBooleanValue;
|
||||||
|
@ -15,14 +14,18 @@ import java.util.Map;
|
||||||
public class StoreEntryListComp extends SimpleComp {
|
public class StoreEntryListComp extends SimpleComp {
|
||||||
|
|
||||||
private Comp<?> createList() {
|
private Comp<?> createList() {
|
||||||
|
var topLevel = StoreEntrySection.createTopLevels();
|
||||||
|
var filtered = BindingsHelper.filteredContentBinding(
|
||||||
|
topLevel,
|
||||||
|
StoreViewState.get().getFilterString().map(s -> (storeEntrySection -> storeEntrySection.shouldShow(s))));
|
||||||
var content = new ListViewComp<>(
|
var content = new ListViewComp<>(
|
||||||
StoreViewState.get().getShownEntries(),
|
filtered,
|
||||||
StoreViewState.get().getAllEntries(),
|
topLevel,
|
||||||
null,
|
null,
|
||||||
(StoreEntryWrapper e) -> {
|
(StoreEntrySection e) -> {
|
||||||
return new StoreEntryComp(e).apply(GrowAugment.create(true, false));
|
return e.comp(true);
|
||||||
});
|
});
|
||||||
return content;
|
return content.styleClass("store-list-comp");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,120 @@
|
||||||
|
package io.xpipe.app.comp.storage.store;
|
||||||
|
|
||||||
|
import io.xpipe.app.comp.base.ListBoxViewComp;
|
||||||
|
import io.xpipe.app.comp.storage.StorageFilter;
|
||||||
|
import io.xpipe.extension.fxcomps.Comp;
|
||||||
|
import io.xpipe.extension.fxcomps.augment.GrowAugment;
|
||||||
|
import io.xpipe.extension.fxcomps.impl.HorizontalComp;
|
||||||
|
import io.xpipe.extension.fxcomps.impl.VerticalComp;
|
||||||
|
import io.xpipe.extension.fxcomps.util.BindingsHelper;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.scene.layout.*;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import org.kordamp.ikonli.javafx.FontIcon;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class StoreEntrySection implements StorageFilter.Filterable {
|
||||||
|
|
||||||
|
public StoreEntrySection(StoreEntryWrapper entry, ObservableList<StoreEntrySection> children) {
|
||||||
|
this.entry = entry;
|
||||||
|
this.children = children;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ObservableList<StoreEntrySection> createTopLevels() {
|
||||||
|
var topLevel = BindingsHelper.mappedContentBinding(
|
||||||
|
StoreViewState.get()
|
||||||
|
.getAllEntries()
|
||||||
|
.filtered(storeEntryWrapper ->
|
||||||
|
!storeEntryWrapper.getEntry().getState().isUsable()
|
||||||
|
|| storeEntryWrapper
|
||||||
|
.getEntry()
|
||||||
|
.getProvider()
|
||||||
|
.getParent(storeEntryWrapper
|
||||||
|
.getEntry()
|
||||||
|
.getStore())
|
||||||
|
== null),
|
||||||
|
storeEntryWrapper -> create(storeEntryWrapper));
|
||||||
|
var ordered = BindingsHelper.orderedContentBinding(
|
||||||
|
topLevel,
|
||||||
|
Comparator.<StoreEntrySection, Instant>comparing(storeEntrySection ->
|
||||||
|
storeEntrySection.entry.lastAccessProperty().getValue())
|
||||||
|
.reversed());
|
||||||
|
return ordered;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StoreEntrySection create(StoreEntryWrapper e) {
|
||||||
|
if (!e.getEntry().getState().isUsable()) {
|
||||||
|
return new StoreEntrySection(e, FXCollections.observableArrayList());
|
||||||
|
}
|
||||||
|
|
||||||
|
var children = BindingsHelper.mappedContentBinding(
|
||||||
|
StoreViewState.get()
|
||||||
|
.getAllEntries()
|
||||||
|
.filtered(other -> other.getEntry().getState().isUsable()
|
||||||
|
&& e.getEntry()
|
||||||
|
.getStore()
|
||||||
|
.equals(other.getEntry()
|
||||||
|
.getProvider()
|
||||||
|
.getParent(other.getEntry().getStore()))),
|
||||||
|
entry1 -> create(entry1));
|
||||||
|
var ordered = BindingsHelper.orderedContentBinding(
|
||||||
|
children,
|
||||||
|
Comparator.<StoreEntrySection, Instant>comparing(storeEntrySection ->
|
||||||
|
storeEntrySection.entry.lastAccessProperty().getValue())
|
||||||
|
.reversed());
|
||||||
|
return new StoreEntrySection(e, ordered);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final StoreEntryWrapper entry;
|
||||||
|
private final ObservableList<StoreEntrySection> children;
|
||||||
|
|
||||||
|
public Comp<?> comp(boolean top) {
|
||||||
|
var root = new StoreEntryComp(entry).apply(struc -> HBox.setHgrow(struc.get(), Priority.ALWAYS));
|
||||||
|
var icon = Comp.of(() -> {
|
||||||
|
var padding = new FontIcon("mdal-arrow_forward_ios");
|
||||||
|
padding.setIconSize(14);
|
||||||
|
var pain = new StackPane(padding);
|
||||||
|
pain.setMinWidth(20);
|
||||||
|
pain.setMaxHeight(20);
|
||||||
|
return pain;
|
||||||
|
});
|
||||||
|
List<Comp<?>> topEntryList = top ? List.of(root) : List.of(icon, root);
|
||||||
|
|
||||||
|
if (children.size() == 0) {
|
||||||
|
return new HorizontalComp(topEntryList);
|
||||||
|
}
|
||||||
|
|
||||||
|
var all = BindingsHelper.orderedContentBinding(
|
||||||
|
children,
|
||||||
|
Comparator.comparing(storeEntrySection ->
|
||||||
|
storeEntrySection.entry.lastAccessProperty().getValue()));
|
||||||
|
var shown = BindingsHelper.filteredContentBinding(
|
||||||
|
all,
|
||||||
|
StoreViewState.get().getFilterString().map(s -> (storeEntrySection -> storeEntrySection.shouldShow(s))));
|
||||||
|
var content = new ListBoxViewComp<>(shown, all, (StoreEntrySection e) -> {
|
||||||
|
return e.comp(false).apply(GrowAugment.create(true, false));
|
||||||
|
})
|
||||||
|
.apply(struc -> HBox.setHgrow(struc.get(), Priority.ALWAYS))
|
||||||
|
.apply(struc -> struc.get().backgroundProperty().set(Background.fill(Color.color(0, 0, 0, 0.01))));
|
||||||
|
var spacer = Comp.of(() -> {
|
||||||
|
var padding = new Region();
|
||||||
|
padding.setMinWidth(25);
|
||||||
|
padding.setMaxWidth(25);
|
||||||
|
return padding;
|
||||||
|
});
|
||||||
|
return new VerticalComp(List.of(
|
||||||
|
new HorizontalComp(topEntryList),
|
||||||
|
new HorizontalComp(List.of(spacer, content))
|
||||||
|
.apply(struc -> struc.get().setFillHeight(true))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldShow(String filter) {
|
||||||
|
return entry.shouldShow(filter)
|
||||||
|
|| children.stream().anyMatch(storeEntrySection -> storeEntrySection.shouldShow(filter));
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ import javafx.application.Platform;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
import javafx.beans.value.ObservableBooleanValue;
|
import javafx.beans.value.ObservableBooleanValue;
|
||||||
|
import javafx.beans.value.ObservableValue;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
|
|
||||||
|
@ -95,6 +96,10 @@ public class StoreViewState {
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ObservableValue<String> getFilterString() {
|
||||||
|
return filter.filterProperty();
|
||||||
|
}
|
||||||
|
|
||||||
public ObservableList<StoreEntryWrapper> getAllEntries() {
|
public ObservableList<StoreEntryWrapper> getAllEntries() {
|
||||||
return allEntries;
|
return allEntries;
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,6 +78,14 @@ public class App extends Application {
|
||||||
focus();
|
focus();
|
||||||
});
|
});
|
||||||
appWindow.show();
|
appWindow.show();
|
||||||
|
|
||||||
|
// For demo purposes
|
||||||
|
if (true) {
|
||||||
|
stage.setX(310);
|
||||||
|
stage.setY(178);
|
||||||
|
stage.setWidth(1300);
|
||||||
|
stage.setHeight(730);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void focus() {
|
public void focus() {
|
||||||
|
|
|
@ -60,6 +60,7 @@ public class DataSourceCollection extends StorageElement {
|
||||||
var json = mapper.readTree(dir.resolve("collection.json").toFile());
|
var json = mapper.readTree(dir.resolve("collection.json").toFile());
|
||||||
var uuid = UUID.fromString(json.required("uuid").textValue());
|
var uuid = UUID.fromString(json.required("uuid").textValue());
|
||||||
var name = json.required("name").textValue();
|
var name = json.required("name").textValue();
|
||||||
|
Objects.requireNonNull(name);
|
||||||
var lastModified = Instant.parse(json.required("lastModified").textValue());
|
var lastModified = Instant.parse(json.required("lastModified").textValue());
|
||||||
|
|
||||||
JavaType listType = mapper.getTypeFactory().constructCollectionType(ArrayList.class, UUID.class);
|
JavaType listType = mapper.getTypeFactory().constructCollectionType(ArrayList.class, UUID.class);
|
||||||
|
|
|
@ -82,7 +82,7 @@ public abstract class DataStorage {
|
||||||
}
|
}
|
||||||
|
|
||||||
public DataSourceCollection getInternalCollection() {
|
public DataSourceCollection getInternalCollection() {
|
||||||
var found = sourceCollections.stream().filter(o -> o.getName().equals("Internal")).findAny();
|
var found = sourceCollections.stream().filter(o -> o.getName() != null && o.getName().equals("Internal")).findAny();
|
||||||
if (found.isPresent()) {
|
if (found.isPresent()) {
|
||||||
return found.get();
|
return found.get();
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,16 +17,16 @@ public class DataStorageWriter {
|
||||||
public static JsonNode storeToNode(DataStore store) {
|
public static JsonNode storeToNode(DataStore store) {
|
||||||
var mapper = JacksonMapper.newMapper();
|
var mapper = JacksonMapper.newMapper();
|
||||||
var tree = mapper.valueToTree(store);
|
var tree = mapper.valueToTree(store);
|
||||||
return replaceReferencesWithIds(store, tree);
|
return replaceReferencesWithIds(tree, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JsonNode sourceToNode(DataSource<?> source) {
|
public static JsonNode sourceToNode(DataSource<?> source) {
|
||||||
var mapper = JacksonMapper.newMapper();
|
var mapper = JacksonMapper.newMapper();
|
||||||
var tree = mapper.valueToTree(source);
|
var tree = mapper.valueToTree(source);
|
||||||
return replaceReferencesWithIds(source, tree);
|
return replaceReferencesWithIds(tree, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static JsonNode replaceReferencesWithIds(Object root, JsonNode node) {
|
private static JsonNode replaceReferencesWithIds(JsonNode node, boolean isRoot) {
|
||||||
var mapper = JacksonMapper.newMapper();
|
var mapper = JacksonMapper.newMapper();
|
||||||
|
|
||||||
node = replaceReferencesWithIds(
|
node = replaceReferencesWithIds(
|
||||||
|
@ -38,7 +38,7 @@ public class DataStorageWriter {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var store = mapper.treeToValue(possibleReference, DataStore.class);
|
var store = mapper.treeToValue(possibleReference, DataStore.class);
|
||||||
if (root == null || !root.equals(store)) {
|
if (!isRoot) {
|
||||||
var found = DataStorage.get().getEntryByStore(store);
|
var found = DataStorage.get().getEntryByStore(store);
|
||||||
return found.map(dataSourceEntry -> dataSourceEntry.getUuid());
|
return found.map(dataSourceEntry -> dataSourceEntry.getUuid());
|
||||||
}
|
}
|
||||||
|
@ -46,14 +46,14 @@ public class DataStorageWriter {
|
||||||
}
|
}
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
},
|
},
|
||||||
"storeId");
|
"storeId", isRoot);
|
||||||
|
|
||||||
node = replaceReferencesWithIds(
|
node = replaceReferencesWithIds(
|
||||||
node,
|
node,
|
||||||
possibleReference -> {
|
possibleReference -> {
|
||||||
try {
|
try {
|
||||||
var source = mapper.treeToValue(possibleReference, DataSource.class);
|
var source = mapper.treeToValue(possibleReference, DataSource.class);
|
||||||
if (root == null || !root.equals(source)) {
|
if (!isRoot) {
|
||||||
var found = DataStorage.get().getEntryBySource(source);
|
var found = DataStorage.get().getEntryBySource(source);
|
||||||
return found.map(dataSourceEntry -> dataSourceEntry.getUuid());
|
return found.map(dataSourceEntry -> dataSourceEntry.getUuid());
|
||||||
}
|
}
|
||||||
|
@ -61,13 +61,13 @@ public class DataStorageWriter {
|
||||||
}
|
}
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
},
|
},
|
||||||
"sourceId");
|
"sourceId", isRoot);
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static JsonNode replaceReferencesWithIds(
|
private static JsonNode replaceReferencesWithIds(
|
||||||
JsonNode node, Function<JsonNode, Optional<UUID>> function, String key) {
|
JsonNode node, Function<JsonNode, Optional<UUID>> function, String key, boolean isRoot) {
|
||||||
if (!node.isObject()) {
|
if (!node.isObject()) {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@ public class DataStorageWriter {
|
||||||
|
|
||||||
var replacement = JsonNodeFactory.instance.objectNode();
|
var replacement = JsonNodeFactory.instance.objectNode();
|
||||||
node.fields().forEachRemaining(stringJsonNodeEntry -> {
|
node.fields().forEachRemaining(stringJsonNodeEntry -> {
|
||||||
var resolved = replaceReferencesWithIds(null, stringJsonNodeEntry.getValue());
|
var resolved = replaceReferencesWithIds(stringJsonNodeEntry.getValue(), false);
|
||||||
replacement.set(stringJsonNodeEntry.getKey(), resolved);
|
replacement.set(stringJsonNodeEntry.getKey(), resolved);
|
||||||
});
|
});
|
||||||
return replacement;
|
return replacement;
|
||||||
|
|
|
@ -75,3 +75,7 @@
|
||||||
-fx-padding: 0;
|
-fx-padding: 0;
|
||||||
-fx-focus-color: transparent;
|
-fx-focus-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.store-list-comp .list-cell {
|
||||||
|
-fx-padding: 0;
|
||||||
|
}
|
||||||
|
|
|
@ -1,27 +1,30 @@
|
||||||
|
|
||||||
.store-entry-comp .date, .store-entry-comp .summary {
|
.store-entry-grid .date, .store-entry-grid .summary {
|
||||||
-fx-text-fill: -xp-text-light;
|
-fx-text-fill: -xp-text-light;
|
||||||
}
|
}
|
||||||
|
|
||||||
.store-entry-comp:failed .jfx-text-field {
|
.store-entry-grid:failed .jfx-text-field {
|
||||||
-fx-text-fill: red;
|
-fx-text-fill: red;
|
||||||
}
|
}
|
||||||
|
|
||||||
.store-entry-comp:incomplete .jfx-text-field {
|
.store-entry-grid:incomplete .jfx-text-field {
|
||||||
-fx-text-fill: gray;
|
-fx-text-fill: gray;
|
||||||
}
|
}
|
||||||
.store-entry-comp:incomplete .summary {
|
.store-entry-grid:incomplete .summary {
|
||||||
-fx-text-fill: gray;
|
-fx-text-fill: gray;
|
||||||
}
|
}
|
||||||
.store-entry-comp:incomplete .information {
|
.store-entry-grid:incomplete .information {
|
||||||
-fx-text-fill: gray;
|
-fx-text-fill: gray;
|
||||||
}
|
}
|
||||||
.store-entry-comp:incomplete .date {
|
.store-entry-grid:incomplete .date {
|
||||||
-fx-text-fill: gray;
|
-fx-text-fill: gray;
|
||||||
}
|
}
|
||||||
.store-entry-comp:incomplete .icon {
|
.store-entry-grid:incomplete .icon {
|
||||||
-fx-opacity: 0.5;
|
-fx-opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
.store-entry-comp {
|
||||||
|
-fx-padding: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -248,6 +248,7 @@ productionTest {
|
||||||
// + System.getProperty("java.vm.version") + ")")
|
// + System.getProperty("java.vm.version") + ")")
|
||||||
|
|
||||||
graalvmNative {
|
graalvmNative {
|
||||||
|
testSupport = false
|
||||||
binaries {
|
binaries {
|
||||||
main {
|
main {
|
||||||
imageName = 'xpipe' // The name of the native image, defaults to the project name
|
imageName = 'xpipe' // The name of the native image, defaults to the project name
|
||||||
|
@ -261,8 +262,6 @@ graalvmNative {
|
||||||
'-Dpicocli.converters.excludes=java.time.*,java.sql.*'
|
'-Dpicocli.converters.excludes=java.time.*,java.sql.*'
|
||||||
)
|
)
|
||||||
buildArgs.addAll(
|
buildArgs.addAll(
|
||||||
'--static',
|
|
||||||
'--libc=musl',
|
|
||||||
// '--debug-attach=8000',
|
// '--debug-attach=8000',
|
||||||
'--enable-https',
|
'--enable-https',
|
||||||
'--install-exit-handlers',
|
'--install-exit-handlers',
|
||||||
|
@ -279,6 +278,13 @@ graalvmNative {
|
||||||
'org.ocpsoft.prettytime,' +
|
'org.ocpsoft.prettytime,' +
|
||||||
'com.fasterxml.jackson')
|
'com.fasterxml.jackson')
|
||||||
|
|
||||||
|
if (org.gradle.internal.os.OperatingSystem.current().isLinux()) {
|
||||||
|
buildArgs.addAll(
|
||||||
|
'--static',
|
||||||
|
'--libc=musl'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Build Time
|
// Build Time
|
||||||
systemProperties(prodProperties)
|
systemProperties(prodProperties)
|
||||||
}
|
}
|
||||||
|
|
44
cli/musl-setup.sh
Executable file
44
cli/musl-setup.sh
Executable file
|
@ -0,0 +1,44 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# This script builds the bundle inside the Docker container and then copies it to the host machine.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
# Set up the URL to the version of musl used by alpine at the time of writing.
|
||||||
|
LATEST_MUSL_URL="http://more.musl.cc/10/x86_64-linux-musl/x86_64-linux-musl-native.tgz"
|
||||||
|
# Set up the URL for the latest zlib version available at the time of writing.
|
||||||
|
LATEST_ZLIB_URL="https://www.zlib.net/zlib-1.2.13.tar.gz"
|
||||||
|
BUNDLE_DIR_NAME="bundle"
|
||||||
|
DIR="$1"
|
||||||
|
BUILD_DIR="$DIR/build/musl"
|
||||||
|
|
||||||
|
# Create the folder that will contain the finished bundle.
|
||||||
|
mkdir -p $BUILD_DIR
|
||||||
|
cd $BUILD_DIR
|
||||||
|
|
||||||
|
echo "Downloading musl library."
|
||||||
|
wget "${LATEST_MUSL_URL}"
|
||||||
|
echo "Downloading zlib library."
|
||||||
|
wget "${LATEST_ZLIB_URL}"
|
||||||
|
# Grab the names of the archives from the URL.
|
||||||
|
MUSL_TAR="${LATEST_MUSL_URL##*/}"
|
||||||
|
ZLIB_TAR="${LATEST_ZLIB_URL##*/}"
|
||||||
|
|
||||||
|
# Compile musl, compiling only the static musl libraries.
|
||||||
|
echo "Extracting musl."
|
||||||
|
tar xvzf "$MUSL_TAR"
|
||||||
|
MUSL_DIR=$(tar tzf "${MUSL_TAR}" | cut -d'/' -f1 | uniq)
|
||||||
|
TOOLCHAIN_DIR="${BUILD_DIR=}/${MUSL_DIR}"
|
||||||
|
echo $TOOLCHAIN_DIR
|
||||||
|
|
||||||
|
# Compile zlib with the musl library we just built.
|
||||||
|
export CC="${TOOLCHAIN_DIR}/bin/gcc"
|
||||||
|
|
||||||
|
echo "Extracting zlib."
|
||||||
|
tar xvzf "${ZLIB_TAR}"
|
||||||
|
ZLIB_DIR=$(tar tzf "${ZLIB_TAR}" | cut -d'/' -f1 | uniq)
|
||||||
|
cd "${ZLIB_DIR}"
|
||||||
|
echo "Configuring zlib."
|
||||||
|
echo $TOOLCHAIN_DIR
|
||||||
|
./configure --static --prefix="${TOOLCHAIN_DIR}"
|
||||||
|
echo "Building zlib."
|
||||||
|
make
|
||||||
|
make install
|
7
cli/native-build-musl.sh
Executable file
7
cli/native-build-musl.sh
Executable file
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
DIR="$1"
|
||||||
|
MUSL_DIR="$DIR/build/musl/x86_64-linux-musl-native"
|
||||||
|
|
||||||
|
export PATH="$PATH:$MUSL_DIR/bin"
|
||||||
|
"$DIR/../gradlew" :cli:nativeCompile "-Dorg.gradle.jvmargs=-Xmx2048M"
|
|
@ -1,3 +1,3 @@
|
||||||
CALL "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat"
|
CALL "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat"
|
||||||
set JAVA_HOME=%GRAALVM_HOME%
|
set JAVA_HOME=%GRAALVM_HOME%
|
||||||
"%~dp0\..\gradlew.bat" :cli:nativeCompile
|
"%~dp0\..\gradlew.bat" :cli:nativeCompile "-Dorg.gradle.jvmargs=-Xmx2048M"
|
|
@ -11,11 +11,9 @@ import java.util.function.Predicate;
|
||||||
|
|
||||||
public interface ShellProcessControl extends ProcessControl {
|
public interface ShellProcessControl extends ProcessControl {
|
||||||
|
|
||||||
default String prepareTerminalOpen() throws Exception {
|
String prepareTerminalOpen() throws Exception;
|
||||||
return prepareTerminalOpen(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
String prepareTerminalOpen(String content) throws Exception;
|
String prepareIntermediateTerminalOpen(String content) throws Exception;
|
||||||
|
|
||||||
default String executeStringSimpleCommand(String command) throws Exception {
|
default String executeStringSimpleCommand(String command) throws Exception {
|
||||||
try (CommandProcessControl c = command(command).start()) {
|
try (CommandProcessControl c = command(command).start()) {
|
||||||
|
@ -60,6 +58,8 @@ public interface ShellProcessControl extends ProcessControl {
|
||||||
|
|
||||||
ShellProcessControl elevation(SecretValue value);
|
ShellProcessControl elevation(SecretValue value);
|
||||||
|
|
||||||
|
ShellProcessControl initWith(List<String> cmds);
|
||||||
|
|
||||||
SecretValue getElevationPassword();
|
SecretValue getElevationPassword();
|
||||||
|
|
||||||
default ShellProcessControl subShell(@NonNull ShellType type) {
|
default ShellProcessControl subShell(@NonNull ShellType type) {
|
||||||
|
@ -80,10 +80,9 @@ public interface ShellProcessControl extends ProcessControl {
|
||||||
|
|
||||||
ShellProcessControl subShell(
|
ShellProcessControl subShell(
|
||||||
@NonNull Function<ShellProcessControl, String> command,
|
@NonNull Function<ShellProcessControl, String> command,
|
||||||
BiFunction<ShellProcessControl, String, String> terminalCommand
|
BiFunction<ShellProcessControl, String, String> terminalCommand);
|
||||||
);
|
|
||||||
|
|
||||||
void executeCommand(String command) throws Exception;
|
void executeLine(String command) throws Exception;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
ShellProcessControl start() throws Exception;
|
ShellProcessControl start() throws Exception;
|
||||||
|
@ -91,8 +90,7 @@ public interface ShellProcessControl extends ProcessControl {
|
||||||
CommandProcessControl command(Function<ShellProcessControl, String> command);
|
CommandProcessControl command(Function<ShellProcessControl, String> command);
|
||||||
|
|
||||||
CommandProcessControl command(
|
CommandProcessControl command(
|
||||||
Function<ShellProcessControl, String> command, Function<ShellProcessControl, String> terminalCommand
|
Function<ShellProcessControl, String> command, Function<ShellProcessControl, String> terminalCommand);
|
||||||
);
|
|
||||||
|
|
||||||
default CommandProcessControl command(String command) {
|
default CommandProcessControl command(String command) {
|
||||||
return command(shellProcessControl -> command);
|
return command(shellProcessControl -> command);
|
||||||
|
|
|
@ -3,7 +3,6 @@ package io.xpipe.core.process;
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||||
import io.xpipe.core.charsetter.NewLine;
|
import io.xpipe.core.charsetter.NewLine;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -55,7 +54,7 @@ public interface ShellType {
|
||||||
return getEchoCommand(s, false);
|
return getEchoCommand(s, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
String getSetVariableCommand(String variable, String value);
|
String getSetEnvironmentVariableCommand(String variable, String value);
|
||||||
|
|
||||||
|
|
||||||
String getEchoCommand(String s, boolean toErrorStream);
|
String getEchoCommand(String s, boolean toErrorStream);
|
||||||
|
@ -67,8 +66,14 @@ public interface ShellType {
|
||||||
|
|
||||||
String getPrintVariableCommand(String prefix, String name);
|
String getPrintVariableCommand(String prefix, String name);
|
||||||
|
|
||||||
|
default String getPrintEnvironmentVariableCommand(String name) {
|
||||||
|
return getPrintVariableCommand(name);
|
||||||
|
}
|
||||||
|
|
||||||
String getNormalOpenCommand();
|
String getNormalOpenCommand();
|
||||||
|
|
||||||
|
String getInitFileOpenCommand(String file);
|
||||||
|
|
||||||
String executeCommandWithShell(String cmd);
|
String executeCommandWithShell(String cmd);
|
||||||
|
|
||||||
List<String> executeCommandListWithShell(String cmd);
|
List<String> executeCommandListWithShell(String cmd);
|
||||||
|
@ -79,7 +84,7 @@ public interface ShellType {
|
||||||
|
|
||||||
String getStreamFileWriteCommand(String file);
|
String getStreamFileWriteCommand(String file);
|
||||||
|
|
||||||
String getSimpleFileWriteCommand(String content, String file);
|
String getTextFileWriteCommand(String content, String file);
|
||||||
|
|
||||||
String getFileDeleteCommand(String file);
|
String getFileDeleteCommand(String file);
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
@ -57,7 +58,7 @@ public class ShellTypes {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getSetVariableCommand(String variableName, String value) {
|
public String getSetEnvironmentVariableCommand(String variableName, String value) {
|
||||||
return ("set \"" + variableName + "=" + value.replaceAll("\"", "^$0") + "\"");
|
return ("set \"" + variableName + "=" + value.replaceAll("\"", "^$0") + "\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,13 +69,13 @@ public class ShellTypes {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getEchoCommand(String s, boolean toErrorStream) {
|
public String getEchoCommand(String s, boolean toErrorStream) {
|
||||||
return "(echo " + s + (toErrorStream ? ")1>&2" : ")");
|
return "(echo " + escapeStringValue(s).replaceAll("\r\n", "^\r\n") + (toErrorStream ? ")1>&2" : ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getScriptEchoCommand(String s) {
|
public String getScriptEchoCommand(String s) {
|
||||||
return ("@echo off\r\nset \"echov=" + escapeStringValue(s)
|
return ("set \"echov=" + escapeStringValue(s)
|
||||||
+ "\"\r\necho %echov%\r\n@echo on\n(goto) 2>nul & del \"%~f0\"");
|
+ "\"\r\necho %echov%\r\n@echo on\r\n(goto) 2>nul & del \"%~f0\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -103,7 +104,7 @@ public class ShellTypes {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String prepareScriptContent(String content) {
|
public String prepareScriptContent(String content) {
|
||||||
return "@echo off\n" + content;
|
return "@echo off\r\n" + content;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -125,6 +126,11 @@ public class ShellTypes {
|
||||||
return "cmd";
|
return "cmd";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getInitFileOpenCommand(String file) {
|
||||||
|
return "cmd /K \"" + file + "\"";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String executeCommandWithShell(String cmd) {
|
public String executeCommandWithShell(String cmd) {
|
||||||
return "cmd.exe /C " + cmd + "";
|
return "cmd.exe /C " + cmd + "";
|
||||||
|
@ -151,8 +157,15 @@ public class ShellTypes {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getSimpleFileWriteCommand(String content, String file) {
|
public String getTextFileWriteCommand(String content, String file) {
|
||||||
return "echo " + content + " > \"" + file + "\"";
|
// if (true) return getEchoCommand(content, false) + " > \"" + file + "\"";
|
||||||
|
|
||||||
|
var command = new ArrayList<String>();
|
||||||
|
for (String line : content.split("(\n|\r\n)")) {
|
||||||
|
command.add("echo " + escapeStringValue(line) + ">> \"" + file + "\"");
|
||||||
|
command.add("echo." + ">> \"" + file + "\"");
|
||||||
|
}
|
||||||
|
return String.join("&", command);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -219,7 +232,7 @@ public class ShellTypes {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void disableHistory(ShellProcessControl pc) throws Exception {
|
public void disableHistory(ShellProcessControl pc) throws Exception {
|
||||||
pc.executeCommand("Set-PSReadLineOption -HistorySaveStyle SaveNothing");
|
pc.executeLine("Set-PSReadLineOption -HistorySaveStyle SaveNothing");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -233,8 +246,8 @@ public class ShellTypes {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getSimpleFileWriteCommand(String content, String file) {
|
public String getTextFileWriteCommand(String content, String file) {
|
||||||
return "echo \"" + content + "\" | Out-File \"" + file + "\"";
|
return "echo \"" + content.replaceAll("(\n|\r\n)", "`n") + "\" | Out-File \"" + file + "\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -258,7 +271,12 @@ public class ShellTypes {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getSetVariableCommand(String variableName, String value) {
|
public String getPrintEnvironmentVariableCommand(String name) {
|
||||||
|
return "echo \"" + "$env:" + escapeStringValue(name) + "\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSetEnvironmentVariableCommand(String variableName, String value) {
|
||||||
return "$env:" + variableName + " = \"" + escapeStringValue(value) + "\"";
|
return "$env:" + variableName + " = \"" + escapeStringValue(value) + "\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,6 +338,11 @@ public class ShellTypes {
|
||||||
return "powershell /nologo";
|
return "powershell /nologo";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getInitFileOpenCommand(String file) {
|
||||||
|
return "powershell.exe -NoExit -File \"" + file + "\"";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String executeCommandWithShell(String cmd) {
|
public String executeCommandWithShell(String cmd) {
|
||||||
return "powershell.exe -Command '" + cmd + "'";
|
return "powershell.exe -Command '" + cmd + "'";
|
||||||
|
@ -394,8 +417,13 @@ public class ShellTypes {
|
||||||
public abstract static class PosixBase implements ShellType {
|
public abstract static class PosixBase implements ShellType {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getSimpleFileWriteCommand(String content, String file) {
|
public String getInitFileOpenCommand(String file) {
|
||||||
return "echo \"" + content + "\" > \"" + file + "\"";
|
return getName() + " --rcfile \"" + file + "\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getTextFileWriteCommand(String content, String file) {
|
||||||
|
return "echo -e '" + content.replaceAll("\n", "\\\\n").replaceAll("'","\\\\'") + "' > \"" + file + "\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -461,7 +489,7 @@ public class ShellTypes {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void disableHistory(ShellProcessControl pc) throws Exception {
|
public void disableHistory(ShellProcessControl pc) throws Exception {
|
||||||
pc.executeCommand("unset HISTFILE");
|
pc.executeLine("unset HISTFILE");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -485,7 +513,7 @@ public class ShellTypes {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getSetVariableCommand(String variable, String value) {
|
public String getSetEnvironmentVariableCommand(String variable, String value) {
|
||||||
return "export " + variable + "=\"" + value + "\"";
|
return "export " + variable + "=\"" + value + "\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,9 +79,9 @@ public class XPipeInstallation {
|
||||||
public static Path getLocalDynamicLibraryDirectory() {
|
public static Path getLocalDynamicLibraryDirectory() {
|
||||||
Path path = getLocalInstallationBasePath();
|
Path path = getLocalInstallationBasePath();
|
||||||
if (OsType.getLocal().equals(OsType.WINDOWS)) {
|
if (OsType.getLocal().equals(OsType.WINDOWS)) {
|
||||||
return path.resolve("runtime").resolve("bin");
|
return path.resolve("app").resolve("runtime").resolve("bin");
|
||||||
} else if (OsType.getLocal().equals(OsType.LINUX)) {
|
} else if (OsType.getLocal().equals(OsType.LINUX)) {
|
||||||
return path.resolve("lib").resolve("runtime").resolve("lib");
|
return path.resolve("app").resolve("lib").resolve("runtime").resolve("lib");
|
||||||
} else {
|
} else {
|
||||||
return path.resolve("Contents")
|
return path.resolve("Contents")
|
||||||
.resolve("runtime")
|
.resolve("runtime")
|
||||||
|
@ -95,7 +95,7 @@ public class XPipeInstallation {
|
||||||
Path path = getLocalInstallationBasePath();
|
Path path = getLocalInstallationBasePath();
|
||||||
return OsType.getLocal().equals(OsType.MAC)
|
return OsType.getLocal().equals(OsType.MAC)
|
||||||
? path.resolve("Contents").resolve("Resources").resolve("extensions")
|
? path.resolve("Contents").resolve("Resources").resolve("extensions")
|
||||||
: path.resolve("extensions");
|
: path.resolve("app").resolve("extensions");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Path getLocalInstallationBasePathForJavaExecutable(Path executable) {
|
private static Path getLocalInstallationBasePathForJavaExecutable(Path executable) {
|
||||||
|
@ -108,9 +108,9 @@ public class XPipeInstallation {
|
||||||
.getParent()
|
.getParent()
|
||||||
.getParent();
|
.getParent();
|
||||||
} else if (OsType.getLocal().equals(OsType.LINUX)) {
|
} else if (OsType.getLocal().equals(OsType.LINUX)) {
|
||||||
return executable.getParent().getParent().getParent().getParent();
|
return executable.getParent().getParent().getParent().getParent().getParent();
|
||||||
} else {
|
} else {
|
||||||
return executable.getParent().getParent().getParent();
|
return executable.getParent().getParent().getParent().getParent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,9 +118,9 @@ public class XPipeInstallation {
|
||||||
if (OsType.getLocal().equals(OsType.MAC)) {
|
if (OsType.getLocal().equals(OsType.MAC)) {
|
||||||
return executable.getParent().getParent().getParent();
|
return executable.getParent().getParent().getParent();
|
||||||
} else if (OsType.getLocal().equals(OsType.LINUX)) {
|
} else if (OsType.getLocal().equals(OsType.LINUX)) {
|
||||||
return executable.getParent().getParent();
|
return executable.getParent().getParent().getParent();
|
||||||
} else {
|
} else {
|
||||||
return executable.getParent();
|
return executable.getParent().getParent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
24
dist/cli.gradle
vendored
24
dist/cli.gradle
vendored
|
@ -3,8 +3,6 @@ import java.nio.file.Paths
|
||||||
import java.nio.file.StandardCopyOption
|
import java.nio.file.StandardCopyOption
|
||||||
|
|
||||||
def distDir = "$buildDir/dist"
|
def distDir = "$buildDir/dist"
|
||||||
def windows = org.gradle.internal.os.OperatingSystem.current().isWindows();
|
|
||||||
|
|
||||||
|
|
||||||
apply plugin: 'org.asciidoctor.jvm.convert'
|
apply plugin: 'org.asciidoctor.jvm.convert'
|
||||||
asciidoctor {
|
asciidoctor {
|
||||||
|
@ -29,21 +27,37 @@ task copyCompletion(type: Copy) {
|
||||||
into "$distDir/cli"
|
into "$distDir/cli"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
task setupMusl(type: Exec) {
|
||||||
|
commandLine "${project(':cli').projectDir.toString()}/musl-setup.sh", project(':cli').projectDir.toString()
|
||||||
|
}
|
||||||
|
|
||||||
task buildCli(type: DefaultTask) {
|
task buildCli(type: DefaultTask) {
|
||||||
if (!org.gradle.internal.os.OperatingSystem.current().isWindows()) {
|
if (org.gradle.internal.os.OperatingSystem.current().isLinux()) {
|
||||||
|
dependsOn(setupMusl)
|
||||||
|
project(':cli').getTasksByName('nativeCompile', true).forEach(v->v.mustRunAfter(setupMusl))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (org.gradle.internal.os.OperatingSystem.current().isMacOsX()) {
|
||||||
dependsOn(project(':cli').getTasksByName('nativeCompile', true))
|
dependsOn(project(':cli').getTasksByName('nativeCompile', true))
|
||||||
}
|
}
|
||||||
|
|
||||||
doLast {
|
doLast {
|
||||||
if (windows) {
|
if (rootProject.os.isWindows()) {
|
||||||
exec {
|
exec {
|
||||||
executable project(':cli').projectDir.toString() + '/native-build.bat'
|
executable project(':cli').projectDir.toString() + '/native-build.bat'
|
||||||
environment System.getenv()
|
environment System.getenv()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rootProject.os.isLinux()) {
|
||||||
|
exec {
|
||||||
|
commandLine project(':cli').projectDir.toString() + '/native-build-musl.sh', project(':cli').projectDir.toString()
|
||||||
|
environment System.getenv()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Files.createDirectories(Paths.get(distDir, 'cli'))
|
Files.createDirectories(Paths.get(distDir, 'cli'))
|
||||||
def ending = windows ? ".exe" : ""
|
def ending = rootProject.os.isWindows() ? ".exe" : ""
|
||||||
var outputFile = Paths.get(project(':cli').buildDir.toString() + "/native/nativeCompile/xpipe$ending")
|
var outputFile = Paths.get(project(':cli').buildDir.toString() + "/native/nativeCompile/xpipe$ending")
|
||||||
if (!Files.exists(outputFile)) {
|
if (!Files.exists(outputFile)) {
|
||||||
throw new IOException("Cli output file does not exist")
|
throw new IOException("Cli output file does not exist")
|
||||||
|
|
|
@ -39,6 +39,10 @@ public interface DataStoreProvider {
|
||||||
throw new ExtensionException("Provider " + getId() + " has no set category");
|
throw new ExtensionException("Provider " + getId() + " has no set category");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default DataStore getParent(DataStore store) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
default GuiDialog guiDialog(Property<DataStore> store) {
|
default GuiDialog guiDialog(Property<DataStore> store) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,6 +72,10 @@ public class TrackEvent {
|
||||||
return builder().type("debug").message(message);
|
return builder().type("debug").message(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static TrackEventBuilder withDebug(String cat, String message) {
|
||||||
|
return builder().category(cat).type("debug").message(message);
|
||||||
|
}
|
||||||
|
|
||||||
public static void debug(String cat, String message) {
|
public static void debug(String cat, String message) {
|
||||||
builder().category(cat).type("debug").message(message).build().handle();
|
builder().category(cat).type("debug").message(message).build().handle();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package io.xpipe.extension.fxcomps.util;
|
package io.xpipe.extension.fxcomps.util;
|
||||||
|
|
||||||
import javafx.beans.binding.Binding;
|
import javafx.beans.binding.Binding;
|
||||||
|
import javafx.beans.value.ObservableValue;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ListChangeListener;
|
import javafx.collections.ListChangeListener;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
|
|
||||||
|
@ -8,6 +10,7 @@ import java.lang.ref.WeakReference;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
public class BindingsHelper {
|
public class BindingsHelper {
|
||||||
|
|
||||||
|
@ -44,6 +47,45 @@ public class BindingsHelper {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T, V> ObservableList<T> mappedContentBinding(ObservableList<V> l2, Function<V, T> map) {
|
||||||
|
ObservableList<T> l1 = FXCollections.observableList(new ArrayList<>());
|
||||||
|
Runnable runnable = () -> {
|
||||||
|
setContent(l1, l2.stream().map(map).toList());
|
||||||
|
};
|
||||||
|
runnable.run();
|
||||||
|
l2.addListener((ListChangeListener<? super V>) c -> {
|
||||||
|
runnable.run();
|
||||||
|
});
|
||||||
|
return l1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <V> ObservableList<V> orderedContentBinding(ObservableList<V> l2, Comparator<V> comp) {
|
||||||
|
ObservableList<V> l1 = FXCollections.observableList(new ArrayList<>());
|
||||||
|
Runnable runnable = () -> {
|
||||||
|
setContent(l1, l2.stream().sorted(comp).toList());
|
||||||
|
};
|
||||||
|
runnable.run();
|
||||||
|
l2.addListener((ListChangeListener<? super V>) c -> {
|
||||||
|
runnable.run();
|
||||||
|
});
|
||||||
|
return l1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <V> ObservableList<V> filteredContentBinding(ObservableList<V> l2, ObservableValue<Predicate<V>> predicate) {
|
||||||
|
ObservableList<V> l1 = FXCollections.observableList(new ArrayList<>());
|
||||||
|
Runnable runnable = () -> {
|
||||||
|
setContent(l1, l2.stream().filter(predicate.getValue()).toList());
|
||||||
|
};
|
||||||
|
runnable.run();
|
||||||
|
l2.addListener((ListChangeListener<? super V>) c -> {
|
||||||
|
runnable.run();
|
||||||
|
});
|
||||||
|
predicate.addListener((c,o,n) -> {
|
||||||
|
runnable.run();
|
||||||
|
});
|
||||||
|
return l1;
|
||||||
|
}
|
||||||
|
|
||||||
public static <T> void setContent(ObservableList<T> toSet, List<? extends T> newList) {
|
public static <T> void setContent(ObservableList<T> toSet, List<? extends T> newList) {
|
||||||
if (toSet.equals(newList)) {
|
if (toSet.equals(newList)) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -40,8 +40,8 @@ public class DataStoreFormatter {
|
||||||
return func.apply(length);
|
return func.apply(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileString = func.apply(length - atString.length() - 4);
|
var fileString = func.apply(length - atString.length() - 3);
|
||||||
return String.format("%s -> %s", atString, fileString);
|
return String.format("%s > %s", atString, fileString);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String toName(DataStore input) {
|
public static String toName(DataStore input) {
|
||||||
|
@ -96,6 +96,17 @@ public class DataStoreFormatter {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (input.endsWith(".compute.amazonaws.com")) {
|
||||||
|
var split = input.split("\\.");
|
||||||
|
var name = split[0];
|
||||||
|
var region = split[1];
|
||||||
|
var lengthShare = (length - 3) / 2;
|
||||||
|
return String.format(
|
||||||
|
"%s.%s",
|
||||||
|
DataStoreFormatter.cut(name, lengthShare), DataStoreFormatter.cut(region, length - lengthShare)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return cut(input, length);
|
return cut(input, length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,24 @@
|
||||||
package io.xpipe.extension.util;
|
package io.xpipe.extension.util;
|
||||||
|
|
||||||
import io.xpipe.core.impl.FileNames;
|
import io.xpipe.core.impl.FileNames;
|
||||||
|
import io.xpipe.core.process.OsType;
|
||||||
import io.xpipe.core.process.ShellProcessControl;
|
import io.xpipe.core.process.ShellProcessControl;
|
||||||
import io.xpipe.core.process.ShellType;
|
import io.xpipe.core.process.ShellType;
|
||||||
import io.xpipe.core.store.ShellStore;
|
import io.xpipe.core.store.ShellStore;
|
||||||
import io.xpipe.core.util.SecretValue;
|
import io.xpipe.core.util.SecretValue;
|
||||||
import io.xpipe.core.util.XPipeSession;
|
|
||||||
import io.xpipe.core.util.XPipeTempDirectory;
|
import io.xpipe.core.util.XPipeTempDirectory;
|
||||||
import io.xpipe.extension.event.TrackEvent;
|
import io.xpipe.extension.event.TrackEvent;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
public class ScriptHelper {
|
public class ScriptHelper {
|
||||||
|
|
||||||
public static int getConnectionHash(String command) {
|
public static int getConnectionHash(String command) {
|
||||||
return Math.abs(Objects.hash(command, XPipeSession.get().getSystemSessionId()));
|
// This deterministic approach can cause permission problems when two different users execute the same command on a system
|
||||||
|
return new Random().nextInt(Integer.MAX_VALUE);
|
||||||
|
//return Math.abs(Objects.hash(command, XPipeSession.get().getSystemSessionId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
|
@ -25,6 +28,38 @@ public class ScriptHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String constructOpenWithInitScriptCommand(ShellProcessControl processControl, List<String> init, String toExecuteInShell) {
|
||||||
|
ShellType t = processControl.getShellType();
|
||||||
|
if (init.size() == 0 && toExecuteInShell == null) {
|
||||||
|
return t.getNormalOpenCommand();
|
||||||
|
}
|
||||||
|
|
||||||
|
String nl = t.getNewLine().getNewLineString();
|
||||||
|
var content = String.join(nl, init)
|
||||||
|
+ nl;
|
||||||
|
|
||||||
|
if (processControl.getOsType().equals(OsType.LINUX)
|
||||||
|
|| processControl.getOsType().equals(OsType.MAC)) {
|
||||||
|
content = "if [ -f ~/.bashrc ]; then . ~/.bashrc; fi\n" + content;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toExecuteInShell != null) {
|
||||||
|
content += toExecuteInShell + nl;
|
||||||
|
content += t.getExitCommand() + nl;
|
||||||
|
}
|
||||||
|
|
||||||
|
var initFile = createExecScript(processControl, content, true);
|
||||||
|
return t.getInitFileOpenCommand(initFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String prepend(ShellProcessControl processControl, List<String> init, String commands) {
|
||||||
|
var prefix = init != null && init.size() > 0
|
||||||
|
? String.join(processControl.getShellType().getNewLine().getNewLineString(), init)
|
||||||
|
+ processControl.getShellType().getNewLine().getNewLineString()
|
||||||
|
: "";
|
||||||
|
return prefix + commands;
|
||||||
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public static String createExecScript(ShellProcessControl processControl, String content, boolean restart) {
|
public static String createExecScript(ShellProcessControl processControl, String content, boolean restart) {
|
||||||
var fileName = "exec-" + getConnectionHash(content);
|
var fileName = "exec-" + getConnectionHash(content);
|
||||||
|
@ -35,7 +70,8 @@ public class ScriptHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
private static String createExecScript(ShellProcessControl processControl, String file, String content, boolean restart) {
|
private static String createExecScript(
|
||||||
|
ShellProcessControl processControl, String file, String content, boolean restart) {
|
||||||
ShellType type = processControl.getShellType();
|
ShellType type = processControl.getShellType();
|
||||||
content = type.prepareScriptContent(content);
|
content = type.prepareScriptContent(content);
|
||||||
|
|
||||||
|
@ -49,29 +85,16 @@ public class ScriptHelper {
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
processControl.executeSimpleCommand(type.getFileTouchCommand(file), "Failed to create script " + file);
|
processControl.executeSimpleCommand(type.getFileTouchCommand(file), "Failed to create script " + file);
|
||||||
processControl.executeSimpleCommand(type.getMakeExecutableCommand(file), "Failed to make script " + file + " executable");
|
processControl.executeSimpleCommand(
|
||||||
|
type.getMakeExecutableCommand(file), "Failed to make script " + file + " executable");
|
||||||
if (!content.contains("\n")) {
|
|
||||||
processControl.executeSimpleCommand(type.getSimpleFileWriteCommand(content, file));
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
try (var c = processControl.command(type.getStreamFileWriteCommand(file)).start()) {
|
|
||||||
c.discardOut();
|
|
||||||
c.discardErr();
|
|
||||||
c.getStdin().write(content.getBytes(processControl.getCharset()));
|
|
||||||
c.closeStdin();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (restart) {
|
|
||||||
processControl.restart();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
processControl.executeSimpleCommand(type.getTextFileWriteCommand(content, file));
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public static String createAskPassScript(SecretValue pass, ShellProcessControl parent, ShellType type, boolean restart) {
|
public static String createAskPassScript(
|
||||||
|
SecretValue pass, ShellProcessControl parent, ShellType type, boolean restart) {
|
||||||
var content = type.getScriptEchoCommand(pass.getSecretValue());
|
var content = type.getScriptEchoCommand(pass.getSecretValue());
|
||||||
var temp = XPipeTempDirectory.get(parent);
|
var temp = XPipeTempDirectory.get(parent);
|
||||||
var file = FileNames.join(temp, "askpass-" + getConnectionHash(content) + "." + type.getScriptFileEnding());
|
var file = FileNames.join(temp, "askpass-" + getConnectionHash(content) + "." + type.getScriptFileEnding());
|
||||||
|
|
Loading…
Reference in a new issue