Ai đó có thể giải thích cách sử dụng SBT đúng không?


100

Tôi lấy ra khỏi tủ về cái này! Tôi không hiểu SBT. Tôi đã nói rồi, giờ giúp tôi với.

Tất cả các con đường đều dẫn đến Rome, và đó là như nhau cho SBT: Để bắt đầu với SBTSBT, SBT Launcher, SBT-extras, vv, và sau đó có những cách khác nhau để bao gồm và quyết định kho. Có cách nào 'tốt nhất' không?

Tôi đang hỏi vì đôi khi tôi hơi lạc lối. Tài liệu SBT rất kỹ lưỡng và đầy đủ, nhưng tôi thấy mình không biết khi nào sử dụng build.sbthoặc project/build.propertieshoặc project/Build.scalahoặc project/plugins.sbt.

Sau đó, nó trở nên thú vị, có Scala-IDESBT- Cách chính xác để sử dụng chúng cùng nhau là gì? Cái gì có trước, con gà hay quả trứng?

Quan trọng nhất có lẽ là, làm thế nào để bạn tìm thấy các kho lưu trữ và phiên bản phù hợp để đưa vào dự án của mình? Tôi chỉ rút ra một con dao nhỏ và bắt đầu đi về phía trước? Tôi khá thường xuyên tìm thấy các dự án bao gồm mọi thứ và bồn rửa nhà bếp, và sau đó tôi nhận ra - tôi không phải là người duy nhất bị lạc một chút.

Ví dụ đơn giản, ngay bây giờ, tôi đang bắt đầu một dự án hoàn toàn mới. Tôi muốn sử dụng các tính năng mới nhất của SLICKScalavà điều này có thể sẽ yêu cầu phiên bản SBT mới nhất. Điểm lành mạnh để bắt đầu là gì và tại sao? Tôi nên định nghĩa nó trong tệp nào và nó trông như thế nào? Tôi biết tôi có thể làm điều này thành công, nhưng tôi thực sự muốn một ý kiến ​​chuyên gia về nơi mọi thứ nên đi đến đâu (tại sao nó nên đi sẽ có một phần thưởng).

Tôi đã sử dụng SBTcho các dự án nhỏ hơn một năm nay. Tôi đã sử dụng SBTvà sau đó SBT Extras(vì nó làm cho một số cơn đau đầu biến mất một cách kỳ diệu), nhưng tôi không chắc tại sao tôi nên sử dụng cái này hay cái kia. Tôi chỉ hơi bực bội vì không hiểu mọi thứ khớp với nhau như thế nào ( SBTvà kho lưu trữ), và nghĩ rằng nó sẽ giúp chàng trai tiếp theo gặp rất nhiều khó khăn nếu điều này có thể được giải thích theo cách hiểu của con người.


2
Chính xác thì ý bạn là gì với "có Scala-IDE và SBT"? Bạn xác định dự án của mình bằng sbt và sbt có thể tạo ra một dự án Ide (eclipse oder intellij). Vì vậy, SBT đến trước ...
tháng 1

2
@Jan Tôi đã đề cập điều đó vì Scala-IDE sử dụng SBT làm trình quản lý bản dựng. Xem assemblybla.com/spaces/scala-ide/wiki/SBT-based_build_manager và hạ xuống trong bài đăng mà họ đề cập "Không cần xác định tệp dự án SBT của bạn." mà tôi thấy khó hiểu.
Jack

đồng ý. Vì tôi thường sử dụng intellij (hoặc sublime) để chỉnh sửa scala, tôi không biết điều đó. Tôi đoán trình tạo tạo cấu hình sbt của riêng nó?
Tháng 1

2
@JacobusR Việc Scala IDE sử dụng SBT để xây dựng nguồn dự án của bạn là một chi tiết triển khai và người dùng không cần phải lo lắng về điều này. Thực sự có 0 hàm ý. Bên ngoài Eclipse, người dùng có thể xây dựng một dự án với SBT, Maven, Ant, ... và điều đó sẽ không tạo ra bất kỳ sự khác biệt nào đối với Scala IDE. Một điều nữa, ngay cả khi bạn có một dự án SBT, Scala IDE không quan tâm, tức là, nó không tìm kiếm bạn Build.scalađể thiết lập classpath, và đó là lý do tại sao bạn thực sự cần sbteclipse để tạo .classpath của Eclipse. Hi vọng điêu nay co ich.
Mirco Dotta

