web-dev-qa-db-fra.com

Comment ajouter des dépendances «fournies» au chemin de classe des tâches d'exécution / test?

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.

39
user2785627

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
49
douglaz

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.

14
tgpfeiffer

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

2
VasiliNovikov

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
  )
1
Ryan