アーティファクト

説明

サブプロジェクトの特定バージョンを公開するためのファイルは、特別に「アーティファクト」と呼ばれる。この概念は Apache MavenIvy に由来する。

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>

ここから、アーティファクトは name、type、extension という属性を持ち、オプションで classifier があることが分かる。

  • name。サブプロジェクトのモジュール名と同じになる。
  • type。アーティファクトの機能カテゴリ。jarsrcdoc など。
  • extensionjarwarzipxml などのファイル拡張子。
  • classifier。Maven では、代替または二次アーティファクト用に付加できる任意の文字列である。

デフォルト・アーティファクトの選択

デフォルトで公開されるアーティファクトは以下の通りである:

  1. メインのバイナリ JAR
  2. メインのソースとリソースを含む JAR
  3. 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>) でスコープされる。

メインアーティファクトの type を変更する例:

Compile / packageBin / artifact := {
  val prev: Artifact = (Compile / packageBin / artifact).value
  prev.withType("bundle")
}

生成されるアーティファクト名は artifactName セッティングで決まる。このセッティングの型は (ScalaVersion, ModuleID, Artifact) => String である。ScalaVersion 引数は Scala のフルバージョン文字列とバイナリ互換部分を提供する。結果の文字列は生成するファイル名である。デフォルト実装は Artifact.artifactName _ である。この関数を変更すると、artifact 定義とリポジトリパターンで決まる公開名に影響せず、ローカル名を変えられる。

例えば、classifier や cross path なしの最小限の名前を生成する場合:

artifactName := { (sv: ScalaVersion, module: ModuleID, artifact: Artifact) =>
  artifact.name + "-" + module.revision + "." + artifact.extension
}

(実際には classifier を削除することはほとんどない。)

最後に、packagedArtifact タスクをマッピングしてアーティファクトの (Artifact, File) ペアを取得できる。Artifact が不要な場合は、パッケージタスク(packagepackageDocpackageSrc)から 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 アプリケーションの一般的な用途として、.jar ファイルの代わりに .war ファイルを公開する。

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"))

fromclassifier メソッド(sbt update で説明)は、実際にはartifacts に変換される便利メソッドである:

def from(url: String) = artifacts(Artifact(name, new URL(url)))
def classifier(c: String) = artifacts(Artifact(name, c))

つまり、以下の 2つのライブラリ依存性宣言は等価である:

libraryDependencies += ("org.testng" % "testng" % "5.7").classifier("jdk15")

libraryDependencies += ("org.testng" % "testng" % "5.7").artifacts(Artifact("testng", "jdk15"))