SlideShare une entreprise Scribd logo
1  sur  41
Télécharger pour lire hors ligne
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宣言なしで
利用できるようになる
お知らせ
ありがとうございました

Contenu connexe

Tendances

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
 

Tendances (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
 

En vedette

コードで学ぶドメイン駆動設計入門
コードで学ぶドメイン駆動設計入門コードで学ぶドメイン駆動設計入門
コードで学ぶドメイン駆動設計入門潤一 加藤
 
第一回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
 

En vedette (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
 

Similaire à 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
 

Similaire à 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
 

Dernier

Best Web Development Agency- Idiosys USA.pdf
Best Web Development Agency- Idiosys USA.pdfBest Web Development Agency- Idiosys USA.pdf
Best Web Development Agency- Idiosys USA.pdfIdiosysTechnologies1
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfAlina Yurenko
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmSujith Sukumaran
 
Cyber security and its impact on E commerce
Cyber security and its impact on E commerceCyber security and its impact on E commerce
Cyber security and its impact on E commercemanigoyal112
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Matt Ray
 
A healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfA healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfMarharyta Nedzelska
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024StefanoLambiase
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityNeo4j
 
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanyChristoph Pohl
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based projectAnoyGreter
 
Odoo 14 - eLearning Module In Odoo 14 Enterprise
Odoo 14 - eLearning Module In Odoo 14 EnterpriseOdoo 14 - eLearning Module In Odoo 14 Enterprise
Odoo 14 - eLearning Module In Odoo 14 Enterprisepreethippts
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作qr0udbr0
 
PREDICTING RIVER WATER QUALITY ppt presentation
PREDICTING  RIVER  WATER QUALITY  ppt presentationPREDICTING  RIVER  WATER QUALITY  ppt presentation
PREDICTING RIVER WATER QUALITY ppt presentationvaddepallysandeep122
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesPhilip Schwarz
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Velvetech LLC
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...OnePlan Solutions
 
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Cizo Technology Services
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfFerryKemperman
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureDinusha Kumarasiri
 

Dernier (20)

2.pdf Ejercicios de programación competitiva
2.pdf Ejercicios de programación competitiva2.pdf Ejercicios de programación competitiva
2.pdf Ejercicios de programación competitiva
 
Best Web Development Agency- Idiosys USA.pdf
Best Web Development Agency- Idiosys USA.pdfBest Web Development Agency- Idiosys USA.pdf
Best Web Development Agency- Idiosys USA.pdf
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalm
 
Cyber security and its impact on E commerce
Cyber security and its impact on E commerceCyber security and its impact on E commerce
Cyber security and its impact on E commerce
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
 
A healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfA healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdf
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered Sustainability
 
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based project
 
Odoo 14 - eLearning Module In Odoo 14 Enterprise
Odoo 14 - eLearning Module In Odoo 14 EnterpriseOdoo 14 - eLearning Module In Odoo 14 Enterprise
Odoo 14 - eLearning Module In Odoo 14 Enterprise
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作
 
PREDICTING RIVER WATER QUALITY ppt presentation
PREDICTING  RIVER  WATER QUALITY  ppt presentationPREDICTING  RIVER  WATER QUALITY  ppt presentation
PREDICTING RIVER WATER QUALITY ppt presentation
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a series
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
 
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdf
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with Azure
 

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.