summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillaume Martres <smarter@ubuntu.com>2018-08-25 18:28:59 +0900
committerGitHub <noreply@github.com>2018-08-25 18:28:59 +0900
commit146d58bc5d98da1d142758f974d4d5de6f5948bf (patch)
tree1395134291f0bdf474ba8e7e6d846bbdb04a126b
parente4d16b38e76884c06ce74903a318b1a148c7a63d (diff)
downloadmill-146d58bc5d98da1d142758f974d4d5de6f5948bf.tar.gz
mill-146d58bc5d98da1d142758f974d4d5de6f5948bf.tar.bz2
mill-146d58bc5d98da1d142758f974d4d5de6f5948bf.zip
Fix incremental compilation when a Scala project depends on a Java project (#414)
* Upgrade ammonite to 1.1.2-30-53edc31 This is mainly to get https://github.com/lihaoyi/Ammonite/pull/851 which should reduce the amount of unnecessary work done by incremental compilation in the Mill build. This requires some code changes since this means we now depend on a more recent version of coursier, as a side-effect this means that we do not depend on scalaz anymore. Also use the same ammonite version in the Mill build and in ScalaModule#ammoniteReplClasspath. Also remove an incorrect dependency in the caffeine integration test. This was always wrong but did not start failing until this commit, probably due to dependencies appearing in a different order on the classpath. * Rename ScalaWorker to ZincWorker Starting with the next commit, it will be used in Java-only projects too, so the name is misleading. * Upgrade to Zinc 1.2.1 * Fix incremental compilation when a Scala project depends on a Java project Before this commit, JavaModule#compile simply called javac unconditionally, thus generating new classfiles every time. But if a Scala project depends on a Java project, this will throw off the incremental compilation algorithm which will unnecessarily recompile files. To avoid this we now use Zinc to compile Java projects too (as a bonus this means that Java compilation becomes incremental). This required some refactoring in ZincWorkerImpl to be able to compile stuff without having to pass Scala-specific options. The issue solved by this commit could be reproduced by running in the Mill repository: $ mill main.compile $ mill -i @ main.compile() and observing that before this commit, the `main.compile()` call ended up recompiling code.
-rwxr-xr-xbuild.sc5
-rw-r--r--docs/VisualizePlan.svg30
-rw-r--r--docs/pages/2 - Configuring Mill.md6
-rw-r--r--docs/pages/5 - Modules.md2
-rw-r--r--integration/test/resources/caffeine/build.sc7
-rw-r--r--main/src/mill/modules/Jvm.scala23
-rw-r--r--scalajslib/src/mill/scalajslib/ScalaJSModule.scala2
-rw-r--r--scalalib/src/mill/scalalib/JavaModule.scala34
-rw-r--r--scalalib/src/mill/scalalib/Lib.scala30
-rw-r--r--scalalib/src/mill/scalalib/ScalaModule.scala35
-rw-r--r--scalalib/src/mill/scalalib/Versions.scala4
-rw-r--r--scalalib/src/mill/scalalib/ZincWorkerApi.scala (renamed from scalalib/src/mill/scalalib/ScalaWorkerApi.scala)32
-rw-r--r--scalalib/src/mill/scalalib/dependency/metadata/MavenMetadataLoader.scala6
-rw-r--r--scalalib/src/mill/scalalib/scalafmt/ScalafmtModule.scala2
-rw-r--r--scalalib/test/src/mill/scalalib/dependency/metadata/MetadataLoaderFactoryTests.scala4
-rw-r--r--scalalib/worker/src/mill/scalalib/worker/ZincWorkerImpl.scala (renamed from scalalib/worker/src/mill/scalalib/worker/ScalaWorkerImpl.scala)133
-rw-r--r--scalanativelib/src/mill/scalanativelib/ScalaNativeModule.scala4
17 files changed, 194 insertions, 165 deletions
diff --git a/build.sc b/build.sc
index 456260d6..b2745404 100755
--- a/build.sc
+++ b/build.sc
@@ -85,7 +85,8 @@ object main extends MillModule {
)
def ivyDeps = Agg(
- ivy"com.lihaoyi:::ammonite:1.1.2-6-27842d9",
+ // Keep synchronized with ammonite in Versions.scala
+ ivy"com.lihaoyi:::ammonite:1.1.2-30-53edc31",
// Necessary so we can share the JNA classes throughout the build process
ivy"net.java.dev.jna:jna:4.5.0",
ivy"net.java.dev.jna:jna-platform:4.5.0"
@@ -176,7 +177,7 @@ object scalalib extends MillModule {
def ivyDeps = Agg(
// Keep synchronized with zinc in Versions.scala
- ivy"org.scala-sbt::zinc:1.1.7"
+ ivy"org.scala-sbt::zinc:1.2.1"
)
def testArgs = Seq(
"-DMILL_SCALA_WORKER=" + runClasspath().map(_.path).mkString(",")
diff --git a/docs/VisualizePlan.svg b/docs/VisualizePlan.svg
index f6e50b39..9f13384f 100644
--- a/docs/VisualizePlan.svg
+++ b/docs/VisualizePlan.svg
@@ -3,33 +3,33 @@
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 328)">
<title>example1</title>
<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-328 3469.1473,-328 3469.1473,4 -4,4"/>
-<!-- mill.scalalib.ScalaWorkerModule.classpath -->
+<!-- mill.scalalib.ZincWorkerModule.classpath -->
<g id="node1" class="node">
-<title>mill.scalalib.ScalaWorkerModule.classpath</title>
+<title>mill.scalalib.ZincWorkerModule.classpath</title>
<ellipse fill="none" stroke="#000000" stroke-dasharray="1,5" cx="179.1736" cy="-162" rx="179.3473" ry="18"/>
-<text text-anchor="middle" x="179.1736" y="-157.8" font-family="Times,serif" font-size="14.00" fill="#000000">mill.scalalib.ScalaWorkerModule.classpath</text>
+<text text-anchor="middle" x="179.1736" y="-157.8" font-family="Times,serif" font-size="14.00" fill="#000000">mill.scalalib.ZincWorkerModule.classpath</text>
</g>
-<!-- mill.scalalib.ScalaWorkerModule.compilerInterfaceClasspath -->
+<!-- mill.scalalib.ZincWorkerModule.compilerInterfaceClasspath -->
<g id="node2" class="node">
-<title>mill.scalalib.ScalaWorkerModule.compilerInterfaceClasspath</title>
+<title>mill.scalalib.ZincWorkerModule.compilerInterfaceClasspath</title>
<ellipse fill="none" stroke="#000000" stroke-dasharray="1,5" cx="626.1736" cy="-162" rx="249.9102" ry="18"/>
-<text text-anchor="middle" x="626.1736" y="-157.8" font-family="Times,serif" font-size="14.00" fill="#000000">mill.scalalib.ScalaWorkerModule.compilerInterfaceClasspath</text>
+<text text-anchor="middle" x="626.1736" y="-157.8" font-family="Times,serif" font-size="14.00" fill="#000000">mill.scalalib.ZincWorkerModule.compilerInterfaceClasspath</text>
</g>
-<!-- mill.scalalib.ScalaWorkerModule.worker -->
+<!-- mill.scalalib.ZincWorkerModule.worker -->
<g id="node3" class="node">
-<title>mill.scalalib.ScalaWorkerModule.worker</title>
+<title>mill.scalalib.ZincWorkerModule.worker</title>
<ellipse fill="none" stroke="#000000" stroke-dasharray="1,5" cx="626.1736" cy="-234" rx="171.2452" ry="18"/>
-<text text-anchor="middle" x="626.1736" y="-229.8" font-family="Times,serif" font-size="14.00" fill="#000000">mill.scalalib.ScalaWorkerModule.worker</text>
+<text text-anchor="middle" x="626.1736" y="-229.8" font-family="Times,serif" font-size="14.00" fill="#000000">mill.scalalib.ZincWorkerModule.worker</text>
</g>
-<!-- mill.scalalib.ScalaWorkerModule.worker&#45;&gt;mill.scalalib.ScalaWorkerModule.classpath -->
+<!-- mill.scalalib.ZincWorkerModule.worker&#45;&gt;mill.scalalib.ZincWorkerModule.classpath -->
<g id="edge1" class="edge">
-<title>mill.scalalib.ScalaWorkerModule.worker&#45;&gt;mill.scalalib.ScalaWorkerModule.classpath</title>
+<title>mill.scalalib.ZincWorkerModule.worker&#45;&gt;mill.scalalib.ZincWorkerModule.classpath</title>
<path fill="none" stroke="#000000" d="M532.4677,-218.9064C459.9462,-207.2251 359.5232,-191.0496 284.2741,-178.9289"/>
<polygon fill="#000000" stroke="#000000" points="284.7249,-175.4565 274.2956,-177.3217 283.6117,-182.3675 284.7249,-175.4565"/>
</g>
-<!-- mill.scalalib.ScalaWorkerModule.worker&#45;&gt;mill.scalalib.ScalaWorkerModule.compilerInterfaceClasspath -->
+<!-- mill.scalalib.ZincWorkerModule.worker&#45;&gt;mill.scalalib.ZincWorkerModule.compilerInterfaceClasspath -->
<g id="edge2" class="edge">
-<title>mill.scalalib.ScalaWorkerModule.worker&#45;&gt;mill.scalalib.ScalaWorkerModule.compilerInterfaceClasspath</title>
+<title>mill.scalalib.ZincWorkerModule.worker&#45;&gt;mill.scalalib.ZincWorkerModule.compilerInterfaceClasspath</title>
<path fill="none" stroke="#000000" d="M626.1736,-215.8314C626.1736,-208.131 626.1736,-198.9743 626.1736,-190.4166"/>
<polygon fill="#000000" stroke="#000000" points="629.6737,-190.4132 626.1736,-180.4133 622.6737,-190.4133 629.6737,-190.4132"/>
</g>
@@ -297,9 +297,9 @@
<ellipse fill="none" stroke="#000000" cx="1913.1736" cy="-306" rx="89.7283" ry="18"/>
<text text-anchor="middle" x="1913.1736" y="-301.8" font-family="Times,serif" font-size="14.00" fill="#000000">moduledefs.compile</text>
</g>
-<!-- moduledefs.compile&#45;&gt;mill.scalalib.ScalaWorkerModule.worker -->
+<!-- moduledefs.compile&#45;&gt;mill.scalalib.ZincWorkerModule.worker -->
<g id="edge24" class="edge">
-<title>moduledefs.compile&#45;&gt;mill.scalalib.ScalaWorkerModule.worker</title>
+<title>moduledefs.compile&#45;&gt;mill.scalalib.ZincWorkerModule.worker</title>
<path fill="none" stroke="#000000" d="M1824.9751,-302.6013C1641.2815,-295.2954 1204.2998,-276.7314 838.1736,-252 814.9556,-250.4316 790.326,-248.5451 766.3857,-246.592"/>
<polygon fill="#000000" stroke="#000000" points="766.4274,-243.0836 756.174,-245.7515 765.8532,-250.06 766.4274,-243.0836"/>
</g>
diff --git a/docs/pages/2 - Configuring Mill.md b/docs/pages/2 - Configuring Mill.md
index 7db19833..989272dd 100644
--- a/docs/pages/2 - Configuring Mill.md
+++ b/docs/pages/2 - Configuring Mill.md
@@ -72,20 +72,20 @@ def repositories = super.repositories ++ Seq(
```
To add custom resolvers to the initial bootstrap of the build, you can create a
-custom `ScalaWorkerModule`, and override the `scalaWorker` method in your
+custom `ZincWorkerModule`, and override the `zincWorker` method in your
`ScalaModule` by pointing it to that custom object:
```scala
import coursier.maven.MavenRepository
-object CustomScalaWorkerModule extends ScalaWorkerModule {
+object CustomZincWorkerModule extends ZincWorkerModule {
def repositories() = super.repositories ++ Seq(
MavenRepository("https://oss.sonatype.org/content/repositories/releases")
)
}
object YourBuild extends ScalaModule {
- def scalaWorker = CustomScalaWorkerModule
+ def zincWorker = CustomZincWorkerModule
// ... rest of your build definitions
}
```
diff --git a/docs/pages/5 - Modules.md b/docs/pages/5 - Modules.md
index 2c13a3e9..fa6260f3 100644
--- a/docs/pages/5 - Modules.md
+++ b/docs/pages/5 - Modules.md
@@ -152,7 +152,7 @@ mill foo.Bar/qux
`ExternalModule`s are useful for someone providing a library for use with Mill
that is shared by the entire build: for example,
-`mill.scalalib.ScalaWorkerApi/scalaWorker` provides a shared Scala compilation
+`mill.scalalib.ZincWorkerApi/zincWorker` provides a shared Scala compilation
service & cache that is shared between all `ScalaModule`s, and
`mill.scalalib.GenIdea/idea` lets you generate IntelliJ projects without
needing to define your own `T.command` in your `build.sc` file
diff --git a/integration/test/resources/caffeine/build.sc b/integration/test/resources/caffeine/build.sc
index aaa66626..a4967f31 100644
--- a/integration/test/resources/caffeine/build.sc
+++ b/integration/test/resources/caffeine/build.sc
@@ -8,11 +8,11 @@ import deps.{benchmarkLibraries, benchmarkVersions, libraries, testLibraries, te
trait CaffeineModule extends MavenModule{
def repositories = super.repositories ++ Seq(
- coursier.ivy.IvyRepository(
+ coursier.ivy.IvyRepository.parse(
"https://dl.bintray.com/sbt/sbt-plugin-releases/" +
coursier.ivy.Pattern.default.string,
dropInfoAttributes = true
- ),
+ ).toOption.get,
MavenRepository("https://jcenter.bintray.com/"),
MavenRepository("https://jitpack.io/"),
MavenRepository("http://repo.spring.io/plugins-release")
@@ -25,7 +25,6 @@ trait CaffeineModule extends MavenModule{
libraries.guava,
testLibraries.mockito,
testLibraries.hamcrest,
- ivy"org.hamcrest:hamcrest-library:1.3",
testLibraries.awaitility,
) ++
testLibraries.testng ++
@@ -151,4 +150,4 @@ object simulator extends CaffeineModule {
def ivyDeps = super.ivyDeps() ++ testLibraries.testng
}
-} \ No newline at end of file
+}
diff --git a/main/src/mill/modules/Jvm.scala b/main/src/mill/modules/Jvm.scala
index 3a6dcb9f..96992d20 100644
--- a/main/src/mill/modules/Jvm.scala
+++ b/main/src/mill/modules/Jvm.scala
@@ -10,6 +10,7 @@ import java.util.jar.{JarEntry, JarFile, JarOutputStream}
import ammonite.ops._
import coursier.{Cache, Dependency, Fetch, Repository, Resolution}
+import coursier.util.{Gather, Task}
import geny.Generator
import mill.main.client.InputPumper
import mill.eval.{PathRef, Result}
@@ -383,7 +384,7 @@ object Jvm {
/**
* Resolve dependencies using Coursier.
*
- * We do not bother breaking this out into the separate ScalaWorker classpath,
+ * We do not bother breaking this out into the separate ZincWorkerApi classpath,
* because Coursier is already bundled with mill/Ammonite to support the
* `import $ivy` syntax.
*/
@@ -413,17 +414,19 @@ object Jvm {
def load(artifacts: Seq[coursier.Artifact]) = {
val logger = None
- val loadedArtifacts = scalaz.concurrent.Task.gatherUnordered(
+
+ import scala.concurrent.ExecutionContext.Implicits.global
+ val loadedArtifacts = Gather[Task].gather(
for (a <- artifacts)
- yield coursier.Cache.file(a, logger = logger).run
+ yield coursier.Cache.file[Task](a, logger = logger).run
.map(a.isOptional -> _)
- ).unsafePerformSync
+ ).unsafeRun
val errors = loadedArtifacts.collect {
- case (false, scalaz.-\/(x)) => x
- case (true, scalaz.-\/(x)) if !x.notFound => x
+ case (false, Left(x)) => x
+ case (true, Left(x)) if !x.notFound => x
}
- val successes = loadedArtifacts.collect { case (_, scalaz.\/-(x)) => x }
+ val successes = loadedArtifacts.collect { case (_, Right(x)) => x }
(errors, successes)
}
@@ -459,8 +462,10 @@ object Jvm {
mapDependencies = mapDependencies
)
- val fetch = Fetch.from(repositories, Cache.fetch())
- val resolution = start.process.run(fetch).unsafePerformSync
+ val fetch = Fetch.from(repositories, Cache.fetch[Task]())
+
+ import scala.concurrent.ExecutionContext.Implicits.global
+ val resolution = start.process.run(fetch).unsafeRun()
(deps.toSeq, resolution)
}
}
diff --git a/scalajslib/src/mill/scalajslib/ScalaJSModule.scala b/scalajslib/src/mill/scalajslib/ScalaJSModule.scala
index efa4dfe0..e0ee55a5 100644
--- a/scalajslib/src/mill/scalajslib/ScalaJSModule.scala
+++ b/scalajslib/src/mill/scalajslib/ScalaJSModule.scala
@@ -15,7 +15,7 @@ trait ScalaJSModule extends scalalib.ScalaModule { outer =>
def scalaJSVersion: T[String]
trait Tests extends TestScalaJSModule {
- override def scalaWorker = outer.scalaWorker
+ override def zincWorker = outer.zincWorker
override def scalaOrganization = outer.scalaOrganization()
override def scalaVersion = outer.scalaVersion()
override def scalaJSVersion = outer.scalaJSVersion()
diff --git a/scalalib/src/mill/scalalib/JavaModule.scala b/scalalib/src/mill/scalalib/JavaModule.scala
index 259e5cd3..ab4f8795 100644
--- a/scalalib/src/mill/scalalib/JavaModule.scala
+++ b/scalalib/src/mill/scalalib/JavaModule.scala
@@ -17,12 +17,13 @@ import mill.util.Loose.Agg
* Core configuration required to compile a single Scala compilation target
*/
trait JavaModule extends mill.Module with TaskModule { outer =>
- def scalaWorker: ScalaWorkerModule = mill.scalalib.ScalaWorkerModule
+ def zincWorker: ZincWorkerModule = mill.scalalib.ZincWorkerModule
trait Tests extends TestModule{
override def moduleDeps = Seq(outer)
override def repositories = outer.repositories
override def javacOptions = outer.javacOptions
+ override def zincWorker = outer.zincWorker
}
def defaultCommandName() = "run"
@@ -38,7 +39,16 @@ trait JavaModule extends mill.Module with TaskModule { outer =>
def finalMainClassOpt: T[Either[String, String]] = T{
mainClass() match{
case Some(m) => Right(m)
- case None => Left("No main class specified or found")
+ case None =>
+ zincWorker.worker().discoverMainClasses(compile())match {
+ case Seq() => Left("No main class specified or found")
+ case Seq(main) => Right(main)
+ case mains =>
+ Left(
+ s"Multiple main classes found (${mains.mkString(",")}) " +
+ "please explicitly specify which one to use by overriding mainClass"
+ )
+ }
}
}
@@ -98,7 +108,7 @@ trait JavaModule extends mill.Module with TaskModule { outer =>
}
- def repositories: Seq[Repository] = scalaWorker.repositories
+ def repositories: Seq[Repository] = zincWorker.repositories
def platformSuffix = T{ "" }
@@ -133,12 +143,12 @@ trait JavaModule extends mill.Module with TaskModule { outer =>
} yield PathRef(path)
}
- def compile: T[CompilationResult] = T{
- Lib.compileJava(
- allSourceFiles().map(_.path.toIO).toArray,
- compileClasspath().map(_.path.toIO).toArray,
- javacOptions(),
- upstreamCompileOutput()
+ def compile: T[CompilationResult] = T.persistent{
+ zincWorker.worker().compileJava(
+ upstreamCompileOutput(),
+ allSourceFiles().map(_.path),
+ compileClasspath().map(_.path),
+ javacOptions()
)
}
@@ -317,7 +327,7 @@ trait JavaModule extends mill.Module with TaskModule { outer =>
val (procId, procTombstone, token) = backgroundSetup(T.ctx().dest)
try Result.Success(Jvm.interactiveSubprocess(
"mill.scalalib.backgroundwrapper.BackgroundWrapper",
- (runClasspath() ++ scalaWorker.backgroundWrapperClasspath()).map(_.path),
+ (runClasspath() ++ zincWorker.backgroundWrapperClasspath()).map(_.path),
forkArgs(),
forkEnv(),
Seq(procId.toString, procTombstone.toString, token, finalMainClass()) ++ args,
@@ -332,7 +342,7 @@ trait JavaModule extends mill.Module with TaskModule { outer =>
val (procId, procTombstone, token) = backgroundSetup(T.ctx().dest)
try Result.Success(Jvm.interactiveSubprocess(
"mill.scalalib.backgroundwrapper.BackgroundWrapper",
- (runClasspath() ++ scalaWorker.backgroundWrapperClasspath()).map(_.path),
+ (runClasspath() ++ zincWorker.backgroundWrapperClasspath()).map(_.path),
forkArgs(),
forkEnv(),
Seq(procId.toString, procTombstone.toString, token, mainClass) ++ args,
@@ -384,7 +394,7 @@ trait TestModule extends JavaModule with TaskModule {
Jvm.subprocess(
mainClass = "mill.scalalib.TestRunner",
- classPath = scalaWorker.scalalibClasspath().map(_.path),
+ classPath = zincWorker.scalalibClasspath().map(_.path),
jvmArgs = forkArgs(),
envArgs = forkEnv(),
mainArgs =
diff --git a/scalalib/src/mill/scalalib/Lib.scala b/scalalib/src/mill/scalalib/Lib.scala
index e890caaf..827c6bf4 100644
--- a/scalalib/src/mill/scalalib/Lib.scala
+++ b/scalalib/src/mill/scalalib/Lib.scala
@@ -27,34 +27,6 @@ object CompilationResult {
case class CompilationResult(analysisFile: Path, classes: PathRef)
object Lib{
- def compileJava(sources: Array[java.io.File],
- classpath: Array[java.io.File],
- javaOpts: Seq[String],
- upstreamCompileOutput: Seq[CompilationResult])
- (implicit ctx: mill.util.Ctx) = {
- val javac = ToolProvider.getSystemJavaCompiler()
- if (javac == null) {
- throw new Exception(
- "Your Java installation is not a JDK, so it can't compile Java code;" +
- " Please install the JDK version of Java")
- }
-
- rm(ctx.dest / 'classes)
- mkdir(ctx.dest / 'classes)
- val cpArgs =
- if(classpath.isEmpty) Seq()
- else Seq("-cp", classpath.mkString(File.pathSeparator))
-
- val args = Seq("-d", ctx.dest / 'classes) ++ cpArgs ++ javaOpts ++ sources
-
- javac.run(
- ctx.log.inStream, ctx.log.outputStream, ctx.log.errorStream,
- args.map(_.toString):_*
- )
- if (ls(ctx.dest / 'classes).isEmpty) mill.eval.Result.Failure("Compilation Failed")
- else mill.eval.Result.Success(CompilationResult(ctx.dest / 'zinc, PathRef(ctx.dest / 'classes)))
- }
-
private val ReleaseVersion = raw"""(\d+)\.(\d+)\.(\d+)""".r
private val MinorSnapshotVersion = raw"""(\d+)\.(\d+)\.([1-9]\d*)-SNAPSHOT""".r
private val DottyVersion = raw"""0\.(\d+)\.(\d+).*""".r
@@ -104,7 +76,7 @@ object Lib{
/**
* Resolve dependencies using Coursier.
*
- * We do not bother breaking this out into the separate ScalaWorker classpath,
+ * We do not bother breaking this out into the separate ZincWorker classpath,
* because Coursier is already bundled with mill/Ammonite to support the
* `import $ivy` syntax.
*/
diff --git a/scalalib/src/mill/scalalib/ScalaModule.scala b/scalalib/src/mill/scalalib/ScalaModule.scala
index 1899ee14..3e90521e 100644
--- a/scalalib/src/mill/scalalib/ScalaModule.scala
+++ b/scalalib/src/mill/scalalib/ScalaModule.scala
@@ -24,7 +24,7 @@ trait ScalaModule extends JavaModule { outer =>
override def scalacPluginIvyDeps = outer.scalacPluginIvyDeps
override def scalacOptions = outer.scalacOptions
override def javacOptions = outer.javacOptions
- override def scalaWorker = outer.scalaWorker
+ override def zincWorker = outer.zincWorker
override def moduleDeps: Seq[JavaModule] = Seq(outer)
}
@@ -60,29 +60,10 @@ trait ScalaModule extends JavaModule { outer =>
)
}
- override def finalMainClassOpt: T[Either[String, String]] = T{
- mainClass() match{
- case Some(m) => Right(m)
- case None =>
- scalaWorker.worker().discoverMainClasses(compile())match {
- case Seq() => Left("No main class specified or found")
- case Seq(main) => Right(main)
- case mains =>
- Left(
- s"Multiple main classes found (${mains.mkString(",")}) " +
- "please explicitly specify which one to use by overriding mainClass"
- )
- }
- }
- }
-
-
def scalacPluginIvyDeps = T{ Agg.empty[Dep] }
def scalacOptions = T{ Seq.empty[String] }
- override def repositories: Seq[Repository] = scalaWorker.repositories
-
private val Milestone213 = raw"""2.13.(\d+)-M(\d+)""".r
def scalaCompilerBridgeSources = T {
@@ -142,16 +123,16 @@ trait ScalaModule extends JavaModule { outer =>
}
override def compile: T[CompilationResult] = T.persistent{
- scalaWorker.worker().compileScala(
- scalaVersion(),
+ zincWorker.worker().compileMixed(
+ upstreamCompileOutput(),
allSourceFiles().map(_.path),
- scalaCompilerBridgeSources(),
compileClasspath().map(_.path),
- scalaCompilerClasspath().map(_.path),
+ javacOptions(),
+ scalaVersion(),
scalacOptions(),
+ scalaCompilerBridgeSources(),
+ scalaCompilerClasspath().map(_.path),
scalacPluginClasspath().map(_.path),
- javacOptions(),
- upstreamCompileOutput()
)
}
@@ -204,7 +185,7 @@ trait ScalaModule extends JavaModule { outer =>
unmanagedClasspath() ++
resolveDeps(T.task{
runIvyDeps() ++ scalaLibraryIvyDeps() ++ transitiveIvyDeps() ++
- Agg(ivy"com.lihaoyi:::ammonite:1.1.2")
+ Agg(ivy"com.lihaoyi:::ammonite:${Versions.ammonite}")
})()
}
diff --git a/scalalib/src/mill/scalalib/Versions.scala b/scalalib/src/mill/scalalib/Versions.scala
index 6c1c385f..bfcc5495 100644
--- a/scalalib/src/mill/scalalib/Versions.scala
+++ b/scalalib/src/mill/scalalib/Versions.scala
@@ -1,6 +1,8 @@
package mill.scalalib
object Versions {
+ // Keep synchronized with ammonite dependency in core in build.sc
+ val ammonite = "1.1.2-30-53edc31"
// Keep synchronized with zinc dependency in scalalib.worker in build.sc
- val zinc = "1.1.7"
+ val zinc = "1.2.1"
}
diff --git a/scalalib/src/mill/scalalib/ScalaWorkerApi.scala b/scalalib/src/mill/scalalib/ZincWorkerApi.scala
index 547cc5db..ebe2f071 100644
--- a/scalalib/src/mill/scalalib/ScalaWorkerApi.scala
+++ b/scalalib/src/mill/scalalib/ZincWorkerApi.scala
@@ -11,10 +11,10 @@ import mill.scalalib.Lib.resolveDependencies
import mill.util.Loose
import mill.util.JsonFormatters._
-object ScalaWorkerModule extends mill.define.ExternalModule with ScalaWorkerModule{
+object ZincWorkerModule extends mill.define.ExternalModule with ZincWorkerModule{
lazy val millDiscover = Discover[this.type]
}
-trait ScalaWorkerModule extends mill.Module{
+trait ZincWorkerModule extends mill.Module{
def repositories = Seq(
Cache.ivy2Local,
MavenRepository("https://repo1.maven.org/maven2"),
@@ -36,15 +36,15 @@ trait ScalaWorkerModule extends mill.Module{
)
}
- def worker: Worker[ScalaWorkerApi] = T.worker{
+ def worker: Worker[ZincWorkerApi] = T.worker{
val cl = mill.util.ClassLoader.create(
classpath().map(_.path.toNIO.toUri.toURL).toVector,
getClass.getClassLoader
)
- val cls = cl.loadClass("mill.scalalib.worker.ScalaWorkerImpl")
+ val cls = cl.loadClass("mill.scalalib.worker.ZincWorkerImpl")
val instance = cls.getConstructor(classOf[mill.util.Ctx], classOf[Array[String]])
.newInstance(T.ctx(), compilerInterfaceClasspath().map(_.path.toString).toArray[String])
- instance.asInstanceOf[ScalaWorkerApi]
+ instance.asInstanceOf[ZincWorkerApi]
}
def compilerInterfaceClasspath = T{
@@ -57,20 +57,26 @@ trait ScalaWorkerModule extends mill.Module{
}
-trait ScalaWorkerApi {
+trait ZincWorkerApi {
+ /** Compile a Java-only project */
+ def compileJava(upstreamCompileOutput: Seq[CompilationResult],
+ sources: Agg[Path],
+ compileClasspath: Agg[Path],
+ javacOptions: Seq[String])
+ (implicit ctx: mill.util.Ctx): mill.eval.Result[CompilationResult]
- def compileScala(scalaVersion: String,
+ /** Compile a mixed Scala/Java or Scala-only project */
+ def compileMixed(upstreamCompileOutput: Seq[CompilationResult],
sources: Agg[Path],
- compilerBridgeSources: Path,
compileClasspath: Agg[Path],
- compilerClasspath: Agg[Path],
- scalacOptions: Seq[String],
- scalacPluginClasspath: Agg[Path],
javacOptions: Seq[String],
- upstreamCompileOutput: Seq[CompilationResult])
+ scalaVersion: String,
+ scalacOptions: Seq[String],
+ compilerBridgeSources: Path,
+ compilerClasspath: Agg[Path],
+ scalacPluginClasspath: Agg[Path])
(implicit ctx: mill.util.Ctx): mill.eval.Result[CompilationResult]
-
def discoverMainClasses(compilationResult: CompilationResult)
(implicit ctx: mill.util.Ctx): Seq[String]
}
diff --git a/scalalib/src/mill/scalalib/dependency/metadata/MavenMetadataLoader.scala b/scalalib/src/mill/scalalib/dependency/metadata/MavenMetadataLoader.scala
index 7f25764b..491911bf 100644
--- a/scalalib/src/mill/scalalib/dependency/metadata/MavenMetadataLoader.scala
+++ b/scalalib/src/mill/scalalib/dependency/metadata/MavenMetadataLoader.scala
@@ -2,16 +2,18 @@ package mill.scalalib.dependency.metadata
import coursier.Cache
import coursier.maven.MavenRepository
+import coursier.util.Task
import mill.scalalib.dependency.versions.Version
private[dependency] final case class MavenMetadataLoader(mavenRepo: MavenRepository)
extends MetadataLoader {
- private val fetch = Cache.fetch()
+ private val fetch = Cache.fetch[Task]()
override def getVersions(module: coursier.Module): List[Version] = {
+ import scala.concurrent.ExecutionContext.Implicits.global
// TODO fallback to 'versionsFromListing' if 'versions' doesn't work? (needs to be made public in coursier first)
- val allVersions = mavenRepo.versions(module, fetch).run.unsafePerformSync
+ val allVersions = mavenRepo.versions(module, fetch).run.unsafeRun
allVersions
.map(_.available.map(Version(_)))
.getOrElse(List.empty)
diff --git a/scalalib/src/mill/scalalib/scalafmt/ScalafmtModule.scala b/scalalib/src/mill/scalalib/scalafmt/ScalafmtModule.scala
index c4d64b0e..74f64e28 100644
--- a/scalalib/src/mill/scalalib/scalafmt/ScalafmtModule.scala
+++ b/scalalib/src/mill/scalalib/scalafmt/ScalafmtModule.scala
@@ -23,7 +23,7 @@ trait ScalafmtModule extends JavaModule {
def scalafmtDeps: T[Agg[PathRef]] = T {
Lib.resolveDependencies(
- scalaWorker.repositories,
+ zincWorker.repositories,
Lib.depToDependency(_, "2.12.4"),
Seq(ivy"com.geirsson::scalafmt-cli:${scalafmtVersion()}")
)
diff --git a/scalalib/test/src/mill/scalalib/dependency/metadata/MetadataLoaderFactoryTests.scala b/scalalib/test/src/mill/scalalib/dependency/metadata/MetadataLoaderFactoryTests.scala
index 8187976c..4c2206b8 100644
--- a/scalalib/test/src/mill/scalalib/dependency/metadata/MetadataLoaderFactoryTests.scala
+++ b/scalalib/test/src/mill/scalalib/dependency/metadata/MetadataLoaderFactoryTests.scala
@@ -32,7 +32,7 @@ import coursier.Fetch.Content
import coursier.core.{Artifact, Module, Project, Repository}
import coursier.ivy.IvyRepository
import coursier.maven.MavenRepository
-import scalaz.{EitherT, Monad}
+import coursier.util.{EitherT, Monad}
import utest._
object MetadataLoaderFactoryTests extends TestSuite {
@@ -45,7 +45,7 @@ object MetadataLoaderFactoryTests extends TestSuite {
}
}
'ivyRepository - {
- val ivyRepo = IvyRepository(
+ val Right(ivyRepo) = IvyRepository.parse(
"https://dl.bintray.com/sbt/sbt-plugin-releases/" + coursier.ivy.Pattern.default.string,
dropInfoAttributes = true)
assertMatch(MetadataLoaderFactory(ivyRepo)) { case None => }
diff --git a/scalalib/worker/src/mill/scalalib/worker/ScalaWorkerImpl.scala b/scalalib/worker/src/mill/scalalib/worker/ZincWorkerImpl.scala
index ebeb9561..6b21de84 100644
--- a/scalalib/worker/src/mill/scalalib/worker/ScalaWorkerImpl.scala
+++ b/scalalib/worker/src/mill/scalalib/worker/ZincWorkerImpl.scala
@@ -24,9 +24,31 @@ case class MockedLookup(am: File => Optional[CompileAnalysis]) extends PerClassp
Locate.definesClass(classpathEntry)
}
-class ScalaWorkerImpl(ctx0: mill.util.Ctx,
- compilerBridgeClasspath: Array[String]) extends mill.scalalib.ScalaWorkerApi{
- @volatile var compilersCache = Option.empty[(Long, Compilers)]
+class ZincWorkerImpl(ctx0: mill.util.Ctx,
+ compilerBridgeClasspath: Array[String]) extends mill.scalalib.ZincWorkerApi{
+ private val ic = new sbt.internal.inc.IncrementalCompilerImpl()
+ val javaOnlyCompilers = {
+ // Keep the classpath as written by the user
+ val classpathOptions = ClasspathOptions.of(false, false, false, false, false)
+
+ val dummyFile = new java.io.File("")
+ // Zinc does not have an entry point for Java-only compilation, so we need
+ // to make up a dummy ScalaCompiler instance.
+ val scalac = ZincUtil.scalaCompiler(
+ new ScalaInstance("", null, null, dummyFile, dummyFile, new Array(0), Some("")), null,
+ classpathOptions // this is used for javac too
+ )
+
+ ic.compilers(
+ instance = null,
+ classpathOptions,
+ None,
+ scalac
+ )
+ }
+
+ @volatile var mixedCompilersCache = Option.empty[(Long, Compilers)]
+
/** Compile the bridge if it doesn't exist yet and return the output directory.
* TODO: Proper invalidation, see #389
@@ -78,27 +100,38 @@ class ScalaWorkerImpl(ctx0: mill.util.Ctx,
.getOrElse(Seq.empty[String])
}
+ def compileJava(upstreamCompileOutput: Seq[CompilationResult],
+ sources: Agg[Path],
+ compileClasspath: Agg[Path],
+ javacOptions: Seq[String])
+ (implicit ctx: mill.util.Ctx): mill.eval.Result[CompilationResult] = {
+ compileInternal(
+ upstreamCompileOutput,
+ sources,
+ compileClasspath,
+ javacOptions,
+ scalacOptions = Nil,
+ javaOnlyCompilers
+ )
+ }
- def compileScala(scalaVersion: String,
+ def compileMixed(upstreamCompileOutput: Seq[CompilationResult],
sources: Agg[Path],
- compilerBridgeSources: Path,
compileClasspath: Agg[Path],
- compilerClasspath: Agg[Path],
- scalacOptions: Seq[String],
- scalacPluginClasspath: Agg[Path],
javacOptions: Seq[String],
- upstreamCompileOutput: Seq[CompilationResult])
+ scalaVersion: String,
+ scalacOptions: Seq[String],
+ compilerBridgeSources: Path,
+ compilerClasspath: Agg[Path],
+ scalacPluginClasspath: Agg[Path])
(implicit ctx: mill.util.Ctx): mill.eval.Result[CompilationResult] = {
- val compileClasspathFiles = compileClasspath.map(_.toIO).toArray
val compilerJars = compilerClasspath.toArray.map(_.toIO)
val compilerBridge = compileZincBridgeIfNeeded(scalaVersion, compilerBridgeSources, compilerJars)
-
- val ic = new sbt.internal.inc.IncrementalCompilerImpl()
-
val compilerBridgeSig = compilerBridge.mtime.toMillis
+
val compilersSig = compilerBridgeSig + compilerClasspath.map(p => p.toString().hashCode + p.mtime.toMillis).sum
- val compilers = compilersCache match {
+ val compilers = mixedCompilersCache match {
case Some((k, v)) if k == compilersSig => v
case _ =>
val compilerName =
@@ -120,12 +153,28 @@ class ScalaWorkerImpl(ctx0: mill.util.Ctx,
None,
ZincUtil.scalaCompiler(scalaInstance, compilerBridge.toIO)
)
- compilersCache = Some((compilersSig, compilers))
+ mixedCompilersCache = Some((compilersSig, compilers))
compilers
}
- mkdir(ctx.dest)
+ compileInternal(
+ upstreamCompileOutput,
+ sources,
+ compileClasspath,
+ javacOptions,
+ scalacOptions = scalacPluginClasspath.map(jar => s"-Xplugin:${jar}").toSeq ++ scalacOptions,
+ compilers
+ )
+ }
+ private def compileInternal(upstreamCompileOutput: Seq[CompilationResult],
+ sources: Agg[Path],
+ compileClasspath: Agg[Path],
+ javacOptions: Seq[String],
+ scalacOptions: Seq[String],
+ compilers: Compilers)
+ (implicit ctx: mill.util.Ctx): mill.eval.Result[CompilationResult] = {
+ mkdir(ctx.dest)
val logger = {
val consoleAppender = MainAppender.defaultScreen(ConsoleOut.printStreamOut(
@@ -158,33 +207,35 @@ class ScalaWorkerImpl(ctx0: mill.util.Ctx,
val store = FileAnalysisStore.binary(zincIOFile)
+ val inputs = ic.inputs(
+ classpath = classesIODir +: compileClasspath.map(_.toIO).toArray,
+ sources = sources.toArray.map(_.toIO),
+ classesDirectory = classesIODir,
+ scalacOptions = scalacOptions.toArray,
+ javacOptions = javacOptions.toArray,
+ maxErrors = 10,
+ sourcePositionMappers = Array(),
+ order = CompileOrder.Mixed,
+ compilers = compilers,
+ setup = ic.setup(
+ lookup,
+ skip = false,
+ zincIOFile,
+ new FreshCompilerCache,
+ IncOptions.of(),
+ new ManagedLoggedReporter(10, logger),
+ None,
+ Array()
+ ),
+ pr = {
+ val prev = store.get()
+ PreviousResult.of(prev.map(_.getAnalysis), prev.map(_.getMiniSetup))
+ }
+ )
+
try {
val newResult = ic.compile(
- ic.inputs(
- classpath = classesIODir +: compileClasspathFiles,
- sources = sources.toArray.map(_.toIO),
- classesDirectory = classesIODir,
- scalacOptions = (scalacPluginClasspath.map(jar => s"-Xplugin:${jar}") ++ scalacOptions).toArray,
- javacOptions = javacOptions.toArray,
- maxErrors = 10,
- sourcePositionMappers = Array(),
- order = CompileOrder.Mixed,
- compilers = compilers,
- setup = ic.setup(
- lookup,
- skip = false,
- zincIOFile,
- new FreshCompilerCache,
- IncOptions.of(),
- new ManagedLoggedReporter(10, logger),
- None,
- Array()
- ),
- pr = {
- val prev = store.get()
- PreviousResult.of(prev.map(_.getAnalysis), prev.map(_.getMiniSetup))
- }
- ),
+ in = inputs,
logger = logger
)
diff --git a/scalanativelib/src/mill/scalanativelib/ScalaNativeModule.scala b/scalanativelib/src/mill/scalanativelib/ScalaNativeModule.scala
index 5e4fc471..748afb79 100644
--- a/scalanativelib/src/mill/scalanativelib/ScalaNativeModule.scala
+++ b/scalanativelib/src/mill/scalanativelib/ScalaNativeModule.scala
@@ -46,7 +46,7 @@ trait ScalaNativeModule extends ScalaModule { outer =>
override def artifactSuffix: T[String] = s"${platformSuffix()}_${artifactScalaVersion()}"
trait Tests extends TestScalaNativeModule {
- override def scalaWorker = outer.scalaWorker
+ override def zincWorker = outer.zincWorker
override def scalaOrganization = outer.scalaOrganization()
override def scalaVersion = outer.scalaVersion()
override def scalaNativeVersion = outer.scalaNativeVersion()
@@ -238,7 +238,7 @@ trait TestScalaNativeModule extends ScalaNativeModule with TestModule { testOute
// creates a specific binary used for running tests - has a different (generated) main class
// which knows the names of all the tests and references to invoke them
object testRunnerNative extends ScalaNativeModule {
- override def scalaWorker = testOuter.scalaWorker
+ override def zincWorker = testOuter.zincWorker
override def scalaOrganization = testOuter.scalaOrganization()
override def scalaVersion = testOuter.scalaVersion()
override def scalaNativeVersion = testOuter.scalaNativeVersion()