Skip to content

Commit 6f84558

Browse files
committed
Opt-in tool definition override for plugins
1 parent 2bb4c2f commit 6f84558

File tree

10 files changed

+288
-36
lines changed

10 files changed

+288
-36
lines changed

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

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,11 @@
1313
import org.gradle.api.initialization.Settings;
1414
import org.gradle.api.invocation.Gradle;
1515
import org.gradle.api.model.ObjectFactory;
16+
import org.gradle.api.plugins.ExtensionAware;
1617
import org.gradle.api.provider.Provider;
1718
import org.gradle.api.provider.ProviderFactory;
19+
import org.jetbrains.annotations.Nullable;
20+
import org.jetbrains.annotations.UnknownNullability;
1821

1922
import javax.inject.Inject;
2023
import java.io.File;
@@ -27,8 +30,10 @@
2730
public abstract class EnhancedPlugin<T> implements Plugin<T>, EnhancedPluginAdditions {
2831
private final String name;
2932
private final String displayName;
33+
private final @Nullable String toolsExtName;
3034

31-
private T target;
35+
private @UnknownNullability T target;
36+
private ToolsExtensionImpl tools;
3237
private final EnhancedProblems problemsInternal;
3338

3439
/// The object factory provided by Gradle services.
@@ -67,8 +72,20 @@ public abstract class EnhancedPlugin<T> implements Plugin<T>, EnhancedPluginAddi
6772
/// @param name The name for this plugin (must be machine-friendly)
6873
/// @param displayName The display name for this plugin
6974
protected EnhancedPlugin(String name, String displayName) {
75+
this(name, displayName, null);
76+
}
77+
78+
/// This constructor must be called by all subclasses using a public constructor annotated with [Inject]. The name
79+
/// and display name passed in are used in a minimal instance of [EnhancedProblems], which is used to set up the
80+
/// plugin's [global][#globalCaches()] and [local][#localCaches()] caches. Additionally, the name is used to
81+
/// create the cache folders (`minecraftforge/name`).
82+
///
83+
/// @param name The name for this plugin (must be machine-friendly)
84+
/// @param displayName The display name for this plugin
85+
protected EnhancedPlugin(String name, String displayName, @Nullable String toolsExtName) {
7086
this.name = name;
7187
this.displayName = displayName;
88+
this.toolsExtName = toolsExtName;
7289

7390
this.problemsInternal = this.getObjects().newInstance(EnhancedProblems.Minimal.class, name, displayName);
7491
}
@@ -79,6 +96,11 @@ protected EnhancedPlugin(String name, String displayName) {
7996
@Override
8097
public final void apply(T target) {
8198
this.setup(this.target = target);
99+
100+
if (this.toolsExtName != null && target instanceof ExtensionAware)
101+
this.tools = ((ExtensionAware) target).getExtensions().create(this.toolsExtName, ToolsExtensionImpl.class);
102+
else
103+
this.tools = this.getObjects().newInstance(ToolsExtensionImpl.class);
82104
}
83105

84106
/// Called when this plugin is applied to do setup work.
@@ -106,10 +128,9 @@ final EnhancedProblems getProblemsInternal() {
106128

107129
/* TOOLS */
108130

109-
@SuppressWarnings("deprecation") // deprecation intentional, please use this method
110131
@Override
111-
public Provider<File> getTool(Tool tool) {
112-
return tool.get(this.globalCaches(), this.getProviders());
132+
public Tool.Resolved getTool(Tool tool) {
133+
return ((ToolInternal) tool).get(this.globalCaches(), this.tools);
113134
}
114135

115136

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public interface EnhancedPluginAdditions {
1717
///
1818
/// @param tool The tool to get
1919
/// @return A provider for the tool file
20-
Provider<File> getTool(Tool tool);
20+
Tool.Resolved getTool(Tool tool);
2121

2222
/// Gets the global caches to be used for this plugin. These caches persist between projects and should be used to
2323
/// eliminate excess work done by projects that request the same data.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public interface EnhancedTask extends Task, EnhancedPluginAdditions {
3434
}
3535

3636
@Override
37-
default Provider<File> getTool(Tool tool) {
37+
default Tool.Resolved getTool(Tool tool) {
3838
return this.getPlugin().getTool(tool);
3939
}
4040

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

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@
44
*/
55
package net.minecraftforge.gradleutils.shared;
66

7+
import org.gradle.api.Action;
78
import org.gradle.api.Named;
8-
import org.gradle.api.file.Directory;
9+
import org.gradle.api.file.ConfigurableFileCollection;
10+
import org.gradle.api.file.FileCollection;
11+
import org.gradle.api.provider.Property;
912
import org.gradle.api.provider.Provider;
10-
import org.gradle.api.provider.ProviderFactory;
13+
import org.gradle.jvm.toolchain.JavaLauncher;
14+
import org.jetbrains.annotations.ApiStatus;
1115
import org.jetbrains.annotations.Nullable;
1216

1317
import java.io.File;
@@ -64,21 +68,47 @@ static Tool of(String name, String version, String downloadUrl, int javaVersion)
6468
/// @return The main class, or `null` if unspecified
6569
@Nullable String getMainClass();
6670

67-
/// Gets this tool and returns a provider for the downloaded/cached file.
71+
/// If this tool has a strictly defined main class. Can be `false`, but does not necessarily mean that this tools is
72+
/// not executable.
6873
///
69-
/// @param cachesDir The caches directory to store the downloaded tool in
70-
/// @param providers The provider factory for creating the provider
71-
/// @return The provider to the tool file
72-
/// @deprecated Use [EnhancedPlugin#getTool(Tool)]
73-
Provider<File> get(Provider<? extends Directory> cachesDir, ProviderFactory providers);
74+
/// @return If this tool has a main class
75+
default boolean hasMainClass() {
76+
return this.getMainClass() != null;
77+
}
7478

75-
/// Gets this tool and returns a provider for the downloaded/cached file.
76-
///
77-
/// @param cachesDir The caches directory to store the downloaded tool in
78-
/// @param providers The provider factory for creating the provider
79-
/// @return The provider to the tool file
80-
/// @deprecated Use [EnhancedPlugin#getTool(Tool)]
81-
default Provider<File> get(Directory cachesDir, ProviderFactory providers) {
82-
return this.get(providers.provider(() -> cachesDir), providers);
79+
@ApiStatus.Experimental
80+
interface Definition extends Named {
81+
/// Gets the classpath to use for the tool. If empty, the static default set by the plugin will be used.
82+
///
83+
/// @return The classpath
84+
/// @apiNote This is *not* the dependency's classpath. This is the classpath used in
85+
/// [org.gradle.process.JavaExecSpec#setClasspath(FileCollection)] to invoke AccessTransformers.
86+
ConfigurableFileCollection getClasspath();
87+
88+
/// Gets the main class to invoke when running AccessTransformers.
89+
///
90+
/// @return The property for the main class.
91+
/// @apiNote This is *not required* if the [classpath][#getClasspath()] is a single executable jar.
92+
Property<String> getMainClass();
93+
94+
/// Gets the Java launcher used to run AccessTransformers.
95+
///
96+
/// This can be easily acquired using [Java toolchains][org.gradle.jvm.toolchain.JavaToolchainService].
97+
///
98+
/// @return The property for the Java launcher
99+
/// @see org.gradle.jvm.toolchain.JavaToolchainService#launcherFor(Action)
100+
Property<JavaLauncher> getJavaLauncher();
101+
}
102+
103+
interface Resolved extends Tool {
104+
FileCollection getClasspath();
105+
106+
/// Gets the Java launcher used to run AccessTransformers.
107+
///
108+
/// This can be easily acquired using [Java toolchains][org.gradle.jvm.toolchain.JavaToolchainService].
109+
///
110+
/// @return The property for the Java launcher
111+
/// @see org.gradle.jvm.toolchain.JavaToolchainService#launcherFor(Action)
112+
Property<JavaLauncher> getJavaLauncher();
83113
}
84114
}

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

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,28 +53,32 @@ public abstract class ToolExecBase<P extends EnhancedProblems> extends JavaExec
5353
protected ToolExecBase(Class<P> problemsType, Tool tool) {
5454
this.problems = this.getObjectFactory().newInstance(problemsType);
5555

56+
Tool.Resolved resolved;
5657
if (this instanceof EnhancedTask) {
58+
resolved = ((EnhancedTask) this).getTool(tool);
5759
this.defaultToolDir = this.getObjectFactory().directoryProperty().value(
5860
((EnhancedTask) this).globalCaches().dir(tool.getName().toLowerCase(Locale.ENGLISH)).map(this.ensureFileLocationInternal())
5961
);
60-
this.setClasspath(this.getObjectFactory().fileCollection().from(((EnhancedTask) this).getTool(tool)));
6162
} else {
6263
this.getProject().afterEvaluate(project -> this.getProblems().reportToolExecNotEnhanced(this));
64+
resolved = ((ToolInternal) tool).get(
65+
this.getProjectLayout().getBuildDirectory().dir("minecraftforge/tools/" + tool.getName().toLowerCase(Locale.ENGLISH)).map(this.ensureFileLocationInternal()),
66+
this.getObjectFactory().newInstance(ToolsExtensionImpl.class)
67+
);
6368

6469
this.defaultToolDir = this.getObjectFactory().directoryProperty().value(
6570
this.getProjectLayout().getBuildDirectory().dir(String.format("minecraftforge/tools/%s/workDir", tool.getName().toLowerCase(Locale.ENGLISH))).map(this.ensureFileLocationInternal())
6671
);
67-
this.setClasspath(this.getObjectFactory().fileCollection().from(tool.get(
68-
this.getProjectLayout().getBuildDirectory().dir("minecraftforge/tools/" + tool.getName().toLowerCase(Locale.ENGLISH)).map(this.ensureFileLocationInternal()),
69-
this.getProviderFactory()
70-
)));
7172
}
7273

74+
this.setClasspath(resolved.getClasspath());
75+
7376
this.defaultToolDir.disallowChanges();
7477
this.defaultToolDir.finalizeValueOnRead();
7578

76-
this.getMainClass().set(Objects.requireNonNull(tool.getMainClass(), "Tool must have a main class"));
77-
this.getJavaLauncher().set(SharedUtil.launcherForStrictly(this.getJavaToolchainService(), tool.getJavaVersion()));
79+
if (resolved.hasMainClass())
80+
this.getMainClass().set(resolved.getMainClass());
81+
this.getJavaLauncher().set(resolved.getJavaLauncher());
7882

7983
this.setStandardOutput(SharedUtil.toLog(this.getLogger()::lifecycle));
8084
this.setErrorOutput(SharedUtil.toLog(this.getLogger()::error));

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

Lines changed: 65 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,23 @@
77
import net.minecraftforge.util.download.DownloadUtils;
88
import net.minecraftforge.util.hash.HashStore;
99
import org.gradle.api.file.Directory;
10+
import org.gradle.api.file.FileCollection;
1011
import org.gradle.api.file.RegularFileProperty;
1112
import org.gradle.api.logging.Logger;
1213
import org.gradle.api.logging.Logging;
14+
import org.gradle.api.model.ObjectFactory;
1315
import org.gradle.api.provider.Property;
1416
import org.gradle.api.provider.Provider;
15-
import org.gradle.api.provider.ProviderFactory;
1617
import org.gradle.api.provider.ValueSource;
1718
import org.gradle.api.provider.ValueSourceParameters;
19+
import org.gradle.jvm.toolchain.JavaLauncher;
1820
import org.jetbrains.annotations.Nullable;
1921

2022
import javax.inject.Inject;
2123
import java.io.File;
2224
import java.io.IOException;
2325

24-
class ToolImpl implements Tool {
26+
class ToolImpl implements ToolInternal {
2527
private static final long serialVersionUID = -862411638019629688L;
2628

2729
private static final Logger LOGGER = Logging.getLogger(Tool.class);
@@ -67,11 +69,67 @@ public int getJavaVersion() {
6769
}
6870

6971
@Override
70-
public Provider<File> get(Provider<? extends Directory> cachesDir, ProviderFactory providers) {
71-
return providers.of(Source.class, spec -> spec.parameters(parameters -> {
72-
parameters.getInputFile().set(cachesDir.map(d -> d.file("tools/" + this.fileName)));
73-
parameters.getDownloadUrl().set(this.downloadUrl);
74-
}));
72+
public Tool.Resolved get(Provider<? extends Directory> cachesDir, ToolsExtensionImpl toolsExt) {
73+
Tool.Definition definition = toolsExt.definitions.maybeCreate(this.name);
74+
FileCollection classpath = definition.getClasspath();
75+
if (classpath.isEmpty()) {
76+
classpath = toolsExt.getObjects().fileCollection().from(
77+
toolsExt.getProviders().of(Source.class, spec -> spec.parameters(parameters -> {
78+
parameters.getInputFile().set(cachesDir.map(d -> d.file("tools/" + this.fileName)));
79+
parameters.getDownloadUrl().set(this.downloadUrl);
80+
}))
81+
);
82+
}
83+
84+
return new ResolvedImpl(
85+
toolsExt.getObjects(),
86+
classpath,
87+
definition.getMainClass().orElse(toolsExt.getProviders().provider(this::getMainClass)),
88+
definition.getJavaLauncher().orElse(SharedUtil.launcherForStrictly(toolsExt.getJavaToolchains(), this.getJavaVersion()))
89+
);
90+
}
91+
92+
@SuppressWarnings("serial")
93+
private class ResolvedImpl implements Tool.Resolved {
94+
private final FileCollection classpath;
95+
private final Property<String> mainClass;
96+
private final Property<JavaLauncher> javaLauncher;
97+
98+
private ResolvedImpl(ObjectFactory objects, FileCollection classpath, Provider<? extends String> mainClass, Provider<? extends JavaLauncher> javaLauncher) {
99+
this.classpath = classpath;
100+
this.mainClass = objects.property(String.class).value(mainClass);
101+
this.javaLauncher = objects.property(JavaLauncher.class).value(javaLauncher);
102+
}
103+
104+
@Override
105+
public FileCollection getClasspath() {
106+
return this.classpath;
107+
}
108+
109+
@Override
110+
public String getName() {
111+
return ToolImpl.this.getName();
112+
}
113+
114+
@Override
115+
public String getVersion() {
116+
return ToolImpl.this.getVersion();
117+
}
118+
119+
@Override
120+
public Property<JavaLauncher> getJavaLauncher() {
121+
return this.javaLauncher;
122+
}
123+
124+
@Override
125+
public int getJavaVersion() {
126+
return this.javaLauncher.get().getMetadata().getLanguageVersion().asInt();
127+
}
128+
129+
@Override
130+
public @Nullable String getMainClass() {
131+
return this.mainClass.getOrNull();
132+
}
75133
}
76134

77135
static abstract class Source implements ValueSource<File, Source.Parameters> {
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright (c) Forge Development LLC and contributors
3+
* SPDX-License-Identifier: LGPL-2.1-only
4+
*/
5+
package net.minecraftforge.gradleutils.shared;
6+
7+
import org.gradle.api.file.Directory;
8+
import org.gradle.api.provider.Provider;
9+
import org.gradle.api.reflect.HasPublicType;
10+
import org.gradle.api.reflect.TypeOf;
11+
12+
interface ToolInternal extends Tool, HasPublicType {
13+
@Override
14+
default TypeOf<?> getPublicType() {
15+
return TypeOf.typeOf(Tool.class);
16+
}
17+
18+
/// Gets this tool and returns a provider for the downloaded/cached file.
19+
///
20+
/// @param cachesDir The caches directory to store the downloaded tool in
21+
/// @param toolsExt The plugin's tools extension, which may contain overrides for the tool definition
22+
/// @return The provider to the tool file
23+
Tool.Resolved get(Provider<? extends Directory> cachesDir, ToolsExtensionImpl toolsExt);
24+
25+
/// Gets this tool and returns a provider for the downloaded/cached file.
26+
///
27+
/// @param cachesDir The caches directory to store the downloaded tool in
28+
/// @param toolsExt The plugin's tools extension, which may contain overrides for the tool definition
29+
/// @return The provider to the tool file
30+
default Tool.Resolved get(Directory cachesDir, ToolsExtensionImpl toolsExt) {
31+
return this.get(toolsExt.getProviders().provider(() -> cachesDir), toolsExt);
32+
}
33+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/*
2+
* Copyright (c) Forge Development LLC and contributors
3+
* SPDX-License-Identifier: LGPL-2.1-only
4+
*/
5+
package net.minecraftforge.gradleutils.shared;
6+
7+
import org.gradle.api.Action;
8+
import org.gradle.api.plugins.ExtensionAware;
9+
import org.jetbrains.annotations.ApiStatus;
10+
11+
@ApiStatus.Experimental
12+
public interface ToolsExtension extends ExtensionAware {
13+
void configure(String name, Action<? super Tool.Definition> action);
14+
}

0 commit comments

Comments
 (0)