1
@Jan Scala IDE đã thêm vào sự nhầm lẫn và vâng, tài liệu cung cấp bức tranh toàn cảnh hơn về việc thiết lập một môi trường phát triển Scala tốt và một số hướng dẫn vững chắc về quy trình lập trình phù hợp sẽ rất hữu ích.
Jack,

Câu trả lời:


29

Quan trọng nhất có lẽ là, làm thế nào để bạn tìm thấy các kho lưu trữ và phiên bản phù hợp để đưa vào dự án của mình? Tôi chỉ rút ra một con dao nhỏ và bắt đầu đi về phía trước? Tôi thường thấy các dự án bao gồm mọi thứ và bồn rửa trong bếp

Đối với các phụ thuộc dựa trên Scala, tôi sẽ làm theo những gì các tác giả đề xuất. Ví dụ: http://code.google.com/p/scalaz/#SBT cho biết sử dụng:

libraryDependencies += "org.scalaz" %% "scalaz-core" % "6.0.4"

Hoặc https://github.com/typesafehub/sbteclipse/ có hướng dẫn về nơi để thêm:

addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.1.0-RC1")

Đối với các phụ thuộc dựa trên Java, tôi sử dụng http://mvnrepository.com/ để xem những gì ở đó, sau đó nhấp vào tab SBT. Ví dụ: http://mvnrepository.com/artifact/net.sf.opencsv/opencsv/2.3 cho biết sử dụng:

libraryDependencies += "net.sf.opencsv" % "opencsv" % "2.3"

Sau đó, rút ​​dao rựa ra và bắt đầu tiến về phía trước. Nếu bạn may mắn, bạn sẽ không sử dụng các lọ phụ thuộc vào một số lọ giống nhau nhưng với các phiên bản không tương thích. Với hệ sinh thái Java, bạn thường kết thúc bằng mọi thứ và bồn rửa bát và cần một chút nỗ lực để loại bỏ các phụ thuộc hoặc đảm bảo bạn không thiếu các phụ thuộc bắt buộc.

Ví dụ đơn giản, ngay bây giờ, tôi đang bắt đầu một dự án hoàn toàn mới. Tôi muốn sử dụng các tính năng mới nhất của SLICK và Scala và điều này có thể sẽ yêu cầu phiên bản mới nhất của SBT. Điểm lành mạnh để bắt đầu là gì và tại sao?

Tôi nghĩ điểm lành mạnh là xây dựng khả năng miễn nhiễm với sbt dần dần .

Đảm bảo rằng bạn hiểu:

  1. định dạng phạm vi {<build-uri>}<project-id>/config:key(for task-key)
  2. 3 hương vị các thiết lập ( SettingKey, TaskKey, InputKey) - đọc phần gọi là "Task Keys" trong http://www.scala-sbt.org/release/docs/Getting-Started/Basic-Def

Luôn mở 4 trang đó để bạn có thể xem và tra cứu các định nghĩa và ví dụ khác nhau:

  1. http://www.scala-sbt.org/release/docs/Getting-Started/Basic-Def
  2. http://www.scala-sbt.org/release/docs/Detailed-Topics/index
  3. http://harrah.github.com/xsbt/latest/sxr/Keys.scala.html
  4. http://harrah.github.com/xsbt/latest/sxr/Defaults.scala.html

Sử dụng tối đa showinspect và hoàn thành tab để làm quen với các giá trị thực tế của cài đặt, sự phụ thuộc, định nghĩa và cài đặt liên quan của chúng. Tôi không tin rằng các mối quan hệ mà bạn sẽ khám phá bằng cách sử dụng inspectđược ghi lại ở bất cứ đâu. Nếu có một cách tốt hơn tôi muốn biết về nó.


25

