如何将“提供的”依赖项添加回运行/测试任务的类路径?
Posted
技术标签:
【中文标题】如何将“提供的”依赖项添加回运行/测试任务的类路径?【英文标题】:How to add "provided" dependencies back to run/test tasks' classpath? 【发布时间】:2013-09-21 05:57:02 【问题描述】:这是一个例子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/环境。我只想手动增加这些任务的类路径,有效地“撤消”“提供”的范围,但以一种继续从组装工件中排除依赖的方式。
【问题讨论】:
我不需要“添加回”使用 sbt run 或 intellij 运行的“提供的”依赖项。看看这个:github.com/dportabella/spark-examples 【参考方案1】:对于我在 assembly.sbt 中使用的类似情况:
run in Compile <<= Defaults.runTask(fullClasspath in Compile, mainClass in (Compile, run), runner in (Compile, run))
现在“运行”任务使用所有库,包括标有“已提供”的库。无需进一步更改。
更新:
@rob 解决方案似乎是唯一适用于最新 SBT 版本的解决方案,只需在 build.sbt
中添加到 settings
:
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
【讨论】:
@douglaz 可以确认不适用于最新的 IntelliJ。我的解决方法是创建一个用于运行和调试本地 spark 应用程序的 SBT 配置,并像这样显式调用 run-main:"run-main MySparkDriverMainClass"
@DavidPortabella 你能澄清一下你做了什么让它工作吗?我正在努力解决同样的问题。
对我来说在 IntelliJ Ultimate 2016.2 中工作得很好......把它放在我的 build.sbt
的底部并使用和 SBT 任务运行配置来执行 run
。
避免使用 <<=
的解决方案现在在 sbt 中已被弃用是 fullClasspath in Runtime := (fullClasspath in Compile).value
对我有用的配置是 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
(在 SBT 版本 0.13.13 中)【参考方案2】:
添加到@douglaz 的答案,
runMain in Compile <<= Defaults.runMainTask(fullClasspath in Compile, runner in (Compile, run))
是 runMain 任务的相应修复。
【讨论】:
有谁知道sbt-start-script 的对应行是怎样的? 知道为什么 IntelliJ 不尊重这一点吗? 实际上,当您在使用本页答案中的解决方案后重新加载项目时,IntelliJ 会自动勾选运行/调试配置对话框中的include dependencies with "Provided" scope
框。至少在 IntelliJ 的 2019.2 版本中。这是非常好的!【参考方案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
)
【讨论】:
【参考方案4】:如果您使用sbt-revolver
插件,这里是其“重新启动”任务的解决方案:
fullClasspath in Revolver.reStart <<= fullClasspath in Compile
UPD:对于 sbt-1.0,您可以使用新的分配表:
fullClasspath in Revolver.reStart := (fullClasspath in Compile).value
【讨论】:
当我尝试这个时,我得到了[error] /Users/irashid/github/pub/spark_streaming_demo/project/Build.scala:69: value fullClasspath is not a member of sbt.Def.Initialize[sbt.InputTask[Unit]] [error] possible cause: maybe a semicolon is missing before `value fullClasspath'? [error] fullClasspath in reStart <<= fullClasspath in Compile [error] ^ [error] one error found [error] (compile:compile) Compilation failed
。有什么建议?我可能遗漏了一些基本的东西,但尝试reStart.fullClasspath
、reStart::fullClasspath
或Revolver.reStart::fullClasspath
都会出现一些错误
我现在已经试过了,它对我有用。但我使用*.sbt
文件,而不是已弃用的Build.sbt。身份证。也许缺少一些导入?以上是关于如何将“提供的”依赖项添加回运行/测试任务的类路径?的主要内容,如果未能解决你的问题,请参考以下文章
如何将 pom 中的依赖项加载到 eclipse 项目的类路径中?
具有依赖项的 Maven2 + JMeter + JUnit