Skip to content

Commit

Permalink
Split mods.toml parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
shedaniel committed Nov 13, 2023
1 parent ad9f241 commit ede0495
Show file tree
Hide file tree
Showing 10 changed files with 157 additions and 51 deletions.
29 changes: 29 additions & 0 deletions src/main/java/dev/architectury/loom/metadata/ForgeModsToml.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package dev.architectury.loom.metadata;

import java.io.File;
import java.io.IOException;
import java.nio.file.Path;

import com.electronwill.nightconfig.core.Config;

public final class ForgeModsToml extends ModsToml {
private ForgeModsToml(Config config) {
super(config);
}

public static ForgeModsToml of(byte[] utf8) {
return of(utf8, ForgeModsToml::new);
}

public static ForgeModsToml of(String text) {
return of(text, ForgeModsToml::new);
}

public static ForgeModsToml of(Path path) throws IOException {
return of(path, ForgeModsToml::new);
}

public static ForgeModsToml of(File file) throws IOException {
return of(file.toPath(), ForgeModsToml::new);
}
}
72 changes: 50 additions & 22 deletions src/main/java/dev/architectury/loom/metadata/ModMetadataFiles.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;

import com.google.common.collect.ImmutableMap;
Expand All @@ -14,6 +13,7 @@
import org.gradle.api.tasks.SourceSet;
import org.jetbrains.annotations.Nullable;

import net.fabricmc.loom.util.ModPlatform;
import net.fabricmc.loom.util.ZipUtils;
import net.fabricmc.loom.util.gradle.SourceSetHelper;

