|
| 1 | +/* NSC -- new Scala compiler |
| 2 | + * Copyright 2005-2018 LAMP/EPFL |
| 3 | + * @author Martin Odersky |
| 4 | + */ |
| 5 | +package scala.tools.nsc |
| 6 | + |
| 7 | +import java.nio.file.{Files, Path, Paths} |
| 8 | + |
| 9 | +import scala.collection.mutable |
| 10 | +import scala.reflect.internal.util.FakePos |
| 11 | +import scala.tools.nsc.reporters.Reporter |
| 12 | +import scala.tools.nsc.util.ClassPath |
| 13 | + |
| 14 | + |
| 15 | +class PipelineMainClass { |
| 16 | + /** Forward errors to the (current) reporter. */ |
| 17 | + protected def scalacError(msg: String): Unit = { |
| 18 | + reporter.error(FakePos("scalac"), msg + "\n scalac -help gives more information") |
| 19 | + } |
| 20 | + |
| 21 | + private var reporter: Reporter = _ |
| 22 | + def process(args: Array[String]): Boolean = { |
| 23 | + reporter = Reporter(new Settings(scalacError)) |
| 24 | + |
| 25 | + def commandFor(argFileArg: String): CompilerCommand = { |
| 26 | + val ss = new Settings(scalacError) |
| 27 | + new CompilerCommand(args.toList, ss) |
| 28 | + } |
| 29 | + val projects: List[CompilerCommand] = args.toList.map(commandFor) |
| 30 | + val produces = mutable.HashMap[Path, CompilerCommand]() |
| 31 | + for (p <- projects) { |
| 32 | + val outputDir = p.settings.outputDirs.getSingleOutput.get.file.toPath.toAbsolutePath.normalize() |
| 33 | + produces(outputDir) = p |
| 34 | + } |
| 35 | + val dependsOn = mutable.HashMap[CompilerCommand, List[CompilerCommand]]() |
| 36 | + for (p <- projects) { |
| 37 | + val value: Seq[String] = ClassPath.expandPath(p.settings.classpath.value, expandStar = true) |
| 38 | + dependsOn(p) = value.flatMap(s => produces.get(Paths.get(s).toAbsolutePath.normalize())).toList |
| 39 | + } |
| 40 | + var toProcess = projects.toList |
| 41 | + val done = mutable.HashSet[CompilerCommand]() |
| 42 | + while (toProcess.nonEmpty) { |
| 43 | + val (nextRound, blocked) = toProcess.partition(x => dependsOn.getOrElse(x, Nil).forall(done)) |
| 44 | + toProcess = blocked |
| 45 | + for (p <- nextRound) { |
| 46 | + if (!compile(p)) return false |
| 47 | + done += p |
| 48 | + } |
| 49 | + } |
| 50 | + true |
| 51 | + } |
| 52 | + |
| 53 | + def compile(command: CompilerCommand): Boolean = { |
| 54 | + val compiler = newCompiler(command.settings) |
| 55 | + reporter = compiler.reporter |
| 56 | + try { |
| 57 | + if (reporter.hasErrors) |
| 58 | + reporter.flush() |
| 59 | + else if (command.shouldStopWithInfo) |
| 60 | + reporter.echo(command.getInfoMessage(compiler)) |
| 61 | + else |
| 62 | + doCompile(command, compiler) |
| 63 | + } catch { |
| 64 | + case ex: Throwable => |
| 65 | + compiler.reportThrowable(ex) |
| 66 | + ex match { |
| 67 | + case FatalError(msg) => // signals that we should fail compilation. |
| 68 | + case _ => throw ex // unexpected error, tell the outside world. |
| 69 | + } |
| 70 | + } |
| 71 | + !reporter.hasErrors |
| 72 | + } |
| 73 | + |
| 74 | + protected def newCompiler(settings: Settings): Global = Global(settings) |
| 75 | + |
| 76 | + protected def doCompile(command: CompilerCommand, compiler: Global): Unit = { |
| 77 | + if (command.files.isEmpty) { |
| 78 | + reporter.echo(command.usageMsg) |
| 79 | + reporter.echo(compiler.pluginOptionsHelp) |
| 80 | + } else { |
| 81 | + val run = new compiler.Run() |
| 82 | + run compile command.files |
| 83 | + reporter.finish() |
| 84 | + } |
| 85 | + } |
| 86 | + |
| 87 | + |
| 88 | + def main(args: Array[String]): Unit = System.exit(if (process(args)) 0 else 1) |
| 89 | +} |
| 90 | + |
| 91 | +object PipelineMain extends PipelineMainClass {} |
0 commit comments