1. 使用 sbt 建立命令列應用程式

使用 sbt 建立命令列應用程式 

sbt 有幾個元件可以用來建立命令列應用程式。此處說明了啟動器命令系統這兩個主要元件。

啟動器頁面所述,已啟動的應用程式會實作 xsbti.AppMain 介面,並定義一個簡短的組態檔,使用者將此檔案傳遞給啟動器以執行應用程式。若要使用命令系統,應用程式會設定一個狀態執行個體,此執行個體會提供命令實作和要執行的初始命令。以下提供了一個最小的 hello world 範例。

Hello World 範例 

此範例中有三個檔案

  1. build.sbt
  2. Main.scala
  3. hello.build.properties

若要試用此範例

  1. 將前兩個檔案放入新目錄
  2. 在 sbt 的 shell 中,在該目錄中執行 publishLocal
  3. 執行 sbt @path/to/hello.build.properties 來執行應用程式。

如同 sbt 本身,您可以從命令列指定命令(批次模式),或在提示字元(互動模式)中執行它們。

建置定義:build.sbt 

build.sbt 檔案應定義標準設定:名稱、版本和組織。若要使用 sbt 命令系統,需要相依於 command 模組。若要使用任務系統,也請新增相依於 task-system 模組的相依性。

organization := "org.example"

name := "hello"

version := "0.1-SNAPSHOT"

libraryDependencies += "org.scala-sbt" % "command" % "0.12.0"

應用程式:Main.scala 

應用程式本身是透過實作xsbti.AppMain 來定義。基本步驟如下

  1. 提供命令定義。這些是使用者可以執行的命令。
  2. 定義初始命令。這些是要最初排定執行的命令。例如,應用程式通常會新增在命令列上指定的任何內容(sbt 稱之為批次模式),如果未定義任何命令,則會執行 'shell' 命令來進入互動模式。
  3. 設定記錄。範例中的預設設定會在每次使用者互動後輪換記錄檔,並將簡短記錄傳送到主控台,將詳細記錄傳送到記錄檔。
package org.example

   import sbt._
   import java.io.{File, PrintWriter}

final class Main extends xsbti.AppMain
{
   /** Defines the entry point for the application.
   * The call to `initialState` sets up the application.
   * The call to runLogged starts command processing. */
   def run(configuration: xsbti.AppConfiguration): xsbti.MainResult =
      MainLoop.runLogged( initialState(configuration) )

   /** Sets up the application by constructing an initial State instance with the supported commands
   * and initial commands to run.  See the State API documentation for details. */
   def initialState(configuration: xsbti.AppConfiguration): State =
   {
      val commandDefinitions = hello +: BasicCommands.allBasicCommands
      val commandsToRun = Hello +: "iflast shell" +: configuration.arguments.map(_.trim)
      State( configuration, commandDefinitions, Set.empty, None, commandsToRun, State.newHistory,
         AttributeMap.empty, initialGlobalLogging, State.Continue )
   }

   // defines an example command.  see the Commands page for details.
   val Hello = "hello"
   val hello = Command.command(Hello) { s =>
      s.log.info("Hello!")
      s
   }

   /** Configures logging to log to a temporary backing file as well as to the console. 
   * An application would need to do more here to customize the logging level and
   * provide access to the backing file (like sbt's last command and logLevel setting).*/
   def initialGlobalLogging: GlobalLogging =
      GlobalLogging.initial(MainLogging.globalDefault _, File.createTempFile("hello", "log"))
}

啟動器組態檔:hello.build.properties 

啟動器需要一個組態檔才能擷取和執行應用程式。 hello.build.properties

[scala]
  version: 2.9.1

[app]
  org: org.example
  name: hello
  version: 0.1-SNAPSHOT
  class: org.example.Main
  components: xsbti
  cross-versioned: true

[repositories]
  local
  maven-central
  typesafe-ivy-releases: https://repo.typesafe.com/typesafe/ivy-releases/, [organization]/[module]/[revision]/[type]s/[artifact](-[classifier]).[ext]