Skip to content

Commit ddf1c58

Browse files
LexManosJonathing
andauthored
Add support for mavenizer output json, and expose mappings helper methods (#1042)
Co-authored-by: Jonathing <me@jonathing.me>
1 parent 59c470d commit ddf1c58

8 files changed

Lines changed: 261 additions & 38 deletions

File tree

settings.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ gradle.beforeProject { Project project ->
2424

2525
//@formatter:off
2626
dependencyResolutionManagement.versionCatalogs.register('libs') {
27-
version 'gradleutils', '3.3.42'
27+
version 'gradleutils', '3.4.3'
2828

2929
plugin 'licenser', 'net.minecraftforge.licenser' version '1.2.0' // https://plugins.gradle.org/plugin/net.minecraftforge.licenser
3030
plugin 'gradleutils', 'net.minecraftforge.gradleutils' versionRef 'gradleutils'
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright (c) Forge Development LLC and contributors
3+
* SPDX-License-Identifier: LGPL-2.1-only
4+
*/
5+
package net.minecraftforge.gradle;
6+
7+
import org.gradle.api.artifacts.ExternalModuleDependency;
8+
import org.gradle.api.provider.Provider;
9+
import org.gradle.api.provider.ProviderConvertible;
10+
11+
import java.io.File;
12+
13+
/// A Mavenizer instance is an abstraction over an invocation of the Minecraft Mavenizer and its output when generating
14+
/// a Minecraft dependency. This is designed to be consumed by one of the various
15+
/// [MinecraftExtensionForProject#dependency] methods as it is a [ProviderConvertible] of a dependency.
16+
///
17+
/// This is not to be confused with [MinecraftDependency], which is designed to add additional DSL features on top of
18+
/// [ExternalModuleDependency] when configuring a Minecraft dependency in your buildscript.
19+
public interface MavenizerInstance extends ProviderConvertible<ExternalModuleDependency> {
20+
/// Gets the dependency (used by Gradle) generated by the Mavenizer instance.
21+
///
22+
/// @return The dependency generated by this instance
23+
@Override Provider<ExternalModuleDependency> asProvider();
24+
25+
/// Gets the mappings version used by the Mavenizer instance.
26+
///
27+
/// @return The mappings version used
28+
/// @see MinecraftMappings#getVersion()
29+
Provider<String> getMappingVersion();
30+
31+
/// Gets the artifact coordinates for the SRG mappings used by the Mavenizer instance.
32+
///
33+
/// @return The SRG mapping artifact coordinate
34+
Provider<String> getToSrg();
35+
36+
/// Gets the SRG mapping file used by the Mavenizer instance.
37+
///
38+
/// @return The SRG mapping file
39+
/// @apiNote Buildscript authors should prefer to use [#getToSrg()] with
40+
/// [org.gradle.api.artifacts.dsl.DependencyFactory#create(CharSequence)] or
41+
/// [org.gradle.api.artifacts.dsl.DependencyHandler#addProvider(String, Provider)].
42+
Provider<File> getToSrgFile();
43+
44+
/// Gets the artifact coordinates for the SRG mappings used by the Mavenizer instance.
45+
///
46+
/// @return The SRG mapping artifact coordinate
47+
Provider<String> getToObf();
48+
49+
/// Gets the notch mapping file used by the Mavenizer instance.
50+
///
51+
/// @return The notch mapping file
52+
/// @apiNote Buildscript authors should prefer to use [#getToObf()] with
53+
/// [org.gradle.api.artifacts.dsl.DependencyFactory#create(CharSequence)] or
54+
/// [org.gradle.api.artifacts.dsl.DependencyHandler#addProvider(String, Provider)].
55+
Provider<File> getToObfFile();
56+
}

src/main/java/net/minecraftforge/gradle/MinecraftExtensionForProject.java

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,10 @@
77
import groovy.lang.Closure;
88
import groovy.lang.DelegatesTo;
99
import groovy.transform.stc.ClosureParams;
10-
import groovy.transform.stc.FromString;
1110
import groovy.transform.stc.SimpleType;
1211
import net.minecraftforge.gradleutils.shared.Closures;
1312
import org.gradle.api.Action;
14-
import org.gradle.api.NamedDomainObjectContainer;
1513
import org.gradle.api.artifacts.ExternalModuleDependency;
16-
import org.gradle.api.provider.Provider;
1714

1815
/// [Project][org.gradle.api.Project]-specific additions for the Minecraft extension. These will be accessible from the
1916
/// `minecraft` DSL object within your project's buildscript.
@@ -28,7 +25,26 @@ public interface MinecraftExtensionForProject extends MinecraftExtension, Minecr
2825
/// @return The dependency
2926
/// @see <a href="https://docs.gradle.org/current/userguide/declaring_dependencies.html">Declaring Dependencies
3027
/// in Gradle</a>
31-
Provider<ExternalModuleDependency> dependency(
28+
default MavenizerInstance dependency(
29+
Object value,
30+
@DelegatesTo(ExternalModuleDependency.class)
31+
@ClosureParams(value = SimpleType.class, options = "net.minecraftforge.gradle.ClosureOwner.MinecraftDependency")
32+
Closure<?> closure
33+
) {
34+
return this.dependency("default", value, closure);
35+
}
36+
37+
/// Creates (or marks if existing) the given dependency as a Minecraft dependency and configures it with the given
38+
/// closure.
39+
///
40+
/// @param name The name to give the Mavenizer instance used to generate the dependency
41+
/// @param value The dependency
42+
/// @param closure The closure to configure the dependency with
43+
/// @return The dependency
44+
/// @see <a href="https://docs.gradle.org/current/userguide/declaring_dependencies.html">Declaring Dependencies
45+
/// in Gradle</a>
46+
MavenizerInstance dependency(
47+
String name,
3248
Object value,
3349
@DelegatesTo(ExternalModuleDependency.class)
3450
@ClosureParams(value = SimpleType.class, options = "net.minecraftforge.gradle.ClosureOwner.MinecraftDependency")
@@ -43,17 +59,56 @@ Provider<ExternalModuleDependency> dependency(
4359
/// @return The dependency
4460
/// @see <a href="https://docs.gradle.org/current/userguide/declaring_dependencies.html">Declaring Dependencies
4561
/// in Gradle</a>
46-
default Provider<ExternalModuleDependency> dependency(Object value, Action<? super ClosureOwner.MinecraftDependency> action) {
47-
return this.dependency(value, Closures.action(this, action));
62+
default MavenizerInstance dependency(Object value, Action<? super ClosureOwner.MinecraftDependency> action) {
63+
return this.dependency("default", value, action);
64+
}
65+
66+
/// Creates (or marks if existing) the given dependency as a Minecraft dependency and applies the given action to
67+
/// it.
68+
///
69+
/// @param name The name to give the Mavenizer instance used to generate the dependency
70+
/// @param value The dependency
71+
/// @param action The action to apply to the dependency attributes
72+
/// @return The dependency
73+
/// @see <a href="https://docs.gradle.org/current/userguide/declaring_dependencies.html">Declaring Dependencies
74+
/// in Gradle</a>
75+
default MavenizerInstance dependency(String name, Object value, Action<? super ClosureOwner.MinecraftDependency> action) {
76+
return this.dependency(name, value, Closures.action(this, action));
77+
}
78+
79+
/// Creates (or marks if existing) the given dependency as a Minecraft dependency.
80+
///
81+
/// @param value The dependency
82+
/// @return The dependency
83+
/// @see <a href="https://docs.gradle.org/current/userguide/declaring_dependencies.html">Declaring Dependencies
84+
/// in Gradle</a>
85+
default MavenizerInstance dependency(Object value) {
86+
return this.dependency("default", value);
4887
}
4988

5089
/// Creates (or marks if existing) the given dependency as a Minecraft dependency.
5190
///
91+
/// @param name The name to give the Mavenizer instance used to generate the dependency
5292
/// @param value The dependency
5393
/// @return The dependency
5494
/// @see <a href="https://docs.gradle.org/current/userguide/declaring_dependencies.html">Declaring Dependencies
5595
/// in Gradle</a>
56-
default Provider<ExternalModuleDependency> dependency(Object value) {
57-
return this.dependency(value, Closures.empty(this));
96+
default MavenizerInstance dependency(String name, Object value) {
97+
return this.dependency(name, value, Closures.empty(this));
5898
}
99+
100+
/// Gets the default Minecraft dependency that was created using one of the [#dependency] methods.
101+
///
102+
/// @return The default Minecraft dependency
103+
/// @throws java.util.NoSuchElementException If the default Minecraft dependency has not yet been created.
104+
/// @see #getDependency(String)
105+
default MavenizerInstance getDependency() {
106+
return this.getDependency("default");
107+
}
108+
109+
/// Gets the named Minecraft dependency that was created using one of the [#dependency] methods.
110+
///
111+
/// @return The default Minecraft dependency
112+
/// @throws java.util.NoSuchElementException If the named Minecraft dependency has not yet been created.
113+
MavenizerInstance getDependency(String name);
59114
}

src/main/java/net/minecraftforge/gradle/internal/Constants.java

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,6 @@ final class Constants {
1111
static final String FORGE_MAVEN = "https://maven.minecraftforge.net/";
1212
static final String MC_LIBS_MAVEN = "https://libraries.minecraft.net/";
1313

14-
static final String SLIMELAUNCHER_NAME = "slimelauncher";
15-
static final String SLIMELAUNCHER_VERSION = "0.1.6";
16-
static final String SLIMELAUNCHER_DL_URL = "https://maven.minecraftforge.net/net/minecraftforge/slime-launcher/" + SLIMELAUNCHER_VERSION + "/slime-launcher-" + SLIMELAUNCHER_VERSION + ".jar";
17-
static final int SLIMELAUNCHER_JAVA_VERSION = 8;
18-
static final String SLIMELAUNCHER_MAIN = "net.minecraftforge.launcher.Main";
19-
20-
static final String MAVENIZER_NAME = "mavenizer";
21-
static final String MAVENIZER_VERSION = "0.4.24";
22-
static final String MAVENIZER_DL_URL = "https://maven.minecraftforge.net/net/minecraftforge/minecraft-mavenizer/" + MAVENIZER_VERSION + "/minecraft-mavenizer-" + MAVENIZER_VERSION + ".jar";
23-
static final int MAVENIZER_JAVA_VERSION = 25;
24-
static final String MAVENIZER_MAIN = "net.minecraftforge.mcmaven.cli.Main";
25-
2614
/// Use these with [java.text.MessageFormat#format(String, Object...)].
2715
static final class Messages {
2816
static final String WELCOME = """

src/main/java/net/minecraftforge/gradle/internal/ForgeGradleProblems.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import javax.inject.Inject;
1818
import java.io.File;
19+
import java.util.NoSuchElementException;
1920

2021
import static net.minecraftforge.gradle.internal.ForgeGradlePlugin.LOGGER;
2122

@@ -213,6 +214,33 @@ void reportForgeMavenNotDeclared() {
213214
.solution(HELP_MESSAGE)
214215
);
215216
}
217+
218+
void reportDuplicateMavenizerNames(String name) {
219+
this.report("mavenizer-instance-duplicate-name", "Duplicate Minecraft dependencies registered", spec -> spec
220+
.details("""
221+
A Minecraft dependency was declared with a name already in use!
222+
In order to manage access to mapping data each deobfuscated dependency needs to have a unique name.
223+
Call the `minecraft.dependency` method with a unique name as the first parameter, the default when not specified is `default`
224+
Name used: %s"""
225+
.formatted(name))
226+
.severity(Severity.WARNING)
227+
.solution("Call `minecraft.dependency` method with a unique name as the first parameter.")
228+
.solution(HELP_MESSAGE)
229+
);
230+
}
231+
232+
RuntimeException mavenizerInstanceNotFound(NoSuchElementException e, String name) {
233+
return this.throwing(e, "mavenizer-instance-not-found", "Minecraft dependency instance not found", spec -> spec
234+
.details("""
235+
A Minecraft dependency instance was requested but not found!
236+
The Minecraft dependency must be declared using `minecraft.dependency` first before it can be referenced.
237+
Name requested: %s"""
238+
.formatted(name))
239+
.severity(Severity.ERROR)
240+
.solution("Call `minecraft.dependency` method before getting it using `minecraft.getDependency()`.")
241+
.solution(HELP_MESSAGE)
242+
);
243+
}
216244
//endregion
217245
//endregion
218246

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright (c) Forge Development LLC and contributors
3+
* SPDX-License-Identifier: LGPL-2.1-only
4+
*/
5+
package net.minecraftforge.gradle.internal;
6+
7+
import groovy.json.JsonSlurper;
8+
import net.minecraftforge.gradle.MavenizerInstance;
9+
import org.gradle.api.Transformer;
10+
import org.gradle.api.artifacts.ExternalModuleDependency;
11+
import org.gradle.api.provider.MapProperty;
12+
import org.gradle.api.provider.Provider;
13+
import org.jspecify.annotations.Nullable;
14+
15+
import java.io.File;
16+
import java.util.Map;
17+
18+
class MavenizerInstanceImpl implements MavenizerInstance {
19+
private final MinecraftExtensionImpl.ForProjectImpl extension;
20+
private final Provider<Boolean> valueSource;
21+
private final ExternalModuleDependency dependency;
22+
private final File jsonFile;
23+
24+
private final MapProperty<String, String> invoke;
25+
private @Nullable Map<String, String> map;
26+
27+
MavenizerInstanceImpl(
28+
MinecraftExtensionImpl.ForProjectImpl extension,
29+
Provider<Boolean> valueSource,
30+
ExternalModuleDependency dependency,
31+
File jsonFile
32+
) {
33+
this.extension = extension;
34+
this.dependency = dependency;
35+
this.valueSource = valueSource;
36+
this.jsonFile = jsonFile;
37+
this.invoke = this.extension.getObjects().mapProperty(String.class, String.class)
38+
.convention(this.extension.getProviders().provider(this::invoke));
39+
}
40+
41+
@SuppressWarnings("unchecked")
42+
private Map<String, String> invoke() {
43+
if (this.map == null) {
44+
valueSource.get(); // Execute Mavenizer, probably called before, but just be sure.
45+
this.map = (Map<String, String>) new JsonSlurper().parse(this.jsonFile, "UTF-8");
46+
//this.map.forEach((k, v) -> this.extension.getProject().getLogger().lifecycle(k + " => " + v));
47+
}
48+
return this.map;
49+
}
50+
51+
private Provider<String> get(String key) {
52+
return this.invoke.getting(key)
53+
.orElse(this.extension.getProviders().provider(() -> {
54+
throw new IllegalStateException("Mavenizer did not output expected json data " + key);
55+
}));
56+
}
57+
58+
@Override
59+
public Provider<ExternalModuleDependency> asProvider() {
60+
return this.invoke.map(m -> this.dependency);
61+
}
62+
63+
@Override
64+
public Provider<String> getMappingVersion() {
65+
return get("mappings.version");
66+
}
67+
68+
@Override
69+
public Provider<String> getToSrg() {
70+
return get("mappings.srg.artifact");
71+
}
72+
73+
@Override
74+
public Provider<File> getToSrgFile() {
75+
return get("mappings.srg.file").map(this.extension.getProject()::file);
76+
}
77+
78+
@Override
79+
public Provider<String> getToObf() {
80+
return get("mappings.obf.artifact");
81+
}
82+
83+
@Override
84+
public Provider<File> getToObfFile() {
85+
return get("mappings.obf.file").map(this.extension.getProject()::file);
86+
}
87+
}

0 commit comments

Comments
 (0)