Allow customizing arguments, ModUpdateCommand

This commit is contained in:
Johannes Frohnmeyer 2022-01-23 18:53:16 +01:00
parent 3814da2013
commit b14a8fbed1
Signed by: Johannes
GPG Key ID: E76429612C2929F4
32 changed files with 709 additions and 445 deletions

View File

@ -60,7 +60,7 @@ if (flavor == 'custom') {
dependencies {
implementation 'com.google.code.gson:gson:2.8.9'
implementation 'org.slf4j:slf4j-api:1.7.32'
implementation 'org.slf4j:slf4j-api:1.7.33'
implementation 'ch.qos.logback:logback-classic:1.2.10'
implementation 'org.eclipse.jgit:org.eclipse.jgit:6.0.0.202111291000-r'
implementation project(":wrapper")

View File

@ -15,6 +15,7 @@ Manually invoking this command WILL cause problems, so a check has been implemen
## The "batch" command
This command will go through every line in the file provided in its arguments and executes the command written there.
It is intended to be used in scripts that only want to run inceptum once, such as the systemd unit in the AUR package.
The batch command has the additional advantage of allowing caches to stay loaded between commands, making execution faster.
For example,
```
git pull icesrv

View File

@ -2,8 +2,8 @@ package io.gitlab.jfronny.inceptum;
import io.gitlab.jfronny.inceptum.frontend.cli.CommandResolution;
import io.gitlab.jfronny.inceptum.frontend.cli.Commands;
import io.gitlab.jfronny.inceptum.frontend.gui.dialog.AlertWindow;
import io.gitlab.jfronny.inceptum.frontend.gui.dialog.TextBoxWindow;
import io.gitlab.jfronny.inceptum.frontend.gui.window.dialog.AlertWindow;
import io.gitlab.jfronny.inceptum.frontend.gui.window.dialog.TextBoxWindow;
import io.gitlab.jfronny.inceptum.gson.*;
import io.gitlab.jfronny.inceptum.util.source.ModSource;
import io.gitlab.jfronny.inceptum.model.microsoft.OauthTokenResponse;

View File

@ -12,7 +12,7 @@ import io.gitlab.jfronny.inceptum.util.MetaHolder;
import io.gitlab.jfronny.inceptum.util.mds.ModsDirScanner;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.util.api.account.AccountManager;
import io.gitlab.jfronny.inceptum.frontend.gui.Window;
import io.gitlab.jfronny.inceptum.frontend.gui.window.Window;
import org.lwjgl.glfw.Callbacks;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWErrorCallback;

View File

@ -6,7 +6,7 @@ import io.gitlab.jfronny.inceptum.frontend.cli.Command;
import io.gitlab.jfronny.inceptum.frontend.cli.CommandArgs;
import io.gitlab.jfronny.inceptum.model.inceptum.UpdateInfo;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.frontend.gui.MainWindow;
import io.gitlab.jfronny.inceptum.frontend.gui.window.MainWindow;
import java.io.IOException;
import java.net.URI;

View File

@ -1,9 +1,12 @@
package io.gitlab.jfronny.inceptum.frontend.cli.commands;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.frontend.cli.BaseInstanceCommand;
import io.gitlab.jfronny.inceptum.frontend.cli.Command;
import io.gitlab.jfronny.inceptum.frontend.cli.CommandArgs;
import io.gitlab.jfronny.inceptum.frontend.gui.window.AddModWindow;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.util.PathUtil;
import io.gitlab.jfronny.inceptum.util.mds.IWModDescription;
import io.gitlab.jfronny.inceptum.util.source.ModSource;
import io.gitlab.jfronny.inceptum.util.ModManager;
@ -16,10 +19,11 @@ import java.nio.file.Path;
import java.util.*;
public class ModCommand extends Command {
//TODO add (search), update
//TODO ModAddCommand (search and install)
public ModCommand() {
super("Allows managing mods in instances", "", List.of("mod"), List.of(
new ModListCommand(),
new ModUpdateCommand(),
new ModRemoveCommand()
));
}
@ -76,7 +80,7 @@ public class ModCommand extends Command {
public static class ModRemoveCommand extends BaseInstanceCommand {
private final boolean ignoreDependencies;
public ModRemoveCommand() {
this("Removes a mod from an instance", List.of("remove", "delete", "rm", "del"), List.of(
this("Removes mods from an instance", List.of("remove", "delete", "rm", "del"), List.of(
new ModRemoveCommand("Skip dependency checks", List.of("ignore-dependencies"), List.of(), true)
), false);
}
@ -99,8 +103,9 @@ public class ModCommand extends Command {
Set<Path> mods = new HashSet<>();
for (String arg : args) {
Path p = instancePath.resolve("mods").resolve(arg);
if (!Files.exists(p)) p = instancePath.resolve("mods").resolve(arg + ".imod");
if (!Files.exists(p)) {
Utils.LOGGER.error("Nonexistant mod file: " + p);
Utils.LOGGER.error("Nonexistant mod file: " + instancePath.resolve("mods").resolve(arg));
return;
}
mods.add(p);
@ -112,7 +117,75 @@ public class ModCommand extends Command {
}
for (Path mod : mods) {
try {
ModManager.delete(new IWModDescription(mod), instancePath.resolve("mods"), mds);
ModManager.delete(mds.get(mod), instancePath.resolve("mods"), mds);
} catch (IOException e) {
Utils.LOGGER.error("Could not delete " + mod, e);
return;
}
}
}
}
public static class ModUpdateCommand extends BaseInstanceCommand {
public ModUpdateCommand() {
super("Update mods in an instance", "<mod file>...", "update", "upgrade", "up");
}
@Override
protected void invoke(CommandArgs args, Path instancePath, InstanceMeta meta) {
if (!meta.isFabric()) {
Utils.LOGGER.error("This is not a fabric instance");
return;
}
if (args.length == 0) {
Utils.LOGGER.error("You must specify mods to remove");
return;
}
Set<Path> mods = new HashSet<>();
for (String arg : args) {
Path p = instancePath.resolve("mods").resolve(arg);
if (!Files.exists(p)) p = instancePath.resolve("mods").resolve(arg + ".imod");
if (!Files.exists(p)) {
Utils.LOGGER.error("Nonexistant mod file: " + instancePath.resolve("mods").resolve(arg));
return;
}
mods.add(p);
}
ModsDirScanner mds = ModsDirScanner.get(instancePath.resolve("mods"), meta);
if (!mds.isComplete()) {
Utils.LOGGER.error("Scanning mods dir to search for dependencies. This might take a while");
mds.runOnce((path, mod) -> System.out.println("Scanned " + path));
}
for (Path mod : mods) {
try {
Utils.LOGGER.info("Updating " + mod);
ModManager.delete(mds.get(mod), instancePath.resolve("mods"), mds);
IWModDescription md = mds.get(mod);
if (md.mod().isEmpty()) {
Utils.LOGGER.error("Could not load mod description");
return;
}
boolean found = false;
for (Map.Entry<ModSource, Optional<ModSource>> source : md.mod().get().sources.entrySet()) {
Optional<ModSource> ms = source.getValue();
if (ms.isPresent()) {
try {
Utils.LOGGER.info("Updating to " + ms.get().getVersion());
Path imodPath = md.imod().isPresent() ? md.imod().get() : instancePath.resolve("mods").resolve(ms.get().getShortName() + PathUtil.EXT_IMOD);
AddModWindow.DownloadMeta dm = AddModWindow.download(ms.get(), imodPath, mds);
Files.delete(md.path());
if (md.imod().isPresent() && Files.exists(md.imod().get()))
Files.delete(md.imod().get());
dm.write();
mds.invalidate(imodPath);
Utils.LOGGER.info("Update completed");
found = true;
} catch (IOException e) {
Inceptum.showError("Update failed", e);
}
}
}
if (!found) Utils.LOGGER.error("Could not find any update");
} catch (IOException e) {
Utils.LOGGER.error("Could not delete " + mod, e);
return;

View File

@ -1,409 +0,0 @@
package io.gitlab.jfronny.inceptum.frontend.gui;
import imgui.ImGui;
import imgui.flag.ImGuiInputTextFlags;
import imgui.type.ImBoolean;
import imgui.type.ImString;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.InceptumGui;
import io.gitlab.jfronny.inceptum.frontend.gui.control.InstanceManageControls;
import io.gitlab.jfronny.inceptum.frontend.gui.dialog.ProcessStateWatcherWindow;
import io.gitlab.jfronny.inceptum.model.inceptum.Config;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.util.*;
import io.gitlab.jfronny.inceptum.util.mds.IWModDescription;
import io.gitlab.jfronny.inceptum.util.mds.ModsDirScanner;
import io.gitlab.jfronny.inceptum.util.source.ModSource;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.Status;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.lwjgl.PointerBuffer;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.util.tinyfd.TinyFileDialogs;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
public class InstanceEditWindow extends Window {
private final Path path;
private final String name;
private final InstanceMeta instance;
private final InstanceManageControls imc;
private final ImBoolean customJava;
private final ImBoolean filterUpdates = new ImBoolean();
private final ImString customJavaPath = new ImString(GuiUtil.INPUT_FIELD_LENGTH);
private final ImString gitUsername = new ImString(GuiUtil.INPUT_FIELD_LENGTH);
private final ImString gitPassword = new ImString(GuiUtil.INPUT_FIELD_LENGTH);
private final ModsDirScanner mds;
private Path selected = null;
private boolean reDownload = false;
private boolean lastTabWasMods = false;
private final Git git;
private CredentialsProvider credentialsProvider;
public InstanceEditWindow(Path path, InstanceMeta instance) {
super(path.getFileName().toString() + " - Edit");
name = path.getFileName().toString();
this.path = path;
this.instance = instance;
mds = ModsDirScanner.get(path.resolve("mods"), instance);
mds.start();
customJava = new ImBoolean(instance.java != null);
imc = new InstanceManageControls(instance);
if (ConfigHolder.CONFIG.git.instanceAuths.containsKey(name)) {
Config.GitConfig.GitAuth config = ConfigHolder.CONFIG.git.instanceAuths.get(name);
gitUsername.set(config.username);
gitPassword.set(config.password);
credentialsProvider = new UsernamePasswordCredentialsProvider(config.username, config.password);
}
else credentialsProvider = CredentialsProvider.getDefault();
Git git = null;
try {
git = Git.open(path.toFile());
} catch (IOException e) {
Utils.LOGGER.error("Could not open instance as git repo", e);
}
this.git = git;
}
@Override
public void draw() {
if (InstanceLock.isSetupLocked(path)) {
ImGui.text("This instance is still being set up.");
return;
}
try {
if (InstanceLock.isRunningLocked(path)) {
ImGui.text("This instance is running. Edits in this state will result in breakage.");
}
} catch (IOException e) {
ImGui.text("Could not read lock state on this instance");
Utils.LOGGER.error("Could not read lock state", e);
}
lastTabWasMods = false;
if (ImGui.beginTabBar("InstanceEdit" + path)) {
if (ImGui.beginTabItem("General")) {
if (ImGui.button("Open Directory")) {
Utils.openFile(path.toFile());
}
imc.nameBox("Rename", name -> {
try {
Path newPath = MetaHolder.INSTANCE_DIR.resolve(name);
Files.move(path, newPath);
InceptumGui.open(new InstanceEditWindow(newPath, instance));
close();
} catch (IOException e) {
e.printStackTrace();
}
});
imc.snapshotsBox();
imc.versionBox(ver -> {
reDownload = true;
instance.version = ver;
save();
});
if (ImGui.button("Delete")) Inceptum.showOkCancel("This instance will be removed forever (a long time)", "Are you sure?", () -> {
try {
Utils.deleteRecursive(path);
} catch (IOException e) {
Inceptum.showError("Could not delete the instance", e);
}
close();
}, () -> {});
if (ImGui.checkbox("Custom Java", customJava)) {
if (customJava.get()) {
instance.java = JvmUtils.getJvm();
customJavaPath.set(instance.java);
} else {
instance.java = null;
}
save();
}
if (customJava.get() && ImGui.inputText("Path", customJavaPath)) {
instance.java = customJavaPath.get();
save();
}
ImGui.endTabItem();
}
if (instance.isFabric() && ImGui.beginTabItem("Mods")) {
lastTabWasMods = true;
if (!Files.exists(path.resolve("mods"))) {
try {
Files.createDirectories(path.resolve("mods"));
} catch (IOException e) {
Utils.LOGGER.error("Could not create mods directory which was missing from this modded instance", e);
}
}
ImGui.beginChild("mods select", 200, 0);
if (ImGui.button("Add")) {
InceptumGui.WINDOWS.add(new AddModWindow(path.resolve("mods"), instance, mds));
}
ImGui.sameLine();
if (Files.exists(path.resolve("mods")) && ImGui.button("Show")) {
Utils.openFile(path.resolve("mods").toFile());
}
ImGui.sameLine();
if (Files.exists(path.resolve("config")) && ImGui.button("Configs")) {
Utils.openFile(path.resolve("config").toFile());
}
try {
Set<IWModDescription> modSet = mds.getMods();
boolean updatesFound = false;
float scannedPercentage = 0;
boolean hasUnScanned = false;
for (IWModDescription mod : modSet) {
if (mds.hasScanned(mod.path())) scannedPercentage++;
else hasUnScanned = true;
if (mod.mod().isEmpty()) continue;
for (Optional<ModSource> value : mod.mod().get().sources.values()) {
if (value.isPresent()) {
updatesFound = true;
break;
}
if (updatesFound)
break;
}
}
scannedPercentage /= modSet.size();
if (hasUnScanned) ImGui.progressBar(scannedPercentage);
if (updatesFound)
ImGui.checkbox("Updatable", filterUpdates);
else
filterUpdates.set(false);
ImGui.separator();
for (IWModDescription mod : modSet) {
updatesFound = false;
if (mod.mod().isPresent()) {
for (Optional<ModSource> value : mod.mod().get().sources.values()) {
updatesFound |= value.isPresent();
}
}
if (filterUpdates.get() && !updatesFound) continue;
boolean wasEnabled = PathUtil.isEnabled(mod.path());
if (ImGui.checkbox("##" + mod.getName(), wasEnabled)) {
Path newSel = PathUtil.toggle(mod.path());
try {
Files.move(mod.path(), newSel);
if (mod.path().equals(selected)) selected = newSel;
mod = new IWModDescription(newSel, mod);
} catch (IOException e) {
Inceptum.showError("Could not change disabled state", e);
}
}
ImGui.sameLine();
if (ImGui.button(mod.getName())) selected = mod.path();
}
} catch (IOException e) {
e.printStackTrace();
}
ImGui.endChild();
ImGui.sameLine();
ImGui.beginGroup();
if (selected == null) {
ImGui.text("Select a mod to view settings");
} else if (mds.hasScanned(selected)) {
IWModDescription md = mds.get(selected);
ImGui.text(md.getName());
ImGui.separator();
for (String s : md.getDescription()) {
ImGui.text(s);
}
ImGui.separator();
if (md.mod().isPresent()) {
Map<ModSource, Optional<ModSource>> sources = md.mod().get().sources;
ImGui.text("Sources:");
if (sources.isEmpty())
ImGui.bulletText("Local Drive");
else {
for (Map.Entry<ModSource, Optional<ModSource>> source : sources.entrySet()) {
ImGui.bulletText(source.getKey().getName());
Optional<ModSource> ms = source.getValue();
if (ms.isPresent()) {
ImGui.sameLine();
if (ImGui.button("Update to " + ms.get().getVersion())) {
try {
Path imodPath = md.imod().isPresent() ? md.imod().get() : path.resolve("mods").resolve(ms.get().getShortName() + PathUtil.EXT_IMOD);
AddModWindow.DownloadMeta dm = AddModWindow.download(ms.get(), imodPath, mds);
Files.delete(md.path());
if (md.imod().isPresent() && Files.exists(md.imod().get()))
Files.delete(md.imod().get());
dm.write();
selected = imodPath;
mds.invalidate(imodPath);
} catch (IOException e) {
Inceptum.showError("Update failed", e);
}
}
}
}
}
}
if (ImGui.button("Delete")) {
if (md.mod().isPresent() && !md.mod().get().dependents.isEmpty())
Inceptum.showError("This mod still has the following dependent mods installed: " + String.join(", ", md.mod().get().dependents), "Dependents present");
else {
try {
delete(md);
} catch (IOException e) {
Inceptum.showError("Couldn't delete the file", e);
}
selected = null;
}
}
}
else {
ImGui.text("This mod has not yet been scanned, please be patient");
}
ImGui.endGroup();
ImGui.endTabItem();
}
if (git != null && ImGui.beginTabItem("Git")) {
Status status = null;
try {
status = git.status().call();
} catch (GitAPIException e) {
Utils.LOGGER.error("Could not check repo status", e);
}
if (status != null && status.isClean()) {
ImGui.text("There are un-committed changes");
for (String change : status.getUncommittedChanges()) {
ImGui.bulletText(change);
}
for (String s : status.getUntracked()) {
ImGui.bulletText(s);
}
if (ImGui.button("Commit")) {
try {
Inceptum.getInput("Commit message", "Commit at t" + System.currentTimeMillis(), message -> {
try {
git.commit()
.setAll(true)
.setMessage(message)
.setSign(ConfigHolder.CONFIG.git.signCommits)
.setAuthor(ConfigHolder.CONFIG.git.commitUsername, ConfigHolder.CONFIG.git.commitMail)
.setCredentialsProvider(credentialsProvider)
.call();
} catch (GitAPIException e) {
Inceptum.showError("Could not commit", e);
}
},() -> {});
} catch (IOException e) {
Inceptum.showError("Could not show dialog", e);
}
}
ImGui.sameLine();
}
if (ImGui.button("Push")) {
try {
git.push()
.setCredentialsProvider(credentialsProvider)
.call();
} catch (GitAPIException e) {
Inceptum.showError("Could not push", e);
}
}
ImGui.sameLine();
if (ImGui.button("Pull")) {
try {
git.pull()
.setRebase(true)
.setCredentialsProvider(credentialsProvider)
.call();
} catch (GitAPIException e) {
Inceptum.showError("Could not pull", e);
}
}
ImGui.sameLine();
if (ImGui.button("Reset")) {
Inceptum.showOkCancel("This will erase all changes since the last commit.\nAre you sure?", "Are you sure?", () -> {
try {
git.checkout()
.setAllPaths(true)
.call();
git.clean()
.setForce(true)
.setCleanDirectories(true)
.call();
} catch (GitAPIException e) {
Inceptum.showError("Could not reset", e);
}
}, () -> {});
}
ImGui.text("Authentication");
boolean update = ImGui.inputText("Username", gitUsername);
update |= ImGui.inputText("Password", gitPassword, ImGuiInputTextFlags.Password);
if (update) {
if (!ConfigHolder.CONFIG.git.instanceAuths.containsKey(name))
ConfigHolder.CONFIG.git.instanceAuths.put(name, new Config.GitConfig.GitAuth());
Config.GitConfig.GitAuth config = ConfigHolder.CONFIG.git.instanceAuths.get(name);
config.username = gitUsername.get();
config.password = gitPassword.get();
ConfigHolder.saveConfig();
credentialsProvider = new UsernamePasswordCredentialsProvider(config.username, config.password);
}
ImGui.text("Please note that Inceptum's git integration intentionally does not cover advanced usage");
ImGui.text("Using software intended to work with git (such as the git CLI or GitHub Desktop) is recommended");
ImGui.endTabItem();
}
if (ImGui.beginTabItem("Export")) {
if (mds.isComplete()) {
if (ImGui.button("CurseForge")) {
try (MemoryStack stack = MemoryStack.stackPush()) {
PointerBuffer aFilterPatterns = stack.mallocPointer(2);
aFilterPatterns.put(stack.UTF8("*.zip"));
aFilterPatterns.flip();
String p = TinyFileDialogs.tinyfd_saveFileDialog("Export Pack", "", aFilterPatterns, "CurseForge packs (*.zip)");
if (p != null) {
ProcessState state = new ProcessState(InstanceExporter.STEP_COUNT, "Initializing...");
InceptumGui.open(new ProcessStateWatcherWindow("Exporting", "Could not export pack", state, cToken -> {
Path exportPath = Path.of(p);
InstanceExporter.exportCurseZip(state, path, instance, mds, git, exportPath);
Inceptum.showInfo(path.getFileName().toString() + " has been successfully exported to " + exportPath, "Successfully exported");
}, null));
}
}
}
}
else {
ImGui.text("The mods directory scan must be completed.\nThe progress for this can be observed in the mods tab");
}
ImGui.endTabItem();
}
ImGui.endTabBar();
}
}
private void delete(IWModDescription md) throws IOException {
ModManager.delete(md, path.resolve("mods"), mds);
}
private void save() {
try {
Utils.writeObject(path.resolve("instance.json"), instance);
} catch (IOException e) {
Utils.LOGGER.error("Could not write instance config", e);
}
}
@Override
public void close() {
super.close();
if (git != null) git.close();
if (reDownload) {
GuiUtil.reload(path);
}
}
@Override
public int getFlags() {
return lastTabWasMods ? 0 : super.getFlags();
}
}

View File

@ -4,7 +4,7 @@ import imgui.ImGui;
import imgui.type.ImBoolean;
import imgui.type.ImInt;
import imgui.type.ImString;
import io.gitlab.jfronny.inceptum.frontend.gui.GuiUtil;
import io.gitlab.jfronny.inceptum.frontend.gui.window.GuiUtil;
import io.gitlab.jfronny.inceptum.model.fabric.FabricVersionLoaderInfo;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.model.inceptum.LoaderInfo;

View File

@ -7,7 +7,7 @@ import io.gitlab.jfronny.inceptum.util.install.Steps;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.util.InstanceLock;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.frontend.gui.InstanceEditWindow;
import io.gitlab.jfronny.inceptum.frontend.gui.window.edit.InstanceEditWindow;
import io.gitlab.jfronny.inceptum.util.InstanceLauncher;
import java.io.IOException;

View File

@ -0,0 +1,24 @@
package io.gitlab.jfronny.inceptum.frontend.gui.control;
import imgui.ImGui;
public abstract class Tab {
private final String name;
public Tab(String name) {
this.name = name;
}
protected abstract void renderInner();
public void render() {
if (canShow() && ImGui.beginTabItem(name)) {
renderInner();
ImGui.endTabItem();
}
}
protected boolean canShow() {
return true;
}
}

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.frontend.gui;
package io.gitlab.jfronny.inceptum.frontend.gui.window;
import imgui.ImGui;
import io.gitlab.jfronny.inceptum.Inceptum;

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.frontend.gui;
package io.gitlab.jfronny.inceptum.frontend.gui.window;
import imgui.ImGui;
import imgui.flag.ImGuiTableFlags;

View File

@ -1,8 +1,8 @@
package io.gitlab.jfronny.inceptum.frontend.gui;
package io.gitlab.jfronny.inceptum.frontend.gui.window;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.InceptumGui;
import io.gitlab.jfronny.inceptum.frontend.gui.dialog.ProcessStateWatcherWindow;
import io.gitlab.jfronny.inceptum.frontend.gui.window.dialog.ProcessStateWatcherWindow;
import io.gitlab.jfronny.inceptum.util.MetaHolder;
import io.gitlab.jfronny.inceptum.util.ProcessState;
import io.gitlab.jfronny.inceptum.util.Utils;

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.frontend.gui;
package io.gitlab.jfronny.inceptum.frontend.gui.window;
import imgui.ImGui;

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.frontend.gui;
package io.gitlab.jfronny.inceptum.frontend.gui.window;
import imgui.ImGui;
import imgui.flag.ImGuiWindowFlags;

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.frontend.gui;
package io.gitlab.jfronny.inceptum.frontend.gui.window;
import com.sun.net.httpserver.HttpServer;
import imgui.ImGui;

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.frontend.gui;
package io.gitlab.jfronny.inceptum.frontend.gui.window;
import imgui.ImGui;
import imgui.type.ImString;

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.frontend.gui;
package io.gitlab.jfronny.inceptum.frontend.gui.window;
import imgui.flag.ImGuiWindowFlags;
import imgui.type.ImBoolean;

View File

@ -1,8 +1,8 @@
package io.gitlab.jfronny.inceptum.frontend.gui.dialog;
package io.gitlab.jfronny.inceptum.frontend.gui.window.dialog;
import imgui.ImGui;
import imgui.flag.ImGuiWindowFlags;
import io.gitlab.jfronny.inceptum.frontend.gui.Window;
import io.gitlab.jfronny.inceptum.frontend.gui.window.Window;
public class AlertWindow extends Window {
private final String message;

View File

@ -1,8 +1,8 @@
package io.gitlab.jfronny.inceptum.frontend.gui.dialog;
package io.gitlab.jfronny.inceptum.frontend.gui.window.dialog;
import imgui.ImGui;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.frontend.gui.Window;
import io.gitlab.jfronny.inceptum.frontend.gui.window.Window;
import io.gitlab.jfronny.inceptum.util.ProcessState;
import io.gitlab.jfronny.inceptum.util.lambda.ThrowingConsumer;
import org.eclipse.jgit.annotations.Nullable;

View File

@ -1,9 +1,9 @@
package io.gitlab.jfronny.inceptum.frontend.gui.dialog;
package io.gitlab.jfronny.inceptum.frontend.gui.window.dialog;
import imgui.ImGui;
import imgui.type.ImString;
import io.gitlab.jfronny.inceptum.frontend.gui.GuiUtil;
import io.gitlab.jfronny.inceptum.frontend.gui.Window;
import io.gitlab.jfronny.inceptum.frontend.gui.window.GuiUtil;
import io.gitlab.jfronny.inceptum.frontend.gui.window.Window;
import java.util.function.Consumer;

View File

@ -0,0 +1,45 @@
package io.gitlab.jfronny.inceptum.frontend.gui.window.edit;
import imgui.ImGui;
import imgui.type.ImString;
import io.gitlab.jfronny.inceptum.frontend.gui.control.Tab;
import io.gitlab.jfronny.inceptum.frontend.gui.window.GuiUtil;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import java.util.LinkedList;
import java.util.List;
public class ArgumentsTab extends Tab {
private final InstanceEditWindow window;
private final ImString jvm = new ImString(GuiUtil.INPUT_FIELD_LENGTH);
private final ImString client = new ImString(GuiUtil.INPUT_FIELD_LENGTH);
private final ImString server = new ImString(GuiUtil.INPUT_FIELD_LENGTH);
public ArgumentsTab(InstanceEditWindow window) {
super("Arguments");
this.window = window;
if (window.instance.arguments == null) window.instance.arguments = new InstanceMeta.Arguments();
if (window.instance.arguments.jvm == null) window.instance.arguments.jvm = new LinkedList<>();
jvm.set(String.join("\n", window.instance.arguments.jvm));
if (window.instance.arguments.client == null) window.instance.arguments.client = new LinkedList<>();
client.set(String.join("\n", window.instance.arguments.client));
if (window.instance.arguments.server == null) window.instance.arguments.server = new LinkedList<>();
server.set(String.join("\n", window.instance.arguments.server));
}
@Override
protected void renderInner() {
if (ImGui.inputTextMultiline("JVM", jvm)) {
window.instance.arguments.jvm = List.of(jvm.get().split("[\r\n]+"));
window.save();
}
if (ImGui.inputTextMultiline("Client", client)) {
window.instance.arguments.client = List.of(client.get().split("[\r\n]+"));
window.save();
}
if (ImGui.inputTextMultiline("Server", server)) {
window.instance.arguments.server = List.of(server.get().split("[\r\n]+"));
window.save();
}
}
}

View File

@ -0,0 +1,48 @@
package io.gitlab.jfronny.inceptum.frontend.gui.window.edit;
import imgui.ImGui;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.InceptumGui;
import io.gitlab.jfronny.inceptum.frontend.gui.control.Tab;
import io.gitlab.jfronny.inceptum.frontend.gui.window.dialog.ProcessStateWatcherWindow;
import io.gitlab.jfronny.inceptum.util.InstanceExporter;
import io.gitlab.jfronny.inceptum.util.ProcessState;
import org.lwjgl.PointerBuffer;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.util.tinyfd.TinyFileDialogs;
import java.nio.file.Path;
public class ExportTab extends Tab {
private final InstanceEditWindow window;
public ExportTab(InstanceEditWindow window) {
super("Export");
this.window = window;
}
@Override
protected void renderInner() {
if (window.mds.isComplete()) {
if (ImGui.button("CurseForge")) {
try (MemoryStack stack = MemoryStack.stackPush()) {
PointerBuffer aFilterPatterns = stack.mallocPointer(2);
aFilterPatterns.put(stack.UTF8("*.zip"));
aFilterPatterns.flip();
String p = TinyFileDialogs.tinyfd_saveFileDialog("Export Pack", "", aFilterPatterns, "CurseForge packs (*.zip)");
if (p != null) {
ProcessState state = new ProcessState(InstanceExporter.STEP_COUNT, "Initializing...");
InceptumGui.open(new ProcessStateWatcherWindow("Exporting", "Could not export pack", state, cToken -> {
Path exportPath = Path.of(p);
InstanceExporter.exportCurseZip(state, window.path, window.instance, window.mds, window.git, exportPath);
Inceptum.showInfo(window.path.getFileName().toString() + " has been successfully exported to " + exportPath, "Successfully exported");
}, null));
}
}
}
}
else {
ImGui.text("The mods directory scan must be completed.\nThe progress for this can be observed in the mods tab");
}
}
}

View File

@ -0,0 +1,75 @@
package io.gitlab.jfronny.inceptum.frontend.gui.window.edit;
import imgui.ImGui;
import imgui.type.ImBoolean;
import imgui.type.ImString;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.InceptumGui;
import io.gitlab.jfronny.inceptum.frontend.gui.control.InstanceManageControls;
import io.gitlab.jfronny.inceptum.frontend.gui.control.Tab;
import io.gitlab.jfronny.inceptum.frontend.gui.window.GuiUtil;
import io.gitlab.jfronny.inceptum.util.JvmUtils;
import io.gitlab.jfronny.inceptum.util.MetaHolder;
import io.gitlab.jfronny.inceptum.util.Utils;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class GeneralTab extends Tab {
private final InstanceManageControls imc;
private final InstanceEditWindow window;
private final ImBoolean customJava;
private final ImString customJavaPath = new ImString(GuiUtil.INPUT_FIELD_LENGTH);
public GeneralTab(InstanceEditWindow window) {
super("General");
this.window = window;
imc = new InstanceManageControls(window.instance);
customJava = new ImBoolean(window.instance.java != null);
}
@Override
protected void renderInner() {
if (ImGui.button("Open Directory")) {
Utils.openFile(window.path.toFile());
}
imc.nameBox("Rename", name -> {
try {
Path newPath = MetaHolder.INSTANCE_DIR.resolve(name);
Files.move(window.path, newPath);
InceptumGui.open(new InstanceEditWindow(newPath, window.instance));
window.close();
} catch (IOException e) {
e.printStackTrace();
}
});
imc.snapshotsBox();
imc.versionBox(ver -> {
window.reDownload = true;
window.instance.version = ver;
window.save();
});
if (ImGui.button("Delete")) Inceptum.showOkCancel("This instance will be removed forever (a long time)", "Are you sure?", () -> {
try {
Utils.deleteRecursive(window.path);
} catch (IOException e) {
Inceptum.showError("Could not delete the instance", e);
}
window.close();
}, () -> {});
if (ImGui.checkbox("Custom Java", customJava)) {
if (customJava.get()) {
window.instance.java = JvmUtils.getJvm();
customJavaPath.set(window.instance.java);
} else {
window.instance.java = null;
}
window.save();
}
if (customJava.get() && ImGui.inputText("Path", customJavaPath)) {
window.instance.java = customJavaPath.get();
window.save();
}
}
}

View File

@ -0,0 +1,131 @@
package io.gitlab.jfronny.inceptum.frontend.gui.window.edit;
import imgui.ImGui;
import imgui.flag.ImGuiInputTextFlags;
import imgui.type.ImString;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.frontend.gui.control.Tab;
import io.gitlab.jfronny.inceptum.frontend.gui.window.GuiUtil;
import io.gitlab.jfronny.inceptum.model.inceptum.Config;
import io.gitlab.jfronny.inceptum.util.ConfigHolder;
import io.gitlab.jfronny.inceptum.util.Utils;
import org.eclipse.jgit.api.Status;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import java.io.IOException;
public class GitTab extends Tab {
private final InstanceEditWindow window;
private final ImString gitUsername = new ImString(GuiUtil.INPUT_FIELD_LENGTH);
private final ImString gitPassword = new ImString(GuiUtil.INPUT_FIELD_LENGTH);
protected CredentialsProvider credentialsProvider;
public GitTab(InstanceEditWindow window) {
super("Git");
this.window = window;
if (ConfigHolder.CONFIG.git.instanceAuths.containsKey(window.name)) {
Config.GitConfig.GitAuth config = ConfigHolder.CONFIG.git.instanceAuths.get(window.name);
gitUsername.set(config.username);
gitPassword.set(config.password);
credentialsProvider = new UsernamePasswordCredentialsProvider(config.username, config.password);
}
else credentialsProvider = CredentialsProvider.getDefault();
}
@Override
protected void renderInner() {
Status status = null;
try {
status = window.git.status().call();
} catch (GitAPIException e) {
Utils.LOGGER.error("Could not check repo status", e);
}
if (status != null && status.isClean()) {
ImGui.text("There are un-committed changes");
for (String change : status.getUncommittedChanges()) {
ImGui.bulletText(change);
}
for (String s : status.getUntracked()) {
ImGui.bulletText(s);
}
if (ImGui.button("Commit")) {
try {
Inceptum.getInput("Commit message", "Commit at t" + System.currentTimeMillis(), message -> {
try {
window.git.commit()
.setAll(true)
.setMessage(message)
.setSign(ConfigHolder.CONFIG.git.signCommits)
.setAuthor(ConfigHolder.CONFIG.git.commitUsername, ConfigHolder.CONFIG.git.commitMail)
.setCredentialsProvider(credentialsProvider)
.call();
} catch (GitAPIException e) {
Inceptum.showError("Could not commit", e);
}
},() -> {});
} catch (IOException e) {
Inceptum.showError("Could not show dialog", e);
}
}
ImGui.sameLine();
}
if (ImGui.button("Push")) {
try {
window.git.push()
.setCredentialsProvider(credentialsProvider)
.call();
} catch (GitAPIException e) {
Inceptum.showError("Could not push", e);
}
}
ImGui.sameLine();
if (ImGui.button("Pull")) {
try {
window.git.pull()
.setRebase(true)
.setCredentialsProvider(credentialsProvider)
.call();
} catch (GitAPIException e) {
Inceptum.showError("Could not pull", e);
}
}
ImGui.sameLine();
if (ImGui.button("Reset")) {
Inceptum.showOkCancel("This will erase all changes since the last commit.\nAre you sure?", "Are you sure?", () -> {
try {
window.git.checkout()
.setAllPaths(true)
.call();
window.git.clean()
.setForce(true)
.setCleanDirectories(true)
.call();
} catch (GitAPIException e) {
Inceptum.showError("Could not reset", e);
}
}, () -> {});
}
ImGui.text("Authentication");
boolean update = ImGui.inputText("Username", gitUsername);
update |= ImGui.inputText("Password", gitPassword, ImGuiInputTextFlags.Password);
if (update) {
if (!ConfigHolder.CONFIG.git.instanceAuths.containsKey(window.name))
ConfigHolder.CONFIG.git.instanceAuths.put(window.name, new Config.GitConfig.GitAuth());
Config.GitConfig.GitAuth config = ConfigHolder.CONFIG.git.instanceAuths.get(window.name);
config.username = gitUsername.get();
config.password = gitPassword.get();
ConfigHolder.saveConfig();
credentialsProvider = new UsernamePasswordCredentialsProvider(config.username, config.password);
}
ImGui.text("Please note that Inceptum's git integration intentionally does not cover advanced usage");
ImGui.text("Using software intended to work with git (such as the git CLI or GitHub Desktop) is recommended");
}
@Override
protected boolean canShow() {
return window.git != null;
}
}

View File

@ -0,0 +1,94 @@
package io.gitlab.jfronny.inceptum.frontend.gui.window.edit;
import imgui.ImGui;
import io.gitlab.jfronny.inceptum.frontend.gui.control.Tab;
import io.gitlab.jfronny.inceptum.frontend.gui.window.GuiUtil;
import io.gitlab.jfronny.inceptum.frontend.gui.window.Window;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.util.InstanceLock;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.util.mds.ModsDirScanner;
import org.eclipse.jgit.api.Git;
import java.io.IOException;
import java.nio.file.Path;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
public class InstanceEditWindow extends Window {
protected final Path path;
protected final String name;
protected final InstanceMeta instance;
protected final ModsDirScanner mds;
protected final Git git;
private final List<Tab> tabs;
protected boolean reDownload = false;
protected boolean lastTabWasMods = false;
public InstanceEditWindow(Path path, InstanceMeta instance) {
super(path.getFileName().toString() + " - Edit");
name = path.getFileName().toString();
this.path = path;
this.instance = instance;
mds = ModsDirScanner.get(path.resolve("mods"), instance);
mds.start();
Git git = null;
try {
git = Git.open(path.toFile());
} catch (IOException e) {
Utils.LOGGER.error("Could not open instance as git repo", e);
}
this.git = git;
this.tabs = List.of(
new GeneralTab(this),
new ArgumentsTab(this),
new ModsTab(this),
new GitTab(this),
new ExportTab(this)
);
}
@Override
public void draw() {
if (InstanceLock.isSetupLocked(path)) {
ImGui.text("This instance is still being set up.");
return;
}
try {
if (InstanceLock.isRunningLocked(path)) {
ImGui.text("This instance is running. Edits in this state will result in breakage.");
}
} catch (IOException e) {
ImGui.text("Could not read lock state on this instance");
Utils.LOGGER.error("Could not read lock state", e);
}
lastTabWasMods = false;
if (ImGui.beginTabBar("InstanceEdit" + path)) {
for (Tab tab : tabs) tab.render();
ImGui.endTabBar();
}
}
protected void save() {
try {
Utils.writeObject(path.resolve("instance.json"), instance);
} catch (IOException e) {
Utils.LOGGER.error("Could not write instance config", e);
}
}
@Override
public void close() {
super.close();
if (git != null) git.close();
if (reDownload) {
GuiUtil.reload(path);
}
}
@Override
public int getFlags() {
return lastTabWasMods ? 0 : super.getFlags();
}
}

View File

@ -0,0 +1,173 @@
package io.gitlab.jfronny.inceptum.frontend.gui.window.edit;
import imgui.ImGui;
import imgui.type.ImBoolean;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.InceptumGui;
import io.gitlab.jfronny.inceptum.frontend.gui.control.Tab;
import io.gitlab.jfronny.inceptum.frontend.gui.window.AddModWindow;
import io.gitlab.jfronny.inceptum.util.ModManager;
import io.gitlab.jfronny.inceptum.util.PathUtil;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.util.mds.IWModDescription;
import io.gitlab.jfronny.inceptum.util.source.ModSource;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
public class ModsTab extends Tab {
private final InstanceEditWindow window;
private final ImBoolean filterUpdates = new ImBoolean();
private Path selected = null;
public ModsTab(InstanceEditWindow window) {
super("Mods");
this.window = window;
}
@Override
protected void renderInner() {
window.lastTabWasMods = true;
if (!Files.exists(window.path.resolve("mods"))) {
try {
Files.createDirectories(window.path.resolve("mods"));
} catch (IOException e) {
Utils.LOGGER.error("Could not create mods directory which was missing from this modded instance", e);
}
}
ImGui.beginChild("mods select", 200, 0);
if (ImGui.button("Add")) {
InceptumGui.WINDOWS.add(new AddModWindow(window.path.resolve("mods"), window.instance, window.mds));
}
ImGui.sameLine();
if (Files.exists(window.path.resolve("mods")) && ImGui.button("Show")) {
Utils.openFile(window.path.resolve("mods").toFile());
}
ImGui.sameLine();
if (Files.exists(window.path.resolve("config")) && ImGui.button("Configs")) {
Utils.openFile(window.path.resolve("config").toFile());
}
try {
Set<IWModDescription> modSet = window.mds.getMods();
boolean updatesFound = false;
float scannedPercentage = 0;
boolean hasUnScanned = false;
for (IWModDescription mod : modSet) {
if (window.mds.hasScanned(mod.path())) scannedPercentage++;
else hasUnScanned = true;
if (mod.mod().isEmpty()) continue;
for (Optional<ModSource> value : mod.mod().get().sources.values()) {
if (value.isPresent()) {
updatesFound = true;
break;
}
if (updatesFound)
break;
}
}
scannedPercentage /= modSet.size();
if (hasUnScanned) ImGui.progressBar(scannedPercentage);
if (updatesFound)
ImGui.checkbox("Updatable", filterUpdates);
else
filterUpdates.set(false);
ImGui.separator();
for (IWModDescription mod : modSet) {
updatesFound = false;
if (mod.mod().isPresent()) {
for (Optional<ModSource> value : mod.mod().get().sources.values()) {
updatesFound |= value.isPresent();
}
}
if (filterUpdates.get() && !updatesFound) continue;
boolean wasEnabled = PathUtil.isEnabled(mod.path());
if (ImGui.checkbox("##" + mod.getName(), wasEnabled)) {
Path newSel = PathUtil.toggle(mod.path());
try {
Files.move(mod.path(), newSel);
if (mod.path().equals(selected)) selected = newSel;
mod = new IWModDescription(newSel, mod);
} catch (IOException e) {
Inceptum.showError("Could not change disabled state", e);
}
}
ImGui.sameLine();
if (ImGui.button(mod.getName())) selected = mod.path();
}
} catch (IOException e) {
e.printStackTrace();
}
ImGui.endChild();
ImGui.sameLine();
ImGui.beginGroup();
if (selected == null) {
ImGui.text("Select a mod to view settings");
} else if (window.mds.hasScanned(selected)) {
IWModDescription md = window.mds.get(selected);
ImGui.text(md.getName());
ImGui.separator();
for (String s : md.getDescription()) {
ImGui.text(s);
}
ImGui.separator();
if (md.mod().isPresent()) {
Map<ModSource, Optional<ModSource>> sources = md.mod().get().sources;
ImGui.text("Sources:");
if (sources.isEmpty())
ImGui.bulletText("Local Drive");
else {
for (Map.Entry<ModSource, Optional<ModSource>> source : sources.entrySet()) {
ImGui.bulletText(source.getKey().getName());
Optional<ModSource> ms = source.getValue();
if (ms.isPresent()) {
ImGui.sameLine();
if (ImGui.button("Update to " + ms.get().getVersion())) {
try {
Path imodPath = md.imod().isPresent() ? md.imod().get() : window.path.resolve("mods").resolve(ms.get().getShortName() + PathUtil.EXT_IMOD);
AddModWindow.DownloadMeta dm = AddModWindow.download(ms.get(), imodPath, window.mds);
Files.delete(md.path());
if (md.imod().isPresent() && Files.exists(md.imod().get()))
Files.delete(md.imod().get());
dm.write();
selected = imodPath;
window.mds.invalidate(imodPath);
} catch (IOException e) {
Inceptum.showError("Update failed", e);
}
}
}
}
}
}
if (ImGui.button("Delete")) {
if (md.mod().isPresent() && !md.mod().get().dependents.isEmpty())
Inceptum.showError("This mod still has the following dependent mods installed: " + String.join(", ", md.mod().get().dependents), "Dependents present");
else {
try {
delete(md);
} catch (IOException e) {
Inceptum.showError("Couldn't delete the file", e);
}
selected = null;
}
}
}
else {
ImGui.text("This mod has not yet been scanned, please be patient");
}
ImGui.endGroup();
}
private void delete(IWModDescription md) throws IOException {
ModManager.delete(md, window.path.resolve("mods"), window.mds);
}
@Override
protected boolean canShow() {
return window.instance.isFabric();
}
}

View File

@ -11,7 +11,7 @@ public class InstanceMeta {
public String java;
public Long minMem;
public Long maxMem;
public Arguments arguments; //TODO allow configuring in UI
public Arguments arguments;
public boolean isFabric() {
return version.startsWith(floaderPrefix);

View File

@ -7,7 +7,7 @@ import io.gitlab.jfronny.inceptum.model.microsoft.OauthTokenResponse;
import io.gitlab.jfronny.inceptum.model.microsoft.Profile;
import io.gitlab.jfronny.inceptum.model.microsoft.XboxLiveAuthResponse;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.frontend.gui.MicrosoftLoginWindow;
import io.gitlab.jfronny.inceptum.frontend.gui.window.MicrosoftLoginWindow;
import java.io.IOException;
import java.net.URISyntaxException;

View File

@ -21,10 +21,12 @@ 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 metaDir = instance.resolve("instance.json");
InstanceMeta meta = new InstanceMeta();
meta.version = info.version().id;
Utils.writeObject(metaDir, meta);
Path metaPath = instance.resolve("instance.json");
if (!Files.exists(metaPath)) {
InstanceMeta meta = new InstanceMeta();
meta.version = info.version().id;
Utils.writeObject(metaPath, meta);
}
InstanceLock.setSetupLock(instance, false);
if (!Files.exists(instance.resolve(".gitignore"))) {
Files.writeString(instance.resolve(".gitignore"), """

View File

@ -145,7 +145,7 @@ public class HttpUtils {
throw new IOException("Could not follow redirect", e);
}
}
throw new IOException("Unexpected return method: " + res.statusCode() + " (URL=" + url + ")\n" + res.body());
throw new IOException("Unexpected return method: " + res.statusCode() + " (URL=" + url + ")");
}
public void send() throws IOException {

View File

@ -19,6 +19,7 @@ import java.nio.file.FileSystem;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
@ -249,8 +250,14 @@ public class Utils {
}
}
private static final Map<Path, FileSystem> zipFsCache = new HashMap<>();
public static FileSystem openZipFile(Path zip, boolean create) throws IOException, URISyntaxException {
URI fileUri = zip.toUri();
return FileSystems.newFileSystem(new URI("jar:" + fileUri.getScheme(), fileUri.getPath(), null), create ? Map.of("create", "true") : Map.of(), WrapperStrap.SYSTEM_LOADER);
synchronized (zipFsCache) {
if (!zipFsCache.containsKey(zip) || !zipFsCache.get(zip).isOpen()) {
URI fileUri = zip.toUri();
zipFsCache.put(zip, FileSystems.newFileSystem(new URI("jar:" + fileUri.getScheme(), fileUri.getPath(), null), create ? Map.of("create", "true") : Map.of(), WrapperStrap.SYSTEM_LOADER));
}
return zipFsCache.get(zip);
}
}
}