Class ForgeExternalToolService

java.lang.Object
net.fabricmc.loom.util.service.Service<ForgeExternalToolService.Options>
dev.architectury.loom.forge.tool.ForgeExternalToolService

public final class ForgeExternalToolService extends Service<ForgeExternalToolService.Options>
服务化的「一次外部 Forge 工具调用」.

它是 ForgeToolService 的「带工具声明」版本:ForgeToolService 只负责执行器本身 (JVM 可执行文件、日志透传等与项目状态相关的基设置),本服务额外把**工具本体**——承载它的 jar 集合、 主类与参数——放到 ForgeExternalToolService.Options 上声明出去。

为什么要有这一层

改造前这类调用走 ForgeToolValueSource.exec(org.gradle.api.Project, org.gradle.api.Action<? super dev.architectury.loom.forge.tool.ForgeToolExecutor.Settings>):它由**项目**的 ProviderFactory 创建 ValueSource 并立刻求值,因此只能在配置期同步执行;工具 classpath 也在那一刻被 DependencyDownloader 解析掉。把工具声明搬进服务选项后:
  • classpath 是惰性的(配置期只接线,取值推迟到真正执行时),于是它既能在配置期路径里被解析, 也能作为任务的 @Classpath 输入在执行期取值,并获得正确的 up-to-date 判定;
  • 发起调用只需要一个 ServiceFactory,不再需要 Project,因此同一次调用既能由 配置期路径发起,也能由执行期任务发起;
  • 服务只持有选项,选项可以被配置缓存序列化,因此可以作为任务的 @Nested 输入携带。

参数模板

工具的参数以「模板」形式声明(ForgeExternalToolService.Options.getArgsTemplate()):模板里可以留 {name} 形式的占位符,由调用方在 exec(java.util.Map<java.lang.String, java.lang.String>) 时给出实际取值。这样一来,配置期才能确定的取值(例如工具任务名、 输入 jar 路径)可以就地定死在模板里,而只有调用时才知道的路径(例如本次调用的临时输出文件)留作占位符, 两者都是任务声明的输入,执行期不必回读项目模型。

调用只有一处构造

settingsFor(java.util.Map<java.lang.String, java.lang.String>) 造出本次调用实际交给 Gradle 的工具设置,exec(java.util.Map<java.lang.String, java.lang.String>) 就是把它交给 ForgeToolService 去执行。两者不会分叉,因此「实际执行的命令行与 classpath」可以被直接断言。
  • Field Details

  • Constructor Details

  • Method Details

    • createOptions

      public static org.gradle.api.provider.Provider<ForgeExternalToolService.Options> createOptions(org.gradle.api.Project project, org.gradle.api.file.FileCollection toolClasspath, org.gradle.api.provider.Provider<String> mainClass)
      创建工具选项.

      只接线、不求值:toolClasspath 的取值被推迟到 exec(java.util.Map<java.lang.String, java.lang.String>)(或任务的输入快照)时, 因此本方法可以在配置期安全调用,也可以把返回的 provider 挂成任务的 @Nested 输入。

      Parameters:
      project - 当前项目,用于惰性 provider 与执行器基设置
      toolClasspath - 工具及其依赖的 jar
      mainClass - 工具主类
      Returns:
      工具选项
    • createOptions

      public static org.gradle.api.provider.Provider<ForgeExternalToolService.Options> createOptions(org.gradle.api.Project project, org.gradle.api.file.FileCollection toolClasspath, String mainClass)
      创建工具选项,主类固定为一个常量(工具清单里没有 Main-Class 时用).
      Parameters:
      project - 当前项目
      toolClasspath - 工具及其依赖的 jar
      mainClass - 工具主类
      Returns:
      工具选项
    • createOptionsFromManifest

      public static org.gradle.api.provider.Provider<ForgeExternalToolService.Options> createOptionsFromManifest(org.gradle.api.Project project, org.gradle.api.file.FileCollection toolClasspath)
      创建工具选项,主类取工具 jar 清单里的 Main-Class.
      Parameters:
      project - 当前项目
      toolClasspath - 工具及其依赖的 jar
      Returns:
      工具选项
    • manifestMainClass

      public static String manifestMainClass(Iterable<File> files)
      Returns 给定 jar 集合里第一个清单含 Main-Class 的那个值..

      与改造前 MinecraftPatchedProvider.getMainClass 逐字一致:只认 .jar 结尾的条目, 读取失败的异常累积下来,全部读完仍没有主类时抛出。

      Parameters:
      files - 工具及其依赖的 jar(已解析)
      Returns:
      给定 jar 集合里第一个清单含 Main-Class 的那个值
    • settingsFor

      public ForgeToolExecutor.Settings settingsFor(Map<String,String> placeholders)
      展开参数模板,构造本次调用交给 Gradle 的工具设置.

      exec(java.util.Map<java.lang.String, java.lang.String>) 走的就是这里,因此返回值的每一个字段都是「实际执行时」的取值:可以直接断言 命令行(ForgeToolExecutor.Settings.getMainClass() 与 ForgeToolExecutor.Settings.getProgramArgs())、classpath(getExecClasspath()) 与执行器(getExecutable())。

      工作目录与环境变量不在这里:ForgeToolExecutor 从不设置它们,故两者始终沿用 Gradle 自身的默认值(与改造前一致)。

      Parameters:
      placeholders - 占位符(含花括号)到实际参数的映射;模板里没有匹配到的条目原样保留
      Returns:
      工具设置
    • exec

      public void exec(Map<String,String> placeholders)
      执行工具.

      命令行与 classpath 由 settingsFor(java.util.Map<java.lang.String, java.lang.String>) 给出,本方法只把它交给 ForgeToolService: 那个服务负责注入执行器(JVM 与日志透传),并通过 ValueSource 在**执行那一刻**发起进程, 因此调用点搬到任务里也不会在配置期触发求值。

      Parameters:
      placeholders - 占位符(含花括号)到实际参数的映射
    • placeholders

      public List<String> placeholders()
      Returns 参数模板里出现的全部占位符..

      供诊断与测试断言使用:调用方据此知道该给 exec(java.util.Map<java.lang.String, java.lang.String>) 准备哪些取值。

      Returns:
      参数模板里出现的全部占位符