Voici un exemple build.sbt
:
import AssemblyKeys._
assemblySettings
buildInfoSettings
net.virtualvoid.sbt.graph.Plugin.graphSettings
name := "scala-app-template"
version := "0.1"
scalaVersion := "2.9.3"
val FunnyRuntime = config("funnyruntime") extend(Compile)
libraryDependencies += "org.spark-project" %% "spark-core" % "0.7.3" % "provided"
sourceGenerators in Compile <+= buildInfo
buildInfoPackage := "com.psnively"
buildInfoKeys := Seq[BuildInfoKey](name, version, scalaVersion, target)
assembleArtifact in packageScala := false
val root = project.in(file(".")).
configs(FunnyRuntime).
settings(inConfig(FunnyRuntime)(Classpaths.configSettings ++ baseAssemblySettings ++ Seq(
libraryDependencies += "org.spark-project" %% "spark-core" % "0.7.3" % "funnyruntime"
)): _*)
Le but est d'avoir un noyau d'allumage "provided"
afin que lui et ses dépendances ne soient pas inclus dans l'artefact Assembly, mais pour les inclure à nouveau dans le chemin d'accès aux classes d'exécution pour les tâches liées à run
- et test
.
Il semble que l'utilisation d'une étendue personnalisée sera finalement utile, mais je suis entravé sur la façon de faire en sorte que les tâches d'exécution/test par défaut/globales utilisent le libraryDependencies
personnalisé et, espérons-le, remplacent le défaut. J'ai essayé des choses comme:
(run in Global) := (run in FunnyRuntime)
et autres en vain.
Pour résumer: cela ressemble essentiellement à une généralisation du cas Web, où le servlet-api est dans la portée "fournie", et les tâches d'exécution/test génèrent généralement un conteneur de servlet qui fournit vraiment le servlet-api au code en cours d'exécution. La seule différence ici est que je ne bifurque pas sur une JVM/un environnement séparé; Je veux juste augmenter manuellement les chemins de classe de ces tâches, "annulant" effectivement la portée "fournie", mais d'une manière qui continue d'exclure la dépendance de l'artefact Assembly.
Pour un cas similaire que j'ai utilisé dans Assembly.sbt:
run in Compile <<= Defaults.runTask(fullClasspath in Compile, mainClass in (Compile, run), runner in (Compile, run))
et maintenant la tâche "exécuter" utilise toutes les bibliothèques, y compris celles marquées "fournies". Aucun autre changement n'était nécessaire.
Mettre à jour:
La solution @rob semble être la seule à travailler sur la dernière version de SBT, il suffit de l'ajouter à settings
dans build.sbt
:
run in Compile := Defaults.runTask(fullClasspath in Compile, mainClass in (Compile, run), runner in (Compile, run)).evaluated,
runMain in Compile := Defaults.runMainTask(fullClasspath in Compile, runner in(Compile, run)).evaluated
Ajoutant à la réponse de @douglaz,
runMain in Compile <<= Defaults.runMainTask(fullClasspath in Compile, runner in (Compile, run))
est le correctif correspondant pour la tâche runMain.
Si vous utilisez le plugin sbt-revolver
, Voici une solution pour sa tâche "reStart":
fullClasspath in Revolver.reStart <<= fullClasspath in Compile
UPD: pour sbt-1.0, vous pouvez utiliser le nouveau formulaire de mission:
fullClasspath in Revolver.reStart := (fullClasspath in Compile).value
Une autre option consiste à créer des projets sbt distincts pour Assembly vs run/test. Cela vous permet d'exécuter sbt asseblyProj/Assembly
pour construire un gros pot à déployer avec spark-submit, ainsi que sbt runTestProj/run
pour s'exécuter directement via sbt avec Spark incorporé. Comme avantages supplémentaires, runTestProj fonctionnera sans modification dans IntelliJ, et une classe principale séparée peut être définie pour chaque projet afin par exemple de spécifier le = spark master dans le code lors de l'exécution avec sbt.
val sparkDep = "org.Apache.spark" %% "spark-core" % sparkVersion
val commonSettings = Seq(
name := "Project",
libraryDependencies ++= Seq(...) // Common deps
)
// Project for running via spark-submit
lazy val assemblyProj = (project in file("proj-dir"))
.settings(
commonSettings,
Assembly / mainClass := Some("com.example.Main"),
libraryDependencies += sparkDep % "provided"
)
// Project for running via sbt with embedded spark
lazy val runTestProj = (project in file("proj-dir"))
.settings(
// Projects' target dirs can't overlap
target := target.value.toPath.resolveSibling("target-runtest").toFile,
commonSettings,
// If separate main file needed, e.g. for specifying spark master in code
Compile / run / mainClass := Some("com.example.RunMain"),
libraryDependencies += sparkDep
)