Kann jemand erklären, wie man SBT richtig einsetzt?

100

Ich steige aus dem Schrank! Ich verstehe SBT nicht. Dort, sagte ich es, hilf mir jetzt bitte.

Alle Wege führen nach Rom, und das ist das gleiche für SBT: Um loszulegen mit SBTgibt es SBT, SBT Launcher, SBT-extras, etc, und dann gibt es verschiedene Möglichkeiten , um auf Repositorys aufzunehmen und zu entscheiden. Gibt es einen "besten" Weg?

Ich frage, weil ich mich manchmal etwas verliere. Die SBT-Dokumentation ist sehr gründlich und vollständig, aber ich weiß nicht, wann ich build.sbtoder project/build.propertiesoder project/Build.scalaoder verwenden soll project/plugins.sbt.

Dann macht es Spaß, es gibt das Scala-IDEund SBT- Was ist die richtige Art, sie zusammen zu verwenden? Was kommt zuerst, das Huhn oder das Ei?

Am wichtigsten ist wahrscheinlich, wie finden Sie die richtigen Repositorys und Versionen, die Sie in Ihr Projekt aufnehmen können? Ziehe ich einfach eine Machette heraus und beginne meinen Weg nach vorne zu hacken? Ich finde ziemlich oft Projekte, die alles und das Spülbecken beinhalten, und dann merke ich - ich bin nicht der einzige, der sich ein wenig verirrt.

Als einfaches Beispiel starte ich gerade ein brandneues Projekt. Ich möchte die neuesten Funktionen von SLICKund verwenden, Scalaund dies erfordert wahrscheinlich die neueste Version von SBT. Was ist der vernünftige Punkt, um loszulegen, und warum? In welcher Datei soll ich es definieren und wie soll es aussehen? Ich weiß, dass ich das zum Laufen bringen kann, aber ich hätte wirklich gerne eine Expertenmeinung darüber, wohin alles gehen soll (warum es dort hingehen sollte, wird ein Bonus sein).

Ich benutze SBTseit weit über einem Jahr für kleine Projekte. Ich benutzte SBTund dann SBT Extras(da dadurch einige Kopfschmerzen auf magische Weise verschwanden), aber ich bin mir nicht sicher, warum ich das eine oder andere verwenden sollte. Ich bin nur ein wenig frustriert, weil ich nicht verstehe, wie die Dinge zusammenpassen ( SBTund die Repositories), und denke, es wird dem nächsten Mann, der auf diese Weise kommt, viel Mühe ersparen, wenn dies in menschlichen Begriffen erklärt werden könnte.

Jack
quelle
2
Was genau meinst du mit "es gibt die Scala-IDE und SBT"? Sie definieren Ihr Projekt mit sbt und sbt kann ein ide-Projekt (Eclipse oder Intellij) generieren. So SBT zuerst kommt ...
Jan
2
@ Jan Ich erwähnte das, weil Scala-IDE SBT als Build Manager verwendet. Siehe assembla.com/spaces/scala-ide/wiki/SBT-based_build_manager und weiter unten in dem Beitrag, in dem erwähnt wird, dass Ihre SBT-Projektdatei nicht definiert werden muss. was ich verwirrend fand.
Jack
OK. Da ich normalerweise Intellij (oder Sublime) benutze, um Scala zu bearbeiten, wusste ich das nicht. Ich denke, der Builder generiert seine eigenen sbt-Konfigurationen.
Jan
2
@JacobusR Die Tatsache, dass die Scala-IDE SBT verwendet, um die Quellen Ihres Projekts zu erstellen, ist ein Implementierungsdetail, und Benutzer müssen sich darüber keine Gedanken machen. Es gibt wirklich 0 Implikationen. Außerhalb von Eclipse können Benutzer ein Projekt mit SBT, Maven, Ant, ... erstellen, was für die Scala-IDE keinen Unterschied macht. Eine weitere Sache, selbst wenn Sie ein SBT-Projekt haben, ist es der Scala-IDE egal, dh sie sucht nicht Build.scalanach dem Einrichten des Klassenpfads, und deshalb benötigen Sie tatsächlich sbteclipse , um den Eclipse-Klassenpfad zu generieren. Hoffe das hilft.
Mirco Dotta
1
@ Jan Scala IDE trug zur Verwirrung bei, und ja, eine Dokumentation, die ein umfassenderes Bild zum Einrichten einer guten Scala-Entwicklungsumgebung und eine solide Anleitung für geeignete Programmierworkflows bietet, wäre sehr nützlich.
Jack

