概述
作为Scala的标准构建工具,使用风格与Maven类似,由Scala语言写的,参考官方网站,目前的版本是0.13,虽然说Scala的项目可以通过Maven来构建和管理,但是依然推荐Sbt,更适合一些。
安装
有两种安装方式,标准版本的sbt只有基础的工具,构建工程和编译打包等需要的额外的工具在需要的时候会自动下载,比如说需要用2.11的版本来编译scala代码,就回下载当前最新的scala-2.11.7的:
- 独立的sbt-launch安装,Windows/Mac/Linux都有对应的安装过程,也是官方的标准工具,包含了sbt标准的命令;
- 通过安装typesafe activator,typesafe是一家商业公司,他们发布的这个工具包含了sbt,同时扩展了这个工具,包含了两个新的命令activator ui和activator new.
- activator ui可以通过视图的方式来管理构建的工程,在ui上可以查看项目模板、创建、运行、测试工作区内的项目,比较方便,另外typesafe提供了大量的教程代码,针对akka/play的不同的功能特性都有一些example代码,可以直接通过ui下载教程查看;
- activator new可以快速的创建项目,类似于maven通过选择archetype来快速创建项目,typesafe提供了很多种模板,包括了web项目,akka, spark,hadoop等等template,根据需要可以选择一种原型作为基础来修改。
配置
sbt虽然默认使用的是maven的仓库,但是是使用ivy来管理依赖,默认的本地缓存也是使用的是ivy的目录结构,与maven的.m2目录不同,是在用户目录下的.ivy目录下,这样会导致如果本地既有maven项目又有sbt的项目,很多jar会存在两份,浪费空间。优点在于ivy支持更智能的依赖解析方式,比如版本号支持区间的形式,[2.4.0,)代表ivy会选择一个在你设定的约束范围内最新的模块下载,保持自动更新。
需要注意的是除了缓存的目录不同,如果我们要使用公司内部的nexus服务器来下载依赖模块,需要的配制也与maven不同,maven使用的是.m2/settings.xml来管理全局配制,设置中央仓库,自定义的仓库以及验证的用户名密码等。sbt的配制都在.sbt目录下,除了自身需要的boot launchers目录,需要添加或者修改两个文件:
1. Repositories配置
repositories 全局的resolvers仓库地址,默认的只有maven2的central repository,这里我们需要加上一些自己的配制,才能够使用我们自己的nexus仓库,当然也可以在自己的项目具体的build.sbt里边增加,不过鉴于这个是全局配置放在这里比较方便:
[repositories] local oschina:http://maven.oschina.net/content/groups/public/ oschina-ivy:http://maven.oschina.net/content/groups/public/, [organization]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)[revision]/[type]s/[artifact](-[classifier]).[ext] sbt-releases-repo: http://repo.typesafe.com/typesafe/ivy-releases/, [organization]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)[revision]/[type]s/[artifact](-[classifier]).[ext] sbt-plugins-repo: http://repo.scala-sbt.org/scalasbt/sbt-plugin-releases/, [organization]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)[revision]/[type]s/[artifact](-[classifier]).[ext] maven-central: http://repo1.maven.org/maven2/ maven-releases: http://teamwork.kmtongji.com/nexus/content/groups/public
在上边的例子中,我们包含了7个仓库,在下载依赖的时候会按照上边的顺序,首先检查local的目录下有没有,如果没有优先选择oschina->sbt->maven官方的地址去下载,oschina是国内的一个镜像,同步速度和带宽都不错,一般情况可以替代官方的仓库,而我们内部的nexus放到了最后,当然这个顺序根据实际情况可以自己调节,因为我们本地的nexus也缓存了大量的模块,可以把他放到靠前的位置。
需要配置-Dsbt.override.build.repos=true,加入到sbtopts文件里边,用来强制覆盖默认的仓库,如果要使用自定义的repositories文件地址,还需要配置-Dsbt.repository.config=/path/repositories, 同时推荐加大sbt所使用的mem大小,也是在sbtopts文件中修改。
2. Http authentication for local repositories
一般情况我们本地的nexus仓库都是有网关密码的,不能随便访问,因此如果sbt在下载的时候需要指定credential,因为sbt本身是一种类似scala的语言,通常用程序来实现就是在build.sbt加上这么一行:
Credentials.add("Sonatype Nexus Repository Manager", "nexusHostIp", "nexususername", "nexuspassword")
更好的办法是把credential放到一个文件:
credentials += Credentials(Path.userHome / ".ivy2" / ".credentials")
但是这样需要在所有的工程里边加这么一句,很是麻烦,作为通用的配制,我们可以让他在更基础的文件里边调用,因此最终的方法如下,先把credential放到一个文件,这里我们选择的是~/.sbt/.credentials, 内容如下:
realm=Sonatype Nexus Repository Manager host=teamwork.kmtongji.com user=xxxxx password=xxxxx
接下来我们在sbt配置目录下创建一个公共调用的文件~/.sbt/0.13/plugins/credentials.sbt,内容如下:
credentials += Credentials(Path.userHome / ".sbt" / ".credentials")
将调用放到底层加载过程中,因此具体的credentials文件放到哪里不那么重要,重点是调用这行代码,可以隐含的加载默认的credentials
上边只这展示了一个的例子,通过realm来匹配验证的用户名密码,只对http basic authentication有效,如果需要多个realm,应该也可以通过toml的配制方式增加[xxxx]的section区分,并没有测试过,只是猜测。
另外,需要注意的是,如果sbt在运行的时候所在的工程目录是一个本地没有的sbt版本,需要进行下载,这时候如果我们使用自己的私服比如JFrog artifactory来加速下载,credential会出现找不到的问题,因为sbt在升级自身的时候比较特殊,是通过SBT_CREDENTIALS这个环境变量来识别credentials未知的,并不会读我们在credentials.sbt里边配置的路径,因此这个环境变量是必须的。
build.sbt
sbt生成的代码目录结构与maven类似,只是会多一个project目录,最外层是整个项目的构建的build.sbt文件,再project目录下会有plugin.sbt用来控制plugin的加载。对于单个工程的项目构建只需要在build.sbt里边直接写相关的settings,包括名字,依赖关系等,不需要外层的变量,不过更多时候我们需要多项目工程构建,这就需要有一个根项目以及里边的子模块,模块之间存在一定的依赖关系,这就需要每个工程对应一个变量,一般我们会用lazy val来生命,只有在用到的时候才会加载这部分,整个文件就是一个简单的脚本程序,不再多说。
整个结构一般情况下包含三部分,
- common settings, 这个配制会被其他的工程所使用,可以在后续覆盖其中一部分配制,
- root项目,用来表明这是一个多工程的项目,列举出他所包含的工程,在根目录执行sbt compile等命令的时候会按顺序将子模块也进行相关的处理,一般也在这部分启动或者禁用某些插件
- 最后就是各个项目的定义或者说自定义的task了
plugin.sbt
这个文件比较简单,一行行的包含了所添加的插件,插件的启用禁用可以在build文件里边控制,举例说明:
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.0.3")
常用命令
sbt批处理的命令与maven有很多相似,不过sbt有两种模式,一种交互界面,输入sbt进入之后,可以在新的shell输入各种命令,一种是批处理命令例如sbt clean compile 与maven类似,sbt还有一种可以实时编译的命令 ~compile在文件改动后会自动编译,且是增量编译,比较方便。
常用的命令包括clean compile test run package console reload help,需要特别注意的是run命令,默认情况执行run命令,这个task所运行的jvm与当前sbt自身运行的jvm是同一个,如果需要给run task设置单独的javaOptions并独立出一个进程来运行,则需要特殊的声明,在build.sbt中举例,比如一个工程的settings:
.settings( name := "aco-queen", javaOptions += "-Dconfig.resource=./queen.conf", // Do not work, you have to run with 'sbt -Dconfig.resource=./queen.conf queen/run' fork in(Test, run) := true, // To enable java options , fork run process to a new jvm separated with sbt )
注意其中的javaOptions要生效,前提是有下边的fork语句,在run和test的时候fork新的进程来执行。
当然之前的javaOptions并没有生效,其实如果是指定一些property直接在sbt命令里边加上就好,会传递给具体的jvm虚拟机里边,类似于直接使用java -Dxxxx=xxxx