使用SBT创建带有类路径的脚本

10

我希望SBT可以创建一个文件,并将项目的运行时完整类路径(Scala、管理和非管理库、项目类)写入该文件,用于特定阶段(在这种情况下,仅针对compile)。

我正在尝试使用maven-antrun-plugin复制我之前使用Maven完成的某些操作:

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-antrun-plugin</artifactId>
      <version>1.6</version>
      <executions>
        <execution>
          <id>generate-runner</id>
          <phase>package</phase>
          <configuration>
            <target>
              <property name="runtime_classpath" refid="maven.runtime.classpath" />
              <property name="runtime_entrypoint" value="com.biasedbit.webserver.Bootstrap" />

              <echo file="../../bin/run-server.sh" append="false">#!/bin/sh
java -classpath ${runtime_classpath} ${runtime_entrypoint} $$*
              </echo>
            </target>
          </configuration>
          <goals>
            <goal>run</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

我该如何使用SBT实现这个?

3个回答

11

David的答案基本正确。但有一些小细节可以改进。由于Scala库已经包含在类路径中,因此可以直接使用Java启动器。如果只定义了一个主类,则sbt可以自动检测该类。sbt还具有一些可使文件处理更轻松的方法,例如在sbt.IO中的实用程序方法。

TaskKey[File]("mkrun") <<= (baseDirectory, fullClasspath in Runtime, mainClass in Runtime) map { (base, cp, main) =>
  val template = """#!/bin/sh
java -classpath "%s" %s "$@"
"""
  val mainStr = main getOrElse error("No main class specified")
  val contents = template.format(cp.files.absString, mainStr)
  val out = base / "../../bin/run-server.sh"
  IO.write(out, contents)
  out.setExecutable(true)
  out
}

这可以直接放在您的build.sbt中。 或者,将该键定义为单独的变量并将其放置在project/Build.scala中:

import sbt._
import Keys._

object MyBuild extends Build {
  val mkrun = TaskKey[File]("mkrun")
  lazy val proj = Project("demo", file(".")) settings(
    mkrun <<= ... same argument as above ...
  )
}

3

您可以创建一个任务来创建一个文件,以启动应用程序。@Kipton Barros在如何将sbt主类作为普通命令行程序从shell运行?中发布了这个问题:

  val MkUnixlauncher = config("mkunixlauncher") extend(Compile)
  val mkunixlauncher = TaskKey[Unit]("mkunixlauncher")
  val mkunixlauncherTask = mkunixlauncher <<= (target, fullClasspath in Runtime) map { (target, cp) =>
    def writeFile(file: File, str: String) {
      val writer = new PrintWriter(file)
      writer.println(str)
      writer.close()
    }
    val cpString = cp.map(_.data).mkString(System.getProperty("path.separator"))
    val runtime_entrypoint = "com.biasedbit.webserver.Bootstrap"
    val launchString = """
CLASSPATH="%s"
scala -usejavacp -Djava.class.path="${CLASSPATH}" %s "$@"
""".format(cpString, entrypoint)
    val targetFile = (target / "run-server.sh").asFile
    writeFile(targetFile, launchString)
    targetFile.setExecutable(true)
  }

这将在目标目录中创建一个名为run-server.sh的文件,其中类路径已正确设置以运行应用程序。 在Build.scala(或build.sbt)中的buildsettings中添加mkunixlauncherTask,然后您就可以使用“mkunixlauncher”命令创建脚本。
根据需要进行微调。

2

刚刚发现了sbt启动脚本插件:https://github.com/typesafehub/xsbt-start-script-plugin

该插件允许您为项目生成一个脚本目标/start。该脚本将在“就地”运行项目(无需首先构建包)。

目标/start脚本类似于sbt run,但它不依赖于SBT。不建议在生产中使用sbt run,因为它会将SBT本身保留在内存中。目标/start旨在在生产环境中运行应用程序。

该插件添加了一个start-script任务,用于生成target/start。它还添加了一个stage任务,别名为start-script任务。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接