Antworten:

29

Am wichtigsten ist wahrscheinlich, wie finden Sie die richtigen Repositorys und Versionen, die Sie in Ihr Projekt aufnehmen können? Ziehe ich einfach eine Machette heraus und beginne meinen Weg nach vorne zu hacken? Ich finde ziemlich oft Projekte, die alles und das Spülbecken beinhalten

Für Scala-basierte Abhängigkeiten würde ich den Empfehlungen der Autoren folgen. Zum Beispiel: http://code.google.com/p/scalaz/#SBT gibt an, Folgendes zu verwenden:

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

Oder https://github.com/typesafehub/sbteclipse/ enthält Anweisungen zum Hinzufügen:

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

Bei Java-basierten Abhängigkeiten verwende ich http://mvnrepository.com/, um zu sehen, was da draußen ist, und klicke dann auf die Registerkarte SBT. Zum Beispiel gibt http://mvnrepository.com/artifact/net.sf.opencsv/opencsv/2.3 an, Folgendes zu verwenden:

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

Ziehen Sie dann die Machette heraus und hacken Sie sich vorwärts. Wenn Sie Glück haben, verwenden Sie keine Gläser, die von einigen der gleichen Gläser abhängen, jedoch mit inkompatiblen Versionen. In Anbetracht des Java-Ökosystems schließen Sie häufig alles und das Spülbecken ein, und es erfordert einige Anstrengungen, um Abhängigkeiten zu beseitigen oder sicherzustellen, dass Ihnen die erforderlichen Abhängigkeiten nicht fehlen.

Als einfaches Beispiel starte ich gerade ein brandneues Projekt. Ich möchte die neuesten Funktionen von SLICK und Scala verwenden und dies erfordert wahrscheinlich die neueste Version von SBT. Was ist der vernünftige Punkt, um loszulegen, und warum?

Ich denke, der vernünftige Punkt ist, allmählich Immunität gegen sbt aufzubauen .

Stellen Sie sicher, dass Sie verstehen:

  1. Gültigkeitsbereichsformat {<build-uri>}<project-id>/config:key(for task-key)
  2. die drei Varianten von Einstellungen ( SettingKey, TaskKey, InputKey) - Abschnitt namens „Task Keys“ in lesen http://www.scala-sbt.org/release/docs/Getting-Started/Basic-Def

Lassen Sie diese 4 Seiten immer offen, damit Sie verschiedene Definitionen und Beispiele nachschlagen können:

  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

Nutzen Sie showund inspect und die Registerkarte vollständig , um sich mit den tatsächlichen Werten der Einstellungen, ihren Abhängigkeiten, Definitionen und zugehörigen Einstellungen vertraut zu machen. Ich glaube nicht, dass die Beziehungen, die Sie entdecken, inspectirgendwo dokumentiert sind. Wenn es einen besseren Weg gibt, möchte ich es wissen.

huynhjl
quelle
25

Ich benutze sbt wie folgt:

  1. Verwenden Sie sbt-extras - holen Sie sich einfach das Shell-Skript und fügen Sie es dem Stammverzeichnis Ihres Projekts hinzu
  2. Erstellen Sie einen projectOrdner mit einer MyProject.scalaDatei zum Einrichten von sbt. Ich ziehe dies dem build.sbtAnsatz vor - es ist eine Scala und flexibler
  3. Erstellen Sie eine project/plugins.sbtDatei und fügen Sie das entsprechende Plugin für Ihre IDE hinzu. Entweder sbt-eclipse, sbt-idea oder ensime-sbt-cmd, damit Sie Projektdateien für Eclipse, Intellij oder Ensime generieren können.
  4. Starten Sie sbt im Stammverzeichnis Ihres Projekts und generieren Sie die Projektdateien für Ihre IDE
  5. Profitieren

