aboutsummaryrefslogblamecommitdiff
path: root/stage2/plugins/Dotty.scala
blob: 766e9d1c2f680364cfa6fafa54c9f4fe333a619f (plain) (tree)
1
2
3
4
5
6
7
8
9






                                       
                                          
                                       
                                                                    
 

                                                                                                                       
 

                                                                  
 
                                           
                                                                    
   
 





                                                                                                                    
                                                                           









                                                                                        
                                                                             










                                                                                                                                      
   
 
                          



                                                            
                                                            


             
                              





                                                                                            

 
               
                        
                   
                                         
                                                                                                             


                           

                                                       
                          


                                   
                                       

                        
               


     











                                                      
                                                                                                                                   
                                                                                                                           


                                                                       
                                      
                              
                                           
              

         

                                


     
              
                           

                        
                                  
                             



                                      
 



                                                                          
                              

          

                                                
                                        





                                            
                                                      
                  



                                                                                    
                                    

                                              
                                                                  

                                                                                                
                                                



                                
                                                                                                                     
                                                         

                                   
                                                       






                                                                
                 
                                                       
                                                                                         
  
                                       
 

             
                   









                                                                                                                       


                            
       


     
package cbt
import java.io.File
import java.net.URL
import java.nio.file.Files
import java.nio.file.attribute.FileTime

trait Dotty extends BaseBuild{
  def dottyVersion: String = Dotty.version
  def dottyOptions: Seq[String] = Seq()
  override def scalaTarget: File = target ++ s"/dotty-$dottyVersion"

  def dottyCompiler: DependencyImplementation = Resolver(mavenCentral).bindOne( Dotty.compilerOnMaven( dottyVersion ) )
  def dottyLibrary: DependencyImplementation = Resolver(mavenCentral).bindOne( Dotty.libraryOnMaven( dottyVersion ) )

  // this seems needed for cbt run of dotty produced artifacts
  override def dependencies: Seq[Dependency] = Seq( dottyLibrary )

  private lazy val dottyLib = new DottyLib(
    context.cbtLastModified, context.paths.mavenCache, dottyCompiler
  )

  def compileJavaFirst: Boolean = false

  // this makes sure the scala or java classes compiled first are available on subsequent compile
  override def compileDependencies: Seq[Dependency]
    = super.compileDependencies ++ Seq( compileTarget ).filter(_.exists).map( t => BinaryDependency( Seq(t), Nil ) )

  override def compile: Option[Long] = taskCache[Dotty]("compile").memoize{
    def compileDotty =
      dottyLib.compile(
        sourceFiles.filter(_.string.endsWith(".scala")),
        compileTarget, compileStatusFile, compileDependencies, dottyOptions
      )
    def compileJava =
      lib.compile(
        context.cbtLastModified,
        sourceFiles.filter(_.string.endsWith(".java")),
        compileTarget, compileStatusFile, compileDependencies, context.paths.mavenCache,
        scalacOptions, zincVersion = zincVersion, scalaVersion = scalaVersion
      )

    def set(time: Long) = if(compileStatusFile.exists) Files.setLastModifiedTime(compileStatusFile.toPath, FileTime.fromMillis(time) )

    val before = compileStatusFile.lastModified
    val firstLastModified = if(compileJavaFirst) compileJava else compileDotty
    set( before )
    val secondLastModified = if(!compileJavaFirst) compileJava else compileDotty
    val min = (firstLastModified ++ secondLastModified).reduceOption(_ min _).getOrElse(0l)
    set( min )
    Some(min)
  }

  def dottydoc: ExitCode =
    dottyLib.doc(
      sourceFiles, compileClasspath, docTarget, dottyOptions
    )

  override def repl = dottyLib.repl(context.args, classpath)
}

object Dotty{
  val groupId = "ch.epfl.lamp"
  val version: String = "0.1.1-20170203-da7d723-NIGHTLY"
  val libraryArtifactId = "dotty-library_2.11"
  val compilerArtifactId = "dotty-compiler_2.11"
  val interfacesArtifactId = "dotty-interfaces"
  def compilerOnMaven(version: String) = MavenDependency(groupId,compilerArtifactId,version)
  def libraryOnMaven(version: String) = MavenDependency(groupId,libraryArtifactId,version)
}

