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
8 changes: 3 additions & 5 deletions src/main/java/me/itzg/helpers/modrinth/ModrinthApiClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,8 @@ public Mono<Version> resolveProjectVersion(Project project, ProjectRef projectRe
@Nullable Loader loader, String gameVersion,
VersionType defaultVersionType) {

final Loader loaderToQuery = projectRef.isDatapack() ? Loader.datapack : loader;

if (projectRef.hasVersionName()) {
return getVersionsForProject(project.getId(), loaderToQuery, gameVersion)
return getVersionsForProject(project.getId(), loader, gameVersion)
.flatMap(versions ->
Mono.justOrEmpty(versions.stream()
.filter(version ->
Expand All @@ -144,7 +142,7 @@ public Mono<Version> resolveProjectVersion(Project project, ProjectRef projectRe
));
}
if (projectRef.hasVersionType()) {
return getVersionsForProject(project.getId(), loaderToQuery, gameVersion)
return getVersionsForProject(project.getId(), loader, gameVersion)
.mapNotNull(versions -> pickVersion(project, versions, projectRef.getVersionType()));
} else if (projectRef.hasVersionId()) {
return getVersionFromId(projectRef.getVersionId())
Expand All @@ -153,7 +151,7 @@ public Mono<Version> resolveProjectVersion(Project project, ProjectRef projectRe
projectRef.getVersionId(), project.getSlug()))
);
} else {
return getVersionsForProject(project.getId(), loaderToQuery, gameVersion)
return getVersionsForProject(project.getId(), loader, gameVersion)
.mapNotNull(versions -> pickVersion(project, versions, defaultVersionType));
}
}
Expand Down
130 changes: 83 additions & 47 deletions src/main/java/me/itzg/helpers/modrinth/ModrinthCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
import me.itzg.helpers.http.Fetch;
import me.itzg.helpers.http.SharedFetchArgs;
import me.itzg.helpers.json.ObjectMappers;
import me.itzg.helpers.modrinth.model.Constants;
import me.itzg.helpers.modrinth.model.DependencyType;
import me.itzg.helpers.modrinth.model.Project;
import me.itzg.helpers.modrinth.model.ProjectType;
Expand All @@ -44,9 +43,13 @@
public class ModrinthCommand implements Callable<Integer> {

public static final String DATAPACKS_SUBDIR = "datapacks";
@Option(names = "--projects", description = "Project ID or Slug",
split = SPLIT_COMMA_NL, splitSynopsisLabel = SPLIT_SYNOPSIS_COMMA_NL,
paramLabel = "id|slug"

@Option(
names = "--projects",
description = "Project ID or Slug. Prefix with loader: e.g. fabric:project-id",
split = SPLIT_COMMA_NL,
splitSynopsisLabel = SPLIT_SYNOPSIS_COMMA_NL,
paramLabel = "[loader:]id|slug"
)
List<String> projects;

Expand Down Expand Up @@ -75,7 +78,7 @@ public enum DownloadDependencies {
/**
* Implies {@link #REQUIRED}
*/
OPTIONAL
OPTIONAL,
}

@Option(names = "--allowed-version-type", defaultValue = "release", description = "Valid values: ${COMPLETION-CANDIDATES}")
Expand Down Expand Up @@ -128,9 +131,13 @@ private List<Path> processProjects(List<String> projects) {
.defaultIfEmpty(Collections.emptyList())
.block()
.stream()
.flatMap(resolvedProject -> processProject(
modrinthApiClient, resolvedProject.getProjectRef(), resolvedProject.getProject()
))
.flatMap(resolvedProject ->
processProject(
modrinthApiClient,
resolvedProject.getProjectRef(),
resolvedProject.getProject()
)
)
.collect(Collectors.toList());
}
}
Expand All @@ -142,9 +149,9 @@ private ModrinthManifest loadManifest() throws IOException {
final ObjectMapper objectMapper = ObjectMappers.defaultMapper();

final LegacyModrinthManifest legacyManifest = objectMapper.readValue(
legacyManifestPath.toFile(),
LegacyModrinthManifest.class
);
legacyManifestPath.toFile(),
LegacyModrinthManifest.class
);

Files.delete(legacyManifestPath);

Expand All @@ -157,7 +164,13 @@ private ModrinthManifest loadManifest() throws IOException {
return Manifests.load(outputDirectory, ModrinthManifest.ID, ModrinthManifest.class);
}

private Stream<Version> expandDependencies(ModrinthApiClient modrinthApiClient, Project project, Version version) {
private Stream<Version> expandDependencies(
ModrinthApiClient modrinthApiClient,
Loader loader,
String gameVersion,
Project project,
Version version
) {
log.debug("Expanding dependencies of version={}", version);
return version.getDependencies().stream()
.filter(this::filterDependency)
Expand All @@ -170,7 +183,7 @@ private Stream<Version> expandDependencies(ModrinthApiClient modrinthApiClient,
if (dep.getVersionId() == null) {
log.debug("Fetching versions of dep={} and picking", dep);
depVersion = pickVersion(
getVersionsForProject(modrinthApiClient, dep.getProjectId())
getVersionsForProject(modrinthApiClient, dep.getProjectId(), loader, gameVersion)
);
}
else {
Expand All @@ -192,8 +205,8 @@ private Stream<Version> expandDependencies(ModrinthApiClient modrinthApiClient,
if (depVersion != null) {
log.debug("Resolved version={} for dep={}", depVersion.getVersionNumber(), dep);
return Stream.concat(
Stream.of(depVersion),
expandDependencies(modrinthApiClient, project, depVersion)
Stream.of(depVersion),
expandDependencies(modrinthApiClient, loader, gameVersion, project, depVersion)
)
.peek(expandedVer -> log.debug("Expanded dependency={} into version={}", dep, expandedVer));
}
Expand Down Expand Up @@ -229,16 +242,14 @@ private Version pickVersion(List<Version> versions, VersionType versionType) {
return null;
}

private Path download(boolean isDatapack, VersionFile versionFile) {
private Path download(Loader loader, VersionFile versionFile) {
final Path outPath;
try {
if (!isDatapack) {
outPath = Files.createDirectories(outputDirectory
.resolve(loader.getType())
)
.resolve(versionFile.getFilename());
}
else {
final Loader effectiveLoader = loader != null ? loader : this.loader;
final String outputType = effectiveLoader.getType();

if (outputType == null) {
// Datapack case
if (worldDirectory.isAbsolute()) {
outPath = Files.createDirectories(worldDirectory
.resolve(DATAPACKS_SUBDIR)
Expand All @@ -253,9 +264,15 @@ private Path download(boolean isDatapack, VersionFile versionFile) {
.resolve(versionFile.getFilename());
}
}
else {
outPath = Files.createDirectories(outputDirectory
.resolve(outputType)
)
.resolve(versionFile.getFilename());
}

} catch (IOException e) {
throw new RuntimeException("Creating mods directory", e);
throw new RuntimeException("Creating output directory", e);
}

try {
Expand All @@ -267,11 +284,11 @@ private Path download(boolean isDatapack, VersionFile versionFile) {
.handleStatus(Fetch.loggingDownloadStatusHandler(log))
.execute();
} catch (IOException e) {
throw new RuntimeException("Downloading mod file", e);
throw new RuntimeException("Downloading file", e);
}
}

private List<Version> getVersionsForProject(ModrinthApiClient modrinthApiClient, String project) {
private List<Version> getVersionsForProject(ModrinthApiClient modrinthApiClient, String project, Loader loader, String gameVersion) {
final List<Version> versions = modrinthApiClient.getVersionsForProject(
project, loader, gameVersion
)
Expand All @@ -294,10 +311,19 @@ private Stream<Path> processProject(ModrinthApiClient modrinthApiClient, Project
log.debug("Starting with project='{}' slug={}", project.getTitle(), project.getSlug());

if (projectsProcessed.add(project.getId())) {
final Loader effectiveLoader = projectRef.getLoader() != null
? projectRef.getLoader()
: this.loader;

final Version version;
try {
version = modrinthApiClient.resolveProjectVersion(
project, projectRef, loader, gameVersion, defaultVersionType
version = modrinthApiClient
.resolveProjectVersion(
project,
projectRef,
effectiveLoader,
gameVersion,
defaultVersionType
)
.block();
} catch (NoApplicableVersionsException | NoFilesAvailableException e) {
Expand All @@ -306,36 +332,46 @@ private Stream<Path> processProject(ModrinthApiClient modrinthApiClient, Project

if (version != null) {
if (version.getFiles().isEmpty()) {
throw new GenericException(String.format("Project %s has no files declared", project.getSlug()));
throw new GenericException(
String.format(
"Project %s has no files declared",
project.getSlug()
)
);
}

final boolean isDatapack = isDatapack(version);

return Stream.concat(
Stream.of(version),
expandDependencies(modrinthApiClient, project, version)
Stream.of(version),
expandDependencies(
modrinthApiClient,
effectiveLoader,
gameVersion,
project,
version
)
)
.map(ModrinthApiClient::pickVersionFile)
.map(versionFile -> download(isDatapack, versionFile))
.flatMap(downloadedFile -> !isDatapack ? expandIfZip(downloadedFile) : Stream.empty());
}
else {
.map(versionFile -> download(effectiveLoader, versionFile))
.flatMap(downloadedFile -> {
// Only expand ZIPs for non-datapack loaders
return effectiveLoader == Loader.datapack
? Stream.of(downloadedFile)
: expandIfZip(downloadedFile);
});
} else {
throw new InvalidParameterException(
String.format("Project %s does not have any matching versions for loader %s, game version %s",
projectRef, loader, gameVersion
));
String.format(
"Project %s does not have any matching versions for loader %s, game version %s",
projectRef,
effectiveLoader,
gameVersion
)
);
}
}
return Stream.empty();
}

private boolean isDatapack(Version version) {
return
version.getLoaders() != null
&& version.getLoaders().size() == 1
&& version.getLoaders().get(0).equals(Constants.LOADER_DATAPACK);
}

/**
* If downloadedFile ends in .zip, then expand it, return its files and given file.
*
Expand Down
Loading