diff options
-rw-r--r-- | scalalib/src/mill/scalalib/GenIdea.scala | 33 | ||||
-rw-r--r-- | scalalib/src/mill/scalalib/JavaModule.scala | 79 | ||||
-rw-r--r-- | scalalib/src/mill/scalalib/ScalaModule.scala | 36 | ||||
-rw-r--r-- | scalalib/src/mill/scalalib/ScalaWorkerApi.scala | 6 | ||||
-rw-r--r-- | scalalib/test/resources/hello-java/core/src/hello/Core.java | 8 | ||||
-rw-r--r-- | scalalib/test/resources/hello-java/main/src/hello/Main.java | 7 | ||||
-rw-r--r-- | scalalib/test/src/mill/scalalib/HelloJavaTests.scala | 60 | ||||
-rw-r--r-- | scalaworker/src/mill/scalaworker/ScalaWorker.scala | 31 |
8 files changed, 211 insertions, 49 deletions
diff --git a/scalalib/src/mill/scalalib/GenIdea.scala b/scalalib/src/mill/scalalib/GenIdea.scala index a67668e4..183d4a79 100644 --- a/scalalib/src/mill/scalalib/GenIdea.scala +++ b/scalalib/src/mill/scalalib/GenIdea.scala @@ -68,7 +68,7 @@ object GenIdea { val buildLibraryPaths = if (!fetchMillModules) Nil else sys.props.get("MILL_BUILD_LIBRARIES") match { - case Some(found) => Agg.from(found.split(',').map(Path(_)).distinct) + case Some(found) => found.split(',').map(Path(_)).distinct.toList case None => val repos = modules.foldLeft(Set.empty[Repository]) { _ ++ _._2.repositories } val artifactNames = Seq("moduledefs", "core", "scalalib", "scalajslib") @@ -78,11 +78,15 @@ object GenIdea { for(name <- artifactNames) yield ivy"com.lihaoyi::mill-$name:${sys.props("MILL_VERSION")}" ) - res.items.toSeq.map(_.path) + res.items.toList.map(_.path) } val resolved = for((path, mod) <- modules) yield { - val allIvyDeps = T.task{mod.transitiveIvyDeps() ++ mod.compileIvyDeps()} + val scalaLibraryIvyDeps = mod match{ + case x: ScalaModule => x.scalaLibraryIvyDeps + case _ => T.task{Nil} + } + val allIvyDeps = T.task{mod.transitiveIvyDeps() ++ scalaLibraryIvyDeps() ++ mod.compileIvyDeps()} val externalDependencies = T.task{ mod.resolveDeps(allIvyDeps)() ++ Task.traverse(mod.transitiveModuleDeps)(_.unmanagedClasspath)().flatten @@ -105,18 +109,27 @@ object GenIdea { val resolvedSp: Loose.Agg[PathRef] = evalOrElse(evaluator, scalacPluginDependencies, Loose.Agg.empty) val scalacOpts: Seq[String] = evalOrElse(evaluator, scalacOptions, Seq()) - (path, resolvedCp.map(_.path).filter(_.ext == "jar") ++ resolvedSrcs.map(_.path), mod, - resolvedSp.map(_.path).filter(_.ext == "jar"), scalacOpts) + ( + path, + resolvedCp.map(_.path).filter(_.ext == "jar") ++ resolvedSrcs.map(_.path), + mod, + resolvedSp.map(_.path).filter(_.ext == "jar"), + scalacOpts + ) } val moduleLabels = modules.map(_.swap).toMap val allResolved = resolved.flatMap(_._2) ++ buildLibraryPaths - val minResolvedLength = allResolved.map(_.segments.length).min - val commonPrefix = allResolved.map(_.segments.take(minResolvedLength)) - .transpose - .takeWhile(_.distinct.length == 1) - .length + val commonPrefix = + if (allResolved.isEmpty) 0 + else { + val minResolvedLength = allResolved.map(_.segments.length).min + allResolved.map(_.segments.take(minResolvedLength)) + .transpose + .takeWhile(_.distinct.length == 1) + .length + } // only resort to full long path names if the jar name is a duplicate val pathShortLibNameDuplicate = allResolved diff --git a/scalalib/src/mill/scalalib/JavaModule.scala b/scalalib/src/mill/scalalib/JavaModule.scala index 0b043bb4..19b81d43 100644 --- a/scalalib/src/mill/scalalib/JavaModule.scala +++ b/scalalib/src/mill/scalalib/JavaModule.scala @@ -1,12 +1,16 @@ package mill package scalalib +import java.nio.charset.Charset +import java.util +import javax.tools.{JavaFileObject, SimpleJavaFileObject, StandardJavaFileManager, ToolProvider} + import ammonite.ops._ import coursier.{Dependency, Repository} import mill.define.Task import mill.define.TaskModule import mill.eval.{PathRef, Result} -import mill.modules.Jvm +import mill.modules.{Jvm, Util} import mill.modules.Jvm.{createAssembly, createJar, subprocess} import Lib._ import mill.util.Loose.Agg @@ -16,6 +20,8 @@ import mill.util.DummyInputStream * 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 defaultCommandName() = "run" def mainClass: T[Option[String]] = None @@ -110,19 +116,13 @@ trait JavaModule extends mill.Module with TaskModule { outer => } yield PathRef(path) } - def compile: T[CompilationResult] = T.persistent{ -// scalaWorker.worker().compileScala( -// scalaVersion(), -// allSourceFiles().map(_.path), -// scalaCompilerBridgeSources(), -// compileClasspath().map(_.path), -// scalaCompilerClasspath().map(_.path), -// scalacOptions(), -// scalacPluginClasspath().map(_.path), -// javacOptions(), -// upstreamCompileOutput() -// ) - Result.Failure[CompilationResult]("???", None) + def compile: T[CompilationResult] = T{ + scalaWorker.worker().compileJava( + allSourceFiles().map(_.path.toIO).toArray, + compileClasspath().map(_.path.toIO).toArray, + javacOptions(), + upstreamCompileOutput() + ) } def localClasspath = T{ resources() ++ Agg(compile().classes) @@ -173,29 +173,34 @@ trait JavaModule extends mill.Module with TaskModule { outer => } def docJar = T[PathRef] { -// val outDir = T.ctx().dest -// -// val javadocDir = outDir / 'javadoc -// mkdir(javadocDir) -// -// val files = for{ -// ref <- allSources() -// if exists(ref.path) -// p <- ls.rec(ref.path) -// if p.isFile -// } yield p.toNIO.toString -// -// val options = Seq("-d", javadocDir.toNIO.toString, "-usejavacp") -// -// if (files.nonEmpty) subprocess( -// "scala.tools.nsc.ScalaDoc", -// scalaCompilerClasspath().map(_.path) ++ compileClasspath().filter(_.path.ext != "pom").map(_.path), -// mainArgs = (files ++ options).toSeq -// ) -// -// -// createJar(Agg(javadocDir))(outDir) - Result.Failure[PathRef]("", None) + val outDir = T.ctx().dest + + val javadocDir = outDir / 'javadoc + mkdir(javadocDir) + + val files = for{ + ref <- allSources() + if exists(ref.path) + p <- ls.rec(ref.path) + if p.isFile + } yield p.toNIO.toString + + val options = Seq("-d", javadocDir.toNIO.toString) + + if (files.nonEmpty) Jvm.baseInteractiveSubprocess( + commandArgs = Seq( + "javadoc" + ) ++ options ++ + Seq( + "-classpath", + compileClasspath().filter(_.path.ext != "pom").mkString(java.io.File.pathSeparator) + ) ++ + files.map(_.toString), + envArgs = Map(), + workingDir = T.ctx().dest + ) + + createJar(Agg(javadocDir))(outDir) } def sourceJar = T { diff --git a/scalalib/src/mill/scalalib/ScalaModule.scala b/scalalib/src/mill/scalalib/ScalaModule.scala index 6997c368..b3013d57 100644 --- a/scalalib/src/mill/scalalib/ScalaModule.scala +++ b/scalalib/src/mill/scalalib/ScalaModule.scala @@ -27,7 +27,7 @@ trait ScalaModule extends JavaModule { outer => } def scalaVersion: T[String] - def scalaWorker: ScalaWorkerModule = mill.scalalib.ScalaWorkerModule + override def finalMainClassOpt: T[Either[String, String]] = T{ mainClass() match{ @@ -81,6 +81,18 @@ trait ScalaModule extends JavaModule { outer => T.task{scalaCompilerIvyDeps(scalaVersion()) ++ scalaRuntimeIvyDeps(scalaVersion())} )() } + override def compileClasspath = T{ + transitiveLocalClasspath() ++ + resources() ++ + unmanagedClasspath() ++ + resolveDeps(T.task{compileIvyDeps() ++ scalaLibraryIvyDeps() ++ transitiveIvyDeps()})() + } + + override def upstreamAssemblyClasspath = T{ + transitiveLocalClasspath() ++ + unmanagedClasspath() ++ + resolveDeps(T.task{runIvyDeps() ++ scalaLibraryIvyDeps() ++ transitiveIvyDeps()})() + } override def compile: T[CompilationResult] = T.persistent{ scalaWorker.worker().compileScala( @@ -96,6 +108,17 @@ trait ScalaModule extends JavaModule { outer => ) } + override def ivyDepsTree(inverse: Boolean = false) = T.command { + val (flattened, resolution) = Lib.resolveDependenciesMetadata( + repositories, scalaVersion(), ivyDeps(), platformSuffix(), Some(mapDependencies) + ) + + println(coursier.util.Print.dependencyTree(flattened, resolution, + printExclusions = false, reverse = inverse)) + + Result.Success() + } + override def docJar = T { val outDir = T.ctx().dest @@ -134,6 +157,17 @@ trait ScalaModule extends JavaModule { outer => } } + override def resolveDeps(deps: Task[Agg[Dep]], sources: Boolean = false) = T.task{ + resolveDependencies( + repositories, + scalaVersion(), + deps(), + platformSuffix(), + sources, + mapDependencies = Some(mapDependencies) + ) + } + def ammoniteReplClasspath = T{ localClasspath() ++ transitiveLocalClasspath() ++ diff --git a/scalalib/src/mill/scalalib/ScalaWorkerApi.scala b/scalalib/src/mill/scalalib/ScalaWorkerApi.scala index 9739089a..7b8f2a20 100644 --- a/scalalib/src/mill/scalalib/ScalaWorkerApi.scala +++ b/scalalib/src/mill/scalalib/ScalaWorkerApi.scala @@ -56,6 +56,12 @@ trait ScalaWorkerModule extends mill.Module{ } trait ScalaWorkerApi { + def compileJava(sources: Array[java.io.File], + classpath: Array[java.io.File], + javaOpts: Seq[String], + upstreamCompileOutput: Seq[CompilationResult]) + (implicit ctx: mill.util.Ctx): mill.eval.Result[CompilationResult] + def compileScala(scalaVersion: String, sources: Agg[Path], compilerBridgeSources: Path, diff --git a/scalalib/test/resources/hello-java/core/src/hello/Core.java b/scalalib/test/resources/hello-java/core/src/hello/Core.java new file mode 100644 index 00000000..bef1a5a0 --- /dev/null +++ b/scalalib/test/resources/hello-java/core/src/hello/Core.java @@ -0,0 +1,8 @@ +package hello; + +public class Core{ + public static String msg(){ + return "Hello World"; + } + +}
\ No newline at end of file diff --git a/scalalib/test/resources/hello-java/main/src/hello/Main.java b/scalalib/test/resources/hello-java/main/src/hello/Main.java new file mode 100644 index 00000000..44b927bd --- /dev/null +++ b/scalalib/test/resources/hello-java/main/src/hello/Main.java @@ -0,0 +1,7 @@ +package hello; + +public class Main{ + public static void main(String[] args){ + System.out.println(Core.msg() + " " + args[0]); + } +}
\ No newline at end of file diff --git a/scalalib/test/src/mill/scalalib/HelloJavaTests.scala b/scalalib/test/src/mill/scalalib/HelloJavaTests.scala new file mode 100644 index 00000000..7794d5a5 --- /dev/null +++ b/scalalib/test/src/mill/scalalib/HelloJavaTests.scala @@ -0,0 +1,60 @@ +package mill.scalalib + + +import ammonite.ops.{%, %%, cp, ls, mkdir, pwd, rm, up} +import ammonite.ops.ImplicitWd._ +import mill.util.{TestEvaluator, TestUtil} +import utest._ +import utest.framework.TestPath + + +object HelloJavaTests extends TestSuite { + + object HelloJava extends TestUtil.BaseModule{ + def millSourcePath = TestUtil.getSrcPathBase() / millOuterCtx.enclosing.split('.') + object core extends JavaModule + object main extends JavaModule{ + def moduleDeps = Seq(core) + } + } + val resourcePath = pwd / 'scalalib / 'test / 'resources / "hello-java" + + def init()(implicit tp: TestPath) = { + val eval = new TestEvaluator(HelloJava) + rm(HelloJava.millSourcePath) + rm(eval.outPath) + mkdir(HelloJava.millSourcePath / up) + cp(resourcePath, HelloJava.millSourcePath) + eval + } + def tests: Tests = Tests { + 'scalaVersion - { + val eval = init() + + val Right((res1, n1)) = eval.apply(HelloJava.core.compile) + val Right((res2, 0)) = eval.apply(HelloJava.core.compile) + val Right((res3, n2)) = eval.apply(HelloJava.main.compile) + + assert( + res1 == res2, + n1 != 0, + n2 != 0, + ls.rec(res1.classes.path).exists(_.last == "Core.class"), + !ls.rec(res1.classes.path).exists(_.last == "Main.class"), + ls.rec(res3.classes.path).exists(_.last == "Main.class"), + !ls.rec(res3.classes.path).exists(_.last == "Core.class") + ) + } + 'docJar - { + val eval = init() + + val Right((ref1, _)) = eval.apply(HelloJava.core.docJar) + val Right((ref2, _)) = eval.apply(HelloJava.main.docJar) + + assert( + %%("jar", "tf", ref1.path).out.lines.contains("hello/Core.html"), + %%("jar", "tf", ref2.path).out.lines.contains("hello/Main.html") + ) + } + } +} diff --git a/scalaworker/src/mill/scalaworker/ScalaWorker.scala b/scalaworker/src/mill/scalaworker/ScalaWorker.scala index 0411af92..8351f6e8 100644 --- a/scalaworker/src/mill/scalaworker/ScalaWorker.scala +++ b/scalaworker/src/mill/scalaworker/ScalaWorker.scala @@ -5,6 +5,7 @@ import java.lang.annotation.Annotation import java.net.URLClassLoader import java.util.Optional import java.util.zip.ZipInputStream +import javax.tools.ToolProvider import ammonite.ops.{Path, exists, ls, mkdir, rm, up} import ammonite.util.Colors @@ -18,9 +19,14 @@ import mill.scalalib.Lib.grepJar import mill.scalalib.TestRunner.Result import mill.util.{Ctx, PrintLogger} import sbt.internal.inc._ +import sbt.internal.inc.classfile.Analyze +import sbt.internal.inc.classpath.ClasspathUtilities +import sbt.internal.inc.javac.JavaCompiler import sbt.internal.util.{ConsoleOut, MainAppender} +import sbt.io.PathFinder import sbt.testing._ -import sbt.util.LogExchange +import sbt.util.{InterfaceUtil, LogExchange} +import xsbti.AnalysisCallback import scala.collection.mutable @@ -131,6 +137,29 @@ class ScalaWorker(ctx0: mill.util.Ctx, .getOrElse(Seq.empty[String]) } + 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() + + 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))) + } + def compileScala(scalaVersion: String, sources: Agg[Path], compilerBridgeSources: Path, |