Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ public interface LoomGradleExtensionAPI {

RegularFileProperty getAccessWidenerPath();

RegularFileProperty getFabricModJsonPath();

NamedDomainObjectContainer<DecompilerOptions> getDecompilerOptions();

void decompilers(Action<NamedDomainObjectContainer<DecompilerOptions>> action);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,14 @@

package net.fabricmc.loom.api.fabricapi;

import net.fabricmc.loom.util.fmj.FabricModJsonFactory;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.provider.Property;

import java.io.File;
import java.io.IOException;
import java.util.Objects;

/**
* Represents the settings for data generation.
*/
Expand Down Expand Up @@ -67,4 +72,15 @@ 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) {
try {
getModId().set(Objects.requireNonNull(FabricModJsonFactory.createFromOverrideNullable(fabricModJsonFile)).getId());
} catch (IOException | NullPointerException e) {
throw new RuntimeException("Failed to set mod id from %s".formatted(fabricModJsonFile), e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,15 @@

package net.fabricmc.loom.api.fabricapi;

import net.fabricmc.loom.util.fmj.FabricModJsonFactory;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Optional;
import org.jetbrains.annotations.ApiStatus;

import java.io.File;
import java.io.IOException;
import java.util.Objects;

/**
* Represents the settings for game and/or client tests.
*/
Expand Down Expand Up @@ -89,4 +94,15 @@ 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) {
try {
getModId().set(Objects.requireNonNull(FabricModJsonFactory.createFromOverrideNullable(fabricModJsonFile)).getId());
} catch (IOException | NullPointerException e) {
throw new RuntimeException("Failed to set mod id from %s".formatted(fabricModJsonFile), e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@

package net.fabricmc.loom.configuration.fabricapi;

import java.io.IOException;
import java.util.List;

import javax.inject.Inject;

import net.fabricmc.loom.util.fmj.FabricModJsonHelpers;
import org.gradle.api.Project;
import org.gradle.api.artifacts.ConfigurationContainer;
import org.gradle.api.provider.Property;
Expand All @@ -37,7 +38,6 @@
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftSourceSets;
import net.fabricmc.loom.util.fmj.FabricModJson;
import net.fabricmc.loom.util.fmj.FabricModJsonFactory;
import net.fabricmc.loom.util.gradle.SourceSetHelper;

abstract class FabricApiAbstractSourceSet {
Expand All @@ -64,17 +64,14 @@ protected SourceSet configureSourceSet(Property<String> modId, boolean isClient)
});

modId.convention(getProject().provider(() -> {
try {
final FabricModJson fabricModJson = FabricModJsonFactory.createFromSourceSetsNullable(getProject(), sourceSet);
List<FabricModJson> fabricModJsons = FabricModJsonHelpers
.getModsInProject(getProject(), null, 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 (fabricModJsons.isEmpty()) {
return null;
}

return fabricModJsons.getFirst().getId();
}));

extension.getMods().create(modId.get(), mod -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@
import java.util.Map;
import java.util.Set;

import net.fabricmc.loom.util.fmj.FabricModJsonHelpers;
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;
Expand Down Expand Up @@ -73,8 +73,6 @@
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.gradle.SourceSetHelper;

/**
Expand All @@ -86,6 +84,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;
Expand Down Expand Up @@ -118,6 +117,7 @@ protected LoomGradleExtensionApiImpl(Project project, LoomFiles directories) {
.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);
Expand Down Expand Up @@ -205,6 +205,11 @@ public RegularFileProperty getAccessWidenerPath() {
return accessWidener;
}

@Override
public RegularFileProperty getFabricModJsonPath() {
return fabricModJsonPath;
}

@Override
public NamedDomainObjectContainer<DecompilerOptions> getDecompilerOptions() {
return decompilers;
Expand Down Expand Up @@ -293,17 +298,13 @@ public SetProperty<String> getKnownIndyBsms() {

@Override
public String getModVersion() {
try {
final FabricModJson fabricModJson = FabricModJsonFactory.createFromSourceSetsNullable(getProject(), SourceSetHelper.getMainSourceSet(getProject()));
var 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
Expand Down
24 changes: 21 additions & 3 deletions src/main/java/net/fabricmc/loom/util/fmj/FabricModJsonFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,29 @@ public static Optional<FabricModJson> createFromZipOptional(Path zipPath) {
return Optional.ofNullable(createFromZipNullable(zipPath));
}

@Nullable
public static FabricModJson createFromOverrideNullable(@Nullable File file) throws IOException {
var modJson = readFmjJsonObject(file);
if (modJson == null) {
return null;
}

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);
var file = SourceSetHelper.findFirstFileInResource(FABRIC_MOD_JSON, project, sourceSets);
var modJson = readFmjJsonObject(file);
if (modJson == null) {
return null;
}

return create(modJson, new FabricModJsonSource.SourceSetSource(project, sourceSets));
}

@Nullable
private static JsonObject readFmjJsonObject(@Nullable File file) {
if (file == null) {
return null;
}
Expand All @@ -121,10 +140,9 @@ public static FabricModJson createFromSourceSetsNullable(Project project, Source
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));
return modJson;
} catch (JsonSyntaxException e) {
LOGGER.warn("Failed to parse fabric.mod.json: {}", file.getAbsolutePath());
return null;
Expand Down
27 changes: 21 additions & 6 deletions src/main/java/net/fabricmc/loom/util/fmj/FabricModJsonHelpers.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,39 +24,54 @@

package net.fabricmc.loom.util.fmj;

import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import net.fabricmc.loom.api.LoomGradleExtensionAPI;
import org.gradle.api.Project;
import org.gradle.api.tasks.SourceSet;

import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.util.gradle.SourceSetHelper;
import org.jetbrains.annotations.Nullable;

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);
LoomGradleExtension extension = LoomGradleExtension.get(project);
var overrideFile = extension.getFabricModJsonPath().getAsFile();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI: I see you like to use var wherever possible, this isnt something we tend to do. In other fabric projects we disallow var other than for new instance creataion. e.g var a = new Object() is fine as you can clearly see the type. Loom doesnt enforce this as there are some places where gradle forces you to use an obtuse type, but for simple types such a File in this case I wouldnt choose to use var as it makes the code harder to read.

Dont worry about it for this PR its just a minor nit pick.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing out. I used var for consistency with the other cases I've seen in the area, but I can replace it if needed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ive done it :) I also moved the tests to one of the existing files, this is becuase each test file gets a new github actions job, there was nothing wrong with having its own file but it will be a tiny bit quicker. Im happy with this PR now :) Thanks.

var sourceSets = new ArrayList<SourceSet>();
sourceSets.add(SourceSetHelper.getMainSourceSet(project));

sourceSets.add(SourceSetHelper.getMainSourceSet(project));
if (extension.areEnvironmentSourceSetsSplit()) {
sourceSets.add(SourceSetHelper.getSourceSetByName("client", project));
}

try {
final FabricModJson fabricModJson = FabricModJsonFactory.createFromSourceSetsNullable(project, sourceSets.toArray(SourceSet[]::new));
return getModsInProject(project, overrideFile.getOrNull(), sourceSets.toArray(SourceSet[]::new));
}

/**
* Returns the list of mods provided by either {@code overrideFile} property
* or {@code fabric.mod.json} in the {@code sourceSets} array.
*/
public static List<FabricModJson> getModsInProject(Project project, @Nullable File overrideFile, SourceSet... sourceSets) {
try {
var fabricModJson = overrideFile != null
? FabricModJsonFactory.createFromOverrideNullable(overrideFile)
: FabricModJsonFactory.createFromSourceSetsNullable(project, sourceSets);
if (fabricModJson != null) {
return List.of(fabricModJson);
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}

return Collections.emptyList();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package net.fabricmc.loom.test.integration

import net.fabricmc.loom.test.util.GradleProjectTestTrait
import org.gradle.testkit.runner.BuildResult
import spock.lang.Specification
import spock.lang.Unroll

import static org.gradle.testkit.runner.TaskOutcome.SUCCESS

class FabricModJsonPathTest extends Specification implements GradleProjectTestTrait {
@Unroll
def "Resolve custom FMJ"() {
setup:
GradleProject gradle = gradleProject(project: "fmjPathConfig")

when:
BuildResult result = gradle.run(task: "build", args: ["-PoverrideFMJ=true"])

then:
result.task(":build").outcome == SUCCESS
}

@Unroll
def "Fail to find FMJ"() {
setup:
GradleProject gradle = gradleProject(project: "fmjPathConfig")

when:
BuildResult result = gradle.run(task: "build", expectFailure: true)

then:
result.task(":build") == null
}
}
38 changes: 38 additions & 0 deletions src/test/resources/projects/fmjPathConfig/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// 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")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"schemaVersion": 1,
"id": "testmod",
"version": "1",
"name": "Test Mod",
"custom": {
"loom:injected_interfaces": {
"net/minecraft/class_310": ["InjectedInterface"]
}
}
}
Original file line number Diff line number Diff line change
@@ -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();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
public interface InjectedInterface {
default void newMethodThatDidNotExist() {
}
}