Skip to content

Commit 320e8d0

Browse files
committed
Refactor ExtraJarDependencyManager and enhance error handling in file downloads
1 parent 71323b4 commit 320e8d0

4 files changed

Lines changed: 139 additions & 44 deletions

File tree

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package net.neoforged.gradle.common
2+
3+
4+
import net.neoforged.trainingwheels.gradle.functional.BuilderBasedTestSpecification
5+
import org.gradle.testkit.runner.TaskOutcome
6+
7+
class FunctionalTests extends BuilderBasedTestSpecification {
8+
9+
@Override
10+
protected void configurePluginUnderTest() {
11+
pluginUnderTest = "net.neoforged.gradle.common";
12+
injectIntoAllProject = true;
13+
}
14+
15+
def "a mod with common as dependency can run build with the client-extra dependencies"() {
16+
given:
17+
def project = create "common-can-run-clean-build", {
18+
it.build("""
19+
java.toolchain.languageVersion = JavaLanguageVersion.of(25)
20+
21+
dependencies {
22+
implementation "net.minecraft:client:+:client-extra"
23+
}
24+
""")
25+
it.withToolchains()
26+
it.withGlobalCacheDirectory(tempDir)
27+
}
28+
29+
when:
30+
def run = project.run {
31+
it.tasks(':clean', ':build')
32+
it.stacktrace()
33+
it.debug()
34+
}
35+
36+
then:
37+
run.task(':clean').outcome == TaskOutcome.SUCCESS || run.task(':clean').outcome == TaskOutcome.UP_TO_DATE
38+
run.task(':build').outcome == TaskOutcome.SUCCESS
39+
}
40+
}

common/src/main/java/net/neoforged/gradle/common/dependency/ExtraJarDependencyManager.java

Lines changed: 66 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
import com.google.common.collect.Maps;
44
import net.neoforged.gradle.common.extensions.problems.IProblemReporter;
55
import net.neoforged.gradle.common.runtime.tasks.GenerateExtraJar;
6+
import net.neoforged.gradle.common.util.ConfigurationUtils;
67
import net.neoforged.gradle.dsl.common.extensions.MinecraftArtifactCache;
78
import net.neoforged.gradle.dsl.common.extensions.dependency.replacement.DependencyReplacement;
89
import net.neoforged.gradle.dsl.common.extensions.dependency.replacement.ReplacementResult;
9-
import net.neoforged.gradle.common.util.ConfigurationUtils;
1010
import net.neoforged.gradle.dsl.common.tasks.WithOutput;
1111
import net.neoforged.gradle.dsl.common.util.DistributionType;
1212
import net.neoforged.gradle.dsl.common.util.GameArtifact;
@@ -18,72 +18,92 @@
1818
import org.gradle.api.tasks.TaskProvider;
1919

2020
import javax.inject.Inject;
21-
import java.util.*;
21+
import java.util.Collections;
22+
import java.util.Locale;
23+
import java.util.Map;
24+
import java.util.Objects;
25+
import java.util.Optional;
2226

