Introduces scala.tools.cmd providing command line tool
infrastructure. For a quick look at what can be done, see scala.tools.cmd.Demo For a more involved, potentially eye-straining look, see scala.tools.partest.PartestSpec To experience it through the eyes of Joe Partest User, run test/partest Review by community. git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@21438 5e8d7ff9-d8ef-0310-90f0-a4852d11357a
This commit is contained in:
parent
d7cbfa47b5
commit
7db525a076
|
@ -0,0 +1,107 @@
|
|||
/* NEST (New Scala Test)
|
||||
* Copyright 2007-2010 LAMP/EPFL
|
||||
* @author Paul Phillips
|
||||
*/
|
||||
|
||||
package scala.tools
|
||||
package cmd
|
||||
|
||||
import scala.collection.mutable.ListBuffer
|
||||
|
||||
/** An instance of a command line, parsed according to a Spec.
|
||||
*/
|
||||
class CommandLine(val spec: Reference, val originalArgs: List[String]) {
|
||||
def this(spec: Reference, line: String) = this(spec, Parser tokenize line)
|
||||
def this(spec: Reference, args: Array[String]) = this(spec, args.toList)
|
||||
|
||||
import spec.{ isAnyOption, isUnaryOption, isBinaryOption, isExpandOption }
|
||||
|
||||
def assumeBinary = true
|
||||
def enforceArity = true
|
||||
def onlyKnownOptions = false
|
||||
|
||||
val Terminator = "--"
|
||||
val ValueForUnaryOption = "true" // so if --opt is given, x(--opt) = true
|
||||
|
||||
def mapForUnary(opt: String) = Map(opt -> ValueForUnaryOption)
|
||||
def errorFn(msg: String) = println(msg)
|
||||
|
||||
/** argMap is option -> argument (or "" if it is a unary argument)
|
||||
* residualArgs are what is left after removing the options and their args.
|
||||
*/
|
||||
lazy val (argMap, residualArgs) = {
|
||||
val residualBuffer = new ListBuffer[String]
|
||||
|
||||
def isOption(s: String) = isAnyOption(s) || ((s startsWith "-") && !onlyKnownOptions)
|
||||
|
||||
def unknownOption(opt: String) =
|
||||
errorFn("Option '%s' not recognized.".format(opt))
|
||||
def missingArg(opt: String, what: String) =
|
||||
errorFn("Option '%s' requires argument, found %s instead.".format(opt, what))
|
||||
|
||||
def loop(args: List[String]): Map[String, String] = {
|
||||
def residual(xs: List[String]) = { residualBuffer ++= xs ; Map[String, String]() }
|
||||
|
||||
/** Returns Some(List(args)) if this option expands to an
|
||||
* argument list and it's not returning only the same arg.
|
||||
*/
|
||||
def expand(s1: String) = {
|
||||
if (isExpandOption(s1)) {
|
||||
val s2 = spec expandArg s1
|
||||
if (s2 == List(s1)) None
|
||||
else Some(s2)
|
||||
}
|
||||
else None
|
||||
}
|
||||
|
||||
args match {
|
||||
case Nil => Map()
|
||||
case Terminator :: xs => residual(xs)
|
||||
case x :: Nil =>
|
||||
expand(x) foreach (exp => return loop(exp))
|
||||
if (isBinaryOption(x) && enforceArity)
|
||||
missingArg(x, "EOF")
|
||||
|
||||
if (isUnaryOption(x)) mapForUnary(x)
|
||||
else residual(args)
|
||||
case x1 :: x2 :: xs =>
|
||||
expand(x1) foreach (exp => return loop(exp ++ args.tail))
|
||||
|
||||
if (x2 == Terminator) mapForUnary(x1) ++ residual(xs)
|
||||
else if (isUnaryOption(x1)) mapForUnary(x1) ++ loop(args.tail)
|
||||
else if (isBinaryOption(x1)) Map(x1 -> x2) ++ loop(xs)
|
||||
else residual(List(x1)) ++ loop(args.tail)
|
||||
}
|
||||
}
|
||||
|
||||
(loop(originalArgs), residualBuffer map stripQuotes toList)
|
||||
}
|
||||
|
||||
def apply(arg: String) = argMap(arg)
|
||||
def get(arg: String) = argMap get arg
|
||||
def isSet(arg: String) = argMap contains arg
|
||||
|
||||
def getOrElse(arg: String, orElse: => String) = if (isSet(arg)) apply(arg) else orElse
|
||||
|
||||
override def toString() = argMap.toString + " " + residualArgs.toString
|
||||
}
|
||||
|
||||
object CommandLine {
|
||||
def apply(args: List[String], unary: List[String], binary: List[String]) = {
|
||||
/** XXX Temporarily assembling a fake spec so we can continue to
|
||||
* do ad-hoc parsing based on a list of unary and binary args.
|
||||
* Should either clean this up or do it differently.
|
||||
*/
|
||||
object NoSpec extends Reference {
|
||||
unary foreach (_ --? )
|
||||
binary foreach (_ --| )
|
||||
|
||||
protected def creator(args: List[String]) = error("No Spec")
|
||||
def programInfo = Spec.Names("", "")
|
||||
lazy val referenceSpec = this
|
||||
}
|
||||
|
||||
new CommandLine(NoSpec, args)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
/* NEST (New Scala Test)
|
||||
* Copyright 2007-2010 LAMP/EPFL
|
||||
* @author Paul Phillips
|
||||
*/
|
||||
|
||||
package scala.tools
|
||||
package cmd
|
||||
|
||||
/** A sample command specification for illustrative purposes.
|
||||
* First take advantage of the meta-options:
|
||||
*
|
||||
* // this command creates an executable runner script "demo"
|
||||
* % scala scala.tools.cmd.Demo --generate-runner demo
|
||||
*
|
||||
* // this one creates and sources a completion file - note backticks
|
||||
* % `./demo --bash`
|
||||
*
|
||||
* // and now you have a runner with working completion
|
||||
* % ./demo --<tab>
|
||||
* --action --defint --int
|
||||
* --bash --defstr --str
|
||||
* --defenv --generate-runner --unary
|
||||
*
|
||||
* The normal option configuration is plausibly self-explanatory.
|
||||
*/
|
||||
trait DemoSpec extends Spec with Meta.StdOpts with Interpolation {
|
||||
lazy val referenceSpec = DemoSpec
|
||||
lazy val programInfo = Spec.Names("demo", "scala.tools.cmd.Demo")
|
||||
|
||||
help("""Usage: demo [<options>]""")
|
||||
heading("Unary options:")
|
||||
|
||||
val optIsUnary = "unary" / "a unary option" --? ;
|
||||
("action" / "a body which may be run") --> println("Hello, I am the --action body.")
|
||||
|
||||
heading("Binary options:")
|
||||
val optopt = "str" / "an optional String" --|
|
||||
val optoptInt = ("int" / "an optional Int") . --^[Int]
|
||||
val optEnv = "defenv" / "an optional String" defaultToEnv "PATH"
|
||||
val optDefault = "defstr" / "an optional String" defaultTo "default"
|
||||
val optDefaultInt = "defint" / "an optional Int" defaultTo -1
|
||||
val optExpand = "alias" / "an option which expands" expandTo ("--int", "15")
|
||||
}
|
||||
|
||||
object DemoSpec extends DemoSpec with Property {
|
||||
lazy val propMapper = new PropertyMapper(DemoSpec)
|
||||
|
||||
type ThisCommandLine = SpecCommandLine
|
||||
def creator(args: List[String]) =
|
||||
new SpecCommandLine(args) {
|
||||
override def onlyKnownOptions = true
|
||||
override def errorFn(msg: String) = { println("Error: " + msg) ; System.exit(0) }
|
||||
}
|
||||
}
|
||||
|
||||
class Demo(args: List[String]) extends {
|
||||
val parsed = DemoSpec(args: _*)
|
||||
} with DemoSpec with Instance {
|
||||
import java.lang.reflect._
|
||||
|
||||
def helpMsg = DemoSpec.helpMsg
|
||||
def demoSpecMethods = this.getClass.getMethods.toList
|
||||
private def isDemo(m: Method) = (m.getName startsWith "opt") && !(m.getName contains "$") && (m.getParameterTypes.isEmpty)
|
||||
|
||||
def demoString(ms: List[Method]) = {
|
||||
val longest = ms map (_.getName.length) max
|
||||
val formatStr = " %-" + longest + "s: %s"
|
||||
val xs = ms map (m => formatStr.format(m.getName, m.invoke(this)))
|
||||
|
||||
xs mkString ("Demo(\n ", "\n ", "\n)\n")
|
||||
}
|
||||
|
||||
override def toString = demoString(demoSpecMethods filter isDemo)
|
||||
}
|
||||
|
||||
object Demo {
|
||||
def main(args: Array[String]): Unit = {
|
||||
val runner = new Demo(args.toList)
|
||||
|
||||
if (args.isEmpty)
|
||||
println(runner.helpMsg)
|
||||
|
||||
println(runner)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/* NSC -- new Scala compiler
|
||||
* Copyright 2005-2010 LAMP/EPFL
|
||||
* @author Paul Phillips
|
||||
*/
|
||||
|
||||
package scala.tools
|
||||
package cmd
|
||||
|
||||
import nsc.io.{ Path, File, Directory }
|
||||
import reflect.OptManifest
|
||||
|
||||
/** A general mechanism for defining how a command line argument
|
||||
* (always a String) is transformed into an arbitrary type. A few
|
||||
* example instances are in the companion object, but in general
|
||||
* either IntFromString will suffice or you'll want custom transformers.
|
||||
*/
|
||||
abstract class FromString[+T](implicit m: OptManifest[T]) extends PartialFunction[String, T] {
|
||||
def apply(s: String): T
|
||||
def isDefinedAt(s: String): Boolean = true
|
||||
def zero: T = apply("")
|
||||
|
||||
def targetString: String = m.toString
|
||||
}
|
||||
|
||||
object FromString {
|
||||
// We need these because we clash with the String => Path implicits.
|
||||
private def toFile(s: String) = new File(new java.io.File(s))
|
||||
private def toDir(s: String) = new Directory(new java.io.File(s))
|
||||
|
||||
/** Path related stringifiers.
|
||||
*/
|
||||
val ExistingFile: FromString[File] = new FromString[File] {
|
||||
override def isDefinedAt(s: String) = toFile(s).isFile
|
||||
def apply(s: String): File =
|
||||
if (isDefinedAt(s)) toFile(s)
|
||||
else cmd.runAndExit(println("'%s' is not an existing file." format s))
|
||||
}
|
||||
val ExistingDir: FromString[Directory] = new FromString[Directory] {
|
||||
override def isDefinedAt(s: String) = toDir(s).isDirectory
|
||||
def apply(s: String): Directory =
|
||||
if (isDefinedAt(s)) toDir(s)
|
||||
else cmd.runAndExit(println("'%s' is not an existing directory." format s))
|
||||
}
|
||||
def ExistingDirRelativeTo(root: Directory) = new FromString[Directory] {
|
||||
private def resolve(s: String) = toDir(s) toAbsoluteWithRoot root toDirectory
|
||||
override def isDefinedAt(s: String) = resolve(s).isDirectory
|
||||
def apply(s: String): Directory =
|
||||
if (isDefinedAt(s)) resolve(s)
|
||||
else cmd.runAndExit(println("'%s' is not an existing directory." format resolve(s)))
|
||||
}
|
||||
|
||||
/** Argument expander, i.e. turns single argument "foo bar baz" into argument
|
||||
* list "foo", "bar", "baz".
|
||||
*/
|
||||
val ArgumentsFromString: FromString[List[String]] = new FromString[List[String]] {
|
||||
def apply(s: String) = toArgs(s)
|
||||
}
|
||||
|
||||
/** Identity.
|
||||
*/
|
||||
implicit val StringFromString: FromString[String] = new FromString[String] {
|
||||
def apply(s: String): String = s
|
||||
}
|
||||
|
||||
/** Implicit as the most likely to be useful as-is.
|
||||
*/
|
||||
implicit val IntFromString: FromString[Int] = new FromString[Int] {
|
||||
override def isDefinedAt(s: String) = safeToInt(s).isDefined
|
||||
def apply(s: String) = safeToInt(s).get
|
||||
def safeToInt(s: String): Option[Int] = try Some(java.lang.Integer.parseInt(s)) catch { case _: NumberFormatException => None }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/* NSC -- new Scala compiler
|
||||
* Copyright 2005-2010 LAMP/EPFL
|
||||
* @author Paul Phillips
|
||||
*/
|
||||
|
||||
package scala.tools
|
||||
package cmd
|
||||
|
||||
/** The trait mixed into each instance of a specification.
|
||||
*
|
||||
* @see Reference
|
||||
*/
|
||||
trait Instance extends Spec {
|
||||
def parsed: CommandLine
|
||||
|
||||
protected def help(str: => String): Unit = ()
|
||||
|
||||
def isSet(s: String) = parsed isSet toOpt(s)
|
||||
def originalArgs = parsed.originalArgs
|
||||
|
||||
type OptionMagic = Opt.Instance
|
||||
protected implicit def optionMagicAdditions(name: String) = new Opt.Instance(programInfo, parsed, name)
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/* NSC -- new Scala compiler
|
||||
* Copyright 2005-2010 LAMP/EPFL
|
||||
* @author Paul Phillips
|
||||
*/
|
||||
|
||||
package scala.tools
|
||||
package cmd
|
||||
|
||||
/** Interpolation logic for generated files. The idea is to be
|
||||
* able to write in terms of @@THIS@@ and @@THAT@@ and the reference
|
||||
* specification knows enough to perform the substitutions. Warrants
|
||||
* expansion.
|
||||
*/
|
||||
trait Interpolation {
|
||||
self: Spec =>
|
||||
|
||||
private lazy val reference = referenceSpec
|
||||
import reference._
|
||||
|
||||
object interpolate {
|
||||
def mapper: Map[String, () => String] = Map(
|
||||
"PROGRAM" -> (() => programInfo.runner),
|
||||
"ALLOPTIONS" -> (() => options.all mkString " "),
|
||||
"MAINCLASS" -> (() => programInfo.mainClass)
|
||||
)
|
||||
|
||||
private def mark(key: String) = "@@" + key + "@@"
|
||||
def apply(template: String) = mapper.foldLeft(template) { case (s, (key, f)) => s.replaceAll(mark(key), f()) }
|
||||
}
|
||||
}
|
||||
|
||||
object Interpolation {
|
||||
/** A simple template for generating bash completion functions.
|
||||
*/
|
||||
lazy val bashTemplate = """
|
||||
|_@@PROGRAM@@()
|
||||
|{
|
||||
| local cur opts base
|
||||
| COMPREPLY=()
|
||||
| cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
| opts="@@ALLOPTIONS@@"
|
||||
|
|
||||
| COMPREPLY=($(compgen -W "${opts}" -- ${cur}))
|
||||
| _filedir
|
||||
| return 0
|
||||
|} && complete -F _@@PROGRAM@@ @@PROGRAM@@
|
||||
""".stripMargin
|
||||
|
||||
/** A simple template for generating a runner script.
|
||||
*/
|
||||
val runnerTemplate = """
|
||||
|#!/bin/sh
|
||||
|#
|
||||
|
|
||||
|scala @@MAINCLASS@@ $*
|
||||
|
|
||||
""".stripMargin
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/* NSC -- new Scala compiler
|
||||
* Copyright 2005-2010 LAMP/EPFL
|
||||
* @author Paul Phillips
|
||||
*/
|
||||
|
||||
package scala.tools
|
||||
package cmd
|
||||
|
||||
import nsc.io.File
|
||||
import Interpolation._
|
||||
|
||||
/** Meta-options for command line tools. We could have all kinds
|
||||
* of additional goodness here, but for now it's completion and script
|
||||
* generation. See Demo for example usage.
|
||||
*/
|
||||
object Meta {
|
||||
trait Opt {
|
||||
def name: String
|
||||
def action: () => Unit
|
||||
}
|
||||
|
||||
trait StdOpts {
|
||||
self: Spec with Interpolation =>
|
||||
|
||||
Bash.name --> runAndExit(Bash.action())
|
||||
val runnerFileName = Runner.name --| ;
|
||||
|
||||
if (runnerFileName.isDefined)
|
||||
runAndExit(Runner.action())
|
||||
|
||||
/** I think we're as close as we can get to bundling completion with
|
||||
* the program given the constraints imposed by bash. This outputs
|
||||
* the completion function to a tempfile and echoes ". /path/to/file"
|
||||
* to the console. Place it inside backtickes like `partest --bash`
|
||||
* and voila, you have absorbed command completion.
|
||||
*/
|
||||
object Bash extends Opt {
|
||||
val name = "bash"
|
||||
val action = () => {
|
||||
val file = File.makeTemp("scala.cmd.bash")
|
||||
file writeAll interpolate(bashTemplate)
|
||||
|
||||
// Would be nice to print something like this but comments are
|
||||
// not always comments in bash, and breaking it is worse.
|
||||
// Console println ("# Run the following line, or issue the --bash command in `backticks`.")
|
||||
Console println (". " + file.normalize.path)
|
||||
}
|
||||
}
|
||||
|
||||
/** A very basic runner script.
|
||||
*/
|
||||
object Runner extends Opt {
|
||||
val name = "generate-runner"
|
||||
val action = () => {
|
||||
val file = File(runnerFileName.get)
|
||||
file writeAll interpolate(runnerTemplate)
|
||||
file setExecutable true
|
||||
()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/* NSC -- new Scala compiler
|
||||
* Copyright 2005-2010 LAMP/EPFL
|
||||
* @author Paul Phillips
|
||||
*/
|
||||
|
||||
package scala.tools
|
||||
package cmd
|
||||
|
||||
import nsc.Properties.envOrElse
|
||||
import Spec.Names
|
||||
|
||||
/** Machinery for what amounts to a command line specification DSL.
|
||||
* It is designed so the same specification trait can be used for
|
||||
* two different purposes: generating a singleton specification object
|
||||
* (trait Reference) and providing well typed vals for every configurable
|
||||
* option in response to any given set of arguments (trait Instance).
|
||||
*/
|
||||
object Opt {
|
||||
trait Error {
|
||||
self: Implicit =>
|
||||
|
||||
protected def fail(msg: String) = runAndExit(println(programInfo.runner + ": " + msg))
|
||||
protected def failOption(arg: String, why: String) = fail("%s: '%s' is %s".format(opt, arg, why))
|
||||
}
|
||||
|
||||
trait Implicit {
|
||||
def name: String
|
||||
def programInfo: Names
|
||||
protected def opt = toOpt(name)
|
||||
|
||||
def --? : Boolean // --opt is set
|
||||
def --> (body: => Unit): Unit // if --opt is set, execute body
|
||||
def --| : Option[String] // --opt <arg: String> is optional, result is Option[String]
|
||||
def --^[T: FromString] : Option[T] // --opt <arg: T> is optional, result is Option[T]
|
||||
|
||||
def optMap[T](f: String => T) = --| map f
|
||||
|
||||
/** Names.
|
||||
*/
|
||||
def defaultTo[T: FromString](default: T): T
|
||||
def defaultToEnv(envVar: String): String
|
||||
def choiceOf[T: FromString](choices: T*): Option[T]
|
||||
def expandTo(args: String*): Unit
|
||||
|
||||
/** Help.
|
||||
*/
|
||||
def /(descr: String): String // --opt has help description 'descr'
|
||||
}
|
||||
|
||||
class Reference(val programInfo: Names, val options: Reference.Accumulators, val name: String) extends Implicit {
|
||||
import options._
|
||||
|
||||
def --? = { addUnary(opt) ; false }
|
||||
def --> (body: => Unit) = { addUnary(opt) }
|
||||
def --| = { addBinary(opt) ; None }
|
||||
def --^[T: FromString] = { addBinary(opt) ; None }
|
||||
|
||||
def defaultTo[T: FromString](default: T) = { addBinary(opt) ; addHelpDefault(() => default.toString) ; default }
|
||||
def defaultToEnv(envVar: String) = { addBinary(opt) ; addHelpEnvDefault(envVar) ; "" }
|
||||
def choiceOf[T: FromString](choices: T*) = { addBinary(opt) ; None }
|
||||
def expandTo(args: String*) = { addExpand(name, args.toList) ; addHelpAlias(() => args mkString " ") }
|
||||
|
||||
def /(descr: String) = returning(name)(_ => addHelp(() => helpFormatStr.format(opt, descr)))
|
||||
}
|
||||
|
||||
class Instance(val programInfo: Names, val parsed: CommandLine, val name: String) extends Implicit with Error {
|
||||
def --? = parsed isSet opt
|
||||
def --> (body: => Unit) = if (parsed isSet opt) body
|
||||
def --| = parsed get opt
|
||||
def --^[T: FromString] = {
|
||||
val fs = implicitly[FromString[T]]
|
||||
--| map { arg =>
|
||||
if (fs isDefinedAt arg) fs(arg)
|
||||
else failOption(arg, "not a " + fs.targetString)
|
||||
}
|
||||
}
|
||||
|
||||
def defaultTo[T: FromString](default: T) = --^[T] getOrElse default
|
||||
def defaultToEnv(envVar: String) = --| getOrElse envOrElse(envVar, "")
|
||||
def expandTo(args: String*) = ()
|
||||
|
||||
def choiceOf[T: FromString](choices: T*) = {
|
||||
--^[T] map { arg =>
|
||||
if (choices contains arg) arg
|
||||
else failOption(arg.toString, "not a valid choice from " + choices)
|
||||
}
|
||||
}
|
||||
|
||||
def /(descr: String) = name
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/* NEST (New Scala Test)
|
||||
* Copyright 2007-2010 LAMP/EPFL
|
||||
* @author Paul Phillips
|
||||
*/
|
||||
|
||||
package scala.tools
|
||||
package cmd
|
||||
|
||||
import scala.util.parsing.combinator._
|
||||
import scala.util.parsing.input.CharArrayReader.EofCh
|
||||
|
||||
/** A simple (overly so) command line parser.
|
||||
* !!! This needs a thorough test suite to make sure quoting is
|
||||
* done correctly and portably.
|
||||
*/
|
||||
trait ParserUtil extends Parsers {
|
||||
class ParserPlus[+T](underlying: Parser[T]) {
|
||||
def !~>[U](p: => Parser[U]): Parser[U] = (underlying ~! p) ^^ { case a~b => b }
|
||||
def <~![U](p: => Parser[U]): Parser[T] = (underlying ~! p) ^^ { case a~b => a }
|
||||
}
|
||||
protected implicit def parser2parserPlus[T](p: Parser[T]): ParserPlus[T] = new ParserPlus(p)
|
||||
}
|
||||
|
||||
object Parser extends RegexParsers with ParserUtil {
|
||||
override def skipWhitespace = false
|
||||
|
||||
def elemExcept(xs: Elem*): Parser[Elem] = elem("elemExcept", x => x != EofCh && !(xs contains x))
|
||||
def elemOf(xs: Elem*): Parser[Elem] = elem("elemOf", xs contains _)
|
||||
def escaped(ch: Char): Parser[String] = "\\" + ch
|
||||
def mkQuoted(ch: Char): Parser[String] = (
|
||||
elem(ch) !~> rep(escaped(ch) | elemExcept(ch)) <~ ch ^^ (_.mkString)
|
||||
| failure("Unmatched %s in input." format ch)
|
||||
)
|
||||
|
||||
/** Apparently windows can't deal with the quotes sticking around. */
|
||||
lazy val squoted: Parser[String] = mkQuoted('\'') // ^^ (x => "'%s'" format x)
|
||||
lazy val dquoted: Parser[String] = mkQuoted('"') // ^^ (x => "\"" + x + "\"")
|
||||
lazy val token: Parser[String] = """\S+""".r
|
||||
|
||||
lazy val argument: Parser[String] = squoted | dquoted | token
|
||||
lazy val commandLine: Parser[List[String]] = phrase(repsep(argument, whiteSpace))
|
||||
|
||||
class ParseException(msg: String) extends RuntimeException(msg)
|
||||
|
||||
def tokenize(line: String): List[String] = tokenize(line, x => throw new ParseException(x))
|
||||
def tokenize(line: String, errorFn: String => Unit): List[String] = {
|
||||
parse(commandLine, line.trim) match {
|
||||
case Success(args, _) => args
|
||||
case NoSuccess(msg, rest) => errorFn(msg) ; Nil
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/* NSC -- new Scala compiler
|
||||
* Copyright 2005-2010 LAMP/EPFL
|
||||
* @author Paul Phillips
|
||||
*/
|
||||
|
||||
package scala.tools
|
||||
package cmd
|
||||
|
||||
import nsc.io._
|
||||
import java.util.Properties
|
||||
import java.io.FileInputStream
|
||||
|
||||
/** Contains logic for translating a property key/value pair into
|
||||
* equivalent command line arguments. The default settings will
|
||||
* translate, given programInfo.runner == "foo" :
|
||||
*
|
||||
* foo.bar=true to --bar // if --bar is unary
|
||||
* foo.bar=quux to --bar quux // if --bar is binary
|
||||
*/
|
||||
class PropertyMapper(reference: Reference) extends (((String, String)) => List[String]) {
|
||||
import reference._
|
||||
lazy val RunnerName = programInfo.runner
|
||||
|
||||
// e.g. "partest.shootout" -> "--shootout"
|
||||
def propNameToOptionName(key: String): Option[String] = (key split '.').toList match {
|
||||
case List(RunnerName, name) => Some(name)
|
||||
case _ => None
|
||||
}
|
||||
|
||||
def isPassThrough(key: String): Boolean = false // e.g. "partest.options"
|
||||
def onError(key: String, value: String): Unit = () // called when translate fails
|
||||
|
||||
def translate(key: String, value: String): List[String] = {
|
||||
val opt = toOpt(key)
|
||||
|
||||
if (isUnaryOption(key) && isTrue(value)) List(opt)
|
||||
else if (isBinaryOption(key)) List(opt, value)
|
||||
else returning(Nil)(_ => onError(key, value))
|
||||
}
|
||||
def isTrue(value: String) = List("yes", "on", "true") contains value.toLowerCase
|
||||
|
||||
def apply(kv: (String, String)): List[String] = {
|
||||
val (k, v) = kv
|
||||
|
||||
if (isPassThrough(k)) toArgs(v)
|
||||
else propNameToOptionName(k) match {
|
||||
case Some(optName) => translate(optName, v)
|
||||
case _ => Nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait Property extends Reference {
|
||||
def propMapper: PropertyMapper
|
||||
override def propertyArgs: List[String] = systemPropertiesToOptions
|
||||
|
||||
def loadProperties(file: File): Properties =
|
||||
returning(new Properties)(_ load new FileInputStream(file.path))
|
||||
|
||||
def systemPropertiesToOptions: List[String] =
|
||||
propertiesToOptions(System.getProperties)
|
||||
|
||||
def propertiesToOptions(file: File): List[String] =
|
||||
propertiesToOptions(loadProperties(file))
|
||||
|
||||
def propertiesToOptions(props: java.util.Properties): List[String] = {
|
||||
import collection.JavaConversions._
|
||||
propertiesToOptions(props.toList)
|
||||
}
|
||||
def propertiesToOptions(props: List[(String, String)]) = props flatMap propMapper
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
/* NSC -- new Scala compiler
|
||||
* Copyright 2005-2010 LAMP/EPFL
|
||||
* @author Paul Phillips
|
||||
*/
|
||||
|
||||
package scala.tools
|
||||
package cmd
|
||||
|
||||
import collection.mutable.ListBuffer
|
||||
import nsc.Properties.envOrNone
|
||||
|
||||
/** Mixes in the specification trait and uses the vals therein to
|
||||
* side-effect private accumulators. From this emerges formatted help,
|
||||
* lists of unary and binary arguments, an apply which can creates
|
||||
* instances of the specification, and etc.
|
||||
*
|
||||
* @see Instance
|
||||
*/
|
||||
trait Reference extends Spec {
|
||||
lazy val options = new Reference.Accumulators()
|
||||
import options._
|
||||
|
||||
def helpMsg = options.helpMsg
|
||||
def propertyArgs: List[String] = Nil
|
||||
|
||||
def isUnaryOption(s: String) = unary contains toOpt(s)
|
||||
def isBinaryOption(s: String) = binary contains toOpt(s)
|
||||
def isExpandOption(s: String) = expansionMap contains toOpt(s)
|
||||
def isAnyOption(s: String) = isUnaryOption(s) || isBinaryOption(s) || isExpandOption(s)
|
||||
|
||||
def expandArg(arg: String) = expansionMap.getOrElse(fromOpt(arg), List(arg))
|
||||
|
||||
protected def help(str: => String) = addHelp(() => str)
|
||||
|
||||
type ThisCommandLine <: SpecCommandLine
|
||||
class SpecCommandLine(args: List[String]) extends CommandLine(Reference.this, args) { }
|
||||
protected def creator(args: List[String]): ThisCommandLine
|
||||
final def apply(args: String*): ThisCommandLine = creator(propertyArgs ++ args flatMap expandArg)
|
||||
|
||||
type OptionMagic = Opt.Reference
|
||||
protected implicit def optionMagicAdditions(name: String) = new Opt.Reference(programInfo, options, name)
|
||||
}
|
||||
|
||||
object Reference {
|
||||
val MaxLine = 80
|
||||
|
||||
class Accumulators() {
|
||||
private var _help = new ListBuffer[() => String]
|
||||
private var _unary = List[String]()
|
||||
private var _binary = List[String]()
|
||||
private var _expand = Map[String, List[String]]()
|
||||
|
||||
def helpFormatStr = " %-" + longestArg + "s %s"
|
||||
def defaultFormatStr = (" " * (longestArg + 7)) + "%s"
|
||||
|
||||
def addUnary(s: String) = _unary +:= s
|
||||
def addBinary(s: String) = _binary +:= s
|
||||
|
||||
def addExpand(opt: String, expanded: List[String]) =
|
||||
_expand += (opt -> expanded)
|
||||
|
||||
def mapHelp(g: String => String) = {
|
||||
val idx = _help.length - 1
|
||||
val f = _help(idx)
|
||||
|
||||
_help(idx) = () => g(f())
|
||||
}
|
||||
|
||||
def addHelp(f: () => String) = _help += f
|
||||
def addHelpAlias(f: () => String) = mapHelp { s =>
|
||||
val str = "alias for '%s'" format f()
|
||||
def noHelp = (helpFormatStr.format("", "")).length == s.length
|
||||
val str2 = if (noHelp) str else " (" + str + ")"
|
||||
|
||||
s + str2
|
||||
}
|
||||
def addHelpDefault(f: () => String) = mapHelp { s =>
|
||||
val str = "(default: %s)" format f()
|
||||
|
||||
if (s.length + str.length < MaxLine) s + " " + str
|
||||
else defaultFormatStr.format(s, str)
|
||||
}
|
||||
def addHelpEnvDefault(name: String) = mapHelp { s =>
|
||||
val line1 = "%s (default: %s)".format(s, name)
|
||||
val envNow = envOrNone(name) map ("'" + _ + "'") getOrElse "unset"
|
||||
val line2 = defaultFormatStr.format("Currently " + envNow)
|
||||
|
||||
line1 + "\n" + line2
|
||||
}
|
||||
|
||||
lazy val unary = (_unary ++ _expand.keys).distinct
|
||||
lazy val binary = _binary.distinct
|
||||
lazy val all = unary ++ binary
|
||||
lazy val expansionMap = _expand
|
||||
lazy val helpMsg = _help map (f => f() + "\n") mkString
|
||||
lazy val longestArg = all map (_.length) max
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/* NSC -- new Scala compiler
|
||||
* Copyright 2005-2010 LAMP/EPFL
|
||||
* @author Paul Phillips
|
||||
*/
|
||||
|
||||
package scala.tools
|
||||
package cmd
|
||||
|
||||
/** This trait works together with others in scala.tools.cmd to allow
|
||||
* declaratively specifying a command line program, with many attendant
|
||||
* benefits. See scala.tools.cmd.DemoSpec for an example.
|
||||
*/
|
||||
trait Spec {
|
||||
def referenceSpec: Reference
|
||||
def programInfo: Spec.Names
|
||||
|
||||
protected def help(str: => String): Unit
|
||||
protected def heading(str: => String): Unit = help("\n " + str)
|
||||
|
||||
type OptionMagic <: Opt.Implicit
|
||||
protected implicit def optionMagicAdditions(s: String): OptionMagic
|
||||
}
|
||||
|
||||
object Spec {
|
||||
case class Names(runner: String, mainClass: String) { }
|
||||
|
||||
class Accumulator[T: FromString]() {
|
||||
private var _buf: List[T] = Nil
|
||||
|
||||
def convert(s: String) = implicitly[FromString[T]] apply s
|
||||
def apply(s: String): T = returning(convert(s))(_buf +:= _)
|
||||
|
||||
lazy val get = _buf
|
||||
}
|
||||
|
||||
class Choices[T: FromString](val xs: List[T]) {
|
||||
def fs: FromString[T] = implicitly[FromString[T]]
|
||||
def contains(x: T) = xs contains x
|
||||
override def toString = xs.mkString("{ ", ", ", " }")
|
||||
}
|
||||
|
||||
class EnvironmentVar(val name: String) {
|
||||
override def toString = "${%s}" format name
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/* NSC -- new Scala compiler
|
||||
* Copyright 2005-2010 LAMP/EPFL
|
||||
* @author Paul Phillips
|
||||
*/
|
||||
|
||||
package scala.tools
|
||||
|
||||
package object cmd {
|
||||
def returning[T](x: T)(f: T => Unit): T = { f(x) ; x }
|
||||
|
||||
private[cmd] def debug(msg: String) = println(msg)
|
||||
|
||||
def runAndExit(body: => Unit): Nothing = {
|
||||
body
|
||||
System exit 0
|
||||
error("unreachable")
|
||||
}
|
||||
|
||||
def toOpt(s: String) = if (s startsWith "--") s else "--" + s
|
||||
def fromOpt(s: String) = s stripPrefix "--"
|
||||
def toArgs(line: String) = Parser tokenize line
|
||||
def fromArgs(args: List[String]) = args mkString " "
|
||||
|
||||
def stripQuotes(s: String) = {
|
||||
def isQuotedBy(c: Char) = s.length > 0 && s.head == c && s.last == c
|
||||
if (List('"', '\'') exists isQuotedBy) s.tail.init else s
|
||||
}
|
||||
}
|
|
@ -136,4 +136,16 @@ with Streamable.Chars {
|
|||
|
||||
true
|
||||
}
|
||||
|
||||
/** Reflection since we're into the java 6+ API.
|
||||
*/
|
||||
def setExecutable(executable: Boolean, ownerOnly: Boolean = true): Boolean = {
|
||||
type JBoolean = java.lang.Boolean
|
||||
val method =
|
||||
try classOf[JFile].getMethod("setExecutable", classOf[Boolean], classOf[Boolean])
|
||||
catch { case _: NoSuchMethodException => return false }
|
||||
|
||||
try method.invoke(jfile, executable: JBoolean, ownerOnly: JBoolean).asInstanceOf[JBoolean].booleanValue
|
||||
catch { case _: Exception => false }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,15 +4,13 @@
|
|||
*/
|
||||
// $Id$
|
||||
|
||||
package scala.tools.nsc
|
||||
package scala.tools
|
||||
package nsc
|
||||
package settings
|
||||
|
||||
import io.AbstractFile
|
||||
import util.{ ClassPath, CommandLineParser }
|
||||
import annotation.elidable
|
||||
import scala.tools.util.StringOps
|
||||
import scala.collection.mutable.ListBuffer
|
||||
import interpreter.{ returning }
|
||||
|
||||
/** A mutable Settings object.
|
||||
*/
|
||||
|
@ -84,7 +82,7 @@ class MutableSettings(val errorFn: String => Unit) extends AbsSettings with Scal
|
|||
|
||||
/** Split the given line into parameters.
|
||||
*/
|
||||
def splitParams(line: String) = CommandLineParser.tokenize(line, errorFn)
|
||||
def splitParams(line: String) = cmd.Parser.tokenize(line, errorFn)
|
||||
|
||||
/** Returns any unprocessed arguments.
|
||||
*/
|
||||
|
@ -426,7 +424,7 @@ class MutableSettings(val errorFn: String => Unit) extends AbsSettings with Scal
|
|||
prependPath: StringSetting,
|
||||
appendPath: StringSetting)
|
||||
extends StringSetting(name, arg, descr, default) {
|
||||
import ClassPath.join
|
||||
import util.ClassPath.join
|
||||
def prepend(s: String) = prependPath.value = join(s, prependPath.value)
|
||||
def append(s: String) = appendPath.value = join(appendPath.value, s)
|
||||
|
||||
|
|
|
@ -4,22 +4,18 @@
|
|||
*/
|
||||
// $Id$
|
||||
|
||||
package scala.tools.nsc
|
||||
package scala.tools
|
||||
package nsc
|
||||
package settings
|
||||
|
||||
import io.AbstractFile
|
||||
import util.{ ClassPath, SourceFile, CommandLineParser }
|
||||
import annotation.elidable
|
||||
import scala.tools.util.{ PathResolver, StringOps }
|
||||
import scala.collection.mutable.{ HashSet, ListBuffer }
|
||||
import scala.collection.immutable.TreeSet
|
||||
import interpreter.{ returning }
|
||||
import scala.tools.util.PathResolver.Defaults
|
||||
import scala.collection.mutable.HashSet
|
||||
|
||||
trait ScalaSettings extends AbsScalaSettings with StandardScalaSettings {
|
||||
self: MutableSettings =>
|
||||
|
||||
import PathResolver.{ Defaults, Environment }
|
||||
import Defaults.{ scalaUserClassPath }
|
||||
import Defaults.scalaUserClassPath
|
||||
|
||||
/** Set of settings */
|
||||
protected lazy val allSettings = HashSet[Setting]()
|
||||
|
|
|
@ -1,142 +0,0 @@
|
|||
/* NEST (New Scala Test)
|
||||
* Copyright 2007-2010 LAMP/EPFL
|
||||
* @author Paul Phillips
|
||||
*/
|
||||
|
||||
package scala.tools.nsc
|
||||
package util
|
||||
|
||||
import scala.util.parsing.combinator._
|
||||
import scala.util.parsing.input.{ Reader }
|
||||
import scala.util.parsing.input.CharArrayReader.EofCh
|
||||
import scala.collection.mutable.ListBuffer
|
||||
|
||||
/** A simple command line parser to replace the several different
|
||||
* simple ones spread around trunk.
|
||||
*/
|
||||
|
||||
trait ParserUtil extends Parsers {
|
||||
class ParserPlus[+T](underlying: Parser[T]) {
|
||||
def !~>[U](p: => Parser[U]): Parser[U] = (underlying ~! p) ^^ { case a~b => b }
|
||||
def <~![U](p: => Parser[U]): Parser[T] = (underlying ~! p) ^^ { case a~b => a }
|
||||
}
|
||||
protected implicit def parser2parserPlus[T](p: Parser[T]): ParserPlus[T] = new ParserPlus(p)
|
||||
}
|
||||
|
||||
case class CommandLine(
|
||||
args: List[String],
|
||||
unaryOptions: List[String],
|
||||
binaryOptions: List[String]
|
||||
) {
|
||||
def this(args: List[String]) = this(args, Nil, Nil)
|
||||
def this(args: Array[String]) = this(args.toList, Nil, Nil)
|
||||
def this(line: String) = this(CommandLineParser tokenize line, Nil, Nil)
|
||||
|
||||
def withUnary(xs: List[String]) = copy(unaryOptions = xs)
|
||||
def withBinary(xs: List[String]) = copy(binaryOptions = xs)
|
||||
|
||||
def allOptions = unaryOptions ++ binaryOptions
|
||||
def originalArgs = args
|
||||
def assumeBinary = true
|
||||
def enforceArity = true
|
||||
def onlyKnownOptions = false
|
||||
|
||||
val Terminator = "--"
|
||||
val ValueForUnaryOption = "true" // so if --opt is given, x(--opt) = true
|
||||
|
||||
def mapForUnary(opt: String) = Map(opt -> ValueForUnaryOption)
|
||||
def errorFn(msg: String) = println(msg)
|
||||
|
||||
/** argMap is option -> argument (or "" if it is a unary argument)
|
||||
* residualArgs are what is left after removing the options and their args.
|
||||
*/
|
||||
lazy val (argMap, residualArgs) = {
|
||||
val residualBuffer = new ListBuffer[String]
|
||||
|
||||
def stripQuotes(s: String) = {
|
||||
def isQuotedBy(c: Char) = s.length > 0 && s.head == c && s.last == c
|
||||
if (List('"', '\'') exists isQuotedBy) s.tail.init else s
|
||||
}
|
||||
|
||||
def isValidOption(s: String) = !onlyKnownOptions || (unaryOptions contains s) || (binaryOptions contains s)
|
||||
def isOption(s: String) = (s startsWith "-") && (isValidOption(s) || { unknownOption(s) ; false })
|
||||
def isUnary(s: String) = isOption(s) && (unaryOptions contains s)
|
||||
def isBinary(s: String) = isOption(s) && !isUnary(s) && (assumeBinary || (binaryOptions contains s))
|
||||
|
||||
def unknownOption(opt: String) =
|
||||
errorFn("Option '%s' not recognized.".format(opt))
|
||||
def missingArg(opt: String, what: String) =
|
||||
errorFn("Option '%s' requires argument, found %s instead.".format(opt, what))
|
||||
|
||||
def loop(args: List[String]): Map[String, String] = {
|
||||
def residual(xs: List[String]) = { residualBuffer ++= xs ; Map[String, String]() }
|
||||
if (args.isEmpty) return Map()
|
||||
val hd :: rest = args
|
||||
if (rest.isEmpty) {
|
||||
if (isBinary(hd) && enforceArity)
|
||||
missingArg(hd, "EOF")
|
||||
|
||||
if (isOption(hd)) mapForUnary(hd) else residual(args)
|
||||
}
|
||||
else
|
||||
if (hd == Terminator) residual(rest)
|
||||
else {
|
||||
val hd1 :: hd2 :: rest = args
|
||||
|
||||
if (hd2 == Terminator) mapForUnary(hd1) ++ residual(rest)
|
||||
else if (isUnary(hd1)) mapForUnary(hd1) ++ loop(hd2 :: rest)
|
||||
else if (isBinary(hd1)) {
|
||||
// Disabling this check so
|
||||
// --scalacopts "-verbose" works. We can't tell if it's quoted,
|
||||
// the shell does us in.
|
||||
//
|
||||
// if (isOption(hd2) && enforceArity)
|
||||
// missingArg(hd1, hd2)
|
||||
|
||||
Map(hd1 -> hd2) ++ loop(rest)
|
||||
}
|
||||
else { residual(List(hd1)) ++ loop(hd2 :: rest) }
|
||||
}
|
||||
}
|
||||
|
||||
(loop(args), residualBuffer map stripQuotes toList)
|
||||
}
|
||||
|
||||
def isSet(arg: String) = args contains arg
|
||||
def get(arg: String) = argMap get arg
|
||||
def getOrElse(arg: String, orElse: => String) = if (isSet(arg)) apply(arg) else orElse
|
||||
def apply(arg: String) = argMap(arg)
|
||||
|
||||
override def toString() = "CommandLine(\n%s)\n" format (args map (" " + _ + "\n") mkString)
|
||||
}
|
||||
|
||||
object CommandLineParser extends RegexParsers with ParserUtil {
|
||||
override def skipWhitespace = false
|
||||
|
||||
def elemExcept(xs: Elem*): Parser[Elem] = elem("elemExcept", x => x != EofCh && !(xs contains x))
|
||||
def elemOf(xs: Elem*): Parser[Elem] = elem("elemOf", xs contains _)
|
||||
def escaped(ch: Char): Parser[String] = "\\" + ch
|
||||
def mkQuoted(ch: Char): Parser[String] = (
|
||||
elem(ch) !~> rep(escaped(ch) | elemExcept(ch)) <~ ch ^^ (_.mkString)
|
||||
| failure("Unmatched %s in input." format ch)
|
||||
)
|
||||
|
||||
/** Apparently windows can't deal with the quotes sticking around. */
|
||||
lazy val squoted: Parser[String] = mkQuoted('\'') // ^^ (x => "'%s'" format x)
|
||||
lazy val dquoted: Parser[String] = mkQuoted('"') // ^^ (x => "\"" + x + "\"")
|
||||
lazy val token: Parser[String] = """\S+""".r
|
||||
|
||||
lazy val argument: Parser[String] = squoted | dquoted | token
|
||||
lazy val commandLine: Parser[List[String]] = phrase(repsep(argument, whiteSpace))
|
||||
|
||||
class ParseException(msg: String) extends RuntimeException(msg)
|
||||
|
||||
def tokenize(line: String): List[String] = tokenize(line, x => throw new ParseException(x))
|
||||
def tokenize(line: String, errorFn: String => Unit): List[String] = {
|
||||
parse(commandLine, line.trim) match {
|
||||
case Success(args, _) => args
|
||||
case NoSuccess(msg, rest) => errorFn(msg) ; Nil
|
||||
}
|
||||
}
|
||||
def apply(line: String) = new CommandLine(tokenize(line))
|
||||
}
|
|
@ -1,150 +0,0 @@
|
|||
/* NSC -- new Scala compiler
|
||||
* Copyright 2005-2010 LAMP/EPFL
|
||||
* @author Paul Phillips
|
||||
*/
|
||||
|
||||
package scala.tools.nsc
|
||||
package util
|
||||
|
||||
import Properties._
|
||||
import io._
|
||||
import CommandLineSpec._
|
||||
import CommandLineParser.tokenize
|
||||
|
||||
/** This trait works together with CommandLine to allow declaratively
|
||||
* specifying a command line program, with many attendant benefits.
|
||||
* See scala.tools.partest.PartestSpec for a full example.
|
||||
*/
|
||||
|
||||
trait CommandLineSpec {
|
||||
def parsed: CommandLine
|
||||
def isReferenceSpec: Boolean = false
|
||||
def isPassthroughProperty(name: String): Boolean = false
|
||||
def isSysPropOption(key: String): Option[String] = None
|
||||
|
||||
protected var _expandingOptions: Map[String, List[String]] = Map()
|
||||
|
||||
private var _helpMessage: String = ""
|
||||
private var _unaryOptions: List[String] = Nil
|
||||
private var _binaryOptions: List[String] = Nil
|
||||
private def allOptions = if (isReferenceSpec) Nil else parsed.allOptions
|
||||
private def longestArg = if (allOptions.isEmpty) 1 else allOptions map (_.length) max
|
||||
private def unquoted(s: String) = {
|
||||
def isQuoted = (s.head == '\'' || s.head == '"') && s.head == s.last
|
||||
|
||||
if (s == null || s.length < 2 || !isQuoted) s
|
||||
else s drop 1 dropRight 1
|
||||
}
|
||||
|
||||
protected def help(str: String) = if (isReferenceSpec) () else _helpMessage += (str.stripMargin + "\n")
|
||||
protected def heading(s: String) = if (isReferenceSpec) () else help("\n " + s)
|
||||
|
||||
/** The various operators:
|
||||
* val isCond1 = "cond1" ? // --cond1 is unary, cond1 is boolean
|
||||
* "cond2" ?> body // --cond2 is unary, body is executed if it is given
|
||||
* "cond3" ?+> List(x1, x2...) // --cond3 is unary, arguments on rhs will be substituted in as if given
|
||||
* val val1 = "val1" |> "alt" // --val1 is binary, val1 is String, alt used if none given
|
||||
* val val2 = "val2" >> // --val2 is binary, val2 is Option[String], None if none given
|
||||
*/
|
||||
protected class OptionStringAdditions(name: String) {
|
||||
val s = toOpt(name)
|
||||
def ?+>(args: List[String]): Unit = { _unaryOptions +:= s ; if (isReferenceSpec) _expandingOptions += (name -> args) }
|
||||
|
||||
def ? : Boolean = { _unaryOptions +:= s ; if (isReferenceSpec) false else parsed isSet s }
|
||||
def ?>(body: => Unit): Unit = { _unaryOptions +:= s ; if (isReferenceSpec) () else if (parsed isSet s) body }
|
||||
def |>(alt: String): String = { _binaryOptions +:= s ; if (isReferenceSpec) "" else parsed.getOrElse(s, alt) }
|
||||
def >> : Option[String] = { _binaryOptions +:= s ; if (isReferenceSpec) None else parsed get s }
|
||||
|
||||
def /(description: String) = {
|
||||
val formatStr = " %-" + longestArg + "s %s"
|
||||
help(formatStr.format(s, description))
|
||||
|
||||
name
|
||||
}
|
||||
}
|
||||
protected implicit def stringAdditions(s: String) = new OptionStringAdditions(s)
|
||||
|
||||
lazy val unaryOptions = _unaryOptions.distinct
|
||||
lazy val binaryOptions = _binaryOptions.distinct
|
||||
lazy val expandingOptions = _expandingOptions.keys.toList
|
||||
lazy val helpMsg = _helpMessage
|
||||
|
||||
def isUnaryOption(s: String) = unaryOptions contains toOpt(s)
|
||||
def isBinaryOption(s: String) = binaryOptions contains toOpt(s)
|
||||
def isExpandingOption(s: String) = expandingOptions contains toOpt(s)
|
||||
|
||||
private def sysPropToOptions(k: String, v: String): List[String] = {
|
||||
if (isPassthroughProperty(k)) toArgs(v)
|
||||
else isSysPropOption(k).toList flatMap { optName =>
|
||||
val opt = toOpt(optName)
|
||||
|
||||
if (isUnaryOption(optName)) List(opt)
|
||||
else if (isBinaryOption(optName)) List(opt, v)
|
||||
else {
|
||||
if (warnSuspiciousProperties) {
|
||||
println("Warning, this looks like a command line option but I don't understand it.")
|
||||
println("Ignoring: " + k + "=" + v)
|
||||
}
|
||||
Nil
|
||||
}
|
||||
}
|
||||
}
|
||||
def warnSuspiciousProperties: Boolean = true
|
||||
def sysPropsAsOptions() = allSystemProperties.toList flatMap (sysPropToOptions _).tupled
|
||||
|
||||
def isSet(s: String) = parsed isSet toOpt(s)
|
||||
def reconstruct: List[String] = {
|
||||
val unary = unaryOptions filter (parsed isSet _)
|
||||
val binary = binaryOptions collect { case x if parsed isSet x => List(x, parsed(x)) }
|
||||
val resid = parsed.residualArgs
|
||||
|
||||
unary ++ binary.flatten ++ resid
|
||||
}
|
||||
|
||||
def bashCompletion(programName: String) = {
|
||||
val opts = unaryOptions ++ binaryOptions
|
||||
bashCompletionTemplate.replaceAll("@@PROGRAM@@", programName).replaceAll("@@OPTIONS@@", opts mkString " ")
|
||||
}
|
||||
}
|
||||
|
||||
trait CommandLineReferenceSpec extends CommandLineSpec {
|
||||
final override def isReferenceSpec: Boolean = true
|
||||
final def apply(args: String*) = creator(args.toList flatMap expandArg)
|
||||
|
||||
protected lazy val expansionMap = _expandingOptions
|
||||
protected def creator(args: List[String]) = new ThisCommandLine(args)
|
||||
protected def expandArg(arg: String) = expansionMap.getOrElse(fromOpt(arg), List(arg))
|
||||
|
||||
class ThisCommandLine(args: List[String]) extends CommandLine(args, unaryOptions, binaryOptions) {
|
||||
}
|
||||
}
|
||||
|
||||
object CommandLineSpec {
|
||||
def toOpt(s: String) = if (s startsWith "--") s else "--" + s
|
||||
def fromOpt(s: String) = s stripPrefix "--"
|
||||
def toArgs(line: String) = tokenize(line)
|
||||
def fromArgs(args: List[String]) = args mkString " "
|
||||
|
||||
def allSystemProperties: Map[String, String] = {
|
||||
import collection.JavaConversions._
|
||||
|
||||
System.getProperties.toMap
|
||||
}
|
||||
|
||||
/** A very simple template for generating bash completion functions.
|
||||
*/
|
||||
val bashCompletionTemplate = """
|
||||
|_@@PROGRAM@@()
|
||||
|{
|
||||
| local cur opts base
|
||||
| COMPREPLY=()
|
||||
| cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
| opts="@@OPTIONS@@"
|
||||
|
|
||||
| COMPREPLY=($(compgen -W "${opts}" -- ${cur}))
|
||||
| _filedir
|
||||
| return 0
|
||||
|}
|
||||
|complete -F _@@PROGRAM@@ @@PROGRAM@@
|
||||
""".stripMargin
|
||||
}
|
|
@ -4,7 +4,8 @@
|
|||
*/
|
||||
// $Id$
|
||||
|
||||
package scala.tools.nsc
|
||||
package scala.tools
|
||||
package nsc
|
||||
package util
|
||||
|
||||
import java.io.{File, FileInputStream, PrintStream, IOException}
|
||||
|
@ -290,7 +291,7 @@ object ShowPickled extends Names {
|
|||
/** Option --bare suppresses numbers so the output can be diffed.
|
||||
*/
|
||||
def main(args: Array[String]) {
|
||||
val parsed = CommandLine(args.toList, List("--bare"), Nil)
|
||||
val parsed = cmd.CommandLine(args.toList, List("--bare"), Nil)
|
||||
def isBare = parsed isSet "--bare"
|
||||
|
||||
parsed.residualArgs foreach { arg =>
|
||||
|
|
|
@ -54,6 +54,7 @@ private[scala] trait PropertiesTrait
|
|||
def clearProp(name: String) = System.clearProperty(name)
|
||||
|
||||
def envOrElse(name: String, alt: String) = Option(System getenv name) getOrElse alt
|
||||
def envOrNone(name: String) = Option(System getenv name)
|
||||
|
||||
// for values based on propFilename
|
||||
def scalaPropOrElse(name: String, alt: String): String = scalaProps.getProperty(name, alt)
|
||||
|
|
|
@ -27,8 +27,10 @@ trait PartestCompilation {
|
|||
// }
|
||||
|
||||
def javac(args: List[String]): Boolean = {
|
||||
val allArgString = fromArgs(javacpArg :: javacOpts :: args)
|
||||
|
||||
// javac -d outdir -classpath <basepath> <files>
|
||||
val cmd = "%s -d %s %s %s".format(javacCmd, outDir, javacpArg, fromArgs(args))
|
||||
val cmd = "%s -d %s %s".format(javacCmd, outDir, allArgString)
|
||||
def traceMsg =
|
||||
if (isVerbose) cmd
|
||||
else "%s -d %s %s".format(tracePath(Path(javacCmd)), tracePath(outDir), fromArgs(args))
|
||||
|
|
|
@ -23,8 +23,6 @@ trait Config {
|
|||
* run we only allocate one worker so the output isn't interspersed.
|
||||
*/
|
||||
def workerTimeout = 3600 // 1 hour, probably overly generous
|
||||
def testTimeout = testTimeout_ flatMap safeToInt getOrElse 900 // test timeout
|
||||
def testWarning = testWarning_ flatMap safeToInt getOrElse (testTimeout / 10) // test warning
|
||||
def numWorkers = if (isDryRun) 1 else propOrElse("partest.actors", "8").toInt
|
||||
def expectedErrors = propOrElse("partest.errors", "0").toInt
|
||||
def poolSize = (wrapAccessControl(propOrNone("actors.corePoolSize")) getOrElse "16").toInt
|
||||
|
@ -121,6 +119,7 @@ trait Config {
|
|||
"Java binaries in: " + javaBin,
|
||||
"Java runtime is: " + javaInfoString,
|
||||
"Java runtime options: " + (Process.javaVmArguments mkString " "),
|
||||
"Javac options are: " + universe.javacOpts,
|
||||
"Java options are: " + universe.javaOpts,
|
||||
"Source directory is: " + src,
|
||||
"Selected categories: " + (selectedCategories mkString " "),
|
||||
|
|
|
@ -6,7 +6,7 @@ package scala.tools
|
|||
package partest
|
||||
|
||||
import nsc.io._
|
||||
import nsc.util.CommandLine
|
||||
import nsc.util._
|
||||
import category.AllCategories
|
||||
|
||||
/** Global object for a Partest run. It is completely configured by the list
|
||||
|
@ -15,10 +15,15 @@ import category.AllCategories
|
|||
* for the complete list.
|
||||
*/
|
||||
class Partest(args: List[String]) extends {
|
||||
val parsed = PartestSpecReference(args: _*)
|
||||
} with Universe with PartestSpec with AllCategories {
|
||||
val parsed = PartestSpec(args: _*)
|
||||
} with Universe with PartestSpec with cmd.Instance with AllCategories {
|
||||
|
||||
debug("Partest object created with args: " + (args mkString " "))
|
||||
if (parsed.propertyArgs.nonEmpty)
|
||||
debug("Partest property args: " + fromArgs(parsed.propertyArgs))
|
||||
|
||||
debug("Partest created with args: " + fromArgs(args))
|
||||
|
||||
def helpMsg = PartestSpec.helpMsg
|
||||
|
||||
// The abstract values from Universe.
|
||||
lazy val testBuildDir = searchForDir(buildDir)
|
||||
|
@ -30,7 +35,6 @@ class Partest(args: List[String]) extends {
|
|||
// Coarse validation of partest directory: holds a file called partest.
|
||||
(partestDir / "partest").isFile || error("'%s' is not a valid partest directory." format partestDir)
|
||||
|
||||
def runSets = toArgs(parsed.getOrElse("--runsets", ""))
|
||||
def specifiedTests = parsed.residualArgs map (x => Path(x).normalize)
|
||||
def specifiedKinds = testKinds filter (x => isSet(x) || (runSets contains x))
|
||||
def specifiedCats = specifiedKinds flatMap (x => allCategories find (_.kind == x))
|
||||
|
|
|
@ -6,9 +6,8 @@
|
|||
package scala.tools
|
||||
package partest
|
||||
|
||||
import Properties._
|
||||
import nsc.io._
|
||||
import nsc.util.{ CommandLine, CommandLineSpec, CommandLineReferenceSpec }
|
||||
import cmd._
|
||||
|
||||
/** This takes advantage of bits of scala goodness to fully define a command
|
||||
* line program with a minimum of duplicated code. When the specification object
|
||||
|
@ -16,93 +15,90 @@ import nsc.util.{ CommandLine, CommandLineSpec, CommandLineReferenceSpec }
|
|||
* a private accumulator. What emerges is a full list of the valid unary
|
||||
* and binary arguments, as well as autogenerated help.
|
||||
*/
|
||||
trait PartestSpec extends CommandLineSpec {
|
||||
override def isPassthroughProperty(key: String) = key == "partest.options"
|
||||
override def isSysPropOption(key: String) = {
|
||||
val segments = (key split '.').toList
|
||||
if (segments.size == 2 && segments.head == "partest") Some(segments.last)
|
||||
else None
|
||||
}
|
||||
|
||||
private var _testKinds: List[String] = Nil
|
||||
private def kind(s: String) = returning(s)(_testKinds +:= _)
|
||||
|
||||
def testKinds = _testKinds
|
||||
def versionMsg = Properties.versionMsg
|
||||
trait PartestSpec extends Spec with Meta.StdOpts with Interpolation {
|
||||
def referenceSpec = PartestSpec
|
||||
def programInfo = Spec.Names("partest", "scala.tools.partest.Runner")
|
||||
private val kind = new Spec.Accumulator[String]()
|
||||
protected def testKinds = kind.get
|
||||
|
||||
private implicit val tokenizeString = FromString.ArgumentsFromString // String => List[String]
|
||||
|
||||
help("""
|
||||
|# Pro Tip! Instant bash completion: `partest --bash` (note backticks)
|
||||
|Usage: partest [<options>] [<test> <test> ...]
|
||||
| <test>: a path to a test designator, typically a .scala file or a directory.
|
||||
| Examples: files/pos/test1.scala, files/res/bug785""")
|
||||
|
||||
heading ("Test categories:")
|
||||
val isAll = ("all" / "run all tests (default, unless no options given)" ?)
|
||||
(kind("pos") / "Compile files that are expected to build" ?)
|
||||
(kind("neg") / "Compile files that are expected to fail" ?)
|
||||
(kind("run") / "Test JVM backend" ?)
|
||||
(kind("jvm") / "Test JVM backend" ?)
|
||||
(kind("res") / "Run resident compiler scenarii" ?)
|
||||
(kind("buildmanager") / "Run Build Manager scenarii" ?)
|
||||
(kind("scalacheck") / "Run Scalacheck tests" ?)
|
||||
(kind("script") / "Run script files" ?)
|
||||
(kind("shootout") / "Run shootout tests" ?)
|
||||
(kind("scalap") / "Run scalap tests" ?)
|
||||
| Examples: files/pos/test1.scala, files/res/bug785
|
||||
|
|
||||
| Test categories:""".stripMargin)
|
||||
|
||||
val isAll = ("all" / "run all tests (default, unless no options given)" --?)
|
||||
(kind("pos") / "Compile files that are expected to build" --?)
|
||||
(kind("neg") / "Compile files that are expected to fail" --?)
|
||||
(kind("run") / "Test JVM backend" --?)
|
||||
(kind("jvm") / "Test JVM backend" --?)
|
||||
(kind("res") / "Run resident compiler scenarii" --?)
|
||||
(kind("buildmanager") / "Run Build Manager scenarii" --?)
|
||||
(kind("scalacheck") / "Run Scalacheck tests" --?)
|
||||
(kind("script") / "Run script files" --?)
|
||||
(kind("shootout") / "Run shootout tests" --?)
|
||||
(kind("scalap") / "Run scalap tests" --?)
|
||||
|
||||
heading ("""Test "smart" categories:""")
|
||||
val grepExpr = "grep" / "run all tests with a source file containing <expr>" >>
|
||||
val isFailed = "failed" / "run all tests which failed on the last run" ?
|
||||
val grepExpr = "grep" / "run all tests with a source file containing <expr>" --|
|
||||
val isFailed = "failed" / "run all tests which failed on the last run" --?
|
||||
|
||||
heading ("Specifying paths and additional flags, ~ means repository root:")
|
||||
val rootDir = "rootdir" / "path from ~ to partest (default: test)" |> "test"
|
||||
val buildDir = "builddir" / "path from ~ to test build (default: build/pack)" |> "build/pack"
|
||||
val srcDir = "srcdir" / "path from --rootdir to sources (default: files)" |> "files"
|
||||
val javaOpts = "javaopts" / "flags to java on all runs (overrides JAVA_OPTS)" |> envOrElse("JAVA_OPTS", "")
|
||||
val scalacOpts = "scalacopts" / "flags to scalac on all tests (overrides SCALAC_OPTS)" |> envOrElse("SCALAC_OPTS", "")
|
||||
|
||||
val rootDir = "rootdir" / "path from ~ to partest" defaultTo "test"
|
||||
val buildDir = "builddir" / "path from ~ to test build" defaultTo "build/pack"
|
||||
val srcDir = "srcdir" / "path from --rootdir to sources" defaultTo "files"
|
||||
val javaOpts = "javaopts" / "flags to java on all runs" defaultToEnv "JAVA_OPTS"
|
||||
val javacOpts = "javacopts" / "flags to javac on all runs" defaultToEnv "JAVAC_OPTS"
|
||||
val scalacOpts = "scalacopts" / "flags to scalac on all tests" defaultToEnv "SCALAC_OPTS"
|
||||
|
||||
("pack" / "alias for --builddir build/pack") ?+> List("--builddir", "build/pack")
|
||||
("quick" / "alias for --builddir build/quick") ?+> List("--builddir", "build/quick")
|
||||
"pack" / "" expandTo ("--builddir", "build/pack")
|
||||
"quick" / "" expandTo ("--builddir", "build/quick")
|
||||
|
||||
heading ("Options influencing output:")
|
||||
val isTrace = "trace" / "show the individual steps taken by each test" ?
|
||||
val isShowDiff = "show-diff" / "show diff between log and check file" ?
|
||||
val isShowLog = "show-log" / "show log on failures" ?
|
||||
val isDryRun = "dry-run" / "do not run tests, only show their traces." ?
|
||||
val isTerse = "terse" / "be less verbose (almost silent except for failures)" ?
|
||||
val isVerbose = "verbose" / "be more verbose (additive with --trace)" ?
|
||||
val isDebug = "debug" / "maximum debugging output" ?
|
||||
val isAnsi = "ansi" / "print output in color" ?
|
||||
val isTrace = "trace" / "show the individual steps taken by each test" --?
|
||||
val isShowDiff = "show-diff" / "show diff between log and check file" --?
|
||||
val isShowLog = "show-log" / "show log on failures" --?
|
||||
val isDryRun = "dry-run" / "do not run tests, only show their traces." --?
|
||||
val isTerse = "terse" / "be less verbose (almost silent except for failures)" --?
|
||||
val isVerbose = "verbose" / "be more verbose (additive with --trace)" --?
|
||||
val isDebug = "debug" / "maximum debugging output" --?
|
||||
val isAnsi = "ansi" / "print output in color" --?
|
||||
|
||||
heading ("Other options:")
|
||||
val timeout_ = "timeout" / "Overall timeout in seconds" |> "14400"
|
||||
val testWarning_ = "test-warning" / "Test warning in seconds" >> ; // defaults to testTimeout / 10
|
||||
val testTimeout_ = "test-timeout" / "Test timeout in seconds" >> ; // defaults to 900
|
||||
val isCleanup = "cleanup" / "delete all stale files and dirs before run" ?
|
||||
val isNoCleanup = "nocleanup" / "do not delete any logfiles or object dirs" ?
|
||||
val isStats = "stats" / "collect and print statistics about the tests" ?
|
||||
val isValidate = "validate" / "examine test filesystem for inconsistencies" ?
|
||||
val isVersion = "version" / "print version" ?
|
||||
val timeout = "timeout" / "Overall timeout in seconds" defaultTo 14400
|
||||
val testWarning = "test-warning" / "Test warning in seconds" defaultTo 90
|
||||
val testTimeout = "test-timeout" / "Test timeout in seconds" defaultTo 900
|
||||
val isCleanup = "cleanup" / "delete all stale files and dirs before run" --?
|
||||
val isNoCleanup = "nocleanup" / "do not delete any logfiles or object dirs" --?
|
||||
val isStats = "stats" / "collect and print statistics about the tests" --?
|
||||
val isValidate = "validate" / "examine test filesystem for inconsistencies" --?
|
||||
|
||||
"version" / "print version" --> runAndExit(println(Properties.versionMsg))
|
||||
|
||||
// no help for anything below this line - secret options
|
||||
// mostly intended for property configuration.
|
||||
val runsets = "runsets" |> ""
|
||||
val isNoAlarms = ("noalarms" ?)
|
||||
val isInsideAnt = ("is-in-ant" ?)
|
||||
val runSets = ("runsets" --^) getOrElse Nil
|
||||
val isNoAlarms = "noalarms" --?
|
||||
val isInsideAnt = "is-in-ant" --?
|
||||
}
|
||||
|
||||
object PartestSpecReference extends PartestSpec with CommandLineReferenceSpec {
|
||||
import CommandLineSpec._
|
||||
object PartestSpec extends PartestSpec with Property {
|
||||
lazy val propMapper = new PropertyMapper(PartestSpec) {
|
||||
override def isPassThrough(key: String) = key == "partest.options"
|
||||
}
|
||||
|
||||
def parsed: CommandLine = null
|
||||
override def creator(args: List[String]) =
|
||||
new ThisCommandLine(args) {
|
||||
override def onlyKnownOptions = true
|
||||
override def errorFn(msg: String) = printAndExit("Error: " + msg)
|
||||
}
|
||||
|
||||
def main(args: Array[String]): Unit = println(bashCompletion("partest"))
|
||||
type ThisCommandLine = PartestCommandLine
|
||||
class PartestCommandLine(args: List[String]) extends SpecCommandLine(args) {
|
||||
override def onlyKnownOptions = true
|
||||
override def errorFn(msg: String) = printAndExit("Error: " + msg)
|
||||
|
||||
def propertyArgs = PartestSpec.propertyArgs
|
||||
}
|
||||
|
||||
/** Append bash completion for partest to the given file.
|
||||
*/
|
||||
def appendCompletionTo(f: File) = f appendAll bashCompletion("partest")
|
||||
override def creator(args: List[String]): PartestCommandLine = new PartestCommandLine(args)
|
||||
}
|
||||
|
||||
|
|
|
@ -9,13 +9,10 @@ package partest
|
|||
import nsc.io._
|
||||
|
||||
object Runner {
|
||||
def main(mainArgs: Array[String]) {
|
||||
val propArgs = PartestSpecReference.sysPropsAsOptions()
|
||||
val args = (propArgs ++ mainArgs).toList
|
||||
def main(args: Array[String]) {
|
||||
val runner = Partest(args: _*)
|
||||
import runner._
|
||||
|
||||
if (isVersion) return println(versionMsg)
|
||||
if (args.isEmpty) return println(helpMsg)
|
||||
if (isValidate) return validateAll()
|
||||
|
||||
|
|
|
@ -12,19 +12,21 @@ package ant
|
|||
|
||||
import org.apache.tools.ant.Task
|
||||
import org.apache.tools.ant.taskdefs.Java
|
||||
import org.apache.tools.ant.types.{ EnumeratedAttribute, Commandline, Environment, PropertySet }
|
||||
import org.apache.tools.ant.types.Environment
|
||||
|
||||
import scala.tools.nsc.io._
|
||||
import scala.tools.nsc.util.{ ClassPath, CommandLineSpec }
|
||||
import CommandLineSpec._
|
||||
import scala.tools.nsc.util.ClassPath
|
||||
import cmd.Spec._
|
||||
|
||||
class JavaTask extends Java {
|
||||
override def getTaskName() = "partest"
|
||||
private val scalaRunnerClass = "scala.tools.nsc.MainGenericRunner"
|
||||
private val partestRunnerClass = "scala.tools.partest.Runner"
|
||||
def defaultJvmArgs = "-Xms64M -Xmx768M -Xss768K -XX:MaxPermSize=96M"
|
||||
|
||||
protected def rootDir = prop("partest.rootdir") getOrElse (baseDir / "test").path
|
||||
protected def partestJVMArgs = prop("partest.jvm.args") getOrElse "-Xms64M -Xmx768M -Xss768K -XX:MaxPermSize=96M"
|
||||
protected def runnerArgs = List("-usejavacp", "scala.tools.partest.Runner", "--javaopts", partestJVMArgs)
|
||||
protected def partestJVMArgs = prop("partest.jvm.args") getOrElse defaultJvmArgs
|
||||
protected def runnerArgs = List("-usejavacp", partestRunnerClass, "--javaopts", partestJVMArgs)
|
||||
|
||||
private def baseDir = Directory(getProject.getBaseDir)
|
||||
private def prop(s: String) = Option(getProject getProperty s)
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
/* __ *\
|
||||
** ________ ___ / / ___ Scala Parallel Testing **
|
||||
** / __/ __// _ | / / / _ | (c) 2007-2010, LAMP/EPFL **
|
||||
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
|
||||
** /____/\___/_/ |_/____/_/ | | **
|
||||
** |/ **
|
||||
\* */
|
||||
|
||||
/**** Note -- this isn't used anymore, but I left it in for the moment. ****/
|
||||
|
||||
package scala.tools
|
||||
package partest
|
||||
package ant
|
||||
|
||||
import java.io.{ File => JFile }
|
||||
|
||||
import org.apache.tools.ant.Task
|
||||
import org.apache.tools.ant.types.{ Reference, FileSet}
|
||||
|
||||
import scala.reflect.BeanProperty
|
||||
import scala.tools.ant.sabbus.CompilationPathProperty
|
||||
import scala.tools.nsc.io
|
||||
import scala.tools.nsc.util.CommandLineSpec._
|
||||
|
||||
class PartestTask extends Task with CompilationPathProperty {
|
||||
/** Used only in ant task */
|
||||
@BeanProperty protected var errorOnFailed: Boolean = _
|
||||
@BeanProperty protected var jUnitReportDir: JFile = _
|
||||
|
||||
/** Propagated to partest run via system properties */
|
||||
@BeanProperty protected var debug: Boolean = _
|
||||
@BeanProperty protected var javaOpts: String = _
|
||||
@BeanProperty protected var partestOpts: String = _
|
||||
@BeanProperty protected var runSets: String = _
|
||||
@BeanProperty protected var scalacOpts: String = _
|
||||
@BeanProperty protected var showDiff: Boolean = _
|
||||
@BeanProperty protected var showLog: Boolean = _
|
||||
@BeanProperty protected var srcDir: String = _
|
||||
@BeanProperty protected var timeout: Int = _
|
||||
|
||||
/** Translating ant information into command line arguments. */
|
||||
private def notEmpty(s: String) = s != null && s.length > 0
|
||||
private def quoted(s: String) = if (s exists (_.isWhitespace)) "\"" + s.trim + "\"" else s
|
||||
private def optionCollection = List[(Boolean, () => List[String])](
|
||||
debug -> (() => List("--debug")),
|
||||
showLog -> (() => List("--show-log")),
|
||||
showDiff -> (() => List("--show-diff")),
|
||||
(timeout > 0) -> (() => List("--timeout", timeout.toString)),
|
||||
notEmpty(javaOpts) -> (() => List("--javaopts", javaOpts)),
|
||||
notEmpty(scalacOpts) -> (() => List("--scalacopts", scalacOpts)),
|
||||
notEmpty(srcDir) -> (() => List("--srcdir", srcDir)),
|
||||
notEmpty(partestOpts) -> (() => toArgs(partestOpts))
|
||||
)
|
||||
|
||||
private def antPropOrNone(name: String) = Option(getProject getProperty name)
|
||||
private def antPropsToCommandLine() = {
|
||||
setProp("partest.isInAnt", "true")
|
||||
val partestDir = antPropOrNone("partest.dir") getOrElse error("Mandatory attribute 'partest.dir' is not set.")
|
||||
|
||||
val root = List("--rootdir", io.Path(partestDir).path)
|
||||
val opts = optionCollection collect { case (true, f) => f() } flatten
|
||||
val sets = Option(runSets).toList flatMap toArgs map toOpt
|
||||
|
||||
root ++ opts ++ sets
|
||||
}
|
||||
private def antRunTests() = {
|
||||
val args = antPropsToCommandLine()
|
||||
val runner = Partest(args: _*)
|
||||
import runner._
|
||||
|
||||
normal("Ant options translate to command line: partest " + fromArgs(args))
|
||||
printConfigBanner()
|
||||
|
||||
val result = launchTestSuite()
|
||||
val msg = result.toString
|
||||
|
||||
if (result.hasFailures && errorOnFailed) error(msg)
|
||||
else log(msg)
|
||||
}
|
||||
|
||||
override def execute() {
|
||||
try antRunTests()
|
||||
catch {
|
||||
case x =>
|
||||
System.err.println("Uncaught exception %s in partest ant ask: aborting." format x)
|
||||
x.printStackTrace()
|
||||
throw x
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,7 +5,6 @@
|
|||
package scala.tools
|
||||
|
||||
import nsc.io.{ File, Path, Process, Directory }
|
||||
import nsc.util.CommandLineSpec
|
||||
import java.nio.charset.CharacterCodingException
|
||||
|
||||
package object partest {
|
||||
|
@ -18,13 +17,12 @@ package object partest {
|
|||
|
||||
private[partest] def safeLines(f: File) = safeSlurp(f) split """\r\n|\r|\n""" toList
|
||||
private[partest] def safeArgs(f: File) = toArgs(safeSlurp(f))
|
||||
private[partest] def safeToInt(s: String) = try Some(s.toInt) catch { case _: NumberFormatException => None }
|
||||
private[partest] def isJava(f: Path) = f.isFile && (f hasExtension "java")
|
||||
private[partest] def isScala(f: Path) = f.isFile && (f hasExtension "scala")
|
||||
private[partest] def isJavaOrScala(f: Path) = isJava(f) || isScala(f)
|
||||
|
||||
private[partest] def toArgs(line: String) = CommandLineSpec toArgs line
|
||||
private[partest] def fromArgs(args: List[String]) = CommandLineSpec fromArgs args
|
||||
private[partest] def toArgs(line: String) = cmd toArgs line
|
||||
private[partest] def fromArgs(args: List[String]) = cmd fromArgs args
|
||||
|
||||
/** Strings, argument lists, etc. */
|
||||
|
||||
|
|
|
@ -75,11 +75,11 @@ if $cygwin; then
|
|||
fi
|
||||
|
||||
# Reminder: substitution ${JAVA_OPTS:=-Xmx256M -Xms16M} DO NOT work on Solaris
|
||||
[ -n "$JAVA_OPTS" ] || JAVA_OPTS="-Xms512M -Xmx1536M -Xss1M -XX:MaxPermSize=128M"
|
||||
[ -n "$JAVA_OPTS" ] || JAVA_OPTS="-Xms64M -Xmx1024M -Xss768K -XX:MaxPermSize=96M"
|
||||
[ -n "$SCALAC_OPTS" ] || SCALAC_OPTS=""
|
||||
|
||||
export SCALAC_OPTS
|
||||
export JAVA_OPTS
|
||||
# export SCALAC_OPTS
|
||||
# export JAVA_OPTS
|
||||
export JAVACMD
|
||||
|
||||
${JAVACMD:=java} $JAVA_OPTS \
|
||||
|
|
Loading…
Reference in New Issue