mirror of
https://github.com/architectury/architectury-loom.git
synced 2026-03-28 04:07:01 -05:00
Use a hash for remapped dependency caching. (#1277)
* Use a hash from ModDependencyOptions for remapped dependency caching. * Use a different group to allow exclusiveContent to work. * Fix unit tests
This commit is contained in:
@@ -58,6 +58,8 @@ import org.gradle.api.tasks.SourceSet;
|
||||
import org.gradle.jvm.JvmLibrary;
|
||||
import org.gradle.language.base.artifact.SourcesArtifact;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.LoomGradlePlugin;
|
||||
@@ -65,6 +67,7 @@ import net.fabricmc.loom.api.RemapConfigurationSettings;
|
||||
import net.fabricmc.loom.configuration.RemapConfigurations;
|
||||
import net.fabricmc.loom.configuration.mods.dependency.ModDependency;
|
||||
import net.fabricmc.loom.configuration.mods.dependency.ModDependencyFactory;
|
||||
import net.fabricmc.loom.configuration.mods.dependency.ModDependencyOptions;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftSourceSets;
|
||||
import net.fabricmc.loom.util.Checksum;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
@@ -79,6 +82,8 @@ public class ModConfigurationRemapper {
|
||||
// This can happen when the dependency is a FileCollectionDependency or from a flatDir repository.
|
||||
public static final String MISSING_GROUP = "unspecified";
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ModConfigurationRemapper.class);
|
||||
|
||||
public static void supplyModConfigurations(Project project, ServiceFactory serviceFactory, String mappingsSuffix, LoomGradleExtension extension, SourceRemapper sourceRemapper) {
|
||||
final DependencyHandler dependencies = project.getDependencies();
|
||||
// The configurations where the source and remapped artifacts go.
|
||||
@@ -135,6 +140,14 @@ public class ModConfigurationRemapper {
|
||||
}
|
||||
}
|
||||
|
||||
final ModDependencyOptions modDependencyOptions = ModDependencyOptions.create(project, ModDependencyOptions.class, options -> {
|
||||
options.getMappings().set(mappingsSuffix);
|
||||
});
|
||||
|
||||
if (LOGGER.isInfoEnabled()) {
|
||||
LOGGER.info("Mod dependency options: {}", modDependencyOptions.getJson());
|
||||
}
|
||||
|
||||
// Round 1: Discovery
|
||||
// Go through all the configs to find artifacts to remap and
|
||||
// the installer data. The installer data has to be added before
|
||||
@@ -176,7 +189,7 @@ public class ModConfigurationRemapper {
|
||||
continue;
|
||||
}
|
||||
|
||||
final ModDependency modDependency = ModDependencyFactory.create(artifact, artifactMetadata, remappedConfig, clientRemappedConfig, mappingsSuffix, project);
|
||||
final ModDependency modDependency = ModDependencyFactory.create(artifact, artifactMetadata, remappedConfig, clientRemappedConfig, modDependencyOptions, project);
|
||||
scheduleSourcesRemapping(project, sourceRemapper, modDependency);
|
||||
modDependencies.add(modDependency);
|
||||
}
|
||||
@@ -332,7 +345,7 @@ public class ModConfigurationRemapper {
|
||||
}
|
||||
|
||||
if (dependency.isCacheInvalid(project, "sources")) {
|
||||
final Path output = dependency.getWorkingFile("sources");
|
||||
final Path output = dependency.getWorkingFile(project, "sources");
|
||||
|
||||
sourceRemapper.scheduleRemapSources(sourcesInput.toFile(), output.toFile(), false, true, () -> {
|
||||
try {
|
||||
|
||||
@@ -253,8 +253,8 @@ public class ModProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
private static Path getRemappedOutput(ModDependency dependency) {
|
||||
return dependency.getWorkingFile(null);
|
||||
private Path getRemappedOutput(ModDependency dependency) {
|
||||
return dependency.getWorkingFile(project, null);
|
||||
}
|
||||
|
||||
private void remapJarManifestEntries(Path jar) throws IOException {
|
||||
|
||||
@@ -37,23 +37,21 @@ import net.fabricmc.loom.configuration.mods.ArtifactRef;
|
||||
public abstract sealed class ModDependency permits SplitModDependency, SimpleModDependency {
|
||||
private final ArtifactRef artifact;
|
||||
private final ArtifactMetadata metadata;
|
||||
protected final String group;
|
||||
protected final String name;
|
||||
protected final String version;
|
||||
private final String group;
|
||||
private final String name;
|
||||
private final String version;
|
||||
@Nullable
|
||||
protected final String classifier;
|
||||
protected final String mappingsSuffix;
|
||||
protected final Project project;
|
||||
private final String classifier;
|
||||
private final ModDependencyOptions options;
|
||||
|
||||
public ModDependency(ArtifactRef artifact, ArtifactMetadata metadata, String mappingsSuffix, Project project) {
|
||||
public ModDependency(ArtifactRef artifact, ArtifactMetadata metadata, ModDependencyOptions options) {
|
||||
this.artifact = artifact;
|
||||
this.metadata = metadata;
|
||||
this.group = artifact.group();
|
||||
this.name = artifact.name();
|
||||
this.version = artifact.version();
|
||||
this.classifier = artifact.classifier();
|
||||
this.mappingsSuffix = mappingsSuffix;
|
||||
this.project = project;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,10 +69,15 @@ public abstract sealed class ModDependency permits SplitModDependency, SimpleMod
|
||||
*/
|
||||
public abstract void applyToProject(Project project);
|
||||
|
||||
protected LocalMavenHelper createMaven(String name) {
|
||||
/**
|
||||
* Create a maven helper for the local cache.
|
||||
* @param type The jar type, e.g "common" or "client" for split dependencies.
|
||||
*/
|
||||
protected LocalMavenHelper createMavenHelper(Project project, @Nullable String type) {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
final Path root = extension.getFiles().getRemappedModCache().toPath();
|
||||
return new LocalMavenHelper(getRemappedGroup(), name, this.version, this.classifier, root);
|
||||
final String fullName = getName() + (type != null ? "-" + type : "");
|
||||
return new LocalMavenHelper(getGroup(), fullName, this.version, this.classifier, root);
|
||||
}
|
||||
|
||||
public ArtifactRef getInputArtifact() {
|
||||
@@ -85,22 +88,26 @@ public abstract sealed class ModDependency permits SplitModDependency, SimpleMod
|
||||
return metadata;
|
||||
}
|
||||
|
||||
protected String getRemappedGroup() {
|
||||
return getMappingsPrefix() + "." + group;
|
||||
protected String getName() {
|
||||
return "%s-%s".formatted(name, options.getCacheKey());
|
||||
}
|
||||
|
||||
private String getMappingsPrefix() {
|
||||
return mappingsSuffix.replace(".", "_").replace("-", "_").replace("+", "_");
|
||||
protected String getGroup() {
|
||||
return "remapped.%s".formatted(group);
|
||||
}
|
||||
|
||||
protected String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public Path getInputFile() {
|
||||
return artifact.path();
|
||||
}
|
||||
|
||||
public Path getWorkingFile(@Nullable String classifier) {
|
||||
public Path getWorkingFile(Project project, @Nullable String classifier) {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
final String fileName = classifier == null ? String.format("%s-%s-%s.jar", getRemappedGroup(), name, version)
|
||||
: String.format("%s-%s-%s-%s.jar", getRemappedGroup(), name, version, classifier);
|
||||
final String fileName = classifier == null ? String.format("%s-%s-%s.jar", getGroup(), getName(), version)
|
||||
: String.format("%s-%s-%s-%s.jar", getGroup(), getName(), version, classifier);
|
||||
|
||||
return extension.getFiles().getProjectBuildCache().toPath().resolve("remapped_working").resolve(fileName);
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ import net.fabricmc.loom.util.AttributeHelper;
|
||||
public class ModDependencyFactory {
|
||||
private static final String TARGET_ATTRIBUTE_KEY = "loom-target";
|
||||
|
||||
public static ModDependency create(ArtifactRef artifact, ArtifactMetadata metadata, Configuration targetConfig, @Nullable Configuration targetClientConfig, String mappingsSuffix, Project project) {
|
||||
public static ModDependency create(ArtifactRef artifact, ArtifactMetadata metadata, Configuration targetConfig, @Nullable Configuration targetClientConfig, ModDependencyOptions options, Project project) {
|
||||
if (targetClientConfig != null && LoomGradleExtension.get(project).getSplitModDependencies().get()) {
|
||||
final Optional<JarSplitter.Target> cachedTarget = readTarget(artifact);
|
||||
JarSplitter.Target target;
|
||||
@@ -54,11 +54,11 @@ public class ModDependencyFactory {
|
||||
}
|
||||
|
||||
if (target != null) {
|
||||
return new SplitModDependency(artifact, metadata, mappingsSuffix, targetConfig, targetClientConfig, target, project);
|
||||
return new SplitModDependency(artifact, metadata, options, targetConfig, targetClientConfig, target, project);
|
||||
}
|
||||
}
|
||||
|
||||
return new SimpleModDependency(artifact, metadata, mappingsSuffix, targetConfig, project);
|
||||
return new SimpleModDependency(artifact, metadata, options, targetConfig, project);
|
||||
}
|
||||
|
||||
private static Optional<JarSplitter.Target> readTarget(ArtifactRef artifact) {
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2025 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.configuration.mods.dependency;
|
||||
|
||||
import org.gradle.api.provider.Property;
|
||||
|
||||
import net.fabricmc.loom.util.CacheKey;
|
||||
|
||||
/**
|
||||
* Inputs used to process a mod dependency. The output jar is cached based on these properties.
|
||||
*/
|
||||
public abstract class ModDependencyOptions extends CacheKey {
|
||||
public abstract Property<String> getMappings();
|
||||
}
|
||||
@@ -40,10 +40,10 @@ public final class SimpleModDependency extends ModDependency {
|
||||
private final Configuration targetConfig;
|
||||
private final LocalMavenHelper maven;
|
||||
|
||||
public SimpleModDependency(ArtifactRef artifact, ArtifactMetadata metadata, String mappingsSuffix, Configuration targetConfig, Project project) {
|
||||
super(artifact, metadata, mappingsSuffix, project);
|
||||
public SimpleModDependency(ArtifactRef artifact, ArtifactMetadata metadata, ModDependencyOptions options, Configuration targetConfig, Project project) {
|
||||
super(artifact, metadata, options);
|
||||
this.targetConfig = Objects.requireNonNull(targetConfig);
|
||||
this.maven = createMaven(name);
|
||||
this.maven = createMavenHelper(project, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -48,13 +48,13 @@ public final class SplitModDependency extends ModDependency {
|
||||
@Nullable
|
||||
private final LocalMavenHelper clientMaven;
|
||||
|
||||
public SplitModDependency(ArtifactRef artifact, ArtifactMetadata metadata, String mappingsSuffix, Configuration targetCommonConfig, Configuration targetClientConfig, JarSplitter.Target target, Project project) {
|
||||
super(artifact, metadata, mappingsSuffix, project);
|
||||
public SplitModDependency(ArtifactRef artifact, ArtifactMetadata metadata, ModDependencyOptions options, Configuration targetCommonConfig, Configuration targetClientConfig, JarSplitter.Target target, Project project) {
|
||||
super(artifact, metadata, options);
|
||||
this.targetCommonConfig = Objects.requireNonNull(targetCommonConfig);
|
||||
this.targetClientConfig = Objects.requireNonNull(targetClientConfig);
|
||||
this.target = Objects.requireNonNull(target);
|
||||
this.commonMaven = target.common() ? createMaven(name + "-common") : null;
|
||||
this.clientMaven = target.client() ? createMaven(name + "-client") : null;
|
||||
this.commonMaven = target.common() ? createMavenHelper(project, "common") : null;
|
||||
this.clientMaven = target.client() ? createMavenHelper(project, "client") : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -86,8 +86,8 @@ public final class SplitModDependency extends ModDependency {
|
||||
// Split the jar into 2
|
||||
case SPLIT -> {
|
||||
final String suffix = variant == null ? "" : "-" + variant;
|
||||
final Path commonTempJar = getWorkingFile("common" + suffix);
|
||||
final Path clientTempJar = getWorkingFile("client" + suffix);
|
||||
final Path commonTempJar = getWorkingFile(project, "common" + suffix);
|
||||
final Path clientTempJar = getWorkingFile(project, "client" + suffix);
|
||||
|
||||
final JarSplitter splitter = new JarSplitter(path);
|
||||
splitter.split(commonTempJar, clientTempJar);
|
||||
@@ -114,15 +114,16 @@ public final class SplitModDependency extends ModDependency {
|
||||
|
||||
if (target == JarSplitter.Target.SPLIT) {
|
||||
createModGroup(
|
||||
project,
|
||||
getCommonMaven().getOutputFile(null),
|
||||
getClientMaven().getOutputFile(null)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void createModGroup(Path commonJar, Path clientJar) {
|
||||
private void createModGroup(Project project, Path commonJar, Path clientJar) {
|
||||
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
final ModSettings modSettings = extension.getMods().maybeCreate(String.format("%s-%s-%s", getRemappedGroup(), name, version));
|
||||
final ModSettings modSettings = extension.getMods().maybeCreate(String.format("%s-%s-%s", getGroup(), getName(), getVersion()));
|
||||
modSettings.getModFiles().from(
|
||||
commonJar.toFile(),
|
||||
clientJar.toFile()
|
||||
|
||||
60
src/main/java/net/fabricmc/loom/util/CacheKey.java
Normal file
60
src/main/java/net/fabricmc/loom/util/CacheKey.java
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2025 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.util;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
import org.gradle.api.Action;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.tasks.Internal;
|
||||
|
||||
import net.fabricmc.loom.util.gradle.GradleTypeAdapter;
|
||||
|
||||
/**
|
||||
* A simple base class for creating cache keys. Extend this class and create abstract properties to be included in the cache key.
|
||||
*/
|
||||
public abstract class CacheKey {
|
||||
private static final int CHECKSUM_LENGTH = 8;
|
||||
private final transient Supplier<String> jsonSupplier = Suppliers.memoize(() -> GradleTypeAdapter.GSON.toJson(this));
|
||||
private final transient Supplier<String> cacheKeySupplier = Suppliers.memoize(() -> Checksum.sha1Hex(jsonSupplier.get().getBytes(StandardCharsets.UTF_8)).substring(0, CHECKSUM_LENGTH));
|
||||
|
||||
public static <T> T create(Project project, Class<T> clazz, Action<T> action) {
|
||||
T instance = project.getObjects().newInstance(clazz);
|
||||
action.execute(instance);
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Internal
|
||||
public final String getJson() {
|
||||
return jsonSupplier.get();
|
||||
}
|
||||
|
||||
@Internal
|
||||
public final String getCacheKey() {
|
||||
return cacheKeySupplier.get();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2025 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.test.unit
|
||||
|
||||
import spock.lang.Specification
|
||||
|
||||
import net.fabricmc.loom.configuration.mods.dependency.ModDependencyOptions
|
||||
import net.fabricmc.loom.test.util.GradleTestUtil
|
||||
import net.fabricmc.loom.util.CacheKey
|
||||
|
||||
class ModDependencyOptionsTest extends Specification {
|
||||
def "test ModDependencyOptions cache key and json value"() {
|
||||
given:
|
||||
def project = GradleTestUtil.mockProject()
|
||||
def modDependencyOptions = CacheKey.create(project, ModDependencyOptions) {
|
||||
it.getMappings().set("testMappings")
|
||||
}
|
||||
|
||||
when:
|
||||
def json = modDependencyOptions.getJson()
|
||||
def cacheKey = modDependencyOptions.getCacheKey()
|
||||
|
||||
then:
|
||||
json == '{"__mappings__":"testMappings"}'
|
||||
cacheKey == "c97692d3"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user