Skip to content

Commit

Permalink
Apify the attribute schema and disambiguation rules for the Minecraft…
Browse files Browse the repository at this point in the history
… Libraries (#168)
  • Loading branch information
shartte authored Oct 9, 2024
1 parent 50eaf6a commit 3023b05
Show file tree
Hide file tree
Showing 9 changed files with 163 additions and 52 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package net.neoforged.minecraftdependencies;

import org.gradle.api.attributes.AttributeDisambiguationRule;
import org.gradle.api.attributes.MultipleCandidatesDetails;

import javax.inject.Inject;

/**
* Sets a default value for an attribute if no value is requested.
*/
abstract class DefaultValueDisambiguationRule<T> implements AttributeDisambiguationRule<T> {
private final T defaultValue;

@Inject
public DefaultValueDisambiguationRule(T defaultValue) {
this.defaultValue = defaultValue;
}

@Override
public void execute(MultipleCandidatesDetails<T> details) {
var consumerValue = details.getConsumerValue();
if (consumerValue != null && details.getCandidateValues().contains(consumerValue)) {
details.closestMatch(consumerValue);
} else {
for (var candidateValue : details.getCandidateValues()) {
if (candidateValue.equals(defaultValue)) {
details.closestMatch(candidateValue);
return;
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package net.neoforged.minecraftdependencies;

import javax.inject.Inject;

abstract class DistributionDisambiguationRule extends DefaultValueDisambiguationRule<MinecraftDistribution> {
@Inject
public DistributionDisambiguationRule(MinecraftDistribution defaultValue) {
super(defaultValue);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package net.neoforged.minecraftdependencies;

import org.gradle.api.Plugin;
import org.gradle.api.Project;

/**
* Applies defaults for the Gradle attributes introduced by the <a href="https://github.com/neoforged/GradleMinecraftDependencies">Minecraft Dependencies modules</a>.
* <p>
* The defaults are:
* <ul>
* <li>{@code net.neoforged.distribution} defaults to {@code client}</li>
* <li>{@code net.neoforged.operatingsystem} defaults to the current operating system</li>
* </ul>
*/
public class MinecraftDependenciesPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
project.getDependencies().attributesSchema(attributesSchema -> {
// Set up a disambiguation that by default selects the client distribution libraries
// This happens under the assumption that client is usually a superset of server.
var defaultDistribution = project.getObjects().named(MinecraftDistribution.class, MinecraftDistribution.CLIENT);
attributesSchema.attribute(MinecraftDistribution.ATTRIBUTE).getDisambiguationRules().add(DistributionDisambiguationRule.class, spec -> spec.params(
defaultDistribution
));

var defaultOperatingSystem = project.getObjects().named(OperatingSystem.class, getDefaultOperatingSystem());
attributesSchema.attribute(OperatingSystem.ATTRIBUTE).getDisambiguationRules().add(OperatingSystemDisambiguationRule.class, spec -> spec.params(
defaultOperatingSystem
));
});
}

private static String getDefaultOperatingSystem() {
return switch (net.neoforged.moddevgradle.internal.utils.OperatingSystem.current()) {
case LINUX -> OperatingSystem.LINUX;
case MACOS -> OperatingSystem.MACOSX;
case WINDOWS -> OperatingSystem.WINDOWS;
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package net.neoforged.minecraftdependencies;

import org.gradle.api.Named;
import org.gradle.api.attributes.Attribute;

/**
* The source of this attribute is the list of dependencies declared by the server and client Minecraft distributions.
* <p>
*
* @see <a href="https://github.com/neoforged/GradleMinecraftDependencies/blob/999449cc54c5c01fff1a66406be6e72872b75979/buildSrc/src/main/groovy/net/neoforged/minecraftdependencies/GenerateModuleMetadata.groovy#L83">GradleMinecraftDependencies project</a>
*/
public interface MinecraftDistribution extends Named {
Attribute<MinecraftDistribution> ATTRIBUTE = Attribute.of("net.neoforged.distribution", MinecraftDistribution.class);

String CLIENT = "client";
String SERVER = "server";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package net.neoforged.minecraftdependencies;

import org.gradle.api.Named;
import org.gradle.api.attributes.Attribute;

/**
* This attribute is used to differentiate between the different native libraries used by Minecraft.
* <p>
* The client in particular uses a rule-based system to declare dependencies that only apply to certain
* operating systems. We model libraries that are declared using such rules by using this attribute.
*
* @see <a href="https://github.com/neoforged/GradleMinecraftDependencies/blob/999449cc54c5c01fff1a66406be6e72872b75979/buildSrc/src/main/groovy/net/neoforged/minecraftdependencies/GenerateModuleMetadata.groovy#L140">GradleMinecraftDependencies</a>
*/
public interface OperatingSystem extends Named {
Attribute<OperatingSystem> ATTRIBUTE = Attribute.of("net.neoforged.operatingsystem", OperatingSystem.class);

String LINUX = "linux";
String MACOSX = "osx";
String WINDOWS = "windows";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package net.neoforged.minecraftdependencies;

import javax.inject.Inject;

abstract class OperatingSystemDisambiguationRule extends DefaultValueDisambiguationRule<OperatingSystem> {
@Inject
public OperatingSystemDisambiguationRule(OperatingSystem defaultValue) {
super(defaultValue);
}
}

This file was deleted.

51 changes: 33 additions & 18 deletions src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import net.neoforged.elc.configs.GradleLaunchConfig;
import net.neoforged.elc.configs.JavaApplicationLaunchConfig;
import net.neoforged.elc.configs.LaunchGroup;
import net.neoforged.minecraftdependencies.MinecraftDependenciesPlugin;
import net.neoforged.minecraftdependencies.MinecraftDistribution;
import net.neoforged.moddevgradle.dsl.DataFileCollection;
import net.neoforged.moddevgradle.dsl.InternalModelHelper;
import net.neoforged.moddevgradle.dsl.NeoForgeExtension;
Expand All @@ -21,6 +23,7 @@
import net.neoforged.vsclc.attribute.ShortCmdBehaviour;
import net.neoforged.vsclc.writer.WritingMode;
import org.gradle.api.GradleException;
import org.gradle.api.Named;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.Task;
Expand All @@ -29,13 +32,15 @@
import org.gradle.api.artifacts.ExternalModuleDependency;
import org.gradle.api.artifacts.ModuleDependency;
import org.gradle.api.attributes.Attribute;
import org.gradle.api.attributes.AttributeContainer;
import org.gradle.api.attributes.Category;
import org.gradle.api.attributes.DocsType;
import org.gradle.api.attributes.Usage;
import org.gradle.api.component.AdhocComponentWithVariants;
import org.gradle.api.file.ConfigurableFileCollection;
import org.gradle.api.file.Directory;
import org.gradle.api.file.RegularFile;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.plugins.ExtensionAware;
import org.gradle.api.plugins.JavaLibraryPlugin;
import org.gradle.api.plugins.JavaPlugin;
Expand Down Expand Up @@ -85,9 +90,6 @@
public class ModDevPlugin implements Plugin<Project> {
private static final Logger LOG = LoggerFactory.getLogger(ModDevPlugin.class);

private static final Attribute<String> ATTRIBUTE_DISTRIBUTION = Attribute.of("net.neoforged.distribution", String.class);
private static final Attribute<String> ATTRIBUTE_OPERATING_SYSTEM = Attribute.of("net.neoforged.operatingsystem", String.class);

/**
* This must be relative to the project directory since we can only set this to the same project-relative
* directory across all subprojects due to IntelliJ limitations.
Expand All @@ -109,12 +111,20 @@ public class ModDevPlugin implements Plugin<Project> {
*/
public static final String CONFIGURATION_COMPILE_DEPENDENCIES = "neoForgeCompileDependencies";

private final ObjectFactory objectFactory;

private Runnable configureTesting = null;

@Inject
public ModDevPlugin(ObjectFactory objectFactory) {
this.objectFactory = objectFactory;
}

@Override
public void apply(Project project) {
project.getPlugins().apply(JavaLibraryPlugin.class);
project.getPlugins().apply(NeoFormRuntimePlugin.class);
project.getPlugins().apply(MinecraftDependenciesPlugin.class);

// Do not apply the repositories automatically if they have been applied at the settings-level.
// It's still possible to apply them manually, though.
Expand Down Expand Up @@ -184,11 +194,6 @@ public void apply(Project project) {
});
}));

project.getDependencies().attributesSchema(attributesSchema -> {
attributesSchema.attribute(ATTRIBUTE_DISTRIBUTION).getDisambiguationRules().add(DistributionDisambiguation.class);
attributesSchema.attribute(ATTRIBUTE_OPERATING_SYSTEM).getDisambiguationRules().add(OperatingSystemDisambiguation.class);
});

var createManifestConfigurations = configureArtifactManifestConfigurations(project, extension);

// Add a filtered parchment repository automatically if enabled
Expand Down Expand Up @@ -343,7 +348,10 @@ public void apply(Project project) {
spec.setCanBeConsumed(false);
spec.shouldResolveConsistentlyWith(runtimeClasspathConfig.get());
spec.attributes(attributes -> {
attributes.attributeProvider(ATTRIBUTE_DISTRIBUTION, type.map(t -> t.equals("client") || t.equals("data") ? "client" : "server"));
attributes.attributeProvider(MinecraftDistribution.ATTRIBUTE, type.map(t -> {
var name = t.equals("client") || t.equals("data") ? MinecraftDistribution.CLIENT : MinecraftDistribution.SERVER;
return project.getObjects().named(MinecraftDistribution.class, name);
}));
attributes.attribute(Usage.USAGE_ATTRIBUTE, project.getObjects().named(Usage.class, Usage.JAVA_RUNTIME));
});
spec.getDependencies().addLater(neoForgeModDevLibrariesDependency);
Expand Down Expand Up @@ -517,8 +525,8 @@ private List<Configuration> configureArtifactManifestConfigurations(Project proj
caps.requireCapability("net.neoforged:neoform-dependencies");
})));
spec.attributes(attributes -> {
attributes.attribute(Usage.USAGE_ATTRIBUTE, project.getObjects().named(Usage.class, Usage.JAVA_API));
attributes.attribute(ATTRIBUTE_DISTRIBUTION, "client");
setNamedAttribute(attributes, Usage.USAGE_ATTRIBUTE, Usage.JAVA_API);
setNamedAttribute(attributes, MinecraftDistribution.ATTRIBUTE, MinecraftDistribution.CLIENT);
});
});

Expand All @@ -538,8 +546,8 @@ private List<Configuration> configureArtifactManifestConfigurations(Project proj
caps.requireCapability("net.neoforged:neoform-dependencies");
})));
spec.attributes(attributes -> {
attributes.attribute(Usage.USAGE_ATTRIBUTE, project.getObjects().named(Usage.class, Usage.JAVA_RUNTIME));
attributes.attribute(ATTRIBUTE_DISTRIBUTION, "client");
setNamedAttribute(attributes, Usage.USAGE_ATTRIBUTE, Usage.JAVA_RUNTIME);
setNamedAttribute(attributes, MinecraftDistribution.ATTRIBUTE, MinecraftDistribution.CLIENT);
});
});

