aboutsummaryrefslogblamecommitdiff
path: root/stage1/Stage1.scala
blob: 99c7b1ede334d92f95163281b6603f3b2250b2dc (plain) (tree)
1
2
3
4
5
6
7
8
           
 
                
                  
 

                                        
                                                       


                                              
                                                                       



                                                           
                                                      



                                                   
                      




                                            

                                       
                                    

 
 
                          
                                          

 



                               

                    
                                

                                   
  
                                                                                                                       
  
                                                
 
 
              

                                                
   
 
                                                                                
                                                
                                                                        
                                                        
                  
                      


                    
                                                                                      


                              



                                                
                                                                                

         


                  
                                                                                        


                                                                                                             

                        
 

                                   
                                        

                  
                             
                      

                                                    
                                                       
                                                            
 
                                                                           
 

                                                   


                                                            
 
                                                  

                                                      

                                             
                                                        
                                                     
                 
                                                  
                                                                                
     
 





                                                            
                                                       
 
















                                                                                                                                                     
                                                                        



                                        
                                                           




                                                                                                                            
                             
                                                    
             

                                                                                                                       







                                                                                                                        
                                                                





                         
                  
                                   
                                                 
            
                                                       
                                                                            

                                  

                                                                                     
 

                                                                                                                    
 
                                    

                                 
                                                                                
                                              
            
              
                                                   

                        

     
                                
                    
                 
                 
                                                          



                                              
                  




                                   
                                                           
                    
   
 
package cbt

import java.io._
import java.util._

import scala.collection.JavaConverters._

final case class Stage1ArgsParser(_args: Seq[String]) {
  /**
   * Raw parameters including their `-D` flag.
  **/
  val propsRaw: Seq[String] = _args.toVector.filter(_.startsWith("-D"))

  /**
   * All arguments that weren't `-D` property declarations.
  **/
  val args: Seq[String] = _args.toVector diff propsRaw

  /**
   * Parsed properties, as a map of keys to values.
  **/
  val props = propsRaw
    .map(_.drop(2).split("=")).map({
      case Array(key, value) =>
        key -> value
    }).toMap ++ System.getProperties.asScala

  val enabledLoggers = props.get("log")

  val tools = _args contains "tools"
}


abstract class Stage2Base{
  def run( context: Stage2Args ): ExitCode
}

class Stage2Args(
  val cwd: File,
  val args: Seq[String],
  val stage2LastModified: Long,
  val cache: File,
  val cbtHome: File,
  val compatibilityTarget: File,
  val stage2sourceFiles: Seq[File],
  val loop: Boolean
)(
  implicit val transientCache: java.util.Map[AnyRef,AnyRef], val classLoaderCache: ClassLoaderCache, val logger: Logger
){
  val persistentCache = classLoaderCache.hashMap
}

object Stage1{
  protected def newerThan( a: File, b: File ) ={
    a.lastModified > b.lastModified
  }

  def getBuild( _context: java.lang.Object, buildStage1: BuildStage1Result ) = {
    val context = _context.asInstanceOf[Context]
    val logger = new Logger( context.enabledLoggers, buildStage1.start )
    val (_, cbtLastModified, classLoader) = buildStage2(
      buildStage1,
      context.cbtHome,
      context.cache,
      context.cwd,
      context.loop
    )(context.transientCache, new ClassLoaderCache( context.persistentCache ), logger)

    classLoader
      .loadClass("cbt.Stage2")
      .getMethod( "getBuild", classOf[Context] )
      .invoke(
        null,
        context.copy(
          cbtLastModified = Math.max( context.cbtLastModified, cbtLastModified )
        )
      )
  }

