Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Execute an SBT command from a script

*decided to start a bounty & edited out information not needed

I would like to run a script inside the SBT console that would run an SBT command at the end. How can this be done

I wrote a script that allows me to execute shell commands. Typing in sbt then path/to/my-script start gives me this error: /bin/sh: start command not found

But path/to/my-script sbt start works fine

Reason why sbt plugins (such as these) or a custom task won't work in this case:

  • The script is not written in scala

quick edit

*I would prefer to execute start from a script instead of using custom task/command to run my script

More info below


I'll explain step by step what I'd like to do (what I'm doing may sound silly to you but please read my response to Etan):

  1. Type sbt in my console which will invoke the SBT console

  2. Instead of typing start, I'd like to run a script which will perform something else that doesn't directly have anything to do with the project and then invoke start for me when it's done.

Being not too familiar with scripting, script can invoke #!/bin/sh commands, so I guess what I'm trying to do is invoke a #!/bin/sh/<*this-sbt-console*> command if that's possible

Even a workaround like if I can get the script to just print start on the terminal and invoke the enter/return key after it's done, would suffice

other info:

  • Not using any specific framework
  • SBT Version = 0.13+
like image 706
goo Avatar asked Jul 04 '14 01:07

goo


People also ask

How run sbt project from command line?

sbt shell has a command prompt (with tab completion and history!). To compile again, press up arrow and then enter. To run your program, type run . To leave sbt shell, type exit or use Ctrl+D (Unix) or Ctrl+Z (Windows).


2 Answers

In order to be able to execute a script and, after that script completes, proceed to execute another sbt command, one approach is to implement a custom sbt command which does the following:

  1. Executes an external process supplied as its first argument, passing any additional arguments to this process.
  2. Waits for the external process to finish.
  3. After the external process finishes, executes another sbt command.

This is demonstrated in this Build.scala file:

import sbt._
import Keys._

// imports standard command parsing functionality
import complete.DefaultParsers._

object CommandExample extends Build {
  // Declare a project, adding new commands.
  lazy override val projects = Seq(root)
  lazy val root = Project("root", file(".")) settings(
    commands ++= Seq(start, customStart)
  )

  // A fake "start" command.
  def start = Command.command("start") { state =>
    println("Fake start command executed.")
    state
  }

  // A command that executes an external command before executing the "start" command. 
  // The name of the external command is the first parameter.
  // Any additional parameters are passed along to the external command.
  def customStart = Command.args("customStart", "<name>") { (state, args) =>
    if (args.length > 0) {
      val externalCommand = args.mkString(" ")
      println(s"Executing '$externalCommand'")
      externalCommand !
    }
    "start" :: state
  }
}

This is a sample execution:

$ sbt
[info] Loading project definition from /home/fernando/work/github/fernandoacorreia/so24565469/project
[info] Set current project to hello (in build file:/home/fernando/work/github/fernandoacorreia/so24565469/)
> customStart ls -la
Executing 'ls -la'
total 40
drwxr-xr-x  6 fernando fernando 4096 Jul  8 10:52 .
drwxr-xr-x 27 fernando fernando 4096 Jul  8 08:51 ..
-rw-r--r--  1 fernando fernando   95 Jul  8 10:47 build.sbt
drwxr-xr-x  8 fernando fernando 4096 Jul  8 08:58 .git
-rw-r--r--  1 fernando fernando  203 Jul  8 09:04 .gitignore
-rw-r--r--  1 fernando fernando 1082 Jul  8 08:51 LICENSE
drwxr-xr-x  3 fernando fernando 4096 Jul  8 10:51 project
-rw-r--r--  1 fernando fernando  111 Jul  8 08:51 README.md
drwxr-xr-x  3 fernando fernando 4096 Jul  8 08:57 src
drwxr-xr-x  2 fernando fernando 4096 Jul  8 10:52 target
Fake start command executed.
> 

The external command passed as a parameter to customStart may be any executable command, e.g. a binary file or a shell script.

To learn more about creating commands, refer to the Commands documentation page.

To learn more about executing external processes, refer to the External Processes documentation page.

The complete example is available for download at this GitHub repository.

Since sbt executes the script (as a child process), that script can't execute commands on the original (parent) sbt process.

It would be possible to capture the script's output, either to stdout or to a file, and have the sbt command execute an arbitrary command generated by the script, but that's somewhat convoluted.

Another approach would be to invert the order of execution. Instead of having sbt execut the script, the script would be executed first, directly from the shell, and the script would execute the sbt command.

For instance, this script:

#!/bin/bash
echo "Running custom script"
# Insert commands here
sbt start

Produces this output:

$ ./script 
Running custom script
[info] Loading project definition from /home/fernando/work/github/fernandoacorreia/so24565469/project
[info] Set current project to hello (in build file:/home/fernando/work/github/fernandoacorreia/so24565469/)
Fake start command executed.
like image 179
Fernando Correia Avatar answered Oct 06 '22 17:10

Fernando Correia


As you say "Is there a way to just tell a script to write something onto the terminal and press return/enter?"

yes - the slightly hacky but highly effective solution is a little program called expect.

http://www.thegeekstuff.com/2010/10/expect-examples/

http://www.admin-magazine.com/Articles/Automating-with-Expect-Scripts

It will let you do anything you can do from the keyboard, but automatically. It's like a macro playback engine for the UNIX command prompt.

like image 26
JCx Avatar answered Oct 06 '22 17:10

JCx