Ich mache mir nicht die Mühe, die IDE-Projektdateien einzuchecken, da sie von sbt generiert werden, aber es kann Gründe geben, warum Sie dies tun möchten.

Ein Beispiel wie dieses sehen Sie hier .

Channing Walton
quelle
Danke für die gute Antwort. Ich habe die andere Antwort akzeptiert, weil sie mehr Boden abdeckt und Ihre Sache verbessert hat, weil sie auch wirklich gut ist. Ich hätte beides akzeptiert, wenn ich könnte.
Jack
0

Verwenden Sie Typesafe Activator, eine ausgefallene Methode zum Aufrufen von sbt, die mit Projektvorlagen und Seeds geliefert wird: 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)
Andreas Neumann
quelle
5
Ich bin Teil der Idee, dass das Hinzufügen von mehr Magie zu der Mischung im Zweifelsfall Ihre Probleme wahrscheinlich nicht lösen wird.
Cubic
0

Installation

brew install sbt oder ähnliches installiert sbt, aus dem technisch gesehen besteht

Wenn Sie sbtvom Terminal ausführen , wird tatsächlich das Bash-Skript sbt launcher ausgeführt. Persönlich musste ich mir nie Sorgen um diese Dreifaltigkeit machen und sbt einfach so verwenden, als wäre es eine einzige Sache.

Aufbau

Um sbt für ein bestimmtes Projekt zu konfigurieren, speichern Sie die .sbtoptsDatei im Stammverzeichnis des Projekts. Um sbt systemweit zu konfigurieren, ändern Sie /usr/local/etc/sbtopts. Die Ausführung sbt -helpsollte Ihnen den genauen Ort mitteilen. Zum Beispiel zu geben sbt mehr Speicher als Einmal ausführen sbt -mem 4096oder speichern -mem 4096in .sbtoptsoder sbtoptsfür Speichererhöhungseffekt dauerhaft zu übernehmen.

 Projektstruktur

sbt new scala/scala-seed.g8 erstellt eine minimale Hello World sbt-Projektstruktur

.
├── 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

Häufige Befehle

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

Unzählige Muscheln

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

Die Build-Definition ist ein richtiges Scala-Projekt

Dies ist eines der wichtigsten idiomatischen sbt-Konzepte. Ich werde versuchen, mit einer Frage zu erklären. Angenommen, Sie möchten eine sbt-Task definieren, die eine HTTP-Anforderung mit scalaj-http ausführt. Intuitiv könnten wir das Folgende versuchenbuild.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
  ...
}

Dies führt jedoch zu einem Fehler bei der Meldung "fehlt" import scalaj.http._. Wie ist das möglich , wenn wir direkt oben, hinzugefügt scalaj-httpzu libraryDependencies? Warum funktioniert es außerdem, wenn wir stattdessen die Abhängigkeit hinzufügen project/build.sbt?

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

Die Antwort ist, dass dies fooTasktatsächlich Teil eines von Ihrem Hauptprojekt getrennten Scala- Projekts ist. Dieses andere Scala-Projekt befindet sich im project/Verzeichnis, das über ein eigenes target/Verzeichnis verfügt, in dem sich die kompilierten Klassen befinden. In der Tat project/target/config-classessollte es unter eine Klasse geben, die sich zu so etwas dekompiliert

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

