Class ForgeExternalToolService
它是 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」可以被直接断言。-
Nested Class Summary
Nested Classes -
Field Summary
FieldsModifier and TypeFieldDescription -
Constructor Summary
ConstructorsConstructorDescriptionForgeExternalToolService(ForgeExternalToolService.Options options, ServiceFactory serviceFactory) -
Method Summary
Modifier and TypeMethodDescriptionstatic org.gradle.api.provider.Provider<ForgeExternalToolService.Options> createOptions(org.gradle.api.Project project, org.gradle.api.file.FileCollection toolClasspath, String mainClass) 创建工具选项,主类固定为一个常量(工具清单里没有Main-Class时用).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) 创建工具选项.static org.gradle.api.provider.Provider<ForgeExternalToolService.Options> createOptionsFromManifest(org.gradle.api.Project project, org.gradle.api.file.FileCollection toolClasspath) 创建工具选项,主类取工具 jar 清单里的Main-Class.void执行工具.static StringmanifestMainClass(Iterable<File> files) Returns 给定 jar 集合里第一个清单含Main-Class的那个值.Returns 参数模板里出现的全部占位符.settingsFor(Map<String, String> placeholders) 展开参数模板,构造本次调用交给 Gradle 的工具设置.Methods inherited from class net.fabricmc.loom.util.service.Service
getOptions, getServiceFactory
-
Field Details
-
TYPE
-
-
Constructor Details
-
ForgeExternalToolService
public ForgeExternalToolService(ForgeExternalToolService.Options options, ServiceFactory serviceFactory)
-
-
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- 工具及其依赖的 jarmainClass- 工具主类- 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- 工具及其依赖的 jarmainClass- 工具主类- 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
Returns 给定 jar 集合里第一个清单含Main-Class的那个值..与改造前
MinecraftPatchedProvider.getMainClass逐字一致:只认.jar结尾的条目, 读取失败的异常累积下来,全部读完仍没有主类时抛出。- Parameters:
files- 工具及其依赖的 jar(已解析)- Returns:
- 给定 jar 集合里第一个清单含
Main-Class的那个值
-
settingsFor
展开参数模板,构造本次调用交给 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
执行工具.命令行与 classpath 由
settingsFor(java.util.Map<java.lang.String, java.lang.String>)给出,本方法只把它交给ForgeToolService: 那个服务负责注入执行器(JVM 与日志透传),并通过ValueSource在**执行那一刻**发起进程, 因此调用点搬到任务里也不会在配置期触发求值。- Parameters:
placeholders- 占位符(含花括号)到实际参数的映射
-
placeholders
Returns 参数模板里出现的全部占位符..供诊断与测试断言使用:调用方据此知道该给
exec(java.util.Map<java.lang.String, java.lang.String>)准备哪些取值。- Returns:
- 参数模板里出现的全部占位符
-