class DottyLib(
  cbtLastModified: Long,
  mavenCache: File,
  dottyCompiler: DependencyImplementation
)(implicit transientCache: java.util.Map[AnyRef,AnyRef], classLoaderCache: ClassLoaderCache, logger: Logger){
  val lib = new Lib(logger)
  import lib._

  def repl(args: Seq[String], classpath: ClassPath) = {
    consoleOrFail("Use `cbt direct repl` instead")
    dottyCompiler.runMain(
      "dotty.tools.dotc.repl.Main",
      Seq(
        "-bootclasspath",
        dottyCompiler.classpath.string,
        "-classpath",
        classpath.string
      ) ++ args
    )
  }

  def doc(
    sourceFiles: Seq[File],
    dependencyClasspath: ClassPath,
    docTarget: File,
    compileArgs: Seq[String]
  ): ExitCode = {
    if(sourceFiles.isEmpty){
      ExitCode.Success
    } else {
      docTarget.mkdirs
      val args = Seq(
        // FIXME: can we use compiler dependency here?
        "-bootclasspath", dottyCompiler.classpath.string, // FIXME: does this break for builds that don't have scalac dependencies?
        "-classpath", dependencyClasspath.string, // FIXME: does this break for builds that don't have scalac dependencies?
        "-d",  docTarget.toString
      ) ++ compileArgs ++ sourceFiles.map(_.toString)
      logger.lib("creating docs for source files "+args.mkString(", "))
      val exitCode = redirectOutToErr{
        dottyCompiler.runMain(
          "dotty.tools.dottydoc.DocDriver",
          args
        )
      }
      System.err.println("done")
      exitCode
    }
  }

  def compile(
    sourceFiles: Seq[File],
    compileTarget: File,
    statusFile: File,
    dependencies: Seq[Dependency],
    dottyOptions: Seq[String]
  ): Option[Long] = {
    val d = Dependencies(dependencies)
    val classpath = d.classpath
    val cp = classpath.string

    def lastModified = (
      cbtLastModified +: d.lastModified +: sourceFiles.map(_.lastModified)
    ).max

    if( sourceFiles.isEmpty ){
      None
    }else{
      val start = System.currentTimeMillis
      val lastCompiled = statusFile.lastModified
      if( lastModified > lastCompiled ){

        val _class = "dotty.tools.dotc.Main"
        val dualArgs =
          Seq(
            "-d", compileTarget.toString
          )
        val singleArgs = dottyOptions.map( "-S" ++ _ )
        val code =
          try{
            System.err.println("Compiling with Dotty to " ++ compileTarget.toString)
            compileTarget.mkdirs
            redirectOutToErr{
              dottyCompiler.runMain(
                _class,
                dualArgs ++ singleArgs ++ Seq(
                  "-bootclasspath", dottyCompiler.classpath.string
                ) ++ (
                  if(cp.isEmpty) Nil else Seq("-classpath", cp) // let's put cp last. It so long
                ) ++ sourceFiles.map(_.toString)
              )
            }
          } catch {
            case e: Exception =>
            System.err.println(red("Dotty crashed. See https://github.com/lampepfl/dotty/issues. To reproduce run:"))
            System.err.println(dottyCompiler.classLoader)
            System.out.println(s"""
java -cp \\
${dottyCompiler.classpath.strings.mkString(":\\\n")} \\
\\
${_class} \\
\\
${dualArgs.grouped(2).map(_.mkString(" ")).mkString(" \\\n")} \\
\\
${singleArgs.mkString(" \\\n")} \\
\\
-bootclasspath \\
${dottyCompiler.classpath.strings.mkString(":\\\n")} \\
${if(cp.isEmpty) "" else ("  -classpath \\\n" ++ classpath.strings.mkString(":\\\n"))} \\
\\
${sourceFiles.sorted.mkString(" \\\n")}

"""
            )
            throw e
          }

        if(code == ExitCode.Success){
          // write version and when last compilation started so we can trigger
          // recompile if cbt version changed or newer source files are seen
          write(statusFile, "")//cbtVersion.getBytes)
          Files.setLastModifiedTime(statusFile.toPath, FileTime.fromMillis(start) )
        } else {
          System.exit(code.integer) // FIXME: let's find a better solution for error handling. Maybe a monad after all.
        }
        Some( start )
      } else {
        Some( lastCompiled )
      }
    }
  }
}