Add file mappings layer (#590)

* Support passing FileSpecs around for the FileSpec notation

* Add file mappings layer

* Add better tests for file mappings

* Remove unnecessary param in setup closure call

* Fix test code style

* Add ZipUtils.isZip

* Automatically detect whether the file is a zip

* Rename LayeredMappingSpecBuilder.fileMappings -> mappings

* Add test for file mappings in layered mappings, fix inconsistent hashCode being

* Resolve reviews
dev/0.11
Juuxel 2022-01-31 16:50:19 +02:00 committed by GitHub
parent 287e6cefb9
commit 5dda747cee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 574 additions and 5 deletions

View File

@ -1,7 +1,7 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2016-2021 FabricMC
* Copyright (c) 2016-2022 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
@ -26,6 +26,8 @@ package net.fabricmc.loom.api.mappings.layered;
import java.util.Locale;
import org.jetbrains.annotations.Nullable;
/**
* The standard namespaces used by loom.
*/
@ -49,6 +51,21 @@ public enum MappingsNamespace {
*/
NAMED;
/**
* Gets a {@code MappingsNamespace} from a namespace string.
*
* @param namespace the name of the namespace as a lowercase string
* @return the {@code MappingsNamespace}, or null if not found
*/
public static @Nullable MappingsNamespace of(String namespace) {
return switch (namespace) {
case "official" -> OFFICIAL;
case "intermediary" -> INTERMEDIARY;
case "named" -> NAMED;
default -> null;
};
}
@Override
public String toString() {
return name().toLowerCase(Locale.ROOT);

View File

@ -0,0 +1,101 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2021-2022 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.api.mappings.layered.spec;
import org.jetbrains.annotations.ApiStatus;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
/**
* A builder for a file mappings layer.
* This layer type supports any mapping type that mapping-io can read.
*/
@ApiStatus.Experimental
public interface FileMappingsSpecBuilder {
/**
* Sets the mapping path inside a zip or jar.
* This will have no effect if the file of this mapping spec
* is not a zip.
*
* <p>Path components within the path should be separated with {@code /}.
*
* <p>The default mapping path is {@code mappings/mappings.tiny}, matching regular mapping dependency jars
* such as Yarn's.
*
* @param mappingPath the mapping path, or null if a bare file
* @return this builder
*/
FileMappingsSpecBuilder mappingPath(String mappingPath);
/**
* Sets the fallback namespaces. They will be used
* if the mapping format itself doesn't provide namespaces with names
* (e.g. Enigma mappings).
*
* <p>The default fallback namespaces are {@code intermediary} as the source namespace
* and {@code named} as the target namespace as in Yarn.
*
* @param sourceNamespace the fallback source namespace
* @param targetNamespace the fallback target namespace
* @return this builder
*/
FileMappingsSpecBuilder fallbackNamespaces(String sourceNamespace, String targetNamespace);
/**
* Marks that the file contains Enigma mappings.
* Because they are stored in a directory, the format cannot be auto-detected.
*
* @return this builder
*/
FileMappingsSpecBuilder enigmaMappings();
/**
* Sets the merge namespace of this mappings spec.
*
* <p>The merge namespace is the namespace that is used to match up this layer's
* names to the rest of the mappings. For example, Yarn mappings should be merged through
* the intermediary names.
*
* <p>The default merge namespace is {@link MappingsNamespace#INTERMEDIARY}.
*
* @param namespace the new merge namespace
* @return this builder
*/
FileMappingsSpecBuilder mergeNamespace(MappingsNamespace namespace);
/**
* Sets the merge namespace of this mappings spec.
*
* <p>The merge namespace is the namespace that is used to match up this layer's
* names to the rest of the mappings. For example, Yarn mappings should be merged through
* the intermediary names.
*
* <p>The default merge namespace is {@code intermediary}.
*
* @param namespace the new merge namespace
* @return this builder
*/
FileMappingsSpecBuilder mergeNamespace(String namespace);
}

View File

@ -1,7 +1,7 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2021 FabricMC
* Copyright (c) 2021-2022 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
@ -50,9 +50,10 @@ public interface FileSpec {
* <p>The parameter will be evaluated like this:
* <ul>
* <li>{@link File}, {@link Path} and {@link FileSystemLocation} will be resolved as local files</li>
* <li>{@link Provider} (including {@link org.gradle.api.provider.Property} will recursively be resolved as its current value</li>
* <li>{@link Provider} (including {@link org.gradle.api.provider.Property}) will recursively be resolved as its current value</li>
* <li>{@link CharSequence} (including {@link String} and {@link groovy.lang.GString}) will be resolved as Maven dependencies</li>
* <li>{@link Dependency} will be resolved as any dependency</li>
* <li>{@code FileSpec} will just return the spec itself</li>
* </ul>
*
* @param o the file notation
@ -73,6 +74,8 @@ public interface FileSpec {
return createFromFile(p);
} else if (o instanceof FileSystemLocation l) {
return createFromFile(l);
} else if (o instanceof FileSpec s) {
return s;
}
throw new UnsupportedOperationException("Cannot create FileSpec from object of type:" + o.getClass().getCanonicalName());

View File

@ -1,7 +1,7 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2021 FabricMC
* Copyright (c) 2021-2022 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
@ -77,4 +77,40 @@ public interface LayeredMappingSpecBuilder {
*/
@ApiStatus.Experimental
LayeredMappingSpecBuilder signatureFix(Object object);
/**
* Add a layer that uses a mappings file or directory.
*
* @param file the file notation for a {@link FileSpec}
* @return this builder
* @see FileMappingsSpecBuilder
*/
@ApiStatus.Experimental
default LayeredMappingSpecBuilder mappings(Object file) {
return mappings(file, builder -> { });
}
/**
* Configure and add a layer that uses a mappings file or directory.
*
* @param file the file notation for a {@link FileSpec}
* @param closure the configuration action
* @return this builder
* @see FileMappingsSpecBuilder
*/
@ApiStatus.Experimental
default LayeredMappingSpecBuilder mappings(Object file, @DelegatesTo(value = FileMappingsSpecBuilder.class, strategy = Closure.DELEGATE_FIRST) Closure<?> closure) {
return mappings(file, new ClosureAction<>(closure));
}
/**
* Configure and add a layer that uses a mappings file or directory.
*
* @param file the file notation for a {@link FileSpec}
* @param action the configuration action
* @return this builder
* @see FileMappingsSpecBuilder
*/
@ApiStatus.Experimental
LayeredMappingSpecBuilder mappings(Object file, Action<? super FileMappingsSpecBuilder> action);
}

View File

@ -30,12 +30,14 @@ import java.util.List;
import org.gradle.api.Action;
import net.fabricmc.loom.api.mappings.layered.spec.FileMappingsSpecBuilder;
import net.fabricmc.loom.api.mappings.layered.spec.FileSpec;
import net.fabricmc.loom.api.mappings.layered.spec.LayeredMappingSpecBuilder;
import net.fabricmc.loom.api.mappings.layered.spec.MappingsSpec;
import net.fabricmc.loom.api.mappings.layered.spec.MojangMappingsSpecBuilder;
import net.fabricmc.loom.api.mappings.layered.spec.ParchmentMappingsSpecBuilder;
import net.fabricmc.loom.configuration.providers.mappings.extras.signatures.SignatureFixesSpec;
import net.fabricmc.loom.configuration.providers.mappings.file.FileMappingsSpecBuilderImpl;
import net.fabricmc.loom.configuration.providers.mappings.intermediary.IntermediaryMappingsSpec;
import net.fabricmc.loom.configuration.providers.mappings.mojmap.MojangMappingsSpecBuilderImpl;
import net.fabricmc.loom.configuration.providers.mappings.parchment.ParchmentMappingsSpecBuilderImpl;
@ -68,6 +70,13 @@ public class LayeredMappingSpecBuilderImpl implements LayeredMappingSpecBuilder
return addLayer(new SignatureFixesSpec(FileSpec.create(object)));
}
@Override
public LayeredMappingSpecBuilder mappings(Object file, Action<? super FileMappingsSpecBuilder> action) {
FileMappingsSpecBuilderImpl builder = FileMappingsSpecBuilderImpl.builder(FileSpec.create(file));
action.execute(builder);
return addLayer(builder.build());
}
public LayeredMappingSpec build() {
List<MappingsSpec<?>> builtLayers = new LinkedList<>();
// Intermediary is always the base layer

View File

@ -0,0 +1,85 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2022 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.providers.mappings.file;
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import net.fabricmc.loom.api.mappings.layered.MappingLayer;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.configuration.providers.mappings.intermediary.IntermediaryMappingLayer;
import net.fabricmc.loom.util.FileSystemUtil;
import net.fabricmc.loom.util.ZipUtils;
import net.fabricmc.mappingio.MappingReader;
import net.fabricmc.mappingio.MappingUtil;
import net.fabricmc.mappingio.MappingVisitor;
import net.fabricmc.mappingio.adapter.MappingNsRenamer;
import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch;
import net.fabricmc.mappingio.format.MappingFormat;
public record FileMappingsLayer(
Path path, String mappingPath,
String fallbackSourceNamespace, String fallbackTargetNamespace,
boolean enigma, // Enigma cannot be automatically detected since it's stored in a directory.
String mergeNamespace
) implements MappingLayer {
@Override
public void visit(MappingVisitor mappingVisitor) throws IOException {
// Bare file
if (!ZipUtils.isZip(path)) {
visit(path, mappingVisitor);
} else {
try (FileSystemUtil.Delegate fileSystem = FileSystemUtil.getJarFileSystem(path)) {
visit(fileSystem.get().getPath(mappingPath), mappingVisitor);
}
}
}
private void visit(Path path, MappingVisitor mappingVisitor) throws IOException {
MappingSourceNsSwitch nsSwitch = new MappingSourceNsSwitch(mappingVisitor, mergeNamespace.toString());
// Replace the default fallback namespaces with
// our fallback namespaces if potentially needed.
Map<String, String> fallbackNamespaceReplacements = Map.of(
MappingUtil.NS_SOURCE_FALLBACK, fallbackSourceNamespace,
MappingUtil.NS_TARGET_FALLBACK, fallbackTargetNamespace
);
MappingNsRenamer renamer = new MappingNsRenamer(nsSwitch, fallbackNamespaceReplacements);
MappingReader.read(path, enigma ? MappingFormat.ENIGMA : null, renamer);
}
@Override
public MappingsNamespace getSourceNamespace() {
return MappingsNamespace.of(mergeNamespace);
}
@Override
public List<Class<? extends MappingLayer>> dependsOn() {
return List.of(IntermediaryMappingLayer.class);
}
}

View File

@ -0,0 +1,41 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2022 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.providers.mappings.file;
import net.fabricmc.loom.api.mappings.layered.MappingContext;
import net.fabricmc.loom.api.mappings.layered.spec.FileSpec;
import net.fabricmc.loom.api.mappings.layered.spec.MappingsSpec;
public record FileMappingsSpec(
FileSpec fileSpec, String mappingPath,
String fallbackSourceNamespace, String fallbackTargetNamespace,
boolean enigma,
String mergeNamespace
) implements MappingsSpec<FileMappingsLayer> {
@Override
public FileMappingsLayer createLayer(MappingContext context) {
return new FileMappingsLayer(fileSpec.get(context), mappingPath, fallbackSourceNamespace, fallbackTargetNamespace, enigma, mergeNamespace);
}
}

View File

@ -0,0 +1,94 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2022 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.providers.mappings.file;
import java.util.Objects;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.api.mappings.layered.spec.FileMappingsSpecBuilder;
import net.fabricmc.loom.api.mappings.layered.spec.FileSpec;
public class FileMappingsSpecBuilderImpl implements FileMappingsSpecBuilder {
/**
* The mapping path of regular mapping dependencies.
*/
private static final String DEFAULT_MAPPING_PATH = "mappings/mappings.tiny";
private final FileSpec fileSpec;
private String mappingPath = DEFAULT_MAPPING_PATH;
private String fallbackSourceNamespace = MappingsNamespace.INTERMEDIARY.toString();
private String fallbackTargetNamespace = MappingsNamespace.NAMED.toString();
private boolean enigma = false;
private String mergeNamespace = MappingsNamespace.INTERMEDIARY.toString();
private FileMappingsSpecBuilderImpl(FileSpec fileSpec) {
this.fileSpec = fileSpec;
}
public static FileMappingsSpecBuilderImpl builder(FileSpec fileSpec) {
return new FileMappingsSpecBuilderImpl(fileSpec);
}
@Override
public FileMappingsSpecBuilderImpl mappingPath(String mappingPath) {
this.mappingPath = Objects.requireNonNull(mappingPath, "mapping path cannot be null");
return this;
}
@Override
public FileMappingsSpecBuilderImpl fallbackNamespaces(String sourceNamespace, String targetNamespace) {
fallbackSourceNamespace = Objects.requireNonNull(sourceNamespace, "fallback source namespace cannot be null");
fallbackTargetNamespace = Objects.requireNonNull(targetNamespace, "fallback target namespace cannot be null");
return this;
}
@Override
public FileMappingsSpecBuilderImpl enigmaMappings() {
enigma = true;
return this;
}
@Override
public FileMappingsSpecBuilderImpl mergeNamespace(MappingsNamespace namespace) {
mergeNamespace = Objects.requireNonNull(namespace, "merge namespace cannot be null").toString();
return this;
}
@Override
public FileMappingsSpecBuilderImpl mergeNamespace(String namespace) {
Objects.requireNonNull(namespace, "merge namespace cannot be null");
if (MappingsNamespace.of(namespace) == null) {
throw new IllegalArgumentException("Namespace '" + namespace + "' is unsupported! It must be either 'official', 'intermediary' or 'named'.");
}
mergeNamespace = namespace;
return this;
}
public FileMappingsSpec build() {
return new FileMappingsSpec(fileSpec, mappingPath, fallbackSourceNamespace, fallbackTargetNamespace, enigma, mergeNamespace);
}
}

View File

@ -25,6 +25,7 @@
package net.fabricmc.loom.util;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UncheckedIOException;
@ -47,6 +48,22 @@ import org.jetbrains.annotations.Nullable;
import net.fabricmc.loom.LoomGradlePlugin;
public class ZipUtils {
public static boolean isZip(Path zip) throws IOException {
if (Files.notExists(zip)) {
throw new NoSuchFileException("Cannot check if '" + zip + "' is a zip because it doesn't exist!");
}
if (Files.isRegularFile(zip)) {
try (DataInputStream in = new DataInputStream(Files.newInputStream(zip))) {
int header = in.readInt();
// See https://en.wikipedia.org/wiki/List_of_file_signatures
return header == 0x504B0304 || header == 0x504B0506 || header == 0x504B0708;
}
} else {
return false;
}
}
public static boolean contains(Path zip, String path) {
try (FileSystemUtil.Delegate fs = FileSystemUtil.getJarFileSystem(zip, false)) {
Path fsPath = fs.get().getPath(path);

View File

@ -121,4 +121,32 @@ class ZipUtilsTest extends Specification {
outputFile.exists()
outputFile.text == "This is a test of unpacking all"
}
def "is zip"() {
setup:
// Create zip
def dir = Files.createTempDirectory("loom-zip-test")
def zip = Files.createTempFile("loom-zip-test", ".zip")
def fileInside = dir.resolve("text.txt")
Files.writeString(fileInside, "hello world")
ZipUtils.pack(dir, zip)
when:
def result = ZipUtils.isZip(zip)
then:
result
}
def "is not zip"() {
setup:
def textFile = Files.createTempFile("loom-zip-test", ".txt")
Files.writeString(textFile, "hello world")
when:
def result = ZipUtils.isZip(textFile)
then:
!result
}
}

View File

@ -0,0 +1,122 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2022 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.layeredmappings
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace
import net.fabricmc.loom.api.mappings.layered.spec.FileSpec
import net.fabricmc.loom.configuration.providers.mappings.file.FileMappingsSpecBuilderImpl
import net.fabricmc.loom.configuration.providers.mappings.intermediary.IntermediaryMappingsSpec
import net.fabricmc.loom.util.DownloadUtil
import net.fabricmc.loom.util.ZipUtils
import spock.lang.Unroll
import java.nio.file.Path
import java.util.function.Consumer
class FileMappingLayerTest extends LayeredMappingsSpecification {
@Unroll
def "read Yarn mappings from #setupType.displayName"() {
setup:
intermediaryUrl = INTERMEDIARY_1_17_URL
mockMinecraftProvider.getVersionInfo() >> VERSION_META_1_17
setupType.setup.delegate = this
def mappingFile = setupType.setup.call()
when:
def builder = FileMappingsSpecBuilderImpl.builder(FileSpec.create(mappingFile))
setupType.mappingsSpec.accept(builder)
def mappings = getLayeredMappings(
new IntermediaryMappingsSpec(),
builder.build()
)
then:
mappings.srcNamespace == "named"
mappings.dstNamespaces == ["intermediary", "official"]
mappings.classes.size() == 6111
mappings.classes[0].srcName == "net/minecraft/block/FenceBlock"
mappings.classes[0].getDstName(0) == "net/minecraft/class_2354"
mappings.classes[0].fields[0].srcName == "cullingShapes"
mappings.classes[0].fields[0].getDstName(0) == "field_11066"
mappings.classes[0].methods[0].srcName == "canConnectToFence"
mappings.classes[0].methods[0].getDstName(0) == "method_26375"
mappings.classes[0].methods[0].args[0].srcName == "state"
where:
setupType << YarnSetupType.values()
}
// Also tests the custom fallback namespace and source namespace functionality
def "read Mojang mappings from proguard"() {
setup:
intermediaryUrl = INTERMEDIARY_1_17_URL
mockMinecraftProvider.getVersionInfo() >> VERSION_META_1_17
def mappingsDownload = VERSION_META_1_17.download('client_mappings')
def mappingsFile = new File(tempDir, 'mappings.txt')
DownloadUtil.downloadIfChanged(new URL(mappingsDownload.url()), mappingsFile, mappingContext.logger)
when:
def mappings = getLayeredMappings(
new IntermediaryMappingsSpec(),
FileMappingsSpecBuilderImpl.builder(FileSpec.create(mappingsFile))
.fallbackNamespaces('named', 'official')
.mergeNamespace(MappingsNamespace.OFFICIAL)
.build()
)
def tiny = getTiny(mappings)
then:
mappings.srcNamespace == "named"
mappings.dstNamespaces == ["intermediary", "official"]
mappings.classes.size() == 6113
mappings.classes[0].srcName.hashCode() == 1869546970 // MojMap name, just check the hash
mappings.classes[0].getDstName(0) == "net/minecraft/class_2354"
mappings.classes[0].methods[0].args.size() == 0 // No Args
tiny.contains('this$0')
}
enum YarnSetupType {
TINY_JAR('tiny jar', { downloadFile(YARN_1_17_URL, "yarn.jar") }, { }),
BARE_TINY('bare tiny file', {
def yarnJar = downloadFile(YARN_1_17_URL, "yarn.jar")
def yarnTiny = new File(tempDir, "yarn.tiny")
yarnTiny.bytes = ZipUtils.unpack(yarnJar.toPath(), "mappings/mappings.tiny")
yarnTiny
}, { }),
ENIGMA_ZIP('enigma zip', {
// Recent Yarn data is not published as Enigma zips, so this zip is just a copy
// of Yarn's repo at a60a3189
Path.of("src/test/resources/mappings/yarn-1.17.zip")
}, {
it.mappingPath("mappings").enigmaMappings()
}),
;
final String displayName
final Closure<?> setup
final Consumer<FileMappingsSpecBuilderImpl> mappingsSpec
YarnSetupType(String displayName, Closure<?> setup, Consumer<FileMappingsSpecBuilderImpl> mappingsSpec) {
this.displayName = displayName
this.setup = setup
this.mappingsSpec = mappingsSpec
}
}
}

View File

@ -24,6 +24,7 @@
package net.fabricmc.loom.test.unit.layeredmappings
import net.fabricmc.loom.configuration.providers.mappings.file.FileMappingsSpec
import net.fabricmc.loom.configuration.providers.mappings.utils.MavenFileSpec
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpec
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpecBuilderImpl
@ -106,6 +107,20 @@ class LayeredMappingSpecBuilderTest extends Specification {
parchment.removePrefix() == false
}
def "yarn through file mappings"() {
when:
def spec = layered {
mappings("net.fabricmc:yarn:1.18.1+build.1:v2")
}
def layers = spec.layers()
then:
spec.version == "layered+hash.1284206205"
layers.size() == 2
layers[0].class == IntermediaryMappingsSpec
layers[1].class == FileMappingsSpec
((layers[1] as FileMappingsSpec).fileSpec() as MavenFileSpec).dependencyNotation() == "net.fabricmc:yarn:1.18.1+build.1:v2"
}
LayeredMappingSpec layered(@DelegatesTo(LayeredMappingSpecBuilderImpl) Closure cl) {
LayeredMappingSpecBuilderImpl builder = new LayeredMappingSpecBuilderImpl()
new ClosureAction(cl).execute(builder)

View File

@ -1,7 +1,7 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2021 FabricMC
* Copyright (c) 2021-2022 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
@ -44,4 +44,5 @@ interface LayeredMappingsTestConstants {
public static final String PARCHMENT_NOTATION = "org.parchmentmc.data:parchment-1.16.5:20210608-SNAPSHOT@zip"
public static final String PARCHMENT_URL = "https://maven.parchmentmc.net/org/parchmentmc/data/parchment-1.16.5/20210608-SNAPSHOT/parchment-1.16.5-20210608-SNAPSHOT.zip"
public static final String YARN_1_17_URL = "https://maven.fabricmc.net/net/fabricmc/yarn/1.17%2Bbuild.13/yarn-1.17%2Bbuild.13-v2.jar"
}

Binary file not shown.