scala.tools.partest.nest.CompileManager.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of scala-partest Show documentation
Show all versions of scala-partest Show documentation
testing framework for the Scala compiler.
/* NEST (New Scala Test)
* Copyright 2007-2013 LAMP/EPFL
* @author Philipp Haller
*/
// $Id$
package scala.tools.partest
package nest
import scala.tools.nsc.{ Global, Settings, CompilerCommand, FatalError, io }
import scala.tools.nsc.io.{ File => SFile }
import scala.tools.nsc.interactive.RangePositions
import scala.tools.nsc.reporters.{ Reporter, ConsoleReporter }
import scala.tools.nsc.util.{ ClassPath, FakePos }
import scala.tools.nsc.Properties.{ setProp, propOrEmpty }
import scala.tools.util.PathResolver
import io.Path
import java.io.{ File, BufferedReader, PrintWriter, FileReader, Writer, FileWriter, StringWriter }
import File.pathSeparator
sealed abstract class CompilationOutcome {
def merge(other: CompilationOutcome): CompilationOutcome
def isPositive = this eq CompileSuccess
def isNegative = this eq CompileFailed
}
case object CompileSuccess extends CompilationOutcome {
def merge(other: CompilationOutcome) = other
}
case object CompileFailed extends CompilationOutcome {
def merge(other: CompilationOutcome) = if (other eq CompileSuccess) this else other
}
case object CompilerCrashed extends CompilationOutcome {
def merge(other: CompilationOutcome) = this
}
class ExtConsoleReporter(settings: Settings, val writer: PrintWriter) extends ConsoleReporter(settings, Console.in, writer) {
shortname = true
}
class TestSettings(cp: String, error: String => Unit) extends Settings(error) {
def this(cp: String) = this(cp, _ => ())
nowarnings.value = false
encoding.value = "UTF-8"
classpath.value = cp
}
abstract class SimpleCompiler {
def compile(out: Option[File], files: List[File], kind: String, log: File): CompilationOutcome
}
class DirectCompiler(val fileManager: FileManager) extends SimpleCompiler {
def newGlobal(settings: Settings, reporter: Reporter): Global =
if (settings.Yrangepos.value)
new Global(settings, reporter) with RangePositions
else
new Global(settings, reporter)
def newGlobal(settings: Settings, logWriter: FileWriter): Global =
newGlobal(settings, new ExtConsoleReporter(settings, new PrintWriter(logWriter)))
def newSettings(): TestSettings = new TestSettings(fileManager.LATEST_LIB)
def newSettings(outdir: String): TestSettings = {
val cp = ClassPath.join(fileManager.LATEST_LIB, outdir)
val s = new TestSettings(cp)
s.outdir.value = outdir
s
}
private def updatePluginPath(options: String): String = {
val dir = fileManager.testRootDir
def absolutize(path: String) = Path(path) match {
case x if x.isAbsolute => x.path
case x => (fileManager.testRootDir / x).toAbsolute.path
}
val (opt1, opt2) = (options split "\\s").toList partition (_ startsWith "-Xplugin:")
val plugins = opt1 map (_ stripPrefix "-Xplugin:") flatMap (_ split pathSeparator) map absolutize
val pluginOption = if (opt1.isEmpty) Nil else List("-Xplugin:" + (plugins mkString pathSeparator))
(opt2 ::: pluginOption) mkString " "
}
def compile(out: Option[File], files: List[File], kind: String, log: File): CompilationOutcome = {
val testSettings = out match {
case Some(f) => newSettings(f.getAbsolutePath)
case _ => newSettings()
}
val logWriter = new FileWriter(log)
// check whether there is a ".flags" file
val logFile = basename(log.getName)
val flagsFileName = "%s.flags" format (logFile.substring(0, logFile.lastIndexOf("-")))
val argString = (io.File(log).parent / flagsFileName) ifFile (x => updatePluginPath(x.slurp())) getOrElse ""
// slurp local flags (e.g., "A_1.flags")
val fstFile = SFile(files(0))
def isInGroup(num: Int) = fstFile.stripExtension endsWith ("_" + num)
val inGroup = (1 to 9) flatMap (group => if (isInGroup(group)) List(group) else List())
val localFlagsList = if (inGroup.nonEmpty) {
val localArgString = (fstFile.parent / (fstFile.stripExtension + ".flags")) ifFile (x => updatePluginPath(x.slurp())) getOrElse ""
localArgString.split(' ').toList.filter(_.length > 0)
} else List()
val allOpts = fileManager.SCALAC_OPTS.toList ::: argString.split(' ').toList.filter(_.length > 0) ::: localFlagsList
val args = allOpts.toList
NestUI.verbose("scalac options: "+allOpts)
val command = new CompilerCommand(args, testSettings)
val global = newGlobal(command.settings, logWriter)
val testRep: ExtConsoleReporter = global.reporter.asInstanceOf[ExtConsoleReporter]
val testFileFn: (File, FileManager) => TestFile = kind match {
case "pos" => PosTestFile.apply
case "neg" => NegTestFile.apply
case "run" => RunTestFile.apply
case "jvm" => JvmTestFile.apply
case "shootout" => ShootoutTestFile.apply
case "scalap" => ScalapTestFile.apply
case "scalacheck" => ScalaCheckTestFile.apply
case "specialized" => SpecializedTestFile.apply
case "instrumented" => InstrumentedTestFile.apply
case "presentation" => PresentationTestFile.apply
case "ant" => AntTestFile.apply
}
val test: TestFile = testFileFn(files.head, fileManager)
if (!test.defineSettings(command.settings, out.isEmpty)) {
testRep.error(FakePos("partest"), test.flags match {
case Some(flags) => "bad flags: " + flags
case _ => "bad settings: " + command.settings
})
}
val toCompile = files map (_.getPath)
try {
NestUI.verbose("compiling "+toCompile)
NestUI.verbose("with classpath: "+global.classPath.toString)
NestUI.verbose("and java classpath: "+ propOrEmpty("java.class.path"))
try new global.Run compile toCompile
catch {
case FatalError(msg) =>
testRep.error(null, "fatal error: " + msg)
return CompilerCrashed
}
testRep.printSummary()
testRep.writer.close()
}
finally logWriter.close()
if (testRep.hasErrors) CompileFailed
else CompileSuccess
}
}
class CompileManager(val fileManager: FileManager) {
private def newCompiler = new DirectCompiler(fileManager)
def attemptCompile(outdir: Option[File], sources: List[File], kind: String, log: File): CompilationOutcome =
newCompiler.compile(outdir, sources, kind, log)
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy