40

这是一个例子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"
  )): _*)

目标是拥有 spark-core "provided",因此它及其依赖项不包含在程序集工件中,而是将它们重新包含在运行时类路径中以用于run- 和 -test相关任务。

似乎使用自定义范围最终会有所帮助,但我对如何实际导致默认/全局运行/测试任务使用自定义libraryDependencies并希望覆盖默认值感到困惑。我尝试过的事情包括:

(run in Global) := (run in FunnyRuntime)

之类的无济于事。

总结一下:这感觉本质上是对 web 案例的概括,其中 servlet-api 在“提供”范围内,并且运行/测试任务通常派生一个 servlet 容器,该容器确实为运行代码提供了 servlet-api。这里唯一的区别是我没有分叉一个单独的 JVM/环境。我只想手动增加这些任务的类路径,有效地“撤消”“提供的”范围,但以一种继续从组装工件中排除依赖的方式。

4

4 回答 4

49

对于我在 assembly.sbt 中使用的类似情况:

run in Compile <<= Defaults.runTask(fullClasspath in Compile, mainClass in (Compile, run), runner in (Compile, run)) 

现在“运行”任务使用所有库,包括标有“提供”的库。无需进一步更改。

更新:

@rob 解决方案似乎是唯一适用于最新 SBT 版本的解决方案,只需添加settingsbuild.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
于 2014-02-15T20:45:12.877 回答
14

添加到@douglaz的答案,

runMain in Compile <<= Defaults.runMainTask(fullClasspath in Compile, runner in (Compile, run))

是 runMain 任务的相应修复。

于 2014-05-22T07:30:53.203 回答
3

另一种选择是为组装与运行/测试创建单独的 sbt 项目。这允许您运行sbt assemblyProj/assembly构建一个 fat jar 以使用 spark-submit 进行部署,以及sbt runTestProj/run直接通过嵌入 Spark 的 sbt 运行。作为额外的好处,runTestProj 无需修改即可在 IntelliJ 中运行,并且可以为每个项目定义一个单独的主类,以便在使用 sbt 运行时在代码中指定 spark master。

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
  )
于 2019-02-27T18:29:58.840 回答
2

如果您使用sbt-revolver插件,这里是其“重新启动”任务的解决方案:

fullClasspath in Revolver.reStart <<= fullClasspath in Compile

UPD:对于 sbt-1.0,您可以使用新的分配表:

fullClasspath in Revolver.reStart := (fullClasspath in Compile).value

于 2015-01-28T19:28:10.547 回答