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 SBT
gibt 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.sbt
oder project/build.properties
oder project/Build.scala
oder verwenden soll project/plugins.sbt
.
Dann macht es Spaß, es gibt das Scala-IDE
und 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 SLICK
und verwenden, Scala
und 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 SBT
seit weit über einem Jahr für kleine Projekte. Ich benutzte SBT
und 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 ( SBT
und 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.
Build.scala
nach dem Einrichten des Klassenpfads, und deshalb benötigen Sie tatsächlich sbteclipse , um den Eclipse-Klassenpfad zu generieren. Hoffe das hilft.Antworten:
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:
Oder https://github.com/typesafehub/sbteclipse/ enthält Anweisungen zum Hinzufügen:
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:
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.
Ich denke, der vernünftige Punkt ist, allmählich Immunität gegen sbt aufzubauen .
Stellen Sie sicher, dass Sie verstehen:
{<build-uri>}<project-id>/config:key(for task-key)
SettingKey
,TaskKey
,InputKey
) - Abschnitt namens „Task Keys“ in lesen http://www.scala-sbt.org/release/docs/Getting-Started/Basic-DefLassen Sie diese 4 Seiten immer offen, damit Sie verschiedene Definitionen und Beispiele nachschlagen können:
Nutzen Sie
show
undinspect
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,inspect
irgendwo dokumentiert sind. Wenn es einen besseren Weg gibt, möchte ich es wissen.quelle
Ich benutze sbt wie folgt:
project
Ordner mit einerMyProject.scala
Datei zum Einrichten von sbt. Ich ziehe dies dembuild.sbt
Ansatz vor - es ist eine Scala und flexiblerproject/plugins.sbt
Datei 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.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 .
quelle
Verwenden Sie Typesafe Activator, eine ausgefallene Methode zum Aufrufen von sbt, die mit Projektvorlagen und Seeds geliefert wird: https://typesafe.com/activator
quelle
Installation
brew install sbt
oder ähnliches installiert sbt, aus dem technisch gesehen bestehtWenn Sie
sbt
vom 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
.sbtopts
Datei im Stammverzeichnis des Projekts. Um sbt systemweit zu konfigurieren, ändern Sie/usr/local/etc/sbtopts
. Die Ausführungsbt -help
sollte Ihnen den genauen Ort mitteilen. Zum Beispiel zu geben sbt mehr Speicher als Einmal ausführensbt -mem 4096
oder speichern-mem 4096
in.sbtopts
odersbtopts
für Speichererhöhungseffekt dauerhaft zu übernehmen.Projektstruktur
sbt new scala/scala-seed.g8
erstellt eine minimale Hello World sbt-ProjektstrukturHäufige Befehle
Unzählige Muscheln
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 versuchen
build.sbt
Dies führt jedoch zu einem Fehler bei der Meldung "fehlt"
import scalaj.http._
. Wie ist das möglich , wenn wir direkt oben, hinzugefügtscalaj-http
zulibraryDependencies
? Warum funktioniert es außerdem, wenn wir stattdessen die Abhängigkeit hinzufügenproject/build.sbt
?Die Antwort ist, dass dies
fooTask
tatsächlich Teil eines von Ihrem Hauptprojekt getrennten Scala- Projekts ist. Dieses andere Scala-Projekt befindet sich improject/
Verzeichnis, das über ein eigenestarget/
Verzeichnis verfügt, in dem sich die kompilierten Klassen befinden. In der Tatproject/target/config-classes
sollte es unter eine Klasse geben, die sich zu so etwas dekompiliertWir sehen, dass dies
fooTask
einfach ein Mitglied eines regulären Scala-Objekts mit dem Namen ist$9c2192aea3f1db3c251d
. Esscalaj-http
sollte klar sein, dass eine Abhängigkeit vom Projekt definiert wird$9c2192aea3f1db3c251d
und nicht die Abhängigkeit des richtigen Projekts. Daher muss esproject/build.sbt
anstelle von deklariert werdenbuild.sbt
, daproject
sich 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 sehenJetzt können wir direkt mit dem Build-Definitionsprojekt interagieren, indem wir es mit Scala anstelle von
build.sbt
DSL aufrufen . Zum Beispiel wird Folgendes ausgeführtfooTask
build.sbt
Unter Root-Projekt befindet sich ein spezielles DSL, mit dessen Hilfe die Build-Definition des Scala-Projekts definiert werden kannproject/
.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.sbt
DSL 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?Intuitiv könnte man denken, dass der Fluss hier darin besteht, zuerst zu drucken,
hello
dann auszuführena
und dann eineb
Aufgabe auszuführen . Allerdings bedeutet dies tatsächlich ausführena
undb
in parallel , und vorprintln("hello")
sooder weil die Reihenfolge von
a
undb
nicht garantiert istVielleicht paradoxerweise ist es in sbt einfacher, parallel als seriell zu arbeiten. Wenn Sie eine Serienbestellung benötigen, müssen Sie spezielle Dinge wie
Def.sequential
oderDef.taskDyn
zum Verständnis nachahmen .ist ähnlich wie
wo wir sehen, gibt es keine Abhängigkeiten zwischen Komponenten, während
ist ähnlich wie
wo wir sehen ,
sum
hängt davon ab , und hat zu wartena
undb
.Mit anderen Worten
.value
sequential
odertaskDyn
Betrachten Sie ein anderes semantisch verwirrendes Snippet als Ergebnis der Abhängigkeitsbildung von
value
, wo stattwir müssen schreiben
Beachten Sie, dass sich die Syntax
.value
auf Beziehungen in der DAG bezieht und nicht bedeutetstattdessen bedeutet es so etwas wie
Jetzt ist es vielleicht etwas klarer, warum
x
noch 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 funktionierenSetting[T]
.value
Syntax und sbt kümmert sich um die Herstellung der Beziehung zwischenSetting[T]
Def.sequential
oderDef.taskDyn
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 gegebenBetrachten Sie die Ausgabe der folgenden Sitzung
Insbesondere nicht, wie wir den Build-Status mutieren
set x := 41
. Mit Befehlen können wir beispielsweise die obige Sitzung permanent aufzeichnenWir können den Befehl auch mit
Project.extract
und typsicher machenrunTask
Geltungsbereich
Bereiche kommen ins Spiel, wenn wir versuchen, die folgenden Fragen zu beantworten
sbt verfügt über einen mehrachsigen Gültigkeitsbereich , der beispielsweise mithilfe der Schrägstrichsyntax navigiert werden kann.
Persönlich muss ich mir selten Sorgen um den Umfang machen. Manchmal möchte ich nur Testquellen kompilieren
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
Ich denke, die folgenden Faustregeln helfen dabei, Komplikationen beim Scoping zu vermeiden
build.sbt
Dateien, sondern nur eine einzige Master-Datei unter dem Root-Projekt, die alle anderen Unterprojekte steuertval
und es explizit zu jedem Teilprojekt hinzufügenMulti-Projekt-Build
Anstelle mehrerer build.sbt-Dateien für jedes Teilprojekt
Haben Sie einen einzigen Meister
build.sbt
, der sie alle regiertEs ist üblich , gemeinsame Einstellungen in Builds mit mehreren Projekten herauszufiltern
beispielsweise
Projektnavigation
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.scala
Dateien erstellenHier ist ein minimales Auto-Plugin unter
project/FooPlugin.scala
Die Außerkraftsetzung
sollte das Plugin effektiv für alle Unterprojekte aktivieren, ohne explizit aufrufen
enablePlugin
zu müssenbuild.sbt
.IntelliJ und sbt
Bitte aktivieren Sie die folgende Einstellung (die eigentlich standardmäßig aktiviert sein sollte )
unter
Wichtige Referenzen
quelle