mirror of
https://github.com/architectury/architectury-loom.git
synced 2026-04-02 13:37:45 -05:00
Make fabric.mod.json path configurable at configuration stage. (#1364)
* Add `fabric.mod.json` path property. * Add path provider integration tests. * Separate fabric.mod.json reading methods and move selection to the helper method. * Separate FMJ getter methods and add configuration to datagen and testmod settings. * Remove the `fabricModJsonPath` property from Fabric API source sets * Address review requests by fixing formatting and removing redundant changes * Fix build * Move tests to existing file, and remove var usage. * Fix build :) --------- Co-authored-by: modmuss50 <modmuss50@gmail.com>
This commit is contained in:
@@ -66,6 +66,22 @@ public interface LoomGradleExtensionAPI {
|
||||
|
||||
RegularFileProperty getAccessWidenerPath();
|
||||
|
||||
/**
|
||||
* Specifies the {@code fabric.mod.json} file location used in injected interface processing.
|
||||
*
|
||||
* <p>
|
||||
* By default, either {@code src/main/resources/fabric.mod.json}
|
||||
* or {@code src/client/resources/fabric.mod.json} in the project directory is used.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Providing a path to a different location allows using a shared or preprocessed
|
||||
* file. However, at the end it must be put into the root of the processed
|
||||
* resources directory (usually {@code build/resources/main}).
|
||||
* </p>
|
||||
*/
|
||||
RegularFileProperty getFabricModJsonPath();
|
||||
|
||||
NamedDomainObjectContainer<DecompilerOptions> getDecompilerOptions();
|
||||
|
||||
void decompilers(Action<NamedDomainObjectContainer<DecompilerOptions>> action);
|
||||
|
||||
@@ -24,9 +24,13 @@
|
||||
|
||||
package net.fabricmc.loom.api.fabricapi;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.gradle.api.file.RegularFileProperty;
|
||||
import org.gradle.api.provider.Property;
|
||||
|
||||
import net.fabricmc.loom.util.fmj.FabricModJsonFactory;
|
||||
|
||||
/**
|
||||
* Represents the settings for data generation.
|
||||
*/
|
||||
@@ -67,4 +71,11 @@ public interface DataGenerationSettings {
|
||||
* Contains a boolean property indicating whether data generation will be compiled and ran with the client.
|
||||
*/
|
||||
Property<Boolean> getClient();
|
||||
|
||||
/**
|
||||
* Sets {@link #getModId()} property based on the {@code id} field defined in the provided file.
|
||||
*/
|
||||
default void modId(File fabricModJsonFile) {
|
||||
getModId().set(FabricModJsonFactory.createFromFile(fabricModJsonFile).getId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,10 +24,14 @@
|
||||
|
||||
package net.fabricmc.loom.api.fabricapi;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.tasks.Optional;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import net.fabricmc.loom.util.fmj.FabricModJsonFactory;
|
||||
|
||||
/**
|
||||
* Represents the settings for game and/or client tests.
|
||||
*/
|
||||
@@ -89,4 +93,11 @@ public interface GameTestSettings {
|
||||
*/
|
||||
@Optional
|
||||
Property<String> getUsername();
|
||||
|
||||
/**
|
||||
* Sets {@link #getModId()} property based on the {@code id} field defined in the provided file.
|
||||
*/
|
||||
default void modId(File fabricModJsonFile) {
|
||||
getModId().set(FabricModJsonFactory.createFromFile(fabricModJsonFile).getId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,6 @@
|
||||
|
||||
package net.fabricmc.loom.configuration.fabricapi;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
@@ -64,17 +62,13 @@ abstract class FabricApiAbstractSourceSet {
|
||||
});
|
||||
|
||||
modId.convention(getProject().provider(() -> {
|
||||
try {
|
||||
final FabricModJson fabricModJson = FabricModJsonFactory.createFromSourceSetsNullable(getProject(), sourceSet);
|
||||
final FabricModJson fabricModJson = FabricModJsonFactory.createFromSourceSetsNullable(getProject(), sourceSet);
|
||||
|
||||
if (fabricModJson == null) {
|
||||
throw new RuntimeException("Could not find a fabric.mod.json file in the data source set or a value for DataGenerationSettings.getModId()");
|
||||
}
|
||||
|
||||
return fabricModJson.getId();
|
||||
} catch (IOException e) {
|
||||
throw new org.gradle.api.UncheckedIOException("Failed to read mod id from the datagen source set.", e);
|
||||
if (fabricModJson == null) {
|
||||
throw new RuntimeException("Could not find a fabric.mod.json file in the data source set or a value for DataGenerationSettings.getModId()");
|
||||
}
|
||||
|
||||
return fabricModJson.getId();
|
||||
}));
|
||||
|
||||
extension.getMods().create(modId.get(), mod -> {
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
package net.fabricmc.loom.extension;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -34,7 +34,6 @@ import org.gradle.api.Action;
|
||||
import org.gradle.api.NamedDomainObjectContainer;
|
||||
import org.gradle.api.NamedDomainObjectList;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.UncheckedIOException;
|
||||
import org.gradle.api.artifacts.Dependency;
|
||||
import org.gradle.api.file.ConfigurableFileCollection;
|
||||
import org.gradle.api.file.FileCollection;
|
||||
@@ -74,7 +73,7 @@ import net.fabricmc.loom.task.GenerateSourcesTask;
|
||||
import net.fabricmc.loom.util.DeprecationHelper;
|
||||
import net.fabricmc.loom.util.MirrorUtil;
|
||||
import net.fabricmc.loom.util.fmj.FabricModJson;
|
||||
import net.fabricmc.loom.util.fmj.FabricModJsonFactory;
|
||||
import net.fabricmc.loom.util.fmj.FabricModJsonHelpers;
|
||||
import net.fabricmc.loom.util.gradle.SourceSetHelper;
|
||||
|
||||
/**
|
||||
@@ -86,6 +85,7 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
|
||||
protected final ListProperty<JarProcessor> jarProcessors;
|
||||
protected final ConfigurableFileCollection log4jConfigs;
|
||||
protected final RegularFileProperty accessWidener;
|
||||
protected final RegularFileProperty fabricModJsonPath;
|
||||
protected final ManifestLocations versionsManifests;
|
||||
protected final Property<String> customMetadata;
|
||||
protected final SetProperty<String> knownIndyBsms;
|
||||
@@ -118,6 +118,7 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
|
||||
.empty();
|
||||
this.log4jConfigs = project.files(directories.getDefaultLog4jConfigFile());
|
||||
this.accessWidener = project.getObjects().fileProperty();
|
||||
this.fabricModJsonPath = project.getObjects().fileProperty();
|
||||
this.versionsManifests = new ManifestLocations();
|
||||
this.versionsManifests.add("mojang", MirrorUtil.getVersionManifests(project), -2);
|
||||
this.versionsManifests.add("fabric_experimental", MirrorUtil.getExperimentalVersions(project), -1);
|
||||
@@ -205,6 +206,11 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
|
||||
return accessWidener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegularFileProperty getFabricModJsonPath() {
|
||||
return fabricModJsonPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamedDomainObjectContainer<DecompilerOptions> getDecompilerOptions() {
|
||||
return decompilers;
|
||||
@@ -293,17 +299,13 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
|
||||
|
||||
@Override
|
||||
public String getModVersion() {
|
||||
try {
|
||||
final FabricModJson fabricModJson = FabricModJsonFactory.createFromSourceSetsNullable(getProject(), SourceSetHelper.getMainSourceSet(getProject()));
|
||||
List<FabricModJson> fabricModJsons = FabricModJsonHelpers.getModsInProject(getProject());
|
||||
|
||||
if (fabricModJson == null) {
|
||||
throw new RuntimeException("Could not find a fabric.mod.json file in the main sourceset");
|
||||
}
|
||||
|
||||
return fabricModJson.getModVersion();
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to read mod version from main sourceset.", e);
|
||||
if (fabricModJsons.isEmpty()) {
|
||||
throw new RuntimeException("Could not find a fabric.mod.json file in the main sourceset");
|
||||
}
|
||||
|
||||
return fabricModJsons.getFirst().getModVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -107,27 +107,38 @@ public final class FabricModJsonFactory {
|
||||
return Optional.ofNullable(createFromZipNullable(zipPath));
|
||||
}
|
||||
|
||||
public static FabricModJson createFromFile(File file) {
|
||||
JsonObject modJson = readFmjJsonObject(file);
|
||||
return create(modJson, new FabricModJsonSource.DirectorySource(file.toPath().getParent()));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static FabricModJson createFromSourceSetsNullable(Project project, SourceSet... sourceSets) throws IOException {
|
||||
final File file = SourceSetHelper.findFirstFileInResource(FABRIC_MOD_JSON, project, sourceSets);
|
||||
public static FabricModJson createFromSourceSetsNullable(Project project, SourceSet... sourceSets) {
|
||||
File file = SourceSetHelper.findFirstFileInResource(FABRIC_MOD_JSON, project, sourceSets);
|
||||
|
||||
if (file == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
JsonObject modJson = readFmjJsonObject(file);
|
||||
return create(modJson, new FabricModJsonSource.SourceSetSource(project, sourceSets));
|
||||
} catch (JsonSyntaxException e) {
|
||||
LOGGER.warn("Failed to parse fabric.mod.json: {}", file.getAbsolutePath());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static JsonObject readFmjJsonObject(File file) {
|
||||
try (Reader reader = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8)) {
|
||||
final JsonObject modJson = LoomGradlePlugin.GSON.fromJson(reader, JsonObject.class);
|
||||
|
||||
if (modJson == null) {
|
||||
// fromJson returns null if the file is empty
|
||||
LOGGER.warn("Failed to parse empty fabric.mod.json: {}", file.getAbsolutePath());
|
||||
return null;
|
||||
}
|
||||
|
||||
return create(modJson, new FabricModJsonSource.SourceSetSource(project, sourceSets));
|
||||
} catch (JsonSyntaxException e) {
|
||||
LOGGER.warn("Failed to parse fabric.mod.json: {}", file.getAbsolutePath());
|
||||
return null;
|
||||
return modJson;
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to read " + file.getAbsolutePath(), e);
|
||||
}
|
||||
|
||||
@@ -24,22 +24,32 @@
|
||||
|
||||
package net.fabricmc.loom.util.fmj;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.provider.Provider;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.api.LoomGradleExtensionAPI;
|
||||
import net.fabricmc.loom.util.gradle.SourceSetHelper;
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
|
||||
public class FabricModJsonHelpers {
|
||||
// Returns a list of Mods found in the provided project's main or client sourcesets
|
||||
/**
|
||||
* Returns the list of mods provided by either {@link LoomGradleExtensionAPI#getFabricModJsonPath()}
|
||||
* or {@code fabric.mod.json} in main or client resources.
|
||||
*/
|
||||
public static List<FabricModJson> getModsInProject(Project project) {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
Provider<File> overrideFile = extension.getFabricModJsonPath().getAsFile();
|
||||
|
||||
if (overrideFile.isPresent()) {
|
||||
return List.of(FabricModJsonFactory.createFromFile(overrideFile.get()));
|
||||
}
|
||||
|
||||
var sourceSets = new ArrayList<SourceSet>();
|
||||
sourceSets.add(SourceSetHelper.getMainSourceSet(project));
|
||||
|
||||
@@ -47,14 +57,10 @@ public class FabricModJsonHelpers {
|
||||
sourceSets.add(SourceSetHelper.getSourceSetByName("client", project));
|
||||
}
|
||||
|
||||
try {
|
||||
final FabricModJson fabricModJson = FabricModJsonFactory.createFromSourceSetsNullable(project, sourceSets.toArray(SourceSet[]::new));
|
||||
final FabricModJson fabricModJson = FabricModJsonFactory.createFromSourceSetsNullable(project, sourceSets.toArray(SourceSet[]::new));
|
||||
|
||||
if (fabricModJson != null) {
|
||||
return List.of(fabricModJson);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
if (fabricModJson != null) {
|
||||
return List.of(fabricModJson);
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
package net.fabricmc.loom.test.integration
|
||||
|
||||
import org.gradle.testkit.runner.BuildResult
|
||||
import spock.lang.Specification
|
||||
import spock.lang.Unroll
|
||||
|
||||
@@ -49,4 +50,34 @@ class InterfaceInjectionTest extends Specification implements GradleProjectTestT
|
||||
where:
|
||||
version << STANDARD_TEST_VERSIONS
|
||||
}
|
||||
|
||||
@Unroll
|
||||
def "Resolve custom FMJ"() {
|
||||
setup:
|
||||
GradleProject gradle = gradleProject(project: "fmjPathConfig", version: version)
|
||||
|
||||
when:
|
||||
BuildResult result = gradle.run(task: "build", args: ["-PoverrideFMJ=true"])
|
||||
|
||||
then:
|
||||
result.task(":build").outcome == SUCCESS
|
||||
|
||||
where:
|
||||
version << STANDARD_TEST_VERSIONS
|
||||
}
|
||||
|
||||
@Unroll
|
||||
def "Fail to find FMJ"() {
|
||||
setup:
|
||||
GradleProject gradle = gradleProject(project: "fmjPathConfig", version: version)
|
||||
|
||||
when:
|
||||
BuildResult result = gradle.run(task: "build", expectFailure: true)
|
||||
|
||||
then:
|
||||
result.task(":build") == null
|
||||
|
||||
where:
|
||||
version << STANDARD_TEST_VERSIONS
|
||||
}
|
||||
}
|
||||
|
||||
37
src/test/resources/projects/fmjPathConfig/build.gradle
Normal file
37
src/test/resources/projects/fmjPathConfig/build.gradle
Normal file
@@ -0,0 +1,37 @@
|
||||
// This is used by a range of tests that append to this file before running the gradle tasks.
|
||||
// Can be used for tests that require minimal custom setup
|
||||
plugins {
|
||||
id 'fabric-loom'
|
||||
id 'maven-publish'
|
||||
}
|
||||
|
||||
version = "1.0.0"
|
||||
group = "com.example"
|
||||
|
||||
// In multi-version setup this would be a separate project,
|
||||
// but a source set will suffice for a test.
|
||||
sourceSets {
|
||||
custom {
|
||||
}
|
||||
main {
|
||||
compileClasspath += sourceSets.custom.compileClasspath
|
||||
runtimeClasspath += sourceSets.custom.runtimeClasspath
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
dependencies {
|
||||
minecraft "com.mojang:minecraft:1.17.1"
|
||||
mappings "net.fabricmc:yarn:1.17.1+build.59:v2"
|
||||
modImplementation "net.fabricmc:fabric-loader:0.11.6"
|
||||
}
|
||||
|
||||
base {
|
||||
archivesName = "fabric-example-mod"
|
||||
}
|
||||
|
||||
if (project.hasProperty("overrideFMJ")) {
|
||||
loom {
|
||||
fabricModJsonPath = file("src/custom/resources/fabric.mod.json")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "testmod",
|
||||
"version": "1",
|
||||
"name": "Test Mod",
|
||||
"custom": {
|
||||
"loom:injected_interfaces": {
|
||||
"net/minecraft/class_310": ["InjectedInterface"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
|
||||
public class ExampleMod implements ModInitializer {
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
MinecraftClient.getInstance().newMethodThatDidNotExist();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
public interface InjectedInterface {
|
||||
default void newMethodThatDidNotExist() {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user