summaryrefslogtreecommitdiff
path: root/project/build/ScalaTools.scala
diff options
context:
space:
mode:
authormoix <moix@epfl.ch>2010-07-29 09:52:28 +0000
committermoix <moix@epfl.ch>2010-07-29 09:52:28 +0000
commite3ca222e48fa917d631c1ee6ecbc8a594ae76d10 (patch)
treec5c719ee1b38d5f238ee513279fda4f8cb263283 /project/build/ScalaTools.scala
parent26bbdbe3a21d17f5b2a94ea528eb4508d2b3b13e (diff)
downloadscala-e3ca222e48fa917d631c1ee6ecbc8a594ae76d10.tar.gz
scala-e3ca222e48fa917d631c1ee6ecbc8a594ae76d10.tar.bz2
scala-e3ca222e48fa917d631c1ee6ecbc8a594ae76d10.zip
First version of SBT build for Scala compiler/l...
First version of SBT build for Scala compiler/library (see README)
Diffstat (limited to 'project/build/ScalaTools.scala')
-rw-r--r--project/build/ScalaTools.scala179
1 files changed, 179 insertions, 0 deletions
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)
+
+ }
+}
+
+