Expand Down Expand Up @@ -622,8 +630,8 @@ private void setupTesting(Project project,
spec.setCanBeConsumed(false);
spec.shouldResolveConsistentlyWith(testRuntimeClasspathConfig.get());
spec.attributes(attributes -> {
attributes.attribute(ATTRIBUTE_DISTRIBUTION, "client");
attributes.attribute(Usage.USAGE_ATTRIBUTE, project.getObjects().named(Usage.class, Usage.JAVA_RUNTIME));
setNamedAttribute(project, attributes, MinecraftDistribution.ATTRIBUTE, MinecraftDistribution.CLIENT);
setNamedAttribute(project, attributes, Usage.USAGE_ATTRIBUTE, Usage.JAVA_RUNTIME);
});
spec.getDependencies().addLater(neoForgeModDevLibrariesDependency);
});
Expand Down Expand Up @@ -1013,14 +1021,14 @@ private static DataFileCollectionWrapper dataFileConfiguration(Project project,
spec.setDescription(description);
spec.setCanBeConsumed(false);
spec.setCanBeResolved(true);
spec.attributes(attributes -> attributes.attribute(Category.CATEGORY_ATTRIBUTE, project.getObjects().named(Category.class, category)));
spec.attributes(attributes -> setNamedAttribute(project, attributes, Category.CATEGORY_ATTRIBUTE, category));
});

var elementsConfiguration = project.getConfigurations().create(name + "Elements", spec -> {
spec.setDescription("Published data files for " + name);
spec.setCanBeConsumed(true);
spec.setCanBeResolved(false);
spec.attributes(attributes -> attributes.attribute(Category.CATEGORY_ATTRIBUTE, project.getObjects().named(Category.class, category)));
spec.attributes(attributes -> setNamedAttribute(project, attributes, Category.CATEGORY_ATTRIBUTE, category));
});

// Set up the variant publishing conditionally
Expand Down Expand Up @@ -1061,5 +1069,12 @@ public void accept(Object artifactNotation) {

return new DataFileCollectionWrapper(extension, configuration);
}
}

private <T extends Named> void setNamedAttribute(AttributeContainer attributes, Attribute<T> attribute, String value) {
attributes.attribute(attribute, objectFactory.named(attribute.getType(), value));
}

private static <T extends Named> void setNamedAttribute(Project project, AttributeContainer attributes, Attribute<T> attribute, String value) {
attributes.attribute(attribute, project.getObjects().named(attribute.getType(), value));
}
}

This file was deleted.

0 comments on commit 3023b05

Please sign in to comment.