2014-01-29 31 views
3

我们需要在编译步骤后运行一些代码。使事情发生编译步骤后似乎很简单:编译后的项目中SBT运行代码

compile in Compile <<= (compile in Compile) map{x=> 
    // post-compile work 
    doFoo() 
    x 
} 

但你怎么跑在新编译的代码的东西吗?

有关该场景的更多信息:我们在电梯项目中使用较少的css。我们希望在编译期间,在测试等运行之前,使用相同的代码,在运行中尽可能少地编译成css(如果需要的话)以帮助开发人员,但生成更少。少一点可能会有所帮助,但我们一般感兴趣的是如何解决这个问题。

+0

改变内置任务覆盖在http://stackoverflow.com/questions/7820939/ –

+0

也,只是注意到这是非常类似于http://stackoverflow.com/questions/17045860/sbt-apply-task -after-compile –

+0

是的,我看到了这些问题,但它们没有回答我编译后执行代码的问题。 –

回答

3

可以使用triggeredBy方法是这样的:

yourTask <<= (fullClasspath in Runtime) map {classpath => 
    val loader: ClassLoader = ClasspathUtilities.toLoader(classpath.map(_.data).map(_.getAbsoluteFile)) 
    loader.loadClass("your.class.Here").newInstance() 
} triggeredBy(compile in Compile) 

这将实例化您的类,它刚刚被编译,使用你的应用程序运行时类路径,任何编译后。

+1

太棒了!我不知道'triggeredBy'。 –

2

如果您为此解释了您的使用场景,这可能会有所帮助,因为这里有一些不同的可能解决方案路径,如果在它们之间进行选择可能会涉及您尚未告诉我们的考虑因素。

您将无法只将普通方法调用写入编译代码。这是不可能的,因为在构建定义的时候,sbt还没有查看你的项目代码。

警告:漫不经心地想出来。

我可以建议的一个技巧是访问testLoader in Test以获得一个类加载器,在该类加载器中加载已编译的类,然后使用反射在那里调用方法。例如,在我自己的构建,我有:

val netlogoVersion = taskKey[String]("...") 

netlogoVersion := { 
    (testLoader in Test).value 
    .loadClass("org.nlogo.api.Version") 
    .getMethod("version") 
    .invoke(null).asInstanceOf[String] 
} 

我不知道是否访问testLoader in Test会在你的情况下,实际的工作,因为testLoader负载测试类以及你的普通班,所以你可能会得到一个圆compile in Compilecompile in Test之间的依赖关系。

如果你想尝试制作一个只有正常类加载的类加载器,那么,嗯。您可以在执行createTestLoader时查看sbt源代码并将其用于获取灵感,修改传递给ClasspathUtilities.makeLoader的参数。 (您也可以看看Run.run0类似的代码。它调用makeLoaderrun任务的实现的一部分。)

你可能会考虑不同的路径是重用run任务背后的机械运行代码。您将无法通过这种方式在编译代码中调用任意方法,只能使用main方法,但如果不需要返回值,也许您可​​以忍受。

fullRunTask方法存在用于创建整个run类似的任务。请参阅“除运行之外,如何创建自定义运行任务?”从http://www.scala-sbt.org/0.13.1/docs/faq.htmlfullRunTask可以很容易地创建一个单独的任务,它在编译的代码中运行某些东西,但是它本身并不会让您一路解决问题,因为您需要将该任务附加到现有的compile in Compile任务中。如果你走这条路,我建议你把最后一条作为一个单独的问题。

考虑绕过fullRunTask并将您自己的电话组装到Run.run。他们使用相同的机器。在我自己的身材,我目前使用fullRunTask,但被SBT加回以前fullRunTask,这里是什么样子我相当于Run.run基于代码:

(..., fullClasspath in Compile, runner, streams, ...) map { 
     (..., cp, runner, s, ...) => 
     Run.run("name.of.my.MainClass", 
       cp.map(_.data), Seq(), s.log)(runner) 
    } 

赦免SBT 0.12,前期宏观语法;如果用0.13宏重做,这看起来会更好。

无论如何,希望这个大脑转储证明有用。

+0

另请参阅雷蒙德的答案 –

+0

谢谢Seth在那里有很多东西,我需要消化。 –