Skip to content

Commit 0faf93d

Browse files
Loader prefix system for Modrinth (#571)
1 parent 9a7e0b1 commit 0faf93d

File tree

5 files changed

+169
-103
lines changed

5 files changed

+169
-103
lines changed

src/main/java/me/itzg/helpers/modrinth/ModrinthApiClient.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,8 @@ public Mono<Version> resolveProjectVersion(Project project, ProjectRef projectRe
130130
@Nullable Loader loader, String gameVersion,
131131
VersionType defaultVersionType) {
132132

133-
final Loader loaderToQuery = projectRef.isDatapack() ? Loader.datapack : loader;
134-
135133
if (projectRef.hasVersionName()) {
136-
return getVersionsForProject(project.getId(), loaderToQuery, gameVersion)
134+
return getVersionsForProject(project.getId(), loader, gameVersion)
137135
.flatMap(versions ->
138136
Mono.justOrEmpty(versions.stream()
139137
.filter(version ->
@@ -144,7 +142,7 @@ public Mono<Version> resolveProjectVersion(Project project, ProjectRef projectRe
144142
));
145143
}
146144
if (projectRef.hasVersionType()) {
147-
return getVersionsForProject(project.getId(), loaderToQuery, gameVersion)
145+
return getVersionsForProject(project.getId(), loader, gameVersion)
148146
.mapNotNull(versions -> pickVersion(project, versions, projectRef.getVersionType()));
149147
} else if (projectRef.hasVersionId()) {
150148
return getVersionFromId(projectRef.getVersionId())
@@ -153,7 +151,7 @@ public Mono<Version> resolveProjectVersion(Project project, ProjectRef projectRe
153151
projectRef.getVersionId(), project.getSlug()))
154152
);
155153
} else {
156-
return getVersionsForProject(project.getId(), loaderToQuery, gameVersion)
154+
return getVersionsForProject(project.getId(), loader, gameVersion)
157155
.mapNotNull(versions -> pickVersion(project, versions, defaultVersionType));
158156
}
159157
}

src/main/java/me/itzg/helpers/modrinth/ModrinthCommand.java

Lines changed: 83 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import me.itzg.helpers.http.Fetch;
2727
import me.itzg.helpers.http.SharedFetchArgs;
2828
import me.itzg.helpers.json.ObjectMappers;
29-
import me.itzg.helpers.modrinth.model.Constants;
3029
import me.itzg.helpers.modrinth.model.DependencyType;
3130
import me.itzg.helpers.modrinth.model.Project;
3231
import me.itzg.helpers.modrinth.model.ProjectType;
@@ -44,9 +43,13 @@
4443
public class ModrinthCommand implements Callable<Integer> {
4544

4645
public static final String DATAPACKS_SUBDIR = "datapacks";
47-
@Option(names = "--projects", description = "Project ID or Slug",
48-
split = SPLIT_COMMA_NL, splitSynopsisLabel = SPLIT_SYNOPSIS_COMMA_NL,
49-
paramLabel = "id|slug"
46+
47+
@Option(
48+
names = "--projects",
49+
description = "Project ID or Slug. Prefix with loader: e.g. fabric:project-id",
50+
split = SPLIT_COMMA_NL,
51+
splitSynopsisLabel = SPLIT_SYNOPSIS_COMMA_NL,
52+
paramLabel = "[loader:]id|slug"
5053
)
5154
List<String> projects;
5255

@@ -75,7 +78,7 @@ public enum DownloadDependencies {
7578
/**
7679
* Implies {@link #REQUIRED}
7780
*/
78-
OPTIONAL
81+
OPTIONAL,
7982
}
8083

8184
@Option(names = "--allowed-version-type", defaultValue = "release", description = "Valid values: ${COMPLETION-CANDIDATES}")
@@ -128,9 +131,13 @@ private List<Path> processProjects(List<String> projects) {
128131
.defaultIfEmpty(Collections.emptyList())
129132
.block()
130133
.stream()
131-
.flatMap(resolvedProject -> processProject(
132-
modrinthApiClient, resolvedProject.getProjectRef(), resolvedProject.getProject()
133-
))
134+
.flatMap(resolvedProject ->
135+
processProject(
136+
modrinthApiClient,
137+
resolvedProject.getProjectRef(),
138+
resolvedProject.getProject()
139+
)
140+
)
134141
.collect(Collectors.toList());
135142
}
136143
}
@@ -142,9 +149,9 @@ private ModrinthManifest loadManifest() throws IOException {
142149
final ObjectMapper objectMapper = ObjectMappers.defaultMapper();
143150

144151
final LegacyModrinthManifest legacyManifest = objectMapper.readValue(
145-
legacyManifestPath.toFile(),
146-
LegacyModrinthManifest.class
147-
);
152+
legacyManifestPath.toFile(),
153+
LegacyModrinthManifest.class
154+
);
148155

149156
Files.delete(legacyManifestPath);
150157

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

160-
private Stream<Version> expandDependencies(ModrinthApiClient modrinthApiClient, Project project, Version version) {
167+
private Stream<Version> expandDependencies(
168+
ModrinthApiClient modrinthApiClient,
169+
Loader loader,
170+
String gameVersion,
171+
Project project,
172+
Version version
173+
) {
161174
log.debug("Expanding dependencies of version={}", version);
162175
return version.getDependencies().stream()
163176
.filter(this::filterDependency)
@@ -170,7 +183,7 @@ private Stream<Version> expandDependencies(ModrinthApiClient modrinthApiClient,
170183
if (dep.getVersionId() == null) {
171184
log.debug("Fetching versions of dep={} and picking", dep);
172185
depVersion = pickVersion(
173-
getVersionsForProject(modrinthApiClient, dep.getProjectId())
186+
getVersionsForProject(modrinthApiClient, dep.getProjectId(), loader, gameVersion)
174187
);
175188
}
176189
else {
@@ -192,8 +205,8 @@ private Stream<Version> expandDependencies(ModrinthApiClient modrinthApiClient,
192205
if (depVersion != null) {
193206
log.debug("Resolved version={} for dep={}", depVersion.getVersionNumber(), dep);
194207
return Stream.concat(
195-
Stream.of(depVersion),
196-
expandDependencies(modrinthApiClient, project, depVersion)
208+
Stream.of(depVersion),
209+
expandDependencies(modrinthApiClient, loader, gameVersion, project, depVersion)
197210
)
198211
.peek(expandedVer -> log.debug("Expanded dependency={} into version={}", dep, expandedVer));
199212
}
@@ -229,16 +242,14 @@ private Version pickVersion(List<Version> versions, VersionType versionType) {
229242
return null;
230243
}
231244

232-
private Path download(boolean isDatapack, VersionFile versionFile) {
245+
private Path download(Loader loader, VersionFile versionFile) {
233246
final Path outPath;
234247
try {
235-
if (!isDatapack) {
236-
outPath = Files.createDirectories(outputDirectory
237-
.resolve(loader.getType())
238-
)
239-
.resolve(versionFile.getFilename());
240-
}
241-
else {
248+
final Loader effectiveLoader = loader != null ? loader : this.loader;
249+
final String outputType = effectiveLoader.getType();
250+
251+
if (outputType == null) {
252+
// Datapack case
242253
if (worldDirectory.isAbsolute()) {
243254
outPath = Files.createDirectories(worldDirectory
244255
.resolve(DATAPACKS_SUBDIR)
@@ -253,9 +264,15 @@ private Path download(boolean isDatapack, VersionFile versionFile) {
253264
.resolve(versionFile.getFilename());
254265
}
255266
}
267+
else {
268+
outPath = Files.createDirectories(outputDirectory
269+
.resolve(outputType)
270+
)
271+
.resolve(versionFile.getFilename());
272+
}
256273

257274
} catch (IOException e) {
258-
throw new RuntimeException("Creating mods directory", e);
275+
throw new RuntimeException("Creating output directory", e);
259276
}
260277

261278
try {
@@ -267,11 +284,11 @@ private Path download(boolean isDatapack, VersionFile versionFile) {
267284
.handleStatus(Fetch.loggingDownloadStatusHandler(log))
268285
.execute();
269286
} catch (IOException e) {
270-
throw new RuntimeException("Downloading mod file", e);
287+
throw new RuntimeException("Downloading file", e);
271288
}
272289
}
273290

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

296313
if (projectsProcessed.add(project.getId())) {
314+
final Loader effectiveLoader = projectRef.getLoader() != null
315+
? projectRef.getLoader()
316+
: this.loader;
317+
297318
final Version version;
298319
try {
299-
version = modrinthApiClient.resolveProjectVersion(
300-
project, projectRef, loader, gameVersion, defaultVersionType
320+
version = modrinthApiClient
321+
.resolveProjectVersion(
322+
project,
323+
projectRef,
324+
effectiveLoader,
325+
gameVersion,
326+
defaultVersionType
301327
)
302328
.block();
303329
} catch (NoApplicableVersionsException | NoFilesAvailableException e) {
@@ -306,36 +332,46 @@ private Stream<Path> processProject(ModrinthApiClient modrinthApiClient, Project
306332

307333
if (version != null) {
308334
if (version.getFiles().isEmpty()) {
309-
throw new GenericException(String.format("Project %s has no files declared", project.getSlug()));
335+
throw new GenericException(
336+
String.format(
337+
"Project %s has no files declared",
338+
project.getSlug()
339+
)
340+
);
310341
}
311342

312-
final boolean isDatapack = isDatapack(version);
313-
314343
return Stream.concat(
315-
Stream.of(version),
316-
expandDependencies(modrinthApiClient, project, version)
344+
Stream.of(version),
345+
expandDependencies(
346+
modrinthApiClient,
347+
effectiveLoader,
348+
gameVersion,
349+
project,
350+
version
317351
)
352+
)
318353
.map(ModrinthApiClient::pickVersionFile)
319-
.map(versionFile -> download(isDatapack, versionFile))
320-
.flatMap(downloadedFile -> !isDatapack ? expandIfZip(downloadedFile) : Stream.empty());
321-
}
322-
else {
354+
.map(versionFile -> download(effectiveLoader, versionFile))
355+
.flatMap(downloadedFile -> {
356+
// Only expand ZIPs for non-datapack loaders
357+
return effectiveLoader == Loader.datapack
358+
? Stream.of(downloadedFile)
359+
: expandIfZip(downloadedFile);
360+
});
361+
} else {
323362
throw new InvalidParameterException(
324-
String.format("Project %s does not have any matching versions for loader %s, game version %s",
325-
projectRef, loader, gameVersion
326-
));
363+
String.format(
364+
"Project %s does not have any matching versions for loader %s, game version %s",
365+
projectRef,
366+
effectiveLoader,
367+
gameVersion
368+
)
369+
);
327370
}
328371
}
329372
return Stream.empty();
330373
}
331374

332-
private boolean isDatapack(Version version) {
333-
return
334-
version.getLoaders() != null
335-
&& version.getLoaders().size() == 1
336-
&& version.getLoaders().get(0).equals(Constants.LOADER_DATAPACK);
337-
}
338-
339375
/**
340376
* If downloadedFile ends in .zip, then expand it, return its files and given file.
341377
*

0 commit comments

Comments
 (0)