Properly implement storage directory switching

This commit is contained in:
crschnick 2023-07-09 11:39:23 +00:00
parent 4c08385098
commit b2d685f523
7 changed files with 40 additions and 75 deletions

View file

@ -205,24 +205,19 @@ public class AppPrefs {
private final BooleanProperty confirmDeletions = typed(new SimpleBooleanProperty(true), Boolean.class);
// External startup behaviour
// ==========================
private final ObjectProperty<Path> internalStorageDirectory =
// Storage
// =======
private final ObjectProperty<Path> storageDirectory =
typed(new SimpleObjectProperty<>(DEFAULT_STORAGE_DIR), Path.class);
private final ObjectProperty<Path> effectiveStorageDirectory = STORAGE_DIR_FIXED
? new SimpleObjectProperty<>(AppProperties.get().getDataDir().resolve("storage"))
: internalStorageDirectory;
private final StringField storageDirectoryControl = PrefFields.ofPath(effectiveStorageDirectory)
.editable(!STORAGE_DIR_FIXED)
private final StringField storageDirectoryControl = PrefFields.ofPath(storageDirectory)
.validate(
CustomValidators.absolutePath(),
CustomValidators.directory(),
CustomValidators.emptyStorageDirectory());
private final ObjectProperty<String> internalLogLevel =
typed(new SimpleObjectProperty<>(DEFAULT_LOG_LEVEL), String.class);
CustomValidators.directory());
// Log level
// =========
private final ObjectProperty<String> internalLogLevel =
typed(new SimpleObjectProperty<>(DEFAULT_LOG_LEVEL), String.class);
private final ObjectProperty<String> effectiveLogLevel = LOG_LEVEL_FIXED
? new SimpleObjectProperty<>(System.getProperty(LOG_LEVEL_PROP).toLowerCase())
: internalLogLevel;
@ -230,6 +225,7 @@ public class AppPrefs {
logLevelList, effectiveLogLevel)
.editable(!LOG_LEVEL_FIXED)
.render(() -> new SimpleComboBoxControl<>());
// Developer mode
// ==============
private final BooleanProperty internalDeveloperMode = typed(new SimpleBooleanProperty(false), Boolean.class);
@ -335,7 +331,7 @@ public class AppPrefs {
}
public ObservableValue<Path> storageDirectory() {
return effectiveStorageDirectory;
return storageDirectory;
}
public ReadOnlyProperty<String> logLevel() {
@ -535,9 +531,9 @@ public class AppPrefs {
automaticallyCheckForUpdatesField,
automaticallyCheckForUpdates),
Setting.of("updateToPrereleases", checkForPrereleasesField, checkForPrereleases)),
Group.of(
group(
"advanced",
Setting.of("storageDirectory", storageDirectoryControl, internalStorageDirectory),
STORAGE_DIR_FIXED ? null : Setting.of("storageDirectory", storageDirectoryControl, storageDirectory),
Setting.of("logLevel", logLevelField, internalLogLevel),
Setting.of("developerMode", developerModeField, internalDeveloperMode))),
Category.of(
@ -602,6 +598,10 @@ public class AppPrefs {
return AppPreferencesFx.of(cats);
}
private Group group(String name, Setting<?,?>... settings) {
return Group.of(name, Arrays.stream(settings).filter(setting -> setting != null).toArray(Setting[]::new));
}
private class PrefsHandlerImpl implements PrefsHandler {
private final List<Category> categories;

View file

@ -3,7 +3,6 @@ package io.xpipe.app.prefs;
import com.dlsc.formsfx.model.validators.CustomValidator;
import com.dlsc.formsfx.model.validators.Validator;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
@ -30,25 +29,4 @@ public class CustomValidators {
},
"notADirectory");
}
public static Validator<String> emptyStorageDirectory() {
return CustomValidator.forPredicate(
(String s) -> {
var p = Path.of(s);
if (AppPrefs.get() == null) {
return true;
}
if (p.equals(AppPrefs.get().storageDirectory().getValue())) {
return true;
}
try {
return Files.list(p).findAny().isEmpty();
} catch (IOException ignored) {
return false;
}
},
"notAnEmptyDirectory");
}
}

View file

