Skip to content

Commit

Permalink
[#1] Continuing work on multimod functionality.
Browse files Browse the repository at this point in the history
  • Loading branch information
DaloLorn committed Dec 10, 2021
1 parent f8e0d2f commit eaf005a
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 35 deletions.
78 changes: 56 additions & 22 deletions src/main/java/com/dalolorn/sr2modmanager/adapter/ModInstaller.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public class ModInstaller {
private static Git repo;

private static Ref currentBranch;
private static Metadata currentMetadata;
@NotNull private static final Map<String, Ref> branches = new HashMap<>();

public interface TextHandler {
Expand All @@ -58,16 +59,23 @@ public static String setActiveBranch(@NotNull String branchName) {

ObjectLoader descriptionLoader;
try {
var repository = repo.getRepository();
var treeId = repository.resolve(currentBranch.getName() + "^{tree}");
var walker = Utils.generateBranchDescWalker(repository, treeId);
var descriptionId = walker.getObjectId(0);
descriptionLoader = repository.open(descriptionId);
descriptionLoader = Utils.getLoader(repo, currentBranch, Utils::generateBranchDescWalker);
} catch (Exception e) {
e.printStackTrace();
return NO_BRANCH_DESC;
}

ObjectLoader metaLoader;
try {
metaLoader = Utils.getLoader(repo, currentBranch, Utils::generateMetadataWalker);
var json = Utils.readGitFile(metaLoader);
if(json != null) {
currentMetadata = new Gson().fromJson(json, Metadata.class);
}
} catch (Exception e) {
e.printStackTrace();
}

var json = Utils.readGitFile(descriptionLoader);
if(json != null) {
try {
Expand Down Expand Up @@ -238,15 +246,17 @@ private static void installModImpl(
@NotNull TextHandler warningHandler,
@NotNull TextHandler progressHandler,
@Nullable TextHandler infoHandler,
@NotNull TextHandler errorHandler
@NotNull TextHandler errorHandler,
@Nullable String modName
) throws IOException {
File root = repo.getRepository().getWorkTree();

progressHandler.handle("Parsing installation instructions...");
var metadata = new File(root.getAbsolutePath() + File.separator + "metadata.json");
Metadata meta = null;
if(metadata.exists()) {
try (var reader = new FileReader(metadata)) {
Metadata meta = new Gson().fromJson(reader, Metadata.class);
meta = new Gson().fromJson(reader, Metadata.class);

if(meta.dependencies != null)
for (Metadata.Dependency dependency : meta.dependencies)
Expand All @@ -260,9 +270,9 @@ private static void installModImpl(
}

progressHandler.handle("Finding modinfo...");
Modinfo modinfo = findModinfo(root, warningHandler);
if(modinfo == null) {
errorHandler.handle("Cannot find modinfo.txt!\n\nThis repository does not appear to contain a valid Star Ruler 2 mod.\nPlease make sure that you have connected to the right repository, and contact the mod developer if the issue persists.");
Modinfo modinfo = findModinfo(root, warningHandler, meta, modName);
if (modinfo == null) {
reportMissingModinfo(errorHandler, modName);
return;
}

Expand All @@ -287,22 +297,42 @@ private static void installModImpl(
infoHandler.handle("Mod successfully installed!");
}

private static void reportMissingModinfo(
@NotNull TextHandler errorHandler,
@Nullable String modName
) {
if(modName != null) {
errorHandler.handle(String.format("Cannot find modinfo.txt!%n%nThis repository does not appear to have registered a valid Star Ruler 2 mod under the name \"%s\".%nPlease make sure that you have connected to the right repository, and contact the mod developer if the issue persists.", modName));
}
else {
errorHandler.handle("Cannot find modinfo.txt!\n\nThis repository does not appear to contain a valid Star Ruler 2 mod.\nPlease make sure that you have connected to the right repository, and contact the mod developer if the issue persists.");
}
}

private static Modinfo findModinfo(
@NotNull File root,
@Nullable TextHandler warningHandler
@Nullable TextHandler warningHandler,
@Nullable Metadata meta,
@Nullable String modName
) throws IOException {
var inRoot = false;
String mod;
String folderName;
var finder = new SingleFinder("modinfo.txt");
Files.walkFileTree(root.getAbsoluteFile().toPath(), finder);
var origin = root.getPath();
if(meta != null && modName != null) {
var mod = meta.mods.get(modName);
if(mod != null && mod.rootFolder != null && !mod.rootFolder.equals(""))
origin += File.separator + mod.rootFolder;
}
Files.walkFileTree(new File(origin).getAbsoluteFile().toPath(), finder);
if(finder.getResult() != null) {
mod = finder.getResult().getParent().getFileName().toString();
if(mod.equalsIgnoreCase(root.toPath().getFileName().toString())) {
folderName = finder.getResult().getParent().getFileName().toString();
if(Files.isSameFile(finder.getResult().getParent(), root.toPath())) {
inRoot = true; // The modinfo is in the repository root, so we can't discard metadata.
if(warningHandler != null)
warningHandler.handle("WARNING: Unable to discard repository metadata!\n\nTo improve loading times, it is recommended that you delete the installed mod's .git folder once installation is completed.");
}
return new Modinfo(inRoot, mod, finder.getResult().toFile());
return new Modinfo(inRoot, folderName, finder.getResult().toFile());
}
else {
return null;
Expand All @@ -323,7 +353,7 @@ private static boolean installDependency(
) {
try {
progressHandler.handle("Parsing URL for dependency \"" + dependency.name + "\"...");
if (dependency.repository.equals("")) {
if (dependency.repository == null || dependency.repository.equals("")) {
warningHandler.handle(String.format("Failed to install dependency \"%s\": Dependency metadata doesn't specify a URL. The author may be playing a prank on his users.", dependency.name));
return false;
}
Expand All @@ -342,16 +372,20 @@ private static boolean installDependency(

depRepo.pull().call();

TextHandler internalWarningHandler =
warning -> warningHandler.handle(String.format("Encountered warning while installing dependency \"%s\": %s", dependency.name, warning));

installModImpl(
depRepo,
warning -> warningHandler.handle(String.format("Encountered warning while installing dependency \"%s\": %s", dependency.name, warning)),
internalWarningHandler,
progress -> {
if(!progress.startsWith("Installing dependency"))
progress = String.format("Installing dependency \"%s\": %s", dependency.name, progress);
progressHandler.handle(progress);
},
null,
error -> warningHandler.handle(String.format("Failed to install dependency \"%s\": %s", dependency.name, error))
error -> warningHandler.handle(String.format("Failed to install dependency \"%s\": %s", dependency.name, error)),
dependency.modName
);
return true;
} catch (Exception e) {
Expand Down Expand Up @@ -391,7 +425,7 @@ public static void installMod(
repo.pull().call();
}

installModImpl(repo, warningHandler, progressHandler, infoHandler, errorHandler);
installModImpl(repo, warningHandler, progressHandler, infoHandler, errorHandler, null);
} catch (RefNotAdvertisedException e) {
errorHandler.handle("This branch or tag is no longer visible. It may have been deleted from the origin repository, or it may have been hidden somehow.\n\nThis may often be the case for branches used in beta testing or miscellaneous development; try another one, or contact the mod developers.");
e.printStackTrace();
Expand All @@ -417,11 +451,11 @@ public static boolean deleteRepository(@NotNull TextHandler errorHandler) {
}
}

public static boolean uninstallMod(@NotNull TextHandler errorHandler) {
public static boolean uninstallMod(@NotNull TextHandler errorHandler, @Nullable String modName) {
File root = repo.getRepository().getWorkTree();
Modinfo modinfo = null;
try {
modinfo = findModinfo(root, null);
modinfo = findModinfo(root, null, currentMetadata, modName);
} catch (Exception e) {
errorHandler.handle("Encountered an exception trying to find the modinfo file!\n\nFor some reason, the mod folder couldn't be detected. You may have to delete it yourself.");
}
Expand Down
43 changes: 43 additions & 0 deletions src/main/java/com/dalolorn/sr2modmanager/adapter/Utils.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package com.dalolorn.sr2modmanager.adapter;

import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.errors.RevisionSyntaxException;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectLoader;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -121,4 +124,44 @@ static String readGitFile(@NotNull ObjectLoader fileLoader) {
return null;
}
}

/** Iterates through a list of likely metadata filenames. I'd use case-insensitive filtering, but I don't fancy figuring out how to write a case-insensitive version of PathFilter. */
static TreeWalk generateMetadataWalker(Repository repo, ObjectId tree) throws FileNotFoundException {
TreeWalk result = null;
try {
result = TreeWalk.forPath(repo, "metadata.json", tree);
if (result == null)
result = TreeWalk.forPath(repo, "METADATA.JSON", tree);
if (result == null)
result = TreeWalk.forPath(repo, "Metadata.json", tree);
if (result == null)
result = TreeWalk.forPath(repo, "METADATA.json", tree);
if (result == null)
result = TreeWalk.forPath(repo, "Metadata.JSON", tree);
if (result == null)
result = TreeWalk.forPath(repo, "metadata.JSON", tree);
} catch (IOException e) {
e.printStackTrace();
}
if (result == null)
throw new FileNotFoundException("Could not find metadata.json!");

return result;
}

interface WalkerGenerator {
TreeWalk call(Repository repository, ObjectId treeId) throws FileNotFoundException;
}

static ObjectLoader getLoader(
@NotNull Git repo,
@NotNull Ref currentBranch,
@NotNull WalkerGenerator walkerGenerator
) throws RevisionSyntaxException, IOException {
var repository = repo.getRepository();
var treeId = repository.resolve(currentBranch.getName() + "^{tree}");
var walker = walkerGenerator.call(repository, treeId);
var descriptionId = walker.getObjectId(0);
return repository.open(descriptionId);
}
}
11 changes: 11 additions & 0 deletions src/main/java/com/dalolorn/sr2modmanager/model/Metadata.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
package com.dalolorn.sr2modmanager.model;

import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Metadata {
public static class Dependency {
public String name;
public String repository;
public String branch;
@Nullable public String modName;
}

public static class Mod {
public String rootFolder;
public List<Dependency> dependencies = new ArrayList<>();
}

public List<Dependency> dependencies = new ArrayList<>();
public Map<String, Mod> mods = new HashMap<>();
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,17 @@
<RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" percentHeight="55.0" vgrow="SOMETIMES" />
</rowConstraints>
<GridPane gridLinesVisible="true" GridPane.hgrow="NEVER" GridPane.vgrow="NEVER">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<ListView fx:id="branchList" prefHeight="275.0" prefWidth="300.0" visible="false" GridPane.columnIndex="0" />
<ListView fx:id="modList" prefHeight="275.0" prefWidth="300.0" GridPane.columnIndex="1" />
</children>
</GridPane>
<GridPane gridLinesVisible="true" GridPane.hgrow="NEVER" GridPane.vgrow="NEVER">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0"/>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" vgrow="SOMETIMES"/>
</rowConstraints>
<ListView fx:id="branchList" prefHeight="275.0" prefWidth="300.0" visible="false" GridPane.columnIndex="0"/>
<ListView fx:id="modList" prefHeight="275.0" prefWidth="300.0" GridPane.columnIndex="1"/>
</GridPane>
<VBox alignment="CENTER" fillWidth="false" spacing="5.0" GridPane.columnIndex="1" GridPane.vgrow="NEVER">
<padding>
<Insets bottom="10.0" left="20.0" right="20.0" top="10.0" />
Expand Down

0 comments on commit eaf005a

Please sign in to comment.