Skip to content

Commit 62a86bb

Browse files
committed
GradleUtils Shared stricter impl details, Gradle 9, Java 17
Dedicated `#report` and `#throwing` in enhanced problems Add enhanced plugin #rootProjectDirectory Documentation and shit
1 parent 39fb771 commit 62a86bb

24 files changed

+364
-306
lines changed

build.gradle

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -29,31 +29,20 @@ java {
2929
withJavadocJar()
3030
}
3131

32-
configurations {
33-
// NOTE: If you are making a new Gradle plugin, do not copy this block!
34-
configureEach {
35-
resolutionStrategy.dependencySubstitution {
36-
// NOTE: We build this in this repo, but enforce the module using a dependency substitution
37-
// That way, new plugins can effectively copy this buildscript just without this section
38-
// The "shadowed" attribute is declared here since project dependencies do not read the published module file
39-
substitute module('net.minecraftforge:gradleutils-shared') using variant(project(':gradleutils-shared')) {
40-
attributes {
41-
attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling, Bundling.SHADOWED))
42-
}
43-
} because 'Project dependencies do not read the published module file, so the shadowed attribute is manually declared.'
44-
}
45-
}
46-
47-
// Applies the "Gradle Plugin API Version" attribute to configuration
48-
// This was added in Gradle 7, gives consumers useful errors if they are on an old version
49-
def applyGradleVersionAttribute = { Configuration configuration ->
50-
configuration.attributes {
51-
attribute(GradlePluginApiVersion.GRADLE_PLUGIN_API_VERSION_ATTRIBUTE, objects.named(GradlePluginApiVersion, gradleutils.unpack(libs.versions.gradle)))
52-
}
32+
gradleutils.pluginDevDefaults(configurations, libs.versions.gradle)
33+
34+
// NOTE: If you are making a new Gradle plugin, do not copy this block!
35+
configurations.configureEach {
36+
resolutionStrategy.dependencySubstitution {
37+
// NOTE: We build this in this repo, but enforce the module using a dependency substitution
38+
// That way, new plugins can effectively copy this buildscript just without this section
39+
// The "shadowed" attribute is declared here since project dependencies do not read the published module file
40+
substitute module('net.minecraftforge:gradleutils-shared') using variant(project(':gradleutils-shared')) {
41+
attributes {
42+
attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling, Bundling.SHADOWED))
43+
}
44+
} because 'Project dependencies do not read the published module file, so the shadowed attribute is manually declared.'
5345
}
54-
55-
named(JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME, applyGradleVersionAttribute)
56-
named(ShadowJavaPlugin.SHADOW_RUNTIME_ELEMENTS_CONFIGURATION_NAME, applyGradleVersionAttribute)
5746
}
5847

