Successfully reported this slideshow.
Your SlideShare is downloading. ×

sbt core concepts (ScalaMatsuri 2019)

sbt core concepts (ScalaMatsuri 2019)

Download to read offline

sbt is an interactive build tool created for Scala. In this talk I will go over the core concepts of sbt such as tasks vs commands, and scoping.

sbt is an interactive build tool created for Scala. In this talk I will go over the core concepts of sbt such as tasks vs commands, and scoping.

More Related Content

Related Books

Free with a 30 day trial from Scribd

See all

Related Audiobooks

Free with a 30 day trial from Scribd

See all

sbt core concepts (ScalaMatsuri 2019)

  1. 1. sbt core concepts Eugene Yokota (@eed3si9n)
 Lightbend
  2. 2. goal: gain better intuition about sbt sbt に対する直感を育む
  3. 3. sbt by example
  4. 4. 
 build tool • "automates repeatable tasks"
 — Build Systems à la Carte
 Mokhov, Mitchell, Jones 「リピータブルなタスクの自動化」
  5. 5. a casually functional
 build tool カジュアルに関数型なビルドツール
  6. 6. State
  7. 7. State 1. build structure 2. your disk sbt での状態は、ビルド構造とあなたのディスク
  8. 8. Command • State State
  9. 9. Command • State State • processed sequentially • low-level construct; avoid making custom commands 逐次処理される 低レベルなものなので、カスタムコマンドは避ける
  10. 10. examples of command commands help, tasks projects, project hello set name := "foo" <command1>; <command2> ++ 2.13.0, ++ 2.13.0!, +<command> shell command act command
  11. 11. act command • lifts tasks and settings into a command act コマンドはタスクやセッティングを持ち上げる
  12. 12. which state is it changing? commands changes help, tasks no changes projects, project hello build structure set name := "foo" build structure <command1>; <command2> both ++ 2.13.0, ++ 2.13.0!, +<command> both act command disk 変更している状態はどっち?
  13. 13. why State + Command? 何のために State + Command があるの?
  14. 14. why State + Command? • predictable checkpoint • building block for interactiveness:
 "automates repeatable tasks" 予測可能なチェックポイント インタラクティブ性のための構成要素
  15. 15. interactive sbt> testOnly foo.bar command logs sbt shell effects
  16. 16. about time
  17. 17. distributed events event a event b "happens before" process p 分散イベント 同プロセス内では、イベントの順序は自明
  18. 18. distributed events event a event b "happens before" process p process q メッセージの送信はメッセージの受信よりも先にある
  19. 19. distributed events • a → b (a happens before b) • a ↛ b (a does not happen before b) • 2 distinct events a and b are said to be concurrent if a ↛ b and b ↛ a a ↛ b かつ b ↛ a であるとき、2つのイベントは並行
  20. 20. distributed events • a → b (a happens before b) • a ↛ b (a does not happen before b) • 2 distinct events a and b are said to be concurrent if a ↛ b and b ↛ a 2 events are concurrent if neither can causality affect each other 2つのイベントがお互いに因果的に影響を持たない場合、並行
  21. 21. Applicative functor scala> (3.some, 2.some) mapN { _ + _ } res8: Option[Int] = Some(5) scala> (none[Int], 5.some) mapN { _ - _ } res9: Option[Int] = None See 'Oh, All the things you'll traverse' by Luka Jacobowitz
  22. 22. for comprehension getLine flatMap { x => print(length(x)) flatMap { _ => getLine flatMap { y => IO(x ++ y) } } } for { x <- getLine _ <- print(length(x)) y <- getLine } yield x ++ y def procedural: Unit = { val x = getLine print(length(x)) val y = getLine x ++ y } for 内包表記

  23. 23. build.sbt DSL // sbt 0.12 style foo <<= (compile in Compile, bar) map { (c, b) => doSomething(b) } // sbt 1.x style foo := { val c = (Compile / compile).value val b = bar.value doSomething(b) }
  24. 24. build.sbt DSL // sbt 0.12 style foo <<= (compile in Compile, bar) map { (c, b) => doSomething(b) } // sbt 1.x style foo := { val c = (Compile / compile).value val b = bar.value doSomething(b) } Applicative composition
  25. 25. build.sbt DSL foo := { val c = (Compile / compile).value val b = bar.value doSomething(b) } Compile / compile bar foo "happens before"
  26. 26. build.sbt DSL foo := { val c = (Compile / compile).value val b = bar.value doSomething(b) } Compile / compile bar foo "happens before" line of sand in time-space
  27. 27. Applicative composition foo := { val c = (Compile / compile).value val b = bar.value doSomething(b) } Test / test := { val c = (Compile / compile).value val f = foo.value } Compile / compile bar foo "happens before" Test / test "happens before"
  28. 28. why Applicative composition? Compile / compile bar foo "happens before" Test / test "happens before" 何故 Applicative 合成をするのか?
  29. 29. why Applicative composition? Compile / compile bar foo "happens before" Test / test "happens before" 1. minimality (executes task at most once, for input that changed) evaluated only once ミニマル性 (タスクは入力が変化したとき、最多で1回のみ) Compile / compile は一回のみ実行される
  30. 30. why Applicative composition? Compile / compile bar foo "happens before" Test / test "happens before" 1. minimality 2. automatic parallel processing 自動並列処理

  31. 31. act command • given a task, creates a plan that evaluates the task in current and aggregated subprojects • concurrent tasks are evaluated in parallel lazy val root = (project in file(".")) .aggregate(util, core) .settings(...) lazy val util = (project in file("util")) .dependsOn(core) lazy val core = (project in file("core")) act コマンドは、与えられたタスクを現在サブプロジェクトと
 集約されたサブプロジェクトで実行するプランを作成する
  32. 32. act command • how does it relate with State? s0 s1 s2 reload (settings) act (task) act (task) 状態との関連は?

  33. 33. tasks vs commands • prefer tasks for plugin extension • tasks compose automatically • command composition is stateful / sequential プラグイン拡張性にはタスクがオススメ
 タスクは自動合成するが、コマンド合成は stateful
  34. 34. ~ command
  35. 35. build structure ビルド構造

  36. 36. build structure: build build {uri} subproject {uri}foo configuration foo/Compile key-value store (settings + tasks) Scala version subproject {uri}bar configuration bar/Compile Scala version
  37. 37. build structure: subproject build {uri} subproject {uri}foo configuration foo/Compile foo/Runtime foo/Test key-value store (settings + tasks) Scala version
  38. 38. build structure: configuration • has its own sources + library dependencies • Test extends Runtime. Runtime extends Compile. subproject {uri}foo configuration foo/Compile foo/Runtime foo/Test Scala version コンフィギュレーションは独自のソースとライブラリ依存性を 持つ
  39. 39. build structure: k-v store build {uri} subproject {uri}foo configuration foo/Compile key-value store (settings + tasks) Scala version subproject {uri}bar configuration bar/Compile Scala version
  40. 40. key-value store key value name helloworld version 0.1.0 organization com.example
  41. 41. key-value store key value foo/name helloworld ThisBuild/version 0.1.0 ThisBuild/organization com.example foo/Compile/compile <task> foo/Compile/console/scalacOptions List()
  42. 42. key scoping 1. subproject (Zero, ThisBuild, foo, etc.) 2. configuration (Zero, Compile, Test, etc.) 3. in-task (Zero, console, etc.) foo/Compile/console/scalacOptions キーのスコープ付け

  43. 43. key-value store key value name foo/name foo/Zero/Zero/name helloworld foo/Compile/console/scalacOptions List() • keys are automatically scoped to the current subproject • other scope axes default to Zero • Global = Zero/Zero/Zero キーは自動的にカレント・サブプロジェクトにスコープされる 他のスコープ軸のデフォルトは Zero
  44. 44. why key-value store? • inspect command • provides flexible extensibility on most aspects of the build • plugins can created based on other plugins sbt:sbtRoot> inspect tree test [info] Test / test = Task[Unit] [info] +-Test / executeTests = Task[sbt.Tests$Output] [info] | +-classLoaderLayeringStrategy = ScalaLibrary [info] | +-Test / loadedTestFrameworks = Task[scala.collection.immutable.Map[sbt.TestFramework, .. [info] | | +-Test / loadedTestFrameworks / streams = Task[sbt.std.TaskStreams[sbt.internal.util... [info] | | | +-Global / streamsManager = Task[sbt.std.Streams[sbt.internal.util.Init$.. [info] | | | 構造を inspect することができる ビルドを形成する多くの部分を柔軟に拡張できる
  45. 45. setting expresion name := { "hello" } key operator (setting/task) body • operators :=, +=, ++= • a setting expression represents a transformation of k-v store セッティング式
  46. 46. setting expresion ThisBuild / organization := "com.example" name := (ThisBuild / organization).value + "12" • use .value to lookup the setting/task value • key-value store forms a DAG (directed acyclic graph) .value を使ってセッティングやタスクの値を参照する key-value ストアは DAG を形成する
  47. 47. delegation rules x := (core / Test / console / scalacOption).value 1. look for the specified key, then try in-task ⇢ Zero 2. next try Test ⇢ Runtime ⇢ Compile ⇢ Zero 3. next try core ⇢ ThisBuild ⇢ Zero 4. precedence: subproject > configuration > in-task 5. transitive evaluation doesn't carry original context (no dynamic dispatch) 5つの移譲ルールがあり、指定されたキーが無い場合に 次に見る場所を規定する
  48. 48. delegation rules ThisBuild / version := name.value lazy val b = project .settings( name := "b" something := version.value ) • transitive evaluation doesn't carry original context (no dynamic dispatch) 間接的評価は元のコンテキストを伴わない OO の this.draw 的な振る舞いでは無い
  49. 49. tip for plugin authors • define custom keys at the widest scope (Global), and reference the keys using the narrowest scope Global / obfuscateLogic := Logic.Default Compile / obfuscate := { val logic = (Compile / obfuscateLogic).value doObfuscate(logic) } • This allows build users various levels to rewire the setting (Global, ThisBuild, proj, proj/Compile) カスタムキーは最も広いスコープ付けで定義し、 最も狭いスコープ付けで参照すると最大の柔軟性を得られる
  50. 50. key-value store foo/Compile/scalacOptions foo/name ThisBuild/version Test Runtime Compile foo/Compile/compile foo ThisBuild Zero key configuration subproject foo/Runtime/compile foo/Test/compile in-task foo/Compile/console/scalacOptions foo/baseDirectory
  51. 51. sbt 1.3.0
  52. 52. sbt 1.3.0 RC-2 • Coursier for library management • super shell and tracing • turbo mode (enabled layered ClassLoader) • details https://www.lightbend.com/blog/sbt-1.3.0- release Coursier がライブラリ管理のデフォルト
 super shell は現行タスクを表示させる
  53. 53. Thank You
  54. 54. delta vee (2019.06 mixtape)

×