summaryrefslogtreecommitdiff
path: root/scalaplugin
diff options
context:
space:
mode:
authorLi Haoyi <haoyi.sg@gmail.com>2017-11-03 23:44:39 -0700
committerLi Haoyi <haoyi.sg@gmail.com>2017-11-03 23:44:39 -0700
commit13270145903b457c906a9fa77bd152afb6448ef5 (patch)
treee85b7ed530e0c8e3c3041cbf17641857c448b602 /scalaplugin
parent66f1c5c2438aeb8f2496575f52c25b09cf5793a6 (diff)
downloadmill-13270145903b457c906a9fa77bd152afb6448ef5.tar.gz
mill-13270145903b457c906a9fa77bd152afb6448ef5.tar.bz2
mill-13270145903b457c906a9fa77bd152afb6448ef5.zip
Split up forge into `scalaplugin` an `core` subprojects, to allow us to use the `T#apply` macro in the implementation of `scalaplugin.Subproject`
Also needed to implement inter-`Subproject` dependencies so the `MetacircularTests` can continue to support the new layout
Diffstat (limited to 'scalaplugin')
-rw-r--r--scalaplugin/src/main/scala/forge/scalaplugin/Subproject.scala143
-rw-r--r--scalaplugin/src/test/scala/forge/scalaplugin/MetacircularTests.scala68
2 files changed, 211 insertions, 0 deletions
diff --git a/scalaplugin/src/main/scala/forge/scalaplugin/Subproject.scala b/scalaplugin/src/main/scala/forge/scalaplugin/Subproject.scala
new file mode 100644
index 00000000..7fad28c9
--- /dev/null
+++ b/scalaplugin/src/main/scala/forge/scalaplugin/Subproject.scala
@@ -0,0 +1,143 @@
+package forge
+package scalaplugin
+
+import java.io.File
+
+import ammonite.ops.{Path, ls, mkdir, pwd}
+import coursier.{Cache, Dependency, Fetch, MavenRepository, Module, Repository, Resolution}
+import forge.{Target => T}
+import forge.util.PathRef
+import sbt.internal.inc.{FreshCompilerCache, ScalaInstance, ZincUtil}
+import sbt.internal.util.{ConsoleOut, MainAppender}
+import sbt.util.LogExchange
+import xsbti.api.{ClassLike, DependencyContext}
+import xsbti.compile.DependencyChanges
+
+import scalaz.concurrent.Task
+object Subproject{
+ def compileScala(scalaVersion: T[String],
+ sources: T[PathRef],
+ compileClasspath: T[Seq[PathRef]],
+ outputPath: T[Path]): T[PathRef] = {
+ for((scalaVersion, sources, compileClasspath, outputPath) <- zip(scalaVersion, sources, compileClasspath, outputPath))
+ yield {
+ val binaryScalaVersion = scalaVersion.split('.').dropRight(1).mkString(".")
+ def grepJar(s: String) = {
+ compileClasspath
+ .find(_.path.toString.endsWith(s))
+ .getOrElse(throw new Exception("Cannot find " + s))
+ .path
+ .toIO
+ }
+ val scalac = ZincUtil.scalaCompiler(
+ new ScalaInstance(
+ version = scalaVersion,
+ loader = getClass.getClassLoader,
+ libraryJar = grepJar(s"scala-library-$scalaVersion.jar"),
+ compilerJar = grepJar(s"scala-compiler-$scalaVersion.jar"),
+ allJars = compileClasspath.toArray.map(_.path.toIO),
+ explicitActual = None
+ ),
+ grepJar(s"compiler-bridge_$binaryScalaVersion-1.0.3.jar")
+ )
+
+ mkdir(outputPath)
+
+
+ scalac.apply(
+ sources = ls.rec(sources.path).filter(_.isFile).map(_.toIO).toArray,
+ changes = new DependencyChanges {
+ def isEmpty = true
+ def modifiedBinaries() = Array[File]()
+ def modifiedClasses() = Array[String]()
+ },
+ classpath = compileClasspath.map(_.path.toIO).toArray,
+ singleOutput = outputPath.toIO,
+ options = Array(),
+ callback = new xsbti.AnalysisCallback {
+ def startSource(source: File) = ()
+ def apiPhaseCompleted() = ()
+ def enabled() = true
+ def binaryDependency(onBinaryEntry: File, onBinaryClassName: String, fromClassName: String, fromSourceFile: File, context: DependencyContext) = ()
+ def generatedNonLocalClass(source: File, classFile: File, binaryClassName: String, srcClassName: String) = ()
+ def problem(what: String, pos: xsbti.Position, msg: String, severity: xsbti.Severity, reported: Boolean) = ()
+ def dependencyPhaseCompleted() = ()
+ def classDependency(onClassName: String, sourceClassName: String, context: DependencyContext) = ()
+ def generatedLocalClass(source: File, classFile: File) = ()
+ def api(sourceFile: File, classApi: ClassLike) = ()
+
+ def mainClass(sourceFile: File, className: String) = ()
+ def usedName(className: String, name: String, useScopes: java.util.EnumSet[xsbti.UseScope]) = ()
+ },
+ maximumErrors = 10,
+ cache = new FreshCompilerCache(),
+ log = {
+ val console = ConsoleOut.systemOut
+ val consoleAppender = MainAppender.defaultScreen(console)
+ val l = LogExchange.logger("Hello")
+ LogExchange.unbindLoggerAppenders("Hello")
+ LogExchange.bindLoggerAppenders("Hello", (consoleAppender -> sbt.util.Level.Warn) :: Nil)
+ l
+ }
+ )
+ PathRef(outputPath)
+ }
+ }
+ def createJar(sourceDirs: T[Seq[PathRef]]) = ???
+ def resolveDependencies(repositories: Seq[Repository],
+ deps: Seq[coursier.Dependency]): Seq[PathRef] = {
+ val start = Resolution(deps.toSet)
+ val fetch = Fetch.from(repositories, Cache.fetch())
+ val resolution = start.process.run(fetch).unsafePerformSync
+ val localArtifacts: Seq[File] = Task.gatherUnordered(
+ resolution.artifacts.map(Cache.file(_).run)
+ ).unsafePerformSync.flatMap(_.toOption)
+
+ localArtifacts.map(p => PathRef(Path(p)))
+ }
+}
+import Subproject._
+abstract class Subproject {
+ val scalaVersion: T[String]
+
+ val scalaBinaryVersion = T{ scalaVersion().split('.').dropRight(1).mkString(".") }
+ val ivyDeps = T{ Seq[coursier.Dependency]() }
+ val compileIvyDeps = T{ Seq[coursier.Dependency]() }
+ val runIvyDeps = T{ Seq[coursier.Dependency]() }
+ val basePath: T[Path]
+
+ val repositories: Seq[Repository] = Seq(
+ Cache.ivy2Local,
+ MavenRepository("https://repo1.maven.org/maven2")
+ )
+
+ val depClasspath = T{ Seq.empty[PathRef] }
+ val compileDepClasspath = T[Seq[PathRef]] {
+ depClasspath() ++ resolveDependencies(
+ repositories,
+ ivyDeps() ++ compileIvyDeps() ++ Seq(
+ Dependency(Module("org.scala-lang", "scala-compiler"), scalaVersion()),
+ Dependency(Module("org.scala-sbt", s"compiler-bridge_${scalaBinaryVersion()}"), "1.0.3")
+ )
+ )
+ }
+ val runDepClasspath = T[Seq[PathRef]] {
+ depClasspath() ++ resolveDependencies(
+ repositories,
+ ivyDeps() ++ runIvyDeps() ++ Seq(
+ Dependency(Module("org.scala-lang", "scala-library"), scalaVersion())
+ )
+ )
+ }
+
+ val sources = T{ PathRef(basePath() / 'src) }
+ val outputPath = T{ basePath() / 'out }
+ val resources = T{ PathRef(basePath() / 'resources) }
+ val compiledPath = T{ outputPath() / 'classpath }
+ val compiled = T{
+ compileScala(scalaVersion, sources, compileDepClasspath, outputPath)
+ }
+
+ val classpath = T{ Seq(resources(), compiled()) }
+// val jar = T{ createJar(classpath) }
+}
diff --git a/scalaplugin/src/test/scala/forge/scalaplugin/MetacircularTests.scala b/scalaplugin/src/test/scala/forge/scalaplugin/MetacircularTests.scala
new file mode 100644
index 00000000..05dd0dbd
--- /dev/null
+++ b/scalaplugin/src/test/scala/forge/scalaplugin/MetacircularTests.scala
@@ -0,0 +1,68 @@
+package forge
+package scalaplugin
+
+import ammonite.ops.pwd
+import coursier.{Dependency => Dep, Module => Mod}
+import forge.util.{OSet, PathRef}
+import utest._
+
+object MetacircularTests extends TestSuite{
+ object Core extends Subproject {
+ val scalaVersion = T{ "2.12.4" }
+ override val compileIvyDeps = T{
+ Seq(
+ Dep(Mod("org.scala-lang", "scala-reflect"), scalaVersion(), configuration = "provided")
+ )
+ }
+
+ override val ivyDeps = T{
+ Seq(
+ Dep(Mod("com.lihaoyi", "sourcecode_" + scalaBinaryVersion()), "0.1.4"),
+ Dep(Mod("com.lihaoyi", "pprint_" + scalaBinaryVersion()), "0.5.3"),
+ Dep(Mod("com.lihaoyi", "ammonite_" + scalaVersion()), "1.0.3"),
+ Dep(Mod("com.typesafe.play", "play-json_" + scalaBinaryVersion()), "2.6.6"),
+ Dep(Mod("org.scala-sbt", "zinc_" + scalaBinaryVersion()), "1.0.3")
+ )
+ }
+
+
+ val basePath = T{ pwd / 'core }
+ override val sources = T{ PathRef(pwd/'core/'src/'main/'scala) }
+ override val resources = T{ sources }
+ }
+ object ScalaPlugin extends Subproject {
+ val scalaVersion = T.apply{ "2.12.4" }
+
+ override val ivyDeps = T{
+ Seq(
+ Dep(Mod("com.lihaoyi", "sourcecode_" + scalaBinaryVersion()), "0.1.4"),
+ Dep(Mod("com.lihaoyi", "pprint_" + scalaBinaryVersion()), "0.5.3"),
+ Dep(Mod("com.lihaoyi", "ammonite_" + scalaVersion()), "1.0.3"),
+ Dep(Mod("com.typesafe.play", "play-json_" + scalaBinaryVersion()), "2.6.6"),
+ Dep(Mod("org.scala-sbt", "zinc_" + scalaBinaryVersion()), "1.0.3")
+ )
+ }
+
+
+ override val depClasspath = T{ Seq(Core.compiled()) }
+ val basePath = T{ pwd / 'scalaplugin }
+ override val sources = T{ PathRef(pwd/'scalaplugin/'src/'main/'scala) }
+ override val resources = T{ sources }
+ }
+
+ val tests = Tests{
+ 'scalac {
+ val workspacePath = pwd / 'target / 'workspace / 'meta
+ val mapping = Discovered.mapping(MetacircularTests)
+ val evaluator = new Evaluator(workspacePath, mapping)
+// val evaluated1 = evaluator.evaluate(OSet(Self.scalaVersion)).evaluated.collect(mapping)
+// val evaluated2 = evaluator.evaluate(OSet(Self.scalaBinaryVersion)).evaluated.collect(mapping)
+// val evaluated3 = evaluator.evaluate(OSet(Self.compileDeps)).evaluated.collect(mapping)
+// val evaluated4 = evaluator.evaluate(OSet(Self.deps)).evaluated.collect(mapping)
+ val evaluated5 = evaluator.evaluate(OSet(Core.compiled)).evaluated.collect(mapping)
+ val evaluated6 = evaluator.evaluate(OSet(ScalaPlugin.compiled)).evaluated.collect(mapping)
+// evaluated3
+ }
+ }
+}
+