sbt入门指南翻译(5)自定义任务/ 组织--渣翻译有错误望指教

Custom settings and tasks(自定义设置和任务)

Defining a key(定义一个关键字)

关键字已经在例子说明很多了怎样去定义个关键字。大多数关键字都是默认实现的。

 

关键字拥有三个类型。SettingKey 和 TaskKey 在.sbt构造定义里面描述。InputKey在任务章节有介绍

 

一些关键字例子

val scalaVersion =settingKey[String]("The version of Scala used forbuilding.")

val clean =taskKey[Unit]("Deletes files produced by the build, such as generated sources,compiled

 

关键字构造有两个字符串参数:一个关键字的名字("scalaVersion") 和一个文档描述字符串("Theversion of scala used for building.")

 

从 .sbt构造定义回想一下在SettingKey[T]里T参数类型,描述了存储值的类型。在TaskKey[T]里面T是描述任务结果的类型。从 .sbt构造定义回想一个setting是有当项目加载的时候,分配一个固定的值,而一个任务每次执行会重复计算。

 

关键字需要定义到.sbt文件,.scala文件或者是一个自动加载插件。任何vals 找到 autoImport 对象下启动自动插件会自动导入你的.sbt文件

 

Implementing a task(实现一个任务)

一旦你为你的任务定义一个关键字,你需要用一个任务定义来计算它。你可以定义你自己的任务,或者计划去重新定义一个已经存在的任务。无论哪种方式看起来都像一样。使用:=来联系一些代码通过任务关键字:

 

val sampleStringTask= taskKey[String]("A sample string task.")

val sampleIntTask =taskKey[Int]("A sample int task.")

 

lazy val commonSettings =Seq(

organization := "com.example",

version := "0.1.0-SNAPSHOT"

)

lazy val library =(project in file("library")).

settings(commonSettings: _*).

settings(

sampleStringTask := System.getProperty("user.home"),

sampleIntTask := {

val sum = 1 + 2

println("sum: " + sum)

sum

}

)

 

如果任务有依赖,你需要引用他们的值使用value方法,就像在更多类型关键字讨论一样

 

在实现任务最困难的部分茶花村不是sbt特有的。任务仅仅是scala代码。困难的部分就是写你任务的内容做就是你尝试去做的。例如,你可能在使用HTML库的情况下尝试格式一个HTML。

 

Sbt有一些使用库 和通用方法,特别是你可以常常使用API操作IO操作文件和路径

 

 

Execution semantics of tasks(执行语义任务)

当一个自定义任务依赖其他任务使用 value方法,一个重要的细节是注意任务执行的语义。通过执行语义,我们意味当这些任务被评估

 

如果我们用一个sampleIntTask作为例子,任务代码块每行被严格一个跟一个执行. 这就是一个语义顺序

sampleIntTask := {

val sum = 1 + 2 // first

println("sum: " + sum) // second

sum // third

}

 

实际上jvm可以内联 sum 到 3,但是观察任务的影响会保持相同如果每一行执行是一个接一个

 

现在假设我们定义了两个自定义任务 startServer 和 stopServer,和一个修改sampleIntTask如下

 

val startServer =taskKey[Unit]("start server")

val stopServer =taskKey[Unit]("stop server")

val sampleIntTask =taskKey[Int]("A sample int task.")

val sampleStringTask= taskKey[String]("A sample string task.")

 

lazy val commonSettings =Seq(

organization := "com.example",

version := "0.1.0-SNAPSHOT"

)

lazy val library =(project in file("library")).

settings(commonSettings: _*).

settings(

startServer := {

println("starting...")

Thread.sleep(500)

},

stopServer := {

println("stopping...")

Thread.sleep(500)

},

sampleIntTask := {

startServer.value

val sum = 1 + 2

println("sum: " + sum)

stopServer.value // THIS WON'TWORK

sum

},

sampleStringTask := {

startServer.value

val s = sampleIntTask.value.toString

println("s: " + s)

s

}

)

在sbt交互模式下运行sampleIntTask 结果如下:

 

> sampleIntTask

stopping...

starting...

sum: 3

[success] Total time: 1 s, completed Dec 22, 2014 5:00:00PM

 

我们检查发生什么,看一下sampleIntTask: 图像执行符号

 

不像scala计划那样执行方法,在任务 执行value 方法并不会严格过程。反而,他们简单看作占位符表示sampleIntTask 依赖 startServer 和 stopServer。当通过你执行sampleIntTask,sbt任务引擎将会:

1.      在执行sampleIntTask之前 执行依赖的任务(偏序)

2.      尝试并行执行依赖任务,如果这些任务都是独立的(并行)

3.      每个依赖任务可能执行一次并且每次命令只会执行一次(两分)

 

Deduplication of task dependencies(任务依赖分开)

为了证明最后一个论点,我们在sbt交互模式下执行sampleStringTask

> sampleStringTask

stopping...

starting...

sum: 3

s: 3

[success] Total time: 1 s, completed Dec 22, 2014 5:30:00PM

 

因为 sampleStringTask同时依赖 startServer 和 sampleIntTask,而sampleIntTask也依赖startServer,这样就会一个任务被依赖两次。如果是在scala方法调用,就会执行两次,但是因为value只会表示一个依赖任务,它就只会执行一次。

下面就是sampleStringTask’s 执行图片

 

 

如果我们不删除任务依赖,我们相会最终编译 测试代码会被执行多次 当 测试任务之被调用因为 compile in Test 出现多次作为一个依赖的任务在test in Test.

 

Cleanup task(清理任务)

怎样实现一个stopServer任务?清理任务的观点在任务执行模型上并不是适合,因为任务都是关于跟踪依赖的。最后操作应该成为任务内部子任务所决定的。例如stopServer 实例应该是取决于 sampleStringTask,,stopServer 应该属于 sampleStringTask.。

 

lazy val library =(project in file("library")).

settings(commonSettings: _*).

settings(

startServer := {

println("starting...")

Thread.sleep(500)

},

sampleIntTask := {

startServer.value

val sum = 1 + 2

println("sum: " + sum)

sum

},

sampleStringTask := {

startServer.value

val s = sampleIntTask.value.toString

println("s: " + s)

s

},

sampleStringTask := {

val old = sampleStringTask.value

println("stopping...")

Thread.sleep(500)

old

}

)

 

为了证明它有效,我们执行sampleStringTask

> sampleStringTask

starting...

sum: 3

s: 3

stopping...

[success] Total time: 1 s, completed Dec 22, 2014 6:00:00PM

 

Use plain Scala(使用简单scala)

另一个方法确保有些发生在一些其他东西发生后去使用scala.。在project/ServerUtil.scala实现一个简单功能 ,如下

 

sampleIntTask := {

ServerUtil.startServer

try {

val sum = 1 + 2

println("sum: " + sum)

} finally {

ServerUtil.stopServer

}

sum

}

 

因为这种调用是根据语言顺序的,每样发生都是顺序的,这里没有两分,所以你需要小心点。

 

Turn them into plugins(把他们转成插件)

如果你发现你有很多自定义代码,考虑一下把他们放到一个插件被多个构造重复使用。

 

是一个很容易创建一个插件,正如前面讨论的。这里执行一个快速的尝试。。

 

 

 

Organizing the build(构造组织)

sbt is recursive(sbt是递归)

build.sbt 隐去了sbt怎样实际工作。 Sbt 构造是通过scala 代码定义的。这些代码,自身,需要去构造。有什么比sbt更加好的方法呢?

 

项目的目录是在你的build的其他build,知道怎样去构造你的build。区分builds,我们有时使用正确的术语引用你的build,并且引用构造项目的元构造

 

hello/ # your build's root project's base directory

Hello.scala# a source file in your build's root project

# (couldbe in src/main/scala too)

build.sbt# build.sbt is part of the source code for

#meta-build's root project inside project/;

# thebuild definition for your build

project/# base directory of meta-build's root project

Build.scala# a source file in the meta-build's root project,

# thatis, a source file in the build definition

# thebuild definition for your build

build.sbt# this is part of the source code for

#meta-meta-build's root project in project/project;

# builddefinition's build definition

project/# base directory of meta-meta-build's root project;

# thebuild definition project for the build definition

Build.scala# source file in the root project of

#meta-meta-build in project/project/

 

不用担心!大多数时间你不需要搞成这样。但是明白这个原理可能是有用的.

顺便说一下,任何时候以 .scala和.sbt结尾的文件都是可用的,但是命名build.sbt和Build.scala

是约定一个。这样就意味着多个文件是允许的

 

Tracking dependencies in one place(在一个地方跟踪依赖)

一个种使用事实是 在project下的.scala文件成为构造定义的一部分,去创建

project/Dependencies.scala  在一个地方跟踪依赖

 

import sbt._

object Dependencies {

// Versions

lazy val akkaVersion = "2.3.8"

// Libraries

val akkaActor = "com.typesafe.akka" %% "akka-actor" % akkaVersion

val akkaCluster = "com.typesafe.akka" %% "akka-cluster" % akkaVersion

val specs2core = "org.specs2" %% "specs2-core" % "2.4.14"

// Projects

val backendDeps =

Seq(akkaActor, specs2core % Test)

}

这个 Dependencies 对象可以在build.sbt使用,为了使用需要导入import Dependencies._.

 

import Dependencies._

 

lazy val commonSettings =Seq(

version := "0.1.0",

scalaVersion := "2.11.8"

)

lazy val backend =(project in file("backend")).

settings(commonSettings: _*).

settings(

libraryDependencies ++= backendDeps

)

 

这个技术是很有用的当你多个巨大的项目,并且你想保证子项目有相同的依赖

 

When to use .scalafiles(什么时候使用.scala文件)

在 .scala文件,你可以写任何scala代码,包括高级类和对象

 

推荐应用是去定义大部分设置在一个build.sbt文件,并且使用 project/*.scala文件对于任务实现和共享值,例如关键字。使用.scala文件也取决怎样通过scala 你和你的团队便利

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值