SlideShare uma empresa Scribd logo
1 de 41
Baixar para ler offline
sbt(すぶた)職人のススメ
かとじゅん@j5ik2o
誰?
• 加藤潤一(かとうじゅんいち)
• j5ik2o = junichikato = j unich i k at o = j5ik2o
• 年齢 0x2B
• ChatWork社 テックリード
• スキル
• DDD x Scala 伝道師
• ケトジェニック・ダイエット・アドバイザー
• 他にもスキル習得中。8月公開予定
今日のテーマは…
酢豚じゃなくsbtの話です
アジェンダ
• 基礎
• 実践
• セッティング
• タスク
• プラグイン
基礎
インストール
$ brew install sbt

==> Downloading https://homebrew.bintray.com/bottles/
sbt-0.13.8.yosemite.bottle.tar.gz
Already downloaded: /Library/Caches/Homebrew/
sbt-0.13.8.yosemite.bottle.tar.gz
==> Pouring sbt-0.13.8.yosemite.bottle.tar.gz
==> Caveats
You can use $SBT_OPTS to pass additional JVM options to SBT:
SBT_OPTS="-XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256M"
This formula is now using the standard typesafe sbt launcher script.
Project specific options should be placed in .sbtopts in the root of your
project.
Global settings should be placed in /usr/local/etc/sbtopts
==> Summary
🍺 /usr/local/Cellar/sbt/0.13.8: 5 files, 1.2M
プロジェクトの最小構成
$ brew install typesafe-activator
==> Downloading https://downloads.typesafe.com/typesafe-activator/1.3.2/typesafe-
activator-1.3.2.zip
Already downloaded: /Library/Caches/Homebrew/typesafe-activator-1.3.2.zip
🍺 /usr/local/Cellar/typesafe-activator/1.3.2: 4413 files, 470M, built in 9 seconds
$ activator new sbt-simple
Fetching the latest list of templates...
Browse the list of templates: http://typesafe.com/activator/templates
Choose from these featured templates or enter a template name:
1) minimal-akka-java-seed
2) minimal-akka-scala-seed
3) minimal-java
4) minimal-scala
5) play-java
6) play-scala
(hit tab to see a list of all templates)
> 4

