diff options
author | Li Haoyi <haoyi.sg@gmail.com> | 2017-11-03 23:44:39 -0700 |
---|---|---|
committer | Li Haoyi <haoyi.sg@gmail.com> | 2017-11-03 23:44:39 -0700 |
commit | 13270145903b457c906a9fa77bd152afb6448ef5 (patch) | |
tree | e85b7ed530e0c8e3c3041cbf17641857c448b602 /scalaplugin | |
parent | 66f1c5c2438aeb8f2496575f52c25b09cf5793a6 (diff) | |
download | mill-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.scala | 143 | ||||
-rw-r--r-- | scalaplugin/src/test/scala/forge/scalaplugin/MetacircularTests.scala | 68 |
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 + } + } +} + |