From 953321ead7b278912529ef34b50e403d1e533c05 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Fri, 6 Apr 2018 23:02:29 -0700 Subject: First pass splitting `JavaModule` out of `ScalaModule` --- scalalib/src/mill/scalalib/GenIdea.scala | 30 +-- scalalib/src/mill/scalalib/JavaModule.scala | 274 +++++++++++++++++++++++++++ scalalib/src/mill/scalalib/Lib.scala | 2 +- scalalib/src/mill/scalalib/ScalaModule.scala | 208 +------------------- 4 files changed, 300 insertions(+), 214 deletions(-) create mode 100644 scalalib/src/mill/scalalib/JavaModule.scala (limited to 'scalalib') diff --git a/scalalib/src/mill/scalalib/GenIdea.scala b/scalalib/src/mill/scalalib/GenIdea.scala index b118f29b..a67668e4 100644 --- a/scalalib/src/mill/scalalib/GenIdea.scala +++ b/scalalib/src/mill/scalalib/GenIdea.scala @@ -62,7 +62,7 @@ object GenIdea { fetchMillModules: Boolean = true): Seq[(RelPath, scala.xml.Node)] = { val modules = rootModule.millInternal.segmentsToModules.values - .collect{ case x: scalalib.ScalaModule => (x.millModuleSegments, x)} + .collect{ case x: scalalib.JavaModule => (x.millModuleSegments, x)} .toSeq val buildLibraryPaths = @@ -70,7 +70,7 @@ object GenIdea { else sys.props.get("MILL_BUILD_LIBRARIES") match { case Some(found) => Agg.from(found.split(',').map(Path(_)).distinct) case None => - val repos = modules.foldLeft(Set.empty[Repository]) { _ ++ _._2.scalaWorker.repositories } + val repos = modules.foldLeft(Set.empty[Repository]) { _ ++ _._2.repositories } val artifactNames = Seq("moduledefs", "core", "scalalib", "scalajslib") val Result.Success(res) = scalalib.Lib.resolveDependencies( repos.toList, @@ -82,7 +82,7 @@ object GenIdea { } val resolved = for((path, mod) <- modules) yield { - val allIvyDeps = T.task{mod.transitiveIvyDeps() ++ mod.scalaLibraryIvyDeps() ++ mod.compileIvyDeps()} + val allIvyDeps = T.task{mod.transitiveIvyDeps() ++ mod.compileIvyDeps()} val externalDependencies = T.task{ mod.resolveDeps(allIvyDeps)() ++ Task.traverse(mod.transitiveModuleDeps)(_.unmanagedClasspath)().flatten @@ -92,8 +92,10 @@ object GenIdea { mod.resolveDeps(allIvyDeps, sources = true)() } - val scalacPluginsIvyDeps = T.task{mod.scalacPluginIvyDeps()} - val scalacOptions = T.task{mod.scalacOptions()} + val (scalacPluginsIvyDeps, scalacOptions) = mod match{ + case mod: ScalaModule => T.task{mod.scalacPluginIvyDeps()} -> T.task{mod.scalacOptions()} + case _ => T.task(Loose.Agg[Dep]()) -> T.task(Seq()) + } val scalacPluginDependencies = T.task{ mod.resolveDeps(scalacPluginsIvyDeps)() } @@ -134,7 +136,7 @@ object GenIdea { .toMap val compilerSettings = resolved - .foldLeft(Map[(Loose.Agg[Path], Seq[String]), Vector[ScalaModule]]()) { + .foldLeft(Map[(Loose.Agg[Path], Seq[String]), Vector[JavaModule]]()) { (r, q) => val key = (q._4, q._5) r + (key -> (r.getOrElse(key, Vector()) :+ q._3)) @@ -190,7 +192,10 @@ object GenIdea { evaluator.outPath, mod.compile.ctx.segments ) - val Seq(scalaVersion: String) = evaluator.evaluate(Agg(mod.scalaVersion)).values + val scalaVersionOpt = mod match { + case x: ScalaModule => Some(evaluator.evaluate(Agg(x.scalaVersion)).values.head.asInstanceOf[String]) + case _ => None + } val generatedSourceOutPath = Evaluator.resolveDestPaths( evaluator.outPath, mod.generatedSources.ctx.segments @@ -198,7 +203,7 @@ object GenIdea { val elem = moduleXmlTemplate( mod.millModuleBasePath.value, - scalaVersion, + scalaVersionOpt, Strict.Agg.from(resourcesPathRefs.map(_.path)), Strict.Agg.from(normalSourcePaths), Strict.Agg.from(generatedSourcePaths), @@ -293,7 +298,7 @@ object GenIdea { } def moduleXmlTemplate(basePath: Path, - scalaVersion: String, + scalaVersionOpt: Option[String], resourcePaths: Strict.Agg[Path], normalSourcePaths: Strict.Agg[Path], generatedSourcePaths: Strict.Agg[Path], @@ -326,7 +331,10 @@ object GenIdea { - + { + for(scalaVersion <- scalaVersionOpt.toSeq) + yield + } { for(name <- libNames.toSeq.sorted) @@ -340,7 +348,7 @@ object GenIdea { } - def scalaCompilerTemplate(settings: Map[(Loose.Agg[Path], Seq[String]), Seq[ScalaModule]]) = { + def scalaCompilerTemplate(settings: Map[(Loose.Agg[Path], Seq[String]), Seq[JavaModule]]) = { diff --git a/scalalib/src/mill/scalalib/JavaModule.scala b/scalalib/src/mill/scalalib/JavaModule.scala new file mode 100644 index 00000000..0b043bb4 --- /dev/null +++ b/scalalib/src/mill/scalalib/JavaModule.scala @@ -0,0 +1,274 @@ +package mill +package scalalib + +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.{createAssembly, createJar, subprocess} +import Lib._ +import mill.util.Loose.Agg +import mill.util.DummyInputStream + +/** + * Core configuration required to compile a single Scala compilation target + */ +trait JavaModule extends mill.Module with TaskModule { outer => + def defaultCommandName() = "run" + + def mainClass: T[Option[String]] = None + + def finalMainClassOpt: T[Either[String, String]] = T{ + mainClass() match{ + case Some(m) => Right(m) + case None => Left("No main class specified or found") + } + } + + def finalMainClass: T[String] = T{ + finalMainClassOpt() match { + case Right(main) => Result.Success(main) + case Left(msg) => Result.Failure(msg) + } + } + + def ivyDeps = T{ Agg.empty[Dep] } + def compileIvyDeps = T{ Agg.empty[Dep] } + def runIvyDeps = T{ Agg.empty[Dep] } + + def javacOptions = T{ Seq.empty[String] } + + def moduleDeps = Seq.empty[JavaModule] + + + def transitiveModuleDeps: Seq[JavaModule] = { + Seq(this) ++ moduleDeps.flatMap(_.transitiveModuleDeps).distinct + } + def unmanagedClasspath = T{ Agg.empty[PathRef] } + + + def transitiveIvyDeps: T[Agg[Dep]] = T{ + ivyDeps() ++ Task.traverse(moduleDeps)(_.transitiveIvyDeps)().flatten + } + + def upstreamCompileOutput = T{ + Task.traverse(moduleDeps)(_.compile) + } + + def transitiveLocalClasspath: T[Agg[PathRef]] = T{ + Task.traverse(moduleDeps)(m => + T.task{m.localClasspath() ++ m.transitiveLocalClasspath()} + )().flatten + } + + def mapDependencies(d: coursier.Dependency) = d + + def resolveDeps(deps: Task[Agg[Dep]], sources: Boolean = false) = T.task{ + resolveDependencies( + repositories, + "???", + deps(), + platformSuffix(), + sources, + mapDependencies = Some(mapDependencies) + ) + } + + + def repositories: Seq[Repository] = ScalaWorkerModule.repositories + + def platformSuffix = T{ "" } + + private val Milestone213 = raw"""2.13.(\d+)-M(\d+)""".r + + def prependShellScript: T[String] = T{ + mainClass() match{ + case None => "" + case Some(cls) => + val isWin = scala.util.Properties.isWin + mill.modules.Jvm.launcherUniversalScript( + cls, + Agg("$0"), Agg("%~dpnx0"), + forkArgs() + ) + } + } + + def sources = T.sources{ millSourcePath / 'src } + def resources = T.sources{ millSourcePath / 'resources } + def generatedSources = T{ Seq.empty[PathRef] } + def allSources = T{ sources() ++ generatedSources() } + + def allSourceFiles = T{ + for { + root <- allSources() + if exists(root.path) + path <- ls.rec(root.path) + if path.isFile && (path.ext == "scala" || path.ext == "java") + } 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 localClasspath = T{ + resources() ++ Agg(compile().classes) + } + def compileClasspath = T{ + transitiveLocalClasspath() ++ + resources() ++ + unmanagedClasspath() ++ + resolveDeps(T.task{compileIvyDeps() ++ transitiveIvyDeps()})() + } + + def upstreamAssemblyClasspath = T{ + transitiveLocalClasspath() ++ + unmanagedClasspath() ++ + resolveDeps(T.task{runIvyDeps() ++ transitiveIvyDeps()})() + } + + def runClasspath = T{ + localClasspath() ++ + upstreamAssemblyClasspath() + } + + /** + * Build the assembly for upstream dependencies separate from the current classpath + * + * This should allow much faster assembly creation in the common case where + * upstream dependencies do not change + */ + def upstreamAssembly = T{ + createAssembly(upstreamAssemblyClasspath().map(_.path), mainClass()) + } + + def assembly = T{ + createAssembly( + Agg.from(localClasspath().map(_.path)), + mainClass(), + prependShellScript(), + Some(upstreamAssembly().path) + ) + } + + + def jar = T{ + createJar( + localClasspath().map(_.path).filter(exists), + mainClass() + ) + } + + 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) + } + + def sourceJar = T { + createJar((allSources() ++ resources()).map(_.path).filter(exists)) + } + + def forkArgs = T{ Seq.empty[String] } + + def forkEnv = T{ sys.env.toMap } + + def launcher = T{ + Result.Success( + Jvm.createLauncher( + finalMainClass(), + runClasspath().map(_.path), + forkArgs() + ) + ) + } + + def ivyDepsTree(inverse: Boolean = false) = T.command { + val (flattened, resolution) = Lib.resolveDependenciesMetadata( + repositories, "???", ivyDeps(), platformSuffix(), Some(mapDependencies) + ) + + println(coursier.util.Print.dependencyTree(flattened, resolution, + printExclusions = false, reverse = inverse)) + + Result.Success() + } + + def runLocal(args: String*) = T.command { + Jvm.runLocal( + finalMainClass(), + runClasspath().map(_.path), + args + ) + } + + def run(args: String*) = T.command{ + Jvm.interactiveSubprocess( + finalMainClass(), + runClasspath().map(_.path), + forkArgs(), + forkEnv(), + args, + workingDir = ammonite.ops.pwd + ) + } + + + def runMainLocal(mainClass: String, args: String*) = T.command { + Jvm.runLocal( + mainClass, + runClasspath().map(_.path), + args + ) + } + + def runMain(mainClass: String, args: String*) = T.command{ + Jvm.interactiveSubprocess( + mainClass, + runClasspath().map(_.path), + forkArgs(), + forkEnv(), + args, + workingDir = ammonite.ops.pwd + ) + } + + // publish artifact with name "mill_2.12.4" instead of "mill_2.12" + + def artifactName: T[String] = millModuleSegments.parts.mkString("-") + + def artifactSuffix: T[String] = T { "" } +} \ No newline at end of file diff --git a/scalalib/src/mill/scalalib/Lib.scala b/scalalib/src/mill/scalalib/Lib.scala index 46296333..26c9a0df 100644 --- a/scalalib/src/mill/scalalib/Lib.scala +++ b/scalalib/src/mill/scalalib/Lib.scala @@ -97,7 +97,7 @@ object Lib{ * `import $ivy` syntax. */ def resolveDependencies(repositories: Seq[Repository], - scalaVersion: String, + scalaVersion: => String, deps: TraversableOnce[Dep], platformSuffix: String = "", sources: Boolean = false, diff --git a/scalalib/src/mill/scalalib/ScalaModule.scala b/scalalib/src/mill/scalalib/ScalaModule.scala index c0ef6cce..6997c368 100644 --- a/scalalib/src/mill/scalalib/ScalaModule.scala +++ b/scalalib/src/mill/scalalib/ScalaModule.scala @@ -15,8 +15,7 @@ import mill.util.DummyInputStream /** * Core configuration required to compile a single Scala compilation target */ -trait ScalaModule extends mill.Module with TaskModule { outer => - def defaultCommandName() = "run" +trait ScalaModule extends JavaModule { outer => trait Tests extends TestModule{ def scalaVersion = outer.scalaVersion() override def repositories = outer.repositories @@ -28,11 +27,9 @@ trait ScalaModule extends mill.Module with TaskModule { outer => } def scalaVersion: T[String] - def mainClass: T[Option[String]] = None - def scalaWorker: ScalaWorkerModule = mill.scalalib.ScalaWorkerModule - def finalMainClassOpt: T[Either[String, String]] = T{ + override def finalMainClassOpt: T[Either[String, String]] = T{ mainClass() match{ case Some(m) => Right(m) case None => @@ -48,61 +45,12 @@ trait ScalaModule extends mill.Module with TaskModule { outer => } } - def finalMainClass: T[String] = T{ - finalMainClassOpt() match { - case Right(main) => Result.Success(main) - case Left(msg) => Result.Failure(msg) - } - } - def ivyDeps = T{ Agg.empty[Dep] } - def compileIvyDeps = T{ Agg.empty[Dep] } def scalacPluginIvyDeps = T{ Agg.empty[Dep] } - def runIvyDeps = T{ Agg.empty[Dep] } def scalacOptions = T{ Seq.empty[String] } - def javacOptions = T{ Seq.empty[String] } - - def moduleDeps = Seq.empty[ScalaModule] - - - def transitiveModuleDeps: Seq[ScalaModule] = { - Seq(this) ++ moduleDeps.flatMap(_.transitiveModuleDeps).distinct - } - def unmanagedClasspath = T{ Agg.empty[PathRef] } - - - def transitiveIvyDeps: T[Agg[Dep]] = T{ - ivyDeps() ++ Task.traverse(moduleDeps)(_.transitiveIvyDeps)().flatten - } - - def upstreamCompileOutput = T{ - Task.traverse(moduleDeps)(_.compile) - } - - def transitiveLocalClasspath: T[Agg[PathRef]] = T{ - Task.traverse(moduleDeps)(m => - T.task{m.localClasspath() ++ m.transitiveLocalClasspath()} - )().flatten - } - - def mapDependencies(d: coursier.Dependency) = d - - def resolveDeps(deps: Task[Agg[Dep]], sources: Boolean = false) = T.task{ - resolveDependencies( - repositories, - scalaVersion(), - deps(), - platformSuffix(), - sources, - mapDependencies = Some(mapDependencies) - ) - } - - def repositories: Seq[Repository] = scalaWorker.repositories - - def platformSuffix = T{ "" } + override def repositories: Seq[Repository] = scalaWorker.repositories private val Milestone213 = raw"""2.13.(\d+)-M(\d+)""".r @@ -134,35 +82,7 @@ trait ScalaModule extends mill.Module with TaskModule { outer => )() } - - def prependShellScript: T[String] = T{ - mainClass() match{ - case None => "" - case Some(cls) => - val isWin = scala.util.Properties.isWin - mill.modules.Jvm.launcherUniversalScript( - cls, - Agg("$0"), Agg("%~dpnx0"), - forkArgs() - ) - } - } - - def sources = T.sources{ millSourcePath / 'src } - def resources = T.sources{ millSourcePath / 'resources } - def generatedSources = T{ Seq.empty[PathRef] } - def allSources = T{ sources() ++ generatedSources() } - - def allSourceFiles = T{ - for { - root <- allSources() - if exists(root.path) - path <- ls.rec(root.path) - if path.isFile && (path.ext == "scala" || path.ext == "java") - } yield PathRef(path) - } - - def compile: T[CompilationResult] = T.persistent{ + override def compile: T[CompilationResult] = T.persistent{ scalaWorker.worker().compileScala( scalaVersion(), allSourceFiles().map(_.path), @@ -175,55 +95,8 @@ trait ScalaModule extends mill.Module with TaskModule { outer => upstreamCompileOutput() ) } - def localClasspath = T{ - resources() ++ Agg(compile().classes) - } - def compileClasspath = T{ - transitiveLocalClasspath() ++ - resources() ++ - unmanagedClasspath() ++ - resolveDeps(T.task{compileIvyDeps() ++ scalaLibraryIvyDeps() ++ transitiveIvyDeps()})() - } - - def upstreamAssemblyClasspath = T{ - transitiveLocalClasspath() ++ - unmanagedClasspath() ++ - resolveDeps(T.task{runIvyDeps() ++ scalaLibraryIvyDeps() ++ transitiveIvyDeps()})() - } - - def runClasspath = T{ - localClasspath() ++ - upstreamAssemblyClasspath() - } - - /** - * Build the assembly for upstream dependencies separate from the current classpath - * - * This should allow much faster assembly creation in the common case where - * upstream dependencies do not change - */ - def upstreamAssembly = T{ - createAssembly(upstreamAssemblyClasspath().map(_.path), mainClass()) - } - - def assembly = T{ - createAssembly( - Agg.from(localClasspath().map(_.path)), - mainClass(), - prependShellScript(), - Some(upstreamAssembly().path) - ) - } - - def jar = T{ - createJar( - localClasspath().map(_.path).filter(exists), - mainClass() - ) - } - - def docJar = T { + override def docJar = T { val outDir = T.ctx().dest val javadocDir = outDir / 'javadoc @@ -247,74 +120,6 @@ trait ScalaModule extends mill.Module with TaskModule { outer => createJar(Agg(javadocDir))(outDir) } - def sourceJar = T { - createJar((allSources() ++ resources()).map(_.path).filter(exists)) - } - - def forkArgs = T{ Seq.empty[String] } - - def forkEnv = T{ sys.env.toMap } - - def launcher = T{ - Result.Success( - Jvm.createLauncher( - finalMainClass(), - runClasspath().map(_.path), - forkArgs() - ) - ) - } - - 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() - } - - def runLocal(args: String*) = T.command { - Jvm.runLocal( - finalMainClass(), - runClasspath().map(_.path), - args - ) - } - - def run(args: String*) = T.command{ - Jvm.interactiveSubprocess( - finalMainClass(), - runClasspath().map(_.path), - forkArgs(), - forkEnv(), - args, - workingDir = ammonite.ops.pwd - ) - } - - - def runMainLocal(mainClass: String, args: String*) = T.command { - Jvm.runLocal( - mainClass, - runClasspath().map(_.path), - args - ) - } - - def runMain(mainClass: String, args: String*) = T.command{ - Jvm.interactiveSubprocess( - mainClass, - runClasspath().map(_.path), - forkArgs(), - forkEnv(), - args, - workingDir = ammonite.ops.pwd - ) - } - def console() = T.command{ if (T.ctx().log.inStream == DummyInputStream){ Result.Failure("repl needs to be run with the -i/--interactive flag") @@ -361,9 +166,8 @@ trait ScalaModule extends mill.Module with TaskModule { outer => if (crossFullScalaVersion()) scalaVersion() else Lib.scalaBinaryVersion(scalaVersion()) } - def artifactName: T[String] = millModuleSegments.parts.mkString("-") - def artifactSuffix: T[String] = T { s"_${artifactScalaVersion()}" } + override def artifactSuffix: T[String] = T { s"_${artifactScalaVersion()}" } } -- cgit v1.2.3