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 reviewsdev/0.11
parent
287e6cefb9
commit
5dda747cee
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
* 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
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* 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 java.util.Locale;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The standard namespaces used by loom.
|
* The standard namespaces used by loom.
|
||||||
*/
|
*/
|
||||||
|
@ -49,6 +51,21 @@ public enum MappingsNamespace {
|
||||||
*/
|
*/
|
||||||
NAMED;
|
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
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return name().toLowerCase(Locale.ROOT);
|
return name().toLowerCase(Locale.ROOT);
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
* 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
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* 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:
|
* <p>The parameter will be evaluated like this:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>{@link File}, {@link Path} and {@link FileSystemLocation} will be resolved as local files</li>
|
* <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 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>{@link Dependency} will be resolved as any dependency</li>
|
||||||
|
* <li>{@code FileSpec} will just return the spec itself</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @param o the file notation
|
* @param o the file notation
|
||||||
|
@ -73,6 +74,8 @@ public interface FileSpec {
|
||||||
return createFromFile(p);
|
return createFromFile(p);
|
||||||
} else if (o instanceof FileSystemLocation l) {
|
} else if (o instanceof FileSystemLocation l) {
|
||||||
return createFromFile(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());
|
throw new UnsupportedOperationException("Cannot create FileSpec from object of type:" + o.getClass().getCanonicalName());
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
* 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
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -77,4 +77,40 @@ public interface LayeredMappingSpecBuilder {
|
||||||
*/
|
*/
|
||||||
@ApiStatus.Experimental
|
@ApiStatus.Experimental
|
||||||
LayeredMappingSpecBuilder signatureFix(Object object);
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,12 +30,14 @@ import java.util.List;
|
||||||
|
|
||||||
import org.gradle.api.Action;
|
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.FileSpec;
|
||||||
import net.fabricmc.loom.api.mappings.layered.spec.LayeredMappingSpecBuilder;
|
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.MappingsSpec;
|
||||||
import net.fabricmc.loom.api.mappings.layered.spec.MojangMappingsSpecBuilder;
|
import net.fabricmc.loom.api.mappings.layered.spec.MojangMappingsSpecBuilder;
|
||||||
import net.fabricmc.loom.api.mappings.layered.spec.ParchmentMappingsSpecBuilder;
|
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.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.intermediary.IntermediaryMappingsSpec;
|
||||||
import net.fabricmc.loom.configuration.providers.mappings.mojmap.MojangMappingsSpecBuilderImpl;
|
import net.fabricmc.loom.configuration.providers.mappings.mojmap.MojangMappingsSpecBuilderImpl;
|
||||||
import net.fabricmc.loom.configuration.providers.mappings.parchment.ParchmentMappingsSpecBuilderImpl;
|
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)));
|
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() {
|
public LayeredMappingSpec build() {
|
||||||
List<MappingsSpec<?>> builtLayers = new LinkedList<>();
|
List<MappingsSpec<?>> builtLayers = new LinkedList<>();
|
||||||
// Intermediary is always the base layer
|
// Intermediary is always the base layer
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,6 +25,7 @@
|
||||||
package net.fabricmc.loom.util;
|
package net.fabricmc.loom.util;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.DataInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.UncheckedIOException;
|
import java.io.UncheckedIOException;
|
||||||
|
@ -47,6 +48,22 @@ import org.jetbrains.annotations.Nullable;
|
||||||
import net.fabricmc.loom.LoomGradlePlugin;
|
import net.fabricmc.loom.LoomGradlePlugin;
|
||||||
|
|
||||||
public class ZipUtils {
|
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) {
|
public static boolean contains(Path zip, String path) {
|
||||||
try (FileSystemUtil.Delegate fs = FileSystemUtil.getJarFileSystem(zip, false)) {
|
try (FileSystemUtil.Delegate fs = FileSystemUtil.getJarFileSystem(zip, false)) {
|
||||||
Path fsPath = fs.get().getPath(path);
|
Path fsPath = fs.get().getPath(path);
|
||||||
|
|
|
@ -121,4 +121,32 @@ class ZipUtilsTest extends Specification {
|
||||||
outputFile.exists()
|
outputFile.exists()
|
||||||
outputFile.text == "This is a test of unpacking all"
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
package net.fabricmc.loom.test.unit.layeredmappings
|
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.utils.MavenFileSpec
|
||||||
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpec
|
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpec
|
||||||
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpecBuilderImpl
|
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpecBuilderImpl
|
||||||
|
@ -106,6 +107,20 @@ class LayeredMappingSpecBuilderTest extends Specification {
|
||||||
parchment.removePrefix() == false
|
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) {
|
LayeredMappingSpec layered(@DelegatesTo(LayeredMappingSpecBuilderImpl) Closure cl) {
|
||||||
LayeredMappingSpecBuilderImpl builder = new LayeredMappingSpecBuilderImpl()
|
LayeredMappingSpecBuilderImpl builder = new LayeredMappingSpecBuilderImpl()
|
||||||
new ClosureAction(cl).execute(builder)
|
new ClosureAction(cl).execute(builder)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
* 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
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* 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_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 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.
Loading…
Reference in New Issue