Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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 @@ -26,6 +26,7 @@

import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Optional;

/**
* Represents the settings for data generation.
Expand Down Expand Up @@ -67,4 +68,11 @@ public interface DataGenerationSettings {
* Contains a boolean property indicating whether data generation will be compiled and ran with the client.
*/
Property<Boolean> getClient();

/**
* Contains the location of a `fabric.mod.json` file used for data generation.
* If unset, the file in the root resources of the respective source set is used.
*/
@Optional
RegularFileProperty getFabricModJsonPath();
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

package net.fabricmc.loom.api.fabricapi;

import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Optional;
import org.jetbrains.annotations.ApiStatus;
Expand Down Expand Up @@ -89,4 +90,11 @@ public interface GameTestSettings {
*/
@Optional
Property<String> getUsername();

/**
* Contains the location of a `fabric.mod.json` file used for the game test.
* If unset, the file in the root resources of the respective source set is used.
*/
@Optional
RegularFileProperty getFabricModJsonPath();
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,21 @@

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.file.RegularFileProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.SourceSetContainer;

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 @@ -46,6 +47,8 @@ abstract class FabricApiAbstractSourceSet {

protected abstract String getSourceSetName();

protected abstract RegularFileProperty getFabricModJsonPath();

protected SourceSet configureSourceSet(Property<String> modId, boolean isClient) {
final LoomGradleExtension extension = LoomGradleExtension.get(getProject());
final SourceSet mainSourceSet = SourceSetHelper.getMainSourceSet(getProject());
Expand All @@ -64,17 +67,14 @@ protected SourceSet configureSourceSet(Property<String> modId, boolean isClient)
});

modId.convention(getProject().provider(() -> {
try {
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()");
}
List<FabricModJson> fabricModJsons = FabricModJsonHelpers
.getModsInProject(getProject(), getFabricModJsonPath().getAsFile(), sourceSet);

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()) {
throw new RuntimeException("Could not find a fabric.mod.json file in the data source set or a value for DataGenerationSettings.getModId()");
}

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

extension.getMods().create(modId.get(), mod -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ void configureDataGeneration(Action<DataGenerationSettings> action) {
settings.getClient().convention(false);

action.execute(settings);
getFabricModJsonPath().set(settings.getFabricModJsonPath());

final SourceSet mainSourceSet = SourceSetHelper.getMainSourceSet(getProject());
final File outputDirectory = settings.getOutputDirectory().getAsFile().get();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ void configureTests(Action<GameTestSettings> action) {
settings.getUsername().convention("Player0");

action.execute(settings);
getFabricModJsonPath().set(settings.getFabricModJsonPath());

final SourceSet testSourceSet;

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
26 changes: 23 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 @@ -38,6 +38,7 @@
import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import org.gradle.api.Project;
import org.gradle.api.provider.Provider;
import org.gradle.api.tasks.SourceSet;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.VisibleForTesting;
Expand Down Expand Up @@ -107,10 +108,30 @@ public static Optional<FabricModJson> createFromZipOptional(Path zipPath) {
return Optional.ofNullable(createFromZipNullable(zipPath));
}

@Nullable
public static FabricModJson createFromOverrideNullable(Provider<File> fileProvider) throws IOException {
var file = fileProvider.getOrNull();
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 +142,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.provider.Provider;
import org.gradle.api.tasks.SourceSet;

import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.util.gradle.SourceSetHelper;

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, 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, Provider<File> overrideFile, SourceSet... sourceSets) {
Copy link
Member

Choose a reason for hiding this comment

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

Why is this needed? Can you just not always get it from the extension? I dont get why this is needed in the fabricapi extension?

try {
var fabricModJson = overrideFile.isPresent()
? 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"]
}
}
}
Loading