From e3ca222e48fa917d631c1ee6ecbc8a594ae76d10 Mon Sep 17 00:00:00 2001 From: moix Date: Thu, 29 Jul 2010 09:52:28 +0000 Subject: First version of SBT build for Scala compiler/l... First version of SBT build for Scala compiler/library (see README) --- README | 16 +- docs/licences/apache_ant.txt | 16 ++ lib/ant/ant.jar.desired.sha1 | 1 + project/build.properties | 11 ++ project/build/AdditionalResources.scala | 103 +++++++++++++ project/build/BasicLayer.scala | 266 ++++++++++++++++++++++++++++++++ project/build/Compilation.scala | 86 +++++++++++ project/build/CompilationStep.scala | 38 +++++ project/build/ExternalTaskRunner.scala | 34 ++++ project/build/Packer.scala | 89 +++++++++++ project/build/Partest.scala | 160 +++++++++++++++++++ project/build/PathConfig.scala | 38 +++++ project/build/SVN.scala | 34 ++++ project/build/ScalaSBTBuilder.scala | 179 +++++++++++++++++++++ project/build/ScalaTools.scala | 179 +++++++++++++++++++++ project/build/Scaladoc.scala | 51 ++++++ 16 files changed, 1298 insertions(+), 3 deletions(-) create mode 100644 docs/licences/apache_ant.txt create mode 100644 lib/ant/ant.jar.desired.sha1 create mode 100644 project/build.properties create mode 100644 project/build/AdditionalResources.scala create mode 100644 project/build/BasicLayer.scala create mode 100644 project/build/Compilation.scala create mode 100644 project/build/CompilationStep.scala create mode 100644 project/build/ExternalTaskRunner.scala create mode 100644 project/build/Packer.scala create mode 100755 project/build/Partest.scala create mode 100644 project/build/PathConfig.scala create mode 100644 project/build/SVN.scala create mode 100644 project/build/ScalaSBTBuilder.scala create mode 100644 project/build/ScalaTools.scala create mode 100644 project/build/Scaladoc.scala diff --git a/README b/README index 106503399b..69b0c7532f 100644 --- a/README +++ b/README @@ -36,6 +36,10 @@ scala/ ant/ Support libraries for the build tool. ant-contrib.jar Provides additional features for Ant vizant.jar Provides DOT graph generation for Ant + project/ All that is needed to use SBT for building + boot/ † SBT storage (for download,...) + build/ The class files that defines the build project + build.properties Various SBT project variables README The file you are currently reading. sandbox/ † A folder to test code etc. src/ All the source files of Scala. @@ -43,6 +47,7 @@ scala/ compiler/ The sources of the Scala compiler. library/ The sources of the core Scala library. swing/ The sources of the Swing library. + target/ † Temporary staging area for build products from the SBT script. test/ The Scala test suite. Part II. Building Scala with SABBUS @@ -82,8 +87,7 @@ compiler without an intermediate build. On the other hand, if building the library requires changes in the compiler, a new locker must be built if bootstrapping is still possible, or a new starr if it is not. -Part III. Requirements for SABBUS --------------------------------------------------------------------------------- +REQUIREMENTS FOR SABBUS: The Scala build system is based on Apache Ant. Most required pre-compiled libraries are part of the repository (in 'lib/'). The following however is @@ -91,7 +95,13 @@ assumed to be installed on the build machine: - A Java runtime environment (JRE) or SDK 1.6 or above. - Apache Ant version 1.7.0 or above. -Part IV. Common use cases + +Part III. Using SBT as an alternative +-------------------------------------------------------------------------------- +It is now possible to use SBT as an alternative to build Scala. This is still in beta stage. +More informations and usage instruction at http://lampsvn.epfl.ch/trac/scala/wiki/SBT + +Part IV. Common use-cases -------------------------------------------------------------------------------- 'ant -p' diff --git a/docs/licences/apache_ant.txt b/docs/licences/apache_ant.txt new file mode 100644 index 0000000000..ac637d760d --- /dev/null +++ b/docs/licences/apache_ant.txt @@ -0,0 +1,16 @@ +Scala includes Ant as a library needed for build with sbt + +Copyright © 1999-2010, The Apache Software Foundation. + http://ant.apache.org/ + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/lib/ant/ant.jar.desired.sha1 b/lib/ant/ant.jar.desired.sha1 new file mode 100644 index 0000000000..852b3397cb --- /dev/null +++ b/lib/ant/ant.jar.desired.sha1 @@ -0,0 +1 @@ +7b456ca6b93900f96e58cc8371f03d90a9c1c8d1 ?ant.jar diff --git a/project/build.properties b/project/build.properties new file mode 100644 index 0000000000..28be1ccc24 --- /dev/null +++ b/project/build.properties @@ -0,0 +1,11 @@ +#Project properties +#Sun Apr 11 14:24:47 CEST 2010 +project.name=scala +def.scala.version=2.7.7 +sbt.version=0.7.4 +copyright=Copyright 2002-2010, LAMP/EPFL +build.scala.versions=2.7.7 +project.initialize=false +project.organization=ch.epfl.lamp +partest.version.number=0.9.2 +project.version=2.8.0 \ No newline at end of file diff --git a/project/build/AdditionalResources.scala b/project/build/AdditionalResources.scala new file mode 100644 index 0000000000..3db7fe6ed2 --- /dev/null +++ b/project/build/AdditionalResources.scala @@ -0,0 +1,103 @@ +import sbt._ +import java.util.jar.{Manifest} +import java.io.{FileInputStream} +import AdditionalResources._ +/** + * Additional tasks that are required to obtain a complete compiler and library pair, but that are not part of the + * compilation task. It copies additional files and generates the properties files + * @author Grégory Moix + */ +trait AdditionalResources { + self : BasicLayer => + + lazy val copyAdditionalFiles = task { + def copy0(steps:List[Step]):Option[String]= steps match{ + case x::xs => x match{ + case c:ResourcesToCopy => { + c.copy orElse copy0(xs) + } + case _ => copy0(xs) + } + case Nil => None + } + copy0(allSteps.topologicalSort) + }.dependsOn(externalCompilation) + + lazy val writeProperties = task { + def write0(steps:List[Step]):Option[String]= steps match{ + case x::xs => x match{ + case c:PropertiesToWrite => { + c.writeProperties orElse write0(xs) + } + case _ => write0(xs) + } + case Nil => None + } + write0(allSteps.topologicalSort) + }.dependsOn(externalCompilation) + + + + +} + +import sbt._ +import BasicLayer._ +object AdditionalResources { + /** + * A FileFilter that defines what are the files that will be copied + */ + lazy val basicFilter = "*.tmpl" | "*.xml"| "*.js"| "*.css" | "*.properties" | "*.swf" | "*.png" + +} + +trait ResourcesToCopy { + self : CompilationStep => + def getResources(from:Path,filter:FileFilter):PathFinder = (from ##)** filter + def getResources(from:Path):PathFinder = getResources(from,AdditionalResources.basicFilter) + + def copyDestination:Path + def filesToCopy:PathFinder + def copy = { + try{ + FileUtilities.copy(filesToCopy.get,copyDestination,log) + }catch{ + case e=>Some(e.toString) + } + None + } +} + +trait PropertiesToWrite { + self : CompilationStep => + + def propertyList:List[Tuple2[String,String]] + def propertyDestination:Path + + def writeProperties:Option[String]={ + import java.io._ + import java.util.Properties + + val properties = new Properties + + def insert(list:List[Tuple2[String,String]]):Unit=list match{ + case Nil => + case x::xs => { + properties setProperty(x._1, x._2) + insert(xs) + } + } + + try{ + insert(propertyList) + val destFile = propertyDestination.asFile + val stream = new FileOutputStream(destFile) + properties.store(stream, null) + }catch{ + case e => Some(e.toString) + } + None + } + +} + diff --git a/project/build/BasicLayer.scala b/project/build/BasicLayer.scala new file mode 100644 index 0000000000..a28b593c1a --- /dev/null +++ b/project/build/BasicLayer.scala @@ -0,0 +1,266 @@ +import sbt._ +import xsbt.{ScalaInstance} +import BasicLayer._ +import scala.collection.immutable.{EmptyMap} + +/** + * Basic tasks and configuration shared by all layers. This class regroups the configuration and behaviour + * shared by all layers. + * @author Grégory Moix + */ +abstract class BasicLayer(val info:ProjectInfo,val versionNumber:String, previousLayer:Option[BasicLayer]) extends Project with ReflectiveProject + with AdditionalResources with Compilation{ + override def dependencies = info.dependencies + lazy val projectRoot = info.projectPath + + lazy val copyright = property[String] + lazy val partestVersionNumber = property[Version] + + + /** + * Before compiling the layer, we need to check that the previous layer + * was created correctly and compile it if necessary + */ + lazy val startLayer = previousLayer match { + case Some(previous) => task{ + None + }.dependsOn(previous.finishLayer) + case None => task{None} + } + + lazy val build= task{ + None + }.dependsOn(externalCompilation,copyAdditionalFiles,writeProperties) + + /** + * Finish the compilation and ressources copy and generation + * It does nothing in itself. As sbt doesn't support conditional dependencies, + * it permit locker to override it in order to lock the layer when the compilation + * is finished. + */ + lazy val finishLayer = task{None}.dependsOn(build) + + 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) + } + + // All path values must be lazy in order to avoid initialization issues (sbt way of doing things) + lazy val layerOutput = outputRootPath / name + lazy val pathLayout = new PathLayout(projectRoot, layerOutput) + lazy val manifestPath = projectRoot/"META-INF"/"MANIFEST.MF" + + // Utility methods (for quick access) + def libraryOutput = libraryConfig.outputDirectory + def actorsOutput = actorsConfig.outputDirectory + def dbcOutput = dbcConfig.outputDirectory + def swingOutput = swingConfig.outputDirectory + def scalapOutput = scalapConfig.outputDirectory + def librarySrcDir = libraryConfig.srcDir + def compilerOutput = compilerConfig.outputDirectory + def compilerSrcDir = compilerConfig.srcDir + def actorsSrcDir = actorsConfig.srcDir + def swingSrcDir = swingConfig.srcDir + def outputLibraryJar = libraryWS.jarDestination + def outputCompilerJar = compilerConfig.jarDestination + def outputPartestJar = partestConfig.jarDestination + def outputScalapJar = scalapConfig.jarDestination + + // CONFIGURATION OF THE COMPILTATION STEPS + + /** + * Configuration of the core library compilation + */ + lazy val libraryConfig = new CompilationStep("library", pathLayout ,log) with ResourcesToCopy with PropertiesToWrite{ + def label = "["+name+"] library" + def options: Seq[String] = Seq("-sourcepath", pathConfig.sources.absolutePath.toString) + def dependencies = Nil + override def classpath = super.classpath +++ forkJoinJar + + def copyDestination = outputDirectory + def filesToCopy = getResources(srcDir) + + def propertyDestination = outputDirectory / "library.properties" + def propertyList = ("version.number",versionNumber)::("copyright.string",copyright.value)::Nil + } + + /** + * Configuration of the compiler + */ + lazy val compilerConfig = new CompilationStep("compiler", pathLayout, log) with ResourcesToCopy with PropertiesToWrite with Packaging{ + def label = "["+name+"] compiler" + private def bootClassPath : String = { + System.getProperty("sun.boot.class.path") + } + override def classpath: PathFinder = super.classpath +++ fjbgJar +++ msilJar +++ jlineJar +++ antJar +++ forkJoinJar + def options = Seq("-bootclasspath",bootClassPath) + def dependencies = if (minimalCompilation) libraryConfig::Nil else libraryConfig::actorsConfig::dbcConfig::swingConfig::Nil + + def copyDestination = outputDirectory + def filesToCopy = getResources(srcDir) + + def propertyDestination = outputDirectory / "compiler.properties" + def propertyList = ("version.number",versionNumber)::("copyright.string",copyright.value)::Nil + + def packagingDestination:Path = packingDestination + def jarName:String = compilerJarName + override def jarsToInclude = compilerAdditionalJars + override def manifest = { + import java.util.jar.Manifest + import java.io.FileInputStream + new Manifest(new FileInputStream(manifestPath.asFile)) + } + override def jarContent = List(outputDirectory ##) + + } + + /** + * Config of the actors library + */ + lazy val actorsConfig = new CompilationStep ("actors", pathLayout,log){ + def label = "["+name+"] actors library" + override def classpath: PathFinder = super.classpath +++ forkJoinJar + def options: Seq[String] = Seq() + def dependencies = libraryConfig::Nil + } + + /** + * Config of the dbc library + */ + lazy val dbcConfig = new CompilationStep("dbc", pathLayout, log) with Packaging{ + def label = "["+name+"] dbc library" + def options: Seq[String] = Seq() + def dependencies = libraryConfig::Nil + + def packagingDestination=packingDestination + def jarName = dbcJarName + def jarContent = List(outputDirectory ##) + + } + + /** + * Config of the swing library + */ + lazy val swingConfig = new CompilationStep("swing", pathLayout, log) with Packaging{ + def label = "["+name+"] swing library" + def options: Seq[String] = Seq() + def dependencies = libraryConfig::actorsConfig::Nil + + def packagingDestination=packingDestination + def jarName = swingJarName + def jarContent = List(outputDirectory ##) + + } + + + /** + * Configuration of scalap tool + */ + lazy val scalapConfig = new CompilationStep("scalap", pathLayout,log) with Packaging{ + def label = "["+name+"] scalap" + def options: Seq[String] = Seq() + def dependencies = libraryConfig::compilerConfig::Nil + + def packagingDestination=packingDestination + def jarName = scalapJarName + def jarContent = { + val decoderProperties = (srcDir ## )/ "decoder.properties" + + List(outputDirectory ##, decoderProperties) + } + } + + /** + * Configuration of the partest tool + */ + lazy val partestConfig = new CompilationStep("partest", pathLayout,log) with ResourcesToCopy with PropertiesToWrite with Packaging{ + def label = "["+name+"] partest" + override def classpath: PathFinder = super.classpath +++ antJar +++ forkJoinJar + def options: Seq[String] = Seq() + def dependencies = libraryConfig::compilerConfig::scalapConfig::actorsConfig::Nil + + def copyDestination = outputDirectory + def filesToCopy = getResources(srcDir) + + def propertyDestination = outputDirectory / "partest.properties" + def propertyList = ("version.number",partestVersionNumber.value.toString)::("copyright.string",copyright.value)::Nil + + def packagingDestination=packingDestination + def jarName = partestJarName + def jarContent = List(outputDirectory ##) + } + + // Grouping compilation steps + def minimalCompilation = false // It must be true for locker because we do not nedd to compile everything + + def libraryWS:WrapperStep with Packaging + def toolsWS:WrapperStep + + + lazy val allSteps = new WrapperStep(libraryWS::compilerConfig::toolsWS::Nil) + + + + + + //Needed Libraries + //TODO Check if not possible to manage some of them with the sbt dependency management (ivy) + lazy val lib = projectRoot / "lib" + lazy val forkJoinJar = lib / forkJoinJarName + lazy val jlineJar = lib / jlineJarName + lazy val antJar = lib / "ant" / "ant.jar" + lazy val fjbgJar = lib / fjbgJarName + lazy val msilJar = lib / msilJarName + + + + + //Paths location that must be defined layer by layer + /* + * We must define which are the libraries used to instantiate the compiler + * that will be used to compile this layer. + */ + def instantiationCompilerJar:Path + def instantiationLibraryJar:Path + def packingDestination :Path = layerOutput / "pack" + def compilerAdditionalJars: List[Path] = Nil + def libraryAdditionalJars: List[Path] = Nil + + + /** + * Environment for storing properties that + * 1) need to be saved across sbt session + * 2) Are local to a layer + * Used to save the last version of the compiler used to build the layer (for discarding it's product if necessary) + */ + lazy val layerEnvironment = new BasicEnvironment { + // use the project's Logger for any properties-related logging + def log = BasicLayer.this.log + + // the properties file will be read from/stored to project/extra.properties + def envBackingPath = outputRootPath / ("build-"+name+".properties") + + // define some properties that will go in project/extra.properties + lazy val lastCompilerVersion:Property[String] = propertyOptional[String]("") + } +} + +object BasicLayer{ + // Some path definitions related strings + val compilerJarName = "scala-compiler.jar" + val libraryJarName = "scala-library.jar" + val scalapJarName = "scalap.jar" + val dbcJarName = "scala-dbc.jar" + val swingJarName = "scala-swing.jar" + val partestJarName = "scala-partest.jar" + val fjbgJarName = "fjbg.jar" + val msilJarName = "msil.jar" + val jlineJarName = "jline.jar" + val forkJoinJarName = "forkjoin.jar" + + implicit def stringToGlob(s:String):NameFilter=GlobFilter(s) + + + +} diff --git a/project/build/Compilation.scala b/project/build/Compilation.scala new file mode 100644 index 0000000000..42e3c55902 --- /dev/null +++ b/project/build/Compilation.scala @@ -0,0 +1,86 @@ +import sbt._ +import xsbt.{AnalyzingCompiler,ScalaInstance} + +/** + * This trait define the compilation task. It is possible to configure what it actually compiles by + * overriding the compilationSteps methods (useful because locker does not compile everything) + * @author Grégory Moix + */ +trait Compilation{ + self : BasicLayer => + + + def lastUsedCompilerVersion = layerEnvironment.lastCompilerVersion + + def cleanCompilation:Option[String]= { + log.info("Cleaning the products of the compilation.") + FileUtilities.clean(layerOutput::Nil,true,log) + } + + /** + * Execute the different compilation parts one after the others. + */ + def compile: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:Option[String]={ + if (compilerVersionHasChanged){ + log.info("The compiler version used to build this layer has changed since last time.") + lastUsedCompilerVersion.update(scala.actualVersion) + layerEnvironment.saveEnvironment + cleanCompilation + }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 compile0(xs) + } + case _ => compile0(xs) + } + case Nil => None + } + + + checkAndClean orElse compile0(allSteps.topologicalSort) + } + } + + /** + * 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} + + /** + * Runs the compilation in another process in order to circumvent memory issues that + * arises when compiling every layer on the same jvm. + */ + lazy val externalCompilation:ManagedTask=task{ + val runner = new ExternalTaskRunner(projectRoot,this.name,compilation.name, log) + runner.runTask + }.dependsOn(startLayer) + + /** + * This method permits to specify what are the different steps of the compilation process, + * meaning that you can customize exactly what is compiled by overriding it. It is overriden by + * the locker layer that doesn't compile actors, sbc, scalap, partest + */ + def compilationSteps:List[CompileConfiguration] = + libraryConfig::actorsConfig::dbcConfig::swingConfig::compilerConfig::scalapConfig::partestConfig::Nil + +} diff --git a/project/build/CompilationStep.scala b/project/build/CompilationStep.scala new file mode 100644 index 0000000000..02d76b9a54 --- /dev/null +++ b/project/build/CompilationStep.scala @@ -0,0 +1,38 @@ +import sbt._ +import BasicLayer._ +trait Step extends Dag[Step] { + def dependencies:Iterable[Step] +} + +class WrapperStep(contents:List[Step]) extends Step{ + def dependencies = contents +} + +abstract class CompilationStep(val name:String, val pathConfig:PathConfig, logger:Logger) extends CompileConfiguration with Step { + def this(name:String, layout:PathLayout,logger:Logger) = this(name, layout / name, logger) + + // Utility methods (for quick access, ...) + def srcDir = pathConfig.sources + + // Methods required for the compilation + def log: Logger = logger + def sourceRoots : PathFinder = pathConfig.sources + def sources: PathFinder = sourceRoots.descendentsExcept("*.java" | "*.scala", ".svn") + def projectPath: Path = pathConfig.projectRoot + def analysisPath: Path = pathConfig.analysis + def outputDirectory: Path = pathConfig.output + def classpath = { + def addDependenciesOutputTo(list:List[Step],acc:PathFinder):PathFinder = list match{ + case Nil => acc + case x::xs => x match{ + case c:CompilationStep => addDependenciesOutputTo(xs,acc +++ c.outputDirectory) + case w:WrapperStep => addDependenciesOutputTo(xs, addDependenciesOutputTo(dependencies.toList,acc)) + } + } + addDependenciesOutputTo(dependencies.toList,outputDirectory) + } + def javaOptions: Seq[String] = Seq ("-target","1.5","-source","1.5","-g:none") + def maxErrors: Int = 100 + def compileOrder = CompileOrder.JavaThenScala + def fingerprints = Fingerprints(Nil,Nil) +} diff --git a/project/build/ExternalTaskRunner.scala b/project/build/ExternalTaskRunner.scala new file mode 100644 index 0000000000..c9ad97b970 --- /dev/null +++ b/project/build/ExternalTaskRunner.scala @@ -0,0 +1,34 @@ +import sbt._ +import ExternalTaskRunner._ + +/** + * Provide a way to launch a specific task in a new sbt instance. + * As the compilation process need to be able to compile in a different process (due to memory related + * performance issue) and that in order to keep incremental compilation, we allow to launch a task from a + * specific project / sub-project in a different instance of sbt that disappear once the task has finished. + */ +class ExternalTaskRunner(root:Path,projectName:String, taskName :String, log: Logger ){ + + def runTask:Option[String] ={ + + val cmd:Seq[String] = Seq("project "+projectName,taskName) // TODO forward logging level (for example debug) + val externalSbt = Process(sbtCommand ++ cmd) + log.info("Launching task ["+taskName+"] of project ["+projectName+"] in new sbt instance") + externalSbt.! match{ + case 0 => None + case _ => Some("External Task Failed") + } + + } + +} + +object ExternalTaskRunner{ + /** + * parameters needed to launch another instance of sbt + */ + val sbtCommand = Seq("sbt") // TODO remove dependency on sbt being on the path of the user + + + +} \ No newline at end of file diff --git a/project/build/Packer.scala b/project/build/Packer.scala new file mode 100644 index 0000000000..8e3be9d9a3 --- /dev/null +++ b/project/build/Packer.scala @@ -0,0 +1,89 @@ +import sbt._ +import java.io.{File,FileInputStream} +import java.util.jar.Manifest +import BasicLayer._ +import FileUtilities._ + +/** + * Create the jars of pack + * @author Grégory Moix + */ +trait Packer { + self: BasicLayer => + + def libraryToCopy:List[Path] = Nil + + protected def jarPattern(path:PathFinder) = path.descendentsExcept(AllPassFilter, defaultExcludes || new ExactFilter("MANIFEST.MF")).get + + def createJar(j:Packaging):Option[String] = { + def pack0(content:Iterable[Path])=jar(content.flatMap(jarPattern(_)),j.jarDestination, j.manifest, false, log) + j.jarsToInclude match { + case Nil => pack0(j.jarContent) + case list => { + withTemporaryDirectory(log) { tmp: File => + val tmpPath = Path.fromFile(tmp) + log.debug("List of jars to be added : " +list) + def unzip0(l:List[Path]):Option[String] = l match { + case x::xs => {unzip(x,tmpPath,log);unzip0(xs)} //TODO properly handle failing of unzip + case Nil => None + } + unzip0(list) + log.debug("Content of temp folder"+ tmpPath.##.**( GlobFilter("*"))) + pack0(j.jarContent ++ Set(tmpPath ##)) + } + } + } + } + + lazy val pack= task { + + def iterate(steps:List[Step]):Option[String]= steps match{ + case x::xs => x match{ + case c:Packaging => { + createJar(c) orElse iterate(xs) + } + case _ => iterate(xs) + } + case Nil => None + } + + def copy0 ={ + copyFile(manifestPath,packingDestination/"META-INF"/"MANIFEST.MF",log) orElse { + copy(libraryToCopy,packingDestination , true,true,log) match { + case Right(_) => None + case Left(e) => Some(e) + } + } + } + iterate(allSteps.topologicalSort) orElse copy0 + }.dependsOn(finishLayer) + + + +} + +trait Packaging extends Step{ + def manifest = new Manifest + def jarDestination:Path = packagingDestination /"lib" / jarName + def packagingDestination:Path + def jarName:String + def jarsToInclude:List[Path] = Nil + def jarContent:Iterable[Path] + +} + +trait WrapperPackaging extends Packaging { + self : WrapperStep => + + def jarContent = { + def getContent(list:List[Step],acc:List[Path]):List[Path]= list match { + case Nil => acc + case x::xs => x match { + case w:WrapperStep => getContent(xs,getContent(w.dependencies.toList,acc)) + case c:CompilationStep => getContent(xs,(c.outputDirectory ##)::acc) + } + } + getContent(dependencies.toList,Nil) + } + +} diff --git a/project/build/Partest.scala b/project/build/Partest.scala new file mode 100755 index 0000000000..b971c668d9 --- /dev/null +++ b/project/build/Partest.scala @@ -0,0 +1,160 @@ +/* +import sbt._ +import java.io.File +import java.net.URLClassLoader + +trait PartestRunner{ + self: BasicLayer with Packer => + import Partest._ + lazy val testRoot = projectRoot / "test" + lazy val testFiles = testRoot / "files" + lazy val testLibs = testFiles / "lib" + lazy val testSuite= task{ + val config = new TestConfiguration( + outputLibraryJar, + (outputLibraryJar +++ outputCompilerJar +++ outputPartestJar +++ outputScalapJar +++ antJar +++ jlineJar +++ (testLibs * "*.jar")).get, + (testFiles /"pos") * "*.scala", + (testFiles /"neg") * "*.scala", + (testFiles / "run") ** "*.scala", + (testFiles /"jvm") * "*.scala", + (testFiles / "res") * "*.res", + (testFiles / "buildmanager"), + Path.emptyPathFinder, + (testFiles/ "shootout") * "*.scala", + (testFiles /"scalap") ** "*.scala" + ) + val javaHome = Path.fromFile(new File(System.getProperty("java.home"))) + val java = javaHome / "bin" / "java" + val javac = javaHome / "bin" / "javac" + + runTest(config,Some(java.asFile),Some(javac.asFile),None,Some("2400000"), false,true,false,true,false,log) + } + +} + + +class TestConfiguration(val library:Path, val classpath:Iterable[Path], + posFiles:PathFinder,negFiles:PathFinder,runFiles:PathFinder, jvmFiles:PathFinder, + residentFiles:PathFinder,buildManagerFiles:PathFinder,scriptFiles:PathFinder, + shootoutFiles:PathFinder,scalapFiles:PathFinder){ + + + private def getFilesAndDirs(path:PathFinder):Array[File]={ + ( path * AllPassFilter --- (path * ((new ExactFilter(".svn")) || GlobFilter("*.obj")))).getFiles.toArray + } + + private def getPosFiles = getFilesAndDirs(posFiles) + private def getNegFiles = getFilesAndDirs(negFiles) + private def getRunFiles = getFilesAndDirs(runFiles) + private def getJvmFiles = getFilesAndDirs(jvmFiles) + private def getResidentFiles = getFilesAndDirs(residentFiles) + private def getBuildManagerFiles = getFilesAndDirs(buildManagerFiles) + private def getScriptFiles = getFilesAndDirs(scriptFiles) + private def getShootoutFiles = getFilesAndDirs(shootoutFiles) + private def getScalapFiles = getFilesAndDirs(scalapFiles) + + lazy val testFileSets = List( + (getPosFiles, "pos", "Compiling files that are expected to build"), + (getNegFiles, "neg", "Compiling files that are expected to fail"), + (getRunFiles, "run", "Compiling and running files"), + (getJvmFiles, "jvm", "Compiling and running files"), + (getResidentFiles, "res", "Running resident compiler scenarii"), + (getBuildManagerFiles, "buildmanager", "Running Build Manager scenarii"), + (getScriptFiles, "script", "Running script files"), + (getShootoutFiles, "shootout", "Running shootout tests"), + (getScalapFiles, "scalap", "Running scalap tests") + ) + + +} +*/ +/** + * Based on scala.tools.partest.PartestTask + */ +/* +object Partest{ + + def runTest(config:TestConfiguration,javacmd:Option[File],javaccmd:Option[File],scalacOpts:Option[String],timeout:Option[String], + showDiff:Boolean,showLog:Boolean,runFailed:Boolean,errorOnFailed:Boolean,debug:Boolean,log:Logger):Option[String] = { + if (debug) + System.setProperty("partest.debug", "true") + + if (config.classpath.isEmpty) + return Some("The classpath is empty") + + + val classloader = new URLClassLoader(Array(config.classpath.toSeq.map(_.asURL):_*)) + + val antRunner: AnyRef = + classloader.loadClass("scala.tools.partest.nest.AntRunner").newInstance().asInstanceOf[AnyRef] + val antFileManager: AnyRef = + antRunner.getClass.getMethod("fileManager", Array[Class[_]](): _*).invoke(antRunner, Array[Object](): _*) + + val runMethod = + antRunner.getClass.getMethod("reflectiveRunTestsForFiles", Array(classOf[Array[File]], classOf[String]): _*) + + def runTestsForFiles(kindFiles: Array[File], kind: String): (Int, Int) = { + val result = runMethod.invoke(antRunner, Array(kindFiles, kind): _*).asInstanceOf[Int] + (result >> 16, result & 0x00FF) + } + + def setFileManagerBooleanProperty(name: String, value: Boolean) { + val setMethod = + antFileManager.getClass.getMethod(name+"_$eq", Array(classOf[Boolean]): _*) + setMethod.invoke(antFileManager, Array(java.lang.Boolean.valueOf(value)).asInstanceOf[Array[Object]]: _*) + } + + def setFileManagerStringProperty(name: String, value: String) { + val setMethod = + antFileManager.getClass.getMethod(name+"_$eq", Array(classOf[String]): _*) + setMethod.invoke(antFileManager, Array(value).asInstanceOf[Array[Object]]: _*) + } + + setFileManagerBooleanProperty("showDiff", showDiff) + setFileManagerBooleanProperty("showLog", showLog) + setFileManagerBooleanProperty("failed", runFailed) + if (!javacmd.isEmpty) + setFileManagerStringProperty("JAVACMD", javacmd.get.getAbsolutePath) + if (!javaccmd.isEmpty) + setFileManagerStringProperty("JAVAC_CMD", javaccmd.get.getAbsolutePath) + setFileManagerStringProperty("CLASSPATH", config.classpath.mkString(File.pathSeparator)) + setFileManagerStringProperty("LATEST_LIB", config.library.absolutePath) + if (!scalacOpts.isEmpty) + setFileManagerStringProperty("SCALAC_OPTS", scalacOpts.get) + if (!timeout.isEmpty) + setFileManagerStringProperty("timeout", timeout.get) + + type TFSet = (Array[File], String, String) + + val testFileSets = config.testFileSets + + def runSet(set: TFSet): (Int, Int) = { + val (files, name, msg) = set + if (files.isEmpty) (0, 0) + else { + log.info(msg) + runTestsForFiles(files, name) + } + } + + val _results = testFileSets map runSet + val allSuccesses = (_results map (_._1)).foldLeft(0)(_+_) + val allFailures = (_results map (_._2)).foldLeft(0)(_+_) + + def f(msg:String):Option[String] = + if (errorOnFailed && allFailures > 0) Some(msg) + else { + log.info(msg) + None + } + def s = if (allFailures > 1) "s" else "" + val msg = + if (allFailures > 0) "Test suite finished with %d case%s failing.".format(allFailures, s) + else if (allSuccesses == 0) "There were no tests to run." + else "Test suite finished with no failures." + + f(msg) + } + + +}*/ diff --git a/project/build/PathConfig.scala b/project/build/PathConfig.scala new file mode 100644 index 0000000000..3410f7c8e5 --- /dev/null +++ b/project/build/PathConfig.scala @@ -0,0 +1,38 @@ +import sbt._ + +/** + * An abstract class for grouping all different paths that are needed to + * compile the a CompilationStep + * @author Grégory Moix + */ +abstract class PathConfig { + def projectRoot:Path + def sources:Path + def analysis:Path + def output:Path +} + +/** + * + */ + +class PathLayout(val projectRoot:Path, val outputDir:Path) { + lazy val srcDir = projectRoot / "src" + lazy val classesOutput = outputDir / " classes" + lazy val analysisOutput = outputDir / "analysis" + + /** + * An utility method to easily create StandardPathConfig from a given path layout + */ + def /(name:String)= new StandardPathConfig(this, name) +} + +/** + * + */ +class StandardPathConfig(layout: PathLayout, name:String) extends PathConfig{ + lazy val projectRoot = layout.projectRoot + lazy val sources = layout.srcDir / name + lazy val analysis = layout.analysisOutput / name + lazy val output = layout.classesOutput / name +} diff --git a/project/build/SVN.scala b/project/build/SVN.scala new file mode 100644 index 0000000000..78624f3ba7 --- /dev/null +++ b/project/build/SVN.scala @@ -0,0 +1,34 @@ +import sbt._ +import java.io.{ByteArrayOutputStream} +import scala.util.matching.{Regex} + +/** + * @param root the root of an svn repository + * @author Moix Grégory + */ +class SVN(root:Path){ + + /** + * Gets the revision number of the repository given through the constructor of the class + * It assumes that svn is installed on the running computer. + */ + def getRevisionNumber:Int = { + val svnInfo = Process("svn info", root) + var result=0 + val out= new ByteArrayOutputStream + val code:Int = svnInfo.#>(out).! + if(code == 0) { + val r = out.toString + val Pattern = new Regex("""Revision: (\d+)""","version") + val version = Pattern.findFirstMatchIn(r) + version match { + case Some(s)=> result=Integer.parseInt(s.group("version")) + case None => throw new UnableToGetRevisionNumberException + } + } else { + throw new UnableToGetRevisionNumberException + } + result + } +} +class UnableToGetRevisionNumberException extends RuntimeException \ No newline at end of file diff --git a/project/build/ScalaSBTBuilder.scala b/project/build/ScalaSBTBuilder.scala new file mode 100644 index 0000000000..10b90247bb --- /dev/null +++ b/project/build/ScalaSBTBuilder.scala @@ -0,0 +1,179 @@ +import sbt._ +import BasicLayer._ + +/** + * This class is the entry point for building scala with SBT. + * @author Grégory Moix + */ +class ScalaSBTBuilder(val info: ProjectInfo) extends Project with ReflectiveProject { + override def dependencies: Iterable[Project] = info.dependencies ++ locker.dependencies ++ quick.dependencies ++ strap.dependencies + override def shouldCheckOutputDirectories = false + + // Main Tasks + + lazy val replaceLocker=task{None}.dependsOn(locker.unlock) + lazy val build = task{None}.dependsOn(quick.binPack,quick.binQuick) + lazy val docs = quick.scaladoc + + // Top level variables + + /** + * The version number of the compiler that will be created by the run of sbt. It is initialised once + * the first time it is needed, meaning that this number will be kept + * until sbt quit. + */ + lazy val versionNumber:String ={ + def getTimeString:String ={ + import java.util.Calendar; + import java.text.SimpleDateFormat; + val formatString = "yyyyMMddHHmmss" + new SimpleDateFormat(formatString) format( Calendar.getInstance.getTime) + } + def getVersion:String ={ + val version:String = projectVersion.value.toString + val stopIndex = version.lastIndexOf('-') + stopIndex match{ + case -1 => version + case i => version substring(0,i) + } + } + def getRevision:Int = { + new SVN(info.projectPath).getRevisionNumber + } + + getVersion+".r"+getRevision+"-b"+getTimeString + } + + + + /* LAYER DEFINITIONS + * We define here what's specific to each layer are they differ. + * The common behavior is defined in the BasicLayer class + * It is important that the class that extends BasicLayer are inner classes of ScalaSBTBuilder. If not, SBT will + * not know what the main project definition is, as it will find many classes that extends Project + */ + + lazy val locker=project(info.projectPath,"locker", new LockerLayer(_)) + lazy val quick=project(info.projectPath,"quick",new QuickLayer(_,locker)) + lazy val strap=project(info.projectPath,"strap", new StrapLayer(_, quick)) + + /** + * Definition of what is specific to the locker layer. It implements SimplePacker in order to + * be able to create palo (packed locker) + */ + class LockerLayer(info:ProjectInfo) extends BasicLayer(info,versionNumber,None) with Packer{ + + import BasicLayer._ + + lazy val instantiationCompilerJar = lib / compilerJarName + lazy val instantiationLibraryJar = lib / libraryJarName + lazy val lockFile = layerOutput / "locker.lock" + + /** + * We override the definition of the task method in order to make the tasks of this layer + * be executed only if the layer is not locked. Task of this layer that should be executed + * whether the layer is locked or not should call super.task instead + */ + override def task(action : => Option[String])= + super.task{ + if (lockFile.exists) { + log.info(name +" is locked") + None + } + else action + } + + /** + * Task for locking locker + */ + lazy val lock = super.task{ + log.info("locking "+name) + FileUtilities.touch(lockFile,log) + } + + /** + * Task for unlocking locker + */ + lazy val unlock = super.task{ + FileUtilities.clean(lockFile,log) + } + + /** + * Making locker being locked when it has finished building + */ + override lazy val finishLayer = lock.dependsOn(build) + + + override lazy val packingDestination:Path = outputRootPath /"palo" + + /** + * We must override the compilation steps as we only want to compile + * the core library (and not actors,dbc, scalap, partest) + */ + override lazy val libraryWS = { + new WrapperStep(libraryConfig::Nil) with WrapperPackaging{ + def jarName = libraryJarName + def packagingDestination = packingDestination + } + } + override val minimalCompilation = true + override lazy val toolsWS = new WrapperStep(Nil) + } + + + /** + * Definition of what is specific to the quick layer. It implements Packer in order to create pack, ScalaTools + * for creating the binaries and Scaladoc to generate the documentation + */ + class QuickLayer(info:ProjectInfo, previous:BasicLayer) extends BasicLayer(info,versionNumber,Some(previous)) + with Packer with ScalaTools with Scaladoc{ + + lazy val instantiationCompilerJar = previous.compilerOutput + lazy val instantiationLibraryJar = previous.libraryOutput + + + override lazy val packingDestination:Path = outputRootPath/ "pack" + override def libraryToCopy = jlineJar::Nil + override def compilerAdditionalJars = msilJar::fjbgJar::Nil + override def libraryAdditionalJars = forkJoinJar::Nil + + + override lazy val libraryWS = new WrapperStep(libraryConfig::actorsConfig::dbcConfig::swingConfig::Nil)with Packaging{ + def jarName = libraryJarName + def packagingDestination = packingDestination + def jarContent = List(libraryConfig.outputDirectory ## , actorsConfig.outputDirectory ## ) + override def jarsToInclude = libraryAdditionalJars + } + override lazy val toolsWS = new WrapperStep(scalapConfig::partestConfig::Nil) + + + + /* + * Defining here the creation of the binaries for quick and pack + */ + private lazy val quickBinClasspath = libraryOutput::actorsOutput::dbcOutput::swingOutput::compilerOutput::scalapOutput::forkJoinJar::fjbgJar::msilJar::jlineJar::Nil + private lazy val packBinClasspath = Nil + lazy val binQuick = tools(layerOutput / "bin", quickBinClasspath).dependsOn(finishLayer) + lazy val binPack = tools(packingDestination / "bin", packBinClasspath).dependsOn(pack) + + + } + + + /** + * Definition of what is specific to the strap layer + */ + class StrapLayer(info:ProjectInfo, previous:BasicLayer) extends BasicLayer(info,versionNumber,Some(previous)) { + + lazy val instantiationCompilerJar = previous.compilerOutput + lazy val instantiationLibraryJar = previous.libraryOutput + + override lazy val libraryWS = new WrapperStep(libraryConfig::actorsConfig::dbcConfig::swingConfig::Nil) with WrapperPackaging{ + def jarName = libraryJarName + def packagingDestination = packingDestination + } + + override lazy val toolsWS= new WrapperStep(scalapConfig::partestConfig::Nil) + + } +} diff --git a/project/build/ScalaTools.scala b/project/build/ScalaTools.scala new file mode 100644 index 0000000000..a182498467 --- /dev/null +++ b/project/build/ScalaTools.scala @@ -0,0 +1,179 @@ +import java.io.{FileInputStream, File, InputStream, FileWriter} +import sbt._ +import scala.io._ + +/** + * Create the scala binaries + * Based on scala.tools.ant.ScalaTool + * @author Grégory Moix (for the sbt adaptation) + */ +trait ScalaTools{ + self:BasicLayer => + + lazy val templatesLocation = compilerConfig.srcDir/ "scala" / "tools" / "ant" / "templates" + lazy val unixTemplate = templatesLocation / "tool-unix.tmpl" + lazy val winTemplate = templatesLocation / "tool-windows.tmpl" + + + // XXX encoding and generalize + private def getResourceAsCharStream(resource: Path): Stream[Char] = { + val stream = new FileInputStream(resource.asFile) + def streamReader():Stream[Char]= stream.read match{ + case -1 => Stream.empty + case value => Stream.cons(value.asInstanceOf[Char], streamReader()) + + } + if (stream == null) { + log.debug("Stream was null") + Stream.empty + } + + //else Stream continually stream.read() takeWhile (_ != -1) map (_.asInstanceOf[Char]) // Does not work in scala 2.7.7 + else streamReader + } + + + // Converts a variable like @SCALA_HOME@ to ${SCALA_HOME} when pre = "${" and post = "}" + private def transposeVariableMarkup(text: String, pre: String, post: String) : String = { + val chars = Source.fromString(text) + val builder = new StringBuilder() + + while (chars.hasNext) { + val char = chars.next + if (char == '@') { + var char = chars.next + val token = new StringBuilder() + while (chars.hasNext && char != '@') { + token.append(char) + char = chars.next + } + if (token.toString == "") + builder.append('@') + else + builder.append(pre + token.toString + post) + } else builder.append(char) + } + builder.toString + } + + private def readAndPatchResource(resource: Path, tokens: Map[String, String]): String = { + val chars = getResourceAsCharStream(resource).elements + val builder = new StringBuilder() + + while (chars.hasNext) { + val char = chars.next + if (char == '@') { + var char = chars.next + val token = new StringBuilder() + while (chars.hasNext && char != '@') { + token.append(char) + char = chars.next + } + if (tokens.contains(token.toString)) + builder.append(tokens(token.toString)) + else if (token.toString == "") + builder.append('@') + else + builder.append("@" + token.toString + "@") + } else builder.append(char) + } + builder.toString + } + + private def writeFile(file: File, content: String, makeExecutable:Boolean):Option[String] = + if (file.exists() && !file.canWrite()) + Some("File " + file + " is not writable") + else { + val writer = new FileWriter(file, false) + writer.write(content) + writer.close() + file.setExecutable(makeExecutable) + None + } + + /** Gets the value of the classpath attribute in a Scala-friendly form. + * @return The class path as a list of files. */ + private def getUnixclasspath(classpath:List[String]): String = + transposeVariableMarkup(classpath.mkString("", ":", "").replace('\\', '/'), "${", "}") + + /** Gets the value of the classpath attribute in a Scala-friendly form. + * @return The class path as a list of files. */ + private def getWinclasspath(classpath:List[String]): String = + transposeVariableMarkup(classpath.mkString("", ";", "").replace('/', '\\'), "%", "%") + + /** Performs the tool creation of a tool with for a given os + * @param file + * @param mainClas + * @param properties + * @param javaFlags + * @param toolFlags + * @param classPath + * @param template + * @param classpathFormater + */ + private def tool(template:Path,classpathFormater: List[String]=>String, file:Path,mainClass:String, + properties:String,javaFlags:String,toolFlags:String,classPath:List[Path],makeExecutable:Boolean):Option[String] = { + val patches = Map ( + ("class", mainClass), + ("properties", properties), + ("javaflags", javaFlags), + ("toolflags", toolFlags), + ("classpath", classpathFormater(classPath.map(_.absolutePath))) + ) + + val result = readAndPatchResource(template,patches) + writeFile(file.asFile,result,makeExecutable) + + } + private def generateTool(config:ToolConfiguration):Option[String] = + generateTool(config.toolName,config.destination,config.mainClass,config.properties,config.javaFlags,config.toolFlags,config.classPath) + + private def generateTool(toolName:String,destination:Path,mainClass:String, properties:String,javaFlags:String,toolFlags:String,classPath:List[Path]):Option[String] ={ + val unixFile = destination / toolName + val winFile = destination /(toolName + ".bat") + tool(unixTemplate,getUnixclasspath,unixFile,mainClass, properties,javaFlags,toolFlags,classPath,true) orElse + tool(winTemplate,getWinclasspath,winFile,mainClass, properties,javaFlags,toolFlags,classPath,false) + } + + + /*============================================================================*\ + ** Definition of the different tools ** + \*============================================================================*/ + private val defaultJavaFlags = "-Xmx256M -Xms32M" + + /** + * A class that holds the different parameters of a tool + */ + class ToolConfiguration(val toolName:String, val destination:Path, val mainClass:String, val properties:String, val javaFlags:String,val toolFlags:String,val classPath:List[Path]) + + /** + * Generate all tools + * @param destination Root folder where all the binaries will be written + * @param classpath Should be specified when you want to use a specific classpath, could be Nil if you want + * to make the bin use what is in the lib folder of the distribution. + */ + def tools(destination:Path,classpath:List[Path]) = task{ + val scala = new ToolConfiguration("scala", destination, "scala.tools.nsc.MainGenericRunner", "",defaultJavaFlags, "", classpath) + val scalac = new ToolConfiguration("scalac", destination, "scala.tools.nsc.Main", "",defaultJavaFlags, "", classpath) + val scaladoc = new ToolConfiguration("scaladoc",destination,"scala.tools.nsc.ScalaDoc", "",defaultJavaFlags,"", classpath) + val fsc = new ToolConfiguration("fsc", destination,"scala.tools.nsc.CompileClient", "",defaultJavaFlags, "", classpath) + val scalap = new ToolConfiguration("scalap",destination, "scala.tools.scalap.Main", "",defaultJavaFlags, "", classpath) + + + val toolList = scala ::scalac::scaladoc::fsc::scalap::Nil + + def process(list:List[ToolConfiguration]):Option[String] = list match{ + case x::xs => { + log.debug("Generating "+x.toolName+" bin") + generateTool(x) orElse process(xs) + } + case Nil => None + + } + FileUtilities.createDirectory(destination,log) + process(toolList) + + } +} + + diff --git a/project/build/Scaladoc.scala b/project/build/Scaladoc.scala new file mode 100644 index 0000000000..d96fd4e3ae --- /dev/null +++ b/project/build/Scaladoc.scala @@ -0,0 +1,51 @@ +import sbt._ +import xsbt.AnalyzingCompiler + +trait Scaladoc{ + self:BasicLayer with Packer => + + lazy val documentationDestination = outputRootPath / "scaladoc" + lazy val libraryDocumentationDestination = documentationDestination / "library" + lazy val compilerDocumentationDestination = documentationDestination / "compiler" + lazy val libraryDoc= { + val reflect = librarySrcDir / "scala" / "reflect" + val runtime = librarySrcDir / "scala" / "runtime" + + ((librarySrcDir +++ actorsSrcDir +++ swingSrcDir)**("*.scala")--- + reflect / "Code.scala" --- + reflect / "Manifest.scala" --- + reflect / "Print.scala" --- + reflect / "Symbol.scala" --- + reflect / "Tree.scala" --- + reflect / "Type.scala" --- + reflect / "TypedCode.scala" --- + runtime /"ScalaRunTime.scala" --- + runtime / "StreamCons.scala" --- + runtime / "StringAdd.scala" --- + runtime * ("*$.scala") --- + runtime *("*Array.scala") + ) + + } + lazy val compilerDoc = { + compilerSrcDir **("*.scala") + } + lazy val classpath ={ + (antJar +++ jlineJar +++ msilJar +++ fjbgJar +++ forkJoinJar +++ outputLibraryJar +++ outputCompilerJar +++ outputPartestJar +++ outputScalapJar ).get + + } + lazy val scaladoc = task{ + val externalSbt = new ExternalTaskRunner(projectRoot,this.name,generateScaladoc.name,log) + externalSbt.runTask + }.dependsOn(pack) + + lazy val generateScaladoc=task{ + instanceScope[Option[String]]{ scala => + lazy val compiler = new AnalyzingCompiler(scala,componentManager,xsbt.ClasspathOptions.manual,log) + val docGenerator = new sbt.Scaladoc(50,compiler) + docGenerator("Scala "+ versionNumber+" API", libraryDoc.get, classpath, libraryDocumentationDestination, Seq(), log) orElse + docGenerator("Scala Compiler"+ versionNumber+" API", compilerDoc.get, classpath, compilerDocumentationDestination, Seq(), log) + } + } + +} -- cgit v1.2.3