GTK: Fix instance list auto-updating
ci/woodpecker/push/docs Pipeline was successful Details
ci/woodpecker/push/woodpecker Pipeline was successful Details

This commit is contained in:
Johannes Frohnmeyer 2023-01-28 14:53:16 +01:00
parent 08bb13f994
commit 0cb3df331a
Signed by: Johannes
GPG Key ID: E76429612C2929F4
10 changed files with 109 additions and 50 deletions

View File

@ -35,8 +35,8 @@ public abstract class BaseInstanceCommand extends Command {
}
Instance instance;
Path normalPath = Path.of(args[0]);
if (Files.exists(normalPath.resolve(InstanceList.INSTANCE_CONFIG_NAME))) {
instance = new Instance(normalPath, GC_InstanceMeta.read(normalPath.resolve(InstanceList.INSTANCE_CONFIG_NAME)));
if (Files.exists(normalPath.resolve(Instance.CONFIG_NAME))) {
instance = new Instance(normalPath, GC_InstanceMeta.read(normalPath.resolve(Instance.CONFIG_NAME)));
} else {
Path instancePath = MetaHolder.INSTANCE_DIR.resolve(args[0]).normalize();
if (!instancePath.startsWith(MetaHolder.INSTANCE_DIR)) {

View File

@ -23,7 +23,7 @@ public class ListCommand extends Command {
List<Path> paths = JFiles.list(MetaHolder.INSTANCE_DIR);
if (paths.isEmpty) System.out.println("No instances are currently present");
for (Path path : paths) {
if (!Files.exists(path.resolve(InstanceList.INSTANCE_CONFIG_NAME))) {
if (!Files.exists(path.resolve(Instance.CONFIG_NAME))) {
System.out.println("- Invalid instance: " + path + " (no instance metadata)");
continue;
}

View File

@ -1,14 +1,14 @@
package io.gitlab.jfronny.inceptum.gtk.window;
import io.gitlab.jfronny.inceptum.common.*;
import io.gitlab.jfronny.inceptum.common.InceptumConfig;
import io.gitlab.jfronny.inceptum.common.Utils;
import io.gitlab.jfronny.inceptum.gtk.GtkMenubar;
import io.gitlab.jfronny.inceptum.gtk.control.InstanceGridEntryFactory;
import io.gitlab.jfronny.inceptum.gtk.control.InstanceListEntryFactory;
import io.gitlab.jfronny.inceptum.gtk.menu.MenuBuilder;
import io.gitlab.jfronny.inceptum.gtk.util.I18n;
import io.gitlab.jfronny.inceptum.gtk.util.ListIndexModel;
import io.gitlab.jfronny.inceptum.launcher.system.instance.Instance;
import io.gitlab.jfronny.inceptum.launcher.system.instance.InstanceList;
import io.gitlab.jfronny.inceptum.launcher.system.instance.*;
import io.gitlab.jfronny.inceptum.launcher.system.launch.LaunchType;
import org.gnome.adw.Clamp;
import org.gnome.adw.StatusPage;
@ -18,12 +18,9 @@ import org.gtk.gtk.*;
import java.io.IOException;
import java.net.URI;
import java.nio.file.*;
import java.util.ArrayList;
import java.util.List;
import static java.nio.file.StandardWatchEventKinds.*;
public class MainWindow extends ApplicationWindow {
private final Button listButton;
private final Button gridButton;
@ -128,30 +125,21 @@ public class MainWindow extends ApplicationWindow {
}
}
private void setupDirWatcher() throws IOException { //TODO fix this never running properly (or at least not updating)
WatchService ws = FileSystems.getDefault().newWatchService();
MetaHolder.INSTANCE_DIR.register(ws, ENTRY_MODIFY, ENTRY_CREATE, ENTRY_DELETE);
int source = GLib.idleAdd(() -> {
//TODO watch instance dirs for locks
WatchKey key = ws.poll();
boolean instancesChanged = false;
if (key != null) {
for (WatchEvent<?> event : key.pollEvents()) {
if (event.context() instanceof Path p) {
p = MetaHolder.INSTANCE_DIR.resolve(p);
instancesChanged |= Files.exists(p.resolve(InstanceList.INSTANCE_CONFIG_NAME));
}
}
private void setupDirWatcher() throws IOException {
InstanceListWatcher isw = new InstanceListWatcher();
addTickCallback((widget, clock) -> {
try {
if (isw.poll()) generateWindowBody();
} catch (IOException e) {
Utils.LOGGER.error("Could not run update task", e);
}
if (instancesChanged) generateWindowBody();
return true;
});
return GLib.SOURCE_CONTINUE;
}, null);
onCloseRequest(() -> {
try {
ws.close();
isw.close();
} catch (IOException ignored) {
}
GLib.sourceRemove(source);
return false;
});
}
@ -167,6 +155,9 @@ public class MainWindow extends ApplicationWindow {
if (InstanceList.isEmpty) stack.visibleChild = empty;
else if (InceptumConfig.listView) stack.visibleChild = listContainer;
else stack.visibleChild = gridView;
stack.queueResize();
stack.queueDraw();
} catch (IOException e) {
Utils.LOGGER.error("Could not generate window body", e);
}

View File

@ -29,8 +29,8 @@ public class InstanceView {
ImGui.text("This instance is currently being set up");
continue;
}
if (!Files.exists(instance.path.resolve(InstanceList.INSTANCE_CONFIG_NAME))) {
Utils.LOGGER.error("Invalid instance (doesn't contain " + InstanceList.INSTANCE_CONFIG_NAME + "): " + instance);
if (!Files.exists(instance.path.resolve(Instance.CONFIG_NAME))) {
Utils.LOGGER.error("Invalid instance (doesn't contain " + Instance.CONFIG_NAME + "): " + instance);
continue;
}
ImGui.tableNextColumn();

View File

@ -60,7 +60,7 @@ public abstract class Importer<T> {
Instance.setSetupLock(iDir, true);
InstanceMeta meta = new InstanceMeta();
meta.gameVersion = createVersionString(man.gameVersion, man.fabricVersion);
GC_InstanceMeta.write(meta, iDir.resolve(InstanceList.INSTANCE_CONFIG_NAME));
GC_InstanceMeta.write(meta, iDir.resolve(Instance.CONFIG_NAME));
state.incrementStep("Downloading mods");
downloadMods(manifest, iDir, state);

View File

@ -16,8 +16,9 @@ import java.nio.file.Path;
import java.util.Set;
public record Instance(String id, Path path, InstanceMeta meta, ModsDirScanner mds) implements Comparable<Instance> {
private static final String INCEPTUM_LOCK = "inceptum.lock";
private static final String INCEPTUM_SETUP_LOCK = "inceptum.setup.lock";
public static final String LOCK_NAME = "inceptum.lock";
public static final String SETUP_LOCK_NAME = "inceptum.setup.lock";
public static final String CONFIG_NAME = "instance.json";
public Instance(Path path, InstanceMeta meta) throws IOException {
this(generateId(path.fileName.toString()), path, meta, ModsDirScanner.get(path.resolve("mods"), meta));
@ -95,7 +96,7 @@ public record Instance(String id, Path path, InstanceMeta meta, ModsDirScanner m
}
public boolean isSetupLocked() {
return Files.exists(path.resolve(INCEPTUM_SETUP_LOCK));
return Files.exists(path.resolve(SETUP_LOCK_NAME));
}
public void setSetupLock(boolean state) throws IOException {
@ -103,19 +104,19 @@ public record Instance(String id, Path path, InstanceMeta meta, ModsDirScanner m
}
public static void setSetupLock(Path instanceDir, boolean state) throws IOException {
if (Files.exists(instanceDir.resolve(INCEPTUM_SETUP_LOCK))) {
if (!state) Files.delete(instanceDir.resolve(INCEPTUM_SETUP_LOCK));
if (Files.exists(instanceDir.resolve(SETUP_LOCK_NAME))) {
if (!state) Files.delete(instanceDir.resolve(SETUP_LOCK_NAME));
} else {
if (state) Files.createDirectories(instanceDir.resolve(INCEPTUM_SETUP_LOCK));
if (state) Files.createDirectories(instanceDir.resolve(SETUP_LOCK_NAME));
}
}
public boolean isRunningLocked() {
if (!Files.exists(path.resolve(INCEPTUM_LOCK))) return false;
if (!Files.exists(path.resolve(LOCK_NAME))) return false;
try {
if (ProcessUtils.isProcessAlive(Files.readString(path.resolve(INCEPTUM_LOCK))))
if (ProcessUtils.isProcessAlive(Files.readString(path.resolve(LOCK_NAME))))
return true;
Files.delete(path.resolve(INCEPTUM_LOCK));
Files.delete(path.resolve(LOCK_NAME));
} catch (IOException e) {
Utils.LOGGER.error("Could not read running lock of " + name, e);
}
@ -123,7 +124,7 @@ public record Instance(String id, Path path, InstanceMeta meta, ModsDirScanner m
}
public void setRunningLock(long pid) throws IOException {
Files.writeString(path.resolve(INCEPTUM_LOCK), Long.toString(pid));
Files.writeString(path.resolve(LOCK_NAME), Long.toString(pid));
}
public boolean isLocked() {
@ -132,7 +133,7 @@ public record Instance(String id, Path path, InstanceMeta meta, ModsDirScanner m
public void writeMeta() {
try {
GC_InstanceMeta.write(meta, path.resolve(InstanceList.INSTANCE_CONFIG_NAME));
GC_InstanceMeta.write(meta, path.resolve(CONFIG_NAME));
} catch (IOException e) {
Utils.LOGGER.error("Could not write instance config", e);
}

View File

@ -16,7 +16,6 @@ import java.util.*;
public class InstanceList {
private static final Map<Path, IEntry> metas = new LinkedHashMap<>();
public static final String INSTANCE_CONFIG_NAME = "instance.json";
public static void reset() {
synchronized (metas) {
@ -62,7 +61,7 @@ public class InstanceList {
if (!metas.containsKey(instancePath)) {
metas[instancePath] = new IEntry(
instancePath,
new FileBackedRef<>(instancePath.resolve(INSTANCE_CONFIG_NAME), GC_InstanceMeta::read)
new FileBackedRef<>(instancePath.resolve(Instance.CONFIG_NAME), GC_InstanceMeta::read)
);
}
return metas[instancePath].toPub();
@ -70,7 +69,7 @@ public class InstanceList {
}
private static boolean isInstance(Path path) {
return Files.isDirectory(path) && Files.exists(path.resolve(INSTANCE_CONFIG_NAME));
return Files.isDirectory(path) && Files.exists(path.resolve(Instance.CONFIG_NAME));
}
private record IEntry(Path path, FileBackedRef<InstanceMeta> meta) implements Closeable {

View File

@ -0,0 +1,69 @@
package io.gitlab.jfronny.inceptum.launcher.system.instance;
import io.gitlab.jfronny.commons.io.JFiles;
import io.gitlab.jfronny.inceptum.common.MetaHolder;
import java.io.Closeable;
import java.io.IOException;
import java.nio.file.*;
import java.util.HashMap;
import java.util.Map;
import static java.nio.file.StandardWatchEventKinds.*;
public class InstanceListWatcher implements Closeable {
private final WatchService watcher = FileSystems.getDefault().newWatchService();
private final Map<WatchKey, Path> keys = new HashMap<>();
private void register(Path dir) throws IOException {
keys.put(dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY), dir);
}
public InstanceListWatcher() throws IOException {
register(MetaHolder.INSTANCE_DIR);
JFiles.listTo(MetaHolder.INSTANCE_DIR, this::register);
}
@Override
public void close() throws IOException {
watcher.close();
}
public boolean poll() throws IOException {
boolean changed = false;
WatchKey key;
while ((key = watcher.poll()) != null) {
Path dir = keys.get(key);
for (WatchEvent<?> event : key.pollEvents()) {
var kind = event.kind();
if (kind == OVERFLOW) continue;
@SuppressWarnings("unchecked") WatchEvent<Path> ev = (WatchEvent<Path>) event;
Path name = ev.context();
Path child = dir.resolve(name);
if (MetaHolder.INSTANCE_DIR.equals(dir)) {
if (kind == ENTRY_CREATE) {
changed = true;
register(child);
}
if (kind == ENTRY_DELETE) changed = true;
} else if (Files.exists(dir.resolve(Instance.CONFIG_NAME))) {
String fn = child.fileName.toString();
if (fn.equals(Instance.CONFIG_NAME)
|| fn.equals(Instance.LOCK_NAME)
|| fn.equals(Instance.SETUP_LOCK_NAME)) {
changed = true;
}
}
}
if (!key.reset()) {
keys.remove(key);
if (MetaHolder.INSTANCE_DIR.equals(dir)) {
Files.createDirectories(MetaHolder.INSTANCE_DIR);
register(MetaHolder.INSTANCE_DIR);
}
}
}
return changed;
}
}

View File

@ -2,7 +2,7 @@ package io.gitlab.jfronny.inceptum.launcher.system.setup.steps;
import gsoncompile.extensions.io.gitlab.jfronny.inceptum.launcher.model.inceptum.InstanceMeta.GC_InstanceMeta;
import io.gitlab.jfronny.inceptum.common.MetaHolder;
import io.gitlab.jfronny.inceptum.launcher.system.instance.InstanceList;
import io.gitlab.jfronny.inceptum.launcher.system.instance.Instance;
import io.gitlab.jfronny.inceptum.launcher.system.mds.ModsDirScanner;
import io.gitlab.jfronny.inceptum.launcher.system.setup.SetupStepInfo;
import io.gitlab.jfronny.inceptum.launcher.system.setup.Step;
@ -16,7 +16,7 @@ public class RunMdsStep implements Step {
public void execute(SetupStepInfo info, AtomicBoolean stopThread) throws IOException {
info.setState("Running MDS");
Path instance = MetaHolder.INSTANCE_DIR.resolve(info.name);
ModsDirScanner.get(instance.resolve("mods"), GC_InstanceMeta.read(instance.resolve(InstanceList.INSTANCE_CONFIG_NAME)))
ModsDirScanner.get(instance.resolve("mods"), GC_InstanceMeta.read(instance.resolve(Instance.CONFIG_NAME)))
.runOnce((path, iwModDescription) -> info.setState("Scanned " + path));
}
}

View File

@ -4,7 +4,6 @@ import gsoncompile.extensions.io.gitlab.jfronny.inceptum.launcher.model.inceptum
import io.gitlab.jfronny.inceptum.common.MetaHolder;
import io.gitlab.jfronny.inceptum.launcher.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.launcher.system.instance.Instance;
import io.gitlab.jfronny.inceptum.launcher.system.instance.InstanceList;
import io.gitlab.jfronny.inceptum.launcher.system.setup.SetupStepInfo;
import io.gitlab.jfronny.inceptum.launcher.system.setup.Step;
@ -18,7 +17,7 @@ public class WriteMetadataStep implements Step {
public void execute(SetupStepInfo info, AtomicBoolean stopThread) throws IOException {
info.setState("Writing metadata");
Path instance = MetaHolder.INSTANCE_DIR.resolve(info.name);
Path metaPath = instance.resolve(InstanceList.INSTANCE_CONFIG_NAME);
Path metaPath = instance.resolve(Instance.CONFIG_NAME);
if (!Files.exists(metaPath)) {
InstanceMeta meta = new InstanceMeta();
meta.gameVersion = info.version.id;
@ -41,7 +40,7 @@ public class WriteMetadataStep implements Step {
realms_persistence.json""");
}
if (!Files.exists(instance.resolve(".iceignore"))) {
Files.writeString(instance.resolve(".iceignore"), InstanceList.INSTANCE_CONFIG_NAME);
Files.writeString(instance.resolve(".iceignore"), Instance.CONFIG_NAME);
}
}
}