স্থাপন
brew install sbt
প্রযুক্তিগতভাবে বলতে গেলে যেগুলি সমন্বিত এসবিটি বা অনুরূপ ইনস্টলগুলি রয়েছে
আপনি যখন sbt
টার্মিনাল থেকে চালাবেন এটি আসলে এসবিটি লঞ্চার বাশ স্ক্রিপ্টটি চালায়। ব্যক্তিগতভাবে, আমাকে কখনই এই ত্রিত্ব সম্পর্কে চিন্তা করতে হবে না, এবং কেবল এসবিটি ব্যবহার করুন যেন এটি কোনও জিনিস।
কনফিগারেশন
প্রকল্পের মূলটিতে একটি নির্দিষ্ট প্রকল্প সেভ .sbtopts
ফাইলের জন্য এসবিটি কনফিগার করতে । এসবিটি সিস্টেম-ব্যাপী সংশোধন কনফিগার করতে /usr/local/etc/sbtopts
। কার্যকর করার সময় sbt -help
আপনাকে সঠিক অবস্থানটি বলা উচিত। উদাহরণস্বরূপ, ওয়ান-অফ এক্সিকিউটিভ হিসাবে এসবিটি আরও মেমরি দেওয়া বা মেমরি বৃদ্ধি বা স্থায়ীভাবে কার্যকর হওয়ার জন্য sbt -mem 4096
সংরক্ষণ -mem 4096
করা ।.sbtopts
sbtopts
প্রকল্প কাঠামো
sbt new scala/scala-seed.g8
একটি সর্বনিম্ন হ্যালো ওয়ার্ল্ড এসবিটি প্রকল্প কাঠামো তৈরি করে
.
├── README.md
├── build.sbt
├── project
├── src
└── target
ঘন ঘন কমান্ড
test
testOnly
testOnly -- -z "The Hello object should say hello"
run
runMain example.Hello
clean
package
assembly
publishLocal
release
reload
শাঁস এর অগণিত
scala
sbt
sbt console
sbt consoleProject
বিল্ড সংজ্ঞা একটি যথাযথ স্কালাল প্রকল্প
এটি মূল কী ইডিয়োম্যাটিক এসবিটি ধারণাগুলির মধ্যে একটি। আমি একটি প্রশ্ন দিয়ে ব্যাখ্যা করার চেষ্টা করব। বলুন আপনি এমন একটি এসবিটি টাস্ক সংজ্ঞায়িত করতে চান যা স্কেলাজ-HTTP দিয়ে একটি HTTP অনুরোধ কার্যকর করবে। স্বজ্ঞাতভাবে আমরা নিম্নলিখিত ভিতরে চেষ্টা করতে পারেনbuild.sbt
libraryDependencies += "org.scalaj" %% "scalaj-http" % "2.4.2"
val fooTask = taskKey[Unit]("Fetch meaning of life")
fooTask := {
import scalaj.http._
val response = Http("http://example.com").asString
...
}
তবে এটি অনুপস্থিত বলতে ত্রুটি করবে import scalaj.http._
। এ কিভাবে সম্ভব যখন আমরা, ডান সর্বোপরি, যোগ scalaj-http
করতে libraryDependencies
? তদ্ব্যতীত, আমরা যখন নির্ভরতা যুক্ত করি তখন এটি কেন কাজ করে project/build.sbt
?
libraryDependencies += "org.scalaj" %% "scalaj-http" % "2.4.2"
উত্তরটি হ'ল এটি আপনার মূল প্রকল্প থেকে পৃথক পৃথক স্কালা প্রকল্পেরfooTask
একটি অংশ । এই আলাদা স্কালা প্রকল্পটি ডিরেক্টরিতে পাওয়া যাবে যার নিজস্ব ডিরেক্টরি রয়েছে যেখানে এর সংকলিত ক্লাসগুলি থাকে। আসলে, এর অধীনে এমন একটি শ্রেণি থাকা উচিত যা এরকম কোনও কিছুর জন্য ক্ষয় হয়project/
target/
project/target/config-classes
object $9c2192aea3f1db3c251d extends scala.AnyRef {
lazy val fooTask : sbt.TaskKey[scala.Unit] = { }
lazy val root : sbt.Project = { }
}
আমরা দেখতে পাচ্ছি যে fooTask
কেবলমাত্র একটি নিয়মিত স্কালাল আইটেমটির সদস্য $9c2192aea3f1db3c251d
। স্পষ্টতই scalaj-http
প্রকল্পটি সংজ্ঞায়নের নির্ভরতা হওয়া উচিত $9c2192aea3f1db3c251d
এবং সঠিক প্রকল্পের নির্ভরতা নয়। সুতরাং এটির project/build.sbt
পরিবর্তে এটি ঘোষণা করা দরকার build.sbt
, কারণ project
এখানেই বিল্ড ডেফিনিশন স্কালা প্রকল্প থাকে।
বিন্দুটি নির্ধারণের জন্য যে বিল্ড সংজ্ঞাটি কেবল একটি অন্য স্কাল প্রকল্প, সম্পাদন করুন sbt consoleProject
। এটি শ্রেণিপথের বিল্ড সংজ্ঞা প্রকল্পের সাথে স্কালা আরএপিএল লোড করবে। আপনি লাইন লাইন বরাবর একটি আমদানি দেখতে হবে
import $9c2192aea3f1db3c251d
সুতরাং এখন আমরা build.sbt
ডিএসএল এর পরিবর্তে স্কেল দিয়ে যথাযথ কল করে বিল্ড সংজ্ঞা প্রকল্পের সাথে সরাসরি যোগাযোগ করতে পারি । উদাহরণস্বরূপ, নিম্নলিখিতগুলি কার্যকর করেfooTask
$9c2192aea3f1db3c251d.fooTask.eval
build.sbt
আন্ডার রুট প্রকল্প হ'ল একটি স্পিশাল ডিএসএল যা স্কেল প্রকল্পের অধীনে বিল্ড ডেফিনেশন সংজ্ঞায়িত করতে সহায়তা করে project/
।
এবং বিল্ড ডেফিনিশন স্কালাল প্রকল্প, এর নিজস্ব বিল্ড সংজ্ঞা স্কালা প্রকল্পের অধীনে থাকতে পারে project/project/
এবং আরও অনেক কিছু। আমরা বলি এসবিটি পুনরাবৃত্ত হয় ।
sbt ডিফল্ট সমান্তরাল হয়
sbt কাজগুলি বাইরে DAG তৈরি করে । এটি এটিকে কাজের মধ্যে নির্ভরতা বিশ্লেষণ করতে এবং সমান্তরালভাবে এটিকে কার্যকর করতে এবং এমনকি নকল সম্পাদন করতে সহায়তা করে। build.sbt
ডিএসএল এটিকে মাথায় রেখে তৈরি করা হয়েছে, যা প্রাথমিকভাবে বিস্ময়কর শব্দার্থক হতে পারে। নিম্নলিখিত স্নিপেটে মৃত্যুদণ্ড কার্যকর করার আদেশটি কী বলে আপনি মনে করেন?
def a = Def.task { println("a") }
def b = Def.task { println("b") }
lazy val c = taskKey[Unit]("sbt is parallel by-default")
c := {
println("hello")
a.value
b.value
}
স্বজ্ঞাতভাবে কেউ মনে করতে পারে যে এখানে প্রবাহ হ'ল প্রথমে মুদ্রণ করা, hello
পরে চালানো a
এবং তার পরে b
টাস্ক। তবে আসলে এই চালানো মানে a
এবং b
এ সমান্তরাল , এবং সামনে println("hello")
তাই
a
b
hello
বা অর্ডার a
এবং b
গ্যারান্টিযুক্ত কারণ
b
a
hello
সম্ভবত বিপরীতে, sbt এ সিরিয়াল চেয়ে সমান্তরাল করা সহজ। আপনার যদি ক্রমিক ক্রমের প্রয়োজন হয় তবে আপনাকে বিশেষ জিনিসগুলি ব্যবহার করতে হবে Def.sequential
বা বোঝার জন্যDef.taskDyn
অনুকরণ করতে হবে ।
def a = Def.task { println("a") }
def b = Def.task { println("b") }
lazy val c = taskKey[Unit]("")
c := Def.sequential(
Def.task(println("hello")),
a,
b
).value
অনুরূপ
for {
h <- Future(println("hello"))
a <- Future(println("a"))
b <- Future(println("b"))
} yield ()
যেখানে আমরা দেখতে পাই যে উপাদানগুলির মধ্যে কোনও নির্ভরতা নেই il
def a = Def.task { println("a"); 1 }
def b(v: Int) = Def.task { println("b"); v + 40 }
def sum(x: Int, y: Int) = Def.task[Int] { println("sum"); x + y }
lazy val c = taskKey[Int]("")
c := (Def.taskDyn {
val x = a.value
val y = Def.task(b(x).value)
Def.taskDyn(sum(x, y.value))
}).value
অনুরূপ
def a = Future { println("a"); 1 }
def b(v: Int) = Future { println("b"); v + 40 }
def sum(x: Int, y: Int) = Future { x + y }
for {
x <- a
y <- b(x)
c <- sum(x, y)
} yield { c }
যেখানে আমরা দেখতে sum
উপর নির্ভর করে এবং জন্য অপেক্ষা করতে হয়েছে a
এবং b
।
অন্য কথায়
- জন্য আবেদন শব্দার্থবিদ্যা, ব্যবহার
.value
- জন্য কীটাণুজাতীয় শব্দার্থবিদ্যা ব্যবহার
sequential
বাtaskDyn
এর পরিবর্তে যেখানে নির্ভরতা বাড়ানোর প্রকৃতির ফলস্বরূপ অন্য শব্দার্থগত বিভ্রান্তি স্নিপেট বিবেচনা করুনvalue
`value` can only be used within a task or setting macro, such as :=, +=, ++=, Def.task, or Def.setting.
val x = version.value
^
আমাদের লিখতে হবে
val x = settingKey[String]("")
x := version.value
দ্রষ্টব্য নোটটি .value
ডাগের সম্পর্কের বিষয়ে এবং এর অর্থ এই নয়
"এখনই আমাকে মূল্য দিন"
পরিবর্তে এটি কিছু ভালো মানে
"আমার কলারটি প্রথমে আমার উপর নির্ভর করে এবং আমি যখন পুরো ডিএজি একসাথে ফিট করে তা জানতে পারি, তখন আমি আমার কলারকে অনুরোধ করা মান সরবরাহ করতে সক্ষম হবো"
সুতরাং এখন এটি আরও পরিষ্কার হতে পারে কেন x
এখনও কোনও মূল্য নির্ধারণ করা যায় না; সম্পর্ক স্থাপনের পর্যায়ে এখনও কোনও মূল্য উপলব্ধ নেই।
আমরা স্কেল যথাযথ এবং ডিএসএল ভাষার মধ্যে শব্দার্থের পার্থক্য স্পষ্ট দেখতে পাচ্ছি build.sbt
। থাম্বসের কয়েকটি নিয়ম এখানে আমার জন্য কার্যকর
- ডিএজি বিভিন্ন ধরণের অভিব্যক্তি তৈরি করে তৈরি করা হয়
Setting[T]
- বেশিরভাগ ক্ষেত্রে আমরা কেবল
.value
সিনট্যাক্স ব্যবহার করি এবং এসবিটি এর মধ্যে সম্পর্ক স্থাপনের যত্ন নেবেSetting[T]
- মাঝেমধ্যে আমাদের ডিএজি-র একটি অংশ ম্যানুয়ালি মুছে ফেলা হয় এবং তার জন্য আমরা ব্যবহার করি
Def.sequential
বা করিDef.taskDyn
- এই অর্ডারিং / রিলেশনশিটির সিনট্যাটিক বৈষম্যগুলির যত্ন নেওয়া হয়ে গেলে, আমরা কাজগুলির বাকী ব্যবসায়ের লজিক তৈরির জন্য সাধারণ স্কালা শব্দার্থবিজ্ঞানের উপর নির্ভর করতে পারি।
কমান্ড বনাম টাস্ক
কমান্ডগুলি ডিএজি থেকে বেরিয়ে আসা অলস উপায়। কমান্ডগুলি ব্যবহার করে বিল্ডের অবস্থা এবং আপনার ইচ্ছামতো ক্রিয়াকলাপগুলি কার্যকর করা সহজ। ব্যয়টি হ'ল আমরা ডিএজি কর্তৃক প্রদত্ত কার্যগুলির সমান্তরালতা এবং প্রতিলিপিটি looseিলে .ালা করে রাখি, কোন ধরণের কাজগুলি পছন্দসই পছন্দ হওয়া উচিত। আপনি কমান্ডগুলি কোনও ধরণের স্থায়ী রেকর্ডিং হিসাবে বিবেচনা করতে পারেন যা কোনও অভ্যন্তরে করতে পারে sbt shell
। উদাহরণস্বরূপ, দেওয়া
vval x = settingKey[Int]("")
x := 13
lazy val f = taskKey[Int]("")
f := 1 + x.value
নিম্নলিখিত সেশনের আউটপুট বিবেচনা করুন
sbt:root> x
[info] 13
sbt:root> show f
[info] 14
sbt:root> set x := 41
[info] Defining x
[info] The new value will be used by f
[info] Reapplying settings...
sbt:root> show f
[info] 42
বিশেষত আমরা কীভাবে বিল্ডের অবস্থাটি পরিবর্তিত করব তা নয় set x := 41
। আদেশগুলি উদাহরণস্বরূপ, উপরের সেশনের স্থায়ী রেকর্ডিং করতে সক্ষম করে
commands += Command.command("cmd") { state =>
"x" :: "show f" :: "set x := 41" :: "show f" :: state
}
আমরা কমান্ডটি টাইপ-নিরাপদ ব্যবহার করে Project.extract
এবং করতে পারিrunTask
commands += Command.command("cmd") { state =>
val log = state.log
import Project._
log.info(x.value.toString)
val (_, resultBefore) = extract(state).runTask(f, state)
log.info(resultBefore.toString)
val mutatedState = extract(state).appendWithSession(Seq(x := 41), state)
val (_, resultAfter) = extract(mutatedState).runTask(f, mutatedState)
log.info(resultAfter.toString)
mutatedState
}
স্কোপস
যখন আমরা নিম্নলিখিত ধরণের প্রশ্নের উত্তর দেওয়ার চেষ্টা করি তখন স্কোপগুলি কার্যকর হয়
- কীভাবে একবার টাস্কটি সংজ্ঞায়িত করা যায় এবং মাল্টি-প্রজেক্ট বিল্ডে সমস্ত উপ-প্রকল্পগুলিতে এটি উপলব্ধ করা যায়?
- মূল ক্লাসপথে পরীক্ষার নির্ভরতা এড়ানো কীভাবে?
এসবিটিতে একটি মাল্টি-অক্ষ স্কোপিং স্পেস রয়েছে যা স্ল্যাশ সিনট্যাক্স ব্যবহার করে নেভিগেট করা যায় , উদাহরণস্বরূপ,
show root / Compile / compile / scalacOptions
| | | |
project configuration task key
ব্যক্তিগতভাবে, আমি নিজেকে খুব কমই সুযোগ সম্পর্কে চিন্তা করতে দেখি। কখনও কখনও আমি কেবল পরীক্ষার উত্সগুলি সংকলন করতে চাই
Test/compile
বা সম্ভবত কোনও প্রকল্পের সাথে নেভিগেট না করেই কোনও নির্দিষ্ট সাবপ্রজেক্ট থেকে একটি নির্দিষ্ট কাজ সম্পাদন করুন project subprojB
subprojB/Test/compile
আমি মনে করি থাম্বের নিম্নলিখিত নিয়মগুলি স্কোপিং জটিলতা এড়াতে সহায়তা করে
build.sbt
রুট প্রকল্পের অধীনে একাধিক ফাইল নেই তবে কেবলমাত্র একক মাস্টার যা অন্য সমস্ত উপ-প্রকল্পগুলি নিয়ন্ত্রণ করে
- অটো প্লাগইনগুলির মাধ্যমে কাজগুলি ভাগ করুন
- সাধারণ সেটিংসকে সরল স্কেলে ফ্যাক্ট
val
করুন এবং স্পষ্টভাবে প্রতিটি উপ-প্রকল্পে এটি যুক্ত করুন
বহু প্রকল্প নির্মাণ
প্রতিটি সাবপ্রজেক্টের জন্য একাধিক বিল্ড.এসবিটি ফাইলের আইন্সটেড
.
├── README.md
├── build.sbt
├── multi1
│ ├── build.sbt
│ ├── src
│ └── target
├── multi2
│ ├── build.sbt
│ ├── src
│ └── target
├── project
│ ├── FooPlugin.scala
│ ├── build.properties
│ ├── build.sbt
│ ├── plugins.sbt
│ ├── project
│ └── target
└── target
build.sbt
তাদের সকলকে শাসন করার জন্য একক মাস্টার থাকুন
.
├── README.md
├── build.sbt
├── common
│ ├── src
│ └── target
├── multi1
│ ├── src
│ └── target
├── multi2
│ ├── src
│ └── target
├── project
│ ├── FooPlugin.scala
│ ├── build.properties
│ ├── build.sbt
│ ├── plugins.sbt
│ ├── project
│ └── target
└── target
বহু-প্রকল্পের বিল্ডগুলিতে সাধারণ সেটিংস ফ্যাক্টর করার একটি প্রচলিত অনুশীলন রয়েছে
একটি ভালে সাধারণ সেটিংসের ক্রম সংজ্ঞায়িত করুন এবং প্রতিটি প্রকল্পে এগুলি যুক্ত করুন। সেভাবে শেখার জন্য কম ধারণা।
উদাহরণ স্বরূপ
lazy val commonSettings = Seq(
scalacOptions := Seq(
"-Xfatal-warnings",
...
),
publishArtifact := true,
...
)
lazy val root = project
.in(file("."))
.settings(settings)
.aggregate(
multi1,
multi2
)
lazy val multi1 = (project in file("multi1")).settings(commonSettings)
lazy val multi2 = (project in file("multi2")).settings(commonSettings)
প্রকল্প নেভিগেশন
projects
project multi1
প্লাগইনস
মনে রাখবেন বিল্ড সংজ্ঞাটি একটি যথাযথ স্কালাল প্রকল্প যা এর অধীনে থাকে project/
। এখানে আমরা .scala
ফাইল তৈরি করে একটি প্লাগইন সংজ্ঞায়িত করি
.
├── project
│ ├── FooPlugin.scala
│ ├── build.properties
│ ├── build.sbt
│ ├── plugins.sbt
│ ├── project
│ └── target
এখানে একটি সংক্ষিপ্ত স্বয়ংক্রিয় প্লাগইন অধীনেproject/FooPlugin.scala
object FooPlugin extends AutoPlugin {
object autoImport {
val barTask = taskKey[Unit]("")
}
import autoImport._
override def requires = plugins.JvmPlugin
override def trigger = allRequirements
override lazy val projectSettings = Seq(
scalacOptions ++= Seq("-Xfatal-warnings"),
barTask := { println("hello task") },
commands += Command.command("cmd") { state =>
"""eval println("hello command")""" :: state
}
)
}
ওভাররাইড
override def requires = plugins.JvmPlugin
কার্যকরভাবে স্পষ্টভাবে কল করেও সমস্ত উপ-প্রকল্পের প্লাগইন সক্রিয় করা উচিত enablePlugin
মধ্যে build.sbt
।
ইন্টেলিজ এবং এসবিটি
নিম্নলিখিত সেটিংস সক্ষম করুন (যা সত্যই ডিফল্ট দ্বারা সক্ষম করা উচিত )
use sbt shell
অধীনে
Preferences | Build, Execution, Deployment | sbt | sbt projects
মূল তথ্যসূত্র