工件
描述
工件是用于发布子项目特定版本的单个文件。该概念源自 Apache Maven 和 Ivy。
在 JVM 生态中,常见工件为 Java 归档(JAR 文件)。压缩包格式通常更受青睐,因其更易管理、下载和存储。
举例来说,以下是库的工件列表,在 ivy.xml 文件中枚举:
<publications>
<artifact name="core_3" type="jar" ext="jar" conf="compile"/>
<artifact e:classifier="sources" name="core_3" type="src" ext="jar" conf="sources"/>
<artifact e:classifier="javadoc" name="core_3" type="doc" ext="jar" conf="docs"/>
<artifact name="core_3" type="pom" ext="pom" conf="pom"/>
</publications>
这表明工件具有名称、类型和扩展名,以及可选的 classifier。
- name。与子项目的模块名相同。
- type。工件的功能类别,如
jar、src和doc。 - extension。文件扩展名,如
jar、war、zip、xml等。 - classifier。在 Maven 中,classifier 是可为替代或次要工件追加的任意字符串。
选择默认工件
默认发布的工件为:
- 主二进制 JAR
- 包含主源码和资源的 JAR
- 包含 API 文档的 JAR
您可添加测试类、源码或 API 的工件,也可禁用部分主工件。
要添加所有 Test 工件:
lazy val app = (project in file("app"))
.settings(
Test / publishArtifact := true,
)
要单独添加:
lazy val app = (project in file("app"))
.settings(
// enable publishing the jar produced by `Test/package`
Test / packageBin / publishArtifact := true,
// enable publishing the test API jar
Test / packageDoc / publishArtifact := true,
// enable publishing the test sources jar
Test / packageSrc / publishArtifact := true,
)
要单独禁用主工件:
lazy val app = (project in file("app"))
.settings(
// disable publishing the main jar produced by `package`
Compile / packageBin / publishArtifact := false,
// disable publishing the main API jar
Compile / packageDoc / publishArtifact := false,
// disable publishing the main sources jar
Compile / packageSrc / publishArtifact := false,
)
修改默认工件
除 publishArtifact 外,每个内置工件还有若干可配置设置。基本包括 artifact(类型为 SettingKey[Artifact])、mappings(类型为 TaskKey[(File, String)])和 artifactPath(类型为 SettingKey[File])。它们按上一节所述以 (Config / <task>) 限定作用域。
例如,要修改主工件的类型:
Compile / packageBin / artifact := {
val prev: Artifact = (Compile / packageBin / artifact).value
prev.withType("bundle")
}
生成的工件名由 artifactName 设置决定。该设置类型为 (ScalaVersion, ModuleID, Artifact) => String。ScalaVersion 参数提供完整 Scala 版本字符串及版本字符串的二进制兼容部分。返回的 String 为要生成的文件名。默认实现为 Artifact.artifactName _。可修改该函数以生成不同的本地工件名,而不影响发布名(发布名由 artifact 定义与仓库模式共同决定)。
例如,要生成不含 classifier 或交叉路径的最小名称:
artifactName := { (sv: ScalaVersion, module: ModuleID, artifact: Artifact) =>
artifact.name + "-" + module.revision + "." + artifact.extension
}
(注意:实践中很少会去掉 classifier。)
最后,您可通过映射 packagedArtifact 任务获取工件的 (Artifact, File) 对。若不需要 Artifact,可从打包任务(package、packageDoc 或 packageSrc)直接获取 File。两种情况下,映射任务以获取文件均可确保先生成工件,从而保证文件为最新。
例如:
val myTask = taskKey[Unit]("My task.")
myTask := {
val (art, file) = (Compile / packageBin / packagedArtifact).value
println("Artifact definition: " + art)
println("Packaged file: " + file.getAbsolutePath)
}
定义自定义工件
除配置内置工件外,您还可声明要发布的其他工件。使用 Ivy 元数据时允许多个工件,但 Maven POM 文件仅支持基于 classifier 区分工件,且这些信息不会记录在 POM 中。
基本 Artifact 构造如下:
Artifact("name", "type", "extension")
Artifact("name", "classifier")
Artifact("name", url: URL)
Artifact("name", Map("extra1" -> "value1", "extra2" -> "value2"))
例如:
Artifact("myproject", "zip", "zip")
Artifact("myproject", "image", "jpg")
Artifact("myproject", "jdk15")
有关工件的更多详情,请参阅 Ivy 文档。有关组合上述参数并指定 [Configurations] 和额外属性,请参阅 Artifact API。
要将这些工件声明为发布,请将它们映射到生成工件的任务:
val myImageTask = taskKey[File](...)
myImageTask := {
val artifact: File = makeArtifact(...)
artifact
}
addArtifact(Artifact("myproject", "image", "jpg"), myImageTask)
addArtifact 返回一系列设置(包装在 SettingsDefinition 中)。在完整构建配置中的用法如下:
lazy val app = (project in file("app"))
.settings(
addArtifact(...)
)
发布 .war 文件
Web 应用的常见做法是发布 .war 文件而非 .jar 文件。
lazy val app = (project in file("app"))
.settings(
// disable .jar publishing
Compile / packageBin / publishArtifact := false,
// create an Artifact for publishing the .war file
Compile / packageWar / artifact := {
val prev: Artifact = (Compile / packageWar / artifact).value
prev.withType("war").withExtension("war")
},
// add the .war file to what gets published
addArtifact(Compile / packageWar / artifact, packageWar),
)
使用带工件的依赖
要从具有自定义或多个工件的依赖中指定要使用的工件,请在依赖上使用 artifacts 方法。例如:
libraryDependencies += ("org" % "name" % "rev").artifacts(Artifact("name", "type", "ext"))
from 和 classifer 方法(在 sbt update 页中描述)实际上是转换为 artifacts 的便捷方法:
def from(url: String) = artifacts(Artifact(name, new URL(url)))
def classifier(c: String) = artifacts(Artifact(name, c))
即,以下两种依赖声明等价:
libraryDependencies += ("org.testng" % "testng" % "5.7").classifier("jdk15")
libraryDependencies += ("org.testng" % "testng" % "5.7").artifacts(Artifact("testng", "jdk15"))