diff options
author | Li Haoyi <haoyi.sg@gmail.com> | 2018-09-20 14:15:50 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-09-20 14:15:50 +0800 |
commit | d551ee9d751201491a1d64e4da76ab03e3815df6 (patch) | |
tree | 60471609f0957401fa1a7002578ad8c1acd6bc75 /main | |
parent | c8fd6bd9e1dc18c24e64147fcd221e0bf91c2d06 (diff) | |
download | mill-d551ee9d751201491a1d64e4da76ab03e3815df6.tar.gz mill-d551ee9d751201491a1d64e4da76ab03e3815df6.tar.bz2 mill-d551ee9d751201491a1d64e4da76ab03e3815df6.zip |
Include scaladoc as part of mill inspect (#435)
Diffstat (limited to 'main')
-rw-r--r-- | main/core/src/mill/define/BaseModule.scala | 10 | ||||
-rw-r--r-- | main/core/src/mill/define/Caller.scala | 13 | ||||
-rw-r--r-- | main/core/src/mill/define/Ctx.scala | 9 | ||||
-rw-r--r-- | main/core/src/mill/define/Task.scala | 9 | ||||
-rw-r--r-- | main/core/src/mill/util/ClassLoader.scala | 36 | ||||
-rw-r--r-- | main/moduledefs/src/mill/moduledefs/AutoOverridePlugin.scala | 114 | ||||
-rw-r--r-- | main/moduledefs/src/mill/moduledefs/Scaladoc.java | 11 | ||||
-rw-r--r-- | main/src/mill/main/MainModule.scala | 13 | ||||
-rw-r--r-- | main/src/mill/main/MainRunner.scala | 4 | ||||
-rw-r--r-- | main/src/mill/main/ReplApplyHandler.scala | 24 | ||||
-rw-r--r-- | main/src/mill/main/Resolve.scala | 1 | ||||
-rw-r--r-- | main/src/mill/main/VisualizeModule.scala | 1 | ||||
-rw-r--r-- | main/src/mill/modules/Util.scala | 13 | ||||
-rw-r--r-- | main/test/src/mill/util/TestUtil.scala | 3 |
14 files changed, 224 insertions, 37 deletions
diff --git a/main/core/src/mill/define/BaseModule.scala b/main/core/src/mill/define/BaseModule.scala index 70826be7..03bdeccc 100644 --- a/main/core/src/mill/define/BaseModule.scala +++ b/main/core/src/mill/define/BaseModule.scala @@ -12,7 +12,8 @@ abstract class BaseModule(millSourcePath0: Path, (implicit millModuleEnclosing0: sourcecode.Enclosing, millModuleLine0: sourcecode.Line, millName0: sourcecode.Name, - millFile0: sourcecode.File) + millFile0: sourcecode.File, + caller: Caller) extends Module()( mill.define.Ctx.make( implicitly, @@ -23,7 +24,8 @@ abstract class BaseModule(millSourcePath0: Path, mill.util.Router.Overrides(0), Ctx.External(external0), Ctx.Foreign(foreign0), - millFile0 + millFile0, + caller ) ){ // A BaseModule should provide an empty Segments list to it's children, since @@ -40,7 +42,9 @@ abstract class BaseModule(millSourcePath0: Path, abstract class ExternalModule(implicit millModuleEnclosing0: sourcecode.Enclosing, millModuleLine0: sourcecode.Line, millName0: sourcecode.Name) - extends BaseModule(ammonite.ops.pwd, external0 = true, foreign0 = false){ + extends BaseModule(ammonite.ops.pwd, external0 = true, foreign0 = false)( + implicitly, implicitly, implicitly, implicitly, Caller(()) + ){ implicit def millDiscoverImplicit: Discover[_] = millDiscover assert( diff --git a/main/core/src/mill/define/Caller.scala b/main/core/src/mill/define/Caller.scala new file mode 100644 index 00000000..6d2d4d1d --- /dev/null +++ b/main/core/src/mill/define/Caller.scala @@ -0,0 +1,13 @@ +package mill.define + +import sourcecode.Compat.Context +import language.experimental.macros +case class Caller(value: Any) +object Caller { + def apply()(implicit c: Caller) = c.value + implicit def generate: Caller = macro impl + def impl(c: Context): c.Tree = { + import c.universe._ + q"new _root_.mill.define.Caller(this)" + } +}
\ No newline at end of file diff --git a/main/core/src/mill/define/Ctx.scala b/main/core/src/mill/define/Ctx.scala index fb15dc19..ba4fae9e 100644 --- a/main/core/src/mill/define/Ctx.scala +++ b/main/core/src/mill/define/Ctx.scala @@ -69,7 +69,8 @@ case class Ctx(enclosing: String, overrides: Int, external: Boolean, foreign: Boolean, - fileName: String){ + fileName: String, + enclosingCls: Class[_]){ } object Ctx{ @@ -83,7 +84,8 @@ object Ctx{ overrides0: mill.util.Router.Overrides, external0: External, foreign0: Foreign, - fileName: sourcecode.File): Ctx = { + fileName: sourcecode.File, + enclosing: Caller): Ctx = { Ctx( millModuleEnclosing0.value, millModuleLine0.value, @@ -93,7 +95,8 @@ object Ctx{ overrides0.value, external0.value, foreign0.value, - fileName.value + fileName.value, + enclosing.value.getClass ) } } diff --git a/main/core/src/mill/define/Task.scala b/main/core/src/mill/define/Task.scala index d5f8680e..64e868f8 100644 --- a/main/core/src/mill/define/Task.scala +++ b/main/core/src/mill/define/Task.scala @@ -254,15 +254,6 @@ object Target extends TargetGenerated with Applicative.Applyer[Task, Task, Resul def zip[A, B](a: Task[A], b: Task[B]) = a.zip(b) } -case class Caller[A](value: A) -object Caller { - def apply[T]()(implicit c: Caller[T]) = c.value - implicit def generate[T]: Caller[T] = macro impl[T] - def impl[T: c.WeakTypeTag](c: Context): c.Tree = { - import c.universe._ - q"new _root_.mill.define.Caller[${weakTypeOf[T]}](this)" - } -} abstract class NamedTaskImpl[+T](ctx0: mill.define.Ctx, t: Task[T]) extends NamedTask[T]{ def evaluate(args: mill.util.Ctx) = args[T](0) val ctx = ctx0.copy(segments = ctx0.segments ++ Seq(ctx0.segment)) diff --git a/main/core/src/mill/util/ClassLoader.scala b/main/core/src/mill/util/ClassLoader.scala index 17268fb0..ebe8e50b 100644 --- a/main/core/src/mill/util/ClassLoader.scala +++ b/main/core/src/mill/util/ClassLoader.scala @@ -5,15 +5,18 @@ import java.net.{URL, URLClassLoader} import ammonite.ops._ import io.github.retronym.java9rtexport.Export -object ClassLoader { - - def create(urls: Seq[URL], parent: java.lang.ClassLoader)( - implicit ctx: Ctx.Home): URLClassLoader = create(urls, parent, _ => None) +import scala.util.Try +object ClassLoader { + def create(urls: Seq[URL], + parent: java.lang.ClassLoader) + (implicit ctx: Ctx.Home): URLClassLoader = { + create(urls, parent, _ => None) + } def create(urls: Seq[URL], parent: java.lang.ClassLoader, - customFindClass: String => Option[Class[_]])( - implicit ctx: Ctx.Home): URLClassLoader = { + customFindClass: String => Option[Class[_]]) + (implicit ctx: Ctx.Home): URLClassLoader = { new URLClassLoader( makeUrls(urls).toArray, refinePlatformParent(parent) @@ -25,6 +28,7 @@ object ClassLoader { } } + /** * Return `ClassLoader.getPlatformClassLoader` for java 9 and above, if parent class loader is null, * otherwise return same parent class loader. @@ -34,15 +38,17 @@ object ClassLoader { * mill could be compiled only with jdk 9 or above. We don't want to introduce this restriction now. */ private def refinePlatformParent(parent: java.lang.ClassLoader): ClassLoader = { - if (ammonite.util.Util.java9OrAbove) { - if (parent == null) - classOf[ClassLoader] - .getMethod("getPlatformClassLoader") - .invoke(null) - .asInstanceOf[ClassLoader] - else parent - } else { - parent + if (!ammonite.util.Util.java9OrAbove || parent != null) parent + else { + // Make sure when `parent == null`, we only delegate java.* classes + // to the parent getPlatformClassLoader. This is necessary because + // in Java 9+, somehow the getPlatformClassLoader ends up with all + // sorts of other non-java stuff on it's classpath, which is not what + // we want for an "isolated" classloader! + classOf[ClassLoader] + .getMethod("getPlatformClassLoader") + .invoke(null) + .asInstanceOf[ClassLoader] } } diff --git a/main/moduledefs/src/mill/moduledefs/AutoOverridePlugin.scala b/main/moduledefs/src/mill/moduledefs/AutoOverridePlugin.scala index 5b33abbe..a870e7ec 100644 --- a/main/moduledefs/src/mill/moduledefs/AutoOverridePlugin.scala +++ b/main/moduledefs/src/mill/moduledefs/AutoOverridePlugin.scala @@ -1,10 +1,14 @@ package mill.moduledefs + +import scala.collection.mutable.ListBuffer import scala.reflect.internal.Flags +import scala.tools.nsc.doc.ScaladocSyntaxAnalyzer import scala.tools.nsc.io.VirtualFile import scala.tools.nsc.util.BatchSourceFile import scala.tools.nsc.{Global, Phase} import scala.tools.nsc.plugins.{Plugin, PluginComponent} +import scala.tools.nsc.transform.Transform class AutoOverridePlugin(val global: Global) extends Plugin { import global._ @@ -12,7 +16,117 @@ class AutoOverridePlugin(val global: Global) extends Plugin { val name = "auto-override-plugin" val description = "automatically inserts `override` keywords for you" + val components = List[PluginComponent]( + new PluginComponent with Transform { + type GT = AutoOverridePlugin.this.global.type + override val global: GT = AutoOverridePlugin.this.global + override val phaseName: String = "EmbedScaladocAnnotation" + override val runsAfter: List[String] = List("parser") + override def newTransformer(unit: global.CompilationUnit): global.Transformer = { + new ScaladocTransformer + } + import global._ + + + class ScaladocTransformer extends global.Transformer { + + val comments = new Comments() + + override def transformUnit(unit: CompilationUnit)= { + if (unit.source.file.name.endsWith(".scala") || + unit.source.file.name.endsWith(".sc")){ + comments.parseComments(unit) + super.transformUnit(unit) + } + } + + override def transform(tree: global.Tree): global.Tree = { + super.transform(tree match { + case x: global.ClassDef => + comments.getComment(x.pos) match { + case Some(comment) => + global.treeCopy.ClassDef(tree, newMods(x.mods, comment), x.name, x.tparams, x.impl) + case None => x + } + + case x: global.ModuleDef => + comments.getComment(x.pos) match { + case Some(comment) => + global.treeCopy.ModuleDef(tree, newMods(x.mods, comment), x.name, x.impl) + case None => x + } + + case x: global.DefDef => + comments.getComment(x.pos) match { + case Some(comment) => + global.treeCopy.DefDef(tree, newMods(x.mods, comment), x.name, x.tparams, x.vparamss, x.tpt, x.rhs) + case None => x + } + + case x: global.ValDef => + comments.getComment(x.pos) match { + case Some(comment) => + global.treeCopy.ValDef(tree, newMods(x.mods, comment), x.name, x.tpt, x.rhs) + case None => x + } + + case x => x + }) + } + + def newMods(old: global.Modifiers, comment: String) = { + old.copy( + annotations = createAnnotation(comment) :: old.annotations + ) + } + + private def createAnnotation(comment: String): global.Tree = + global.Apply( + global.Select( + global.New( + global.Select( + global.Select( + global.Ident( + global.newTermName("mill") + ), + global.newTermName("moduledefs") + ), + global.newTypeName("Scaladoc") + ) + ), + global.nme.CONSTRUCTOR + ), + List(Literal(Constant(comment))) + ) + + } + + class Comments extends ScaladocSyntaxAnalyzer[global.type](global){ + val comments = ListBuffer[(Position, String)]() + + def getComment(pos: Position): Option[String] = { + val tookComments = comments.takeWhile { case (x, _) => x.end < pos.start } + comments --= (tookComments) + tookComments.lastOption.map(_._2) + } + + def parseComments(unit: CompilationUnit): Unit = { + comments.clear() + + new ScaladocUnitParser(unit, Nil) { + override def newScanner = new ScaladocUnitScanner(unit, Nil) { + override def registerDocComment(str: String, pos: Position) = { + comments += ((pos, str)) + } + } + }.parse() + } + + override val runsAfter: List[String] = Nil + override val runsRightAfter: Option[String] = None + } + }, new PluginComponent { val global = AutoOverridePlugin.this.global diff --git a/main/moduledefs/src/mill/moduledefs/Scaladoc.java b/main/moduledefs/src/mill/moduledefs/Scaladoc.java new file mode 100644 index 00000000..7a7d700b --- /dev/null +++ b/main/moduledefs/src/mill/moduledefs/Scaladoc.java @@ -0,0 +1,11 @@ +package mill.moduledefs; + + +import java.lang.annotation.*; + +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Scaladoc { + String value(); +} diff --git a/main/src/mill/main/MainModule.scala b/main/src/mill/main/MainModule.scala index 834d5609..7e326860 100644 --- a/main/src/mill/main/MainModule.scala +++ b/main/src/mill/main/MainModule.scala @@ -135,6 +135,7 @@ trait MainModule extends mill.Module{ */ def inspect(evaluator: Evaluator, targets: String*) = mill.T.command{ MainModule.resolveTasks(evaluator, targets, multiSelect = true){ tasks => + val output = new StringBuilder for{ task <- tasks tree = ReplApplyHandler.pprintTask(task, evaluator) @@ -149,8 +150,10 @@ trait MainModule extends mill.Module{ val truncated = new Truncated(rendered, defaults.defaultWidth, defaults.defaultHeight) str <- truncated ++ Iterator("\n") } { - print(str) + output.append(str) } + println(output) + output.toString } } @@ -222,10 +225,17 @@ trait MainModule extends mill.Module{ } } + + /** + * Renders the dependencies between the given tasks as a SVG for you to look at + */ def visualize(evaluator: Evaluator, targets: String*) = mill.T.command{ visualize0(evaluator, targets, T.ctx(), mill.main.VisualizeModule.worker()) } + /** + * Renders the dependencies between the given tasks, and all their dependencies, as a SVG + */ def visualizePlan(evaluator: Evaluator, targets: String*) = mill.T.command{ plan0(evaluator, targets) match { case Left(err) => Result.Failure(err) @@ -258,5 +268,4 @@ trait MainModule extends mill.Module{ } } } - } diff --git a/main/src/mill/main/MainRunner.scala b/main/src/mill/main/MainRunner.scala index 30a23632..58c47998 100644 --- a/main/src/mill/main/MainRunner.scala +++ b/main/src/mill/main/MainRunner.scala @@ -144,7 +144,9 @@ class MainRunner(val config: ammonite.main.Cli.Config, |$imports |import mill._ |object $wrapName - |extends mill.define.BaseModule(ammonite.ops.Path($literalPath), foreign0 = $external) + |extends mill.define.BaseModule(ammonite.ops.Path($literalPath), foreign0 = $external)( + | implicitly, implicitly, implicitly, implicitly, mill.define.Caller(()) + |) |with $wrapName{ | // Stub to make sure Ammonite has something to call after it evaluates a script, | // even if it does nothing... diff --git a/main/src/mill/main/ReplApplyHandler.scala b/main/src/mill/main/ReplApplyHandler.scala index c40b82c9..59a6780b 100644 --- a/main/src/mill/main/ReplApplyHandler.scala +++ b/main/src/mill/main/ReplApplyHandler.scala @@ -6,6 +6,7 @@ import mill.define.Applicative.ApplyHandler import mill.define.Segment.Label import mill.define._ import mill.eval.{Evaluator, Result} + import mill.util.Strict.Agg import scala.collection.mutable @@ -69,6 +70,11 @@ object ReplApplyHandler{ ) } + + def resolveParents(c: Class[_]): Seq[Class[_]] = { + Seq(c) ++ Option(c.getSuperclass).toSeq.flatMap(resolveParents) ++ c.getInterfaces.flatMap(resolveParents) + } + def pprintTask(t: NamedTask[_], evaluator: Evaluator) = { val seen = mutable.Set.empty[Task[_]] def rec(t: Task[_]): Seq[Segments] = { @@ -81,10 +87,24 @@ object ReplApplyHandler{ t.inputs.flatMap(rec) } } + + val annots = for { + c <- resolveParents(t.ctx.enclosingCls) + m <- c.getMethods + if m.getName == t.ctx.segment.pathSegments.head + a = m.getAnnotation(classOf[mill.moduledefs.Scaladoc]) + if a != null + }yield a + + val allDocs = + for(a <- annots.distinct) + yield mill.modules.Util.cleanupScaladoc(a.value).map("\n " + _).mkString + pprint.Tree.Lazy(ctx => Iterator( - t.toString, "(", t.ctx.fileName.split('/').last, ":", t.ctx.lineNum.toString, ")", - "\n", ctx.applyPrefixColor("Inputs:").toString + ctx.applyPrefixColor(t.toString).toString, "(", t.ctx.fileName.split('/').last, ":", t.ctx.lineNum.toString, ")", + allDocs.mkString("\n"), "\n", + "\n", ctx.applyPrefixColor("Inputs").toString, ":" ) ++ t.inputs.iterator.flatMap(rec).map("\n " + _.render) ) } diff --git a/main/src/mill/main/Resolve.scala b/main/src/mill/main/Resolve.scala index d0a08c87..a2c186ed 100644 --- a/main/src/mill/main/Resolve.scala +++ b/main/src/mill/main/Resolve.scala @@ -219,6 +219,7 @@ object ResolveTasks extends Resolve[NamedTask[Any]]{ } } } + object Resolve{ def minimum(i1: Int, i2: Int, i3: Int)= math.min(math.min(i1, i2), i3) diff --git a/main/src/mill/main/VisualizeModule.scala b/main/src/mill/main/VisualizeModule.scala index 6945cf2f..ea4d46c6 100644 --- a/main/src/mill/main/VisualizeModule.scala +++ b/main/src/mill/main/VisualizeModule.scala @@ -10,7 +10,6 @@ import mill.T import mill.define.{Discover, ExternalModule} import mill.eval.{PathRef, Result} - object VisualizeModule extends ExternalModule with VisualizeModule { def repositories = Seq( Cache.ivy2Local, diff --git a/main/src/mill/modules/Util.scala b/main/src/mill/modules/Util.scala index 2d71c13e..38cd056b 100644 --- a/main/src/mill/modules/Util.scala +++ b/main/src/mill/modules/Util.scala @@ -7,6 +7,19 @@ import mill.eval.PathRef import mill.util.{Ctx, IO, Loose} object Util { + def cleanupScaladoc(v: String) = { + v.lines.map( + _.dropWhile(_.isWhitespace) + .stripPrefix("/**") + .stripPrefix("*/") + .stripPrefix("*") + .dropWhile(_.isWhitespace) + ).toArray + .dropWhile(_.isEmpty) + .reverse + .dropWhile(_.isEmpty) + .reverse + } def download(url: String, dest: RelPath = "download")(implicit ctx: Ctx.Dest) = { val out = ctx.dest / dest diff --git a/main/test/src/mill/util/TestUtil.scala b/main/test/src/mill/util/TestUtil.scala index dede8bcf..b4e3af89 100644 --- a/main/test/src/mill/util/TestUtil.scala +++ b/main/test/src/mill/util/TestUtil.scala @@ -31,7 +31,8 @@ object TestUtil { millModuleLine0: sourcecode.Line, millName0: sourcecode.Name, overrides: Overrides) - extends mill.define.BaseModule(getSrcPathBase() / millModuleEnclosing0.value.split("\\.| |#")){ + extends mill.define.BaseModule(getSrcPathBase() / millModuleEnclosing0.value.split("\\.| |#"))( + implicitly, implicitly, implicitly, implicitly, implicitly){ lazy val millDiscover: Discover[this.type] = Discover[this.type] } |