diff options
author | Roman Timushev <rtimush@gmail.com> | 2017-12-29 22:23:57 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-12-29 22:23:57 +0100 |
commit | 81d4cfb6f63512b314fbbf49c4ba415aedc469d7 (patch) | |
tree | 384952c3be58592a9d54af40f4ce7edefed3eee5 | |
parent | 19ecb2b4b9d6e91c6a765e7dbae79e3c1e968888 (diff) | |
parent | 417f2ea33202c4dd5d3732cb9fbc6a35f8b7b4ed (diff) | |
download | mill-81d4cfb6f63512b314fbbf49c4ba415aedc469d7.tar.gz mill-81d4cfb6f63512b314fbbf49c4ba415aedc469d7.tar.bz2 mill-81d4cfb6f63512b314fbbf49c4ba415aedc469d7.zip |
Merge pull request #67 from lihaoyi/scalajs
Scala.js support
17 files changed, 456 insertions, 29 deletions
@@ -1,3 +1,5 @@ +import java.io.File + val sharedSettings = Seq( scalaVersion := "2.12.4", organization := "com.lihaoyi", @@ -131,9 +133,42 @@ lazy val scalaplugin = project baseDirectory in Test := (baseDirectory in Test).value / "..", javaOptions := bridgeProps.value.toSeq ) - +lazy val scalajsplugin = project + .dependsOn(scalaplugin % "compile->compile;test->test") + .settings( + sharedSettings, + name := "mill-scalajsplugin", + fork in Test := true, + baseDirectory in (Test, test) := (baseDirectory in (Test, test)).value / "..", + javaOptions in (Test, test) := jsbridgeProps.value.toSeq + ) +def jsbridge(binary: String, version: String) = + Project( + id = "scalajsbridge_" + binary.replace('.', '_'), + base = file("scalajsplugin/bridge_" + binary.replace('.', '_')) + ) + .settings( + organization := "com.lihaoyi", + scalaVersion := "2.12.4", + name := "mill-js-bridge", + libraryDependencies ++= Seq("org.scala-js" %% "scalajs-tools" % version) + ) +lazy val scalajsbridge_0_6 = jsbridge("0.6", "0.6.21") +lazy val scalajsbridge_1_0 = jsbridge("1.0", "1.0.0-M2") +val jsbridgeProps = Def.task{ + def bridgeClasspath(depClasspath: Classpath, jar: File) = { + (depClasspath.files :+ jar).map(_.absolutePath).mkString(File.pathSeparator) + } + val mapping = Map( + "MILL_SCALAJS_BRIDGE_0_6" -> bridgeClasspath((dependencyClasspath in (scalajsbridge_0_6, Compile)).value, + (packageBin in (scalajsbridge_0_6, Compile)).value), + "MILL_SCALAJS_BRIDGE_1_0" -> bridgeClasspath((dependencyClasspath in (scalajsbridge_1_0, Compile)).value, + (packageBin in (scalajsbridge_1_0, Compile)).value) + ) + for((k, v) <- mapping) yield s"-D$k=$v" +} lazy val bin = project - .dependsOn(scalaplugin) + .dependsOn(scalaplugin, scalajsplugin) .settings( sharedSettings, fork := true, @@ -146,7 +181,7 @@ lazy val bin = project prependShellScript = Some( Seq( "#!/usr/bin/env sh", - s"""exec java ${bridgeProps.value.mkString(" ")} -cp "$$0" mill.Main "$$@" """ + s"""exec java ${(bridgeProps.value ++ jsbridgeProps.value).mkString(" ")} -cp "$$0" mill.Main "$$@" """ ) ) ) @@ -1,4 +1,6 @@ import $file.shared +import java.io.File + import ammonite.ops._ import coursier.maven.MavenRepository import mill._ @@ -10,7 +12,7 @@ trait MillPublishModule extends PublishModule { def pomSettings = PomSettings( organization = "com.lihaoyi", - description = publishName(), + description = artifactId(), developers = Seq(Developer("lihaoyi", "Li Haoyi", "https://github.com/lihaoyi/mill")), licenses = Seq(License("MIT License", "https://spdx.org/licenses/MIT.html#licenseText")), scm = SCM("https://github.com/lihaoyi/mill", "scm:git:https://github.com/lihaoyi/mill.git"), @@ -143,8 +145,37 @@ object ScalaPlugin extends MillModule { } } } +val jsbridges = for{ + scalajsBinary <- mill.define.Cross("0.6", "1.0") +} yield new MillModule{ + def basePath = pwd / 'scalajsplugin / s"bridge_${scalajsBinary.replace('.', '_')}" + val scalajsVersion = scalajsBinary match { + case "0.6" => "0.6.21" + case "1.0" => "1.0.0-M2" + } + override def ivyDeps = Seq( + Dep("org.scala-js", "scalajs-tools", scalajsVersion) + ) +} + +object ScalaJSPlugin extends MillModule { + + def projectDeps = Seq(ScalaPlugin) + def basePath = pwd / 'scalajsplugin + + def bridgeClasspath(runDepClasspath: Seq[PathRef], classes: PathRef) = + (runDepClasspath :+ classes).map(_.path).mkString(File.pathSeparator) + def testArgs = T{ + val mapping = Map( + "MILL_SCALAJS_BRIDGE_0_6" -> bridgeClasspath(jsbridges("0.6").runDepClasspath(), jsbridges("0.6").compile().classes), + "MILL_SCALAJS_BRIDGE_1_0" -> bridgeClasspath(jsbridges("1.0").runDepClasspath(), jsbridges("1.0").compile().classes) + ) + for((k, v) <- mapping.toSeq) yield s"-D$k=$v" + } + +} -val assemblyProjects = Seq(ScalaPlugin) +val assemblyProjects = Seq(ScalaPlugin, ScalaJSPlugin) def assemblyClasspath = mill.define.Task.traverse(assemblyProjects)(_.assemblyClasspath) @@ -163,7 +194,7 @@ def assemblyBase(classpath: Seq[Path], extraArgs: String) } def devAssembly = T{ - assemblyBase(assemblyClasspath().flatten, ScalaPlugin.testArgs().mkString(" ")) + assemblyBase(assemblyClasspath().flatten, (ScalaPlugin.testArgs() ++ ScalaJSPlugin.testArgs()).mkString(" ")) } def releaseAssembly = T{ diff --git a/scalaplugin/src/test/scala/mill/scalaplugin/TestEvaluator.scala b/core/src/test/scala/mill/util/TestEvaluator.scala index f1cee213..5d16de43 100644 --- a/scalaplugin/src/test/scala/mill/scalaplugin/TestEvaluator.scala +++ b/core/src/test/scala/mill/util/TestEvaluator.scala @@ -1,10 +1,9 @@ -package mill.scalaplugin +package mill.util import ammonite.ops.Path import mill.define.{Target, Task} import mill.discover.{Discovered, Mirror} import mill.eval.{Evaluator, Result} -import mill.util.{DummyLogger, OSet, PrintLogger} class TestEvaluator(mapping: Discovered.Mapping[_], workspacePath: Path){ val evaluator = new Evaluator(workspacePath, mapping, DummyLogger) diff --git a/scalajsplugin/bridge_0_6/src/main/scala/mill/scalajsplugin/bridge/ScalaJSLinkerBridge.scala b/scalajsplugin/bridge_0_6/src/main/scala/mill/scalajsplugin/bridge/ScalaJSLinkerBridge.scala new file mode 100644 index 00000000..82295740 --- /dev/null +++ b/scalajsplugin/bridge_0_6/src/main/scala/mill/scalajsplugin/bridge/ScalaJSLinkerBridge.scala @@ -0,0 +1,24 @@ +package mill +package scalajsplugin +package bridge + +import java.io.File + +import org.scalajs.core.tools.io.IRFileCache.IRContainer +import org.scalajs.core.tools.io.{AtomicWritableFileVirtualJSFile, FileVirtualBinaryFile, FileVirtualScalaJSIRFile, VirtualJarFile} +import org.scalajs.core.tools.linker.{ModuleInitializer, StandardLinker} +import org.scalajs.core.tools.logging.ScalaConsoleLogger + +class ScalaJSLinkerBridge { + def link(sources: Array[File], libraries: Array[File], dest: File, main: String, fullOpt: Boolean): Unit = { + val config = StandardLinker.Config().withOptimizer(fullOpt) + val linker = StandardLinker(config) + val sourceSJSIRs = sources.map(new FileVirtualScalaJSIRFile(_)) + val jars = libraries.map(jar => IRContainer.Jar(new FileVirtualBinaryFile(jar) with VirtualJarFile)) + val jarSJSIRs = jars.flatMap(_.jar.sjsirFiles) + val destFile = AtomicWritableFileVirtualJSFile(dest) + val logger = new ScalaConsoleLogger + val initializer = Option(main).map { cls => ModuleInitializer.mainMethodWithArgs(cls, "main") } + linker.link(sourceSJSIRs ++ jarSJSIRs, initializer.toSeq, destFile, logger) + } +}
\ No newline at end of file diff --git a/scalajsplugin/bridge_1_0/src/main/scala/mill/scalajsplugin/bridge/ScalaJSLinkerBridge.scala b/scalajsplugin/bridge_1_0/src/main/scala/mill/scalajsplugin/bridge/ScalaJSLinkerBridge.scala new file mode 100644 index 00000000..7d54ae52 --- /dev/null +++ b/scalajsplugin/bridge_1_0/src/main/scala/mill/scalajsplugin/bridge/ScalaJSLinkerBridge.scala @@ -0,0 +1,24 @@ +package mill +package scalajsplugin +package bridge + +import java.io.File + +import org.scalajs.core.tools.io._ +import org.scalajs.core.tools.linker.{ModuleInitializer, StandardLinker} +import org.scalajs.core.tools.logging.ScalaConsoleLogger + +class ScalaJSLinkerBridge { + def link(sources: Array[File], libraries: Array[File], dest: File, main: String, fullOpt: Boolean): Unit = { + val config = StandardLinker.Config().withOptimizer(fullOpt) + val linker = StandardLinker(config) + val cache = new IRFileCache().newCache + val sourceIRs = sources.map(FileVirtualScalaJSIRFile) + val irContainers = FileScalaJSIRContainer.fromClasspath(libraries) + val libraryIRs = cache.cached(irContainers) + val destFile = AtomicWritableFileVirtualJSFile(dest) + val logger = new ScalaConsoleLogger + val initializer = Option(main).map { cls => ModuleInitializer.mainMethodWithArgs(cls, "main") } + linker.link(sourceIRs ++ libraryIRs, initializer.toSeq, destFile, logger) + } +}
\ No newline at end of file diff --git a/scalajsplugin/src/main/scala/mill/scalajsplugin/Lib.scala b/scalajsplugin/src/main/scala/mill/scalajsplugin/Lib.scala new file mode 100644 index 00000000..980a728a --- /dev/null +++ b/scalajsplugin/src/main/scala/mill/scalajsplugin/Lib.scala @@ -0,0 +1,62 @@ +package mill +package scalajsplugin + +import java.io.File +import java.net.URLClassLoader + +import ammonite.ops.{Path, mkdir, rm, _} +import mill.eval.PathRef +import mill.scalaplugin.Dep +import mill.util.Ctx + +import scala.collection.breakOut +import scala.language.reflectiveCalls + +private object LinkerBridge { + @volatile var scalaInstanceCache = Option.empty[(Long, ScalaJSLinkerBridge)] +} + +object Lib { + + def scalaJSLinkerIvyDep(scalaJSVersion: String): Dep = + Dep("com.lihaoyi", s"mill-jsbridge_${scalaJSVersion.replace('.', '_')}", "0.1-SNAPSHOT") + + def scalaJSLinkerBridge(classPath: Seq[Path]): ScalaJSLinkerBridge = { + val classloaderSig = classPath.map(p => p.toString().hashCode + p.mtime.toMillis).sum + LinkerBridge.scalaInstanceCache match { + case Some((`classloaderSig`, linker)) => linker + case _ => + val cl = new URLClassLoader(classPath.map(_.toIO.toURI.toURL).toArray) + val bridge = cl.loadClass("mill.scalajsplugin.bridge.ScalaJSLinkerBridge") + .getDeclaredConstructor().newInstance().asInstanceOf[ { + def link(sources: Array[File], libraries: Array[File], dest: File, main: String, fullOpt: Boolean): Unit + }] + val linker: ScalaJSLinkerBridge = (sources: Seq[File], + libraries: Seq[File], + dest: File, + main: Option[String], + mode: OptimizeMode) => + bridge.link(sources.toArray, libraries.toArray, dest, main.orNull, mode == FullOpt) + LinkerBridge.scalaInstanceCache = Some((classloaderSig, linker)) + linker + } + } + + def link(main: Option[String], + inputPaths: Seq[Path], + libraries: Seq[Path], + linker: ScalaJSLinkerBridge, + mode: OptimizeMode) + (implicit ctx: Ctx.DestCtx): PathRef = { + val outputPath = ctx.dest.copy(segments = ctx.dest.segments.init :+ (ctx.dest.segments.last + ".js")) + rm(outputPath) + if (inputPaths.nonEmpty) { + mkdir(outputPath / up) + val inputFiles: Vector[File] = inputPaths.map(ls).flatMap(_.filter(_.ext == "sjsir")).map(_.toIO)(breakOut) + val inputLibraries: Vector[File] = libraries.filter(_.ext == "jar").map(_.toIO)(breakOut) + linker.link(inputFiles, inputLibraries, outputPath.toIO, main, mode) + } + PathRef(outputPath) + } + +} diff --git a/scalajsplugin/src/main/scala/mill/scalajsplugin/ScalaJSLinkerBridge.scala b/scalajsplugin/src/main/scala/mill/scalajsplugin/ScalaJSLinkerBridge.scala new file mode 100644 index 00000000..1aa8da8c --- /dev/null +++ b/scalajsplugin/src/main/scala/mill/scalajsplugin/ScalaJSLinkerBridge.scala @@ -0,0 +1,12 @@ +package mill.scalajsplugin + +import java.io.File + +sealed trait OptimizeMode + +object FastOpt extends OptimizeMode +object FullOpt extends OptimizeMode + +trait ScalaJSLinkerBridge { + def link(sources: Seq[File], libraries: Seq[File], dest: File, main: Option[String], mode: OptimizeMode): Unit +} diff --git a/scalajsplugin/src/main/scala/mill/scalajsplugin/ScalaJSModule.scala b/scalajsplugin/src/main/scala/mill/scalajsplugin/ScalaJSModule.scala new file mode 100644 index 00000000..c3e8a89d --- /dev/null +++ b/scalajsplugin/src/main/scala/mill/scalajsplugin/ScalaJSModule.scala @@ -0,0 +1,69 @@ +package mill +package scalajsplugin + +import java.io.File + +import ammonite.ops.Path +import mill.eval.Result.Success +import mill.scalajsplugin.Lib._ +import mill.scalaplugin.Lib.resolveDependencies +import mill.scalaplugin.{Dep, PublishModule, ScalaModule, TestScalaModule} + +trait ScalaJSModule extends ScalaModule { outer => + + def scalaJSVersion: T[String] + + private val ReleaseVersion = raw"""(\d+)\.(\d+)\.(\d+)""".r + private val MinorSnapshotVersion = raw"""(\d+)\.(\d+)\.([1-9]\d*)-SNAPSHOT""".r + + def scalaJSBinaryVersion = T{ + scalaJSVersion() match { + case ReleaseVersion(major, minor, _) => s"$major.$minor" + case MinorSnapshotVersion(major, minor, _) => s"$major.$minor" + case _ => scalaJSVersion() + } + } + + def scalaJSBridgeVersion = T{ scalaJSVersion().split('.').dropRight(1).mkString(".") } + + def scalaJSLinkerClasspath: T[Seq[PathRef]] = T{ + val jsBridgeKey = "MILL_SCALAJS_BRIDGE_" + scalaJSBridgeVersion().replace('.', '_') + val jsBridgePath = sys.props(jsBridgeKey) + if (jsBridgePath != null) Success(jsBridgePath.split(File.pathSeparator).map(f => PathRef(Path(f), quick = true)).toVector) + else { + val dep = scalaJSLinkerIvyDep(scalaJSBridgeVersion()) + resolveDependencies( + repositories, + scalaVersion(), + scalaBinaryVersion(), + Seq(dep) + ) + } + } + + def fastOpt = T{ + val linker = scalaJSLinkerBridge(scalaJSLinkerClasspath().map(_.path)) + link(mainClass(), Seq(compile().classes.path), compileDepClasspath().map(_.path), linker, FastOpt) + } + + def fullOpt = T{ + val linker = scalaJSLinkerBridge(scalaJSLinkerClasspath().map(_.path)) + link(mainClass(), Seq(compile().classes.path), compileDepClasspath().map(_.path), linker, FullOpt) + } + + override def scalacPluginIvyDeps = T{ Seq(Dep.Point("org.scala-js", "scalajs-compiler", scalaJSVersion())) } + + override def ivyDeps = T{ Seq(Dep("org.scala-js", "scalajs-library", scalaJSVersion())) } + + // publish artifact with name "mill_sjs0.6.4_2.12" instead of "mill_sjs0.6_2.12" + def crossFullScalaJSVersion: T[Boolean] = false + def artifactScalaJSVersion: T[String] = T { + if (crossFullScalaJSVersion()) scalaJSVersion() + else scalaJSBinaryVersion() + } + + override def artifactId: T[String] = T { s"${artifactName()}_sjs${artifactScalaJSVersion()}_${artifactScalaVersion()}" } + +} + +trait TestScalaJSModule extends ScalaJSModule with TestScalaModule
\ No newline at end of file diff --git a/scalajsplugin/src/test/resource/hello-js-world/src/main/scala/Main.scala b/scalajsplugin/src/test/resource/hello-js-world/src/main/scala/Main.scala new file mode 100644 index 00000000..60cef56d --- /dev/null +++ b/scalajsplugin/src/test/resource/hello-js-world/src/main/scala/Main.scala @@ -0,0 +1,3 @@ +object Main extends App { + println("Hello " + sys.props("java.vm.name")) +} diff --git a/scalajsplugin/src/test/scala/mill/scalajsplugin/HelloJSWorldTests.scala b/scalajsplugin/src/test/scala/mill/scalajsplugin/HelloJSWorldTests.scala new file mode 100644 index 00000000..e199c1da --- /dev/null +++ b/scalajsplugin/src/test/scala/mill/scalajsplugin/HelloJSWorldTests.scala @@ -0,0 +1,160 @@ +package mill.scalajsplugin + +import java.io.{FileReader, StringWriter} +import java.util.jar.JarFile +import javax.script.{ScriptContext, ScriptEngineManager} + +import ammonite.ops._ +import mill._ +import mill.define.Cross +import mill.discover.Discovered +import mill.scalaplugin.PublishModule +import mill.scalaplugin.publish.{Developer, License, PomSettings, SCM} +import mill.util.TestEvaluator +import utest._ + +import scala.collection.JavaConverters._ + +trait HelloJSWorldModule extends ScalaJSModule with PublishModule { + def basePath = HelloJSWorldTests.workspacePath + override def mainClass = Some("Main") +} + +object HelloJSWorld { + val build = for { + scalaJS <- Cross("0.6.20", "0.6.21", "1.0.0-M2") + scala <- Cross("2.11.8", "2.12.3", "2.12.4") + } yield + new HelloJSWorldModule { + def scalaVersion = scala + def scalaJSVersion = scalaJS + def pomSettings = PomSettings( + organization = "com.lihaoyi", + description = "hello js world ready for real world publishing", + url = "https://github.com/lihaoyi/hello-world-publish", + licenses = Seq( + License("Apache License, Version 2.0", + "http://www.apache.org/licenses/LICENSE-2.0")), + scm = SCM( + "https://github.com/lihaoyi/hello-world-publish", + "scm:git:https://github.com/lihaoyi/hello-world-publish" + ), + developers = + Seq(Developer("lihaoyi", "Li Haoyi", "https://github.com/lihaoyi")) + ) + } +} + +object HelloJSWorldTests extends TestSuite { + + val srcPath = pwd / 'scalajsplugin / 'src / 'test / 'resource / "hello-js-world" + val workspacePath = pwd / 'target / 'workspace / "hello-js-world" + val outputPath = workspacePath / 'out + val mainObject = workspacePath / 'src / 'main / 'scala / "Main.scala" + + val helloWorldEvaluator = new TestEvaluator( + Discovered.mapping(HelloJSWorld), + workspacePath + ) + + class Console { + val out = new StringWriter() + def log(s: String): Unit = out.append(s) + } + + def runJS(path: Path): String = { + val engineManager = new ScriptEngineManager + val engine = engineManager.getEngineByName("nashorn") + val console = new Console + engine.getBindings(ScriptContext.ENGINE_SCOPE).put("console", console) + engine.eval(new FileReader(path.toIO)) + console.out.toString + } + + def tests: Tests = Tests { + prepareWorkspace() + 'compile - { + def testCompileFromScratch(scalaVersion: String, + scalaJSVersion: String): Unit = { + val Right((result, evalCount)) = + helloWorldEvaluator(HelloJSWorld.build(scalaVersion, scalaJSVersion).compile) + + val outPath = result.classes.path + val outputFiles = ls.rec(outPath) + val expectedClassfiles = compileClassfiles(outPath) + assert( + outputFiles.toSet == expectedClassfiles, + evalCount > 0 + ) + + // don't recompile if nothing changed + val Right((_, unchangedEvalCount)) = + helloWorldEvaluator(HelloJSWorld.build(scalaVersion, scalaJSVersion).compile) + assert(unchangedEvalCount == 0) + } + + 'fromScratch_2124_0621 - testCompileFromScratch("2.12.4", "0.6.21") + 'fromScratch_2123_0621 - testCompileFromScratch("2.12.3", "0.6.21") + 'fromScratch_2118_0621 - testCompileFromScratch("2.11.8", "0.6.21") + 'fromScratch_2124_100M2 - testCompileFromScratch("2.11.8", "1.0.0-M2") + } + + def testRun(scalaVersion: String, + scalaJSVersion: String, + mode: OptimizeMode): Unit = { + val task = mode match { + case FullOpt => HelloJSWorld.build(scalaVersion, scalaJSVersion).fullOpt + case FastOpt => HelloJSWorld.build(scalaVersion, scalaJSVersion).fastOpt + } + val Right((result, evalCount)) = helloWorldEvaluator(task) + val output = runJS(result.path) + assert(output == "Hello Scala.js") + } + + 'fullOpt - { + 'run_2124_0621 - testRun("2.12.4", "0.6.21", FullOpt) + 'run_2123_0621 - testRun("2.12.3", "0.6.21", FullOpt) + 'run_2118_0621 - testRun("2.11.8", "0.6.21", FullOpt) + 'run_2124_100M2 - testRun("2.11.8", "1.0.0-M2", FullOpt) + } + 'fastOpt - { + 'run_2124_0621 - testRun("2.12.4", "0.6.21", FastOpt) + 'run_2123_0621 - testRun("2.12.3", "0.6.21", FastOpt) + 'run_2118_0621 - testRun("2.11.8", "0.6.21", FastOpt) + 'run_2124_100M2 - testRun("2.11.8", "1.0.0-M2", FastOpt) + } + 'jar - { + 'containsSJSIRs - { + val Right((result, evalCount)) = helloWorldEvaluator(HelloJSWorld.build("2.12.4", "0.6.21").jar) + val jar = result.path + val entries = new JarFile(jar.toIO).entries().asScala.map(_.getName) + assert(entries.contains("Main$.sjsir")) + } + } + 'publish - { + def testArtifactId(scalaVersion: String, + scalaJSVersion: String, + artifactId: String): Unit = { + val Right((result, evalCount)) = helloWorldEvaluator(HelloJSWorld.build(scalaVersion, scalaJSVersion).artifact) + assert(result.id == artifactId) + } + 'artifactId_0621 - testArtifactId("2.12.4", "0.6.21", "hello-js-world_sjs0.6_2.12") + 'artifactId_0621 - testArtifactId("2.12.4", "1.0.0-M2", "hello-js-world_sjs1.0.0-M2_2.12") + } + } + + def compileClassfiles(parentDir: Path) = Set( + parentDir / "Main.class", + parentDir / "Main$.class", + parentDir / "Main$delayedInit$body.class", + parentDir / "Main$.sjsir", + parentDir / "Main$delayedInit$body.sjsir" + ) + + def prepareWorkspace(): Unit = { + rm(workspacePath) + mkdir(workspacePath / up) + cp(srcPath, workspacePath) + } + +} diff --git a/scalaplugin/src/main/scala/mill/scalaplugin/Lib.scala b/scalaplugin/src/main/scala/mill/scalaplugin/Lib.scala index 7dad791d..de1906ab 100644 --- a/scalaplugin/src/main/scala/mill/scalaplugin/Lib.scala +++ b/scalaplugin/src/main/scala/mill/scalaplugin/Lib.scala @@ -26,8 +26,8 @@ object ZincWorker extends Worker[ZincWorker]{ def make() = new ZincWorker } class ZincWorker{ - var scalaClassloaderCache = Option.empty[(Long, ClassLoader)] - var scalaInstanceCache = Option.empty[(Long, ScalaInstance)] + @volatile var scalaClassloaderCache = Option.empty[(Long, ClassLoader)] + @volatile var scalaInstanceCache = Option.empty[(Long, ScalaInstance)] } object Lib{ case class MockedLookup(am: File => Optional[CompileAnalysis]) extends PerClasspathEntryLookup { diff --git a/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala b/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala index b1102234..13e91c2a 100644 --- a/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala +++ b/scalaplugin/src/main/scala/mill/scalaplugin/ScalaModule.scala @@ -257,29 +257,32 @@ trait ScalaModule extends Module with TaskModule { outer => options = Seq("-usejavacp") ) } -} - -trait PublishModule extends ScalaModule { outer => - import mill.scalaplugin.publish._ - - def publishName: T[String] = basePath.last.toString - def publishVersion: T[String] = "0.0.1-SNAPSHOT" - def pomSettings: T[PomSettings] // publish artifact with name "mill_2.12.4" instead of "mill_2.12" - def publishWithFullScalaVersion: Boolean = false + def crossFullScalaVersion: T[Boolean] = false + def artifactName: T[String] = basePath.last.toString def artifactScalaVersion: T[String] = T { - if (publishWithFullScalaVersion) scalaVersion() + if (crossFullScalaVersion()) scalaVersion() else scalaBinaryVersion() } + def artifactId: T[String] = T { s"${artifactName()}_${artifactScalaVersion()}" } + +} + +trait PublishModule extends ScalaModule { outer => + import mill.scalaplugin.publish._ + + def pomSettings: T[PomSettings] + def publishVersion: T[String] = "0.0.1-SNAPSHOT" + def pom = T { val dependencies = ivyDeps().map(Artifact.fromDep(_, scalaVersion(), scalaBinaryVersion())) - val pom = Pom(artifact(), dependencies, publishName(), pomSettings()) + val pom = Pom(artifact(), dependencies, artifactName(), pomSettings()) - val pomPath = T.ctx().dest / s"${publishName()}_${artifactScalaVersion()}-${publishVersion()}.pom" + val pomPath = T.ctx().dest / s"${artifactId()}-${publishVersion()}.pom" write.over(pomPath, pom) PathRef(pomPath) } @@ -294,7 +297,7 @@ trait PublishModule extends ScalaModule { outer => } def artifact: T[Artifact] = T { - Artifact(pomSettings().organization, s"${publishName()}_${artifactScalaVersion()}", publishVersion()) + Artifact(pomSettings().organization, artifactId(), publishVersion()) } def publishLocal(): define.Command[Unit] = T.command { @@ -313,7 +316,7 @@ trait PublishModule extends ScalaModule { outer => def sonatypeSnapshotUri: String = "https://oss.sonatype.org/content/repositories/snapshots" def publish(credentials: String, gpgPassphrase: String): define.Command[Unit] = T.command { - val baseName = s"${publishName()}_${artifactScalaVersion()}-${publishVersion()}" + val baseName = s"${artifactId()}-${publishVersion()}" val artifacts = Seq( jar().path -> s"${baseName}.jar", sourcesJar().path -> s"${baseName}-sources.jar", diff --git a/scalaplugin/src/test/scala/mill/scalaplugin/AcyclicTests.scala b/scalaplugin/src/test/scala/mill/scalaplugin/AcyclicTests.scala index 13349aec..131ee6bb 100644 --- a/scalaplugin/src/test/scala/mill/scalaplugin/AcyclicTests.scala +++ b/scalaplugin/src/test/scala/mill/scalaplugin/AcyclicTests.scala @@ -7,16 +7,17 @@ import mill.discover.Discovered import mill.scalaplugin.publish._ import utest._ import mill.util.JsonFormatters._ +import mill.util.TestEvaluator object AcyclicBuild{ val acyclic = for(crossVersion <- Cross("2.10.6", "2.11.8", "2.12.3", "2.12.4")) yield new SbtScalaModule with PublishModule {outer => def basePath = AcyclicTests.workspacePath - def publishName = "acyclic" + def artifactName = "acyclic" def publishVersion = "0.1.7" def pomSettings = PomSettings( - description = publishName(), + description = artifactName(), organization = "com.lihaoyi", url = "https://github.com/lihaoyi/acyclic", licenses = Seq( diff --git a/scalaplugin/src/test/scala/mill/scalaplugin/BetterFilesTests.scala b/scalaplugin/src/test/scala/mill/scalaplugin/BetterFilesTests.scala index f2e21a81..f608f311 100644 --- a/scalaplugin/src/test/scala/mill/scalaplugin/BetterFilesTests.scala +++ b/scalaplugin/src/test/scala/mill/scalaplugin/BetterFilesTests.scala @@ -5,6 +5,7 @@ import ammonite.ops._ import mill.discover.Discovered import utest._ import mill.util.JsonFormatters._ +import mill.util.TestEvaluator object BetterFilesBuild{ trait BetterFilesModule extends SbtScalaModule{ outer => diff --git a/scalaplugin/src/test/scala/mill/scalaplugin/HelloWorldTests.scala b/scalaplugin/src/test/scala/mill/scalaplugin/HelloWorldTests.scala index 51d1dc94..4272654a 100644 --- a/scalaplugin/src/test/scala/mill/scalaplugin/HelloWorldTests.scala +++ b/scalaplugin/src/test/scala/mill/scalaplugin/HelloWorldTests.scala @@ -9,6 +9,7 @@ import mill.define.{Cross, Target} import mill.discover.Discovered import mill.eval.{Evaluator, Result} import mill.scalaplugin.publish._ +import mill.util.TestEvaluator import sbt.internal.inc.CompileFailed import utest._ @@ -41,7 +42,7 @@ object HelloWorldFatalWarnings extends HelloWorldModule { } object HelloWorldWithPublish extends HelloWorldModule with PublishModule { - def publishName = "hello-world" + def artifactName = "hello-world" def publishVersion = "0.0.1" def pomSettings = PomSettings( diff --git a/scalaplugin/src/test/scala/mill/scalaplugin/JawnTests.scala b/scalaplugin/src/test/scala/mill/scalaplugin/JawnTests.scala index 97dff017..81d6e71a 100644 --- a/scalaplugin/src/test/scala/mill/scalaplugin/JawnTests.scala +++ b/scalaplugin/src/test/scala/mill/scalaplugin/JawnTests.scala @@ -8,6 +8,7 @@ import mill.discover.Discovered import mill.eval.Result import utest._ import mill.util.JsonFormatters._ +import mill.util.TestEvaluator object JawnBuild{ val Jawn = Cross("2.10.6", "2.11.11", "2.12.3").map(new Jawn(_)) @@ -6,12 +6,13 @@ set -eux git clean -xdf # First build & run tests using SBT -sbt core/test scalaplugin/test bin/test:assembly +sbt core/test scalaplugin/test scalajsplugin/test bin/test:assembly # Build Mill using SBT bin/target/mill devAssembly -# Secpmd build & run tests using Mill +# Second build & run tests using Mill out/devAssembly Core.test out/devAssembly ScalaPlugin.test +out/devAssembly ScalaJSPlugin.test out/devAssembly devAssembly
\ No newline at end of file |