Cách tôi sử dụng sbt là:

  1. Sử dụng sbt-extras - chỉ cần lấy tập lệnh shell và thêm nó vào thư mục gốc của dự án của bạn
  2. Tạo một projectthư mục với một MyProject.scalatệp để thiết lập sbt. Tôi thích điều này hơn build.sbtcách tiếp cận - nó là vảy và linh hoạt hơn
  3. Tạo project/plugins.sbttệp và thêm plugin thích hợp cho IDE của bạn. Sbt-eclipse, sbt-idea hoặc ensime-sbt-cmd để bạn có thể tạo tệp dự án cho eclipse, intellij hoặc ensime.
  4. Khởi chạy sbt trong thư mục gốc của dự án của bạn và tạo các tệp dự án cho IDE của bạn
  5. Lợi nhuận

Tôi không bận tâm đến việc kiểm tra các tệp dự án IDE vì chúng được tạo bởi sbt, nhưng có thể có lý do bạn muốn làm điều đó.

Bạn có thể xem một ví dụ được thiết lập như thế này tại đây .


Cảm ơn bạn vì câu trả lời hay. Tôi chấp nhận câu trả lời khác, bởi vì nó bao gồm nhiều cơ sở hơn, và do bạn bỏ phiếu vì nó cũng thực sự tốt. Tôi sẽ chấp nhận cả hai nếu tôi có thể.
Jack

0

Sử dụng Typesafe Activator, một cách gọi sbt ưa thích, đi kèm với các mẫu và hạt giống của dự án: https://typesafe.com/activator

Activator new

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-java
 2) minimal-scala
 3) play-java
 4) play-scala
(hit tab to see a list of all templates)

5
Tôi có một phần ý tưởng rằng, khi nghi ngờ, việc thêm nhiều ma thuật vào hỗn hợp không có khả năng giải quyết vấn đề của bạn.
Khối

0

Cài đặt

brew install sbt hoặc số lượt cài đặt tương tự sbt mà về mặt kỹ thuật mà nói bao gồm

Khi bạn thực thi sbttừ thiết bị đầu cuối, nó thực sự chạy tập lệnh bash của trình khởi chạy sbt. Cá nhân tôi, tôi không bao giờ phải lo lắng về ba ngôi này, và chỉ sử dụng sbt như thể nó là một thứ duy nhất.

Cấu hình

Để cấu hình sbt cho một dự án cụ thể lưu .sbtoptstệp ở gốc của dự án. Để cấu hình sửa đổi toàn hệ thống sbt /usr/local/etc/sbtopts. Việc thực thi sbt -helpsẽ cho bạn biết vị trí chính xác. Ví dụ: để cung cấp thêm bộ nhớ cho sbt khi thực thi một lần sbt -mem 4096, hoặc lưu -mem 4096vào .sbtoptshoặc sbtoptsđể tăng bộ nhớ có hiệu lực vĩnh viễn.

 Cấu trúc dự án

sbt new scala/scala-seed.g8 tạo cấu trúc dự án Hello World sbt tối thiểu

.
├── README.md  // most important part of any software project
├── build.sbt  // build definition of the project
├── project    // build definition of the build (sbt is recursive - explained below)
├── src        // test and main source code
└── target     // compiled classes, deployment package

Các lệnh thường xuyên

test                                                // run all test
testOnly                                            // run only failed tests
testOnly -- -z "The Hello object should say hello"  // run one specific test
run                                                 // run default main
runMain example.Hello                               // run specific main
clean                                               // delete target/
package                                             // package skinny jar
assembly                                            // package fat jar
publishLocal                                        // library to local cache
release                                             // library to remote repository
reload                                              // after each change to build definition

Vô số vỏ

scala              // Scala REPL that executes Scala language (nothing to do with sbt)
sbt                // sbt REPL that executes special sbt shell language (not Scala REPL)
sbt console        // Scala REPL with dependencies loaded as per build.sbt
sbt consoleProject // Scala REPL with project definition and sbt loaded for exploration with plain Scala langauage

Định nghĩa xây dựng là một dự án Scala phù hợp