Wir sehen, dass dies fooTaskeinfach ein Mitglied eines regulären Scala-Objekts mit dem Namen ist $9c2192aea3f1db3c251d. Es scalaj-httpsollte klar sein, dass eine Abhängigkeit vom Projekt definiert wird $9c2192aea3f1db3c251dund nicht die Abhängigkeit des richtigen Projekts. Daher muss es project/build.sbtanstelle von deklariert werden build.sbt, da projectsich dort das Build-Definitions-Scala-Projekt befindet.

Führen Sie aus, um den Punkt zu bestimmen, dass die Build-Definition nur ein weiteres Scala-Projekt ist sbt consoleProject. Dadurch wird Scala REPL mit dem Build-Definitionsprojekt im Klassenpfad geladen. Sie sollten einen Import nach dem Vorbild von sehen

import $9c2192aea3f1db3c251d

Jetzt können wir direkt mit dem Build-Definitionsprojekt interagieren, indem wir es mit Scala anstelle von build.sbtDSL aufrufen . Zum Beispiel wird Folgendes ausgeführtfooTask

$9c2192aea3f1db3c251d.fooTask.eval

build.sbtUnter Root-Projekt befindet sich ein spezielles DSL, mit dessen Hilfe die Build-Definition des Scala-Projekts definiert werden kann project/.

Und Build Definition Scala-Projekt, kann ein eigenes Build Definition Scala-Projekt unter project/project/und so weiter haben. Wir sagen, sbt ist rekursiv .

sbt ist standardmäßig parallel

sbt baut DAG aus Aufgaben auf. Auf diese Weise können Abhängigkeiten zwischen Aufgaben analysiert und parallel ausgeführt und sogar eine Deduplizierung durchgeführt werden. build.sbtDSL wurde unter diesem Gesichtspunkt entwickelt, was zu einer zunächst überraschenden Semantik führen kann. Was denkst du, ist die Reihenfolge der Ausführung im folgenden Ausschnitt?

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
}

Intuitiv könnte man denken, dass der Fluss hier darin besteht, zuerst zu drucken, hellodann auszuführen aund dann eine bAufgabe auszuführen . Allerdings bedeutet dies tatsächlich ausführen aund bin parallel , und vor println("hello") so

a
b
hello

oder weil die Reihenfolge von aund bnicht garantiert ist

b
a
hello

Vielleicht paradoxerweise ist es in sbt einfacher, parallel als seriell zu arbeiten. Wenn Sie eine Serienbestellung benötigen, müssen Sie spezielle Dinge wie Def.sequentialoder Def.taskDynzum Verständnis nachahmen .

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

ist ähnlich wie

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

wo wir sehen, gibt es keine Abhängigkeiten zwischen Komponenten, während

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

ist ähnlich wie

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 }

wo wir sehen , sumhängt davon ab , und hat zu warten aund b.

Mit anderen Worten

  • Verwenden Sie für die anwendungsbezogene Semantik.value
  • für monadische Semantik verwenden sequentialodertaskDyn

Betrachten Sie ein anderes semantisch verwirrendes Snippet als Ergebnis der Abhängigkeitsbildung von value, wo statt

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

wir müssen schreiben

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

Beachten Sie, dass sich die Syntax .valueauf Beziehungen in der DAG bezieht und nicht bedeutet

"Gib mir jetzt den Wert"

stattdessen bedeutet es so etwas wie

"Mein Anrufer hängt zuerst von mir ab, und sobald ich weiß, wie die gesamte DAG zusammenpasst, kann ich meinem Anrufer den gewünschten Wert liefern."

Jetzt ist es vielleicht etwas klarer, warum xnoch kein Wert zugewiesen werden kann. In der Phase des Beziehungsaufbaus ist noch kein Wert verfügbar.

Wir können deutlich einen Unterschied in der Semantik zwischen Scala und der DSL-Sprache in erkennen build.sbt. Hier sind einige Faustregeln, die für mich funktionieren

  • DAG besteht aus Typausdrücken Setting[T]
  • In den meisten Fällen verwenden wir einfach die .valueSyntax und sbt kümmert sich um die Herstellung der Beziehung zwischenSetting[T]
  • Gelegentlich müssen wir einen Teil der DAG manuell anpassen und dafür verwenden wir Def.sequentialoderDef.taskDyn
  • Sobald diese Ordnungs- / Beziehungssyntatik-Kuriositäten behoben sind, können wir uns auf die übliche Scala-Semantik verlassen, um den Rest der Geschäftslogik von Aufgaben aufzubauen.

 Befehle gegen Aufgaben

