file:scala/dummy-guide-to-sbt.org
source link: https://blog.oyanglul.us/scala/dummy-guide-to-sbt.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Then follow the Stereo type
So the common here they are both very simple to use, without understanding how it works even what it means, just follow the same pattern you could get the build working.
Same way if any user come from those build tool, they may assume the Scala build tool should share the same trait as well - a build tool should have low learning effort, just copy paste should be enough get it work.
With that kind of expectation, sbt will let you down. Since it has very good and detail documents, but no one is going to spends days to read the hundreds page of documents just to get a project compile and ship. Most people just what things like npm or makefile that you can just simply copy paste and everything just works.
sbt is actually both a build tool, can be use like make
and rake
, at the same time also a simple to use manage dependencies, just like
npm
or bundler
.
So let us start with package management.
Package management
in bundler dependencies can be defined as:
gem 'httparty', '0.17.3'
Let us define `finagle` as sbt project dependencies, you can find how to add it from the right hand side of: https://index.scala-lang.org/twitter/finagle/finagle-core/20.5.0?target=_2.13
libraryDependencies += "com.twitter" %% "finagle-core" % "20.5.0"
where
com.twitter
is group idfinagle-core
is package name20.5.0
is the version of course
Comparing to bundler, there a lot other thing you may need to pay attention to.
What is %%
and %
, what is +=
?
It is totally fine to not knowing those symbols, the build still works, but they are noises and if you put the wrong thing it won't compile.
%%
Here is a quick guide how to use %
// Java library
libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.2.3"
// Scala library %%
libraryDependencies += "com.twitter" %% "finagle-core" % "20.5.0"
// Scala lib % with hard coded Scala version
libraryDependencies += "com.twitter" % "finagle-core_2.13" % "20.5.0"
// Test only library
libraryDependencies += "org.scalameta" %% "munit-scalacheck" % "0.7.7" % Test
That is all you need to know to get a basic dependencies working.
Version handling
don't care the patch version, pick the bigest patch
libraryDependencies += "com.twitter" %% "finagle-core" % "20.5.+"
don't care the minor version, pick the bigest patch
libraryDependencies += "com.twitter" %% "finagle-core" % "20.+"
rang of version
libraryDependencies += "com.twitter" %% "finagle-core" % "[19.4.0, 20.5.0)"
Package management actually isn't the most painful setting in sbt, since all library will give you the config of how to install already in README already.
Simply copy paste generally works.
In Rakefile, we can have very simply task flow, i.e.
- start database
- run test
- stop database
task :db_up do
sh "docker-compose up -d db"
end
task test: [:db_up] do
task(:spec).invoke
end
task :db_down do
`docker-compose stop db`
end
desc 'run db up test and db down'
task default: [:spec] do
task(:db_down).invoke
end
Let us define the same tasks in sbt https://www.scala-sbt.org/1.x/docs/Tasks.html :
// for the `!` syntax to exec external command
import scala.sys.process._
val dbUp = taskKey[Unit]("start database")
val dbDown = taskKey[Unit]("stop database")
val runTest = taskKey[Unit]("run test")
val default = taskKey[Unit]("default task")
dbUp := {
"docker-compose up -d db" !
}
dbDown := {
"docker-compose stop db" !
}
runTest := { dbUp.value;
Command.process("test", state.value)
}
default := Def.sequential(
runTest,
dbDown
).value
It is bit more verbose than Rake because of the Type things, but generally it is as simply as rake when defining external process https://www.scala-sbt.org/1.x/docs/Process.html and task dependency.
There are lot of ways you can define default
in sbt, as a new command:
commands += Command.command("defaultCommand") { state =>
"runTest" :: "dbDown" ::
state
}
or as command alias:
addCommandAlias("defaultCommand", "runTest;dbDown")
Another example is you can operate on files as well from sbt.
For instance there is built-in task in sbt called makePom
, but it will generate
pom.xml
to target
folder, we preferred to generate the file into .github/pom.xml
so Github can pick it up and analyst what jar file is in CVE list.
val genPom = taskKey[Unit]("generate pom for github to do security monitoring")
genPom := {
val pomFile = makePom.value
io.IO.copyFile(pomFile, file(".") / ".github" / "pom.xml")
}
Very simply and declarative task, right.
makePom: TaskKey[File]
is a task that return the pom file,makePom.value
will call the task and generate the file, and return the file aspomFile
io.IO.copyFile
will copy the file to expected path
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK