Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 定义从项目代码调用方法的sbt任务?_Scala_Sbt - Fatal编程技术网

Scala 定义从项目代码调用方法的sbt任务?

Scala 定义从项目代码调用方法的sbt任务?,scala,sbt,Scala,Sbt,我正在使用SBT构建一个scala项目。我想定义一个非常简单的任务,当我在sbt中输入generate时: sbt> generate 它将调用我的my.App.main(…)方法来生成一些东西 在myproject/src/main/scala/my中有一个App.scala文件,简化代码如下: object App { def main(args: Array[String]) { val source = readContentOfFile("mysource.

我正在使用SBT构建一个scala项目。我想定义一个非常简单的任务,当我在sbt中输入
generate
时:

sbt> generate
它将调用我的
my.App.main(…)
方法来生成一些东西

myproject/src/main/scala/my
中有一个
App.scala
文件,简化代码如下:

object App {
   def main(args: Array[String]) {
       val source = readContentOfFile("mysource.txt")
       val result = convert(source)
       writeToFile(result, "mytarget.txt");
   }
   // ignore some methods here
}
我试图将以下代码添加到
myproject/build.sbt

lazy val generate = taskKey[Unit]("Generate my file")

generate := {
  my.App.main(Array())
}
但是它没有编译,因为它找不到
my.App

然后我尝试将它添加到
myproject/project/build.scala

import sbt._
import my._

object HelloBuild extends Build {

  lazy val generate = taskKey[Unit]("Generate my file")

  generate := {
    App.main(Array())
  }

}
但它仍然无法编译,无法找到包
my


如何在SBT中定义这样的任务?

@SethTisue提出的解决方案将起作用。另一种方法是将其作为其他项目可以使用的单独项目。为此,您需要将
应用程序
对象放入一个单独的项目中,并将其作为依赖项包含在
项目/项目
中,或者将其打包为sbt插件(理想情况下包括此任务定义)


有关如何创建打包为插件的库的示例,请参阅。
gen
目录包含执行某些代码生成的代码(类似于您的
应用程序
代码),而
sbt
目录包含
gen
的sbt插件包装器。sbt格式,请执行以下操作:

lazy val generate = taskKey[Unit]("Generate my file")

fullRunTask(generate, Compile, "my.App")
这在“除了运行任务外,如何创建自定义运行任务”中有说明

另一种办法是:

lazy val generate = taskKey[Unit]("Generate my file")

generate := (runMain in Compile).toTask(" my.App").value
它在简单的情况下可以正常工作,但不能定制


更新:Jacek建议改用
resourceGenerators
sourceGenerators
是好的,如果它适合您的用例-无法从您的描述中判断它是否适合。

其他答案非常适合这个问题,但我认为OP也可能从我的回答中受益:)

OP询问“我想定义一个非常简单的任务,当我在sbt中输入
generate
时,将调用我的
my.App.main(…)
方法来生成一些东西。”这可能最终会使构建复杂化

Sbt已经提供了一种在构建时生成文件的方法——
sourceGenerators
resourceGenerators
——在阅读了这个问题之后,我似乎没有注意到需要为此定义一个单独的任务

在(请参阅)中,您可以阅读:

sbt提供用于添加源或资源生成的标准挂钩 任务

有了这些知识,人们可以想到以下解决方案:

sourceGenerators in Compile += Def.task {
  my.App.main(Array()) // it's not going to work without one change, though
  Seq[File]()          // a workaround before the above change is in effect
}.taskValue
要使其工作,您应该返回一个包含生成的文件的
Seq[File]
(而不是空的
Seq[File]()

代码工作的主要变化是将
my.App
类移动到
project
文件夹。然后,它将成为构建定义的一部分。它还反映了类的功能,因为它实际上是构建的一部分,而不是它的产品。当相同的代码是构建和工件本身的一部分时,您不会将不同的关注点分开。如果
my.App
类参与了一个构建,那么它应该属于它-因此移动到
project
文件夹

该项目的布局如下所示:

$ tree
.
├── build.sbt
└── project
    ├── App.scala
    └── build.properties
jacek:~/sandbox/so/generate-project-code/project-code
$ tree
.
├── build.sbt
└── project
    ├── build.properties
    └── build.sbt
关注点分离(又名da haus中的joescii) @joescii的回答中有一点(我在回答中对此进行了扩展)-“要使它成为其他项目可以使用的单独项目。为此,您需要将您的
应用程序
对象放入单独的项目中,并将其作为依赖项包含在
项目/project
”中,即

假设您在
src/main/scala
下有一个单独的项目
buildutils
App.scala
。这是一个常规的sbt配置,只有Scala代码

jacek:~/sandbox/so/generate-project-code
$ tree build-utils/
build-utils/
└── src
    └── main
        └── scala
            └── App.scala
您可以将其作为常规Scala应用程序进行测试,而不会弄乱sbt。不需要额外的设置(并将您的思想从有时可能有益的sbt中解放出来-较少的设置总是有帮助的)

在另一个项目中-
project code
,它使用了
App.scala
,而这应该是构建的基础,build.sbt如下所示:

$ tree
.
├── build.sbt
└── project
    ├── App.scala
    └── build.properties
jacek:~/sandbox/so/generate-project-code/project-code
$ tree
.
├── build.sbt
└── project
    ├── build.properties
    └── build.sbt
项目代码/build.sbt

lazy val generate = taskKey[Unit]("Generate my file")

generate := {
  my.App.main(Array())
}
lazy val buildUtils = RootProject(
  uri("file:/Users/jacek/sandbox/so/generate-project-code/build-utils")
)

lazy val plugins = project in file(".") dependsOn buildUtils
现在最重要的部分是项目之间的连接,因此
App
代码对于
项目代码的构建可见:

项目代码/项目/构建.sbt

lazy val generate = taskKey[Unit]("Generate my file")

generate := {
  my.App.main(Array())
}
lazy val buildUtils = RootProject(
  uri("file:/Users/jacek/sandbox/so/generate-project-code/build-utils")
)

lazy val plugins = project in file(".") dependsOn buildUtils
使用生成定义,执行
generate
可获得以下信息:

jacek:~/sandbox/so/generate-project-code/project-code
$ sbt
[info] Loading global plugins from /Users/jacek/.sbt/0.13/plugins
[info] Loading project definition from /Users/jacek/sandbox/so/generate-project-code/project-code/project
[info] Updating {file:/Users/jacek/sandbox/so/generate-project-code/build-utils/}build-utils...
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[info] Done updating.
[info] Updating {file:/Users/jacek/sandbox/so/generate-project-code/project-code/project/}plugins...
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[info] Done updating.
[info] Compiling 1 Scala source to /Users/jacek/sandbox/so/generate-project-code/build-utils/target/scala-2.10/classes...
[info] Set current project to project-code (in build file:/Users/jacek/sandbox/so/generate-project-code/project-code/)
> generate
Hello from App.main
[success] Total time: 0 s, completed May 2, 2014 2:54:29 PM
我已将
App
的代码更改为:

> eval "cat ../build-utils/src/main/scala/App.scala"!
package my

object App {
  def main(args: Array[String]) {
    println("Hello from App.main")
  }
}
项目结构如下:

$ tree
.
├── build.sbt
└── project
    ├── App.scala
    └── build.properties
jacek:~/sandbox/so/generate-project-code/project-code
$ tree
.
├── build.sbt
└── project
    ├── build.properties
    └── build.sbt
其他的变化也叫好事 我还建议对源代码生成器的代码进行一些其他更改:

  • 将代码从
    main
    方法移到一个单独的方法,该方法返回生成的文件,并让
    main
    调用它。这将使重用
    sourceGenerators
    中的代码变得更容易(无需调用不必要的
    Array()
    ,也无需显式返回文件)
  • 使用
    filter
    map
    函数进行
    convert
    (添加更具功能性的风格)

感谢您提供此解决方案,如果我想为SBT创建一些UTIL,它将非常有用。对于这个问题,我不能选择它,因为我必须将我的
App.scala
保存在
src
目录中,以便其他人在不了解sbtHi的情况下查看标准scala项目!您的解决方案将如何在多模块项目中工作?子模块不能有自己的project/build.sbtIn
.scala
格式,您可以将
lazy val
部分放在任何地方,
generate:=…
部分是一个普通设置,您可以将它放在
.scala
文件的同一部分中,该部分包含您的其余设置。为什么在我的前面有一个空格。。。它应该是
“my.App”
而不是