Đây là một trong những khái niệm sbt thành ngữ chính. Tôi sẽ cố gắng giải thích bằng một câu hỏi. Giả sử bạn muốn xác định một nhiệm vụ sbt sẽ thực thi một yêu cầu HTTP với scalaj-http. Bằng trực giác, chúng ta có thể thử những điều sau bên trongbuild.sbt

libraryDependencies +=  "org.scalaj" %% "scalaj-http" % "2.4.2"

val fooTask = taskKey[Unit]("Fetch meaning of life")
fooTask := {
  import scalaj.http._ // error: cannot resolve symbol
  val response = Http("http://example.com").asString
  ...
}

Tuy nhiên điều này sẽ báo lỗi thiếu import scalaj.http._. Làm thế nào điều này có thể thực hiện được khi chúng tôi, ngay phía trên, được thêm scalaj-httpvào libraryDependencies? Hơn nữa, tại sao nó hoạt động khi thay vào đó, chúng ta thêm phần phụ thuộc vào project/build.sbt?

// project/build.sbt
libraryDependencies +=  "org.scalaj" %% "scalaj-http" % "2.4.2"

Câu trả lời là đó fooTaskthực sự là một phần của dự án Scala riêng biệt với dự án chính của bạn. Dự án Scala khác nhau này có thể được tìm thấy trong project/thư mục có target/thư mục riêng nơi các lớp được biên dịch của nó cư trú. Trên thực tế, bên dưới project/target/config-classesnên có một lớp dịch ngược thành một cái gì đó như

object $9c2192aea3f1db3c251d extends scala.AnyRef {
  lazy val fooTask : sbt.TaskKey[scala.Unit] = { /* compiled code */ }
  lazy val root : sbt.Project = { /* compiled code */ }
}

Chúng ta thấy đó fooTaskchỉ đơn giản là một thành viên của một đối tượng Scala thông thường được đặt tên $9c2192aea3f1db3c251d. Rõ ràng scalaj-httpphải là sự phụ thuộc của dự án xác định $9c2192aea3f1db3c251dchứ không phải là sự phụ thuộc của dự án thích hợp. Do đó, nó cần phải được khai báo trong project/build.sbtthay vì build.sbt, bởi vì projectdự án Scala định nghĩa xây dựng nằm ở đâu.

Để thúc đẩy quan điểm rằng định nghĩa xây dựng chỉ là một dự án Scala khác, hãy thực thi sbt consoleProject. Điều này sẽ tải Scala REPL với dự án định nghĩa xây dựng trên classpath. Bạn sẽ thấy một nhập dọc theo các dòng

import $9c2192aea3f1db3c251d

Vì vậy, bây giờ chúng ta có thể tương tác trực tiếp với dự án định nghĩa xây dựng bằng cách gọi nó bằng Scala thích hợp thay vì build.sbtDSL. Ví dụ, các thực thi saufooTask

$9c2192aea3f1db3c251d.fooTask.eval

build.sbttrong dự án gốc là một DSL spcial giúp xác định định nghĩa xây dựng dự án Scala theo project/.

Và xây dựng định nghĩa dự án Scala, có thể có định nghĩa xây dựng dự án Scala của riêng mình theo project/project/và như vậy. Chúng tôi nói rằng sbt là đệ quy .

sbt là song song theo mặc định

sbt xây dựng DAG ngoài nhiệm vụ. Điều này cho phép nó phân tích sự phụ thuộc giữa các tác vụ và thực thi chúng song song và thậm chí thực hiện việc khử trùng lặp. build.sbtDSL được thiết kế với tâm trí này, có thể dẫn đến ngữ nghĩa ban đầu đáng ngạc nhiên. Bạn nghĩ thứ tự thực hiện trong đoạn mã sau là gì?

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
}

Theo trực giác, người ta có thể nghĩ rằng quy trình ở đây là đầu tiên in ra hellosau đó thực thi a, sau đó là btác vụ. Tuy nhiên điều này thực sự có nghĩa là thực hiện abtrong song song , và trước khi println("hello") quá

a
b
hello

hoặc vì thứ tự của abkhông được đảm bảo

b
a
hello

Có lẽ nghịch lý là trong sbt thì làm song song dễ hơn nối tiếp. Nếu bạn cần sắp xếp thứ tự, bạn sẽ phải sử dụng những thứ đặc biệt như Def.sequentialhoặc Def.taskDynđể mô phỏng để hiểu .

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

