34

I want to automatically build documentation for my Java Play 2.3 application. At the moment, I use a Makefile to generate images from *.dotfiles and combine Markdown sources together into Html/PDF:

dot diagram1.dot -Tpdf -o diagram1.pdf
dot diagram2.dot -Tpdf -o diagram2.pdf
pandoc doc1.markdown -o doc1.pdf
# ...

Now I want to run these simple bash commands directly from SBT. What's the best way to do this?

I found some SBT Documentation plugins in the SBT reference, but nothing to run a simple shell script.

Jacek Laskowski
  • 72,696
  • 27
  • 242
  • 420
Sonson123
  • 10,879
  • 12
  • 54
  • 72

2 Answers2

72

You can find some answers in External Processes in the official documentation of sbt, e.g.

To run an external command, follow it with an exclamation mark !:

 "find project -name *.jar" !

Don't forget to use import scala.sys.process._ so ! can be resolved as a method of String.

Do the following in activator console (aka sbt shell) to execute yourshell.sh - mind the eval command and the quotes around the name of the script:

eval "yourshell.sh" !

To have it available as a task add the following to build.sbt of your project:

lazy val execScript = taskKey[Unit]("Execute the shell script")

execScript := {
  "yourshell.sh" !
}
Jacek Laskowski
  • 72,696
  • 27
  • 242
  • 420
  • I'm trying to run the following command which contains double quotes and it fails to execute. It just prints whatever is within the double quotes. `"mongo test -eval \"db.dropDatabase()\"" !` This is an issue for every command containing quotes. – WarLord Jun 15 '16 at 11:01
  • 1
    Can you use triple quotes instead? – Jacek Laskowski Jun 15 '16 at 18:03
  • 1
    Is it possible to honour the response code of the script as well as log the complete output – johnflan Jan 05 '18 at 16:36
37

We had the requirement to execute some npm scripts as sbt task and let the build fail if one of the npm scripts fails. Took me some time to find a way to create a Task that works on Windows and Unix. And so here is what I came up with.

lazy val buildFrontend = taskKey[Unit]("Execute frontend scripts")

buildFrontend := {
      val s: TaskStreams = streams.value
      val shell: Seq[String] = if (sys.props("os.name").contains("Windows")) Seq("cmd", "/c") else Seq("bash", "-c")
      val npmInstall: Seq[String] = shell :+ "npm install"
      val npmTest: Seq[String] = shell :+    "npm run test"
      val npmLint: Seq[String] = shell :+    "npm run lint"
      val npmBuild: Seq[String] = shell :+   "npm run build"
      s.log.info("building frontend...")
      if((npmInstall #&& npmTest #&& npmLint #&& npmBuild !) == 0) {
        s.log.success("frontend build successful!")
      } else {
        throw new IllegalStateException("frontend build failed!")
      }
},
(run in Compile) <<= (run in Compile).dependsOn(buildFrontend)
Steffen
  • 3,327
  • 2
  • 26
  • 30