23-
public abstract class ExtraJarDependencyManager {
27+
public abstract class ExtraJarDependencyManager
28+
{
2429

2530
private final Map<String, ReplacementResult> replacements = Maps.newHashMap();
2631

27-
public static String generateClientCoordinateFor(final String version) {
32+
public static String generateClientCoordinateFor(final String version)
33+
{
2834
return "net.minecraft:client:" + version + ":client-extra";
2935
}
30-
31-
public static String generateServerCoordinateFor(final String version) {
36+
37+
public static String generateServerCoordinateFor(final String version)
38+
{
3239
return "net.minecraft:client:" + version + ":client-extra";
3340
}
34-
35-
public static String generateCoordinateFor(final DistributionType type, final String version) {
41+
42+
public static String generateCoordinateFor(final DistributionType type, final String version)
43+
{
3644
return String.format("net.minecraft:%s:%s:%s-extra", type.getName().toLowerCase(Locale.ROOT), version, type.getName().toLowerCase(Locale.ROOT));
3745
}
3846

3947
@Inject
40-
public ExtraJarDependencyManager(final Project project) {
48+
public ExtraJarDependencyManager(final Project project)
49+
{
4150
final DependencyReplacement dependencyReplacementsExtension = project.getExtensions().getByType(DependencyReplacement.class);
4251

4352
dependencyReplacementsExtension.getReplacementHandlers().register("extraJar", dependencyReplacementHandler -> dependencyReplacementHandler.getReplacer().set(context -> {
44-
if (isNotAMatchingDependency(context.getDependency()))
45-
return Optional.empty();
53+
if (isNotAMatchingDependency(context.getDependency()))
54+
{
55+
return Optional.empty();
56+
}
4657

47-
return Optional.of(generateReplacement(project, context.getDependency()));
48-
}));
58+
return Optional.of(generateReplacement(project, context.getDependency()));
59+
}));
4960
}
5061

51-
private boolean isNotAMatchingDependency(final Dependency dependencyToCheck) {
52-
if (dependencyToCheck instanceof ExternalModuleDependency) {
62+
private boolean isNotAMatchingDependency(final Dependency dependencyToCheck)
63+
{
64+
if (dependencyToCheck instanceof ExternalModuleDependency)
65+
{
5366
final ExternalModuleDependency externalModuleDependency = (ExternalModuleDependency) dependencyToCheck;
54-
return externalModuleDependency.getGroup() == null || !externalModuleDependency.getGroup().equals("net.minecraft") || !isSupportedSide(dependencyToCheck) || !hasMatchingArtifact(externalModuleDependency);
67+
return externalModuleDependency.getGroup() == null || !externalModuleDependency.getGroup().equals("net.minecraft") || !isSupportedSide(dependencyToCheck)
68+
|| !hasMatchingArtifact(externalModuleDependency);
5569
}
5670

5771
return true;
5872
}
5973

60-
private boolean isSupportedSide(final Dependency dependency) {
74+
private boolean isSupportedSide(final Dependency dependency)
75+
{
6176
return dependency.getName().equals("client") || dependency.getName().equals("server");
6277
}
6378

64-
private boolean hasMatchingArtifact(ExternalModuleDependency externalModuleDependency) {
65-
if (externalModuleDependency.getVersion() == null) {
79+
private boolean hasMatchingArtifact(ExternalModuleDependency externalModuleDependency)
80+
{
81+
if (externalModuleDependency.getVersion() == null)
82+
{
6683
return false;
6784
}
6885

69-
if (externalModuleDependency.getArtifacts().size() != 1) {
86+
if (externalModuleDependency.getArtifacts().size() != 1)
87+
{
7088
return false;
7189
}
7290

7391
final DependencyArtifact artifact = externalModuleDependency.getArtifacts().iterator().next();
7492
return Objects.equals(artifact.getClassifier(), "client-extra") || Objects.equals(artifact.getClassifier(), "server-extra");
7593
}
7694

77-
private ReplacementResult generateReplacement(final Project project, final Dependency dependency) {
95+
private ReplacementResult generateReplacement(final Project project, final Dependency dependency)
96+
{
7897
final String minecraftVersion = dependency.getVersion();
79-
if (minecraftVersion == null) {
98+
if (minecraftVersion == null)
99+
{
80100
final IProblemReporter problemReporter = project.getExtensions().getByType(IProblemReporter.class);
81101
throw problemReporter.throwing(spec -> {
82-
spec.id("dependencies.extra-jar", "missingVersion")
83-
.contextualLabel("Client-Extra Jar: Missing Version")
84-
.details("The dependency %s does not have a version specified".formatted(dependency))
85-
.solution("Specify a version for the dependency")
86-
.section("common-dep-management-extra-jar");
102+
spec.id("dependencies.extra-jar", "missingVersion")
103+
.contextualLabel("Client-Extra Jar: Missing Version")
104+
.details("The dependency %s does not have a version specified".formatted(dependency))
105+
.solution("Specify a version for the dependency")
106+
.section("common-dep-management-extra-jar");
87107
});
88108
}
89109

@@ -92,22 +112,27 @@ private ReplacementResult generateReplacement(final Project project, final Depen
92112

93113
Map<GameArtifact, TaskProvider<? extends WithOutput>> tasks = minecraftArtifactCacheExtension.cacheGameVersionTasks(project, minecraftVersion, DistributionType.JOINED);
94114

95-
final TaskProvider<GenerateExtraJar> extraJarTaskProvider = project.getTasks().register("create" + minecraftVersion + StringUtils.capitalize(dependency.getName()) + "ExtraJar", GenerateExtraJar.class, task -> {
96-
task.getOriginalJar().set(tasks.get(GameArtifact.CLIENT_JAR).flatMap(WithOutput::getOutput));
97-
task.getServerJar().set(tasks.get(GameArtifact.EXTRACTED_SERVER_JAR).flatMap(WithOutput::getOutput));
98-
task.getMappings().set(tasks.get(GameArtifact.CLIENT_MAPPINGS).flatMap(WithOutput::getOutput));
99-
task.getOutput().set(project.getLayout().getBuildDirectory().dir("jars/extra/" + dependency.getName()).map(cacheDir -> cacheDir.dir(Objects.requireNonNull(minecraftVersion)).file( dependency.getName() + "-extra.jar")));
100-
});
115+
final TaskProvider<GenerateExtraJar> extraJarTaskProvider =
116+
project.getTasks().register("create" + minecraftVersion + StringUtils.capitalize(dependency.getName()) + "ExtraJar", GenerateExtraJar.class, task -> {
117+
task.getOriginalJar().set(tasks.get(GameArtifact.CLIENT_JAR).flatMap(WithOutput::getOutput));
118+
task.getServerJar().set(tasks.get(GameArtifact.EXTRACTED_SERVER_JAR).flatMap(WithOutput::getOutput));
119+
task.getMappings().set(tasks.get(GameArtifact.CLIENT_MAPPINGS).flatMap(WithOutput::getOutput));
120+
task.getOutput()
121+
.set(project.getLayout()
122+
.getBuildDirectory()
123+
.dir("jars/extra/" + dependency.getName())
124+
.map(cacheDir -> cacheDir.dir(Objects.requireNonNull(minecraftVersion)).file(dependency.getName() + "-extra.jar")));
125+
});
101126

102127
return new ReplacementResult(
103-
project,
104-
extraJarTaskProvider,
105-
project.getConfigurations().detachedConfiguration(),
106-
ConfigurationUtils.temporaryUnhandledConfiguration(
107-
project.getConfigurations(),
108-
"EmptyExtraJarConfigurationFor" + minecraftVersion.replace(".", "_")
109-
),
110-
Collections.emptySet()
128+
project,
129+
extraJarTaskProvider,
130+
project.getConfigurations().detachedConfiguration(),
131+
ConfigurationUtils.temporaryUnhandledConfiguration(
132+
project.getConfigurations(),
133+
"EmptyExtraJarConfigurationFor" + minecraftVersion.replace(".", "_")
134+
),
135+
Collections.emptySet()
111136
);
112137
});
113138
}

common/src/main/java/net/neoforged/gradle/common/runtime/tasks/GenerateExtraJar.java

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package net.neoforged.gradle.common.runtime.tasks;
22

3+
import net.minecraftforge.srgutils.IMappingBuilder;
34
import net.minecraftforge.srgutils.IMappingFile;
45
import net.neoforged.gradle.common.services.caching.CachedExecutionService;
56
import net.neoforged.gradle.common.services.caching.jobs.ICacheableJob;
@@ -14,13 +15,15 @@
1415
import org.gradle.api.services.ServiceReference;
1516
import org.gradle.api.tasks.CacheableTask;
1617
import org.gradle.api.tasks.InputFile;
18+
import org.gradle.api.tasks.Optional;
1719
import org.gradle.api.tasks.PathSensitive;
1820
import org.gradle.api.tasks.PathSensitivity;
1921
import org.gradle.api.tasks.TaskAction;
2022

2123
import java.io.BufferedOutputStream;
2224
import java.io.File;
2325
import java.io.FileOutputStream;
26+
import java.io.IOException;
2427
import java.util.HashSet;
2528
import java.util.Set;
2629
import java.util.jar.Attributes;
@@ -55,7 +58,7 @@ private void doRun() throws Exception {
5558
final File outputJar = ensureFileWorkspaceReady(getOutput());
5659

5760
// Official mappings are Named -> Obf and need to be reversed
58-
var mappings = IMappingFile.load(getMappings().getAsFile().get()).reverse();
61+
var mappings = getMappings().isPresent() ? getReverse() : null;
5962
try (var clientZip = new JarFile(getOriginalJar().getAsFile().get());
6063
var serverZip = new JarFile(getServerJar().getAsFile().get())) {
6164
var clientFiles = getFileIndex(clientZip);
@@ -67,8 +70,10 @@ private void doRun() throws Exception {
6770
manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
6871
manifest.getMainAttributes().putValue("Minecraft-Dists", "server client");
6972

70-
addSourceDistEntries(clientFiles, serverFiles, "client", mappings, manifest);
71-
addSourceDistEntries(serverFiles, clientFiles, "server", mappings, manifest);
73+
if (mappings != null) {
74+
addSourceDistEntries(clientFiles, serverFiles, "client", mappings, manifest);
75+
addSourceDistEntries(serverFiles, clientFiles, "server", mappings, manifest);
76+
}
7277

7378
try (var zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(outputJar)))) {
7479
zos.putNextEntry(FileUtils.getStableEntry(JarFile.MANIFEST_NAME));
@@ -91,6 +96,15 @@ private void doRun() throws Exception {
9196
}
9297
}
9398

99+
private IMappingFile getReverse() throws IOException
100+
{
101+
final File mappingsFile = getMappings().getAsFile().get();
102+
if (mappingsFile.length() > 0)
103+
return IMappingFile.load(getMappings().getAsFile().get()).reverse();
104+
105+
return IMappingBuilder.create("left", "right").build().getMap("left", "right");
106+
}
107+
94108
private static void addSourceDistEntries(Set<String> distFiles,
95109
Set<String> otherDistFiles,
96110
String dist,

common/src/main/java/net/neoforged/gradle/common/tasks/FileCacheProviding.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,22 @@ protected void downloadJsonTo(String url) {
5252
protected File doDownloadVersionDownloadToCache(final String artifact, final String potentialError, File versionManifest) {
5353
JsonObject json = SerializationUtils.fromJson(versionManifest, JsonObject.class);
5454

55+
final JsonObject downloads = json.getAsJsonObject("downloads");
56+
if (!downloads.has(artifact)) {
57+
final File output = getOutput().get().getAsFile();
58+
if (output.exists())
59+
output.delete();
60+
61+
try
62+
{
63+
output.createNewFile();
64+
return output;
65+
}
66+
catch (IOException e)
67+
{
68+
throw new RuntimeException(e);
69+
}
70+
}
5571
final JsonObject artifactInfo = json.getAsJsonObject("downloads").getAsJsonObject(artifact);
5672
final String url = artifactInfo.get("url").getAsString();
5773
final String hash = artifactInfo.get("sha1").getAsString();

0 commit comments

Comments
 (0)