tương tự như

for {
  h <- Future(println("hello"))
  a <- Future(println("a"))
  b <- Future(println("b"))
} yield ()

nơi chúng tôi thấy không có sự phụ thuộc giữa các thành phần, trong khi

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

tương tự như

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 }

nơi chúng ta thấy sumphụ thuộc vào và phải chờ đợi ab.

Nói cách khác

  • đối với ngữ nghĩa ứng dụng , sử dụng.value
  • để sử dụng ngữ nghĩa đơn nguyênsequential hoặctaskDyn

Hãy xem xét một đoạn mã khác khó hiểu về mặt ngữ nghĩa do bản chất xây dựng phụ thuộc của value, where thay vì

`value` can only be used within a task or setting macro, such as :=, +=, ++=, Def.task, or Def.setting.
val x = version.value
                ^

chúng ta phải viết

val x = settingKey[String]("")
x := version.value

Lưu ý rằng cú pháp .valuelà về các mối quan hệ trong DAG và không có nghĩa là

"cho tôi giá trị ngay bây giờ"

thay vào đó nó có nghĩa là

"Người gọi của tôi phụ thuộc vào tôi trước tiên và khi tôi biết cách toàn bộ DAG khớp với nhau, tôi sẽ có thể cung cấp cho người gọi của mình giá trị được yêu cầu"

Vì vậy, bây giờ có thể rõ ràng hơn một chút tại sao xvẫn chưa thể gán giá trị; chưa có giá trị nào trong giai đoạn xây dựng mối quan hệ.

Chúng ta có thể thấy rõ sự khác biệt về ngữ nghĩa giữa ngôn ngữ Scala thích hợp và ngôn ngữ DSL trong build.sbt. Dưới đây là một số quy tắc ngón tay cái phù hợp với tôi

  • DAG được tạo ra từ các biểu thức của loại Setting[T]
  • Trong hầu hết các trường hợp, chúng tôi chỉ sử dụng .valuecú pháp và sbt sẽ đảm nhận việc thiết lập mối quan hệ giữaSetting[T]
  • Đôi khi, chúng tôi phải tinh chỉnh thủ công một phần của DAG và chúng tôi sử dụng Def.sequentialhoặcDef.taskDyn
  • Khi những điều kỳ lạ về thứ tự / mối quan hệ này được xử lý, chúng ta có thể dựa vào ngữ nghĩa Scala thông thường để xây dựng phần còn lại của logic nghiệp vụ của các tác vụ.

 Lệnh so với Nhiệm vụ

Các lệnh là một cách lười biếng ra khỏi DAG. Sử dụng các lệnh, bạn có thể dễ dàng thay đổi trạng thái xây dựng và tuần tự hóa các tác vụ theo ý muốn. Cái giá phải trả là chúng ta mất khả năng song song và loại trừ các nhiệm vụ do DAG cung cấp, theo cách nào thì các nhiệm vụ sẽ là lựa chọn ưu tiên. Bạn có thể coi các lệnh như một kiểu ghi lại vĩnh viễn một phiên mà người ta có thể thực hiện bên trong sbt shell. Ví dụ, cho

vval x = settingKey[Int]("")
x := 13
lazy val f = taskKey[Int]("")
f := 1 + x.value

xem xét kết quả của phiên sau

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

Đặc biệt không phải là cách chúng ta thay đổi trạng thái xây dựng với set x := 41. Các lệnh cho phép chúng tôi ghi lại vĩnh viễn phiên ở trên, ví dụ:

commands += Command.command("cmd") { state =>
  "x" :: "show f" :: "set x := 41" :: "show f" :: state
}

Chúng tôi cũng có thể làm cho loại lệnh an toàn bằng cách sử dụng Project.extractrunTask

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
}

Phạm vi

Phạm vi phát huy tác dụng khi chúng tôi cố gắng trả lời các loại câu hỏi sau

  • Làm thế nào để xác định nhiệm vụ một lần và cung cấp nó cho tất cả các dự án con trong xây dựng nhiều dự án?
  • Làm thế nào để tránh có các phụ thuộc kiểm tra vào classpath chính?

