Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,8 @@ dependencies {
def picocliVersion = '4.7.4'

implementation(platform('com.fasterxml.jackson:jackson-bom:2.15.2'))
implementation(platform('ch.qos.logback:logback-parent:1.3.5')) {
because '1.4.+ requires Java 11 and we are stuck on 8'
version {
reject '1.4.+'
}
}
// 1.4.+ requires Java 11 and we are stuck on 8
implementation(platform('ch.qos.logback:logback-parent:[1.3.5,1.4)'))

implementation 'ch.qos.logback:logback-core'
implementation 'ch.qos.logback:logback-classic'
Expand All @@ -104,6 +100,7 @@ dependencies {
implementation 'commons-codec:commons-codec:1.15'
// for RFC5987 parsing of content-disposition filename*
implementation 'org.apache.cxf:cxf-core:4.0.2'
implementation 'org.jetbrains:annotations:24.0.1'

testImplementation 'org.assertj:assertj-core:3.24.2'
// https://github.com/webcompere/model-assert
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/me/itzg/helpers/McImageHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import me.itzg.helpers.vanillatweaks.VanillaTweaksCommand;
import me.itzg.helpers.versions.CompareVersionsCommand;
import me.itzg.helpers.versions.JavaReleaseCommand;
import me.itzg.helpers.versions.ResolveMinecraftVersionCommand;
import org.slf4j.LoggerFactory;
import picocli.CommandLine;
import picocli.CommandLine.ArgGroup;
Expand Down Expand Up @@ -68,6 +69,7 @@
MulitCopyCommand.class,
NetworkInterfacesCommand.class,
PatchCommand.class,
ResolveMinecraftVersionCommand.class,
Sync.class,
SyncAndInterpolate.class,
YamlPathCmd.class,
Expand Down
35 changes: 23 additions & 12 deletions src/main/java/me/itzg/helpers/curseforge/CurseForgeApiClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,33 @@

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import me.itzg.helpers.curseforge.model.*;
import me.itzg.helpers.errors.GenericException;
import me.itzg.helpers.errors.InvalidParameterException;
import me.itzg.helpers.http.*;
import me.itzg.helpers.json.ObjectMappers;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

import java.io.IOException;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import me.itzg.helpers.curseforge.model.Category;
import me.itzg.helpers.curseforge.model.CurseForgeFile;
import me.itzg.helpers.curseforge.model.CurseForgeMod;
import me.itzg.helpers.curseforge.model.CurseForgeResponse;
import me.itzg.helpers.curseforge.model.GetCategoriesResponse;
import me.itzg.helpers.curseforge.model.GetModFileResponse;
import me.itzg.helpers.curseforge.model.GetModFilesResponse;
import me.itzg.helpers.curseforge.model.GetModResponse;
import me.itzg.helpers.curseforge.model.ModsSearchResponse;
import me.itzg.helpers.errors.GenericException;
import me.itzg.helpers.errors.InvalidParameterException;
import me.itzg.helpers.http.FailedRequestException;
import me.itzg.helpers.http.Fetch;
import me.itzg.helpers.http.FileDownloadStatusHandler;
import me.itzg.helpers.http.SharedFetch;
import me.itzg.helpers.http.UriBuilder;
import me.itzg.helpers.json.ObjectMappers;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

@Slf4j
public class CurseForgeApiClient implements AutoCloseable {
Expand Down Expand Up @@ -48,7 +59,7 @@ public CategoryInfo loadCategoryInfo(Set<String> applicableClassIdSlugs, String
.fetch(uriBuilder.resolve("/categories?gameId={gameId}&classesOnly=true", gameId))
.toObject(GetCategoriesResponse.class)
.assemble()
.map(resp -> {
.flatMap(resp -> {
final Map<Integer, Category> contentClassIds = new HashMap<>();
Integer modpackClassId = null;

Expand All @@ -62,10 +73,10 @@ public CategoryInfo loadCategoryInfo(Set<String> applicableClassIdSlugs, String
}

if (modpackClassId == null) {
throw new GenericException("Unable to lookup classId for modpacks");
return Mono.error(new GenericException("Unable to lookup classId for modpacks"));
}

return new CategoryInfo(contentClassIds, modpackClassId);
return Mono.just(new CategoryInfo(contentClassIds, modpackClassId));
}
)
.block();
Expand Down
20 changes: 20 additions & 0 deletions src/main/java/me/itzg/helpers/errors/Validators.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package me.itzg.helpers.errors;

import java.util.regex.Matcher;
import java.util.regex.Pattern;
import picocli.CommandLine.Model.CommandSpec;
import picocli.CommandLine.ParameterException;

public class Validators {
public static final Pattern VERSION_OR_LATEST = Pattern.compile("latest|\\d+(\\.\\d+)+(-.+)?", Pattern.CASE_INSENSITIVE);
public static final String DESCRIPTION_MINECRAFT_VERSION = "May be 'latest' or specific version";

public static String validateMinecraftVersion(CommandSpec spec, String input) {
final Matcher m = VERSION_OR_LATEST.matcher(input);
if (m.matches()) {
return input.toLowerCase();
}

throw new ParameterException(spec.commandLine(), "Invalid value for minecraft version: " + input);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -167,12 +167,13 @@ private Mono<Path> installLauncherUsingInstaller(SharedFetch sharedFetch,
.skipExisting(true)
.assemble()
.publishOn(Schedulers.boundedElastic())
.map(path -> {
.flatMap(path -> {
log.info("Running Fabric installer for Minecraft {} and loader version {}",
minecraftVersion, loaderVersion
);

try {
//noinspection BlockingMethodInNonBlockingContext because IntelliJ is confused
final Process proc = new ProcessBuilder(
"java", "-jar", path.toString(),
"server",
Expand All @@ -183,29 +184,31 @@ private Mono<Path> installLauncherUsingInstaller(SharedFetch sharedFetch,
.redirectErrorStream(true)
.start();

//noinspection BlockingMethodInNonBlockingContext because IntelliJ is confused
final boolean success = proc.waitFor(FABRIC_INSTALLER_TIMEOUT_SEC, TimeUnit.SECONDS);
if (!success) {
IoStreams.transfer(proc.getInputStream(), System.err);
throw new GenericException("Fabric installer took too long to run");
return Mono.error(new GenericException("Fabric installer took too long to run"));
}

if (proc.exitValue() != 0) {
IoStreams.transfer(proc.getInputStream(), System.err);
throw new GenericException("Fabric installer failed to run");
return Mono.error(new GenericException("Fabric installer failed to run"));
}
} catch (IOException e) {
throw new GenericException("Failed to run fabric installer", e);
return Mono.error(new GenericException("Failed to run fabric installer", e));
} catch (InterruptedException e) {
throw new GenericException("While running fabric installer", e);
return Mono.error(new GenericException("While running fabric installer", e));
} finally {
try {
//noinspection BlockingMethodInNonBlockingContext because IntelliJ is confused
Files.delete(path);
} catch (IOException e) {
log.warn("Failed to delete fabric installer at {}", path, e);
}
}

return outputDir.resolve("fabric-server-launch.jar");
return Mono.just(outputDir.resolve("fabric-server-launch.jar"));
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import me.itzg.helpers.errors.GenericException;
import org.jetbrains.annotations.Blocking;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
import reactor.netty.http.client.HttpClient;
Expand Down Expand Up @@ -71,6 +72,7 @@ private static class FileToDownload {
}

public Mono<Path> assemble() {
//noinspection BlockingMethodInNonBlockingContext
return useReactiveClient(client ->
client
.followRedirect(true)
Expand All @@ -96,9 +98,7 @@ public Mono<Path> assemble() {
);
}

/**
* NOTE: contains blocking call
*/
@Blocking
private Mono<Path> assembleFileDownload(HttpClient client, FileToDownload fileToDownload) {
final Path outputFile = fileToDownload.outputFile;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
package me.itzg.helpers.modrinth;

import static me.itzg.helpers.modrinth.ModrinthApiClient.pickVersionFile;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Callable;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import lombok.extern.slf4j.Slf4j;
import me.itzg.helpers.errors.GenericException;
import me.itzg.helpers.errors.InvalidParameterException;
Expand All @@ -20,32 +38,14 @@
import me.itzg.helpers.modrinth.model.VersionFile;
import me.itzg.helpers.modrinth.model.VersionType;
import me.itzg.helpers.quilt.QuiltInstaller;
import org.jetbrains.annotations.Blocking;
import picocli.CommandLine;
import picocli.CommandLine.ExitCode;
import picocli.CommandLine.Option;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Callable;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import static me.itzg.helpers.modrinth.ModrinthApiClient.pickVersionFile;

@CommandLine.Command(name = "install-modrinth-modpack",
description = "Supports installation of Modrinth modpacks along with the associated mod loader",
mixinStandardHelpOptions = true
Expand Down Expand Up @@ -155,6 +155,7 @@ private ModrinthModpackManifest processModpack(ProjectRef projectRef, ModrinthMo
.flatMap(version -> {
final VersionFile versionFile = pickVersionFile(version);
log.info("Installing version {} of {}", version.getVersionNumber(), project.getTitle());
//noinspection BlockingMethodInNonBlockingContext because IntelliJ is confused
return apiClient.downloadMrPack(versionFile)
.publishOn(Schedulers.boundedElastic())
.flatMap(zipPath ->
Expand All @@ -175,6 +176,7 @@ private ModrinthModpackManifest processModpack(ProjectRef projectRef, ModrinthMo
}
}

@Blocking
private boolean needsInstall(ModrinthModpackManifest prevManifest, Project project, Version version) {
if (prevManifest != null) {
if (prevManifest.getProjectSlug().equals(project.getSlug())
Expand All @@ -194,6 +196,7 @@ private boolean needsInstall(ModrinthModpackManifest prevManifest, Project proje
return true;
}

@Blocking
private Mono<ModrinthModpackManifest> processModpackZip(ModrinthApiClient apiClient, Path zipFile, Project project,
Version version
) {
Expand Down Expand Up @@ -287,14 +290,15 @@ private String applyModloader(Map<DependencyId, String> dependencies) throws IOE

final String quiltVersion = dependencies.get(DependencyId.quiltLoader);
if (quiltVersion != null) {
new QuiltInstaller(QuiltInstaller.DEFAULT_REPO_URL,
try (QuiltInstaller installer = new QuiltInstaller(QuiltInstaller.DEFAULT_REPO_URL,
sharedFetchArgs.options(),
outputDirectory,
minecraftVersion
)
.setResultsFile(resultsFile)
.setLoaderVersion(quiltVersion)
.install();
.setResultsFile(resultsFile)) {

installer.installWithVersion(null, quiltVersion);
}
}

return minecraftVersion;
Expand Down
9 changes: 3 additions & 6 deletions src/main/java/me/itzg/helpers/mvn/MavenRepoApi.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
package me.itzg.helpers.mvn;

import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import me.itzg.helpers.http.Fetch;
import java.nio.file.Path;
import me.itzg.helpers.http.SharedFetch;
import me.itzg.helpers.http.SharedFetch.Options;
import me.itzg.helpers.http.UriBuilder;
import reactor.core.publisher.Mono;

import java.nio.file.Path;

public class MavenRepoApi {
private final UriBuilder uriBuilder;
private final SharedFetch sharedFetch;
private final XmlMapper xmlMapper;

public MavenRepoApi(String repoUrl, String forCommand, Options options) {
public MavenRepoApi(String repoUrl, SharedFetch sharedFetch) {
uriBuilder = UriBuilder.withBaseUrl(repoUrl);
sharedFetch = Fetch.sharedFetch(forCommand, options);
this.sharedFetch = sharedFetch;
xmlMapper = new XmlMapper();
}

Expand Down
17 changes: 10 additions & 7 deletions src/main/java/me/itzg/helpers/patch/PatchSetProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,22 @@
import com.fasterxml.jackson.databind.node.TextNode;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;
import lombok.extern.slf4j.Slf4j;
import me.itzg.helpers.CharsetDetector;
import me.itzg.helpers.env.Interpolator;
import me.itzg.helpers.env.MissingVariablesException;
import me.itzg.helpers.patch.model.*;

import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import lombok.extern.slf4j.Slf4j;
import me.itzg.helpers.CharsetDetector;
import me.itzg.helpers.env.Interpolator;
import me.itzg.helpers.env.MissingVariablesException;
import me.itzg.helpers.patch.model.PatchDefinition;
import me.itzg.helpers.patch.model.PatchOperation;
import me.itzg.helpers.patch.model.PatchPutOperation;
import me.itzg.helpers.patch.model.PatchSet;
import me.itzg.helpers.patch.model.PatchSetOperation;

@Slf4j
public class PatchSetProcessor {
Expand Down Expand Up @@ -160,7 +163,7 @@ private void processTextNode(TextNode value, String valueType,

consumer.accept(convertedValue);
}
else if (!interpolateResult.getMissingVariables().isEmpty()) {
else {
throw new MissingVariablesException(interpolateResult.getMissingVariables());
}
}
Expand Down
Loading