summaryrefslogtreecommitdiff
path: root/core/src/main/scala
diff options
context:
space:
mode:
authorLi Haoyi <haoyi.sg@gmail.com>2017-12-10 15:43:43 -0800
committerLi Haoyi <haoyi.sg@gmail.com>2017-12-10 15:43:43 -0800
commita687f3908c84d5149fe8ef32bfb73872d65675d2 (patch)
treef039ca2aaf6aa5456fe52b46db2c46126ef95dd8 /core/src/main/scala
parent4a7e9f6da30f3997fcf6b3a41db07ff837708e67 (diff)
downloadmill-a687f3908c84d5149fe8ef32bfb73872d65675d2.tar.gz
mill-a687f3908c84d5149fe8ef32bfb73872d65675d2.tar.bz2
mill-a687f3908c84d5149fe8ef32bfb73872d65675d2.zip
First pass at simplifying Ammonite integration and enabling the REPL. Can query for terms like `Core.compile`, but still can't run `Core.compile()`
Diffstat (limited to 'core/src/main/scala')
-rw-r--r--core/src/main/scala/mill/Main.scala249
-rw-r--r--core/src/main/scala/mill/main/Resolve.scala78
2 files changed, 126 insertions, 201 deletions
diff --git a/core/src/main/scala/mill/Main.scala b/core/src/main/scala/mill/Main.scala
index 24cd7ed1..711f251e 100644
--- a/core/src/main/scala/mill/Main.scala
+++ b/core/src/main/scala/mill/Main.scala
@@ -37,76 +37,6 @@ object Main {
}
}
- def resolve[T, V](remainingSelector: List[Mirror.Segment],
- hierarchy: Mirror[T, V],
- obj: T,
- rest: Seq[String],
- remainingCrossSelectors: List[List[String]],
- revSelectorsSoFar: List[Mirror.Segment]): Either[String, Task[Any]] = {
-
- remainingSelector match{
- case Mirror.Segment.Cross(_) :: Nil => Left("Selector cannot start with a [cross] segment")
- case Mirror.Segment.Label(last) :: Nil =>
- def target =
- hierarchy.targets
- .find(_.label == last)
- .map(x => Right(x.run(hierarchy.node(obj, remainingCrossSelectors))))
-
- def invokeCommand[V](mirror: Mirror[T, V], name: String) = for{
- cmd <- mirror.commands.find(_.name == name)
- } yield cmd.invoke(
- mirror.node(obj, remainingCrossSelectors),
- ammonite.main.Scripts.groupArgs(rest.toList)
- ) match {
- case Router.Result.Success(v) => Right(v)
- case _ => Left(s"Command failed $last")
- }
-
- def runDefault = for{
- (label, child) <- hierarchy.children
- if label == last
- res <- child.node(obj, remainingCrossSelectors) match{
- case taskMod: TaskModule => Some(invokeCommand(child, taskMod.defaultCommandName()))
- case _ => None
- }
- } yield res
-
- def command = invokeCommand(hierarchy, last)
-
- command orElse target orElse runDefault.headOption.flatten match{
- case None => Left("Cannot resolve task " + Mirror.renderSelector(
- (Mirror.Segment.Label(last) :: revSelectorsSoFar).reverse)
- )
- case Some(either) => either
- }
-
-
- case head :: tail =>
- val newRevSelectorsSoFar = head :: revSelectorsSoFar
- head match{
- case Mirror.Segment.Label(singleLabel) =>
- hierarchy.children.collectFirst{
- case (label, child) if label == singleLabel => child
- } match{
- case Some(child) => resolve(tail, child, obj, rest, remainingCrossSelectors, newRevSelectorsSoFar)
- case None => Left("Cannot resolve module " + Mirror.renderSelector(newRevSelectorsSoFar.reverse))
- }
-
- case Mirror.Segment.Cross(cross) =>
- val Some((crossGen, childMirror)) = hierarchy.crossChildren
- val crossOptions = crossGen(hierarchy.node(obj, remainingCrossSelectors))
- if (crossOptions.contains(cross)){
- resolve(tail, childMirror, obj, rest, remainingCrossSelectors, newRevSelectorsSoFar)
- }else{
- Left("Cannot resolve cross " + Mirror.renderSelector(newRevSelectorsSoFar.reverse))
- }
-
-
- }
-
- case Nil => Left("Selector cannot be empty")
- }
- }
def discoverMirror[T: Discovered](obj: T): Either[String, Discovered[T]] = {
val discovered = implicitly[Discovered[T]]
@@ -162,7 +92,7 @@ object Main {
case Mirror.Segment.Cross(x) => x.toList.map(_.toString)
case _ => Nil
}
- target <- resolve(sel, disc.mirror, obj, rest, crossSelectors, Nil)
+ target <- mill.main.Resolve.resolve(sel, disc.mirror, obj, rest, crossSelectors, Nil)
evaluator = new Evaluator(pwd / 'out, Discovered.mapping(obj)(disc), log)
_ <- evaluate(evaluator, target, watch).toLeft(())
} yield ()
@@ -182,141 +112,58 @@ object Main {
watch: Boolean = false)
def main(args: Array[String]): Unit = {
- val startTime = System.currentTimeMillis()
-
-
- import ammonite.main.Cli.Arg
- val signature = Seq(
- Arg[Config, Path](
- "home", Some('h'),
- "The home directory of the REPL; where it looks for config and caches",
- (c, v) => c.copy(home = v)
- ),
- Arg[Config, Unit](
- "help", None,
- """Print this message""".stripMargin,
- (c, v) => c.copy(help = true)
- ),
- Arg[Config, Boolean](
- "color", None,
- """Enable or disable colored output; by default colors are enabled
- |in both REPL and scripts if the console is interactive, and disabled
- |otherwise""".stripMargin,
- (c, v) => c.copy(colored = Some(v))
- ),
- Arg[Config, Unit](
- "repl", Some('r'),
- "Open a build REPL",
- (c, v) => c.copy(repl = true)
- ),
- Arg[Config, Unit](
- "watch", Some('w'),
- "Watch and re-run your build when it changes",
- (c, v) => c.copy(watch = true)
- )
+ val syntheticPath = pwd / 'out / "run.sc"
+ write.over(
+ syntheticPath,
+ s"""import $$file.^.build
+ |import mill._
+ |
+ |@main def run(args: String*) = mill.Main(args, build, interp.watch, true/*interp.colors()*/)
+ |
+ |@main def idea() = mill.scalaplugin.GenIdea(build)""".stripMargin
)
- ammonite.main.Cli.groupArgs(args.toList, signature, Config()) match{
- case Left(err) =>
- case Right((config, leftover)) =>
- if (config.help) {
- val leftMargin = signature.map(ammonite.main.Cli.showArg(_).length).max + 2
- System.err.println(ammonite.main.Cli.formatBlock(signature, leftMargin).mkString("\n"))
- System.exit(0)
+ import ammonite.main.Cli
+ var repl = false
+ val replCliArg = Cli.Arg[Cli.Config, Unit](
+ "repl",
+ None,
+ "Open a Build REPL",
+ (x, _) => {
+ repl = true
+ x
+ }
+ )
+ Cli.groupArgs(
+ args.toList,
+ Cli.ammoniteArgSignature :+ replCliArg,
+ Cli.Config()
+ ) match{
+ case Left(msg) =>
+ System.err.println(msg)
+ System.exit(1)
+ case Right((cliConfig, leftoverArgs)) =>
+ if (repl){
+
+ val runner = new ammonite.MainRunner(
+ cliConfig.copy(
+ predefFile = Some(pwd / "build.sc"),
+ welcomeBanner = Some("")
+ ),
+ System.out, System.err,
+ System.in, System.out, System.err
+ )
+ runner.printInfo("Loading...")
+ runner.runRepl()
} else {
- val res = new Main(config).run(leftover, startTime)
- System.exit(res)
+ val runner = new ammonite.MainRunner(
+ cliConfig,
+ System.out, System.err,
+ System.in, System.out, System.err
+ )
+ runner.runScript(syntheticPath, leftoverArgs)
}
}
}
}
-
-class Main(config: Main.Config){
- val coloredOutput = config.colored.getOrElse(ammonite.Main.isInteractive())
- val log = new PrintLogger(coloredOutput)
-
-
- def watchAndWait(watched: Seq[(Path, Long)]) = {
- log.info(s"Watching for changes to ${watched.length} files... (Ctrl-C to exit)")
- def statAll() = watched.forall{ case (file, lastMTime) =>
- Interpreter.pathSignature(file) == lastMTime
- }
-
- while(statAll()) Thread.sleep(100)
- }
-
- def handleWatchRes[T](res: Res[T], printing: Boolean) = res match {
- case Res.Failure(msg) =>
- log.error(msg)
- false
-
- case Res.Exception(ex, s) =>
- log.error(
- Repl.showException(ex, fansi.Color.Red, fansi.Attr.Reset, fansi.Color.Green)
- )
- false
-
- case Res.Success(value) =>
- if (printing && value != ()) println(pprint.PPrinter.BlackWhite(value))
- true
-
- case Res.Skip => true // do nothing on success, everything's already happened
- case Res.Exit(_) => ???
- }
-
- def run(leftover: List[String], startTime0: Long): Int = {
-
- var exitCode = 0
- var startTime = startTime0
- val loop = config.watch
-
- do {
- val watchedFiles = if (config.repl) {
- val repl = ammonite.Main(
- predefFile = Some(pwd / "build.sc")
- ).instantiateRepl(remoteLogger = None).right.get
- repl.interp.initializePredef()
- repl.run()
- repl.interp.watchedFiles
- } else {
- val interp = ammonite.Main(
- predefFile = Some(pwd / "build.sc")
- ).instantiateInterpreter()match{
- case Left(x) => println(x); ???
- case Right(x) => x
- }
-
- interp.initializePredef()
- val syntheticPath = pwd / 'out / "run.sc"
- write.over(
- syntheticPath,
- s"""@main def run(args: String*) = mill.Main(args, ammonite.predef.FilePredef, interp.watch, $coloredOutput)
- |
- |@main def idea() = mill.scalaplugin.GenIdea(ammonite.predef.FilePredef)
- """.stripMargin
- )
-
- val res = ammonite.main.Scripts.runScript(
- pwd,
- syntheticPath,
- interp,
- Scripts.groupArgs(leftover)
- )
- res match{
- case Res.Success(v: Int) => exitCode = v
- case _ => exitCode = 1
- }
-
- handleWatchRes(res, false)
- interp.watchedFiles
- }
-
- val delta = System.currentTimeMillis() - startTime
- log.info("Finished in " + delta/1000.0 + "s")
- if (loop) watchAndWait(watchedFiles)
- startTime = System.currentTimeMillis()
- } while(loop)
- exitCode
- }
-}
diff --git a/core/src/main/scala/mill/main/Resolve.scala b/core/src/main/scala/mill/main/Resolve.scala
new file mode 100644
index 00000000..9cfc33b5
--- /dev/null
+++ b/core/src/main/scala/mill/main/Resolve.scala
@@ -0,0 +1,78 @@
+package mill.main
+
+import mill.define.Task
+import mill.define.Task.TaskModule
+import mill.discover.{Mirror, Router}
+
+object Resolve {
+ def resolve[T, V](remainingSelector: List[Mirror.Segment],
+ hierarchy: Mirror[T, V],
+ obj: T,
+ rest: Seq[String],
+ remainingCrossSelectors: List[List[String]],
+ revSelectorsSoFar: List[Mirror.Segment]): Either[String, Task[Any]] = {
+
+ remainingSelector match{
+ case Mirror.Segment.Cross(_) :: Nil => Left("Selector cannot start with a [cross] segment")
+ case Mirror.Segment.Label(last) :: Nil =>
+ def target =
+ hierarchy.targets
+ .find(_.label == last)
+ .map(x => Right(x.run(hierarchy.node(obj, remainingCrossSelectors))))
+
+ def invokeCommand[V](mirror: Mirror[T, V], name: String) = for{
+ cmd <- mirror.commands.find(_.name == name)
+ } yield cmd.invoke(
+ mirror.node(obj, remainingCrossSelectors),
+ ammonite.main.Scripts.groupArgs(rest.toList)
+ ) match {
+ case Router.Result.Success(v) => Right(v)
+ case _ => Left(s"Command failed $last")
+ }
+
+ def runDefault = for{
+ (label, child) <- hierarchy.children
+ if label == last
+ res <- child.node(obj, remainingCrossSelectors) match{
+ case taskMod: TaskModule => Some(invokeCommand(child, taskMod.defaultCommandName()))
+ case _ => None
+ }
+ } yield res
+
+ def command = invokeCommand(hierarchy, last)
+
+ command orElse target orElse runDefault.headOption.flatten match{
+ case None => Left("Cannot resolve task " + Mirror.renderSelector(
+ (Mirror.Segment.Label(last) :: revSelectorsSoFar).reverse)
+ )
+ case Some(either) => either
+ }
+
+
+ case head :: tail =>
+ val newRevSelectorsSoFar = head :: revSelectorsSoFar
+ head match{
+ case Mirror.Segment.Label(singleLabel) =>
+ hierarchy.children.collectFirst{
+ case (label, child) if label == singleLabel => child
+ } match{
+ case Some(child) => resolve(tail, child, obj, rest, remainingCrossSelectors, newRevSelectorsSoFar)
+ case None => Left("Cannot resolve module " + Mirror.renderSelector(newRevSelectorsSoFar.reverse))
+ }
+
+ case Mirror.Segment.Cross(cross) =>
+ val Some((crossGen, childMirror)) = hierarchy.crossChildren
+ val crossOptions = crossGen(hierarchy.node(obj, remainingCrossSelectors))
+ if (crossOptions.contains(cross)){
+ resolve(tail, childMirror, obj, rest, remainingCrossSelectors, newRevSelectorsSoFar)
+ }else{
+ Left("Cannot resolve cross " + Mirror.renderSelector(newRevSelectorsSoFar.reverse))
+ }
+
+
+ }
+
+ case Nil => Left("Selector cannot be empty")
+ }
+ }
+}