diff --git a/src/main/java/net/minecraftforge/gradle/MinecraftExtensionForProject.java b/src/main/java/net/minecraftforge/gradle/MinecraftExtensionForProject.java
index ae942d764..116258821 100644
--- a/src/main/java/net/minecraftforge/gradle/MinecraftExtensionForProject.java
+++ b/src/main/java/net/minecraftforge/gradle/MinecraftExtensionForProject.java
@@ -13,6 +13,7 @@
import org.gradle.api.Action;
import org.gradle.api.NamedDomainObjectContainer;
import org.gradle.api.artifacts.ExternalModuleDependency;
+import org.gradle.api.provider.Provider;
/// [Project][org.gradle.api.Project]-specific additions for the Minecraft extension. These will be accessible from the
/// `minecraft` DSL object within your project's buildscript.
@@ -27,7 +28,7 @@ public interface MinecraftExtensionForProject extends MinecraftExtension, Minecr
/// @return The dependency
/// @see Declaring Dependencies
/// in Gradle
- ExternalModuleDependency dependency(
+ Provider dependency(
Object value,
@DelegatesTo(ExternalModuleDependency.class)
@ClosureParams(value = SimpleType.class, options = "net.minecraftforge.gradle.ClosureOwner.MinecraftDependency")
@@ -42,7 +43,7 @@ ExternalModuleDependency dependency(
/// @return The dependency
/// @see Declaring Dependencies
/// in Gradle
- default ExternalModuleDependency dependency(Object value, Action super ClosureOwner.MinecraftDependency> action) {
+ default Provider dependency(Object value, Action super ClosureOwner.MinecraftDependency> action) {
return this.dependency(value, Closures.action(this, action));
}
@@ -52,7 +53,7 @@ default ExternalModuleDependency dependency(Object value, Action super Closure
/// @return The dependency
/// @see Declaring Dependencies
/// in Gradle
- default ExternalModuleDependency dependency(Object value) {
+ default Provider dependency(Object value) {
return this.dependency(value, Closures.empty(this));
}
}
diff --git a/src/main/java/net/minecraftforge/gradle/internal/Constants.java b/src/main/java/net/minecraftforge/gradle/internal/Constants.java
index 40c8c5e29..0ce575537 100644
--- a/src/main/java/net/minecraftforge/gradle/internal/Constants.java
+++ b/src/main/java/net/minecraftforge/gradle/internal/Constants.java
@@ -18,7 +18,7 @@ final class Constants {
static final String SLIMELAUNCHER_MAIN = "net.minecraftforge.launcher.Main";
static final String MAVENIZER_NAME = "mavenizer";
- static final String MAVENIZER_VERSION = "0.4.19";
+ static final String MAVENIZER_VERSION = "0.4.20";
static final String MAVENIZER_DL_URL = "https://maven.minecraftforge.net/net/minecraftforge/minecraft-mavenizer/" + MAVENIZER_VERSION + "/minecraft-mavenizer-" + MAVENIZER_VERSION + ".jar";
static final int MAVENIZER_JAVA_VERSION = 25;
static final String MAVENIZER_MAIN = "net.minecraftforge.mcmaven.cli.Main";
diff --git a/src/main/java/net/minecraftforge/gradle/internal/ForgeGradleProblems.java b/src/main/java/net/minecraftforge/gradle/internal/ForgeGradleProblems.java
index 5b55f3fe1..9478dc8ca 100644
--- a/src/main/java/net/minecraftforge/gradle/internal/ForgeGradleProblems.java
+++ b/src/main/java/net/minecraftforge/gradle/internal/ForgeGradleProblems.java
@@ -140,7 +140,6 @@ void mavenizerOutOfDate(boolean throwIt, Object dependency) {
.severity(Severity.ERROR)
.solution("Re-import your project in your IDE, as this will automatically synchronize the Mavenizer.")
.solution("Run `gradlew` with no arguments, as this will automatically synchronize the Mavenizer.")
- .solution("Manually run the `syncMavenizer` task, located in the 'Build Setup' group.")
.solution("Temporary revert any edits to the Minecraft dependency until the Mavenizer is re-run.")
.solution(HELP_MESSAGE);
diff --git a/src/main/java/net/minecraftforge/gradle/internal/MavenizerValueSource.java b/src/main/java/net/minecraftforge/gradle/internal/MavenizerValueSource.java
new file mode 100644
index 000000000..68253d906
--- /dev/null
+++ b/src/main/java/net/minecraftforge/gradle/internal/MavenizerValueSource.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) Forge Development LLC and contributors
+ * SPDX-License-Identifier: LGPL-2.1-only
+ */
+package net.minecraftforge.gradle.internal;
+
+import org.gradle.api.file.ConfigurableFileCollection;
+import org.gradle.api.file.RegularFileProperty;
+import org.gradle.api.provider.ListProperty;
+import org.gradle.api.provider.ValueSource;
+import org.gradle.api.provider.ValueSourceParameters;
+import org.gradle.process.ExecOperations;
+import org.jspecify.annotations.Nullable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+
+abstract class MavenizerValueSource implements ValueSource {
+ interface Parameters extends ValueSourceParameters {
+ ConfigurableFileCollection getClasspath();
+ RegularFileProperty getJavaLauncher();
+ ListProperty getArguments();
+ }
+
+ private final ExecOperations execOps;
+ private final static Logger logger = LoggerFactory.getLogger(MavenizerValueSource.class);
+
+ @Inject
+ public MavenizerValueSource(ExecOperations execOps) {
+ this.execOps = execOps;
+ }
+
+ private void log(String line) {
+ logger.info(line);
+ }
+
+ @Override
+ @Nullable
+ public Boolean obtain() {
+ this.execOps.javaexec(spec -> {
+ var params = this.getParameters();
+ spec.setClasspath(params.getClasspath());
+ spec.setExecutable(params.getJavaLauncher().get());
+ spec.setArgs(params.getArguments().get());
+
+ log("Executing Mavenizer: ");
+ var itr = params.getClasspath().iterator();
+ log(" Classpath: " + itr.next().getAbsolutePath());
+ while (itr.hasNext())
+ log(" " + itr.next().getAbsolutePath());
+
+ log(" Java: " + params.getJavaLauncher().get().getAsFile().getAbsolutePath());
+ var args = params.getArguments().get();
+ var prefix = " Arguments: ";
+ for (int x = 0; x < args.size(); x++) {
+ var current = args.get(x);
+ var next = args.size() > x + 1 ? args.get(x + 1) : null;
+ var line = current;
+ if (current.startsWith("--") && next != null && !next.startsWith("--")) {
+ x++;
+ line += ' ' + next;
+ }
+ log(prefix + line);
+ prefix = " ";
+ }
+ }).assertNormalExitValue();
+ return false;
+ }
+}
diff --git a/src/main/java/net/minecraftforge/gradle/internal/MinecraftDependencyImpl.java b/src/main/java/net/minecraftforge/gradle/internal/MinecraftDependencyImpl.java
index 08ebab257..1a87ea9b6 100644
--- a/src/main/java/net/minecraftforge/gradle/internal/MinecraftDependencyImpl.java
+++ b/src/main/java/net/minecraftforge/gradle/internal/MinecraftDependencyImpl.java
@@ -10,7 +10,6 @@
import net.minecraftforge.gradle.MinecraftMappings;
import net.minecraftforge.gradle.SlimeLauncherOptions;
import net.minecraftforge.gradleutils.shared.Closures;
-import org.gradle.api.Action;
import org.gradle.api.InvalidUserCodeException;
import org.gradle.api.NamedDomainObjectContainer;
import org.gradle.api.NamedDomainObjectSet;
@@ -19,14 +18,10 @@
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.artifacts.ExternalModuleDependency;
import org.gradle.api.artifacts.ModuleIdentifier;
-import org.gradle.api.artifacts.type.ArtifactTypeDefinition;
-import org.gradle.api.attributes.Attribute;
-import org.gradle.api.attributes.AttributeContainer;
import org.gradle.api.file.ConfigurableFileCollection;
import org.gradle.api.file.Directory;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.file.ProjectLayout;
-import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.flow.FlowProviders;
import org.gradle.api.flow.FlowScope;
import org.gradle.api.model.ObjectFactory;
@@ -34,7 +29,6 @@
import org.gradle.api.provider.Property;
import org.gradle.api.provider.Provider;
import org.gradle.api.tasks.SourceSet;
-import org.gradle.api.tasks.TaskProvider;
import org.jspecify.annotations.Nullable;
import javax.inject.Inject;
@@ -44,7 +38,6 @@
abstract class MinecraftDependencyImpl implements MinecraftDependencyInternal {
// These can be nullable due to configuration caching.
private transient @Nullable ExternalModuleDependency delegate;
- private transient @Nullable TaskProvider mavenizer;
private transient @Nullable NamedDomainObjectContainer runs;
// Minecraft extension
@@ -129,12 +122,6 @@ private boolean hasAccessTransformers() {
return this.delegate;
}
- // Can be nullable due to configuration caching.
- @Override
- public @Nullable TaskProvider asTask() {
- return this.mavenizer;
- }
-
@Override
public ExternalModuleDependency init(Object dependencyNotation, Closure> closure) {
this.runs = getObjects().domainObjectContainer(SlimeLauncherOptionsImpl.class);
@@ -153,8 +140,6 @@ public ExternalModuleDependency init(Object dependencyNotation, Closure> closu
return module;
}));
- this.mavenizer = SyncMavenizer.register(getProject(), dependency, this.mappings, this.accessTransformer, mavenizerOutput);
-
this.asString.set(dependency.toString());
this.asPath.set(Util.pathify(dependency));
this.module.set(dependency.getModule());
@@ -190,10 +175,6 @@ public void handle(Configuration configuration) {
@Override
public void handle(NamedDomainObjectSet sourceSets, NamedDomainObjectSet allSourceSets) {
- allSourceSets.all(sourceSet ->
- getProject().getTasks().named(sourceSet.getTaskName("sync", "mavenizer"), task -> task.dependsOn(this.mavenizer))
- );
-
var asString = this.asString.get();
var dependencyOutput = this.mavenizerOutput.dir(this.asPath);
getFlowScope().always(ForgeGradleFlowAction.MavenizerSyncCheck.class, spec ->
@@ -221,6 +202,10 @@ public void handle(NamedDomainObjectSet sourceSets, NamedDomainObject
});
});
+ finalizeAccessTransformers(sourceSets);
+ }
+
+ void finalizeAccessTransformers(NamedDomainObjectSet sourceSets) {
if (this.accessTransformer.isEmpty() && !this.accessTransformerPath.isPresent()) {
this.accessTransformer.convention(minecraft.getAccessTransformer());
this.accessTransformerPath.convention(minecraft.getAccessTransformerPath());
diff --git a/src/main/java/net/minecraftforge/gradle/internal/MinecraftDependencyInternal.java b/src/main/java/net/minecraftforge/gradle/internal/MinecraftDependencyInternal.java
index bc664c0e1..3a0d9d2d8 100644
--- a/src/main/java/net/minecraftforge/gradle/internal/MinecraftDependencyInternal.java
+++ b/src/main/java/net/minecraftforge/gradle/internal/MinecraftDependencyInternal.java
@@ -55,9 +55,6 @@ static boolean is(Dependency dependency) {
// Can be nullable due to configuration caching.
@Nullable ExternalModuleDependency asDependency();
- // Can be nullable due to configuration caching.
- @Nullable TaskProvider asTask();
-
default Closure closure(Closure closure) {
return closure.rehydrate(closure.getDelegate(), new ClosureOwnerImpl.MinecraftDependencyImpl(closure.getOwner(), this), closure.getThisObject());
}
diff --git a/src/main/java/net/minecraftforge/gradle/internal/MinecraftExtensionImpl.java b/src/main/java/net/minecraftforge/gradle/internal/MinecraftExtensionImpl.java
index b4986fa25..343aa2da1 100644
--- a/src/main/java/net/minecraftforge/gradle/internal/MinecraftExtensionImpl.java
+++ b/src/main/java/net/minecraftforge/gradle/internal/MinecraftExtensionImpl.java
@@ -39,9 +39,12 @@
import org.gradle.api.plugins.ExtensionAware;
import org.gradle.api.plugins.JavaPluginExtension;
import org.gradle.api.provider.Property;
+import org.gradle.api.provider.Provider;
import org.gradle.api.provider.ProviderFactory;
import org.gradle.api.reflect.TypeOf;
import org.gradle.api.tasks.TaskProvider;
+import org.gradle.jvm.toolchain.JavaLauncher;
+import org.gradle.jvm.toolchain.JavaToolchainService;
import org.gradle.plugins.ide.eclipse.model.EclipseModel;
import org.jetbrains.annotations.UnmodifiableView;
import org.jspecify.annotations.Nullable;
@@ -50,17 +53,22 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Locale;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Collectors;
abstract class MinecraftExtensionImpl implements MinecraftExtensionInternal {
+ private static final String MAVENIZER_REPO_NAME = "MinecraftMavenizer";
+
private final DirectoryProperty mavenizerOutput = getObjects().directoryProperty();
private final Property mappings = getObjects().property(MinecraftMappingsInternal.class);
private final ForgeGradleProblems problems = getObjects().newInstance(ForgeGradleProblems.class);
+ protected final ForgeGradlePlugin plugin;
+
protected abstract @Inject ObjectFactory getObjects();
protected abstract @Inject ProviderFactory getProviders();
@@ -85,6 +93,7 @@ static void register(
@Inject
public MinecraftExtensionImpl(ForgeGradlePlugin plugin) {
+ this.plugin = plugin;
this.mavenizerOutput.convention(plugin.localCaches().dir("mavenizer/output").map(this.problems.ensureFileLocation()));
}
@@ -101,7 +110,7 @@ public DirectoryProperty getMavenizerOutput() {
@Override
public Action getMavenizer() {
return maven -> {
- maven.setName("MinecraftMavenizer");
+ maven.setName(MAVENIZER_REPO_NAME);
maven.setUrl(this.getMavenizerOutput());
};
}
@@ -306,26 +315,12 @@ private void finish(Project project) {
var sourceSetsDir = this.getObjects().directoryProperty().value(this.getProjectLayout().getBuildDirectory().dir("sourceSets"));
var mergeSourceSets = this.problems.test("net.minecraftforge.gradle.merge-source-sets");
sourceSets.all(sourceSet -> {
- var sourceSetName = sourceSet.getName();
- var syncMavenizer = Util.runFirst(project, project.getTasks().register(sourceSet.getTaskName("sync", "mavenizer"), task -> {
- task.setGroup("Build Setup");
- task.setDescription("Synchronizes the Mavenizer output for source set '" + sourceSetName + '.');
- }));
-
- try {
- project.getTasks().named(sourceSet.getCompileJavaTaskName(), task -> task.dependsOn(syncMavenizer));
- } catch (UnknownTaskException ignored) { }
-
if (mergeSourceSets) {
// This is documented in SourceSetOutput's javadoc comment
var unifiedDir = sourceSetsDir.dir(sourceSet.getName());
sourceSet.getOutput().setResourcesDir(unifiedDir);
sourceSet.getJava().getDestinationDirectory().set(unifiedDir);
}
-
- project.getPluginManager().withPlugin("eclipse", appliedPlugin ->
- project.getExtensions().configure(EclipseModel.class, eclipse -> eclipse.synchronizationTasks(syncMavenizer))
- );
});
project.getPluginManager().withPlugin("eclipse", eclipsePlugin -> {
@@ -375,8 +370,9 @@ public NamedDomainObjectContainer extends SlimeLauncherOptions> getRuns() {
return this.runs;
}
+ @SuppressWarnings({"UnstableApiUsage"})
@Override
- public ExternalModuleDependency dependency(
+ public Provider dependency(
Object value,
@DelegatesTo(ExternalModuleDependency.class)
@ClosureParams(value = SimpleType.class, options = "net.minecraftforge.gradle.MinecraftDependency.ClosureOwner")
@@ -389,7 +385,64 @@ public ExternalModuleDependency dependency(
var minecraftDependency = this.getObjects().newInstance(MinecraftDependencyImpl.class, this.getMavenizerOutput());
this.minecraftDependencies.add(minecraftDependency);
- return minecraftDependency.init(value, closure);
+ var dep = minecraftDependency.init(value, closure);
+ var mavenizer = this.getProviders().of(MavenizerValueSource.class, spec -> {
+ spec.parameters(params -> {
+ var tool = this.plugin.getTool(Tools.MAVENIZER);
+ params.getClasspath().setFrom(tool.getClasspath());
+ params.getJavaLauncher().set(tool.getJavaLauncher().map(JavaLauncher::getExecutablePath));
+ params.getArguments().set(this.getProviders().provider(() -> {
+ var toolCache = this.plugin.globalCaches()
+ .dir(tool.getName().toLowerCase(Locale.ENGLISH))
+ .map(this.problems.ensureFileLocation());
+ var cache = toolCache.get().dir("caches").getAsFile().getAbsolutePath();
+
+ var ret = new ArrayList();
+ ret.addAll(List.of(
+ "--maven",
+ "--cache", cache,
+ "--jdk-cache", cache,
+ "--output", this.getMavenizerOutput().get().getAsFile().getAbsolutePath(),
+ "--artifact", dep.getModule().toString(),
+ "--version", Objects.requireNonNull(dep.getVersion()),
+ "--global-auxiliary-variants"
+ ));
+
+ // If we are finding the access transformer from sourcesets, just find from any source set
+ // We can't filter by configurations becase the config cache doesn't like that.
+ // So if users fuck up, then we can output a warning, or they can manually set the AT file.
+ // This is a 'best effort'
+ var sourceSets = getProject().getExtensions().getByType(JavaPluginExtension.class).getSourceSets();
+ minecraftDependency.finalizeAccessTransformers(sourceSets);
+
+ for (var at : minecraftDependency.getAccessTransformer()) {
+ //System.out.println("Access Transformer: " + at);
+ ret.add("--access-transformer");
+ ret.add(at.getAbsolutePath());
+ }
+
+ var mappings = minecraftDependency.getMappings();
+ if ("parchment".equals(mappings.getChannel()))
+ ret.addAll(List.of("--parchment", mappings.getVersion()));
+
+ for (var repo : this.getRepositories()) {
+ if (MAVENIZER_REPO_NAME.equals(repo.getName()))
+ continue;
+ var url = repo.getUrl().toString();
+ if (!url.endsWith("/"))
+ url += '/';
+ ret.add("--repository");
+ ret.add(repo.getName() + ',' + url);
+ }
+ return ret;
+ }));
+ });
+ });
+
+ return this.getProviders().provider(() -> {
+ mavenizer.get();// Invoke mavenizer, it should be invoked already by gradle config cache, but Force it to be
+ return dep;
+ });
}
private void checkRepos(List extends MavenArtifactRepository> repos) {
diff --git a/src/main/java/net/minecraftforge/gradle/internal/SyncMavenizer.java b/src/main/java/net/minecraftforge/gradle/internal/SyncMavenizer.java
deleted file mode 100644
index 0decd8d94..000000000
--- a/src/main/java/net/minecraftforge/gradle/internal/SyncMavenizer.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (c) Forge Development LLC and contributors
- * SPDX-License-Identifier: LGPL-2.1-only
- */
-package net.minecraftforge.gradle.internal;
-
-import net.minecraftforge.gradle.MinecraftExtensionForProject;
-import net.minecraftforge.gradle.MinecraftMappings;
-import org.codehaus.groovy.runtime.StringGroovyMethods;
-import org.gradle.api.Project;
-import org.gradle.api.UnknownDomainObjectException;
-import org.gradle.api.artifacts.ExternalModuleDependency;
-import org.gradle.api.artifacts.ModuleIdentifier;
-import org.gradle.api.artifacts.repositories.MavenArtifactRepository;
-import org.gradle.api.file.ConfigurableFileCollection;
-import org.gradle.api.file.Directory;
-import org.gradle.api.file.DirectoryProperty;
-import org.gradle.api.file.RegularFile;
-import org.gradle.api.file.RegularFileProperty;
-import org.gradle.api.provider.ListProperty;
-import org.gradle.api.provider.Property;
-import org.gradle.api.provider.Provider;
-import org.gradle.api.tasks.Input;
-import org.gradle.api.tasks.InputFile;
-import org.gradle.api.tasks.InputFiles;
-import org.gradle.api.tasks.Internal;
-import org.gradle.api.tasks.Optional;
-import org.gradle.api.tasks.TaskProvider;
-import org.gradle.process.ExecResult;
-import org.gradle.work.DisableCachingByDefault;
-
-import javax.inject.Inject;
-import java.io.IOException;
-import java.util.List;
-
-@DisableCachingByDefault(because = "Mavenizer uses its own in-house caching")
-abstract class SyncMavenizer extends ToolExec {
- static TaskProvider register(Project project, ExternalModuleDependency dependency, Provider extends MinecraftMappings> mappings, ConfigurableFileCollection accessTransformer, Provider extends Directory> output) {
- var version = dependency.getVersion();
- var taskName = "syncMavenizerFor"
- + StringGroovyMethods.capitalize(dependency.getName())
- + (version == null ? "" : version.replace(".", "").replace('-', '_'));
-
- var tasks = project.getTasks();
- return tasks.getNames().contains(taskName)
- ? tasks.named(taskName, SyncMavenizer.class)
- : tasks.register(taskName, SyncMavenizer.class, task -> {
- task.getOutput().set(output);
- task.getModule().set(dependency.getModule());
- task.getVersion().set(dependency.getVersion());
- task.getMappings().set(mappings);
- task.getAccessTransformer().setFrom(accessTransformer);
- });
- }
-
- protected abstract @Internal DirectoryProperty getCaches();
-
- protected abstract @Internal DirectoryProperty getOutput();
-
- protected abstract @Input Property getModule();
-
- protected abstract @Input Property getVersion();
-
- protected abstract @Input Property getMappings();
-
- protected abstract @InputFiles @Optional ConfigurableFileCollection getAccessTransformer();
-
- protected abstract @Input @Optional ListProperty getRepositories();
-
- private void addRepositories(Iterable extends MavenArtifactRepository> repositories) {
- for (var repository : repositories) {
- if (repository.getName().equals("MinecraftMavenizer"))
- continue;
-
- String url;
- {
- var s = repository.getUrl().toString();
- if (!s.endsWith("/"))
- s += "/";
- url = s;
- }
-
- this.getRepositories().add(this.getProviders().provider(() -> repository.getName() + ',' + url));
- }
- }
-
- @Inject
- public SyncMavenizer() {
- super(Tools.MAVENIZER);
-
- this.getCaches().convention(this.defaultToolDir.dir("caches"));
-
- var minecraft = ((MinecraftExtensionInternal.ForProject) getProject().getExtensions().getByType(MinecraftExtensionForProject.class));
- this.addRepositories(minecraft.getRepositories());
- }
-
- @Override
- protected ExecResult exec() throws IOException {
- return super.exec().rethrowFailure().assertNormalExitValue();
- }
-
- @Override
- protected void addArguments() {
- super.addArguments();
-
- this.args("--maven");
- this.args("--cache", this.getCaches());
- this.args("--output", this.getOutput());
- this.args("--jdk-cache", this.getCaches());
- this.args("--artifact", this.getModule());
- this.args("--version", this.getVersion());
- this.args("--access-transformer", this.getAccessTransformer());
- this.args("--global-auxiliary-variants");
-
- if ("parchment".equals(this.getMappings().get().getChannel())) {
- this.args("--parchment", this.getMappings().get().getVersion());
- }
-
- for (var repository : this.getRepositories().getOrElse(List.of())) {
- this.args("--repository", repository);
- }
- }
-}