From d551ee9d751201491a1d64e4da76ab03e3815df6 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Thu, 20 Sep 2018 14:15:50 +0800 Subject: Include scaladoc as part of mill inspect (#435) --- scalalib/src/mill/scalalib/JavaModule.scala | 161 ++++++++++++++++++++- scalalib/src/mill/scalalib/ScalaModule.scala | 49 ++++++- .../src/mill/scalalib/worker/ZincWorkerImpl.scala | 18 ++- 3 files changed, 217 insertions(+), 11 deletions(-) (limited to 'scalalib') diff --git a/scalalib/src/mill/scalalib/JavaModule.scala b/scalalib/src/mill/scalalib/JavaModule.scala index fc01dceb..b15e0bdb 100644 --- a/scalalib/src/mill/scalalib/JavaModule.scala +++ b/scalalib/src/mill/scalalib/JavaModule.scala @@ -34,6 +34,11 @@ trait JavaModule extends mill.Module with TaskModule { outer => Lib.depToDependencyJava(_: Dep) } + /** + * Allows you to specify an explicit main class to use for the `run` command. + * If none is specified, the classpath is searched for an appropriate main + * class to use if one exists + */ def mainClass: T[Option[String]] = None def finalMainClassOpt: T[Either[String, String]] = T{ @@ -59,10 +64,29 @@ trait JavaModule extends mill.Module with TaskModule { outer => } } + /** + * Any ivy dependencies you want to add to this Module, in the format + * ivy"org::name:version" for Scala dependencies or ivy"org:name:version" + * for Java dependencies + */ def ivyDeps = T{ Agg.empty[Dep] } + + /** + * Same as `ivyDeps`, but only present at compile time. Useful for e.g. + * macro-related dependencies like `scala-reflect` that doesn't need to be + * present at runtime + */ def compileIvyDeps = T{ Agg.empty[Dep] } + /** + * Same as `ivyDeps`, but only present at runtime. Useful for e.g. + * selecting different versions of a dependency to use at runtime after your + * code has already been compiled + */ def runIvyDeps = T{ Agg.empty[Dep] } + /** + * Options to pass to the java compiler + */ def javacOptions = T{ Seq.empty[String] } /** The direct dependencies of this module */ @@ -78,17 +102,30 @@ trait JavaModule extends mill.Module with TaskModule { outer => Seq(this) ++ recursiveModuleDeps } + /** + * Additional jars, classfiles or resources to add to the classpath directly + * from disk rather than being downloaded from Maven Central or other package + * repositories + */ def unmanagedClasspath = T{ Agg.empty[PathRef] } - + /** + * The transitive ivy dependencies of this module and all it's upstream modules + */ def transitiveIvyDeps: T[Agg[Dep]] = T{ ivyDeps() ++ Task.traverse(moduleDeps)(_.transitiveIvyDeps)().flatten } + /** + * The upstream compilation output of all this module's upstream modules + */ def upstreamCompileOutput = T{ Task.traverse(recursiveModuleDeps)(_.compile) } + /** + * The transitive version of `localClasspath` + */ def transitiveLocalClasspath: T[Agg[PathRef]] = T{ Task.traverse(moduleDeps)(m => T.task{m.localClasspath() ++ m.transitiveLocalClasspath()} @@ -110,10 +147,19 @@ trait JavaModule extends mill.Module with TaskModule { outer => def repositories: Seq[Repository] = zincWorker.repositories + /** + * What platform suffix to use for publishing, e.g. `_sjs` for Scala.js + * projects + */ def platformSuffix = T{ "" } private val Milestone213 = raw"""2.13.(\d+)-M(\d+)""".r + /** + * What shell script to use to launch the executable generated by `assembly`. + * Defaults to a generic "universal" launcher that should work for Windows, + * OS-X and Linux + */ def prependShellScript: T[String] = T{ mainClass() match{ case None => "" @@ -129,11 +175,29 @@ trait JavaModule extends mill.Module with TaskModule { outer => def assemblyRules: Seq[Assembly.Rule] = Assembly.defaultRules + /** + * The folders where the source files for this module live + */ def sources = T.sources{ millSourcePath / 'src } + /** + * The folders where the resource files for this module live + */ def resources = T.sources{ millSourcePath / 'resources } + /** + * Folders containing source files that are generated rather than + * hand-written; these files can be generated in this target itself, + * or can refer to files generated from other targets + */ def generatedSources = T{ Seq.empty[PathRef] } + + /** + * The folders containing all source files fed into the compiler + */ def allSources = T{ sources() ++ generatedSources() } + /** + * All individual source files fed into the compiler + */ def allSourceFiles = T{ def isHiddenFile(path: Path) = path.segments.last.startsWith(".") for { @@ -144,6 +208,9 @@ trait JavaModule extends mill.Module with TaskModule { outer => } yield PathRef(path) } + /** + * Compiles the current module to generate compiled classfiles/bytecode + */ def compile: T[CompilationResult] = T.persistent{ zincWorker.worker().compileJava( upstreamCompileOutput(), @@ -153,9 +220,18 @@ trait JavaModule extends mill.Module with TaskModule { outer => ) } + /** + * The output classfiles/resources from this module, excluding upstream + * modules and third-party dependencies + */ def localClasspath = T{ resources() ++ Agg(compile().classes) } + + /** + * All classfiles and resources from upstream modules and dependencies + * necessary to compile this module + */ def compileClasspath = T{ transitiveLocalClasspath() ++ resources() ++ @@ -163,19 +239,28 @@ trait JavaModule extends mill.Module with TaskModule { outer => resolveDeps(T.task{compileIvyDeps() ++ transitiveIvyDeps()})() } + /** + * All upstream classfiles and resources necessary to build and executable + * assembly, but without this module's contribution + */ def upstreamAssemblyClasspath = T{ transitiveLocalClasspath() ++ unmanagedClasspath() ++ resolveDeps(T.task{runIvyDeps() ++ transitiveIvyDeps()})() } + /** + * All classfiles and resources from upstream modules and dependencies + * necessary to run this module's code after compilation + */ def runClasspath = T{ localClasspath() ++ upstreamAssemblyClasspath() } /** - * Build the assembly for upstream dependencies separate from the current classpath + * 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 @@ -188,6 +273,10 @@ trait JavaModule extends mill.Module with TaskModule { outer => ) } + /** + * An executable uber-jar/assembly containing all the resources and compiled + * classfiles from this module and all it's upstream modules and dependencies + */ def assembly = T{ createAssembly( Agg.from(localClasspath().map(_.path)), @@ -198,6 +287,10 @@ trait JavaModule extends mill.Module with TaskModule { outer => ) } + /** + * A jar containing only this module's resources and compiled classfiles, + * without those from upstream modules and dependencies + */ def jar = T{ createJar( localClasspath().map(_.path).filter(exists), @@ -205,6 +298,10 @@ trait JavaModule extends mill.Module with TaskModule { outer => ) } + /** + * The documentation jar, containing all the Javadoc/Scaladoc HTML files, for + * publishing to Maven Central + */ def docJar = T[PathRef] { val outDir = T.ctx().dest @@ -239,14 +336,30 @@ trait JavaModule extends mill.Module with TaskModule { outer => createJar(Agg(javadocDir))(outDir) } + /** + * The source jar, containing only source code for publishing to Maven Central + */ def sourceJar = T { createJar((allSources() ++ resources()).map(_.path).filter(exists)) } + /** + * Any command-line parameters you want to pass to the forked JVM under `run`, + * `test` or `repl` + */ def forkArgs = T{ Seq.empty[String] } + /** + * Any environment variables you want to pass to the forked JVM under `run`, + * `test` or `repl` + */ def forkEnv = T{ sys.env.toMap } + /** + * Builds a command-line "launcher" file that can be used to run this module's + * code, without the Mill process. Useful for deployment & other places where + * you do not want a build tool running + */ def launcher = T{ Result.Success( Jvm.createLauncher( @@ -271,6 +384,12 @@ trait JavaModule extends mill.Module with TaskModule { outer => Result.Success() } + /** + * Runs this module's code in-process within an isolated classloader. This is + * faster than `run`, but in exchange you have less isolation between runs + * since the code can dirty the parent Mill process and potentially leave it + * in a bad state. + */ def runLocal(args: String*) = T.command { Jvm.runLocal( finalMainClass(), @@ -279,6 +398,9 @@ trait JavaModule extends mill.Module with TaskModule { outer => ) } + /** + * Runs this module's code in a subprocess and waits for it to finish + */ def run(args: String*) = T.command{ try Result.Success(Jvm.interactiveSubprocess( finalMainClass(), @@ -324,6 +446,18 @@ trait JavaModule extends mill.Module with TaskModule { outer => write(procTombstone, token) (procId, procTombstone, token) } + + /** + * Runs this module's code in a background process, until it dies or + * `runBackground` is used again. This lets you continue using Mill while + * the process is running in the background: editing files, compiling, and + * only re-starting the background process when you're ready. + * + * You can also use `-w foo.runBackground` to make Mill watch for changes + * and automatically recompile your code & restart the background process + * when ready. This is useful when working on long-running server processes + * that would otherwise run forever + */ def runBackground(args: String*) = T.command{ val (procId, procTombstone, token) = backgroundSetup(T.ctx().dest) try Result.Success(Jvm.interactiveSubprocess( @@ -339,6 +473,9 @@ trait JavaModule extends mill.Module with TaskModule { outer => } } + /** + * Same as `runBackground`, but lets you specify a main class to run + */ def runMainBackground(mainClass: String, args: String*) = T.command{ val (procId, procTombstone, token) = backgroundSetup(T.ctx().dest) try Result.Success(Jvm.interactiveSubprocess( @@ -354,6 +491,9 @@ trait JavaModule extends mill.Module with TaskModule { outer => } } + /** + * Same as `runLocal`, but lets you specify a main class to run + */ def runMainLocal(mainClass: String, args: String*) = T.command { Jvm.runLocal( mainClass, @@ -362,6 +502,9 @@ trait JavaModule extends mill.Module with TaskModule { outer => ) } + /** + * Same as `run`, but lets you specify a main class to run + */ def runMain(mainClass: String, args: String*) = T.command{ try Result.Success(Jvm.interactiveSubprocess( mainClass, @@ -388,8 +531,14 @@ trait JavaModule extends mill.Module with TaskModule { outer => trait TestModule extends JavaModule with TaskModule { override def defaultCommandName() = "test" + /** + * What test frameworks to use. + */ def testFrameworks: T[Seq[String]] - + /** + * Discovers and runs the module's tests in a subprocess, reporting the + * results to the console + */ def test(args: String*) = T.command{ val outputPath = T.ctx().dest/"out.json" @@ -418,6 +567,11 @@ trait TestModule extends JavaModule with TaskModule { } } + + /** + * Discovers and runs the module's tests in-process in an isolated classloader, + * reporting the results to the console + */ def testLocal(args: String*) = T.command{ val outputPath = T.ctx().dest/"out.json" @@ -448,3 +602,4 @@ object TestModule{ } } } + diff --git a/scalalib/src/mill/scalalib/ScalaModule.scala b/scalalib/src/mill/scalalib/ScalaModule.scala index 3a4a9d45..74656818 100644 --- a/scalalib/src/mill/scalalib/ScalaModule.scala +++ b/scalalib/src/mill/scalalib/ScalaModule.scala @@ -27,6 +27,10 @@ trait ScalaModule extends JavaModule { outer => override def moduleDeps: Seq[JavaModule] = Seq(outer) } + /** + * What Scala organization to use + * @return + */ def scalaOrganization: T[String] = T { if (isDotty(scalaVersion())) "ch.epfl.lamp" @@ -34,6 +38,9 @@ trait ScalaModule extends JavaModule { outer => "org.scala-lang" } + /** + * What version of Scala to use + */ def scalaVersion: T[String] override def mapDependencies = T.task{ d: coursier.Dependency => @@ -59,10 +66,16 @@ trait ScalaModule extends JavaModule { outer => ) } + /** + * Allows you to make use of Scala compiler plugins from maven central + */ def scalacPluginIvyDeps = T{ Agg.empty[Dep] } def scalaDocPluginIvyDeps = T{ scalacPluginIvyDeps() } + /** + * Command-line options to pass to the Scala compiler + */ def scalacOptions = T{ Seq.empty[String] } def scalaDocOptions = T{ scalacOptions() } @@ -98,22 +111,33 @@ trait ScalaModule extends JavaModule { outer => ) } + /** + * The local classpath of Scala compiler plugins on-disk; you can add + * additional jars here if you have some copiler plugin that isn't present + * on maven central + */ def scalacPluginClasspath: T[Agg[PathRef]] = T { resolveDeps(scalacPluginIvyDeps)() } + /** + * The ivy coordinates of Scala's own standard library + */ def scalaDocPluginClasspath: T[Agg[PathRef]] = T { resolveDeps(scalaDocPluginIvyDeps)() } def scalaLibraryIvyDeps = T{ scalaRuntimeIvyDeps(scalaOrganization(), scalaVersion()) } + /** * Classpath of the Scala Compiler & any compiler plugins */ def scalaCompilerClasspath: T[Agg[PathRef]] = T{ resolveDeps( - T.task{scalaCompilerIvyDeps(scalaOrganization(), scalaVersion()) ++ - scalaRuntimeIvyDeps(scalaOrganization(), scalaVersion())} + T.task{ + scalaCompilerIvyDeps(scalaOrganization(), scalaVersion()) ++ + scalaRuntimeIvyDeps(scalaOrganization(), scalaVersion()) + } )() } override def compileClasspath = T{ @@ -168,6 +192,10 @@ trait ScalaModule extends JavaModule { outer => createJar(Agg(javadocDir))(outDir) } + /** + * Opens up a Scala console with your module and all dependencies present, + * for you to test and operate your code interactively + */ def console() = T.command{ if (T.ctx().log.inStream == DummyInputStream){ Result.Failure("repl needs to be run with the -i/--interactive flag") @@ -186,6 +214,9 @@ trait ScalaModule extends JavaModule { outer => } } + /** + * Dependencies that are necessary to run the Ammonite Scala REPL + */ def ammoniteReplClasspath = T{ localClasspath() ++ transitiveLocalClasspath() ++ @@ -196,6 +227,10 @@ trait ScalaModule extends JavaModule { outer => })() } + /** + * Opens up an Ammonite Scala REPL with your module and all dependencies present, + * for you to test and operate your code interactively + */ def repl(replOptions: String*) = T.command{ if (T.ctx().log.inStream == DummyInputStream){ Result.Failure("repl needs to be run with the -i/--interactive flag") @@ -211,14 +246,22 @@ trait ScalaModule extends JavaModule { outer => } - // publish artifact with name "mill_2.12.4" instead of "mill_2.12" + /** + * Whether to publish artifacts with name "mill_2.12.4" instead of "mill_2.12" + */ def crossFullScalaVersion: T[Boolean] = false + /** + * What Scala version string to use when publishing + */ def artifactScalaVersion: T[String] = T { if (crossFullScalaVersion()) scalaVersion() else Lib.scalaBinaryVersion(scalaVersion()) } + /** + * The suffix appended to the artifact IDs during publishing + */ def artifactSuffix: T[String] = s"_${artifactScalaVersion()}" override def artifactId: T[String] = artifactName() + artifactSuffix() diff --git a/scalalib/worker/src/mill/scalalib/worker/ZincWorkerImpl.scala b/scalalib/worker/src/mill/scalalib/worker/ZincWorkerImpl.scala index 6b21de84..d2be35e9 100644 --- a/scalalib/worker/src/mill/scalalib/worker/ZincWorkerImpl.scala +++ b/scalalib/worker/src/mill/scalalib/worker/ZincWorkerImpl.scala @@ -125,12 +125,20 @@ class ZincWorkerImpl(ctx0: mill.util.Ctx, compilerClasspath: Agg[Path], scalacPluginClasspath: Agg[Path]) (implicit ctx: mill.util.Ctx): mill.eval.Result[CompilationResult] = { - val compilerJars = compilerClasspath.toArray.map(_.toIO) + val combinedCompilerClasspath = compilerClasspath ++ scalacPluginClasspath + val combinedCompilerJars = combinedCompilerClasspath.toArray.map(_.toIO) - val compilerBridge = compileZincBridgeIfNeeded(scalaVersion, compilerBridgeSources, compilerJars) + val compilerBridge = compileZincBridgeIfNeeded( + scalaVersion, + compilerBridgeSources, + compilerClasspath.toArray.map(_.toIO) + ) val compilerBridgeSig = compilerBridge.mtime.toMillis - val compilersSig = compilerBridgeSig + compilerClasspath.map(p => p.toString().hashCode + p.mtime.toMillis).sum + val compilersSig = + compilerBridgeSig + + combinedCompilerClasspath.map(p => p.toString().hashCode + p.mtime.toMillis).sum + val compilers = mixedCompilersCache match { case Some((k, v)) if k == compilersSig => v case _ => @@ -141,10 +149,10 @@ class ZincWorkerImpl(ctx0: mill.util.Ctx, "scala-compiler" val scalaInstance = new ScalaInstance( version = scalaVersion, - loader = mill.util.ClassLoader.create(compilerJars.map(_.toURI.toURL), null), + loader = mill.util.ClassLoader.create(combinedCompilerJars.map(_.toURI.toURL), null), libraryJar = grepJar(compilerClasspath, "scala-library", scalaVersion).toIO, compilerJar = grepJar(compilerClasspath, compilerName, scalaVersion).toIO, - allJars = compilerJars, + allJars = combinedCompilerJars, explicitActual = None ) val compilers = ic.compilers( -- cgit v1.2.3