1. 一般的なベストプラクティス

一般的なベストプラクティス 

このページでは、sbt を使用するためのベストプラクティスについて説明します。

project/ vs. ~/.sbt/ 

プロジェクトのビルドに必要なものはすべて project/ に配置する必要があります。これには、web プラグインなどが含まれます。 ~/.sbt/ には、ビルドを操作するためのローカルのカスタマイズとコマンドを含める必要がありますが、必須ではありません。例としては、IDE プラグインがあります。

ローカル設定 

ユーザー固有の設定には、2 つのオプションがあります。このような設定の例としては、ローカル Maven リポジトリをリゾルバーリストの先頭に挿入することが挙げられます。

resolvers := {
  val localMaven = "Local Maven Repository" at "file://"+Path.userHome.absolutePath+"/.m2/repository"
  localMaven +: resolvers.value
}
  1. ユーザー固有の設定は、グローバル .sbt ファイル (例: $HOME/.sbt/1.0/global.sbt) に配置します。これらの設定はすべてのプロジェクトに適用されます。
  2. バージョン管理にチェックインされていないプロジェクトの .sbt ファイル (例: <project>/local.sbt) に設定を配置します。 sbt は複数の .sbt ファイルの設定を組み合わせるため、標準の <project>/build.sbt を使用し、それをバージョン管理にチェックインすることもできます。

.sbtrc 

sbt の起動時に実行されるコマンドは、.sbtrc ファイルに 1 行に 1 つずつ配置します。これらのコマンドはプロジェクトがロードされる前に実行され、エイリアスの定義などに役立ちます。 sbt は $HOME/.sbtrc (存在する場合) のコマンドを実行し、次に <project>/.sbtrc (存在する場合) のコマンドを実行します。

生成されたファイル 

生成されたファイルはすべて、target 設定で指定された出力ディレクトリのサブディレクトリに書き込みます。これにより、ビルド後のクリーンアップが容易になり、生成されたファイルを整理するための単一の場所が提供されます。 Scala バージョン固有の生成ファイルは、効率的なクロスビルドのために crossTarget に配置する必要があります。

ソースとリソースの生成については、ファイルの生成 を参照してください。

ハードコードしない 

出力ディレクトリ target/ などの定数をハードコードしないでください。これは特にプラグインにとって重要です。ユーザーが target 設定を build/ などに変更する場合があり、プラグインはそれを尊重する必要があります。代わりに、次のように設定を使用します。

myDirectory := target.value / "sub-directory"

ファイルを「変更」しない 

ビルドは、当然のことながら多くのファイル操作で構成されます。これを、変更可能な状態を回避するのに役立つタスクシステムとどのように両立させることができるでしょうか。推奨されるアプローチであり、sbt のデフォルトタスクで使用されるアプローチは、特定のファイルに一度だけ、単一のタスクからのみ書き込むことです。

ビルド成果物 (または副産物) は、1 つのタスクによって 1 回だけ書き込まれる必要があります。タスクは、少なくとも、作成されたファイルを結果として提供する必要があります。ファイルを使用する別のタスクは、タスクをマップし、同時にファイル参照を取得し、タスクが実行されたこと (したがってファイルが構築されたこと) を確認する必要があります。明らかに、ユーザーや他のプロセスがファイルを変更することについては何もできませんが、タスクレベルでファイルの内容を変更不可として扱うことにより、ビルドの制御下にある I/O をより予測可能にすることができます。

例えば

lazy val makeFile = taskKey[File]("Creates a file with some content.")

// define a task that creates a file,
//  writes some content, and returns the File
makeFile := {
    val f: File = file("/tmp/data.txt")
    IO.write(f, "Some content")
    f
}

// The result of makeFile is the constructed File,
//   so useFile can map makeFile and simultaneously
//   get the File and declare the dependency on makeFile
useFile :=
    doSomething( makeFile.value )

この配置は常に可能であるとは限りませんが、例外ではなくルールである必要があります。

絶対パスを使用する 

絶対ファイルのみを構築します。絶対パスを指定するか

file("/home/user/A.scala")

絶対ベースからファイルを構築します

base / "A.scala"

これは、適切な方法には baseDirectory 設定を参照することが含まれるため、ハードコーディングを行わないというベストプラクティスに関連しています。たとえば、以下では、myPath 設定を <base>/licenses/ ディレクトリに定義しています。

myPath := baseDirectory.value / "licenses"

Java (したがって Scala) では、相対ファイルは現在の作業ディレクトリからの相対パスです。作業ディレクトリは、さまざまな理由でビルドルートディレクトリと同じとは限りません。

このルールの唯一の例外は、プロジェクトのベースディレクトリを指定する場合です。ここでは、sbt は便宜上、ビルドルートディレクトリに対して相対ファイルを解決します。

パーサーコンビネーター 

  1. タブ補完の境界を明確に区切るために、どこでも token を使用します。
  2. トークンを重複させたりネストしたりしないでください。ここでの動作は未定であり、将来エラーが発生する可能性があります。
  3. 一般的な再帰には flatMap を使用します。 sbt のコンビネーターは生成されるクラスの数を制限するために厳密であるため、次のように flatMap を使用します。
lazy val parser: Parser[Int] =
  token(IntBasic) flatMap { i =>
    if(i <= 0)
      success(i)
    else
      token(Space ~> parser)
  }

この例では、負の数で終わる空白区切りの整数のリストを解析し、最後の負の数を返すパーサーを定義しています。