sbt có một không gian phạm vi nhiều trục có thể được điều hướng bằng cách sử dụng cú pháp gạch chéo , ví dụ:

show  root   /  Compile         /  compile   /   scalacOptions
        |        |                  |             |
     project    configuration      task          key

Cá nhân, tôi hiếm khi thấy mình phải lo lắng về phạm vi. Đôi khi tôi chỉ muốn biên dịch các nguồn thử nghiệm

Test/compile

hoặc có thể thực hiện một nhiệm vụ cụ thể từ một dự án con cụ thể mà không cần phải điều hướng đến dự án đó với project subprojB

subprojB/Test/compile

Tôi nghĩ rằng các quy tắc ngón tay cái sau đây giúp tránh các biến chứng trong phạm vi

  • không có nhiều build.sbttệp mà chỉ có một tệp chính duy nhất trong dự án gốc kiểm soát tất cả các dự án con khác
  • chia sẻ nhiệm vụ qua plugin tự động
  • đưa ra các cài đặt chung thành Scala đơn giản valvà thêm rõ ràng nó vào từng dự án con

Xây dựng nhiều dự án

Thay thế nhiều tệp build.sbt cho mỗi dự án con

.
├── README.md
├── build.sbt                  // OK
├── multi1
│   ├── build.sbt              // NOK
│   ├── src
│   └── target
├── multi2
│   ├── build.sbt              // NOK
│   ├── src
│   └── target
├── project                    // this is the meta-project
│   ├── FooPlugin.scala        // custom auto plugin
│   ├── build.properties       // version of sbt and hence Scala for meta-project
│   ├── build.sbt              // OK - this is actually for meta-project 
│   ├── plugins.sbt            // OK
│   ├── project
│   └── target
└── target

Có một bậc thầy duy nhất build.sbtđể cai trị tất cả

.
├── README.md
├── build.sbt                  // single build.sbt to rule theme all
├── common
│   ├── src
│   └── target
├── multi1
│   ├── src
│   └── target
├── multi2
│   ├── src
│   └── target
├── project
│   ├── FooPlugin.scala
│   ├── build.properties
│   ├── build.sbt
│   ├── plugins.sbt
│   ├── project
│   └── target
└── target

Có một thực tế phổ biến là tính các cài đặt chung trong các bản dựng nhiều dự án

xác định một chuỗi các cài đặt chung trong val và thêm chúng vào từng dự án. Ít khái niệm hơn để học theo cách đó.

ví dụ

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)

Điều hướng dự án

projects         // list all projects
project multi1   // change to particular project

bổ sung

Hãy nhớ định nghĩa xây dựng là một dự án Scala thích hợp nằm trong đó project/. Đây là nơi chúng tôi xác định một plugin bằng cách tạo .scalacác tệp

.                          // directory of the (main) proper project
├── project
│   ├── FooPlugin.scala    // auto plugin
│   ├── build.properties   // version of sbt library and indirectly Scala used for the plugin
│   ├── build.sbt          // build definition of the plugin
│   ├── plugins.sbt        // these are plugins for the main (proper) project, not the meta project
│   ├── project            // the turtle supporting this turtle
│   └── target             // compiled binaries of the plugin

Đây là một plugin tự động tối thiểu dướiproject/FooPlugin.scala

object FooPlugin extends AutoPlugin {
  object autoImport {
      val barTask = taskKey[Unit]("")
  }

  import autoImport._

  override def requires = plugins.JvmPlugin  // avoids having to call enablePlugin explicitly
  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
    }   
  )
}

Ghi đè

override def requires = plugins.JvmPlugin

hiệu quả nên kích hoạt các plugin cho tất cả các tiểu dự án mà không cần phải gọi một cách rõ ràng enablePlugintrong build.sbt.

IntelliJ và sbt

Vui lòng bật cài đặt sau (cài đặt này thực sự phải được bật theo mặc định )

use sbt shell

Dưới

Preferences | Build, Execution, Deployment | sbt | sbt projects

Tài liệu tham khảo chính

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.