在开放源代码之前,我想为我的项目创建一个sbt插件。
该项目将Java代理附加到运行应用程序的开始,以便对其进行各种类型的分析。代理输出文本文件以供以后处理。
我希望能够编写一个sbt插件
run
的替代方法,称为runWithProfiling
,它启动一个新的java进程,将代理添加到参数列表中,并传递所有用户命令。我大致知道如何创建新命令,但我不知道如何最好地实现run
的替代方案。我不想通过复制run
所做的所有代码来重新发明轮子。有什么方法可以调用run
,但确保参数被传递(一次),并且它肯定是一个新的java进程?
而且,能够为测试做同样的事情也是很棒的。
UPDATE:这是我目前拥有的代码,但它遇到了一些问题,标记为TODO
的
import sbt._
import Keys._
import sbt.Attributed.data
object LionPlugin extends Plugin {
val lion = TaskKey[Unit]("lion", "Run a main class with lions-share profiling.")
override val projectSettings = Seq(
fork := true,
javaOptions ++= Seq(
"-Xloggc:gc.log", "-XX:+PrintGCDetails", "-XX:+PrintGCDateStamps",
"-XX:+PrintTenuringDistribution", "-XX:+PrintHeapAtGC"
// TODO: need to get hold of the local jar file for a particular artifact
// IMPL: pass the jar as the agent
),
lion <<= (
runner,
fullClasspath in Runtime,
mainClass in Runtime,
streams in Runtime
) map runLion
)
// TODO: update to a task that can take parameters (e.g. number of repeats, profiling settings)
def runLion(runner: ScalaRun, cp: Classpath, main: Option[String], streams: TaskStreams): Unit = {
assert(runner.isInstanceOf[ForkRun], "didn't get a forked runner... SBT is b0rk3d")
println("RUNNING with " + runner.getClass)
// TODO: ask user if main is None, like 'run' does
val m = main.getOrElse("Scratch")
// TODO: get the user's arguments
val args = Nil
runner.run(m, data(cp), args, streams.log)
// IMPL: post-process and produce the report
println("FINISHED")
}
}
发布于 2014-04-13 12:01:09
插件作者需要遵守一条不成文的希波克拉底誓言,即“第一,不要伤害”。您的实现目前强制自己执行每个子项目,并更改默认行为的fork
和javaOptions
,我认为这是危险的。我认为您需要将作用域范围内的run
参数复制到您的任务中,这样默认设置就不会受到损害。
// TODO:更新到可以接受参数的任务(例如重复次数、分析设置)
有关示例,请参阅插件最佳实践和现有插件(如sbt-应用程序引擎 )。
在sbt中,devServer
是一个输入任务,可以设置一组参数.
gae.devServer := {
val args = startArgsParser.parsed
val x = (products in Compile).value
AppEngine.restartDevServer(streams.value, (gae.reLogTag in gae.devServer).value,
thisProjectRef.value, (gae.reForkOptions in gae.devServer).value,
(mainClass in gae.devServer).value, (fullClasspath in gae.devServer).value,
(gae.reStartArgs in gae.devServer).value, args,
packageWar.value,
(gae.onStartHooks in gae.devServer).value, (gae.onStopHooks in gae.devServer).value)
}
正如您所看到的,代码的本质实际上是在AppEngine
对象下的一个方法中实现的,因此其他人可以重用您的东西。方法中的许多参数(在本例中为restartDevServer
)的作用域是gae.devServer
任务,如(mainClass in gae.devServer)
。
您打算如何由构建用户设置插件?他们是将其作为一个全局插件启用一次,并在任何地方使用相同的设置,还是为project/lion.sbt
中的每个构建启用它?插件最佳实践的建议是提供baseLionSettings
和lionSettings
,以便构建用户可以选择并选择启用lion
任务的哪个子项目。
根据实际运行情况,您可能想看看如何重用来自sbt左轮手枪的代码,类似于我在sbt中所做的工作。
发布于 2014-04-12 07:27:30
请参阅http://www.scala-sbt.org/0.13.0/docs/faq.html上的“如何创建自定义运行任务,以及运行?”。在您的自定义任务中,您需要将fork
设置为true,以便启动一个新的JVM。
https://stackoverflow.com/questions/23029910
复制相似问题