summaryrefslogtreecommitdiff
path: root/src/partest-alternative/scala/tools/partest/category/Compiler.scala
blob: 49775d5031474484ca3697c3c86128af3d2e8ea3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/* NEST (New Scala Test)
 * Copyright 2007-2010 LAMP/EPFL
 */

package scala.tools
package partest
package category

import nsc.io._
import nsc.reporters._
import nsc.{ Settings, CompilerCommand }
import scala.tools.nsc.interactive.RefinedBuildManager
import util.copyPath

trait Compiler {
  self: Universe =>

  /** Resident Compiler.
   *  $SCALAC -d dir.obj -Xresident -sourcepath . "$@"
   */
  object Res extends DirBasedCategory("res") {
    lazy val testSequence: TestSequence = List(checkFileRequired, compile, diff)

    override def denotesTest(p: Path)       = p.isDirectory && resFile(p).isFile
    override def createTest(location: Path) = new ResidentTest(location.toDirectory)

    override def createSettings(entity: TestEntity): TestSettings =
      returning(super.createSettings(entity)) { settings =>
        settings.resident.value   = true
        settings.sourcepath.value = entity.sourcesDir.path
      }

    class ResidentTest(val location: Directory) extends TestEntity {
      val category = Res
      override def sourcesDir     = categoryDir

      override def acknowledges(p: Path) =
        super.acknowledges(p) || (resFile(location) isSame p)

      private def residentCompilerCommands = safeLines(resFile(location))
      private def compileResident(global: PartestGlobal, lines: List[String]) = {
        def printPrompt = global inform "nsc> "
        val results =
          lines map { line =>
            printPrompt
            trace("compile " + line)
            isDryRun || global.partestCompile(toArgs(line) map (categoryDir / _ path), false)
          }

        printPrompt

        /** Note - some res tests are really "neg" style tests, so we can't
         *  use the return value of the compile.  The diff catches failures.
         */
        true  // results forall (_ == true)
      }

      override def compile() = compileResident(newGlobal(Nil)._1, residentCompilerCommands)
    }
    private[Res] def resFile(p: Path) = p.toFile addExtension "res"
  }

  object BuildManager extends DirBasedCategory("buildmanager") {
    lazy val testSequence: TestSequence = List(checkFileRequired, compile, diff)
    override def denotesTest(p: Path) = p.isDirectory && testFile(p).isFile
    override def createTest(location: Path) = new BuildManagerTest(location.toDirectory)

    override def createSettings(entity: TestEntity): TestSettings =
      returning[TestSettings](super.createSettings(entity)) { settings =>
        settings.Ybuildmanagerdebug.value = true
        settings.sourcepath.value = entity.sourcesDir.path
      }

    class PartestBuildManager(settings: Settings, val reporter: ConsoleReporter) extends RefinedBuildManager(settings) {
      def errorFn(msg: String) = Console println msg

      override protected def newCompiler(newSettings: Settings) =
        new BuilderGlobal(newSettings, reporter)

      private def filesToSet(pre: String, fs: List[String]): Set[AbstractFile] =
        fs flatMap (s => Option(AbstractFile getFile (Path(settings.sourcepath.value) / s path))) toSet

      def buildManagerCompile(line: String): Boolean = {
        val prompt = "builder > "
        reporter printMessage (prompt + line)
        val command = new CompilerCommand(toArgs(line), settings)
        val files   = filesToSet(settings.sourcepath.value, command.files)

        update(files, Set.empty)
        true
      }
    }

    private[BuildManager] def testFile(p: Path) = (p / p.name addExtension "test").toFile

    class BuildManagerTest(val location: Directory) extends TestEntity {
      val category = BuildManager

      override def sourcesDir     = outDir
      override def sourceFiles    = Path onlyFiles (location walkFilter (_ != changesDir) filter isJavaOrScala toList)
      override def checkFile      = File(location / location.name addExtension "check")

      override def acknowledges(p: Path) = super.acknowledges(p) || (p isSame testFile(location))

      def buildManagerCommands  = safeLines(testFile(location))
      def changesDir            = Directory(location / (location.name + ".changes"))

      override def compile() = {
        val settings = createSettings(this)
        val pbm      = new PartestBuildManager(settings, newReporter(settings))

        // copy files
        for (source <- sourceFiles) {
          val target = outDir / (location.normalize relativize source)
          copyPath(source, target.toFile)
        }

        def runUpdate(line: String) = {
          val Array(srcName, replacement) = line split "=>"
          copyPath(File(changesDir / replacement), File(outDir / srcName))
        }

        def sendCommand(line: String): Boolean = {
          val compileRegex  = """^>>compile (.*)$""".r
          val updateRegex   = """^>>update\s+(.*)""".r
          trace("send: " + (line drop 2))

          isDryRun || (line match {
            case compileRegex(xs)   => pbm.buildManagerCompile(xs)
            case updateRegex(line)  => runUpdate(line)
          })
        }

        // send each line to the build manager
        buildManagerCommands forall sendCommand
      }
    }
  }
}