import sbt._ import xsbt.{AnalyzingCompiler,ScalaInstance} import FileUtilities._ /** * This trait define the compilation task. * @author Grégory Moix */ trait Compilation { self : ScalaBuildProject with BuildInfoEnvironment => def lastUsedCompilerVersion = layerEnvironment.lastCompilerVersion def instantiationCompilerJar:Path def instantiationLibraryJar:Path def instanceScope[A](action: ScalaInstance => A):A={ val instance = ScalaInstance(instantiationLibraryJar.asFile, instantiationCompilerJar.asFile, info.launcher, msilJar.asFile, fjbgJar.asFile) log.debug("Compiler will be instantiated by :" +instance.compilerJar +" and :" +instance.libraryJar ) action(instance) } def compile(stepList:Step,clean:()=>Option[String]):Option[String]=compile(stepList,Some(clean)) def compile(stepList:Step):Option[String]=compile(stepList,None) /** * Execute the different compilation parts one after the others. */ def compile(stepsList:Step,clean:Option[()=>Option[String]]):Option[String]={ instanceScope[Option[String]]{ scala => lazy val analyzing = new AnalyzingCompiler(scala,componentManager,xsbt.ClasspathOptions.manual,log) def compilerVersionHasChanged:Boolean={ val lastVersion = lastUsedCompilerVersion.value !(lastVersion.compareTo(scala.actualVersion) == 0) } def checkAndClean(cleanFunction:()=>Option[String]):Option[String]={ if (compilerVersionHasChanged){ log.info("The compiler version used to build this layer has changed since last time or this is a clean build.") lastUsedCompilerVersion.update(scala.actualVersion) layerEnvironment.saveEnvironment cleanFunction() }else{ log.debug("The compiler version is unchanged. No need for cleaning.") None } } def compile0(steps:List[Step]):Option[String]= steps match{ case x::xs => x match{ case c:CompilationStep => { val conditional = new CompileConditional(c, analyzing) log.info("") conditional.run orElse copy(c) orElse earlyPackaging(c) orElse compile0(xs) } case _ => compile0(xs) } case Nil => None } /** * When we finishe to compile a step we want to jar if necessary in order to * be able to load plugins for the associated library */ def earlyPackaging(step:CompilationStep):Option[String]= step match { case s:EarlyPackaging => { val c = s.earlyPackagingConfig log.debug("Creating jar for plugin") jar(c.content.flatMap(Packer.jarPattern(_)),c.jarDestination,c.manifest, false, log) } case _ => None } def copy(step:CompilationStep):Option[String]= step match { case s:ResourcesToCopy => s.copy case _ => None } def cleanIfNecessary:Option[String] = clean match{ case None => None case Some(f) => checkAndClean(f) } cleanIfNecessary orElse compile0(stepsList.topologicalSort) } } } trait LayerCompilation extends Compilation{ self : BasicLayer => protected def cleanCompilation:Option[String]= { log.info("Cleaning the products of the compilation.") FileUtilities.clean(layerOutput::Nil,true,log) } /** * Run the actual compilation. Should not be called directly because it is executed on the same jvm and that * it could lead to memory issues. It is used only when launching a new sbt process to do the compilation. */ lazy val compilation = task{compile(allSteps,cleanCompilation _)} def externalCompilation:Option[String] = { val runner = new ExternalTaskRunner(projectRoot,this.name,compilation.name,"Error during external compilation", log) runner.runTask } }