  def buildStage2(
    buildStage1: BuildStage1Result, cbtHome: File, cache: File, cwd: File, loop: Boolean
  )(
    implicit transientCache: java.util.Map[AnyRef,AnyRef], classLoaderCache: ClassLoaderCache, logger: Logger
  ): (Seq[File], Long, ClassLoader) = {

    import buildStage1._

    val lib = new Stage1Lib(logger)
    import lib._
    val paths = CbtPaths(cbtHome, cache)
    import paths._

    val stage2sourceFiles = (
      stage2.listFiles
      ++ (stage2 / "plugins").listOrFail
      ++ (cbtHome / "libraries" / "eval").listOrFail
      ++ (cbtHome / "libraries" / "process").listOrFail
    ).filter(_.isFile).filter(_.toString.endsWith(".scala"))

    val cls = this.getClass.getClassLoader.loadClass("cbt.NailgunLauncher")

    def _cbtDependencies = new CbtDependencies(
      (stage2Target++".last-success").lastModified,
      mavenCache, nailgunTarget, stage1Target, stage2Target,
      new File(buildStage1.compatibilityClasspath)
    )

    logger.stage1("Compiling stage2 if necessary")
    if(loop)
      lib.addLoopFiles( cwd, stage2sourceFiles.toSet )
    val Some( stage2LastModified ) = compile(
      buildStage1.stage1LastModified,
      stage2sourceFiles, stage2Target, stage2StatusFile,
      _cbtDependencies.stage2Dependency.dependencies,
      mavenCache,
      Seq("-deprecation","-feature","-unchecked"),
      zincVersion = constants.zincVersion, scalaVersion = constants.scalaVersion
    )

    def cbtDependencies = new CbtDependencies(
      (stage2Target++".last-success").lastModified,
      mavenCache, nailgunTarget, stage1Target, stage2Target,
      new File(buildStage1.compatibilityClasspath)
    )

    logger.stage1(s"calling CbtDependency.classLoader")

    assert(
      buildStage1.compatibilityClasspath === cbtDependencies.compatibilityDependency.classpath.string,
      "compatibility classpath different from NailgunLauncher"
    )
    assert(
      buildStage1.stage1Classpath === cbtDependencies.stage1Dependency.classpath.string,
      "stage1 classpath different from NailgunLauncher"
    )
    assert(
      classLoaderCache.containsKey( cbtDependencies.compatibilityDependency.classpath.string, cbtDependencies.compatibilityDependency.lastModified ),
      "cbt unchanged, expected compatibility classloader to be cached"
    )
    assert(
      classLoaderCache.containsKey( cbtDependencies.stage1Dependency.classpath.string, cbtDependencies.stage1Dependency.lastModified ),
      "cbt unchanged, expected stage1 classloader to be cached"
    )

    val stage2ClassLoader = cbtDependencies.stage2Dependency.classLoader

    {
      // a few classloader sanity checks
      val compatibilityClassLoader =
        cbtDependencies.compatibilityDependency.classLoader
      assert(
        classOf[BuildInterface].getClassLoader == compatibilityClassLoader,
        classOf[BuildInterface].getClassLoader.toString ++ "\n\nis not the same as\n\n" ++ compatibilityClassLoader.toString
      )
      //-------------
      val stage1ClassLoader =
        cbtDependencies.stage1Dependency.classLoader
      assert(
        classOf[Stage1ArgsParser].getClassLoader == stage1ClassLoader,
        classOf[Stage1ArgsParser].getClassLoader.toString ++ "\n\nis not the same as\n\n" ++ stage1ClassLoader.toString
      )
      //-------------
      assert(
        Stage0Lib.get(stage2ClassLoader.getParent,"parents").asInstanceOf[Seq[ClassLoader]].contains(stage1ClassLoader),
        stage1ClassLoader.toString ++ "\n\nis not contained in parents of\n\n" ++ stage2ClassLoader.toString
      )
    }

    ( stage2sourceFiles, stage2LastModified, stage2ClassLoader )
  }

  def run(
    _args: Array[String],
    cache: File,
    cbtHome: File,
    loop: Boolean,
    buildStage1: BuildStage1Result,
    persistentCache: java.util.Map[AnyRef,AnyRef]
  ): Int = {
    val args = Stage1ArgsParser(_args.toVector.drop(1))
    implicit val logger = new Logger(args.enabledLoggers, buildStage1.start)
    logger.stage1(s"Stage1 start")

    implicit val transientCache: java.util.Map[AnyRef,AnyRef] = new java.util.HashMap
    implicit val classLoaderCache = new ClassLoaderCache( persistentCache )

    val cwd = new File( args.args(0) )
    val (stage2sourceFiles, stage2LastModified, classLoader) = buildStage2( buildStage1, cbtHome, cache, cwd, loop )

    val stage2Args = new Stage2Args(
      cwd,
      args.args.drop(2).toVector,
      // launcher changes cause entire nailgun restart, so no need for them here
      stage2LastModified = stage2LastModified,
      cache,
      cbtHome,
      new File(buildStage1.compatibilityClasspath),
      stage2sourceFiles,
      loop
    )

    logger.stage1(s"Run Stage2")
    val exitCode = (
      classLoader
      .loadClass(
        if(args.tools) "cbt.ToolsStage2" else "cbt.Stage2"
      )
      .getMethod( "run", classOf[Stage2Args] )
      .invoke(
        null,
        stage2Args
      ) match {
        case code: ExitCode => code
        case _ => ExitCode.Success
      }
    ).integer
    logger.stage1(s"Stage1 end with exit code " + exitCode)
    return exitCode;
  }
}