OK, application "sbt-simple" is being created using the "minimal-scala" template.
To run "sbt-simple" from the command line, "cd sbt-simple" then:
/Users/cw-junichi/temp/sbt-simple/activator run
To run the test for "sbt-simple" from the command line, "cd sbt-simple" then:
/Users/cw-junichi/temp/sbt-simple/activator test
To run the Activator UI for "sbt-simple" from the command line, "cd sbt-simple" then:
/Users/cw-junichi/temp/sbt-simple/activator ui
生成されたファイル群
.
"## LICENSE
"## activator
"## activator-launch-1.3.2.jar
"## build.sbt
"## project
$   &## build.properties
&## src
"## main
$   &## scala
$   &## com
$   &## example
$   &## Hello.scala
&## test
&## scala
&## HelloSpec.scala
build.sbt
name := """sbt-simple"""
version := "1.0"
scalaVersion := "2.11.7"
// Change this to another test framework if you prefer
libraryDependencies += "org.scalatest" %% "scalatest" % "2.2.4" % "test"
// Uncomment to use Akka
//libraryDependencies += "com.typesafe.akka" %% "akka-actor" % "2.3.11"
project/build.properties
Activator-generated Properties
#Thu Jul 30 14:55:12 JST 2015
template.uuid=e17acfbb-1ff5-41f5-b8cf-2c40be6a8340
sbt.version=0.13.8 # sbtのバージョンを固定できる
build.sbt vs project/Build.scala
• sbt 0.12の時代は、マルチプロジェクトのために
Build.scalaを利用していた。
• sbt 0.13からは、build.sbtだけでマルチプロジェク
トに対応できるようになった。加えてval, def も定
義できるようになった。
• Build.scalaは積極的に使わなくなった?
sbt compile
$ sbt
[info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/project
[info] Updating {file:/Users/cw-junichi/temp/sbt-simple/project/}sbt-simple-build...
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[info] Done updating.
[info] Set current project to sbt-simple (in build file:/Users/cw-junichi/temp/sbt-
simple/)

> compile
[info] Updating {file:/Users/cw-junichi/temp/sbt-simple/}sbt-simple...
[info] Resolving jline#jline;2.12.1 ...
[info] Done updating.
[info] Compiling 1 Scala source to /Users/cw-junichi/temp/sbt-simple/target/
scala-2.11/classes...
[success] Total time: 3 s, completed 2015/07/30 15:37:49
$ sbt compile
[info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/project
[info] Set current project to sbt-simple (in build file:/Users/cw-junichi/temp/
sbt-simple/)
[info] Updating {file:/Users/cw-junichi/temp/sbt-simple/}sbt-simple...
[info] Resolving jline#jline;2.12.1 ...
[info] Done updating.
[info] Compiling 1 Scala source to /Users/cw-junichi/temp/sbt-simple/target/
scala-2.11/classes...
[success] Total time: 3 s, completed 2015/07/30 15:38:19
sbt run
package com.example
object Hello {
def main(args: Array[String]): Unit = {
println("Hello, world!")
}
}
$ sbt run
[info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/
project
[info] Set current project to sbt-simple (in build file:/Users/cw-junichi/
temp/sbt-simple/)
[info] Running com.example.Hello
Hello, world!
[success] Total time: 0 s, completed 2015/07/30 15:40:02
sbt test
import org.scalatest._
class HelloSpec extends FlatSpec with Matchers {
"Hello" should "have tests" in {
true should === (true)
}
}
$ sbt test
[info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/project
[info] Set current project to sbt-simple (in build file:/Users/cw-junichi/temp/sbt-simple/)
[info] Compiling 1 Scala source to /Users/cw-junichi/temp/sbt-simple/target/scala-2.11/
test-classes...
[info] HelloSpec:
[info] Hello
[info] - should have tests
[info] Run completed in 294 milliseconds.
[info] Total number of tests run: 1
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
[success] Total time: 4 s, completed 2015/07/30 15:42:53
IDEAでそのまま読み込めます
マルチプロジェクト
lazy val commonSettings = Seq(
organization := "com.example",
version := "0.1.0",
scalaVersion := "2.11.4"
)
lazy val core = (project in file("core")).
settings(commonSettings: _*).
settings(
// other settings
)
lazy val util = (project in file("util")).
settings(commonSettings: _*).
settings(
// other settings
)
lazy val root = (project in file(".")).
aggregate(util, core)
プラグイン
addSbtPlugin("com.typesafe.sbt" % "sbt-scalariform" % "1.3.0")
Add following to project/plugins.sbt
scalariformSettings
Add following to build.sbt
$ sbt scalariformFormat
$ sbt compile
[info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/project
[info] Set current project to sbt-simple (in build file:/Users/cw-junichi/temp/sbt-simple/)
[info] Updating {file:/Users/cw-junichi/temp/sbt-simple/}sbt-simple...
[info] Formatting 1 Scala source {file:/Users/cw-junichi/temp/sbt-simple/}sbt-simple(compile) ...
[info] Resolving org.scala-lang#scala-library;2.11.7 ...
[info] Reformatted 1 Scala source {file:/Users/cw-junichi/temp/sbt-simple/}sbt-simple(compile).
[info] Resolving jline#jline;2.12.1 ...
[info] Done updating.
[success] Total time: 1 s, completed 2015/07/30 16:24:30
Execute plugin’s function.
実践
コマンド
def hello = Command.command("hello") { state =>
println("Hello")
state
}
commands ++= Seq(hello)
コマンドの定義
$ sbt hello

[info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/
project
[info] Set current project to sbt-simple (in build file:/Users/cw-junichi/
temp/sbt-simple/)
Hello
コマンド名で呼び出す
sbtで使えるキー
• キーには3種類ある
• SettingKey[T]
• 一度だけ値が計算されるキー(値はプロジェクトの読み込
み時に計算され、保存される)
• TaskKey[T]
• 毎回再計算されるタスクを呼び出す、副作用を伴う可能性
のある値のキー。
• InputKey[T]
• コマンドラインの引数を入力として受け取るタスクのキー。
• 組み込みキー
• import sbt.Keys._
セッティング
lazy val message = settingKey[String]("message")

message := “hello”
セッティングキーを定義して、セッティングに対して値を割り当てる
$ sbt message

[info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/
project
[info] Set current project to sbt-simple (in build file:/Users/cw-junichi/
temp/sbt-simple/)
[info] hello
セッティングキー名で呼び出す
タスク
lazy val hello = taskKey[Unit]("An example task")

hello := { println(“Hello!") }
タスクキーを定義して、タスクに対して関数を割り当てる
$ sbt hello

[info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/
project
[info] Set current project to sbt-simple (in build file:/Users/cw-junichi/
temp/sbt-simple/)
Hello!
[success] Total time: 0 s, completed 2015/07/31 10:51:11
タスクキー名で呼び出す
タスクからセッティングを参照する
lazy val message = settingKey[String]("message")
lazy val say = taskKey[Unit]("say task")
message := "hello"
say := { println(message.value) }
セッティングキー名.valueで割当られている値を参照する
$ sbt say
[info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/
project
[info] Set current project to sbt-simple (in build file:/Users/cw-junichi/
temp/sbt-simple/)
hello
[success] Total time: 0 s, completed 2015/07/31 12:04:46
タスクの結果を得る
lazy val message = settingKey[String]("message")
lazy val modifier = taskKey[String]("modifier task")
lazy val display = taskKey[Unit]("display task")
message := "hello"
modifier := { "{{{" + message.value + "}}}" }
display := { println(modifier.value) }
タスクキー.valueでタスクの結果を得ることができる
$ sbt display
[info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/
project
[info] Set current project to sbt-simple (in build file:/Users/cw-junichi/
temp/sbt-simple/)
{{{hello}}}
[success] Total time: 0 s, completed 2015/08/01 7:43:23
タスクの実行意味論
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.")
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'T WORK
sum
}
sampleStringTask := {
startServer.value
val s = sampleIntTask
.value.toString
println("s: " + s)
s
}
$ sbt sampleStringTask
[info] Loading project definition from /
Users/cw-junichi/temp/sbt-simple/project
[info] Set current project to sbt-simple (in
build file:/Users/cw-junichi/temp/sbt-
simple/)
stopping...
starting...
sum: 3
s: 3
[success] Total time: 1 s, completed
2015/07/31 12:40:28
sampleIntTask := {
ServerUtil.startServer
try {
val sum = 1 + 2
println("sum: " + sum)
sum
} finally {
ServerUtil.stopServer
}
}
スコープ
• マルチプロジェクトで、各プロジェクトにおいて
同じキーが別の値を取ることができる
• メインとテストのソースで異なるようにコンパイ
ルしたければ、compileキーは別の値と取ること
ができる
• つまり、キーとスコープによって値が決定され
る
• スコープには、プロジェクト、コンフィグレーショ
ン、タスクがある。
タスクのスコープ
lazy val say = taskKey[Unit](“say task”)



lazy val message = settingKey[String]("message")
lazy val modifier = taskKey[String]("modifier task")
lazy val display = taskKey[Unit]("display task")
message in say := "hello"
modifier in say := { "{{{" + (message in say).value + "}}}" }
display in say := { println((modifier in say).value) }
$ sbt say::display
[info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/
project
[info] Set current project to sbt-simple (in build file:/Users/cw-junichi/
temp/sbt-simple/)
{{{hello}}}
[success] Total time: 0 s, completed 2015/08/01 7:45:33
sbt plugin
sbtPlugin := true



name := """sbt-simple-plugin"""
version := "1.0"
scalaVersion := “2.10.5"
libraryDependencies += "org.scalatest" %% "scalatest" % "2.2.4" % "test"
sbtPlugin := trueとするだけ、他は通常のsbtプロジェクトと同じ
chatwork/sbt-docker
chatwork/sbt-docker
$ sbt docker::build
[info] Loading project definition from /Users/cw-junichi/sbt-docker/src/sbt-test/sbt-docker/simple/project
[info] Set current project to simple (in build file:/Users/cw-junichi/sbt-docker/src/sbt-test/sbt-docker/simple/)
[info] generated docker file from template file. dockerTemplate = /Users/cw-junichi/sbt-docker/src/sbt-test/sbt-docker/simple/
docker/Dockerfile.ftl, templateContext = Map(name -> simple, version -> 0.1-SNAPSHOT), dockerfile = /Users/cw-junichi/sbt-
docker/src/sbt-test/sbt-docker/simple/docker/Dockerfile
[info] Set(/Users/cw-junichi/sbt-docker/src/sbt-test/sbt-docker/simple/target/docker/Dockerfile, /Users/cw-junichi/sbt-docker/
src/sbt-test/sbt-docker/simple/target/docker/bin/echo.sh)
[info] userName = , emailAddress =
[info] Step 0 : FROM busybox
[info] ---> 8c2e06607696
[info] Step 1 : ADD bin/echo.sh /
[info] ---> f7bffdfc573c
[info] Removing intermediate container f6a8e236bf34
[info] Step 2 : CMD sh /echo.sh simple-0.1-SNAPSHOT
[info] ---> Running in d761354df21a
[info] ---> 7ae24d96c42c
[info] Removing intermediate container d761354df21a
[info] Successfully built 7ae24d96c42c
[info] docker build, imageId = 7ae24d96c42c
[success] Total time: 3 s, completed 2015/07/31 13:58:46
docker build
docker buildの前にアプリケーションをbuildできる。
ディレクトリ構成
"## build.sbt
"## project
$   "## build.properties
$   "## plugins.sbt
$   "## scripted.sbt
"## release.sbt
"## scripted.sbt
"## src
$   "## main
$   $   "## resources
$   $   $   &## logback.xml
$   $   &## scala
$   $   &## com
$   $   &## chatwork
$   $   &## sbt
$   $   &## docker
$   $   "## BuildOptions.scala
$   $   "## DockerfileBuilder.scala
$   $   "## SbtDocker.scala
$   $   "## SbtDockerKeys.scala
$   $   &## SbtDockerPlugin.scala
$   &## sbt-test
$   &## sbt-docker
$   &## simple
$   "## build.sbt
$   "## docker
$   $   "## Dockerfile.ftl
$   $   &## bin
$   $   &## echo.sh
$   &## project
$      &## plugins.sbt
&## version.sbt
build.sbt
import scalariform.formatter.preferences._
scalaVersion := "2.10.5"
sonatypeProfileName := "com.chatwork"
organization := "com.chatwork"
publishMavenStyle := true
publishArtifact in Test := false
pomIncludeRepository := {
_ => false
}
pomExtra := {
<url>https://github.com/chatwork/sbt-docker</url>
<licenses>
<license>
<name>The MIT License</name>
<url>http://opensource.org/licenses/MIT</url>
</license>
</licenses>
<scm>
<url>git@github.com:chatwork/sbt-docker.git</url>
<connection>scm:git:github.com/chatwork/sbt-docker</
connection>
<developerConnection>scm:git:git@github.com:chatwork/
sbt-docker.git</developerConnection>
</scm>
<developers>
<developer>
<id>cw-junichikato</id>
<name>Junichi Kato</name>
</developer>
</developers>
}
name := "sbt-docker"
sbtPlugin := true



resolvers ++= Seq(
"Sonatype OSS Snapshot Repository" at "https://
oss.sonatype.org/content/repositories/snapshots/",
"Sonatype OSS Release Repository" at "https://
oss.sonatype.org/content/repositories/releases/",
"Typesafe Releases" at "http://repo.typesafe.com/
typesafe/releases/"
)



libraryDependencies ++= Seq(
"com.spotify" % "docker-client" % "2.7.7",
"ch.qos.logback" % "logback-classic" % "1.1.3",
"org.slf4j" % "slf4j-api" % "1.7.12",
"org.freemarker" % "freemarker" % "2.3.14"
)
scalariformSettings
ScalariformKeys.preferences :=
ScalariformKeys.preferences.value
.setPreference(AlignParameters, true)
.setPreference(AlignSingleLineCaseStatements, true)
.setPreference(DoubleIndentClassDeclaration, true)
.setPreference(PreserveDanglingCloseParenthesis, true)
.setPreference(MultilineScaladocCommentsStartOnFirstLin
e, false)
credentials <<= Def.task {
val ivyCredentials = (baseDirectory in
LocalRootProject).value / ".credentials"
val result = Credentials(ivyCredentials) :: Nil
result
}
project/plugins.sbt
logLevel := Level.Warn
addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "0.5.0")
addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0")
addSbtPlugin("com.typesafe.sbt" % "sbt-scalariform" % "1.3.0")
addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.0")
プラグイン本体
package
com.chatwork.sbt.docker
import sbt.Keys._
import sbt._
import sbt.plugins.IvyPlugin
object SbtDockerPlugin
extends AutoPlugin {
override def trigger =
allRequirements
override def requires:
Plugins = IvyPlugin
object autoImport extends
SbtDockerKeys
import SbtDocker._
import SbtDockerKeys._
override def projectSettings: Seq[Def.Setting[_]] = Seq(
name in docker := (name in thisProjectRef).value,
sourceDirectory in docker := baseDirectory.value / "docker",
buildDirectory in docker :=
baseDirectory.value / "target" / "docker",
sourceFiles in docker := Seq(),
login in docker := false,
emailAddress in docker := "",
userName in docker := "",
password in docker := "",
buildOptions in docker := Set.empty[BuildOptions.Value],
build in docker <<=
dockerBuildTask dependsOn (copySourceFiles in docker),
copySourceFiles in docker <<= copySourceFilesTask,
dockerfileTemplate in docker :=
(sourceDirectory in docker).value / "Dockerfile.ftl",
dockerfile in docker :=
(sourceDirectory in docker).value / "Dockerfile",
templateContext in docker := Map(
"name" -> (name in thisProjectRef).value,
"version" -> (version in thisProjectRef).value
),
generateDockerfile in docker <<= generateDockerfileTask,
push in docker <<= dockerPushTask,
pull in docker <<= dockerPullTask,
list in docker <<= dockerListImagesTask,
start in docker <<= dockerStartTask dependsOn (copySourceFiles in docker),
startAndWait in docker <<=
dockerStartAndWaitTask dependsOn (copySourceFiles in docker)
)
}
Key関係
val build = taskKey[Option[String]]("build")
val buildOptions = settingKey[Set[BuildOptions.Value]]
("build-options")
val buildDirectory = settingKey[File]("build-
directory")
// ---
val dockerfileTemplate = settingKey[File]("dockerfile-
template")
val dockerfile = settingKey[File]("dockerfile")
val templateContext = settingKey[Map[String, String]]
("template-context")
val generateDockerfile = taskKey[File]("generate-
dockerfile")
// ---
val push = taskKey[Unit]("push")
val pull = taskKey[Unit]("pull")
val list = taskKey[Unit]("list")
val start = taskKey[Option[Future[String]]]("start")
val startAndWait = taskKey[Unit]("start-and-wait")
}
package com.chatwork.sbt.docker
import sbt._
import scala.concurrent.Future
object SbtDockerKeys extends SbtDockerKeys
trait SbtDockerKeys {
val docker = taskKey[Unit]("docker")
val login = settingKey[Boolean]("login")
val emailAddress = settingKey[String]("email-
address")
val userName = settingKey[String]("user-name")
val password = settingKey[String]("password")
// ---
val sourceFiles = taskKey[Seq[(File, String)]]
("source-files")
val copySourceFiles = taskKey[Set[File]]
("copy-source-files")
// ---
タスクの定義
trait SbtDocker {
def dockerBuildTask: Def.Initialize[Task[Option[String]]] = Def.task {
val logger = streams.value.log
val sut = dockerClient.value
val workDir = (buildDirectory in docker).value.toPath
val repositoryName = (name in docker).value
val bo = (buildOptions in docker).value.map(toBuildParameter)
Try {
val result = sut.build(workDir, repositoryName, progressHandler(logger)
{ pm => Some(pm.stream()) }, bo.toArray: _*)
logger.info(s"docker build, imageId = $result")
Some(result)
}.recover {
case ex: DockerException =>
logger.error(ex.toString)
None
}.get
}
}
AutoPlugin
• これまでは
• project/plugins.sbtにプラグインを追加
• build.sbtにプラグイン固有のセッティングを追加
• AutoPluginでは、タスク、セッティングなどのビルド定義を自動的に追加できる
• 明示的に利用するプラグインを指定できる。
• (project in file(“.”)).enablePlugins(a, b).disablePlugins(c)
• requires
• 依存しているプラグイン(AutoPlugin)を指定できる
• trigger
• プラグインが動作する条件。allRequirementsは、すべての依存プラグインが
使えるようになってから動作できるようにする。
• autoImport
• importの自動化。autoImportメンバー内に存在するものはimport宣言なしで
利用できるようになる
お知らせ
ありがとうございました

Mais conteúdo relacionado

Mais procurados

Java, Ruby & Rails
Java, Ruby & RailsJava, Ruby & Rails
Java, Ruby & RailsPeter Lind
 
Our Puppet Story (GUUG FFG 2015)
Our Puppet Story (GUUG FFG 2015)Our Puppet Story (GUUG FFG 2015)
Our Puppet Story (GUUG FFG 2015)DECK36
 
Java Unit Testing with Unitils
Java Unit Testing with UnitilsJava Unit Testing with Unitils
Java Unit Testing with UnitilsMikalai Alimenkou
 
We Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End DevelopmentWe Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End DevelopmentAll Things Open
 
Scala Frustrations
Scala FrustrationsScala Frustrations
Scala Frustrationstakezoe
 
“Purikura” culture in Japan and our web application architecture
“Purikura” culturein Japan andour web application architecture“Purikura” culturein Japan andour web application architecture
“Purikura” culture in Japan and our web application architectureKoichi Sakata
 
Ruby - a tester's best friend
Ruby - a tester's best friendRuby - a tester's best friend
Ruby - a tester's best friendPeter Lind
 
Original slides from Ryan Dahl's NodeJs intro talk
Original slides from Ryan Dahl's NodeJs intro talkOriginal slides from Ryan Dahl's NodeJs intro talk
Original slides from Ryan Dahl's NodeJs intro talkAarti Parikh
 
Play Framework 2.5
Play Framework 2.5Play Framework 2.5
Play Framework 2.5m-kurz
 
Dmp hadoop getting_start
Dmp hadoop getting_startDmp hadoop getting_start
Dmp hadoop getting_startGim GyungJin
 
JRubyによるエンタープライズweb開発
JRubyによるエンタープライズweb開発JRubyによるエンタープライズweb開発
JRubyによるエンタープライズweb開発Naoto Takai
 
A Taste of Clojure
A Taste of ClojureA Taste of Clojure
A Taste of ClojureDavid Leung
 
Node.js Explained
Node.js ExplainedNode.js Explained
Node.js ExplainedJeff Kunkle
 
Gradle in a Polyglot World
Gradle in a Polyglot WorldGradle in a Polyglot World
Gradle in a Polyglot WorldSchalk Cronjé
 
Single Page Applications in Drupal
Single Page Applications in DrupalSingle Page Applications in Drupal
Single Page Applications in DrupalChris Tankersley
 
Pse2010 rel storage
Pse2010 rel storagePse2010 rel storage
Pse2010 rel storageLars Noldan
 

Mais procurados (20)

Java, Ruby & Rails
Java, Ruby & RailsJava, Ruby & Rails
Java, Ruby & Rails
 
NodeJS for Beginner
NodeJS for BeginnerNodeJS for Beginner
NodeJS for Beginner
 
Our Puppet Story (GUUG FFG 2015)
Our Puppet Story (GUUG FFG 2015)Our Puppet Story (GUUG FFG 2015)
Our Puppet Story (GUUG FFG 2015)
 
Java Unit Testing with Unitils
Java Unit Testing with UnitilsJava Unit Testing with Unitils
Java Unit Testing with Unitils
 
We Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End DevelopmentWe Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End Development
 
Scala Frustrations
Scala FrustrationsScala Frustrations
Scala Frustrations
 
Zen of Akka
Zen of AkkaZen of Akka
Zen of Akka
 
“Purikura” culture in Japan and our web application architecture
“Purikura” culturein Japan andour web application architecture“Purikura” culturein Japan andour web application architecture
“Purikura” culture in Japan and our web application architecture
 
Ruby - a tester's best friend
Ruby - a tester's best friendRuby - a tester's best friend
Ruby - a tester's best friend
 
Nodejs vatsal shah
Nodejs vatsal shahNodejs vatsal shah
Nodejs vatsal shah
 
Original slides from Ryan Dahl's NodeJs intro talk
Original slides from Ryan Dahl's NodeJs intro talkOriginal slides from Ryan Dahl's NodeJs intro talk
Original slides from Ryan Dahl's NodeJs intro talk
 
Play Framework 2.5
Play Framework 2.5Play Framework 2.5
Play Framework 2.5
 
Nashorn
NashornNashorn
Nashorn
 
Dmp hadoop getting_start
Dmp hadoop getting_startDmp hadoop getting_start
Dmp hadoop getting_start
 
JRubyによるエンタープライズweb開発
JRubyによるエンタープライズweb開発JRubyによるエンタープライズweb開発
JRubyによるエンタープライズweb開発
 
A Taste of Clojure
A Taste of ClojureA Taste of Clojure
A Taste of Clojure
 
Node.js Explained
Node.js ExplainedNode.js Explained
Node.js Explained
 
Gradle in a Polyglot World
Gradle in a Polyglot WorldGradle in a Polyglot World
Gradle in a Polyglot World
 
Single Page Applications in Drupal
Single Page Applications in DrupalSingle Page Applications in Drupal
Single Page Applications in Drupal
 
Pse2010 rel storage
Pse2010 rel storagePse2010 rel storage
Pse2010 rel storage
 

Destaque

コードで学ぶドメイン駆動設計入門
コードで学ぶドメイン駆動設計入門コードで学ぶドメイン駆動設計入門
コードで学ぶドメイン駆動設計入門潤一 加藤
 
第一回Scala会議
第一回Scala会議第一回Scala会議
第一回Scala会議潤一 加藤
 
Servlet と Future の関わり方 #scala_ks
Servlet と Future の関わり方 #scala_ksServlet と Future の関わり方 #scala_ks
Servlet と Future の関わり方 #scala_ksKazuhiro Sera
 
第1回 チキチキ『( ゜ェ゜)・;'.、ゴフッ』 - シングルトンパターン(Java)
第1回 チキチキ『( ゜ェ゜)・;'.、ゴフッ』 - シングルトンパターン(Java)第1回 チキチキ『( ゜ェ゜)・;'.、ゴフッ』 - シングルトンパターン(Java)
第1回 チキチキ『( ゜ェ゜)・;'.、ゴフッ』 - シングルトンパターン(Java)潤一 加藤
 
3週連続DDDその1 ドメイン駆動設計の基本を理解する
3週連続DDDその1  ドメイン駆動設計の基本を理解する3週連続DDDその1  ドメイン駆動設計の基本を理解する
3週連続DDDその1 ドメイン駆動設計の基本を理解する増田 亨
 
Scalaでのプログラム開発
Scalaでのプログラム開発Scalaでのプログラム開発
Scalaでのプログラム開発Kota Mizushima
 
RICOH THETAの全天球画像でペーパークラフト
RICOH THETAの全天球画像でペーパークラフトRICOH THETAの全天球画像でペーパークラフト
RICOH THETAの全天球画像でペーパークラフトTakehiko YOSHIDA
 
某S社のddd(メイリオ)
某S社のddd(メイリオ)某S社のddd(メイリオ)
某S社のddd(メイリオ)kumake
 
Scala × DDD × 弊社実践例
Scala × DDD × 弊社実践例Scala × DDD × 弊社実践例
Scala × DDD × 弊社実践例侑亮 原田
 
Java エンジニアチームが始めやすい Scala コーディングスタイル #ichigayageek
Java エンジニアチームが始めやすい Scala コーディングスタイル #ichigayageekJava エンジニアチームが始めやすい Scala コーディングスタイル #ichigayageek
Java エンジニアチームが始めやすい Scala コーディングスタイル #ichigayageekKazuhiro Sera
 
[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24
[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24
[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24Kazuhiro Sera
 
めんどくさくない Scala #kwkni_scala
めんどくさくない Scala #kwkni_scalaめんどくさくない Scala #kwkni_scala
めんどくさくない Scala #kwkni_scalaKazuhiro Sera
 
Seasar2で作った俺たちのサービスの今
Seasar2で作った俺たちのサービスの今Seasar2で作った俺たちのサービスの今
Seasar2で作った俺たちのサービスの今Koichi Sakata
 
GANMA!でDDDをやってみてから1年くらい経った
GANMA!でDDDをやってみてから1年くらい経ったGANMA!でDDDをやってみてから1年くらい経った
GANMA!でDDDをやってみてから1年くらい経ったYasuyuki Sugitani
 
Introduction to GraphQL in Scala (ScalaMatsuri 2017)
Introduction to GraphQL in Scala (ScalaMatsuri 2017)Introduction to GraphQL in Scala (ScalaMatsuri 2017)
Introduction to GraphQL in Scala (ScalaMatsuri 2017)Yuki Katada
 
JPEGのDCTブロックで コンテンツ指向のトリミング
JPEGのDCTブロックで コンテンツ指向のトリミングJPEGのDCTブロックで コンテンツ指向のトリミング
JPEGのDCTブロックで コンテンツ指向のトリミングYohsuke Furuta
 
はじめての CircleCI
はじめての CircleCIはじめての CircleCI
はじめての CircleCIYosuke Mizutani
 
ディープラーニングでおそ松さんの6つ子は見分けられるのか? FIT2016
ディープラーニングでおそ松さんの6つ子は見分けられるのか? FIT2016ディープラーニングでおそ松さんの6つ子は見分けられるのか? FIT2016
ディープラーニングでおそ松さんの6つ子は見分けられるのか? FIT2016Yota Ishida
 

Destaque (20)

Scala with DDD
Scala with DDDScala with DDD
Scala with DDD
 
コードで学ぶドメイン駆動設計入門
コードで学ぶドメイン駆動設計入門コードで学ぶドメイン駆動設計入門
コードで学ぶドメイン駆動設計入門
 
Actor&stm
Actor&stmActor&stm
Actor&stm
 
第一回Scala会議
第一回Scala会議第一回Scala会議
第一回Scala会議
 
Servlet と Future の関わり方 #scala_ks
Servlet と Future の関わり方 #scala_ksServlet と Future の関わり方 #scala_ks
Servlet と Future の関わり方 #scala_ks
 
第1回 チキチキ『( ゜ェ゜)・;'.、ゴフッ』 - シングルトンパターン(Java)
第1回 チキチキ『( ゜ェ゜)・;'.、ゴフッ』 - シングルトンパターン(Java)第1回 チキチキ『( ゜ェ゜)・;'.、ゴフッ』 - シングルトンパターン(Java)
第1回 チキチキ『( ゜ェ゜)・;'.、ゴフッ』 - シングルトンパターン(Java)
 
3週連続DDDその1 ドメイン駆動設計の基本を理解する
3週連続DDDその1  ドメイン駆動設計の基本を理解する3週連続DDDその1  ドメイン駆動設計の基本を理解する
3週連続DDDその1 ドメイン駆動設計の基本を理解する
 
Scalaでのプログラム開発
Scalaでのプログラム開発Scalaでのプログラム開発
Scalaでのプログラム開発
 
RICOH THETAの全天球画像でペーパークラフト
RICOH THETAの全天球画像でペーパークラフトRICOH THETAの全天球画像でペーパークラフト
RICOH THETAの全天球画像でペーパークラフト
 
某S社のddd(メイリオ)
某S社のddd(メイリオ)某S社のddd(メイリオ)
某S社のddd(メイリオ)
 
Scala × DDD × 弊社実践例
Scala × DDD × 弊社実践例Scala × DDD × 弊社実践例
Scala × DDD × 弊社実践例
 
Java エンジニアチームが始めやすい Scala コーディングスタイル #ichigayageek
Java エンジニアチームが始めやすい Scala コーディングスタイル #ichigayageekJava エンジニアチームが始めやすい Scala コーディングスタイル #ichigayageek
Java エンジニアチームが始めやすい Scala コーディングスタイル #ichigayageek
 
[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24
[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24
[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24
 
めんどくさくない Scala #kwkni_scala
めんどくさくない Scala #kwkni_scalaめんどくさくない Scala #kwkni_scala
めんどくさくない Scala #kwkni_scala
 
Seasar2で作った俺たちのサービスの今
Seasar2で作った俺たちのサービスの今Seasar2で作った俺たちのサービスの今
Seasar2で作った俺たちのサービスの今
 
GANMA!でDDDをやってみてから1年くらい経った
GANMA!でDDDをやってみてから1年くらい経ったGANMA!でDDDをやってみてから1年くらい経った
GANMA!でDDDをやってみてから1年くらい経った
 
Introduction to GraphQL in Scala (ScalaMatsuri 2017)
Introduction to GraphQL in Scala (ScalaMatsuri 2017)Introduction to GraphQL in Scala (ScalaMatsuri 2017)
Introduction to GraphQL in Scala (ScalaMatsuri 2017)
 
JPEGのDCTブロックで コンテンツ指向のトリミング
JPEGのDCTブロックで コンテンツ指向のトリミングJPEGのDCTブロックで コンテンツ指向のトリミング
JPEGのDCTブロックで コンテンツ指向のトリミング
 
はじめての CircleCI
はじめての CircleCIはじめての CircleCI
はじめての CircleCI
 
ディープラーニングでおそ松さんの6つ子は見分けられるのか? FIT2016
ディープラーニングでおそ松さんの6つ子は見分けられるのか? FIT2016ディープラーニングでおそ松さんの6つ子は見分けられるのか? FIT2016
ディープラーニングでおそ松さんの6つ子は見分けられるのか? FIT2016
 

Semelhante a Sbt職人のススメ

An introduction to maven gradle and sbt
An introduction to maven gradle and sbtAn introduction to maven gradle and sbt
An introduction to maven gradle and sbtFabio Fumarola
 
Continuous Integration/Deployment with Docker and Jenkins
Continuous Integration/Deployment with Docker and JenkinsContinuous Integration/Deployment with Docker and Jenkins
Continuous Integration/Deployment with Docker and JenkinsFrancesco Bruni
 
Gradle - time for a new build
Gradle - time for a new buildGradle - time for a new build
Gradle - time for a new buildIgor Khotin
 
sbt 0.10 for beginners?
sbt 0.10 for beginners?sbt 0.10 for beginners?
sbt 0.10 for beginners?k4200
 
Acquia BLT for the Win, or How to speed up the project setup, development an...
Acquia BLT for the Win, or  How to speed up the project setup, development an...Acquia BLT for the Win, or  How to speed up the project setup, development an...
Acquia BLT for the Win, or How to speed up the project setup, development an...DrupalCamp Kyiv
 
sbt core concepts (ScalaMatsuri 2019)
sbt core concepts (ScalaMatsuri 2019)sbt core concepts (ScalaMatsuri 2019)
sbt core concepts (ScalaMatsuri 2019)Eugene Yokota
 
Developing Liferay Plugins with Maven
Developing Liferay Plugins with MavenDeveloping Liferay Plugins with Maven
Developing Liferay Plugins with MavenMika Koivisto
 
Gradle talk, Javarsovia 2010
Gradle talk, Javarsovia 2010Gradle talk, Javarsovia 2010
Gradle talk, Javarsovia 2010Tomek Kaczanowski
 
SBT by Aform Research, Saulius Valatka
SBT by Aform Research, Saulius ValatkaSBT by Aform Research, Saulius Valatka
SBT by Aform Research, Saulius ValatkaVasil Remeniuk
 
How to start using Scala
How to start using ScalaHow to start using Scala
How to start using ScalaNgoc Dao
 
Sbt, idea and eclipse
Sbt, idea and eclipseSbt, idea and eclipse
Sbt, idea and eclipseMike Slinn
 

Semelhante a Sbt職人のススメ (20)

SBT Concepts, part 2
SBT Concepts, part 2SBT Concepts, part 2
SBT Concepts, part 2
 
An introduction to maven gradle and sbt
An introduction to maven gradle and sbtAn introduction to maven gradle and sbt
An introduction to maven gradle and sbt
 
Pragmatic sbt
Pragmatic sbtPragmatic sbt
Pragmatic sbt
 
Apache DeltaSpike: The CDI Toolbox
Apache DeltaSpike: The CDI ToolboxApache DeltaSpike: The CDI Toolbox
Apache DeltaSpike: The CDI Toolbox
 
Apache DeltaSpike the CDI toolbox
Apache DeltaSpike the CDI toolboxApache DeltaSpike the CDI toolbox
Apache DeltaSpike the CDI toolbox
 
Gradle como alternativa a maven
Gradle como alternativa a mavenGradle como alternativa a maven
Gradle como alternativa a maven
 
Intro to sbt-web
Intro to sbt-webIntro to sbt-web
Intro to sbt-web
 
Continuous Integration/Deployment with Docker and Jenkins
Continuous Integration/Deployment with Docker and JenkinsContinuous Integration/Deployment with Docker and Jenkins
Continuous Integration/Deployment with Docker and Jenkins
 
Simple build tool
Simple build toolSimple build tool
Simple build tool
 
Gradle - time for a new build
Gradle - time for a new buildGradle - time for a new build
Gradle - time for a new build
 
Dev ops meetup
Dev ops meetupDev ops meetup
Dev ops meetup
 
sbt 0.10 for beginners?
sbt 0.10 for beginners?sbt 0.10 for beginners?
sbt 0.10 for beginners?
 
Acquia BLT for the Win, or How to speed up the project setup, development an...
Acquia BLT for the Win, or  How to speed up the project setup, development an...Acquia BLT for the Win, or  How to speed up the project setup, development an...
Acquia BLT for the Win, or How to speed up the project setup, development an...
 
SBT Crash Course
SBT Crash CourseSBT Crash Course
SBT Crash Course
 
sbt core concepts (ScalaMatsuri 2019)
sbt core concepts (ScalaMatsuri 2019)sbt core concepts (ScalaMatsuri 2019)
sbt core concepts (ScalaMatsuri 2019)
 
Developing Liferay Plugins with Maven
Developing Liferay Plugins with MavenDeveloping Liferay Plugins with Maven
Developing Liferay Plugins with Maven
 
Gradle talk, Javarsovia 2010
Gradle talk, Javarsovia 2010Gradle talk, Javarsovia 2010
Gradle talk, Javarsovia 2010
 
SBT by Aform Research, Saulius Valatka
SBT by Aform Research, Saulius ValatkaSBT by Aform Research, Saulius Valatka
SBT by Aform Research, Saulius Valatka
 
How to start using Scala
How to start using ScalaHow to start using Scala
How to start using Scala
 
Sbt, idea and eclipse
Sbt, idea and eclipseSbt, idea and eclipse
Sbt, idea and eclipse
 

Último

%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...masabamasaba
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...masabamasaba
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrandmasabamasaba
 
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...WSO2
 
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Bert Jan Schrijver
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyviewmasabamasaba
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...Health
 
tonesoftg
tonesoftgtonesoftg
tonesoftglanshi9
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...masabamasaba
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...masabamasaba
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastPapp Krisztián
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfonteinmasabamasaba
 
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...masabamasaba
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfonteinmasabamasaba
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2
 
%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in sowetomasabamasaba
 
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...WSO2
 
What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationJuha-Pekka Tolvanen
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension AidPhilip Schwarz
 
WSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaSWSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaSWSO2
 

Último (20)

%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
 
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
tonesoftg
tonesoftgtonesoftg
tonesoftg
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the past
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?
 
%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto
 
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
 
What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the Situation
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
WSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaSWSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaS
 

Sbt職人のススメ

  • 2. 誰? • 加藤潤一(かとうじゅんいち) • j5ik2o = junichikato = j unich i k at o = j5ik2o • 年齢 0x2B • ChatWork社 テックリード • スキル • DDD x Scala 伝道師 • ケトジェニック・ダイエット・アドバイザー • 他にもスキル習得中。8月公開予定
  • 5.
  • 6. アジェンダ • 基礎 • 実践 • セッティング • タスク • プラグイン
  • 8. インストール $ brew install sbt
 ==> Downloading https://homebrew.bintray.com/bottles/ sbt-0.13.8.yosemite.bottle.tar.gz Already downloaded: /Library/Caches/Homebrew/ sbt-0.13.8.yosemite.bottle.tar.gz ==> Pouring sbt-0.13.8.yosemite.bottle.tar.gz ==> Caveats You can use $SBT_OPTS to pass additional JVM options to SBT: SBT_OPTS="-XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256M" This formula is now using the standard typesafe sbt launcher script. Project specific options should be placed in .sbtopts in the root of your project. Global settings should be placed in /usr/local/etc/sbtopts ==> Summary 🍺 /usr/local/Cellar/sbt/0.13.8: 5 files, 1.2M
  • 9. プロジェクトの最小構成 $ brew install typesafe-activator ==> Downloading https://downloads.typesafe.com/typesafe-activator/1.3.2/typesafe- activator-1.3.2.zip Already downloaded: /Library/Caches/Homebrew/typesafe-activator-1.3.2.zip 🍺 /usr/local/Cellar/typesafe-activator/1.3.2: 4413 files, 470M, built in 9 seconds $ activator new sbt-simple Fetching the latest list of templates... Browse the list of templates: http://typesafe.com/activator/templates Choose from these featured templates or enter a template name: 1) minimal-akka-java-seed 2) minimal-akka-scala-seed 3) minimal-java 4) minimal-scala 5) play-java 6) play-scala (hit tab to see a list of all templates) > 4
 OK, application "sbt-simple" is being created using the "minimal-scala" template. To run "sbt-simple" from the command line, "cd sbt-simple" then: /Users/cw-junichi/temp/sbt-simple/activator run To run the test for "sbt-simple" from the command line, "cd sbt-simple" then: /Users/cw-junichi/temp/sbt-simple/activator test To run the Activator UI for "sbt-simple" from the command line, "cd sbt-simple" then: /Users/cw-junichi/temp/sbt-simple/activator ui
  • 10. 生成されたファイル群 . "## LICENSE "## activator "## activator-launch-1.3.2.jar "## build.sbt "## project $   &## build.properties &## src "## main $   &## scala $   &## com $   &## example $   &## Hello.scala &## test &## scala &## HelloSpec.scala
  • 11. build.sbt name := """sbt-simple""" version := "1.0" scalaVersion := "2.11.7" // Change this to another test framework if you prefer libraryDependencies += "org.scalatest" %% "scalatest" % "2.2.4" % "test" // Uncomment to use Akka //libraryDependencies += "com.typesafe.akka" %% "akka-actor" % "2.3.11" project/build.properties Activator-generated Properties #Thu Jul 30 14:55:12 JST 2015 template.uuid=e17acfbb-1ff5-41f5-b8cf-2c40be6a8340 sbt.version=0.13.8 # sbtのバージョンを固定できる
  • 12. build.sbt vs project/Build.scala • sbt 0.12の時代は、マルチプロジェクトのために Build.scalaを利用していた。 • sbt 0.13からは、build.sbtだけでマルチプロジェク トに対応できるようになった。加えてval, def も定 義できるようになった。 • Build.scalaは積極的に使わなくなった?
  • 13. sbt compile $ sbt [info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/project [info] Updating {file:/Users/cw-junichi/temp/sbt-simple/project/}sbt-simple-build... [info] Resolving org.fusesource.jansi#jansi;1.4 ... [info] Done updating. [info] Set current project to sbt-simple (in build file:/Users/cw-junichi/temp/sbt- simple/)
 > compile [info] Updating {file:/Users/cw-junichi/temp/sbt-simple/}sbt-simple... [info] Resolving jline#jline;2.12.1 ... [info] Done updating. [info] Compiling 1 Scala source to /Users/cw-junichi/temp/sbt-simple/target/ scala-2.11/classes... [success] Total time: 3 s, completed 2015/07/30 15:37:49 $ sbt compile [info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/project [info] Set current project to sbt-simple (in build file:/Users/cw-junichi/temp/ sbt-simple/) [info] Updating {file:/Users/cw-junichi/temp/sbt-simple/}sbt-simple... [info] Resolving jline#jline;2.12.1 ... [info] Done updating. [info] Compiling 1 Scala source to /Users/cw-junichi/temp/sbt-simple/target/ scala-2.11/classes... [success] Total time: 3 s, completed 2015/07/30 15:38:19
  • 14. sbt run package com.example object Hello { def main(args: Array[String]): Unit = { println("Hello, world!") } } $ sbt run [info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/ project [info] Set current project to sbt-simple (in build file:/Users/cw-junichi/ temp/sbt-simple/) [info] Running com.example.Hello Hello, world! [success] Total time: 0 s, completed 2015/07/30 15:40:02
  • 15. sbt test import org.scalatest._ class HelloSpec extends FlatSpec with Matchers { "Hello" should "have tests" in { true should === (true) } } $ sbt test [info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/project [info] Set current project to sbt-simple (in build file:/Users/cw-junichi/temp/sbt-simple/) [info] Compiling 1 Scala source to /Users/cw-junichi/temp/sbt-simple/target/scala-2.11/ test-classes... [info] HelloSpec: [info] Hello [info] - should have tests [info] Run completed in 294 milliseconds. [info] Total number of tests run: 1 [info] Suites: completed 1, aborted 0 [info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0 [info] All tests passed. [success] Total time: 4 s, completed 2015/07/30 15:42:53
  • 17. マルチプロジェクト lazy val commonSettings = Seq( organization := "com.example", version := "0.1.0", scalaVersion := "2.11.4" ) lazy val core = (project in file("core")). settings(commonSettings: _*). settings( // other settings ) lazy val util = (project in file("util")). settings(commonSettings: _*). settings( // other settings ) lazy val root = (project in file(".")). aggregate(util, core)
  • 18. プラグイン addSbtPlugin("com.typesafe.sbt" % "sbt-scalariform" % "1.3.0") Add following to project/plugins.sbt scalariformSettings Add following to build.sbt $ sbt scalariformFormat $ sbt compile [info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/project [info] Set current project to sbt-simple (in build file:/Users/cw-junichi/temp/sbt-simple/) [info] Updating {file:/Users/cw-junichi/temp/sbt-simple/}sbt-simple... [info] Formatting 1 Scala source {file:/Users/cw-junichi/temp/sbt-simple/}sbt-simple(compile) ... [info] Resolving org.scala-lang#scala-library;2.11.7 ... [info] Reformatted 1 Scala source {file:/Users/cw-junichi/temp/sbt-simple/}sbt-simple(compile). [info] Resolving jline#jline;2.12.1 ... [info] Done updating. [success] Total time: 1 s, completed 2015/07/30 16:24:30 Execute plugin’s function.
  • 20. コマンド def hello = Command.command("hello") { state => println("Hello") state } commands ++= Seq(hello) コマンドの定義 $ sbt hello
 [info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/ project [info] Set current project to sbt-simple (in build file:/Users/cw-junichi/ temp/sbt-simple/) Hello コマンド名で呼び出す
  • 21. sbtで使えるキー • キーには3種類ある • SettingKey[T] • 一度だけ値が計算されるキー(値はプロジェクトの読み込 み時に計算され、保存される) • TaskKey[T] • 毎回再計算されるタスクを呼び出す、副作用を伴う可能性 のある値のキー。 • InputKey[T] • コマンドラインの引数を入力として受け取るタスクのキー。 • 組み込みキー • import sbt.Keys._
  • 22. セッティング lazy val message = settingKey[String]("message")
 message := “hello” セッティングキーを定義して、セッティングに対して値を割り当てる $ sbt message
 [info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/ project [info] Set current project to sbt-simple (in build file:/Users/cw-junichi/ temp/sbt-simple/) [info] hello セッティングキー名で呼び出す
  • 23. タスク lazy val hello = taskKey[Unit]("An example task")
 hello := { println(“Hello!") } タスクキーを定義して、タスクに対して関数を割り当てる $ sbt hello
 [info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/ project [info] Set current project to sbt-simple (in build file:/Users/cw-junichi/ temp/sbt-simple/) Hello! [success] Total time: 0 s, completed 2015/07/31 10:51:11 タスクキー名で呼び出す
  • 24. タスクからセッティングを参照する lazy val message = settingKey[String]("message") lazy val say = taskKey[Unit]("say task") message := "hello" say := { println(message.value) } セッティングキー名.valueで割当られている値を参照する $ sbt say [info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/ project [info] Set current project to sbt-simple (in build file:/Users/cw-junichi/ temp/sbt-simple/) hello [success] Total time: 0 s, completed 2015/07/31 12:04:46
  • 25. タスクの結果を得る lazy val message = settingKey[String]("message") lazy val modifier = taskKey[String]("modifier task") lazy val display = taskKey[Unit]("display task") message := "hello" modifier := { "{{{" + message.value + "}}}" } display := { println(modifier.value) } タスクキー.valueでタスクの結果を得ることができる $ sbt display [info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/ project [info] Set current project to sbt-simple (in build file:/Users/cw-junichi/ temp/sbt-simple/) {{{hello}}} [success] Total time: 0 s, completed 2015/08/01 7:43:23
  • 26. タスクの実行意味論 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.") 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'T WORK sum } sampleStringTask := { startServer.value val s = sampleIntTask .value.toString println("s: " + s) s } $ sbt sampleStringTask [info] Loading project definition from / Users/cw-junichi/temp/sbt-simple/project [info] Set current project to sbt-simple (in build file:/Users/cw-junichi/temp/sbt- simple/) stopping... starting... sum: 3 s: 3 [success] Total time: 1 s, completed 2015/07/31 12:40:28 sampleIntTask := { ServerUtil.startServer try { val sum = 1 + 2 println("sum: " + sum) sum } finally { ServerUtil.stopServer } }
  • 28. タスクのスコープ lazy val say = taskKey[Unit](“say task”)
 
 lazy val message = settingKey[String]("message") lazy val modifier = taskKey[String]("modifier task") lazy val display = taskKey[Unit]("display task") message in say := "hello" modifier in say := { "{{{" + (message in say).value + "}}}" } display in say := { println((modifier in say).value) } $ sbt say::display [info] Loading project definition from /Users/cw-junichi/temp/sbt-simple/ project [info] Set current project to sbt-simple (in build file:/Users/cw-junichi/ temp/sbt-simple/) {{{hello}}} [success] Total time: 0 s, completed 2015/08/01 7:45:33
  • 29. sbt plugin sbtPlugin := true
 
 name := """sbt-simple-plugin""" version := "1.0" scalaVersion := “2.10.5" libraryDependencies += "org.scalatest" %% "scalatest" % "2.2.4" % "test" sbtPlugin := trueとするだけ、他は通常のsbtプロジェクトと同じ
  • 31. chatwork/sbt-docker $ sbt docker::build [info] Loading project definition from /Users/cw-junichi/sbt-docker/src/sbt-test/sbt-docker/simple/project [info] Set current project to simple (in build file:/Users/cw-junichi/sbt-docker/src/sbt-test/sbt-docker/simple/) [info] generated docker file from template file. dockerTemplate = /Users/cw-junichi/sbt-docker/src/sbt-test/sbt-docker/simple/ docker/Dockerfile.ftl, templateContext = Map(name -> simple, version -> 0.1-SNAPSHOT), dockerfile = /Users/cw-junichi/sbt- docker/src/sbt-test/sbt-docker/simple/docker/Dockerfile [info] Set(/Users/cw-junichi/sbt-docker/src/sbt-test/sbt-docker/simple/target/docker/Dockerfile, /Users/cw-junichi/sbt-docker/ src/sbt-test/sbt-docker/simple/target/docker/bin/echo.sh) [info] userName = , emailAddress = [info] Step 0 : FROM busybox [info] ---> 8c2e06607696 [info] Step 1 : ADD bin/echo.sh / [info] ---> f7bffdfc573c [info] Removing intermediate container f6a8e236bf34 [info] Step 2 : CMD sh /echo.sh simple-0.1-SNAPSHOT [info] ---> Running in d761354df21a [info] ---> 7ae24d96c42c [info] Removing intermediate container d761354df21a [info] Successfully built 7ae24d96c42c [info] docker build, imageId = 7ae24d96c42c [success] Total time: 3 s, completed 2015/07/31 13:58:46 docker build docker buildの前にアプリケーションをbuildできる。
  • 32. ディレクトリ構成 "## build.sbt "## project $   "## build.properties $   "## plugins.sbt $   "## scripted.sbt "## release.sbt "## scripted.sbt "## src $   "## main $   $   "## resources $   $   $   &## logback.xml $   $   &## scala $   $   &## com $   $   &## chatwork $   $   &## sbt $   $   &## docker $   $   "## BuildOptions.scala $   $   "## DockerfileBuilder.scala $   $   "## SbtDocker.scala $   $   "## SbtDockerKeys.scala $   $   &## SbtDockerPlugin.scala $   &## sbt-test $   &## sbt-docker $   &## simple $   "## build.sbt $   "## docker $   $   "## Dockerfile.ftl $   $   &## bin $   $   &## echo.sh $   &## project $      &## plugins.sbt &## version.sbt
  • 33. build.sbt import scalariform.formatter.preferences._ scalaVersion := "2.10.5" sonatypeProfileName := "com.chatwork" organization := "com.chatwork" publishMavenStyle := true publishArtifact in Test := false pomIncludeRepository := { _ => false } pomExtra := { <url>https://github.com/chatwork/sbt-docker</url> <licenses> <license> <name>The MIT License</name> <url>http://opensource.org/licenses/MIT</url> </license> </licenses> <scm> <url>git@github.com:chatwork/sbt-docker.git</url> <connection>scm:git:github.com/chatwork/sbt-docker</ connection> <developerConnection>scm:git:git@github.com:chatwork/ sbt-docker.git</developerConnection> </scm> <developers> <developer> <id>cw-junichikato</id> <name>Junichi Kato</name> </developer> </developers> } name := "sbt-docker" sbtPlugin := true
 
 resolvers ++= Seq( "Sonatype OSS Snapshot Repository" at "https:// oss.sonatype.org/content/repositories/snapshots/", "Sonatype OSS Release Repository" at "https:// oss.sonatype.org/content/repositories/releases/", "Typesafe Releases" at "http://repo.typesafe.com/ typesafe/releases/" )
 
 libraryDependencies ++= Seq( "com.spotify" % "docker-client" % "2.7.7", "ch.qos.logback" % "logback-classic" % "1.1.3", "org.slf4j" % "slf4j-api" % "1.7.12", "org.freemarker" % "freemarker" % "2.3.14" ) scalariformSettings ScalariformKeys.preferences := ScalariformKeys.preferences.value .setPreference(AlignParameters, true) .setPreference(AlignSingleLineCaseStatements, true) .setPreference(DoubleIndentClassDeclaration, true) .setPreference(PreserveDanglingCloseParenthesis, true) .setPreference(MultilineScaladocCommentsStartOnFirstLin e, false) credentials <<= Def.task { val ivyCredentials = (baseDirectory in LocalRootProject).value / ".credentials" val result = Credentials(ivyCredentials) :: Nil result }
  • 34. project/plugins.sbt logLevel := Level.Warn addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "0.5.0") addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0") addSbtPlugin("com.typesafe.sbt" % "sbt-scalariform" % "1.3.0") addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.0")
  • 35. プラグイン本体 package com.chatwork.sbt.docker import sbt.Keys._ import sbt._ import sbt.plugins.IvyPlugin object SbtDockerPlugin extends AutoPlugin { override def trigger = allRequirements override def requires: Plugins = IvyPlugin object autoImport extends SbtDockerKeys import SbtDocker._ import SbtDockerKeys._ override def projectSettings: Seq[Def.Setting[_]] = Seq( name in docker := (name in thisProjectRef).value, sourceDirectory in docker := baseDirectory.value / "docker", buildDirectory in docker := baseDirectory.value / "target" / "docker", sourceFiles in docker := Seq(), login in docker := false, emailAddress in docker := "", userName in docker := "", password in docker := "", buildOptions in docker := Set.empty[BuildOptions.Value], build in docker <<= dockerBuildTask dependsOn (copySourceFiles in docker), copySourceFiles in docker <<= copySourceFilesTask, dockerfileTemplate in docker := (sourceDirectory in docker).value / "Dockerfile.ftl", dockerfile in docker := (sourceDirectory in docker).value / "Dockerfile", templateContext in docker := Map( "name" -> (name in thisProjectRef).value, "version" -> (version in thisProjectRef).value ), generateDockerfile in docker <<= generateDockerfileTask, push in docker <<= dockerPushTask, pull in docker <<= dockerPullTask, list in docker <<= dockerListImagesTask, start in docker <<= dockerStartTask dependsOn (copySourceFiles in docker), startAndWait in docker <<= dockerStartAndWaitTask dependsOn (copySourceFiles in docker) ) }
  • 36. Key関係 val build = taskKey[Option[String]]("build") val buildOptions = settingKey[Set[BuildOptions.Value]] ("build-options") val buildDirectory = settingKey[File]("build- directory") // --- val dockerfileTemplate = settingKey[File]("dockerfile- template") val dockerfile = settingKey[File]("dockerfile") val templateContext = settingKey[Map[String, String]] ("template-context") val generateDockerfile = taskKey[File]("generate- dockerfile") // --- val push = taskKey[Unit]("push") val pull = taskKey[Unit]("pull") val list = taskKey[Unit]("list") val start = taskKey[Option[Future[String]]]("start") val startAndWait = taskKey[Unit]("start-and-wait") } package com.chatwork.sbt.docker import sbt._ import scala.concurrent.Future object SbtDockerKeys extends SbtDockerKeys trait SbtDockerKeys { val docker = taskKey[Unit]("docker") val login = settingKey[Boolean]("login") val emailAddress = settingKey[String]("email- address") val userName = settingKey[String]("user-name") val password = settingKey[String]("password") // --- val sourceFiles = taskKey[Seq[(File, String)]] ("source-files") val copySourceFiles = taskKey[Set[File]] ("copy-source-files") // ---
  • 37. タスクの定義 trait SbtDocker { def dockerBuildTask: Def.Initialize[Task[Option[String]]] = Def.task { val logger = streams.value.log val sut = dockerClient.value val workDir = (buildDirectory in docker).value.toPath val repositoryName = (name in docker).value val bo = (buildOptions in docker).value.map(toBuildParameter) Try { val result = sut.build(workDir, repositoryName, progressHandler(logger) { pm => Some(pm.stream()) }, bo.toArray: _*) logger.info(s"docker build, imageId = $result") Some(result) }.recover { case ex: DockerException => logger.error(ex.toString) None }.get } }
  • 38. AutoPlugin • これまでは • project/plugins.sbtにプラグインを追加 • build.sbtにプラグイン固有のセッティングを追加 • AutoPluginでは、タスク、セッティングなどのビルド定義を自動的に追加できる • 明示的に利用するプラグインを指定できる。 • (project in file(“.”)).enablePlugins(a, b).disablePlugins(c) • requires • 依存しているプラグイン(AutoPlugin)を指定できる • trigger • プラグインが動作する条件。allRequirementsは、すべての依存プラグインが 使えるようになってから動作できるようにする。 • autoImport • importの自動化。autoImportメンバー内に存在するものはimport宣言なしで 利用できるようになる
  • 40.