5948
dependencies {

gradleutils-shared/build.gradle

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@ plugins {
1313
alias libs.plugins.shadow
1414
}
1515

16-
gradleutils.displayName = 'Minecraft Forge Shared Plugin Base'
17-
description = 'The shared base used by all of Minecraft Forge\'s Gradle plugins'
16+
gradleutils.displayName = 'GradleUtils Shared'
17+
description = 'The shared base used by all of Forge\'s Gradle plugins.'
1818
base.archivesName = 'gradleutils-shared'
1919
group = 'net.minecraftforge'
2020
// version set by gitversion in settings.gradle
2121

2222
java {
23-
toolchain.languageVersion = JavaLanguageVersion.of(8)
23+
toolchain.languageVersion = JavaLanguageVersion.of(17)
2424
withSourcesJar()
2525
withJavadocJar()
2626
}
@@ -30,7 +30,7 @@ dependencies {
3030
compileOnly libs.nulls
3131

3232
// Gradle API
33-
compileOnly sharedLibs.gradle
33+
compileOnly libs.gradle
3434

3535
// Tools
3636
implementation sharedLibs.bundles.utils

gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/Closures.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.gradle.api.Action;
1212
import org.jetbrains.annotations.UnknownNullability;
1313

14+
import java.io.Serial;
1415
import java.util.concurrent.Callable;
1516
import java.util.function.Consumer;
1617
import java.util.function.Function;
@@ -61,13 +62,13 @@ public final class Closures {
6162

6263
@SuppressWarnings({"rawtypes", "unchecked"})
6364
private static <T> @UnknownNullability T invokeInternal(Closure closure, Object... object) {
64-
ClassLoader original = Thread.currentThread().getContextClassLoader();
65+
var original = Thread.currentThread().getContextClassLoader();
6566
Thread.currentThread().setContextClassLoader(closure.getClass().getClassLoader());
6667
try {
67-
Object ret = closure.getMaximumNumberOfParameters() == 0 ? closure.call() : closure.call(object);
68+
var ret = closure.getMaximumNumberOfParameters() == 0 ? closure.call() : closure.call(object);
6869
return ret != null ? (T) ret : null;
6970
} catch (InvokerInvocationException e) {
70-
Throwable cause = e.getCause();
71+
var cause = e.getCause();
7172
throw cause instanceof RuntimeException ? (RuntimeException) cause : e;
7273
} finally {
7374
Thread.currentThread().setContextClassLoader(original);
@@ -248,7 +249,7 @@ public static Closure<Void> empty(Object owner) {
248249
}
249250

250251
private static final class Functional<T, R> extends Closure<R> {
251-
private static final long serialVersionUID = -8736820647200105725L;
252+
private static final @Serial long serialVersionUID = -8736820647200105725L;
252253

253254
private final Function<? super T, ? extends R> function;
254255

@@ -264,7 +265,7 @@ public R doCall(T object) {
264265
}
265266

266267
private static final class Supplying<R> extends Closure<R> {
267-
private static final long serialVersionUID = 1281109313872080614L;
268+
private static final @Serial long serialVersionUID = 1281109313872080614L;
268269

269270
private final Callable<? extends R> supplier;
270271

@@ -280,7 +281,7 @@ public R doCall() throws Exception {
280281
}
281282

282283
private static final class Consuming<T> extends Closure<Void> {
283-
private static final long serialVersionUID = 1165200476195312981L;
284+
private static final @Serial long serialVersionUID = 1165200476195312981L;
284285

285286
private final Consumer<? super T> consumer;
286287

@@ -297,7 +298,7 @@ public Void doCall(T object) {
297298
}
298299

299300
private static final class Running extends Empty {
300-
private static final long serialVersionUID = -3453835628821302135L;
301+
private static final @Serial long serialVersionUID = -3453835628821302135L;
301302

302303
private final Runnable runnable;
303304

@@ -314,7 +315,7 @@ public Void doCall() {
314315
}
315316

316317
private static class Empty extends Closure<Void> {
317-
private static final long serialVersionUID = 6072707343050307552L;
318+
private static final @Serial long serialVersionUID = 6072707343050307552L;
318319

319320
private Empty(Object owner) {
320321
super(owner, owner);

gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/EnhancedFlowAction.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ protected EnhancedFlowAction() { }
8080
/// @param s The string to match for (ignoring case)
8181
/// @return If the throwable's message contains the string
8282
protected static boolean contains(Throwable e, String s) {
83-
for (Throwable cause = e; cause != null; cause = cause.getCause()) {
83+
for (var cause = e; cause != null; cause = cause.getCause()) {
8484
if (StringGroovyMethods.containsIgnoreCase(s, cause.getMessage()))
8585
return true;
8686
}
@@ -99,7 +99,7 @@ public final void execute(P parameters) {
9999
this.run(parameters);
100100
} catch (Exception e) {
101101
// wrapping in this exception will prevent gradle from eating the stacktrace
102-
throw new RuntimeException(e);
102+
throw e instanceof RuntimeException rte ? rte : new RuntimeException(e);
103103
}
104104
}
105105

gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/EnhancedPlugin.java

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
/// needing to duplicate code across projects.
3030
///
3131
/// @param <T> The type of target
32-
public abstract class EnhancedPlugin<T> implements Plugin<T>, EnhancedPluginAdditions {
32+
public non-sealed abstract class EnhancedPlugin<T> implements Plugin<T>, EnhancedPluginAdditions {
3333
private final String name;
3434
private final String displayName;
3535
private final @Nullable String toolsExtName;
@@ -87,8 +87,9 @@ protected EnhancedPlugin(String name, String displayName) {
8787
/// plugin's [global][#globalCaches()] and [local][#localCaches()] caches. Additionally, the name is used to
8888
/// create the cache folders (`minecraftforge/name`).
8989
///
90-
/// @param name The name for this plugin (must be machine-friendly)
91-
/// @param displayName The display name for this plugin
90+
/// @param name The name for this plugin (must be machine-friendly)
91+
/// @param displayName The display name for this plugin
92+
/// @param toolsExtName The name for the tools extension to used, or `null` if it should not be created
9293
protected EnhancedPlugin(String name, String displayName, @Nullable String toolsExtName) {
9394
this.name = name;
9495
this.displayName = displayName;
@@ -104,8 +105,8 @@ protected EnhancedPlugin(String name, String displayName, @Nullable String tools
104105
public final void apply(T target) {
105106
this.setup(this.target = target);
106107

107-
if (this.toolsExtName != null && target instanceof ExtensionAware)
108-
this.tools = ((ExtensionAware) target).getExtensions().create(this.toolsExtName, ToolsExtensionImpl.class, (Callable<? extends JavaToolchainService>) this::toolchainsForTools);
108+
if (this.toolsExtName != null && target instanceof ExtensionAware extensionAware)
109+
this.tools = extensionAware.getExtensions().create(this.toolsExtName, ToolsExtensionImpl.class, (Callable<? extends JavaToolchainService>) this::toolchainsForTools);
109110
// else
110111
// this.tools = this.getObjects().newInstance(ToolsExtensionImpl.class, (Callable<? extends JavaToolchainService>) this::toolchainsForTools);
111112
}
@@ -164,8 +165,8 @@ public final DirectoryProperty globalCaches() {
164165

165166
private DirectoryProperty makeGlobalCaches() {
166167
try {
167-
Gradle gradle = ((Gradle) InvokerHelper.getProperty(this.target, "gradle"));
168-
DirectoryProperty gradleUserHomeDir = this.getObjects().directoryProperty().fileValue(gradle.getGradleUserHomeDir());
168+
var gradle = ((Gradle) InvokerHelper.getProperty(this.target, "gradle"));
169+
var gradleUserHomeDir = this.getObjects().directoryProperty().fileValue(gradle.getGradleUserHomeDir());
169170

170171
return this.getObjects().directoryProperty().convention(
171172
gradleUserHomeDir.dir("caches/minecraftforge/" + this.name).map(this.problemsInternal.ensureFileLocation())
@@ -207,6 +208,32 @@ private DirectoryProperty makeLocalCaches() {
207208
}
208209
}
209210

211+
private final Lazy<DirectoryProperty> rootProjectDirectory = Lazy.simple(this::makeRootProjectDirectory);
212+
213+
@Override
214+
public final DirectoryProperty rootProjectDirectory() {
215+
return this.rootProjectDirectory.get();
216+
}
217+
218+
private DirectoryProperty makeRootProjectDirectory() {
219+
var target = this.getTarget();
220+
try {
221+
var rootProjectDirectory = this.getObjects().directoryProperty();
222+
if (target instanceof Project project) {
223+
return rootProjectDirectory.value(project.getRootProject().getLayout().getProjectDirectory());
224+
} else if (target instanceof Settings) {
225+
return rootProjectDirectory.value(this.getBuildLayout().getRootDirectory());
226+
} else {
227+
throw new IllegalStateException("Cannot get root project directory with an unsupported type (must be project or settings)");
228+
}
229+
} catch (Exception e) {
230+
throw this.problemsInternal.illegalPluginTarget(
231+
new IllegalArgumentException("Failed to get %s root project directory for target: %s".formatted(this.displayName, target), e),
232+
Project.class, Settings.class
233+
);
234+
}
235+
}
236+
210237
private final Lazy<DirectoryProperty> workingProjectDirectory = Lazy.simple(this::makeWorkingProjectDirectory);
211238

212239
@Override
@@ -215,18 +242,19 @@ public final DirectoryProperty workingProjectDirectory() {
215242
}
216243

217244
private DirectoryProperty makeWorkingProjectDirectory() {
245+
var target = this.getTarget();
218246
try {
219-
DirectoryProperty workingProjectDirectory = this.getObjects().directoryProperty();
220-
if (this.target instanceof Project) {
247+
var workingProjectDirectory = this.getObjects().directoryProperty();
248+
if (target instanceof Project) {
221249
return workingProjectDirectory.value(this.getProjectLayout().getProjectDirectory());
222-
} else if (this.target instanceof Settings) {
250+
} else if (target instanceof Settings) {
223251
return workingProjectDirectory.value(this.getBuildLayout().getRootDirectory());
224252
} else {
225253
throw new IllegalStateException("Cannot get working project directory with an unsupported type (must be project or settings)");
226254
}
227255
} catch (Exception e) {
228256
throw this.problemsInternal.illegalPluginTarget(
229-
new IllegalArgumentException(String.format("Failed to get %s working project directory for target: %s", this.displayName, this.getTarget()), e),
257+
new IllegalArgumentException("Failed to get %s working project directory for target: %s".formatted(this.displayName, target), e),
230258
Project.class, Settings.class
231259
);
232260
}

gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/EnhancedPluginAdditions.java

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,10 @@
55
package net.minecraftforge.gradleutils.shared;
66

77
import org.gradle.api.file.DirectoryProperty;
8-
import org.gradle.api.provider.Provider;
9-
10-
import java.io.File;
118

129
/// This interface defines the additional methods added by [EnhancedPlugin]. They are additionally accessible in tasks
1310
/// that implement [EnhancedTask].
14-
public interface EnhancedPluginAdditions {
11+
public sealed interface EnhancedPluginAdditions permits EnhancedPlugin, EnhancedTask {
1512
/// Gets a provider to the file for a [Tool] to be used. The tool's state is managed by Gradle through the
1613
/// [org.gradle.api.provider.ValueSource] API and will not cause caching issues.
1714
///
@@ -35,16 +32,28 @@ public interface EnhancedPluginAdditions {
3532
/// It is located in `project/build/minecraftforge/plugin`.
3633
///
3734
/// @return The global caches
38-
/// @throws RuntimeException If this plugin cannot access global caches (i.e. the target is not
35+
/// @throws RuntimeException If this plugin cannot access local caches (i.e. the target is not
3936
/// [org.gradle.api.Project] or [org.gradle.api.initialization.Settings])
4037
DirectoryProperty localCaches();
4138

42-
/// Gets the working project directory to be used for this plugin. This directory is either the
43-
/// [org.gradle.api.file.ProjectLayout#getProjectDirectory()] of the [org.gradle.api.Project] or the
44-
/// [org.gradle.api.file.BuildLayout#getRootDirectory()] of the [org.gradle.api.initialization.Settings]. Attempting
45-
/// to call this when the plugin target is not either type will throw an exception.
39+
/// Gets the root project directory to be used for this plugin.
4640
///
47-
/// It is located in `project/build/minecraftforge/plugin`.
41+
/// This directory is either the [org.gradle.api.file.ProjectLayout#getProjectDirectory()] of
42+
/// [org.gradle.api.Project#getRootProject()] or the [org.gradle.api.file.BuildLayout#getRootDirectory()] of the
43+
/// [org.gradle.api.initialization.Settings]. Attempting to call this when the plugin target is neither type will
44+
/// throw an exception.
45+
///
46+
/// @return The root project directory
47+
/// @throws RuntimeException If this plugin cannot access the root project directory (i.e. the target is not
48+
/// [org.gradle.api.Project] or [org.gradle.api.initialization.Settings])
49+
DirectoryProperty rootProjectDirectory();
50+
51+
/// Gets the working project directory to be used for this plugin.
52+
///
53+
/// This directory is either the [org.gradle.api.file.ProjectLayout#getProjectDirectory()] of the
54+
/// [org.gradle.api.Project] or the [org.gradle.api.file.BuildLayout#getRootDirectory()] of the
55+
/// [org.gradle.api.initialization.Settings]. Attempting to call this when the plugin target is neither type will
56+
/// throw an exception.
4857
///
4958
/// @return The working project directory
5059
/// @throws RuntimeException If this plugin cannot access the working project directory (i.e. the target is not

0 commit comments

Comments
 (0)