11
11
import scala.tools.nsc.{ Global, Settings, CompilerCommand, FatalError, io }
12
import scala.tools.nsc.io.{ File => SFile }
13
import scala.tools.nsc.interactive.RangePositions
12
14
import scala.tools.nsc.reporters.{ Reporter, ConsoleReporter }
13
15
import scala.tools.nsc.util.{ ClassPath, FakePos }
16
import scala.tools.nsc.Properties.{ setProp, propOrEmpty }
14
17
import scala.tools.util.PathResolver
16
19
import java.io.{ File, BufferedReader, PrintWriter, FileReader, Writer, FileWriter, StringWriter }
17
20
import File.pathSeparator
22
sealed abstract class CompilationOutcome {
23
def merge(other: CompilationOutcome): CompilationOutcome
24
def isPositive = this eq CompileSuccess
25
def isNegative = this eq CompileFailed
27
case object CompileSuccess extends CompilationOutcome {
28
def merge(other: CompilationOutcome) = other
30
case object CompileFailed extends CompilationOutcome {
31
def merge(other: CompilationOutcome) = if (other eq CompileSuccess) this else other
33
case object CompilerCrashed extends CompilationOutcome {
34
def merge(other: CompilationOutcome) = this
19
37
class ExtConsoleReporter(settings: Settings, val writer: PrintWriter) extends ConsoleReporter(settings, Console.in, writer) {
23
41
class TestSettings(cp: String, error: String => Unit) extends Settings(error) {
24
42
def this(cp: String) = this(cp, _ => ())
26
deprecation.value = true
27
44
nowarnings.value = false
28
encoding.value = "ISO-8859-1"
45
encoding.value = "UTF-8"
29
46
classpath.value = cp
32
49
abstract class SimpleCompiler {
33
def compile(out: Option[File], files: List[File], kind: String, log: File): Boolean
50
def compile(out: Option[File], files: List[File], kind: String, log: File): CompilationOutcome
36
53
class DirectCompiler(val fileManager: FileManager) extends SimpleCompiler {
37
54
def newGlobal(settings: Settings, reporter: Reporter): Global =
38
new Global(settings, reporter)
55
if (settings.Yrangepos.value)
56
new Global(settings, reporter) with RangePositions
58
new Global(settings, reporter)
40
60
def newGlobal(settings: Settings, logWriter: FileWriter): Global =
41
61
newGlobal(settings, new ExtConsoleReporter(settings, new PrintWriter(logWriter)))
71
91
val logWriter = new FileWriter(log)
73
93
// check whether there is a ".flags" file
74
val flagsFileName = "%s.flags" format (basename(log.getName) dropRight 4) // 4 is "-run" or similar
94
val logFile = basename(log.getName)
95
val flagsFileName = "%s.flags" format (logFile.substring(0, logFile.lastIndexOf("-")))
75
96
val argString = (io.File(log).parent / flagsFileName) ifFile (x => updatePluginPath(x.slurp())) getOrElse ""
76
val allOpts = fileManager.SCALAC_OPTS+" "+argString
77
val args = (allOpts split "\\s").toList
98
// slurp local flags (e.g., "A_1.flags")
99
val fstFile = SFile(files(0))
100
def isInGroup(num: Int) = fstFile.stripExtension endsWith ("_" + num)
101
val inGroup = (1 to 9) flatMap (group => if (isInGroup(group)) List(group) else List())
102
val localFlagsList = if (inGroup.nonEmpty) {
103
val localArgString = (fstFile.parent / (fstFile.stripExtension + ".flags")) ifFile (x => updatePluginPath(x.slurp())) getOrElse ""
104
localArgString.split(' ').toList.filter(_.length > 0)
107
val allOpts = fileManager.SCALAC_OPTS.toList ::: argString.split(' ').toList.filter(_.length > 0) ::: localFlagsList
108
val args = allOpts.toList
79
110
NestUI.verbose("scalac options: "+allOpts)
117
153
finally logWriter.close()
155
if (testRep.hasErrors) CompileFailed
123
// class ReflectiveCompiler(val fileManager: ConsoleFileManager) extends SimpleCompiler {
124
// import fileManager.{latestCompFile, latestPartestFile}
126
// val sepUrls = Array(latestCompFile.toURI.toURL, latestPartestFile.toURI.toURL)
127
// //NestUI.verbose("constructing URLClassLoader from URLs "+latestCompFile+" and "+latestPartestFile)
129
// val sepLoader = new java.net.URLClassLoader(sepUrls, null)
131
// val sepCompilerClass =
132
// sepLoader.loadClass("scala.tools.partest.nest.DirectCompiler")
133
// val sepCompiler = sepCompilerClass.newInstance()
135
// // needed for reflective invocation
136
// val fileClass = Class.forName("java.io.File")
137
// val stringClass = Class.forName("java.lang.String")
138
// val sepCompileMethod =
139
// sepCompilerClass.getMethod("compile", fileClass, stringClass)
140
// val sepCompileMethod2 =
141
// sepCompilerClass.getMethod("compile", fileClass, stringClass, fileClass)
143
// /* This method throws java.lang.reflect.InvocationTargetException
144
// * if the compiler crashes.
145
// * This exception is handled in the shouldCompile and shouldFailCompile
146
// * methods of class CompileManager.
148
// def compile(out: Option[File], files: List[File], kind: String, log: File): Boolean = {
149
// val res = sepCompileMethod2.invoke(sepCompiler, out, files, kind, log).asInstanceOf[java.lang.Boolean]
150
// res.booleanValue()
154
160
class CompileManager(val fileManager: FileManager) {
155
var compiler: SimpleCompiler = new DirectCompiler(fileManager)
157
var numSeparateCompilers = 1
158
def createSeparateCompiler() = {
159
numSeparateCompilers += 1
160
compiler = new /*ReflectiveCompiler*/ DirectCompiler(fileManager)
163
/* This method returns true iff compilation succeeds.
165
def shouldCompile(files: List[File], kind: String, log: File): Boolean = {
166
createSeparateCompiler()
167
compiler.compile(None, files, kind, log)
170
/* This method returns true iff compilation succeeds.
172
def shouldCompile(out: File, files: List[File], kind: String, log: File): Boolean = {
173
createSeparateCompiler()
174
compiler.compile(Some(out), files, kind, log)
177
/* This method returns true iff compilation fails
178
* _and_ the compiler does _not_ crash or loop.
180
* If the compiler crashes, this method returns false.
182
def shouldFailCompile(files: List[File], kind: String, log: File): Boolean = {
183
createSeparateCompiler()
184
!compiler.compile(None, files, kind, log)
187
/* This method returns true iff compilation fails
188
* _and_ the compiler does _not_ crash or loop.
190
* If the compiler crashes, this method returns false.
192
def shouldFailCompile(out: File, files: List[File], kind: String, log: File): Boolean = {
193
createSeparateCompiler()
194
!compiler.compile(Some(out), files, kind, log)
161
private def newCompiler = new DirectCompiler(fileManager)
162
def attemptCompile(outdir: Option[File], sources: List[File], kind: String, log: File): CompilationOutcome =
163
newCompiler.compile(outdir, sources, kind, log)