diff options
author | Jan Christopher Vogt <oss.nsp@cvogt.org> | 2016-09-28 21:29:26 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-09-28 21:29:26 -0400 |
commit | 9d3c9e9087a6dc0a4445f9428e02f6e7612470c6 (patch) | |
tree | ab1aef0726e71ff1ad760b6574489dc20b2d1950 | |
parent | ab5ebf2577146b6d8e7c54db4d6bf9ba6230ab57 (diff) | |
parent | 9b4b9e0c7a747972229fe9dbabe4b6e546c29f4d (diff) | |
download | cbt-9d3c9e9087a6dc0a4445f9428e02f6e7612470c6.tar.gz cbt-9d3c9e9087a6dc0a4445f9428e02f6e7612470c6.tar.bz2 cbt-9d3c9e9087a6dc0a4445f9428e02f6e7612470c6.zip |
Merge pull request #235 from cvogt/dotty
Dotty plugin and example project.
-rw-r--r-- | examples/dotty-example/README.md | 3 | ||||
-rw-r--r-- | examples/dotty-example/build/build.scala | 2 | ||||
-rw-r--r-- | examples/dotty-example/src/Main.scala | 11 | ||||
-rw-r--r-- | stage1/Stage1Lib.scala | 16 | ||||
-rw-r--r-- | stage2/plugins/Dotty.scala | 172 | ||||
-rw-r--r-- | test/simple-fixed/build/build.scala | 1 | ||||
-rw-r--r-- | test/simple/build/build.scala | 1 | ||||
-rw-r--r-- | test/test.scala | 30 |
8 files changed, 220 insertions, 16 deletions
diff --git a/examples/dotty-example/README.md b/examples/dotty-example/README.md new file mode 100644 index 0000000..bc0f6b0 --- /dev/null +++ b/examples/dotty-example/README.md @@ -0,0 +1,3 @@ +Dotty example project compiling hello world with the next version of Scala. + +All you need to do to enable Dotty is `extends Dotty` in your build.scala . diff --git a/examples/dotty-example/build/build.scala b/examples/dotty-example/build/build.scala new file mode 100644 index 0000000..eb67d93 --- /dev/null +++ b/examples/dotty-example/build/build.scala @@ -0,0 +1,2 @@ +import cbt._ +class Build(val context: Context) extends Dotty diff --git a/examples/dotty-example/src/Main.scala b/examples/dotty-example/src/Main.scala new file mode 100644 index 0000000..1963b51 --- /dev/null +++ b/examples/dotty-example/src/Main.scala @@ -0,0 +1,11 @@ +object Main extends Foo("Hello Dotty - trait parameters, yay"){ + def main(args: Array[String]) = { + println(hello) + + // Sanity check the classpath: this won't run if the dotty jar is not present. + val x: Int => Int = z => z + x(1) + } +} + +trait Foo(val hello: String) diff --git a/stage1/Stage1Lib.scala b/stage1/Stage1Lib.scala index bbb6f7b..c427b77 100644 --- a/stage1/Stage1Lib.scala +++ b/stage1/Stage1Lib.scala @@ -101,13 +101,19 @@ class Stage1Lib( val logger: Logger ) extends BaseLib{ } else ExitCode.Success } - def runMain(cls: String, args: Seq[String], classLoader: ClassLoader ): ExitCode = { + def runMain( cls: String, args: Seq[String], classLoader: ClassLoader, fakeInstance: Boolean = false ): ExitCode = { + import java.lang.reflect.Modifier logger.lib(s"Running $cls.main($args) with classLoader: " ++ classLoader.toString) trapExitCode{ - classLoader - .loadClass(cls) - .getMethod( "main", classOf[Array[String]] ) - .invoke( null, args.toArray.asInstanceOf[AnyRef] ) + val c = classLoader.loadClass(cls) + val m = c.getMethod( "main", classOf[Array[String]] ) + val instance = + if(!fakeInstance) null else c.newInstance + assert( + fakeInstance || (m.getModifiers & java.lang.reflect.Modifier.STATIC) > 0, + "Cannot run non-static method " ++ cls+".main" + ) + m.invoke( instance, args.toArray.asInstanceOf[AnyRef] ) ExitCode.Success } } diff --git a/stage2/plugins/Dotty.scala b/stage2/plugins/Dotty.scala new file mode 100644 index 0000000..50255d5 --- /dev/null +++ b/stage2/plugins/Dotty.scala @@ -0,0 +1,172 @@ +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 = "0.1-20160926-ec28ea1-NIGHTLY" + def dottyOptions: Seq[String] = Seq() + override def scalaTarget: File = target ++ s"/dotty-$dottyVersion" + + private lazy val dottyLib = new DottyLib( + logger, context.cbtHasChanged, context.paths.mavenCache, + context.classLoaderCache, dottyVersion = dottyVersion + ) + + private object compileCache extends Cache[Option[File]] + override def compile: Option[File] = compileCache{ + dottyLib.compile( + needsUpdate || context.parentBuild.map(_.needsUpdate).getOrElse(false), + sourceFiles, compileTarget, compileStatusFile, compileClasspath, + dottyOptions + ) + } + + def doc: ExitCode = + dottyLib.doc( + sourceFiles, compileClasspath, docTarget, dottyOptions + ) + + def repl = dottyLib.repl(context.args, classpath) + + override def dependencies = Resolver(mavenCentral).bind( + ScalaDependency( "org.scala-lang.modules", "scala-java8-compat", "0.8.0-RC7" ) + ) +} + +class DottyLib( + logger: Logger, + cbtHasChanged: Boolean, + mavenCache: File, + classLoaderCache: ClassLoaderCache, + dottyVersion: String +){ + val lib = new Lib(logger) + import lib._ + + private def Resolver(urls: URL*) = MavenResolver(cbtHasChanged, mavenCache, urls: _*) + private lazy val dottyDependency = Resolver(mavenCentral).bindOne( + MavenDependency("ch.epfl.lamp","dotty_2.11",dottyVersion) + ) + + def repl(args: Seq[String], classpath: ClassPath) = { + consoleOrFail("Use `cbt direct repl` instead") + lib.runMain( + "dotty.tools.dotc.repl.Main", + Seq( + "-bootclasspath", + dottyDependency.classpath.string, + "-classpath", + classpath.string + ) ++ args, + dottyDependency.classLoader(classLoaderCache) + ) + } + + 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", dottyDependency.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{ + runMain( + "dotty.tools.dottydoc.api.java.Dottydoc", + args, + dottyDependency.classLoader(classLoaderCache), + fakeInstance = true // this is a hack as Dottydoc's main method is not static + ) + } + System.err.println("done") + exitCode + } + } + + def compile( + needsRecompile: Boolean, + files: Seq[File], + compileTarget: File, + statusFile: File, + classpath: ClassPath, + dottyOptions: Seq[String] + ): Option[File] = { + + if(classpath.files.isEmpty) + throw new Exception("Trying to compile with empty classpath. Source files: " ++ files.toString) + + if( files.isEmpty ){ + None + }else{ + if( needsRecompile ){ + val start = System.currentTimeMillis + + 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{ + lib.runMain( + _class, + dualArgs ++ singleArgs ++ Seq( + "-bootclasspath", dottyDependency.classpath.string, // let's put cp last. It so long + "-classpath", classpath.string // let's put cp last. It so long + ) ++ files.map(_.toString), + dottyDependency.classLoader(classLoaderCache) + ) + } + } catch { + case e: Exception => + System.err.println(red("Dotty crashed. See https://github.com/lampepfl/dotty/issues. To reproduce run:")) + System.out.println(s""" +java -cp \\ +${dottyDependency.classpath.strings.mkString(":\\\n")} \\ +\\ +${_class} \\ +\\ +${dualArgs.grouped(2).map(_.mkString(" ")).mkString(" \\\n")} \\ +\\ +${singleArgs.mkString(" \\\n")} \\ +\\ +-bootclasspath \\ +${dottyDependency.classpath.strings.mkString(":\\\n")} \\ +-classpath \\ +${classpath.strings.mkString(":\\\n")} \\ +\\ +${files.sorted.mkString(" \\\n")} +""" + ) + ExitCode.Failure + } + + 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( compileTarget ) + } + } +} diff --git a/test/simple-fixed/build/build.scala b/test/simple-fixed/build/build.scala index 3f1ff66..42130ee 100644 --- a/test/simple-fixed/build/build.scala +++ b/test/simple-fixed/build/build.scala @@ -24,7 +24,6 @@ class Build(context: cbt.Context) extends BasicBuild(context){ sonatypeSnapshots ).bind( "org.cvogt" %% "play-json-extensions" % "0.8.0", - "org.tpolecat" %% "tut-core" % "0.4.2", "ai.x" %% "lens" % "1.0.0" ) ) diff --git a/test/simple/build/build.scala b/test/simple/build/build.scala index b75d262..affe7f6 100644 --- a/test/simple/build/build.scala +++ b/test/simple/build/build.scala @@ -35,7 +35,6 @@ class Build(val context: cbt.Context) extends BaseBuild{ sonatypeSnapshots ).bind( "org.cvogt" %% "play-json-extensions" % "0.8.0", - "org.tpolecat" %% "tut-core" % "0.4.2", "ai.x" %% "lens" % "1.0.0" ) ) diff --git a/test/test.scala b/test/test.scala index 4f0afcd..dfc35d0 100644 --- a/test/test.scala +++ b/test/test.scala @@ -147,20 +147,25 @@ object Main{ } ( - Dependencies( - Resolver( mavenCentral, bintray("tpolecat") ).bind( - lib.ScalaDependency("org.tpolecat","tut-core","0.4.2", scalaMajorVersion="2.11") - ) - ).classpath.strings - ++ + ( + if(System.getenv("CIRCLECI") == null){ + // tenporarily disable on circleci as it seems to have trouble reliably + // downloading from bintray + Dependencies( + Resolver( bintray("tpolecat") ).bind( + lib.ScalaDependency("org.tpolecat","tut-core","0.4.2", scalaMajorVersion="2.11") + ) + ).classpath.strings + } else Nil + ) ++ Dependencies( - Resolver(sonatypeReleases).bind( - MavenDependency("org.cvogt","play-json-extensions_2.11","0.8.0") + Resolver( sonatypeReleases ).bind( + MavenDependency("org.cvogt","scala-extensions_2.11","0.5.1") ) ).classpath.strings ++ Dependencies( - Resolver( mavenCentral, sonatypeSnapshots ).bind( + Resolver( mavenCentral ).bind( MavenDependency("ai.x","lens_2.11","1.0.0") ) ).classpath.strings @@ -193,6 +198,13 @@ object Main{ compile("../examples/scalajs-react-example/js") compile("../examples/scalajs-react-example/jvm") compile("../examples/multi-project-example") + if(sys.props("java.version").startsWith("1.7")){ + System.err.println("\nskipping dotty tests on Java 7") + } else { + compile("../examples/dotty-example") + task("run","../examples/dotty-example") + task("doc","../examples/dotty-example") + } task("fastOptJS","../examples/scalajs-react-example/js") task("fullOptJS","../examples/scalajs-react-example/js") compile("../examples/uber-jar-example") |