From 852a3af96d28a86bf8bb257dc00534bb5b630972 Mon Sep 17 00:00:00 2001 From: Jonathing Date: Sat, 27 Dec 2025 17:03:39 -0500 Subject: [PATCH 1/6] Update Gradle to 9.3.0-rc-2 --- gradle/wrapper/gradle-wrapper.jar | Bin 45457 -> 46175 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 3 --- gradlew.bat | 3 +-- 4 files changed, 2 insertions(+), 6 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 8bdaf60c75ab801e22807dde59e12a8735a34077..61285a659d17295f1de7c53e24fdf13ad755c379 100644 GIT binary patch delta 36855 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%0Aonjyf`q#Bg+;H(_UceX22V^ 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 Date: Sat, 27 Dec 2025 17:03:56 -0500 Subject: [PATCH 2/6] Move internal implementations to inaccessible subpackage --- build.gradle | 2 +- .../gradleutils/GenerateActionsWorkflow.java | 5 +- .../gradleutils/GradleUtilsExtension.java | 52 ++++----- .../GradleUtilsExtensionForProject.java | 16 ++- .../GradleUtilsExtensionInternal.java | 56 ---------- .../minecraftforge/gradleutils/PomUtils.java | 20 ++-- .../gradleutils/PromotePublication.java | 2 +- .../gradleutils/WriteManifest.java | 14 ++- .../gradleutils/{ => internal}/Constants.java | 2 +- .../EnhancedVersionReporter.java | 2 +- .../GenerateActionsWorkflowImpl.groovy | 2 +- .../GenerateActionsWorkflowInternal.java | 5 +- .../GradleUtilsExtensionImpl.groovy | 8 +- .../GradleUtilsExtensionInternal.java | 104 ++++++++++++++++++ .../{ => internal}/GradleUtilsFlowAction.java | 2 +- .../{ => internal}/GradleUtilsPlugin.java | 3 +- .../{ => internal}/GradleUtilsProblems.java | 2 +- .../{ => internal}/GradleUtilsTask.java | 2 +- .../{ => internal}/PomUtilsImpl.groovy | 6 +- .../{ => internal}/PomUtilsInternal.java | 12 +- .../internal/PomUtilsInternalProxy.java | 23 ++++ .../PromotePublicationImpl.groovy | 2 +- .../PromotePublicationInternal.java | 8 +- .../gradleutils/{ => internal}/Util.java | 2 +- 24 files changed, 215 insertions(+), 137 deletions(-) delete mode 100644 src/main/groovy/net/minecraftforge/gradleutils/GradleUtilsExtensionInternal.java rename src/main/groovy/net/minecraftforge/gradleutils/{ => internal}/Constants.java (90%) rename src/main/groovy/net/minecraftforge/gradleutils/{ => internal}/EnhancedVersionReporter.java (99%) rename src/main/groovy/net/minecraftforge/gradleutils/{ => internal}/GenerateActionsWorkflowImpl.groovy (99%) rename src/main/groovy/net/minecraftforge/gradleutils/{ => internal}/GenerateActionsWorkflowInternal.java (58%) rename src/main/groovy/net/minecraftforge/gradleutils/{ => internal}/GradleUtilsExtensionImpl.groovy (98%) create mode 100644 src/main/groovy/net/minecraftforge/gradleutils/internal/GradleUtilsExtensionInternal.java rename src/main/groovy/net/minecraftforge/gradleutils/{ => internal}/GradleUtilsFlowAction.java (96%) rename src/main/groovy/net/minecraftforge/gradleutils/{ => internal}/GradleUtilsPlugin.java (90%) rename src/main/groovy/net/minecraftforge/gradleutils/{ => internal}/GradleUtilsProblems.java (98%) rename src/main/groovy/net/minecraftforge/gradleutils/{ => internal}/GradleUtilsTask.java (92%) rename src/main/groovy/net/minecraftforge/gradleutils/{ => internal}/PomUtilsImpl.groovy (92%) rename src/main/groovy/net/minecraftforge/gradleutils/{ => internal}/PomUtilsInternal.java (93%) create mode 100644 src/main/groovy/net/minecraftforge/gradleutils/internal/PomUtilsInternalProxy.java rename src/main/groovy/net/minecraftforge/gradleutils/{ => internal}/PromotePublicationImpl.groovy (98%) rename src/main/groovy/net/minecraftforge/gradleutils/{ => internal}/PromotePublicationInternal.java (54%) rename src/main/groovy/net/minecraftforge/gradleutils/{ => internal}/Util.java (80%) diff --git a/build.gradle b/build.gradle index 684bb49..b7b1e5d 100644 --- a/build.gradle +++ b/build.gradle @@ -94,7 +94,7 @@ gradlePlugin { plugins.register('gradleutils') { id = 'net.minecraftforge.gradleutils' - implementationClass = 'net.minecraftforge.gradleutils.GradleUtilsPlugin' + implementationClass = 'net.minecraftforge.gradleutils.internal.GradleUtilsPlugin' displayName = gradleutils.displayName description = project.description tags = ['minecraftforge'] diff --git a/src/main/groovy/net/minecraftforge/gradleutils/GenerateActionsWorkflow.java b/src/main/groovy/net/minecraftforge/gradleutils/GenerateActionsWorkflow.java index ba04bd8..5fda99c 100644 --- a/src/main/groovy/net/minecraftforge/gradleutils/GenerateActionsWorkflow.java +++ b/src/main/groovy/net/minecraftforge/gradleutils/GenerateActionsWorkflow.java @@ -20,7 +20,7 @@ /// /// @implNote See [GenerateActionsWorkflowImpl] @ApiStatus.Internal -public sealed interface GenerateActionsWorkflow extends Task permits GenerateActionsWorkflowInternal { +public interface GenerateActionsWorkflow extends Task { /// The name for this task. /// /// Each [project][org.gradle.api.Project] should only have one of this type of task and it must be named this. @@ -49,7 +49,6 @@ public sealed interface GenerateActionsWorkflow extends Task permits GenerateAct /// Default: Automatically detected by Git Version, otherwise `master` /// /// @return The property for the branch name - /// @implNote See [GenerateActionsWorkflowImpl#DEFAULT_BRANCH] @Optional @Input Property getBranch(); /// The local path from the [root project][org.gradle.api.Project#getRootProject()] to the current project to use in @@ -69,7 +68,6 @@ public sealed interface GenerateActionsWorkflow extends Task permits GenerateAct /// Default: The project's toolchain version, or `17` if it is lower than that. /// /// @return The property for the Gradle Java version - /// @implNote See [GenerateActionsWorkflowImpl#DEFAULT_GRADLE_JAVA] @Input Property getGradleJavaVersion(); /// The Shared Actions branch to use with this workflow. @@ -77,6 +75,5 @@ public sealed interface GenerateActionsWorkflow extends Task permits GenerateAct /// Default: `v0` /// /// @return The property for the Shared Actions branch - /// @implNote See [GenerateActionsWorkflowImpl#DEFAULT_SHARED_ACTIONS_BRANCH] @Input Property getSharedActionsBranch(); } diff --git a/src/main/groovy/net/minecraftforge/gradleutils/GradleUtilsExtension.java b/src/main/groovy/net/minecraftforge/gradleutils/GradleUtilsExtension.java index aae81e7..00d0ed6 100644 --- a/src/main/groovy/net/minecraftforge/gradleutils/GradleUtilsExtension.java +++ b/src/main/groovy/net/minecraftforge/gradleutils/GradleUtilsExtension.java @@ -5,8 +5,6 @@ package net.minecraftforge.gradleutils; import groovy.lang.Closure; -import kotlin.jvm.functions.Function0; -import net.minecraftforge.gradleutils.shared.Closures; import org.gradle.api.Action; import org.gradle.api.artifacts.repositories.MavenArtifactRepository; import org.gradle.api.file.Directory; @@ -16,12 +14,11 @@ import java.io.File; import java.util.concurrent.Callable; -import java.util.function.Supplier; /// Contains various utilities for working with Gradle scripts. /// /// @see GradleUtilsExtensionForProject -public sealed interface GradleUtilsExtension permits GradleUtilsExtensionForProject, GradleUtilsExtensionInternal { +public interface GradleUtilsExtension { /// The name for this extension. String NAME = "gradleutils"; @@ -31,7 +28,10 @@ public sealed interface GradleUtilsExtension permits GradleUtilsExtensionForProj /// @deprecated Use [#getForgeMaven()] @Deprecated(forRemoval = true, since = "3.3.28") @ApiStatus.ScheduledForRemoval(inVersion = "4.0.0") - Action forgeMaven = GradleUtilsExtensionInternal.forgeMaven; + Action forgeMaven = repo -> { + repo.setName("MinecraftForge"); + repo.setUrl("https://maven.minecraftforge.net/"); + }; /** * A closure for the Forge maven to be passed into @@ -42,14 +42,15 @@ public sealed interface GradleUtilsExtension permits GradleUtilsExtensionForProj * } * */ - default Action getForgeMaven() { - return GradleUtilsExtensionInternal.forgeMaven; - } + Action getForgeMaven(); /// @deprecated Use [#getForgeReleaseMaven()] @Deprecated(forRemoval = true, since = "3.3.28") @ApiStatus.ScheduledForRemoval(inVersion = "4.0.0") - Action forgeReleaseMaven = GradleUtilsExtensionInternal.forgeReleaseMaven; + Action forgeReleaseMaven = repo -> { + repo.setName("MinecraftForge releases"); + repo.setUrl("https://maven.minecraftforge.net/releases"); + }; /** * A closure for the Forge releases maven to be passed into @@ -62,14 +63,15 @@ default Action getForgeMaven() { * * @see #forgeMaven */ - default Action getForgeReleaseMaven() { - return GradleUtilsExtensionInternal.forgeReleaseMaven; - } + Action getForgeReleaseMaven(); /// @deprecated Use [#getMinecraftLibsMaven()] @Deprecated(forRemoval = true, since = "3.3.28") @ApiStatus.ScheduledForRemoval(inVersion = "4.0.0") - Action minecraftLibsMaven = GradleUtilsExtensionInternal.minecraftLibsMaven; + Action minecraftLibsMaven = repo -> { + repo.setName("Minecraft libraries"); + repo.setUrl("https://libraries.minecraft.net/"); + }; /** * A closure for the Minecraft libraries maven to be passed into @@ -80,9 +82,7 @@ default Action getForgeReleaseMaven() { * } * */ - default Action getMinecraftLibsMaven() { - return GradleUtilsExtensionInternal.minecraftLibsMaven; - } + Action getMinecraftLibsMaven(); /* PUBLISHING */ @@ -106,9 +106,7 @@ default Action getMinecraftLibsMaven() { /// (`https://maven.minecraftforge.net/releases`). /// /// @return The closure - default Action getPublishingForgeMaven() { - return getPublishingForgeMaven(Constants.FORGE_MAVEN_RELEASE); - } + Action getPublishingForgeMaven(); /// Get a configuring closure to be passed into [org.gradle.api.artifacts.dsl.RepositoryHandler#maven(Closure)] in a /// publishing block. @@ -173,9 +171,7 @@ default Action getPublishingForgeMaven() { /// /// @param defaultFolder The default folder if the required maven information is not set /// @return The closure - default Action getPublishingForgeMaven(File defaultFolder) { - return this.getPublishingForgeMaven(Constants.FORGE_MAVEN_RELEASE, defaultFolder); - } + Action getPublishingForgeMaven(File defaultFolder); /// Get a configuring closure to be passed into [org.gradle.api.artifacts.dsl.RepositoryHandler#maven(Closure)] in a /// publishing block. **Important:** The following environment variables must be set for this to work: @@ -218,9 +214,7 @@ default Action getPublishingForgeMaven(File defaultFold /// /// @param defaultFolder The default folder if the required maven information is not set /// @return The closure - default Action getPublishingForgeMaven(Directory defaultFolder) { - return this.getPublishingForgeMaven(Constants.FORGE_MAVEN_RELEASE, defaultFolder); - } + Action getPublishingForgeMaven(Directory defaultFolder); /// Get a configuring closure to be passed into [org.gradle.api.artifacts.dsl.RepositoryHandler#maven(Closure)] in a /// publishing block. **Important:** The following environment variables must be set for this to work: @@ -263,9 +257,7 @@ default Action getPublishingForgeMaven(Directory defaul /// /// @param defaultFolder The default folder if the required maven information is not set /// @return The closure - default Action getPublishingForgeMaven(Provider defaultFolder) { - return this.getPublishingForgeMaven(Constants.FORGE_MAVEN_RELEASE, defaultFolder); - } + Action getPublishingForgeMaven(Provider defaultFolder); /// Get a configuring closure to be passed into [org.gradle.api.artifacts.dsl.RepositoryHandler#maven(Closure)] in a /// publishing block. **Important:** The following environment variables must be set for this to work: @@ -306,9 +298,7 @@ default Action getPublishingForgeMaven(Provider defa /// @param value The value to unpack /// @param The type of value held by the provider /// @return The unpacked value - default T unpack(Object value) { - return Util.unpack(value); - } + T unpack(Object value); /// Packs a (deferred) value as a provider. /// diff --git a/src/main/groovy/net/minecraftforge/gradleutils/GradleUtilsExtensionForProject.java b/src/main/groovy/net/minecraftforge/gradleutils/GradleUtilsExtensionForProject.java index 52cdc4a..7a302eb 100644 --- a/src/main/groovy/net/minecraftforge/gradleutils/GradleUtilsExtensionForProject.java +++ b/src/main/groovy/net/minecraftforge/gradleutils/GradleUtilsExtensionForProject.java @@ -12,12 +12,13 @@ import org.gradle.api.provider.ProviderConvertible; import org.gradle.api.publish.maven.MavenPublication; import org.gradle.api.tasks.TaskProvider; +import org.jetbrains.annotations.ApiStatus; import java.util.Map; /// A subset of [GradleUtilsExtension] that is given to projects. Includes additional convenience methods that only /// apply to projects. -public sealed interface GradleUtilsExtensionForProject extends GradleUtilsExtension permits GradleUtilsExtensionInternal.ForProject { +public interface GradleUtilsExtensionForProject extends GradleUtilsExtension { /// The display name for the project. /// /// If the relevant properties are enabled, it is used in areas such as the Javadoc window title, among other @@ -60,6 +61,10 @@ default void manifestDefaults(Manifest manifest, String packageName) { /// /// @param configurations The configurations container to apply defaults to /// @param gradleVersion The Gradle version to target + /// @deprecated This logic will be superseded by Forge's PluginDev plugin. + @ApiStatus.Internal + @Deprecated(forRemoval = true) + @ApiStatus.ScheduledForRemoval(inVersion = "4.0.0") void pluginDevDefaults(ConfigurationContainer configurations, CharSequence gradleVersion); /// Applies known defaults for Minecraft Forge's Gradle plugins. @@ -72,6 +77,10 @@ default void manifestDefaults(Manifest manifest, String packageName) { /// /// @param configurations The configurations container to apply defaults to /// @param gradleVersion The Gradle version to target + /// @deprecated This logic will be superseded by Forge's PluginDev plugin. + @ApiStatus.Internal + @Deprecated(forRemoval = true) + @ApiStatus.ScheduledForRemoval(inVersion = "4.0.0") void pluginDevDefaults(ConfigurationContainer configurations, Provider gradleVersion); /// Applies known defaults for Minecraft Forge's Gradle plugins. @@ -84,6 +93,9 @@ default void manifestDefaults(Manifest manifest, String packageName) { /// /// @param configurations The configurations container to apply defaults to /// @param gradleVersion The Gradle version to target + @ApiStatus.Internal + @Deprecated(forRemoval = true) + @ApiStatus.ScheduledForRemoval(inVersion = "4.0.0") default void pluginDevDefaults(ConfigurationContainer configurations, ProviderConvertible gradleVersion) { this.pluginDevDefaults(configurations, gradleVersion.asProvider()); } @@ -97,6 +109,7 @@ default void pluginDevDefaults(ConfigurationContainer configurations, ProviderCo /// /// @param publication The publication to promote /// @return The provider for the promotion task + @ApiStatus.Internal default TaskProvider promote(MavenPublication publication) { return this.promote(publication, null); } @@ -111,5 +124,6 @@ default TaskProvider promote(MavenPublication publ /// @param publication The publication to promote /// @param cfg A configuring action for the task /// @return The provider for the promotion task + @ApiStatus.Internal TaskProvider promote(MavenPublication publication, Action cfg); } diff --git a/src/main/groovy/net/minecraftforge/gradleutils/GradleUtilsExtensionInternal.java b/src/main/groovy/net/minecraftforge/gradleutils/GradleUtilsExtensionInternal.java deleted file mode 100644 index 1c0e99d..0000000 --- a/src/main/groovy/net/minecraftforge/gradleutils/GradleUtilsExtensionInternal.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ -package net.minecraftforge.gradleutils; - -import org.gradle.api.Action; -import org.gradle.api.artifacts.repositories.MavenArtifactRepository; -import org.gradle.api.reflect.HasPublicType; -import org.gradle.api.reflect.TypeOf; -import org.jetbrains.annotations.UnknownNullability; - -import java.util.Objects; - -non-sealed interface GradleUtilsExtensionInternal extends GradleUtilsExtension, HasPublicType { - @Override - default TypeOf getPublicType() { - return TypeOf.typeOf(GradleUtilsExtension.class); - } - - Action forgeMaven = repo -> { - repo.setName("MinecraftForge"); - repo.setUrl(Constants.FORGE_MAVEN); - }; - - Action forgeReleaseMaven = repo -> { - repo.setName("MinecraftForge releases"); - repo.setUrl(Constants.FORGE_MAVEN_RELEASE); - }; - - Action minecraftLibsMaven = repo -> { - repo.setName("Minecraft libraries"); - repo.setUrl(Constants.MC_LIBS_MAVEN); - }; - - /// Unpacks a deferred value or returns `null` if the value could not be unpacked or queried. - /// - /// @param value The value to unpack - /// @param The type of value held by the provider - /// @return The unpacked value - /// @see #unpack(Object) - default T unpackOrNull(@UnknownNullability Object value) { - try { - return this.unpack(Objects.requireNonNull(value)); - } catch (Throwable e) { - return null; - } - } - - non-sealed interface ForProject extends GradleUtilsExtensionInternal, GradleUtilsExtensionForProject, HasPublicType { - @Override - default TypeOf getPublicType() { - return TypeOf.typeOf(GradleUtilsExtensionForProject.class); - } - } -} diff --git a/src/main/groovy/net/minecraftforge/gradleutils/PomUtils.java b/src/main/groovy/net/minecraftforge/gradleutils/PomUtils.java index 80b95eb..03181c0 100644 --- a/src/main/groovy/net/minecraftforge/gradleutils/PomUtils.java +++ b/src/main/groovy/net/minecraftforge/gradleutils/PomUtils.java @@ -4,6 +4,7 @@ */ package net.minecraftforge.gradleutils; +import net.minecraftforge.gradleutils.internal.PomUtilsInternalProxy; import org.gradle.api.Action; import org.gradle.api.publish.maven.MavenPom; import org.gradle.api.publish.maven.MavenPomDeveloper; @@ -14,10 +15,11 @@ /// Contains utilities to make working with [POMs][MavenPom] more ergonomic. /// /// This can be accessed using the [gradleutils][GradleUtilsExtension] extension. -public sealed interface PomUtils permits PomUtilsInternal { +public interface PomUtils { /// Allows accessing [licenses][Licenses] from buildscripts using `gradleutils.pom.licenses`. /// /// @return A reference to the licenses + /// @apiNote In GradleUtils 4.0.0, this method will instead return a [Map] of [Action]`<`[MavenPomLicense]`>`. /// @see Licenses Licenses getLicenses(); @@ -25,25 +27,25 @@ public sealed interface PomUtils permits PomUtilsInternal { /// that uses one. /// /// @see #getLicenses() - //@formatter:off - sealed interface Licenses permits PomUtilsInternal.Licenses { + interface Licenses { + //@formatter:off /// @see Apache License 2.0 on SPDX - Action Apache2_0 = PomUtilsInternal.makeLicense("Apache-2.0", "https://www.apache.org/licenses/LICENSE-2.0"); + Action Apache2_0 = PomUtilsInternalProxy.makeLicense("Apache-2.0", "https://www.apache.org/licenses/LICENSE-2.0"); /// @see GNU Lesser General Public License v2.1 only on SPDX - Action LGPLv2_1 = PomUtilsInternal.makeLicense("LGPL-2.1-only", "https://www.gnu.org/licenses/old-licenses/lgpl-2.1-standalone.html"); + Action LGPLv2_1 = PomUtilsInternalProxy.makeLicense("LGPL-2.1-only", "https://www.gnu.org/licenses/old-licenses/lgpl-2.1-standalone.html"); /// @see GNU Lesser General Public License v3.0 only on SPDX - Action LGPLv3 = PomUtilsInternal.makeLicense("LGPL-3.0-only", "https://www.gnu.org/licenses/lgpl-3.0-standalone.html"); + Action LGPLv3 = PomUtilsInternalProxy.makeLicense("LGPL-3.0-only", "https://www.gnu.org/licenses/lgpl-3.0-standalone.html"); /// @see MIT License on SPDX - Action MIT = PomUtilsInternal.makeLicense("MIT", "https://opensource.org/license/mit/"); + Action MIT = PomUtilsInternalProxy.makeLicense("MIT", "https://opensource.org/license/mit/"); + //@formatter:on } - //@formatter:on /// Contains several developers within the MinecraftForge organization to reduce needing to manually write them out /// in each project they contribute to. /// /// If a queried developer does not exist, it is automatically created with the input which is set to the /// {@linkplain MavenPomDeveloper#getId() ID} and {@linkplain MavenPomDeveloper#getName() name}. - Map> developers = PomUtilsInternal.makeDevelopers(); + Map> developers = PomUtilsInternalProxy.makeDevelopers(); /// Adds details from the project's remote URL to the given POM. /// diff --git a/src/main/groovy/net/minecraftforge/gradleutils/PromotePublication.java b/src/main/groovy/net/minecraftforge/gradleutils/PromotePublication.java index 9200c68..c26be30 100644 --- a/src/main/groovy/net/minecraftforge/gradleutils/PromotePublication.java +++ b/src/main/groovy/net/minecraftforge/gradleutils/PromotePublication.java @@ -14,7 +14,7 @@ /// @apiNote This task is [internal][org.jetbrains.annotations.ApiStatus.Internal] as it is meant for use in Forge /// projects only. @ApiStatus.Internal -public sealed interface PromotePublication extends Task permits PromotePublicationInternal { +public interface PromotePublication extends Task { /// The publication group to promote. /// /// By convention, this is [org.gradle.api.Project#getGroup()], but the set value is diff --git a/src/main/groovy/net/minecraftforge/gradleutils/WriteManifest.java b/src/main/groovy/net/minecraftforge/gradleutils/WriteManifest.java index b904f50..c3469b1 100644 --- a/src/main/groovy/net/minecraftforge/gradleutils/WriteManifest.java +++ b/src/main/groovy/net/minecraftforge/gradleutils/WriteManifest.java @@ -4,7 +4,9 @@ */ package net.minecraftforge.gradleutils; +import org.gradle.api.Action; import org.gradle.api.DefaultTask; +import org.gradle.api.Project; import org.gradle.api.file.DuplicatesStrategy; import org.gradle.api.file.ProjectLayout; import org.gradle.api.file.RegularFileProperty; @@ -27,7 +29,7 @@ @ApiStatus.Internal @ApiStatus.Experimental -public abstract class WriteManifest extends DefaultTask implements GradleUtilsTask { +public abstract class WriteManifest extends DefaultTask { protected abstract @Input Property getInputBytes(); protected abstract @OutputFile RegularFileProperty getOutput(); @@ -49,7 +51,7 @@ public WriteManifest(TaskProvider jar) { }); }); - afterEvaluate(project -> { + Action afterEvaluate = project -> { try (var os = new ByteArrayOutputStream()) { // RATIONALE: ManifestInternal has not changed since Gradle 2.14 // Due to the hacky nature of needing the proper manifest in the resources, this is the only good way of doing this @@ -60,7 +62,13 @@ public WriteManifest(TaskProvider jar) { } catch (IOException e) { throw new RuntimeException(e); } - }); + }; + + try { + getProject().afterEvaluate(afterEvaluate); + } catch (Exception ignored) { + afterEvaluate.execute(getProject()); + } } @TaskAction diff --git a/src/main/groovy/net/minecraftforge/gradleutils/Constants.java b/src/main/groovy/net/minecraftforge/gradleutils/internal/Constants.java similarity index 90% rename from src/main/groovy/net/minecraftforge/gradleutils/Constants.java rename to src/main/groovy/net/minecraftforge/gradleutils/internal/Constants.java index f0c90cd..f16c132 100644 --- a/src/main/groovy/net/minecraftforge/gradleutils/Constants.java +++ b/src/main/groovy/net/minecraftforge/gradleutils/internal/Constants.java @@ -2,7 +2,7 @@ * Copyright (c) Forge Development LLC and contributors * SPDX-License-Identifier: LGPL-2.1-only */ -package net.minecraftforge.gradleutils; +package net.minecraftforge.gradleutils.internal; final class Constants { static final String FORGE_MAVEN = "https://maven.minecraftforge.net/"; diff --git a/src/main/groovy/net/minecraftforge/gradleutils/EnhancedVersionReporter.java b/src/main/groovy/net/minecraftforge/gradleutils/internal/EnhancedVersionReporter.java similarity index 99% rename from src/main/groovy/net/minecraftforge/gradleutils/EnhancedVersionReporter.java rename to src/main/groovy/net/minecraftforge/gradleutils/internal/EnhancedVersionReporter.java index 05310ef..4ae64bd 100644 --- a/src/main/groovy/net/minecraftforge/gradleutils/EnhancedVersionReporter.java +++ b/src/main/groovy/net/minecraftforge/gradleutils/internal/EnhancedVersionReporter.java @@ -2,7 +2,7 @@ * Copyright (c) Forge Development LLC and contributors * SPDX-License-Identifier: LGPL-2.1-only */ -package net.minecraftforge.gradleutils; +package net.minecraftforge.gradleutils.internal; import com.github.benmanes.gradle.versions.reporter.Reporter; import com.github.benmanes.gradle.versions.reporter.result.DependenciesGroup; diff --git a/src/main/groovy/net/minecraftforge/gradleutils/GenerateActionsWorkflowImpl.groovy b/src/main/groovy/net/minecraftforge/gradleutils/internal/GenerateActionsWorkflowImpl.groovy similarity index 99% rename from src/main/groovy/net/minecraftforge/gradleutils/GenerateActionsWorkflowImpl.groovy rename to src/main/groovy/net/minecraftforge/gradleutils/internal/GenerateActionsWorkflowImpl.groovy index e33882a..0c75228 100644 --- a/src/main/groovy/net/minecraftforge/gradleutils/GenerateActionsWorkflowImpl.groovy +++ b/src/main/groovy/net/minecraftforge/gradleutils/internal/GenerateActionsWorkflowImpl.groovy @@ -2,7 +2,7 @@ * Copyright (c) Forge Development LLC and contributors * SPDX-License-Identifier: LGPL-2.1-only */ -package net.minecraftforge.gradleutils +package net.minecraftforge.gradleutils.internal import groovy.transform.CompileStatic import groovy.transform.PackageScope diff --git a/src/main/groovy/net/minecraftforge/gradleutils/GenerateActionsWorkflowInternal.java b/src/main/groovy/net/minecraftforge/gradleutils/internal/GenerateActionsWorkflowInternal.java similarity index 58% rename from src/main/groovy/net/minecraftforge/gradleutils/GenerateActionsWorkflowInternal.java rename to src/main/groovy/net/minecraftforge/gradleutils/internal/GenerateActionsWorkflowInternal.java index 88c085a..669fca6 100644 --- a/src/main/groovy/net/minecraftforge/gradleutils/GenerateActionsWorkflowInternal.java +++ b/src/main/groovy/net/minecraftforge/gradleutils/internal/GenerateActionsWorkflowInternal.java @@ -2,12 +2,13 @@ * Copyright (c) Forge Development LLC and contributors * SPDX-License-Identifier: LGPL-2.1-only */ -package net.minecraftforge.gradleutils; +package net.minecraftforge.gradleutils.internal; +import net.minecraftforge.gradleutils.GenerateActionsWorkflow; import org.gradle.api.reflect.HasPublicType; import org.gradle.api.reflect.TypeOf; -non-sealed interface GenerateActionsWorkflowInternal extends GenerateActionsWorkflow, GradleUtilsTask, HasPublicType { +interface GenerateActionsWorkflowInternal extends GenerateActionsWorkflow, GradleUtilsTask, HasPublicType { @Override default TypeOf getPublicType() { return TypeOf.typeOf(GenerateActionsWorkflow.class); diff --git a/src/main/groovy/net/minecraftforge/gradleutils/GradleUtilsExtensionImpl.groovy b/src/main/groovy/net/minecraftforge/gradleutils/internal/GradleUtilsExtensionImpl.groovy similarity index 98% rename from src/main/groovy/net/minecraftforge/gradleutils/GradleUtilsExtensionImpl.groovy rename to src/main/groovy/net/minecraftforge/gradleutils/internal/GradleUtilsExtensionImpl.groovy index 0413e24..50bc5b2 100644 --- a/src/main/groovy/net/minecraftforge/gradleutils/GradleUtilsExtensionImpl.groovy +++ b/src/main/groovy/net/minecraftforge/gradleutils/internal/GradleUtilsExtensionImpl.groovy @@ -2,18 +2,20 @@ * Copyright (c) Forge Development LLC and contributors * SPDX-License-Identifier: LGPL-2.1-only */ -package net.minecraftforge.gradleutils +package net.minecraftforge.gradleutils.internal import com.github.benmanes.gradle.versions.reporter.result.Result import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask import groovy.transform.CompileStatic import groovy.transform.PackageScope +import net.minecraftforge.gradleutils.GenerateActionsWorkflow +import net.minecraftforge.gradleutils.PomUtils +import net.minecraftforge.gradleutils.PromotePublication import org.codehaus.groovy.runtime.DefaultGroovyMethods import org.gradle.api.Action import org.gradle.api.Project import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.ConfigurationContainer -import org.gradle.api.artifacts.DependencySet import org.gradle.api.artifacts.repositories.MavenArtifactRepository import org.gradle.api.attributes.plugin.GradlePluginApiVersion import org.gradle.api.file.Directory @@ -52,7 +54,7 @@ import javax.inject.Inject import java.nio.charset.Charset import java.nio.charset.StandardCharsets -import static net.minecraftforge.gradleutils.GradleUtilsPlugin.LOGGER +import static GradleUtilsPlugin.LOGGER @CompileStatic @PackageScope abstract class GradleUtilsExtensionImpl implements GradleUtilsExtensionInternal { diff --git a/src/main/groovy/net/minecraftforge/gradleutils/internal/GradleUtilsExtensionInternal.java b/src/main/groovy/net/minecraftforge/gradleutils/internal/GradleUtilsExtensionInternal.java new file mode 100644 index 0000000..d3dd293 --- /dev/null +++ b/src/main/groovy/net/minecraftforge/gradleutils/internal/GradleUtilsExtensionInternal.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ +package net.minecraftforge.gradleutils.internal; + +import net.minecraftforge.gradleutils.GradleUtilsExtension; +import net.minecraftforge.gradleutils.GradleUtilsExtensionForProject; +import org.gradle.api.Action; +import org.gradle.api.artifacts.repositories.MavenArtifactRepository; +import org.gradle.api.file.Directory; +import org.gradle.api.provider.Provider; +import org.gradle.api.reflect.HasPublicType; +import org.gradle.api.reflect.TypeOf; +import org.jetbrains.annotations.UnknownNullability; + +import java.io.File; +import java.util.Objects; + +interface GradleUtilsExtensionInternal extends GradleUtilsExtension, HasPublicType { + @Override + default TypeOf getPublicType() { + return TypeOf.typeOf(GradleUtilsExtension.class); + } + + // NOTE: Rename from forgeMaven -> FORGE_MAVEN in GU4 + Action forgeMaven = repo -> { + repo.setName("MinecraftForge"); + repo.setUrl(Constants.FORGE_MAVEN); + }; + + // NOTE: Rename from forgeReleaseMaven -> FORGE_MAVEN_RELEASES in GU4 + Action forgeReleaseMaven = repo -> { + repo.setName("MinecraftForge releases"); + repo.setUrl(Constants.FORGE_MAVEN_RELEASE); + }; + + // NOTE: Rename from minecraftLibsMaven -> MINECRAFT_LIBS_MAVEN in GU4 + Action minecraftLibsMaven = repo -> { + repo.setName("Minecraft libraries"); + repo.setUrl("https://libraries.minecraft.net/"); + }; + + @Override + default Action getForgeMaven() { + return forgeMaven; + } + + @Override + default Action getForgeReleaseMaven() { + return forgeReleaseMaven; + } + + @Override + default Action getMinecraftLibsMaven() { + return minecraftLibsMaven; + } + + @Override + default Action getPublishingForgeMaven() { + return getPublishingForgeMaven(Constants.FORGE_MAVEN_RELEASE); + } + + @Override + default Action getPublishingForgeMaven(File defaultFolder) { + return this.getPublishingForgeMaven(Constants.FORGE_MAVEN_RELEASE, defaultFolder); + } + + @Override + default Action getPublishingForgeMaven(Directory defaultFolder) { + return this.getPublishingForgeMaven(Constants.FORGE_MAVEN_RELEASE, defaultFolder); + } + + @Override + default Action getPublishingForgeMaven(Provider defaultFolder) { + return this.getPublishingForgeMaven(Constants.FORGE_MAVEN_RELEASE, defaultFolder); + } + + @Override + default T unpack(Object value) { + return Util.unpack(value); + } + + /// Unpacks a deferred value or returns `null` if the value could not be unpacked or queried. + /// + /// @param value The value to unpack + /// @param The type of value held by the provider + /// @return The unpacked value + /// @see #unpack(Object) + default T unpackOrNull(@UnknownNullability Object value) { + try { + return this.unpack(Objects.requireNonNull(value)); + } catch (Throwable e) { + return null; + } + } + + interface ForProject extends GradleUtilsExtensionInternal, GradleUtilsExtensionForProject, HasPublicType { + @Override + default TypeOf getPublicType() { + return TypeOf.typeOf(GradleUtilsExtensionForProject.class); + } + } +} diff --git a/src/main/groovy/net/minecraftforge/gradleutils/GradleUtilsFlowAction.java b/src/main/groovy/net/minecraftforge/gradleutils/internal/GradleUtilsFlowAction.java similarity index 96% rename from src/main/groovy/net/minecraftforge/gradleutils/GradleUtilsFlowAction.java rename to src/main/groovy/net/minecraftforge/gradleutils/internal/GradleUtilsFlowAction.java index a42c211..51aea4b 100644 --- a/src/main/groovy/net/minecraftforge/gradleutils/GradleUtilsFlowAction.java +++ b/src/main/groovy/net/minecraftforge/gradleutils/internal/GradleUtilsFlowAction.java @@ -2,7 +2,7 @@ * Copyright (c) Forge Development LLC and contributors * SPDX-License-Identifier: LGPL-2.1-only */ -package net.minecraftforge.gradleutils; +package net.minecraftforge.gradleutils.internal; import net.minecraftforge.gradleutils.shared.EnhancedFlowAction; import org.jetbrains.annotations.Nullable; diff --git a/src/main/groovy/net/minecraftforge/gradleutils/GradleUtilsPlugin.java b/src/main/groovy/net/minecraftforge/gradleutils/internal/GradleUtilsPlugin.java similarity index 90% rename from src/main/groovy/net/minecraftforge/gradleutils/GradleUtilsPlugin.java rename to src/main/groovy/net/minecraftforge/gradleutils/internal/GradleUtilsPlugin.java index b313502..eb7c52f 100644 --- a/src/main/groovy/net/minecraftforge/gradleutils/GradleUtilsPlugin.java +++ b/src/main/groovy/net/minecraftforge/gradleutils/internal/GradleUtilsPlugin.java @@ -2,8 +2,9 @@ * Copyright (c) Forge Development LLC and contributors * SPDX-License-Identifier: LGPL-2.1-only */ -package net.minecraftforge.gradleutils; +package net.minecraftforge.gradleutils.internal; +import net.minecraftforge.gradleutils.GradleUtilsExtension; import net.minecraftforge.gradleutils.shared.EnhancedPlugin; import org.gradle.api.Project; import org.gradle.api.logging.Logger; diff --git a/src/main/groovy/net/minecraftforge/gradleutils/GradleUtilsProblems.java b/src/main/groovy/net/minecraftforge/gradleutils/internal/GradleUtilsProblems.java similarity index 98% rename from src/main/groovy/net/minecraftforge/gradleutils/GradleUtilsProblems.java rename to src/main/groovy/net/minecraftforge/gradleutils/internal/GradleUtilsProblems.java index 3bbbc1c..342d277 100644 --- a/src/main/groovy/net/minecraftforge/gradleutils/GradleUtilsProblems.java +++ b/src/main/groovy/net/minecraftforge/gradleutils/internal/GradleUtilsProblems.java @@ -2,7 +2,7 @@ * Copyright (c) Forge Development LLC and contributors * SPDX-License-Identifier: LGPL-2.1-only */ -package net.minecraftforge.gradleutils; +package net.minecraftforge.gradleutils.internal; import net.minecraftforge.gradleutils.shared.EnhancedProblems; import org.gradle.api.problems.Severity; diff --git a/src/main/groovy/net/minecraftforge/gradleutils/GradleUtilsTask.java b/src/main/groovy/net/minecraftforge/gradleutils/internal/GradleUtilsTask.java similarity index 92% rename from src/main/groovy/net/minecraftforge/gradleutils/GradleUtilsTask.java rename to src/main/groovy/net/minecraftforge/gradleutils/internal/GradleUtilsTask.java index 9c626d8..118bd0a 100644 --- a/src/main/groovy/net/minecraftforge/gradleutils/GradleUtilsTask.java +++ b/src/main/groovy/net/minecraftforge/gradleutils/internal/GradleUtilsTask.java @@ -2,7 +2,7 @@ * Copyright (c) Forge Development LLC and contributors * SPDX-License-Identifier: LGPL-2.1-only */ -package net.minecraftforge.gradleutils; +package net.minecraftforge.gradleutils.internal; import net.minecraftforge.gradleutils.shared.EnhancedPlugin; import net.minecraftforge.gradleutils.shared.EnhancedTask; diff --git a/src/main/groovy/net/minecraftforge/gradleutils/PomUtilsImpl.groovy b/src/main/groovy/net/minecraftforge/gradleutils/internal/PomUtilsImpl.groovy similarity index 92% rename from src/main/groovy/net/minecraftforge/gradleutils/PomUtilsImpl.groovy rename to src/main/groovy/net/minecraftforge/gradleutils/internal/PomUtilsImpl.groovy index d2024af..3104aba 100644 --- a/src/main/groovy/net/minecraftforge/gradleutils/PomUtilsImpl.groovy +++ b/src/main/groovy/net/minecraftforge/gradleutils/internal/PomUtilsImpl.groovy @@ -2,7 +2,7 @@ * Copyright (c) Forge Development LLC and contributors * SPDX-License-Identifier: LGPL-2.1-only */ -package net.minecraftforge.gradleutils +package net.minecraftforge.gradleutils.internal import groovy.transform.CompileDynamic import groovy.transform.CompileStatic @@ -26,10 +26,10 @@ import javax.inject.Inject this.problems = this.objects.newInstance(GradleUtilsProblems) } - final Licenses licenses = this.objects.newInstance(Licenses) + final Licenses licenses = this.objects.newInstance(LicensesImpl) @CompileStatic - @PackageScope static abstract class Licenses implements PomUtilsInternal.Licenses { + @PackageScope static abstract class LicensesImpl implements Licenses { @Inject Licenses() { } } diff --git a/src/main/groovy/net/minecraftforge/gradleutils/PomUtilsInternal.java b/src/main/groovy/net/minecraftforge/gradleutils/internal/PomUtilsInternal.java similarity index 93% rename from src/main/groovy/net/minecraftforge/gradleutils/PomUtilsInternal.java rename to src/main/groovy/net/minecraftforge/gradleutils/internal/PomUtilsInternal.java index 76e0f4a..0b1c5ef 100644 --- a/src/main/groovy/net/minecraftforge/gradleutils/PomUtilsInternal.java +++ b/src/main/groovy/net/minecraftforge/gradleutils/internal/PomUtilsInternal.java @@ -2,8 +2,9 @@ * Copyright (c) Forge Development LLC and contributors * SPDX-License-Identifier: LGPL-2.1-only */ -package net.minecraftforge.gradleutils; +package net.minecraftforge.gradleutils.internal; +import net.minecraftforge.gradleutils.PomUtils; import org.gradle.api.Action; import org.gradle.api.publish.maven.MavenPom; import org.gradle.api.publish.maven.MavenPomDeveloper; @@ -16,19 +17,12 @@ import java.util.HashMap; import java.util.Map; -non-sealed interface PomUtilsInternal extends PomUtils, HasPublicType { +interface PomUtilsInternal extends PomUtils, HasPublicType { @Override default TypeOf getPublicType() { return TypeOf.typeOf(PomUtils.class); } - non-sealed interface Licenses extends PomUtils.Licenses, HasPublicType { - @Override - default TypeOf getPublicType() { - return TypeOf.typeOf(PomUtils.Licenses.class); - } - } - static Action makeLicense(String name, String url) { return license -> { license.getName().set(name); diff --git a/src/main/groovy/net/minecraftforge/gradleutils/internal/PomUtilsInternalProxy.java b/src/main/groovy/net/minecraftforge/gradleutils/internal/PomUtilsInternalProxy.java new file mode 100644 index 0000000..c596300 --- /dev/null +++ b/src/main/groovy/net/minecraftforge/gradleutils/internal/PomUtilsInternalProxy.java @@ -0,0 +1,23 @@ +package net.minecraftforge.gradleutils.internal; + +import org.gradle.api.Action; +import org.gradle.api.publish.maven.MavenPomDeveloper; +import org.gradle.api.publish.maven.MavenPomLicense; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.VisibleForTesting; + +import java.util.Map; + +@VisibleForTesting +@ApiStatus.Internal +@Deprecated(forRemoval = true, since = "3.4.0") +@ApiStatus.ScheduledForRemoval(inVersion = "4.0.0") +public final class PomUtilsInternalProxy { + public static Action makeLicense(String name, String url) { + return PomUtilsInternal.makeLicense(name, url); + } + + public static Map> makeDevelopers() { + return PomUtilsInternal.makeDevelopers(); + } +} diff --git a/src/main/groovy/net/minecraftforge/gradleutils/PromotePublicationImpl.groovy b/src/main/groovy/net/minecraftforge/gradleutils/internal/PromotePublicationImpl.groovy similarity index 98% rename from src/main/groovy/net/minecraftforge/gradleutils/PromotePublicationImpl.groovy rename to src/main/groovy/net/minecraftforge/gradleutils/internal/PromotePublicationImpl.groovy index 8fc80a0..b2d9b21 100644 --- a/src/main/groovy/net/minecraftforge/gradleutils/PromotePublicationImpl.groovy +++ b/src/main/groovy/net/minecraftforge/gradleutils/internal/PromotePublicationImpl.groovy @@ -2,7 +2,7 @@ * Copyright (c) Forge Development LLC and contributors * SPDX-License-Identifier: LGPL-2.1-only */ -package net.minecraftforge.gradleutils +package net.minecraftforge.gradleutils.internal import groovy.json.JsonBuilder import groovy.transform.CompileStatic diff --git a/src/main/groovy/net/minecraftforge/gradleutils/PromotePublicationInternal.java b/src/main/groovy/net/minecraftforge/gradleutils/internal/PromotePublicationInternal.java similarity index 54% rename from src/main/groovy/net/minecraftforge/gradleutils/PromotePublicationInternal.java rename to src/main/groovy/net/minecraftforge/gradleutils/internal/PromotePublicationInternal.java index 3ac65c7..b384e90 100644 --- a/src/main/groovy/net/minecraftforge/gradleutils/PromotePublicationInternal.java +++ b/src/main/groovy/net/minecraftforge/gradleutils/internal/PromotePublicationInternal.java @@ -2,16 +2,14 @@ * Copyright (c) Forge Development LLC and contributors * SPDX-License-Identifier: LGPL-2.1-only */ -package net.minecraftforge.gradleutils; +package net.minecraftforge.gradleutils.internal; -import net.minecraftforge.gradleutils.shared.EnhancedPlugin; -import net.minecraftforge.gradleutils.shared.EnhancedTask; -import org.gradle.api.Project; +import net.minecraftforge.gradleutils.PromotePublication; import org.gradle.api.reflect.HasPublicType; import org.gradle.api.reflect.TypeOf; import org.gradle.api.tasks.Internal; -non-sealed interface PromotePublicationInternal extends PromotePublication, GradleUtilsTask, HasPublicType { +interface PromotePublicationInternal extends PromotePublication, GradleUtilsTask, HasPublicType { @Override default @Internal TypeOf getPublicType() { return TypeOf.typeOf(PromotePublication.class); diff --git a/src/main/groovy/net/minecraftforge/gradleutils/Util.java b/src/main/groovy/net/minecraftforge/gradleutils/internal/Util.java similarity index 80% rename from src/main/groovy/net/minecraftforge/gradleutils/Util.java rename to src/main/groovy/net/minecraftforge/gradleutils/internal/Util.java index 2b2f55b..6de5bf0 100644 --- a/src/main/groovy/net/minecraftforge/gradleutils/Util.java +++ b/src/main/groovy/net/minecraftforge/gradleutils/internal/Util.java @@ -2,7 +2,7 @@ * Copyright (c) Forge Development LLC and contributors * SPDX-License-Identifier: LGPL-2.1-only */ -package net.minecraftforge.gradleutils; +package net.minecraftforge.gradleutils.internal; import net.minecraftforge.gradleutils.shared.SharedUtil; From 19a019a1cd8cac9924a0fdb419aa94e4c5b1dc98 Mon Sep 17 00:00:00 2001 From: Jonathing Date: Sat, 27 Dec 2025 18:58:12 -0500 Subject: [PATCH 3/6] Initial tools rework --- .../gradleutils/shared/EnhancedPlugin.java | 33 ++--- .../gradleutils/shared/SharedUtil.java | 127 +++++++++++++++++- .../gradleutils/shared/Tool.java | 56 +++++--- .../gradleutils/shared/ToolImpl.java | 61 +++++++-- .../shared/ToolsExtensionImpl.java | 16 ++- .../gradleutils/internal/Constants.java | 2 +- 6 files changed, 242 insertions(+), 53 deletions(-) diff --git a/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/EnhancedPlugin.java b/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/EnhancedPlugin.java index ed7bd0c..bd7d692 100644 --- a/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/EnhancedPlugin.java +++ b/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/EnhancedPlugin.java @@ -35,7 +35,7 @@ public non-sealed abstract class EnhancedPlugin implements Plugin, Enhance private final @Nullable String toolsExtName; private @UnknownNullability T target; - private ToolsExtensionImpl tools = this.getObjects().newInstance(ToolsExtensionImpl.class, (Callable) this::toolchainsForTools); + private @Nullable ToolsExtensionImpl tools; private final EnhancedProblems problemsInternal; /// The object factory provided by Gradle services. @@ -66,11 +66,6 @@ public non-sealed abstract class EnhancedPlugin implements Plugin, Enhance /// Service Injection protected abstract @Inject ProviderFactory getProviders(); - /// The Java toolchain service provided by Gradle services. - /// - /// @return The Java toolchain service - protected abstract @Inject JavaToolchainService getJavaToolchains(); - /// This constructor must be called by all subclasses using a public constructor annotated with [Inject]. The name /// and display name passed in are used in a minimal instance of [EnhancedProblems], which is used to set up the /// plugin's [global][#globalCaches()] and [local][#localCaches()] caches. Additionally, the name is used to @@ -103,12 +98,20 @@ protected EnhancedPlugin(String name, String displayName, @Nullable String tools /// @param target The target for this plugin @Override public final void apply(T target) { - this.setup(this.target = target); + if (this.toolsExtName != null && target instanceof ExtensionAware extensionAware) { + this.tools = (ToolsExtensionImpl) extensionAware.getExtensions().create(ToolsExtension.class, this.toolsExtName, ToolsExtensionImpl.class); + + try { + var gradle = (Gradle) InvokerHelper.getProperty(this.target, "gradle"); + var tools = (ToolsExtensionImpl) gradle.getExtensions().findByName(this.toolsExtName); + if (tools != null) + this.tools.definitions.addAll(tools.definitions); + } catch (Exception ignored) { } + } else { + this.tools = this.getObjects().newInstance(ToolsExtensionImpl.class); + } - if (this.toolsExtName != null && target instanceof ExtensionAware extensionAware) - this.tools = extensionAware.getExtensions().create(this.toolsExtName, ToolsExtensionImpl.class, (Callable) this::toolchainsForTools); -// else -// this.tools = this.getObjects().newInstance(ToolsExtensionImpl.class, (Callable) this::toolchainsForTools); + this.setup(this.target = target); } /// Called when this plugin is applied to do setup work. @@ -138,6 +141,9 @@ final EnhancedProblems getProblemsInternal() { @Override public Tool.Resolved getTool(Tool tool) { + if (this.tools == null) + throw new IllegalStateException("Plugin has not yet been applied"); + ProviderFactory providers; try { providers = this.target instanceof Project ? this.getProviders() : ((Gradle) InvokerHelper.getProperty(this.target, "gradle")).getRootProject().getProviders(); @@ -148,11 +154,6 @@ public Tool.Resolved getTool(Tool tool) { return ((ToolInternal) tool).get(this.globalCaches(), providers, this.tools); } - // NOTE: Use this in Tool implementations. Enhanced plugins do not enforce application on projects. - JavaToolchainService toolchainsForTools() { - return this.target instanceof Project ? this.getJavaToolchains() : ((Gradle) InvokerHelper.getProperty(this.target, "gradle")).getRootProject().getExtensions().getByType(JavaToolchainService.class); - } - /* CACHES */ diff --git a/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/SharedUtil.java b/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/SharedUtil.java index 17b0979..30c1afb 100644 --- a/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/SharedUtil.java +++ b/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/SharedUtil.java @@ -20,6 +20,8 @@ import org.gradle.api.artifacts.Configuration; import org.gradle.api.artifacts.Dependency; import org.gradle.api.artifacts.FileCollectionDependency; +import org.gradle.api.artifacts.ModuleIdentifier; +import org.gradle.api.artifacts.ModuleVersionIdentifier; import org.gradle.api.artifacts.ModuleVersionSelector; import org.gradle.api.logging.LogLevel; import org.gradle.api.logging.Logger; @@ -250,6 +252,129 @@ public List getArgs() { //region Dependency Information + public record SimpleModuleIdentifier(String getGroup, String getName) implements ModuleIdentifier { + static SimpleModuleIdentifier of(String group, String name) { + return new SimpleModuleIdentifier(group, name); + } + + static SimpleModuleIdentifier of(String module) { + var substring = module.split(":"); + if (substring.length != 2) + throw new IllegalArgumentException("Invalid non-versioned module identifier: " + module); + + return of(substring[0], substring[1]); + } + } + + public record SimpleModuleVersionIdentifier(ModuleIdentifier getModule, String getVersion, + @Nullable String classifier, + String extension) implements ModuleVersionIdentifier { + @Override + public String getGroup() { + return getModule.getGroup(); + } + + @Override + public String getName() { + return getModule.getName(); + } + + public String getDownloadUrl(String prefix) { + var builder = new StringBuilder(); + + // Use HTTPS by default if protocol not defined + if (!prefix.contains("://")) + builder.append("https://"); + + builder.append(prefix); + + // Account for trailing slash + if (!prefix.endsWith("/")) + builder.append('/'); + + builder.append(getGroup().replace('.', '/')) + .append('/').append(getName()) + .append('/').append(getVersion()) + .append('/').append(getName()).append('-').append(getVersion()); + + if (classifier != null) + builder.append('-').append(classifier); + + return builder.append('.').append(extension).toString(); + } + + static SimpleModuleVersionIdentifier of(ModuleIdentifier module, String version) { + return of(module, version, null, "jar"); + } + + static SimpleModuleVersionIdentifier of(ModuleIdentifier module, String version, @Nullable String classifier, String extension) { + return new SimpleModuleVersionIdentifier(module, version, classifier, extension); + } + + static SimpleModuleVersionIdentifier of(String module, String version) { + return of(SimpleModuleIdentifier.of(module), version); + } + + static SimpleModuleVersionIdentifier of(String group, String name, String version) { + return of(SimpleModuleIdentifier.of(group, name), version); + } + + static SimpleModuleVersionIdentifier of(String group, String name, String version, @Nullable String classifier, String extension) { + return of(SimpleModuleIdentifier.of(group, name), version, classifier, extension); + } + + static SimpleModuleVersionIdentifier of(String artifact) { + var split = artifact.split(":", 4); + var group = split[0]; + var name = split[1]; + + String version; + @Nullable String classifier = null; + String extension = "jar"; + + // Check if version has @ before : + if (split[2].indexOf('@') > 0) { + if (split.length > 3) + throw new IllegalArgumentException("Invalid module version identifier (found @ character before another : character): " + artifact); + + var s = split[2].split("@"); + version = s[0]; + extension = s[1]; + } else { + version = split[2]; + } + + // Check if classifier has an @ + if (split.length > 3) { + if (split[3].indexOf('@') > 0) { + var s = split[2].split("@"); + classifier = s[0]; + extension = s[1]; + } else { + classifier = split[3]; + } + } + + return of(group, name, version, classifier, extension); + } + } + + public static SimpleModuleVersionIdentifier moduleOf(String artifact) { + return SimpleModuleVersionIdentifier.of(artifact); + } + + public static SimpleModuleIdentifier moduleOf(String group, String name) { + return SimpleModuleIdentifier.of(group, name); + } + + public static SimpleModuleVersionIdentifier moduleOf(String group, String name, String version) { + return SimpleModuleVersionIdentifier.of(group, name, version); + } + + public static SimpleModuleVersionIdentifier moduleOf(ModuleIdentifier module, String version) { + return SimpleModuleVersionIdentifier.of(module, version); + } + public static String dependencyToArtifactString(Dependency dependency) { var builder = new StringBuilder(); @@ -437,7 +562,7 @@ public static Comparator versionComparator() { public static Class> versionComparatorClass() { return StaticVersionComparator.class; } - //endergion + //endregion //region Domain Object Handling diff --git a/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/Tool.java b/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/Tool.java index afdce8b..4120f8f 100644 --- a/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/Tool.java +++ b/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/Tool.java @@ -6,6 +6,7 @@ import org.gradle.api.Action; import org.gradle.api.Named; +import org.gradle.api.artifacts.ModuleVersionIdentifier; import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.FileCollection; import org.gradle.api.provider.Property; @@ -23,38 +24,61 @@ public sealed interface Tool extends Named, Serializable permits ToolInternal, Tool.Resolved { /// Creates a new tool with the given information. /// - /// @param name The name for this tool (will be used in the file name) - /// @param version The version for this tool (will be used in the file name) - /// @param downloadUrl The download URL for this tool + /// @param name The name for this tool, used to reference it in configuration and for the file name + /// @param artifact The artifact for this tool, used to get the download URL + /// @param mavenUrl The maven URL this tool is hosted on (if protocol is omitted, prepends `https://`, and + /// appends adds trailing slash if missing) (default: `https://maven.minecraftforge.net/`) /// @param javaVersion The Java version this tool was built with, or should run on - /// @param mainClass The main class to use when executing this tool + /// @param mainClass The main class to use when executing this tool (optional) /// @return The tool - static Tool of(String name, String version, String downloadUrl, int javaVersion, String mainClass) { - return new ToolImpl(name, version, downloadUrl, javaVersion, mainClass); + static Tool of(String name, String artifact, String mavenUrl, int javaVersion, String mainClass) { + return new ToolImpl(name, artifact, mavenUrl, javaVersion, mainClass); } /// Creates a new tool with the given information. /// - /// @param name The name for this tool (will be used in the file name) - /// @param version The version for this tool (will be used in the file name) - /// @param downloadUrl The download URL for this tool + /// @param name The name for this tool, used to reference it in configuration and for the file name + /// @param artifact The artifact for this tool, used to get the download URL /// @param javaVersion The Java version this tool was built with, or should run on + /// @param mainClass The main class to use when executing this tool (optional) /// @return The tool - static Tool of(String name, String version, String downloadUrl, int javaVersion) { - return new ToolImpl(name, version, downloadUrl, javaVersion, null); + static Tool of(String name, String artifact, int javaVersion, String mainClass) { + return new ToolImpl(name, artifact, null, javaVersion, mainClass); } + /// Creates a new tool with the given information. + /// + /// @param name The name for this tool, used to reference it in configuration and for the file name + /// @param artifact The artifact for this tool, used to get the download URL + /// @param mavenUrl The maven URL this tool is hosted on (if protocol is omitted, prepends `https://`, and + /// appends adds trailing slash if missing) (default: `https://maven.minecraftforge.net/`) + /// @param javaVersion The Java version this tool was built with, or should run on + /// @return The tool + static Tool of(String name, String artifact, String mavenUrl, int javaVersion) { + return new ToolImpl(name, artifact, mavenUrl, javaVersion, null); + } + + /// Creates a new tool with the given information. + /// + /// @param name The name for this tool, used to reference it in configuration and for the file name + /// @param artifact The artifact for this tool, used to get the download URL + /// @param javaVersion The Java version this tool was built with, or should run on + /// @return The tool + static Tool of(String name, String artifact, int javaVersion) { + return new ToolImpl(name, artifact, null, javaVersion, null); + } + + /// The module for this tool. + /// + /// @return The module for this tool + ModuleVersionIdentifier getModule(); + /// The name for this tool. Primarily used by [ToolExecBase] to create a default tool directory. /// /// @return The name of this tool @Override String getName(); - /// The version of this tool. - /// - /// @return The version of this tool - String getVersion(); - /// The Java version this tool was built with. Primarily used by [ToolExecBase] to determine the /// [org.gradle.jvm.toolchain.JavaLauncher]. /// diff --git a/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/ToolImpl.java b/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/ToolImpl.java index 27657e9..a92d928 100644 --- a/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/ToolImpl.java +++ b/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/ToolImpl.java @@ -6,6 +6,8 @@ import net.minecraftforge.util.download.DownloadUtils; import net.minecraftforge.util.hash.HashStore; +import org.gradle.api.artifacts.Configuration; +import org.gradle.api.artifacts.ModuleVersionIdentifier; import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.Directory; import org.gradle.api.file.FileCollection; @@ -27,22 +29,40 @@ import java.io.Serial; import java.nio.file.Files; -record ToolImpl(String getName, String getVersion, String fileName, String downloadUrl, int getJavaVersion, +record ToolImpl(String getName, ModuleVersionIdentifier getModule, String artifact, String fileName, String downloadUrl, int getJavaVersion, @Nullable String getMainClass) implements ToolInternal { private static final @Serial long serialVersionUID = -862411638019629688L; private static final Logger LOGGER = Logging.getLogger(Tool.class); - ToolImpl(String name, String version, String downloadUrl, int javaVersion, @Nullable String mainClass) { - this(name, version, String.format("%s-%s.jar", name, version), downloadUrl, javaVersion, mainClass); + ToolImpl(String name, String artifact, @Nullable String mavenUrl, int javaVersion, @Nullable String mainClass) { + this(name, SharedUtil.moduleOf(artifact), artifact, mavenUrl, javaVersion, mainClass); + } + + ToolImpl(String name, SharedUtil.SimpleModuleVersionIdentifier module, String artifact, @Nullable String mavenUrl, int javaVersion, @Nullable String mainClass) { + this( + name, + module, + artifact, + String.format("%s-%s.jar", name, module.getVersion()), + module.getDownloadUrl(mavenUrl != null ? mavenUrl : "https://maven.minecraftforge.net/"), + javaVersion, + mainClass + ); } @Override public Tool.Resolved get(Provider cachesDir, ProviderFactory providers, ToolsExtensionImpl toolsExt) { var definition = toolsExt.definitions.maybeCreate(this.getName()); - var classpath = definition.getClasspath(); - if (classpath.isEmpty()) { - classpath = toolsExt.getObjects().fileCollection().from( + + FileCollection classpathFromGradle = toolsExt.getObjects().fileCollection(); + var classpathFromDownload = definition.getClasspath(); + + if (classpathFromDownload.isEmpty()) { + classpathFromGradle = toolsExt.getProject().getConfigurations().detachedConfiguration( + toolsExt.getDependencies().create(artifact) + ); + classpathFromDownload = toolsExt.getObjects().fileCollection().from( providers.of(Source.class, spec -> spec.parameters(parameters -> { parameters.getInputFile().set(cachesDir.map(d -> d.file("tools/" + this.fileName))); parameters.getDownloadUrl().set(this.downloadUrl); @@ -52,9 +72,10 @@ public Tool.Resolved get(Provider cachesDir, ProviderFactor return new ResolvedImpl( toolsExt.getObjects(), - classpath, + classpathFromGradle, + classpathFromDownload, definition.getMainClass().orElse(providers.provider(this::getMainClass)), - definition.getJavaLauncher().orElse(providers.provider(() -> SharedUtil.launcherForStrictly(toolsExt.javaToolchains.call(), this.getJavaVersion()).get())) + definition.getJavaLauncher().orElse(providers.provider(() -> SharedUtil.launcherForStrictly(toolsExt.getJavaToolchains(), this.getJavaVersion()).get())) ); } @@ -94,19 +115,31 @@ public Property getJavaLauncher() { @SuppressWarnings("serial") final class ResolvedImpl implements ToolInternal.Resolved { - private final FileCollection classpath; + private final FileCollection classpathFromGradle; + private final FileCollection classpathFromDownload; private final Property mainClass; private final Property javaLauncher; - private ResolvedImpl(ObjectFactory objects, FileCollection classpath, Provider mainClass, Provider javaLauncher) { - this.classpath = classpath; + private @Nullable Boolean useGradle = null; + + private ResolvedImpl(ObjectFactory objects, FileCollection classpathFromGradle, FileCollection classpathFromDownload, Provider mainClass, Provider javaLauncher) { + this.classpathFromGradle = classpathFromGradle; + this.classpathFromDownload = classpathFromDownload; this.mainClass = objects.property(String.class).value(mainClass); this.javaLauncher = objects.property(JavaLauncher.class).value(javaLauncher); } @Override public FileCollection getClasspath() { - return this.classpath; + if (useGradle == null) { + try { + useGradle = !classpathFromGradle.getFiles().isEmpty(); + } catch (Exception e) { + useGradle = false; + } + } + + return useGradle ? classpathFromGradle : classpathFromDownload; } @Override @@ -115,8 +148,8 @@ public String getName() { } @Override - public String getVersion() { - return ToolImpl.this.getVersion(); + public ModuleVersionIdentifier getModule() { + return ToolImpl.this.getModule(); } @Override diff --git a/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/ToolsExtensionImpl.java b/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/ToolsExtensionImpl.java index 17460ad..e319e9f 100644 --- a/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/ToolsExtensionImpl.java +++ b/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/ToolsExtensionImpl.java @@ -6,6 +6,8 @@ import org.gradle.api.Action; import org.gradle.api.NamedDomainObjectContainer; +import org.gradle.api.Project; +import org.gradle.api.artifacts.dsl.DependencyFactory; import org.gradle.api.model.ObjectFactory; import org.gradle.jvm.toolchain.JavaToolchainService; @@ -13,15 +15,19 @@ import java.util.concurrent.Callable; abstract class ToolsExtensionImpl implements ToolsExtensionInternal { - final Callable javaToolchains; - final NamedDomainObjectContainer definitions; + final NamedDomainObjectContainer definitions; + + protected abstract @Inject Project getProject(); protected abstract @Inject ObjectFactory getObjects(); + protected abstract @Inject DependencyFactory getDependencies(); + + protected abstract @Inject JavaToolchainService getJavaToolchains(); + @Inject - public ToolsExtensionImpl(Callable javaToolchains) { - this.javaToolchains = javaToolchains; - this.definitions = this.getObjects().domainObjectContainer(ToolImpl.DefinitionImpl.class); + public ToolsExtensionImpl() { + this.definitions = this.getObjects().domainObjectContainer(Tool.Definition.class, name -> getObjects().newInstance(ToolImpl.DefinitionImpl.class, name)); } @Override diff --git a/src/main/groovy/net/minecraftforge/gradleutils/internal/Constants.java b/src/main/groovy/net/minecraftforge/gradleutils/internal/Constants.java index f16c132..5e785f3 100644 --- a/src/main/groovy/net/minecraftforge/gradleutils/internal/Constants.java +++ b/src/main/groovy/net/minecraftforge/gradleutils/internal/Constants.java @@ -6,7 +6,7 @@ final class Constants { static final String FORGE_MAVEN = "https://maven.minecraftforge.net/"; - static final String FORGE_MAVEN_RELEASE = FORGE_MAVEN + "releases"; + static final String FORGE_MAVEN_RELEASE = FORGE_MAVEN + "releases/"; static final String MC_LIBS_MAVEN = "https://libraries.minecraft.net/"; static final String FORGE_ORG_NAME = "Forge Development LLC"; From 6b491b72aee0bd6dd07efd653837b582be4ca118 Mon Sep 17 00:00:00 2001 From: Jonathing Date: Sun, 28 Dec 2025 12:41:28 -0500 Subject: [PATCH 4/6] Don't default to ForgeMaven, add `Tool#ofForge` --- .../gradleutils/shared/Tool.java | 22 +++++++++---------- .../gradleutils/shared/ToolImpl.java | 6 ++--- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/Tool.java b/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/Tool.java index 4120f8f..5a66031 100644 --- a/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/Tool.java +++ b/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/Tool.java @@ -27,11 +27,11 @@ public sealed interface Tool extends Named, Serializable permits ToolInternal, T /// @param name The name for this tool, used to reference it in configuration and for the file name /// @param artifact The artifact for this tool, used to get the download URL /// @param mavenUrl The maven URL this tool is hosted on (if protocol is omitted, prepends `https://`, and - /// appends adds trailing slash if missing) (default: `https://maven.minecraftforge.net/`) + /// appends adds trailing slash if missing) /// @param javaVersion The Java version this tool was built with, or should run on /// @param mainClass The main class to use when executing this tool (optional) /// @return The tool - static Tool of(String name, String artifact, String mavenUrl, int javaVersion, String mainClass) { + static Tool of(String name, String artifact, String mavenUrl, int javaVersion, @Nullable String mainClass) { return new ToolImpl(name, artifact, mavenUrl, javaVersion, mainClass); } @@ -39,23 +39,23 @@ static Tool of(String name, String artifact, String mavenUrl, int javaVersion, S /// /// @param name The name for this tool, used to reference it in configuration and for the file name /// @param artifact The artifact for this tool, used to get the download URL + /// @param mavenUrl The maven URL this tool is hosted on (if protocol is omitted, prepends `https://`, and + /// appends adds trailing slash if missing) /// @param javaVersion The Java version this tool was built with, or should run on - /// @param mainClass The main class to use when executing this tool (optional) /// @return The tool - static Tool of(String name, String artifact, int javaVersion, String mainClass) { - return new ToolImpl(name, artifact, null, javaVersion, mainClass); + static Tool of(String name, String artifact, String mavenUrl, int javaVersion) { + return new ToolImpl(name, artifact, mavenUrl, javaVersion, null); } /// Creates a new tool with the given information. /// /// @param name The name for this tool, used to reference it in configuration and for the file name /// @param artifact The artifact for this tool, used to get the download URL - /// @param mavenUrl The maven URL this tool is hosted on (if protocol is omitted, prepends `https://`, and - /// appends adds trailing slash if missing) (default: `https://maven.minecraftforge.net/`) /// @param javaVersion The Java version this tool was built with, or should run on + /// @param mainClass The main class to use when executing this tool (optional) /// @return The tool - static Tool of(String name, String artifact, String mavenUrl, int javaVersion) { - return new ToolImpl(name, artifact, mavenUrl, javaVersion, null); + static Tool ofForge(String name, String artifact, int javaVersion, String mainClass) { + return new ToolImpl(name, artifact, "https://maven.minecraftforge.net/", javaVersion, mainClass); } /// Creates a new tool with the given information. @@ -64,8 +64,8 @@ static Tool of(String name, String artifact, String mavenUrl, int javaVersion) { /// @param artifact The artifact for this tool, used to get the download URL /// @param javaVersion The Java version this tool was built with, or should run on /// @return The tool - static Tool of(String name, String artifact, int javaVersion) { - return new ToolImpl(name, artifact, null, javaVersion, null); + static Tool ofForge(String name, String artifact, int javaVersion) { + return new ToolImpl(name, artifact, "https://maven.minecraftforge.net/", javaVersion, null); } /// The module for this tool. diff --git a/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/ToolImpl.java b/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/ToolImpl.java index a92d928..8dd7386 100644 --- a/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/ToolImpl.java +++ b/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/ToolImpl.java @@ -35,17 +35,17 @@ record ToolImpl(String getName, ModuleVersionIdentifier getModule, String artifa private static final Logger LOGGER = Logging.getLogger(Tool.class); - ToolImpl(String name, String artifact, @Nullable String mavenUrl, int javaVersion, @Nullable String mainClass) { + ToolImpl(String name, String artifact, String mavenUrl, int javaVersion, @Nullable String mainClass) { this(name, SharedUtil.moduleOf(artifact), artifact, mavenUrl, javaVersion, mainClass); } - ToolImpl(String name, SharedUtil.SimpleModuleVersionIdentifier module, String artifact, @Nullable String mavenUrl, int javaVersion, @Nullable String mainClass) { + ToolImpl(String name, SharedUtil.SimpleModuleVersionIdentifier module, String artifact, String mavenUrl, int javaVersion, @Nullable String mainClass) { this( name, module, artifact, String.format("%s-%s.jar", name, module.getVersion()), - module.getDownloadUrl(mavenUrl != null ? mavenUrl : "https://maven.minecraftforge.net/"), + module.getDownloadUrl(mavenUrl), javaVersion, mainClass ); From a0274c7b693a25c6c993ad380c70a7b1a36fd619 Mon Sep 17 00:00:00 2001 From: Jonathing Date: Sun, 28 Dec 2025 12:41:41 -0500 Subject: [PATCH 5/6] Look for Main-Class in ToolExecBase --- .../gradleutils/shared/EnhancedProblems.java | 18 +++++++++++-- .../gradleutils/shared/ToolExecBase.java | 27 ++++++++++++++++++- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/EnhancedProblems.java b/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/EnhancedProblems.java index 83349db..0fa9742 100644 --- a/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/EnhancedProblems.java +++ b/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/EnhancedProblems.java @@ -31,7 +31,6 @@ import java.io.Serializable; import java.nio.file.Files; import java.util.Collection; -import java.util.Locale; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -213,7 +212,8 @@ final RuntimeException illegalPluginTarget(Exception e, String allowedTargets) { final RuntimeException pluginNotYetApplied(Exception e) { return this.throwing(e, "plugin-not-yet-applied", String.format("%s is not applied", this.displayName), spec -> spec .details(""" - Attempted to get details from the %s plugin, but it has not yet been applied to the target.""".formatted(this.displayName)) + Attempted to get details from the %s plugin, but it has not yet been applied to the target.""" + .formatted(this.displayName)) .severity(Severity.ERROR) .stackLocation() .solution("Apply the plugin before attempting to use it from the target's plugin manager.") @@ -223,6 +223,20 @@ final RuntimeException pluginNotYetApplied(Exception e) { } //endregion + //region ToolExec + final RuntimeException toolExecNoMainClass(Exception e, Task task) { + getLogger().error("ERROR: Failed to find Main-Class for tool task: {}", task.getName()); + return throwing(e, "toolexec-missing-main-class", "Renamer tool not executable jar", spec -> spec + .details(""" + When using a tool execution task, the classpath must be a single executable jar with no transitive dependencies. + If this is not the case, then you must specify the main class using %s.mainClass = 'some.class'""" + .formatted(task.getName())) + .severity(Severity.ERROR) + .solution("Specify the main class for task '" + task.getName() + "'.") + .solution(HELP_MESSAGE)); + } + //endregion + //region Utilities /// A utility method to ensure that a [FileSystemLocation] [Provider] has (its parent) directory created. If the diff --git a/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/ToolExecBase.java b/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/ToolExecBase.java index 3616942..416e653 100644 --- a/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/ToolExecBase.java +++ b/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/ToolExecBase.java @@ -14,6 +14,7 @@ import org.gradle.api.artifacts.dsl.ExternalModuleDependencyVariantSpec; import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.file.FileCollection; import org.gradle.api.file.FileSystemLocation; import org.gradle.api.file.FileSystemLocationProperty; import org.gradle.api.file.RegularFileProperty; @@ -57,6 +58,7 @@ import java.util.Locale; import java.util.Map; import java.util.concurrent.Callable; +import java.util.jar.JarFile; /// This tool execution task is a template on top of [JavaExec] to make executing [tools][Tool] much easier and more /// consistent between plugins. @@ -136,7 +138,7 @@ protected ToolExecBase(Tool tool) { this.getClasspath().setFrom(resolved.getClasspath()); if (resolved.hasMainClass()) - this.getMainClass().set(resolved.getMainClass()); + this.getMainClass().convention(getProviders().provider(resolved::getMainClass).orElse(getProviders().provider(this::findMainClass))); this.getJavaLauncher().set(resolved.getJavaLauncher()); this.getToolchainLauncher().convention(getJavaToolchains().launcherFor(spec -> spec.getLanguageVersion().set(JavaLanguageVersion.current()))); @@ -301,6 +303,29 @@ protected ExecResult exec() throws IOException { } } + private String findMainClass() { + File tool; + try { + tool = this.getClasspath().getSingleFile(); + } catch (IllegalStateException exception) { + throw problems.toolExecNoMainClass(exception, this); + } + + try (var jar = new JarFile(tool)) { + var manifest = jar.getManifest(); + if (manifest == null) + throw problems.toolExecNoMainClass(new IllegalStateException("Tool jar does not have manifest: " + tool.getAbsolutePath()), this); + + var mainClass = manifest.getMainAttributes().getValue("Main-Class"); + if (mainClass == null) + throw problems.toolExecNoMainClass(new IllegalStateException("Tool jar does not have Main-Class entry in its Manifest: " + tool.getAbsolutePath()), this); + + return mainClass; + } catch (IOException e) { + throw problems.toolExecNoMainClass(new IllegalStateException("Tool jar does not have Main-Class entry in its Manifest: " + tool.getAbsolutePath(), e), this); + } + } + protected final void args(Object... args) { this.args(Arrays.asList(args)); } From baa35b19cb66629d7928508a58ea4e644ed61934 Mon Sep 17 00:00:00 2001 From: Jonathing Date: Sun, 28 Dec 2025 12:44:46 -0500 Subject: [PATCH 6/6] Revert "Look for Main-Class in ToolExecBase" This reverts commit a0274c7b693a25c6c993ad380c70a7b1a36fd619. --- .../gradleutils/shared/EnhancedProblems.java | 18 ++----------- .../gradleutils/shared/ToolExecBase.java | 27 +------------------ 2 files changed, 3 insertions(+), 42 deletions(-) diff --git a/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/EnhancedProblems.java b/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/EnhancedProblems.java index 0fa9742..83349db 100644 --- a/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/EnhancedProblems.java +++ b/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/EnhancedProblems.java @@ -31,6 +31,7 @@ import java.io.Serializable; import java.nio.file.Files; import java.util.Collection; +import java.util.Locale; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -212,8 +213,7 @@ final RuntimeException illegalPluginTarget(Exception e, String allowedTargets) { final RuntimeException pluginNotYetApplied(Exception e) { return this.throwing(e, "plugin-not-yet-applied", String.format("%s is not applied", this.displayName), spec -> spec .details(""" - Attempted to get details from the %s plugin, but it has not yet been applied to the target.""" - .formatted(this.displayName)) + Attempted to get details from the %s plugin, but it has not yet been applied to the target.""".formatted(this.displayName)) .severity(Severity.ERROR) .stackLocation() .solution("Apply the plugin before attempting to use it from the target's plugin manager.") @@ -223,20 +223,6 @@ final RuntimeException pluginNotYetApplied(Exception e) { } //endregion - //region ToolExec - final RuntimeException toolExecNoMainClass(Exception e, Task task) { - getLogger().error("ERROR: Failed to find Main-Class for tool task: {}", task.getName()); - return throwing(e, "toolexec-missing-main-class", "Renamer tool not executable jar", spec -> spec - .details(""" - When using a tool execution task, the classpath must be a single executable jar with no transitive dependencies. - If this is not the case, then you must specify the main class using %s.mainClass = 'some.class'""" - .formatted(task.getName())) - .severity(Severity.ERROR) - .solution("Specify the main class for task '" + task.getName() + "'.") - .solution(HELP_MESSAGE)); - } - //endregion - //region Utilities /// A utility method to ensure that a [FileSystemLocation] [Provider] has (its parent) directory created. If the diff --git a/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/ToolExecBase.java b/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/ToolExecBase.java index 416e653..3616942 100644 --- a/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/ToolExecBase.java +++ b/gradleutils-shared/src/main/java/net/minecraftforge/gradleutils/shared/ToolExecBase.java @@ -14,7 +14,6 @@ import org.gradle.api.artifacts.dsl.ExternalModuleDependencyVariantSpec; import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.DirectoryProperty; -import org.gradle.api.file.FileCollection; import org.gradle.api.file.FileSystemLocation; import org.gradle.api.file.FileSystemLocationProperty; import org.gradle.api.file.RegularFileProperty; @@ -58,7 +57,6 @@ import java.util.Locale; import java.util.Map; import java.util.concurrent.Callable; -import java.util.jar.JarFile; /// This tool execution task is a template on top of [JavaExec] to make executing [tools][Tool] much easier and more /// consistent between plugins. @@ -138,7 +136,7 @@ protected ToolExecBase(Tool tool) { this.getClasspath().setFrom(resolved.getClasspath()); if (resolved.hasMainClass()) - this.getMainClass().convention(getProviders().provider(resolved::getMainClass).orElse(getProviders().provider(this::findMainClass))); + this.getMainClass().set(resolved.getMainClass()); this.getJavaLauncher().set(resolved.getJavaLauncher()); this.getToolchainLauncher().convention(getJavaToolchains().launcherFor(spec -> spec.getLanguageVersion().set(JavaLanguageVersion.current()))); @@ -303,29 +301,6 @@ protected ExecResult exec() throws IOException { } } - private String findMainClass() { - File tool; - try { - tool = this.getClasspath().getSingleFile(); - } catch (IllegalStateException exception) { - throw problems.toolExecNoMainClass(exception, this); - } - - try (var jar = new JarFile(tool)) { - var manifest = jar.getManifest(); - if (manifest == null) - throw problems.toolExecNoMainClass(new IllegalStateException("Tool jar does not have manifest: " + tool.getAbsolutePath()), this); - - var mainClass = manifest.getMainAttributes().getValue("Main-Class"); - if (mainClass == null) - throw problems.toolExecNoMainClass(new IllegalStateException("Tool jar does not have Main-Class entry in its Manifest: " + tool.getAbsolutePath()), this); - - return mainClass; - } catch (IOException e) { - throw problems.toolExecNoMainClass(new IllegalStateException("Tool jar does not have Main-Class entry in its Manifest: " + tool.getAbsolutePath(), e), this); - } - } - protected final void args(Object... args) { this.args(Arrays.asList(args)); }