Befehle sind ein fauler Ausweg aus der DAG. Mit Befehlen können Sie den Build-Status einfach mutieren und Aufgaben nach Ihren Wünschen serialisieren. Die Kosten sind, dass wir die Parallelisierung und Deduplizierung der von der DAG bereitgestellten Aufgaben verlieren. Auf diese Weise sollten Aufgaben die bevorzugte Wahl sein. Sie können sich Befehle als eine Art permanente Aufzeichnung einer Sitzung vorstellen, die Sie möglicherweise im Inneren ausführen sbt shell. Zum Beispiel gegeben

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

Betrachten Sie die Ausgabe der folgenden Sitzung

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

Insbesondere nicht, wie wir den Build-Status mutieren set x := 41. Mit Befehlen können wir beispielsweise die obige Sitzung permanent aufzeichnen

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

Wir können den Befehl auch mit Project.extractund typsicher machenrunTask

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
}

Geltungsbereich

Bereiche kommen ins Spiel, wenn wir versuchen, die folgenden Fragen zu beantworten

  • Wie definiere ich eine Aufgabe einmal und stelle sie allen Teilprojekten im Multi-Projekt-Build zur Verfügung?
  • Wie vermeide ich Testabhängigkeiten vom Hauptklassenpfad?

sbt verfügt über einen mehrachsigen Gültigkeitsbereich , der beispielsweise mithilfe der Schrägstrichsyntax navigiert werden kann.

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

Persönlich muss ich mir selten Sorgen um den Umfang machen. Manchmal möchte ich nur Testquellen kompilieren

Test/compile

oder führen Sie möglicherweise eine bestimmte Aufgabe aus einem bestimmten Teilprojekt aus, ohne zuvor mit zu diesem Projekt navigieren zu müssen project subprojB

subprojB/Test/compile

Ich denke, die folgenden Faustregeln helfen dabei, Komplikationen beim Scoping zu vermeiden

  • Sie haben nicht mehrere build.sbtDateien, sondern nur eine einzige Master-Datei unter dem Root-Projekt, die alle anderen Unterprojekte steuert
  • Aufgaben über Auto-Plugins teilen
  • Faktor aus allgemeinen Einstellungen in Klar Scala valund es explizit zu jedem Teilprojekt hinzufügen

Multi-Projekt-Build

Anstelle mehrerer build.sbt-Dateien für jedes Teilprojekt

.
├── 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

Haben Sie einen einzigen Meister build.sbt, der sie alle regiert

.
├── 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

Es ist üblich , gemeinsame Einstellungen in Builds mit mehreren Projekten herauszufiltern

Definieren Sie eine Folge allgemeiner Einstellungen in einem Wert und fügen Sie sie jedem Projekt hinzu. Weniger Konzepte, um so zu lernen.

beispielsweise

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)

Projektnavigation

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

Plugins

Denken Sie daran, dass die Build-Definition ein richtiges Scala-Projekt ist, unter dem sich befindet project/. Hier definieren wir ein Plugin, indem wir .scalaDateien erstellen

.                          // 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

Hier ist ein minimales Auto-Plugin unterproject/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
    }   
  )
}

Die Außerkraftsetzung

override def requires = plugins.JvmPlugin

sollte das Plugin effektiv für alle Unterprojekte aktivieren, ohne explizit aufrufen enablePluginzu müssen build.sbt.

IntelliJ und sbt

Bitte aktivieren Sie die folgende Einstellung (die eigentlich standardmäßig aktiviert sein sollte )

use sbt shell

unter

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

Wichtige Referenzen

Mario Galic
quelle