Expand All @@ -22,35 +22,27 @@
*/
public final class ModMetadataFiles {
private static final Logger LOGGER = Logging.getLogger(ModMetadataFiles.class);
private static final Map<String, Function<byte[], ModMetadataFile>> SINGLE_FILE_METADATA_TYPES = ImmutableMap.<String, Function<byte[], ModMetadataFile>>builder()
.put(QuiltModJson.FILE_NAME, QuiltModJson::of)
.put(ArchitecturyCommonJson.FILE_NAME, ArchitecturyCommonJson::of)
.put(ModsToml.FILE_PATH, onError(ModsToml::of, "Could not load mods.toml", () -> new ErroringModMetadataFile("mods.toml")))
private static final Map<String, MetadataFileProvider> SINGLE_FILE_METADATA_TYPES = ImmutableMap.<String, MetadataFileProvider>builder()
.put(QuiltModJson.FILE_NAME, MetadataFileProvider.withPlatform((bytes, platform) -> QuiltModJson.of(bytes), ModPlatform.QUILT))
.put(ArchitecturyCommonJson.FILE_NAME, (bytes, platform) -> ArchitecturyCommonJson.of(bytes))
.put(ModsToml.FILE_PATH, MetadataFileProvider.concat(
MetadataFileProvider.withPlatform((bytes, platform) -> ForgeModsToml.of(bytes), ModPlatform.FORGE),
MetadataFileProvider.withPlatform((bytes, platform) -> NeoForgeModsToml.of(bytes), ModPlatform.NEOFORGE)
).onError("Could not load mods.toml", () -> new ErroringModMetadataFile("mods.toml")))
.build();

private static <A, B> Function<A, B> onError(Function<A, B> fn, String message, Supplier<B> onError) {
return a -> {
try {
return fn.apply(a);
} catch (Exception e) {
LOGGER.info(message, e);
return onError.get();
}
};
}

/**
* Reads the mod metadata file from a jar.
*
* @param jar the path to the jar file
* @return the mod metadata file, or {@code null} if not found
*/
public static @Nullable ModMetadataFile fromJar(Path jar) throws IOException {
public static @Nullable ModMetadataFile fromJar(Path jar, @Nullable ModPlatform platform) throws IOException {
for (final String filePath : SINGLE_FILE_METADATA_TYPES.keySet()) {
final byte @Nullable [] bytes = ZipUtils.unpackNullable(jar, filePath);

if (bytes != null) {
return SINGLE_FILE_METADATA_TYPES.get(filePath).apply(bytes);
return SINGLE_FILE_METADATA_TYPES.get(filePath).apply(bytes, platform);
}
}

Expand All @@ -63,12 +55,12 @@ private static <A, B> Function<A, B> onError(Function<A, B> fn, String message,
* @param directory the path to the directory
* @return the mod metadata file, or {@code null} if not found
*/
public static @Nullable ModMetadataFile fromDirectory(Path directory) throws IOException {
public static @Nullable ModMetadataFile fromDirectory(Path directory, @Nullable ModPlatform platform) throws IOException {
for (final String filePath : SINGLE_FILE_METADATA_TYPES.keySet()) {
final Path metadataPath = directory.resolve(filePath);

if (Files.exists(metadataPath)) {
return SINGLE_FILE_METADATA_TYPES.get(filePath).apply(Files.readAllBytes(metadataPath));
return SINGLE_FILE_METADATA_TYPES.get(filePath).apply(Files.readAllBytes(metadataPath), platform);
}
}

Expand All @@ -81,15 +73,51 @@ private static <A, B> Function<A, B> onError(Function<A, B> fn, String message,
* @param sourceSets the source sets to read from
* @return the mod metadata file, or {@code null} if not found
*/
public static @Nullable ModMetadataFile fromSourceSets(SourceSet... sourceSets) throws IOException {
public static @Nullable ModMetadataFile fromSourceSets(@Nullable ModPlatform platform, SourceSet... sourceSets) throws IOException {
for (final String filePath : SINGLE_FILE_METADATA_TYPES.keySet()) {
final @Nullable File file = SourceSetHelper.findFirstFileInResource(filePath, sourceSets);

if (file != null) {
return SINGLE_FILE_METADATA_TYPES.get(filePath).apply(Files.readAllBytes(file.toPath()));
return SINGLE_FILE_METADATA_TYPES.get(filePath).apply(Files.readAllBytes(file.toPath()), platform);
}
}

return null;
}

@FunctionalInterface
private interface MetadataFileProvider {
@Nullable
ModMetadataFile apply(byte[] bytes, @Nullable ModPlatform platform);

default MetadataFileProvider onError(String message, Supplier<ModMetadataFile> onError) {
MetadataFileProvider provider = this;
return (bytes, platform) -> {
try {
return provider.apply(bytes, platform);
} catch (Exception e) {
LOGGER.info(message, e);
return onError.get();
}
};
}

static MetadataFileProvider withPlatform(MetadataFileProvider provider, ModPlatform requiredPlatform) {
return (bytes, platform) -> {
if (requiredPlatform != platform) return null;
return provider.apply(bytes, platform);
};
}

static MetadataFileProvider concat(MetadataFileProvider... providers) {
return (bytes, platform) -> {
for (MetadataFileProvider provider : providers) {
ModMetadataFile file = provider.apply(bytes, platform);
if (file != null) return file;
}

return null;
};
}
}
}
23 changes: 12 additions & 11 deletions src/main/java/dev/architectury/loom/metadata/ModsToml.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;

import com.electronwill.nightconfig.core.Config;
import com.electronwill.nightconfig.core.io.ParsingException;
Expand All @@ -20,36 +21,36 @@
import net.fabricmc.loom.configuration.ifaceinject.InterfaceInjectionProcessor;
import net.fabricmc.loom.util.ExceptionUtil;

public final class ModsToml implements ModMetadataFile {
public abstract sealed class ModsToml implements ModMetadataFile permits ForgeModsToml, NeoForgeModsToml {
public static final String FILE_PATH = "META-INF/mods.toml";
private final Config config;
protected final Config config;

private ModsToml(Config config) {
protected ModsToml(Config config) {
this.config = Objects.requireNonNull(config);
}

public static ModsToml of(byte[] utf8) {
return of(new String(utf8, StandardCharsets.UTF_8));
static <T extends ModsToml> T of(byte[] utf8, Function<Config, T> constructor) {
return of(new String(utf8, StandardCharsets.UTF_8), constructor);
}

public static ModsToml of(String text) {
static <T extends ModsToml> T of(String text, Function<Config, T> constructor) {
try {
return new ModsToml(new TomlParser().parse(text));
return constructor.apply(new TomlParser().parse(text));
} catch (ParsingException e) {
throw ExceptionUtil.createDescriptiveWrapper(IllegalArgumentException::new, "Could not parse mods.toml", e);
}
}

public static ModsToml of(Path path) throws IOException {
static <T extends ModsToml> T of(Path path, Function<Config, T> constructor) throws IOException {
try (BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
return new ModsToml(new TomlParser().parse(reader));
return constructor.apply(new TomlParser().parse(reader));
} catch (ParsingException e) {
throw ExceptionUtil.createDescriptiveWrapper(IllegalArgumentException::new, "Could not parse mods.toml", e);
}
}

public static ModsToml of(File file) throws IOException {
return of(file.toPath());
static <T extends ModsToml> T of(File file, Function<Config, T> constructor) throws IOException {
return of(file.toPath(), constructor);
}

@Override
Expand Down
47 changes: 47 additions & 0 deletions src/main/java/dev/architectury/loom/metadata/NeoForgeModsToml.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package dev.architectury.loom.metadata;

import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
import java.util.Optional;

import com.electronwill.nightconfig.core.Config;
import com.google.common.collect.ImmutableList;

public final class NeoForgeModsToml extends ModsToml {
private NeoForgeModsToml(Config config) {
super(config);
}

public static NeoForgeModsToml of(byte[] utf8) {
return of(utf8, NeoForgeModsToml::new);
}

public static NeoForgeModsToml of(String text) {
return of(text, NeoForgeModsToml::new);
}

public static NeoForgeModsToml of(Path path) throws IOException {
return of(path, NeoForgeModsToml::new);
}

public static NeoForgeModsToml of(File file) throws IOException {
return of(file.toPath(), NeoForgeModsToml::new);
}

@Override
public List<String> getMixinConfigs() {
Optional<List<Config>> mixins = config.getOptional("mixins");
if (mixins.isEmpty()) return List.of();

final ImmutableList.Builder<String> configs = ImmutableList.builder();

for (final Config mixin : mixins.get()) {
final Optional<String> config = mixin.getOptional("config");
config.ifPresent(configs::add);
}

return configs.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import dev.architectury.loom.metadata.ModMetadataFile;
import dev.architectury.loom.metadata.ModMetadataFiles;

import net.fabricmc.loom.util.ModPlatform;
import net.fabricmc.loom.util.ZipUtils;
import net.fabricmc.loom.util.function.CollectionUtil;

Expand All @@ -48,7 +49,7 @@ public record AccessWidenerFile(
/**
* Reads the access-widener contained in a mod jar, or returns null if there is none.
*/
public static AccessWidenerFile fromModJar(Path modJarPath) {
public static AccessWidenerFile fromModJar(Path modJarPath, ModPlatform platform) {
byte[] modJsonBytes;

try {
Expand All @@ -62,7 +63,7 @@ public static AccessWidenerFile fromModJar(Path modJarPath) {
String awPath;

try {
modMetadata = ModMetadataFiles.fromJar(modJarPath);
modMetadata = ModMetadataFiles.fromJar(modJarPath, platform);

if (modMetadata != null) {
final Set<String> accessWideners = modMetadata.getAccessWideners();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public static AccessWidenerData readAccessWidenerData(Path inputJar, ModPlatform
return null;
}

final FabricModJson fabricModJson = FabricModJsonFactory.createFromZip(inputJar);
final FabricModJson fabricModJson = FabricModJsonFactory.createFromZip(inputJar, platform);
final List<String> classTweakers = List.copyOf(fabricModJson.getClassTweakers().keySet());

if (classTweakers.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ private static List<FabricModJson> getDependentMods(Project project) {
final Set<File> artifacts = entry.getSourceConfiguration().get().resolve();

for (File artifact : artifacts) {
final FabricModJson fabricModJson = FabricModJsonFactory.createFromZipNullable(artifact.toPath());
final FabricModJson fabricModJson = FabricModJsonFactory.createFromZipNullable(artifact.toPath(), extension.getPlatform().get());

if (fabricModJson != null) {
mods.add(fabricModJson);
Expand Down Expand Up @@ -118,7 +118,7 @@ private static Stream<FabricModJson> getCompileRuntimeModsFromRemapConfigs(Proje
.filter(settings -> settings.getApplyDependencyTransforms().get())
.flatMap(resolveArtifacts(project, false))
.filter(runtimeEntries::contains) // Use the intersection of the two configurations.
.map(FabricModJsonFactory::createFromZipOptional)
.map(zipPath -> FabricModJsonFactory.createFromZipOptional(zipPath, extension.getPlatform().get()))
.filter(Optional::isPresent)
.map(Optional::get)
.sorted(Comparator.comparing(FabricModJson::getId));
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/net/fabricmc/loom/task/RemapJarTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ private void setupLegacyMixinRefmapRemapping(RemapParams params) {
final MixinExtension mixinExtension = extension.getMixin();

final Collection<String> allMixinConfigs = new LinkedHashSet<>();
final FabricModJson fabricModJson = FabricModJsonFactory.createFromZipNullable(getInputFile().getAsFile().get().toPath());
final FabricModJson fabricModJson = FabricModJsonFactory.createFromZipNullable(getInputFile().getAsFile().get().toPath(), extension.getPlatform().get());

if (fabricModJson != null) {
allMixinConfigs.addAll(fabricModJson.getMixinConfigurations());
Expand Down Expand Up @@ -395,7 +395,7 @@ private boolean injectAccessWidener() throws IOException {
}

private void remapAccessWidener() throws IOException {
final AccessWidenerFile accessWidenerFile = AccessWidenerFile.fromModJar(inputFile);
final AccessWidenerFile accessWidenerFile = AccessWidenerFile.fromModJar(inputFile, getParameters().getPlatform().get());

if (accessWidenerFile == null) {
return;
Expand Down
Loading

0 comments on commit ede0495

Please sign in to comment.