diff --git a/src/main/java/me/itzg/helpers/curseforge/CurseForgeInstaller.java b/src/main/java/me/itzg/helpers/curseforge/CurseForgeInstaller.java index f3285b81..0be70ebc 100644 --- a/src/main/java/me/itzg/helpers/curseforge/CurseForgeInstaller.java +++ b/src/main/java/me/itzg/helpers/curseforge/CurseForgeInstaller.java @@ -465,7 +465,27 @@ private ModPackResults processModpack(InstallContext context, // ...does the modpack even say it's required? .filter(ManifestFileRef::isRequired) // ...is this mod file excluded because it is a client mod that didn't declare as such - .filter(manifestFileRef -> !excludeIncludeIds.getExcludeIds().contains(manifestFileRef.getProjectID())) + .filterWhen(manifestFileRef -> { + final int projectID = manifestFileRef.getProjectID(); + final boolean exclude = excludeIncludeIds.getExcludeIds().contains(projectID); + final boolean forceInclude = excludeIncludeIds.getForceIncludeIds().contains(projectID); + + log.debug("Evaluating projectId={} with exclude={} and forceInclude={}", + projectID, exclude, forceInclude + ); + + return Mono.just(forceInclude || !exclude) + .flatMap(proceed -> proceed ? Mono.just(true) + : context.cfApi.getModInfo(projectID) + .map(mod -> { + log.info("Excluding mod file '{}' ({}) due to configuration", + mod.getName(), mod.getSlug() + ); + // and filter away + return false; + }) + ); + }) // ...download and possibly unzip world file .flatMap(fileRef -> downloadFileFromModpack(context, outputPaths, diff --git a/src/main/java/me/itzg/helpers/curseforge/InstallCurseForgeCommand.java b/src/main/java/me/itzg/helpers/curseforge/InstallCurseForgeCommand.java index 95541175..c3b97cd8 100644 --- a/src/main/java/me/itzg/helpers/curseforge/InstallCurseForgeCommand.java +++ b/src/main/java/me/itzg/helpers/curseforge/InstallCurseForgeCommand.java @@ -1,14 +1,6 @@ package me.itzg.helpers.curseforge; -import me.itzg.helpers.files.ResultsFileWriter; -import me.itzg.helpers.http.PathOrUri; -import me.itzg.helpers.http.PathOrUriConverter; -import me.itzg.helpers.http.SharedFetchArgs; -import me.itzg.helpers.json.ObjectMappers; -import picocli.CommandLine.ArgGroup; -import picocli.CommandLine.Command; -import picocli.CommandLine.ExitCode; -import picocli.CommandLine.Option; +import static me.itzg.helpers.http.Fetch.fetch; import java.io.IOException; import java.nio.file.Path; @@ -18,8 +10,15 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; - -import static me.itzg.helpers.http.Fetch.fetch; +import me.itzg.helpers.files.ResultsFileWriter; +import me.itzg.helpers.http.PathOrUri; +import me.itzg.helpers.http.PathOrUriConverter; +import me.itzg.helpers.http.SharedFetchArgs; +import me.itzg.helpers.json.ObjectMappers; +import picocli.CommandLine.ArgGroup; +import picocli.CommandLine.Command; +import picocli.CommandLine.ExitCode; +import picocli.CommandLine.Option; @Command(name = "install-curseforge", subcommands = { SchemasCommand.class @@ -90,18 +89,19 @@ static class ExcludeIncludeArgs { + "See README for schema.", converter = PathOrUriConverter.class ) - PathOrUri exludeIncludeFile; + PathOrUri excludeIncludeFile; static class Listed { @Option(names = "--exclude-mods", paramLabel = "PROJECT_ID|SLUG", - split = "\\s+|,", splitSynopsisLabel = ",| ", + split = "\\s+|,", splitSynopsisLabel = ",|", description = "For mods that need to be excluded from server deployments, such as those that don't label as client" ) Set excludedMods; @Option(names = "--force-include-mods", paramLabel = "PROJECT_ID|SLUG", - split = "\\s+|,", splitSynopsisLabel = ",| ", - description = "Some mods incorrectly declare client-only support, but still need to be included in a server deploy" + split = "\\s+|,", splitSynopsisLabel = ",|", + description = "Some mods incorrectly declare client-only support, but still need to be included in a server deploy." + + "%nThis can also be used to selectively override exclusions." ) Set forceIncludeMods; @@ -194,7 +194,7 @@ public Integer call() throws Exception { private ExcludeIncludesContent loadExcludeIncludes() throws IOException { final ExcludeIncludesContent fromFile = - excludeIncludeArgs.exludeIncludeFile != null ? loadExcludeIncludesFile() + excludeIncludeArgs.excludeIncludeFile != null ? loadExcludeIncludesFile() : null; if (excludeIncludeArgs.listed != null) { @@ -241,14 +241,14 @@ private Set mergeSets(Set s1, Set s2) { } private ExcludeIncludesContent loadExcludeIncludesFile() throws IOException { - if (excludeIncludeArgs.exludeIncludeFile.getPath() != null) { + if (excludeIncludeArgs.excludeIncludeFile.getPath() != null) { return ObjectMappers.defaultMapper() - .readValue(excludeIncludeArgs.exludeIncludeFile.getPath().toFile(), + .readValue(excludeIncludeArgs.excludeIncludeFile.getPath().toFile(), ExcludeIncludesContent.class ); } else { - return fetch(excludeIncludeArgs.exludeIncludeFile.getUri()) + return fetch(excludeIncludeArgs.excludeIncludeFile.getUri()) .toObject(ExcludeIncludesContent.class) .acceptContentTypes(null) .execute();