Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Run a SBT task with arguments from command line

I want to hava a SBT task which takes comma-separated list of test classes given by their fully qualified name as input from command line. Now that I run the task with hard-coded value but I want to get it from command line. Can someone help me in writing a task like this.

 lazy val runTask = inputKey[Unit]("custom run")

 runTask := {
    val one = (runMain in Compile).fullInput(" org.scalatest.tools.Runner -P1 -C reporter.TestReporter -o -s testcase.GetAccountInfo -s testcase.GetProfileInfo").evaluated
 }

Something like this,

 sbt runTask testcase.GetProfileInfo,testcase.GetAccountInfo

Thanks in advance.

like image 678
Sarath Avatar asked May 30 '14 10:05

Sarath


People also ask

How do I pass a command line argument in Scala?

you can access your Scala command-line arguments using the args array, which is made available to you implicitly when you extend App . As an example, your code will look like this: object Foo extends App { if (args. length == 0) { println("dude, i need at least one parameter") } val filename = args(0) ... }


1 Answers

You have to have a Parser, which will parse the input given to the task. Once you have the input, you can convert (runMain in Compile).toTask, and feed the input to the task.

TL;DR; build.sbt

import sbt.complete._

import complete.DefaultParsers._

lazy val myRunTask = inputKey[Unit]("Runs actual tests")

lazy val FullQualifiedClassName = 
  (charClass(c => isScalaIDChar(c) || (c == '.'), "class name")).+.string

def commaDelimited(display: String) =
  token(Space) ~> repsep(token(FullQualifiedClassName, display), token(","))

lazy val testClassArgs: Parser[Seq[String]] = 
  commaDelimited("<full qualified test class name>").map { 
    xs: Seq[String] => xs.map(e => s" -s $e ")
  }

myRunTask := Def.inputTaskDyn {
  val classes = testClassArgs.parsed
  runMainInCompile(classes)
}.evaluated

def runMainInCompile(classes: Seq[String]) = Def.taskDyn {
  (runMain in Compile).toTask(s" org.scalatest.tools.Runner -P1 -C reporter.TestReporter -o ${classes.mkString}")
}

Parser

Let's start with a parser. The parser must take a space, followed by your classes separated by comma.

Let's first defined a parser, which parses full qualified class name:

lazy val FullQualifiedClassName = 
      (charClass(c => isScalaIDChar(c) || (c == '.'), "class name")).+.string

Once we have the parser, we can combine it together with another parser. We need to create a parser, which takes comma separated full qualified class names:

def commaDelimited(display: String) = 
      token(Space) ~> repsep(token(FullQualifiedClassName, display), token(","))

The ~> operator means that the input on the left of it will be discarded. The value returned from the parser is a Seq[String] of the full qualified class names.

Judging from your question, you want your classes to be prefixed with -s. You could do it later, but just to show one more feature of parsers, I'll just do it here.

You can take an output of a parser and convert it to another output, using map.

lazy val testClassArgs: Parser[Seq[String]] = 
  commaDelimited("<full qualified test class name>").map { 
    xs: Seq[String] => xs.map(e => s" -s $e ")
  }

OK, we're almost there.

Run InputTask with arguments combined with a static string

We can define a new input task key. I'll chose myRunTask, because otherwise it will collide with runTask, which already exists.

Let's define a method which takes a sequence of classes (already prefixed with -s) as an argument, and which returns a Task obtained from an InputTask.

def runMainInCompile(classes: Seq[String]) = Def.taskDyn {
  (runMain in Compile).toTask(s" org.scalatest.tools.Runner -P1 -C reporter.TestReporter -o ${classes.mkString}")
} 

Now let's combine all elements in one task:

myRunTask := Def.inputTaskDyn {
  val classes = testClassArgs.parsed
  runMainInCompile(classes)
}.evaluated
like image 68
lpiepiora Avatar answered Oct 02 '22 15:10

lpiepiora