Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -27,7 +28,7 @@ public interface MinecraftExtensionForProject extends MinecraftExtension, Minecr
/// @return The dependency
/// @see <a href="https://docs.gradle.org/current/userguide/declaring_dependencies.html">Declaring Dependencies
/// in Gradle</a>
ExternalModuleDependency dependency(
Provider<ExternalModuleDependency> dependency(
Object value,
@DelegatesTo(ExternalModuleDependency.class)
@ClosureParams(value = SimpleType.class, options = "net.minecraftforge.gradle.ClosureOwner.MinecraftDependency")
Expand All @@ -42,7 +43,7 @@ ExternalModuleDependency dependency(
/// @return The dependency
/// @see <a href="https://docs.gradle.org/current/userguide/declaring_dependencies.html">Declaring Dependencies
/// in Gradle</a>
default ExternalModuleDependency dependency(Object value, Action<? super ClosureOwner.MinecraftDependency> action) {
default Provider<ExternalModuleDependency> dependency(Object value, Action<? super ClosureOwner.MinecraftDependency> action) {
return this.dependency(value, Closures.action(this, action));
}

Expand All @@ -52,7 +53,7 @@ default ExternalModuleDependency dependency(Object value, Action<? super Closure
/// @return The dependency
/// @see <a href="https://docs.gradle.org/current/userguide/declaring_dependencies.html">Declaring Dependencies
/// in Gradle</a>
default ExternalModuleDependency dependency(Object value) {
default Provider<ExternalModuleDependency> dependency(Object value) {
return this.dependency(value, Closures.empty(this));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
Original file line number Diff line number Diff line change
@@ -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<Boolean, MavenizerValueSource.Parameters> {
interface Parameters extends ValueSourceParameters {
ConfigurableFileCollection getClasspath();
RegularFileProperty getJavaLauncher();
ListProperty<String> 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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -19,22 +18,17 @@
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;
import org.gradle.api.plugins.ExtensionAware;
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;
Expand All @@ -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<SyncMavenizer> mavenizer;
private transient @Nullable NamedDomainObjectContainer<SlimeLauncherOptionsImpl> runs;

// Minecraft extension
Expand Down Expand Up @@ -129,12 +122,6 @@ private boolean hasAccessTransformers() {
return this.delegate;
}

// Can be nullable due to configuration caching.
@Override
public @Nullable TaskProvider<SyncMavenizer> asTask() {
return this.mavenizer;
}

@Override
public ExternalModuleDependency init(Object dependencyNotation, Closure<?> closure) {
this.runs = getObjects().domainObjectContainer(SlimeLauncherOptionsImpl.class);
Expand All @@ -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());
Expand Down Expand Up @@ -190,10 +175,6 @@ public void handle(Configuration configuration) {

@Override
public void handle(NamedDomainObjectSet<SourceSet> sourceSets, NamedDomainObjectSet<SourceSet> 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 ->
Expand Down Expand Up @@ -221,6 +202,10 @@ public void handle(NamedDomainObjectSet<SourceSet> sourceSets, NamedDomainObject
});
});

finalizeAccessTransformers(sourceSets);
}

void finalizeAccessTransformers(NamedDomainObjectSet<SourceSet> sourceSets) {
if (this.accessTransformer.isEmpty() && !this.accessTransformerPath.isPresent()) {
this.accessTransformer.convention(minecraft.getAccessTransformer());
this.accessTransformerPath.convention(minecraft.getAccessTransformerPath());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<SyncMavenizer> asTask();

default <R> Closure<R> closure(Closure<R> closure) {
return closure.rehydrate(closure.getDelegate(), new ClosureOwnerImpl.MinecraftDependencyImpl(closure.getOwner(), this), closure.getThisObject());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<MinecraftMappingsInternal> 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();
Expand All @@ -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()));
}

Expand All @@ -101,7 +110,7 @@ public DirectoryProperty getMavenizerOutput() {
@Override
public Action<MavenArtifactRepository> getMavenizer() {
return maven -> {
maven.setName("MinecraftMavenizer");
maven.setName(MAVENIZER_REPO_NAME);
maven.setUrl(this.getMavenizerOutput());
};
}
Expand Down Expand Up @@ -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 -> {
Expand Down Expand Up @@ -375,8 +370,9 @@ public NamedDomainObjectContainer<? extends SlimeLauncherOptions> getRuns() {
return this.runs;
}

@SuppressWarnings({"UnstableApiUsage"})
@Override
public ExternalModuleDependency dependency(
public Provider<ExternalModuleDependency> dependency(
Object value,
@DelegatesTo(ExternalModuleDependency.class)
@ClosureParams(value = SimpleType.class, options = "net.minecraftforge.gradle.MinecraftDependency.ClosureOwner")
Expand All @@ -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<String>();
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) {
Expand Down
Loading