@ -3,34 +3,39 @@ package io.xpipe.app.prefs;
import com.dlsc.formsfx.model.structure.StringField;
import com.dlsc.preferencesfx.formsfx.view.controls.SimpleChooserControl;
import io.xpipe.app.core.AppI18n;
import io.xpipe.app.fxcomps.util.BindingsHelper;
import io.xpipe.app.fxcomps.util.PlatformThread;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.util.StringConverter;
import java.nio.file.Path;
import java.util.Objects;
public class PrefFields {
public static StringField ofPath(ObjectProperty<Path> fileProperty) {
StringProperty stringProperty = new SimpleStringProperty();
stringProperty.bindBidirectional(fileProperty, new StringConverter<>() {
@Override
public String toString(Path file) {
if (Objects.isNull(file)) {
return "";
}
return file.toString();
}
StringProperty stringProperty = new SimpleStringProperty(fileProperty.getValue().toString());
@Override
public Path fromString(String value) {
return Path.of(value);
}
// Prevent garbage collection of this due to how preferencesfx handles properties via bindings
BindingsHelper.linkPersistently(fileProperty, stringProperty);
stringProperty.addListener((observable, oldValue, newValue) -> {
fileProperty.setValue(newValue != null ? Path.of(newValue) : null);
});
fileProperty.addListener((observable, oldValue, newValue) -> {
PlatformThread.runLaterIfNeeded(() -> {
stringProperty.setValue(newValue != null ? newValue.toString() : "");
});
});
return StringField.ofStringType(stringProperty)
.render(() -> new SimpleChooserControl(
AppI18n.get("browse"), fileProperty.getValue().toFile(), true));
.render(() -> {
var c = new SimpleChooserControl(
AppI18n.get("browse"), fileProperty.getValue().toFile(), true);
c.setMinWidth(600);
c.setPrefWidth(600);
return c;
});
}
}

View file

@ -145,10 +145,6 @@ public abstract class DataStorage {
}
}
protected Path getSourcesDir() {
return dir.resolve("sources");
}
protected Path getStoresDir() {
return dir.resolve("stores");
}

View file

@ -17,14 +17,10 @@ public class ImpersistentStorage extends DataStorage {
@Override
public void save() {
var sourcesDir = getSourcesDir();
var storesDir = getStoresDir();
TrackEvent.info("Storage persistence is disabled. Deleting storage contents ...");
try {
if (Files.exists(sourcesDir)) {
FileUtils.cleanDirectory(sourcesDir.toFile());
}
if (Files.exists(storesDir)) {
FileUtils.cleanDirectory(storesDir.toFile());
}

View file

@ -24,8 +24,6 @@ public class StandardStorage extends DataStorage {
}
private void deleteLeftovers() {
var entriesDir = getSourcesDir().resolve("entries");
var collectionsDir = getSourcesDir().resolve("collections");
var storesDir = getStoresDir();
// Delete leftover directories in entries dir
@ -63,14 +61,10 @@ public class StandardStorage extends DataStorage {
public synchronized void load() {
var newSession = isNewSession();
var entriesDir = getSourcesDir().resolve("entries");
var collectionsDir = getSourcesDir().resolve("collections");
var storesDir = getStoresDir();
var streamsDir = getStreamsDir();
try {
FileUtils.forceMkdir(entriesDir.toFile());
FileUtils.forceMkdir(collectionsDir.toFile());
FileUtils.forceMkdir(storesDir.toFile());
FileUtils.forceMkdir(streamsDir.toFile());
} catch (Exception e) {
@ -120,14 +114,10 @@ public class StandardStorage extends DataStorage {
}
public synchronized void save() {
var entriesDir = getSourcesDir().resolve("entries");
var collectionsDir = getSourcesDir().resolve("collections");
try {
FileUtils.forceMkdir(entriesDir.toFile());
FileUtils.forceMkdir(collectionsDir.toFile());
FileUtils.forceMkdir(getStoresDir().toFile());
} catch (Exception e) {
ErrorEvent.fromThrowable(e).terminal(true).build().handle();
ErrorEvent.fromThrowable(e).description("Unable to create storage directory " + getStoresDir()).terminal(true).build().handle();
}
// Save stores

View file

@ -56,7 +56,7 @@ automaticallyUpdateDescription=When enabled, new release information is automati
sendAnonymousErrorReports=Send anonymous error reports
sendUsageStatistics=Send anonymous usage statistics
storageDirectory=Storage directory
storageDirectoryDescription=The location where XPipe should store all connection and data source information.
storageDirectoryDescription=The location where XPipe should store all connection information. This setting will only be applied at the next restart. When changing this, the data in the old directory is not copied to the new one.
logLevel=Log level
appBehaviour=Application behaviour
logLevelDescription=The log level that should be used when writing log files.