summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xci/test-mill-built.sh2
-rwxr-xr-xci/test-mill-release.sh4
-rwxr-xr-xci/test-sbt-built.sh2
-rwxr-xr-xci/test_all.sh4
-rw-r--r--core/src/mill/define/BaseModule.scala43
-rw-r--r--core/src/mill/define/Ctx.scala4
-rw-r--r--core/src/mill/define/Discover.scala6
-rw-r--r--core/src/mill/define/Module.scala2
-rw-r--r--core/src/mill/eval/Evaluator.scala12
-rw-r--r--core/src/mill/main/MagicScopt.scala49
-rw-r--r--core/src/mill/main/MainModule.scala27
-rw-r--r--core/src/mill/main/MainRunner.scala24
-rw-r--r--core/src/mill/main/Resolve.scala21
-rw-r--r--core/src/mill/main/Router.scala (renamed from core/src/mill/define/Router.scala)104
-rw-r--r--core/src/mill/main/RunScript.scala6
-rw-r--r--core/src/mill/main/Scopt.scala19
-rw-r--r--core/src/mill/main/Scripts.scala330
-rw-r--r--core/test/src/mill/define/CacherTests.scala1
-rw-r--r--core/test/src/mill/eval/CrossTests.scala3
-rw-r--r--core/test/src/mill/eval/FailureTests.scala2
-rw-r--r--core/test/src/mill/eval/ModuleTests.scala1
-rw-r--r--core/test/src/mill/eval/TaskTests.scala1
-rw-r--r--core/test/src/mill/main/MainTests.scala1
-rw-r--r--core/test/src/mill/util/TestUtil.scala2
-rw-r--r--scalalib/src/mill/scalalib/GenIdea.scala18
-rw-r--r--scalalib/src/mill/scalalib/PublishModule.scala5
26 files changed, 512 insertions, 181 deletions
diff --git a/ci/test-mill-built.sh b/ci/test-mill-built.sh
index 5b3b1a28..52be8851 100755
--- a/ci/test-mill-built.sh
+++ b/ci/test-mill-built.sh
@@ -13,7 +13,7 @@ target/bin/mill devAssembly
# Second build & run tests using Mill
-out/devAssembly/dest/out.jar --all {core,scalalib,scalajslib}.test devAssembly
+out/devAssembly/dest/out.jar all {core,scalalib,scalajslib}.test devAssembly
out/devAssembly/dest/out.jar integration.test mill.integration.AmmoniteTests
out/devAssembly/dest/out.jar integration.test "mill.integration.{AcyclicTests,BetterFilesTests,JawnTests}"
out/devAssembly/dest/out.jar devAssembly
diff --git a/ci/test-mill-release.sh b/ci/test-mill-release.sh
index 5e19bcdc..e3755e93 100755
--- a/ci/test-mill-release.sh
+++ b/ci/test-mill-release.sh
@@ -9,7 +9,7 @@ git clean -xdf
sbt bin/test:assembly
# Build Mill using SBT
-target/bin/mill --all _.publishLocal releaseAssembly
+target/bin/mill all __.publishLocal releaseAssembly
mv out/releaseAssembly/dest/out.jar ~/mill-release
@@ -17,7 +17,7 @@ git clean -xdf
# Second build & run tests using Mill
-~/mill-release --all {core,scalalib,scalajslib}.test devAssembly
+~/mill-release all {core,scalalib,scalajslib}.test devAssembly
~/mill-release integration.test mill.integration.AmmoniteTests
~/mill-release integration.test "mill.integration.{AcyclicTests,BetterFilesTests,JawnTests}"
~/mill-release devAssembly
diff --git a/ci/test-sbt-built.sh b/ci/test-sbt-built.sh
index ebb3ddb5..3a60cbd3 100755
--- a/ci/test-sbt-built.sh
+++ b/ci/test-sbt-built.sh
@@ -8,7 +8,7 @@ git clean -xdf
sbt bin/test:assembly
# Run tests using Mill built using SBT
-target/bin/mill --all {core,scalalib,scalajslib}.test devAssembly
+target/bin/mill all {core,scalalib,scalajslib}.test devAssembly
target/bin/mill integration.test mill.integration.AmmoniteTests
target/bin/mill integration.test "mill.integration.{AcyclicTests,BetterFilesTests,JawnTests}"
target/bin/mill devAssembly
diff --git a/ci/test_all.sh b/ci/test_all.sh
index 74b6d203..a04f7119 100755
--- a/ci/test_all.sh
+++ b/ci/test_all.sh
@@ -9,7 +9,7 @@ git clean -xdf
sbt core/test scalalib/test scalajslib/test integration/test bin/test:assembly
# Run tests using Mill built using SBT
-target/bin/mill --all {core,scalalib,scalajslib,integration}.test devAssembly
+target/bin/mill all {core,scalalib,scalajslib,integration}.test devAssembly
# Second build & run tests using Mill
-out/devAssembly/dest/out.jar --all {core,scalalib,scalajslib,integration}.test devAssembly \ No newline at end of file
+out/devAssembly/dest/out.jar all {core,scalalib,scalajslib,integration}.test devAssembly \ No newline at end of file
diff --git a/core/src/mill/define/BaseModule.scala b/core/src/mill/define/BaseModule.scala
index cedfcef7..5253e691 100644
--- a/core/src/mill/define/BaseModule.scala
+++ b/core/src/mill/define/BaseModule.scala
@@ -1,6 +1,6 @@
package mill.define
-import ammonite.main.Router.Overrides
+import mill.main.Router.Overrides
import ammonite.ops.Path
import mill.main.ParseArgs
@@ -31,7 +31,6 @@ abstract class BaseModule(millSourcePath0: Path, external0: Boolean = false)
override implicit def millModuleBasePath: BasePath = BasePath(millSourcePath)
implicit def millImplicitBaseModule: BaseModule.Implicit = BaseModule.Implicit(this)
def millDiscover: Discover[this.type]
- implicit def millScoptTargetReads[T] = new TargetScopt[T]()
}
@@ -49,43 +48,3 @@ abstract class ExternalModule(implicit millModuleEnclosing0: sourcecode.Enclosin
Segments(millModuleEnclosing0.value.split('.').map(Segment.Label):_*)
}
}
-
-object TargetScopt{
- case class Targets[T](items: Seq[mill.define.Target[T]])
- implicit def millScoptTargetReads[T] = new TargetScopt[T]()
- // This needs to be a ThreadLocal because we need to pass it into the body of
- // the TargetScopt#read call, which does not accept additional parameters.
- // Until we migrate our CLI parsing off of Scopt (so we can pass the BaseModule
- // in directly) we are forced to pass it in via a ThreadLocal
- val currentRootModule = new ThreadLocal[BaseModule]
-}
-class TargetScopt[T]()
- extends scopt.Read[TargetScopt.Targets[T]]{
- def arity = 1
- def reads = s => try{
- val rootModule = TargetScopt.currentRootModule.get
- val d = rootModule.millDiscover
- val (expanded, Nil) = ParseArgs(Seq("--all", s)).fold(e => throw new Exception(e), identity)
-
- val resolved = expanded.map{
- case (Some(scoping), segments) =>
- val moduleCls = rootModule.getClass.getClassLoader.loadClass(scoping.render + "$")
- val externalRootModule = moduleCls.getField("MODULE$").get(moduleCls).asInstanceOf[ExternalModule]
- val crossSelectors = segments.value.map {
- case mill.define.Segment.Cross(x) => x.toList.map(_.toString)
- case _ => Nil
- }
- mill.main.Resolve.resolve(segments.value.toList, externalRootModule, d, Nil, crossSelectors.toList, Nil)
- case (None, segments) =>
- val crossSelectors = segments.value.map {
- case mill.define.Segment.Cross(x) => x.toList.map(_.toString)
- case _ => Nil
- }
- mill.main.Resolve.resolve(segments.value.toList, rootModule, d, Nil, crossSelectors.toList, Nil)
- }
- mill.util.EitherOps.sequence(resolved) match{
- case Left(s) => throw new Exception(s)
- case Right(ts) => TargetScopt.Targets(ts.flatten.collect{case t: mill.define.Target[T] => t})
- }
- }catch{case e => e.printStackTrace(); throw e}
-}
diff --git a/core/src/mill/define/Ctx.scala b/core/src/mill/define/Ctx.scala
index 1e85d8b3..11e9e1f5 100644
--- a/core/src/mill/define/Ctx.scala
+++ b/core/src/mill/define/Ctx.scala
@@ -1,6 +1,6 @@
package mill.define
-import ammonite.main.Router.Overrides
+import mill.main.Router.Overrides
import ammonite.ops.{Path, RelPath}
import scala.annotation.implicitNotFound
@@ -67,7 +67,7 @@ object Ctx{
millName0: sourcecode.Name,
millModuleBasePath0: BasePath,
segments0: Segments,
- overrides0: Overrides,
+ overrides0: mill.main.Router.Overrides,
external0: External): Ctx = {
Ctx(
millModuleEnclosing0.value,
diff --git a/core/src/mill/define/Discover.scala b/core/src/mill/define/Discover.scala
index b213d9f3..fd5bd449 100644
--- a/core/src/mill/define/Discover.scala
+++ b/core/src/mill/define/Discover.scala
@@ -1,6 +1,6 @@
package mill.define
import language.experimental.macros
-import ammonite.main.Router.{EntryPoint, Overrides}
+import mill.main.Router.{EntryPoint, Overrides}
import sourcecode.Compat.Context
import scala.collection.mutable
@@ -41,7 +41,7 @@ object Discover {
}
rec(weakTypeOf[T])
- val router = new mill.define.Router(c)
+ val router = new mill.main.Router(c)
val mapping = for{
discoveredModuleType <- seen
val curCls = discoveredModuleType.asInstanceOf[router.c.Type]
@@ -57,7 +57,7 @@ object Discover {
val (overrides, routes) = overridesRoutes.unzip
val lhs = q"classOf[${discoveredModuleType.typeSymbol.asClass}]"
val clsType = discoveredModuleType.typeSymbol.asClass
- val rhs = q"scala.Seq[(Int, ammonite.main.Router.EntryPoint[_])](..$overridesRoutes)"
+ val rhs = q"scala.Seq[(Int, mill.main.Router.EntryPoint[_])](..$overridesRoutes)"
q"$lhs -> $rhs"
}
diff --git a/core/src/mill/define/Module.scala b/core/src/mill/define/Module.scala
index 66132fa9..a53ed345 100644
--- a/core/src/mill/define/Module.scala
+++ b/core/src/mill/define/Module.scala
@@ -2,7 +2,7 @@ package mill.define
import java.lang.reflect.Modifier
-import ammonite.main.Router.{EntryPoint, Overrides}
+import mill.main.Router.{EntryPoint, Overrides}
import ammonite.ops.Path
import scala.language.experimental.macros
diff --git a/core/src/mill/eval/Evaluator.scala b/core/src/mill/eval/Evaluator.scala
index 3d8e82b8..347ad321 100644
--- a/core/src/mill/eval/Evaluator.scala
+++ b/core/src/mill/eval/Evaluator.scala
@@ -2,7 +2,7 @@ package mill.eval
import java.net.URLClassLoader
-import ammonite.main.Router.EntryPoint
+import mill.main.Router.EntryPoint
import ammonite.ops._
import ammonite.runtime.SpecialClassLoader
import mill.define.{Ctx => _, _}
@@ -58,13 +58,9 @@ class Evaluator[T](val outPath: Path,
}
}
}
- pprint.log(discover.value.keySet)
- pprint.log(c.cls)
findMatching(c.cls) match{
case Some(v) =>
- pprint.log(v)
- pprint.log(c.ctx.segment.pathSegments)
v.find(_._2.name == c.ctx.segment.pathSegments.head).get._1
// For now we don't properly support overrides for external modules
// that do not appear in the Evaluator's main Discovered listing
@@ -334,12 +330,6 @@ class Evaluator[T](val outPath: Path,
object Evaluator{
- class Scopt extends scopt.Read[Evaluator[_]] {
- def arity = 0
- def reads = _ => dynamicScopt.get
- }
- val dynamicScopt = new ThreadLocal[Evaluator[_]]
- implicit def evaluatorScopt = new Scopt
case class Paths(out: Path,
dest: Path,
meta: Path,
diff --git a/core/src/mill/main/MagicScopt.scala b/core/src/mill/main/MagicScopt.scala
new file mode 100644
index 00000000..acba57cb
--- /dev/null
+++ b/core/src/mill/main/MagicScopt.scala
@@ -0,0 +1,49 @@
+package mill.main
+import mill.define.ExternalModule
+import mill.main.ParseArgs
+
+object MagicScopt{
+ // This needs to be a ThreadLocal because we need to pass it into the body of
+ // the TargetScopt#read call, which does not accept additional parameters.
+ // Until we migrate our CLI parsing off of Scopt (so we can pass the BaseModule
+ // in directly) we are forced to pass it in via a ThreadLocal
+ val currentEvaluator = new ThreadLocal[mill.eval.Evaluator[_]]
+
+ case class Tasks[T](items: Seq[mill.define.NamedTask[T]])
+}
+class EvaluatorScopt[T]()
+ extends scopt.Read[mill.eval.Evaluator[T]]{
+ def arity = 0
+ def reads = s => try{
+ MagicScopt.currentEvaluator.get.asInstanceOf[mill.eval.Evaluator[T]]
+ }
+}
+class TargetScopt[T]()
+ extends scopt.Read[MagicScopt.Tasks[T]]{
+ def arity = 0
+ def reads = s => {
+ val rootModule = MagicScopt.currentEvaluator.get.rootModule
+ val d = rootModule.millDiscover
+ val (expanded, leftover) = ParseArgs(Seq(s)).fold(e => throw new Exception(e), identity)
+ val resolved = expanded.map{
+ case (Some(scoping), segments) =>
+ val moduleCls = rootModule.getClass.getClassLoader.loadClass(scoping.render + "$")
+ val externalRootModule = moduleCls.getField("MODULE$").get(moduleCls).asInstanceOf[ExternalModule]
+ val crossSelectors = segments.value.map {
+ case mill.define.Segment.Cross(x) => x.toList.map(_.toString)
+ case _ => Nil
+ }
+ mill.main.Resolve.resolve(segments.value.toList, externalRootModule, d, leftover, crossSelectors.toList, Nil)
+ case (None, segments) =>
+ val crossSelectors = segments.value.map {
+ case mill.define.Segment.Cross(x) => x.toList.map(_.toString)
+ case _ => Nil
+ }
+ mill.main.Resolve.resolve(segments.value.toList, rootModule, d, leftover, crossSelectors.toList, Nil)
+ }
+ mill.util.EitherOps.sequence(resolved) match{
+ case Left(s) => throw new Exception(s)
+ case Right(ts) => MagicScopt.Tasks(ts.flatten).asInstanceOf[MagicScopt.Tasks[T]]
+ }
+ }
+} \ No newline at end of file
diff --git a/core/src/mill/main/MainModule.scala b/core/src/mill/main/MainModule.scala
new file mode 100644
index 00000000..fd46fb77
--- /dev/null
+++ b/core/src/mill/main/MainModule.scala
@@ -0,0 +1,27 @@
+package mill.main
+
+trait MainModule extends mill.Module{
+ implicit def millDiscover: mill.define.Discover[_]
+ implicit def millScoptTargetReads[T] = new mill.main.TargetScopt[T]()
+ implicit def millScoptEvaluatorReads[T] = new mill.main.EvaluatorScopt[T]()
+ def resolve(targets: mill.main.MagicScopt.Tasks[Any]*) = mill.T.command{
+ targets.flatMap(_.items).foreach(println)
+ }
+ def all(evaluator: mill.eval.Evaluator[Any],
+ targets: mill.main.MagicScopt.Tasks[Any]*) = mill.T.command{
+ val (watched, res) = mill.main.RunScript.evaluate(
+ evaluator,
+ mill.util.Strict.Agg.from(targets.flatMap(_.items))
+ )
+ }
+ def show(evaluator: mill.eval.Evaluator[Any],
+ targets: mill.main.MagicScopt.Tasks[Any]*) = mill.T.command{
+ val (watched, res) = mill.main.RunScript.evaluate(
+ evaluator,
+ mill.util.Strict.Agg.from(targets.flatMap(_.items))
+ )
+ for(json <- res.right.get.flatMap(_._2)){
+ println(json)
+ }
+ }
+}
diff --git a/core/src/mill/main/MainRunner.scala b/core/src/mill/main/MainRunner.scala
index b61ab450..9004de39 100644
--- a/core/src/mill/main/MainRunner.scala
+++ b/core/src/mill/main/MainRunner.scala
@@ -91,7 +91,6 @@ class MainRunner(config: ammonite.main.Cli.Config,
|package ${Util.encodeScalaSourcePath(pkgName.tail)}
|$imports
|import mill._
- |import mill.eval.Evaluator.evaluatorScopt
|object $wrapName
|extends mill.define.BaseModule(ammonite.ops.Path($literalPath))
|with $wrapName{
@@ -105,28 +104,7 @@ class MainRunner(config: ammonite.main.Cli.Config,
| val millSelf = Some(this)
|}
|
- |sealed trait $wrapName extends mill.Module{this: mill.define.BaseModule =>
- | def resolve(targets: mill.define.TargetScopt.Targets[Any]*) = mill.T.command{
- | targets.flatMap(_.items).foreach(println)
- | }
- | def all(evaluator: mill.eval.Evaluator[_],
- | targets: mill.define.TargetScopt.Targets[Any]*) = mill.T.command{
- | val (watched, res) = mill.main.RunScript.evaluate(
- | evaluator,
- | mill.util.Strict.Agg.from(targets.flatMap(_.items))
- | )
- | }
- | def show(evaluator: mill.eval.Evaluator[_],
- | targets: mill.define.TargetScopt.Targets[Any]*) = mill.T.command{
- | val (watched, res) = mill.main.RunScript.evaluate(
- | evaluator,
- | mill.util.Strict.Agg.from(targets.flatMap(_.items))
- | )
- | for(json <- res.right.get.flatMap(_._2)){
- | println(json)
- | }
- | }
- | implicit def millDiscover: mill.define.Discover[_]
+ |sealed trait $wrapName extends mill.main.MainModule{
|""".stripMargin
}
diff --git a/core/src/mill/main/Resolve.scala b/core/src/mill/main/Resolve.scala
index 7ecd4ac8..1932c241 100644
--- a/core/src/mill/main/Resolve.scala
+++ b/core/src/mill/main/Resolve.scala
@@ -2,9 +2,8 @@ package mill.main
import mill.define._
import mill.define.TaskModule
-import ammonite.main.Router
-import ammonite.main.Router.EntryPoint
-import ammonite.util.Res
+import mill.main.Router.EntryPoint
+import ammonite.util.{Res}
object Resolve {
def resolve[T, V](remainingSelector: List[Segment],
@@ -12,7 +11,7 @@ object Resolve {
discover: Discover[_],
rest: Seq[String],
remainingCrossSelectors: List[List[String]],
- revSelectorsSoFar: List[Segment]): Either[String, Seq[Task[Any]]] = {
+ revSelectorsSoFar: List[Segment]): Either[String, Seq[NamedTask[Any]]] = {
remainingSelector match{
case Segment.Cross(_) :: Nil => Left("Selector cannot start with a [cross] segment")
@@ -24,17 +23,25 @@ object Resolve {
.find(_.label == last)
.map(Right(_))
+ def shimArgsig[T](a: mill.main.Router.ArgSig[T, _]) = {
+ ammonite.main.Router.ArgSig[T](
+ a.name,
+ a.typeString,
+ a.doc,
+ a.default
+ )
+ }
def invokeCommand(target: mill.Module, name: String) = for{
(cls, entryPoints) <- discover.value
if cls.isAssignableFrom(target.getClass)
ep <- entryPoints
if ep._2.name == name
- } yield ammonite.main.Scripts.runMainMethod(
+ } yield mill.main.Scripts.runMainMethod(
target,
ep._2.asInstanceOf[EntryPoint[mill.Module]],
ammonite.main.Scripts.groupArgs(rest.toList)
) match{
- case Res.Success(v) => Right(v)
+ case Res.Success(v: Command[_]) => Right(v)
case Res.Failure(msg) => Left(msg)
case Res.Exception(ex, msg) =>
val sw = new java.io.StringWriter()
@@ -61,7 +68,7 @@ object Resolve {
)
// Contents of `either` *must* be a `Task`, because we only select
// methods returning `Task` in the discovery process
- case Some(either) => either.right.map{ case x: Task[Any] => Seq(x) }
+ case Some(either) => either.right.map(Seq(_))
}
diff --git a/core/src/mill/define/Router.scala b/core/src/mill/main/Router.scala
index 4a9c3ffb..935ffc72 100644
--- a/core/src/mill/define/Router.scala
+++ b/core/src/mill/main/Router.scala
@@ -1,8 +1,7 @@
-package mill.define
+package mill.main
import ammonite.main.Compat
-import sourcecode.Compat.Context
import scala.annotation.StaticAnnotation
import scala.collection.mutable
@@ -25,7 +24,7 @@ object Router{
implicit def generate: Overrides = macro impl
def impl(c: Context): c.Tree = {
import c.universe._
- q"new _root_.ammonite.main.Router.Overrides(${c.internal.enclosingOwner.overrides.length})"
+ q"new _root_.mill.main.Router.Overrides(${c.internal.enclosingOwner.overrides.length})"
}
}
@@ -48,10 +47,11 @@ object Router{
* (just for logging and reading, not a replacement for a `TypeTag`) and
* possible a function that can compute its default value
*/
- case class ArgSig[T](name: String,
- typeString: String,
- doc: Option[String],
- default: Option[T => Any])
+ case class ArgSig[T, V](name: String,
+ typeString: String,
+ doc: Option[String],
+ default: Option[T => V])
+ (implicit val reads: scopt.Read[V])
def stripDashes(s: String) = {
if (s.startsWith("--")) s.drop(2)
@@ -68,25 +68,24 @@ object Router{
* calling a Scala method.
*/
case class EntryPoint[T](name: String,
- argSignatures: Seq[ArgSig[T]],
+ argSignatures: Seq[ArgSig[T, _]],
doc: Option[String],
varargs: Boolean,
invoke0: (T, Map[String, String], Seq[String]) => Result[Any],
overrides: Int){
def invoke(target: T, groupedArgs: Seq[(String, Option[String])]): Result[Any] = {
- var remainingArgSignatures = argSignatures.toList
+ var remainingArgSignatures = argSignatures.toList.filter(_.reads.arity > 0)
-
- val accumulatedKeywords = mutable.Map.empty[ArgSig[T], mutable.Buffer[String]]
+ val accumulatedKeywords = mutable.Map.empty[ArgSig[T, _], mutable.Buffer[String]]
val keywordableArgs = if (varargs) argSignatures.dropRight(1) else argSignatures
for(arg <- keywordableArgs) accumulatedKeywords(arg) = mutable.Buffer.empty
val leftoverArgs = mutable.Buffer.empty[String]
- val lookupArgSig = argSignatures.map(x => (x.name, x)).toMap
+ val lookupArgSig = Map(argSignatures.map(x => (x.name, x)):_*)
- var incomplete: Option[ArgSig[T]] = None
+ var incomplete: Option[ArgSig[T, _]] = None
for(group <- groupedArgs){
@@ -121,7 +120,9 @@ object Router{
}
}
- val missing0 = remainingArgSignatures.filter(_.default.isEmpty)
+ val missing0 = remainingArgSignatures
+ .filter(_.default.isEmpty)
+
val missing = if(varargs) {
missing0.filter(_ != argSignatures.last)
} else {
@@ -160,9 +161,9 @@ object Router{
try Right(t)
catch{ case e: Throwable => Left(error(e))}
}
- def readVarargs[T](arg: ArgSig[_],
- values: Seq[String],
- thunk: String => T) = {
+ def readVarargs(arg: ArgSig[_, _],
+ values: Seq[String],
+ thunk: String => Any) = {
val attempts =
for(item <- values)
yield tryEither(thunk(item), Result.ParamError.Invalid(arg, item, _))
@@ -172,17 +173,23 @@ object Router{
if (bad.nonEmpty) Left(bad)
else Right(attempts.collect{case Right(x) => x})
}
- def read[T](dict: Map[String, String],
- default: => Option[Any],
- arg: ArgSig[_],
- thunk: String => T): FailMaybe = {
- dict.get(arg.name) match{
- case None =>
- tryEither(default.get, Result.ParamError.DefaultFailed(arg, _)).left.map(Seq(_))
-
- case Some(x) =>
- tryEither(thunk(x), Result.ParamError.Invalid(arg, x, _)).left.map(Seq(_))
+ def read(dict: Map[String, String],
+ default: => Option[Any],
+ arg: ArgSig[_, _],
+ thunk: String => Any): FailMaybe = {
+ arg.reads.arity match{
+ case 0 =>
+ tryEither(thunk(null), Result.ParamError.DefaultFailed(arg, _)).left.map(Seq(_))
+ case 1 =>
+ dict.get(arg.name) match{
+ case None =>
+ tryEither(default.get, Result.ParamError.DefaultFailed(arg, _)).left.map(Seq(_))
+
+ case Some(x) =>
+ tryEither(thunk(x), Result.ParamError.Invalid(arg, x, _)).left.map(Seq(_))
+ }
}
+
}
/**
@@ -214,10 +221,10 @@ object Router{
* Invoking the [[EntryPoint]] failed because the arguments provided
* did not line up with the arguments expected
*/
- case class MismatchedArguments(missing: Seq[ArgSig[_]],
+ case class MismatchedArguments(missing: Seq[ArgSig[_, _]],
unknown: Seq[String],
- duplicate: Seq[(ArgSig[_], Seq[String])],
- incomplete: Option[ArgSig[_]]) extends Error
+ duplicate: Seq[(ArgSig[_, _], Seq[String])],
+ incomplete: Option[ArgSig[_, _]]) extends Error
/**
* Invoking the [[EntryPoint]] failed because there were problems
* deserializing/parsing individual arguments
@@ -231,12 +238,12 @@ object Router{
* Something went wrong trying to de-serialize the input parameter;
* the thrown exception is stored in [[ex]]
*/
- case class Invalid(arg: ArgSig[_], value: String, ex: Throwable) extends ParamError
+ case class Invalid(arg: ArgSig[_, _], value: String, ex: Throwable) extends ParamError
/**
* Something went wrong trying to evaluate the default value
* for this input parameter
*/
- case class DefaultFailed(arg: ArgSig[_], ex: Throwable) extends ParamError
+ case class DefaultFailed(arg: ArgSig[_, _], ex: Throwable) extends ParamError
}
}
@@ -254,14 +261,13 @@ object Router{
}
}
- def makeReadCall[T: scopt.Read](dict: Map[String, String],
- default: => Option[Any],
- arg: ArgSig[_]) = {
- read[T](dict, default, arg, implicitly[scopt.Read[T]].reads(_))
+ def makeReadCall(dict: Map[String, String],
+ default: => Option[Any],
+ arg: ArgSig[_, _]) = {
+ read(dict, default, arg, arg.reads.reads(_))
}
- def makeReadVarargsCall[T: scopt.Read](arg: ArgSig[_],
- values: Seq[String]) = {
- readVarargs[T](arg, values, implicitly[scopt.Read[T]].reads(_))
+ def makeReadVarargsCall(arg: ArgSig[_, _], values: Seq[String]) = {
+ readVarargs(arg, values, arg.reads.reads(_))
}
}
@@ -357,8 +363,9 @@ class Router [C <: Context](val c: C) {
case None => q"scala.None"
case Some(s) => q"scala.Some($s)"
}
+
val argSig = q"""
- ammonite.main.Router.ArgSig(
+ mill.main.Router.ArgSig[$curCls, $docUnwrappedType](
${arg.name.toString},
${docUnwrappedType.toString + (if(vararg) "*" else "")},
$docTree,
@@ -368,12 +375,12 @@ class Router [C <: Context](val c: C) {
val reader =
if(vararg) q"""
- ammonite.main.Router.makeReadVarargsCall[$docUnwrappedType](
+ mill.main.Router.makeReadVarargsCall(
$argSig,
$extrasSymbol
)
""" else q"""
- ammonite.main.Router.makeReadCall[$docUnwrappedType](
+ mill.main.Router.makeReadCall(
$argListSymbol,
$default,
$argSig
@@ -395,8 +402,8 @@ class Router [C <: Context](val c: C) {
}.unzip
- q"""
- ammonite.main.Router.EntryPoint[$curCls](
+ val res = q"""
+ mill.main.Router.EntryPoint[$curCls](
${meth.name.toString},
scala.Seq(..$argSigs),
${methodDoc match{
@@ -405,16 +412,17 @@ class Router [C <: Context](val c: C) {
}},
${varargs.contains(true)},
($baseArgSym: $curCls, $argListSymbol: Map[String, String], $extrasSymbol: Seq[String]) =>
- ammonite.main.Router.validate(Seq(..$readArgs)) match{
- case ammonite.main.Router.Result.Success(List(..$argNames)) =>
- ammonite.main.Router.Result.Success(
+ mill.main.Router.validate(Seq(..$readArgs)) match{
+ case mill.main.Router.Result.Success(List(..$argNames)) =>
+ mill.main.Router.Result.Success(
$baseArgSym.${meth.name.toTermName}(..$argNameCasts)
)
- case x: ammonite.main.Router.Result.Error => x
+ case x: mill.main.Router.Result.Error => x
},
ammonite.main.Router.Overrides()
)
"""
+ res
}
def hasMainAnnotation(t: MethodSymbol) = {
diff --git a/core/src/mill/main/RunScript.scala b/core/src/mill/main/RunScript.scala
index 3aaeb44f..17d520e7 100644
--- a/core/src/mill/main/RunScript.scala
+++ b/core/src/mill/main/RunScript.scala
@@ -155,16 +155,14 @@ object RunScript{
// module we still want you to be able to resolve targets from your
// main build. Resolving targets from external builds as CLI arguments
// is not currently supported
- mill.define.TargetScopt.currentRootModule.set(evaluator.rootModule)
- mill.eval.Evaluator.dynamicScopt.set(evaluator)
+ mill.main.MagicScopt.currentEvaluator.set(evaluator)
mill.main.Resolve.resolve(
sel.value.toList, rootModule,
discover,
args, crossSelectors.toList, Nil
)
} finally{
- mill.eval.Evaluator.dynamicScopt.set(null)
- mill.define.TargetScopt.currentRootModule.set(null)
+ mill.main.MagicScopt.currentEvaluator.set(null)
}
}
EitherOps.sequence(selected)
diff --git a/core/src/mill/main/Scopt.scala b/core/src/mill/main/Scopt.scala
deleted file mode 100644
index 57d6529d..00000000
--- a/core/src/mill/main/Scopt.scala
+++ /dev/null
@@ -1,19 +0,0 @@
-//package mill.main
-//
-//import mill.define.{BaseModule, Discover, ExternalModule}
-//
-////class ModuleScopt[T <: mill.Module, M <: BaseModule](rootModule: M, d: => Discover[M])
-//// extends scopt.Read[Seq[T]]{
-//// def arity = 1
-//// def reads = s => {
-//// val (expanded, Nil) = ParseArgs(Seq(s)).fold(e => throw new Exception(e), identity)
-//// expanded.map{
-//// case (Some(scoping), segments) =>
-//// val moduleCls = rootModule.getClass.getClassLoader.loadClass(scoping.render + "$")
-//// val externalRootModule = moduleCls.getField("MODULE$").get(moduleCls).asInstanceOf[ExternalModule]
-//// externalRootModule.millInternal.segmentsToModules(segments).asInstanceOf[T]
-//// case (None, segments) =>
-//// rootModule.millInternal.segmentsToModules(segments).asInstanceOf[T]
-//// }
-//// }
-////}
diff --git a/core/src/mill/main/Scripts.scala b/core/src/mill/main/Scripts.scala
new file mode 100644
index 00000000..334c610f
--- /dev/null
+++ b/core/src/mill/main/Scripts.scala
@@ -0,0 +1,330 @@
+package mill.main
+import java.nio.file.NoSuchFileException
+
+
+import mill.main.Router.{ArgSig, EntryPoint}
+import ammonite.ops._
+import ammonite.runtime.Evaluator.AmmoniteExit
+import ammonite.util.Name.backtickWrap
+import ammonite.util.Util.CodeSource
+import ammonite.util.{Name, Res, Util}
+import fastparse.utils.Utils._
+
+/**
+ * Logic around using Ammonite as a script-runner; invoking scripts via the
+ * macro-generated [[Router]], and pretty-printing any output or error messages
+ */
+object Scripts {
+ def groupArgs(flatArgs: List[String]): Seq[(String, Option[String])] = {
+ var keywordTokens = flatArgs
+ var scriptArgs = Vector.empty[(String, Option[String])]
+
+ while(keywordTokens.nonEmpty) keywordTokens match{
+ case List(head, next, rest@_*) if head.startsWith("-") =>
+ scriptArgs = scriptArgs :+ (head, Some(next))
+ keywordTokens = rest.toList
+ case List(head, rest@_*) =>
+ scriptArgs = scriptArgs :+ (head, None)
+ keywordTokens = rest.toList
+
+ }
+ scriptArgs
+ }
+
+ def runScript(wd: Path,
+ path: Path,
+ interp: ammonite.interp.Interpreter,
+ scriptArgs: Seq[(String, Option[String])] = Nil) = {
+ interp.watch(path)
+ val (pkg, wrapper) = Util.pathToPackageWrapper(Seq(), path relativeTo wd)
+
+ for{
+ scriptTxt <- try Res.Success(Util.normalizeNewlines(read(path))) catch{
+ case e: NoSuchFileException => Res.Failure("Script file not found: " + path)
+ }
+
+ processed <- interp.processModule(
+ scriptTxt,
+ CodeSource(wrapper, pkg, Seq(Name("ammonite"), Name("$file")), Some(path)),
+ autoImport = true,
+ // Not sure why we need to wrap this in a separate `$routes` object,
+ // but if we don't do it for some reason the `generateRoutes` macro
+ // does not see the annotations on the methods of the outer-wrapper.
+ // It can inspect the type and its methods fine, it's just the
+ // `methodsymbol.annotations` ends up being empty.
+ extraCode = Util.normalizeNewlines(
+ s"""
+ |val $$routesOuter = this
+ |object $$routes
+ |extends scala.Function0[scala.Seq[ammonite.main.Router.EntryPoint[$$routesOuter.type]]]{
+ | def apply() = ammonite.main.Router.generateRoutes[$$routesOuter.type]
+ |}
+ """.stripMargin
+ ),
+ hardcoded = true
+ )
+
+ routeClsName <- processed.blockInfo.lastOption match{
+ case Some(meta) => Res.Success(meta.id.wrapperPath)
+ case None => Res.Skip
+ }
+
+ mainCls =
+ interp
+ .evalClassloader
+ .loadClass(processed.blockInfo.last.id.wrapperPath + "$")
+
+ routesCls =
+ interp
+ .evalClassloader
+ .loadClass(routeClsName + "$$routes$")
+
+ scriptMains =
+ routesCls
+ .getField("MODULE$")
+ .get(null)
+ .asInstanceOf[() => Seq[Router.EntryPoint[Any]]]
+ .apply()
+
+
+ mainObj = mainCls.getField("MODULE$").get(null)
+
+ res <- Util.withContextClassloader(interp.evalClassloader){
+ scriptMains match {
+ // If there are no @main methods, there's nothing to do
+ case Seq() =>
+ if (scriptArgs.isEmpty) Res.Success(())
+ else {
+ val scriptArgString =
+ scriptArgs.flatMap{case (a, b) => Seq(a) ++ b}.map(literalize(_))
+ .mkString(" ")
+
+ Res.Failure("Script " + path.last + " does not take arguments: " + scriptArgString)
+ }
+
+ // If there's one @main method, we run it with all args
+ case Seq(main) => runMainMethod(mainObj, main, scriptArgs)
+
+ // If there are multiple @main methods, we use the first arg to decide
+ // which method to run, and pass the rest to that main method
+ case mainMethods =>
+ val suffix = formatMainMethods(mainObj, mainMethods)
+ scriptArgs match{
+ case Seq() =>
+ Res.Failure(
+ s"Need to specify a subcommand to call when running " + path.last + suffix
+ )
+ case Seq((head, Some(_)), tail @ _*) =>
+ Res.Failure(
+ "To select a subcommand to run, you don't need --s." + Util.newLine +
+ s"Did you mean `${head.drop(2)}` instead of `$head`?"
+ )
+ case Seq((head, None), tail @ _*) =>
+ mainMethods.find(_.name == head) match{
+ case None =>
+ Res.Failure(
+ s"Unable to find subcommand: " + backtickWrap(head) + suffix
+ )
+ case Some(main) =>
+ runMainMethod(mainObj, main, tail)
+ }
+ }
+ }
+ }
+ } yield res
+ }
+ def formatMainMethods[T](base: T, mainMethods: Seq[Router.EntryPoint[T]]) = {
+ if (mainMethods.isEmpty) ""
+ else{
+ val leftColWidth = getLeftColWidth(mainMethods.flatMap(_.argSignatures))
+
+ val methods =
+ for(main <- mainMethods)
+ yield formatMainMethodSignature(base, main, 2, leftColWidth)
+
+ Util.normalizeNewlines(
+ s"""
+ |
+ |Available subcommands:
+ |
+ |${methods.mkString(Util.newLine)}""".stripMargin
+ )
+ }
+ }
+ def getLeftColWidth[T](items: Seq[ArgSig[T, _]]) = {
+ items.map(_.name.length + 2) match{
+ case Nil => 0
+ case x => x.max
+ }
+ }
+ def formatMainMethodSignature[T](base: T,
+ main: Router.EntryPoint[T],
+ leftIndent: Int,
+ leftColWidth: Int) = {
+ // +2 for space on right of left col
+ val args = main.argSignatures.map(renderArg(base, _, leftColWidth + leftIndent + 2 + 2, 80))
+
+ val leftIndentStr = " " * leftIndent
+ val argStrings =
+ for((lhs, rhs) <- args)
+ yield {
+ val lhsPadded = lhs.padTo(leftColWidth, ' ')
+ val rhsPadded = rhs.lines.mkString(Util.newLine)
+ s"$leftIndentStr $lhsPadded $rhsPadded"
+ }
+ val mainDocSuffix = main.doc match{
+ case Some(d) => Util.newLine + leftIndentStr + softWrap(d, leftIndent, 80)
+ case None => ""
+ }
+
+ s"""$leftIndentStr${main.name}$mainDocSuffix
+ |${argStrings.map(_ + Util.newLine).mkString}""".stripMargin
+ }
+ def runMainMethod[T](base: T,
+ mainMethod: Router.EntryPoint[T],
+ scriptArgs: Seq[(String, Option[String])]): Res[Any] = {
+ val leftColWidth = getLeftColWidth(mainMethod.argSignatures)
+
+ def expectedMsg = formatMainMethodSignature(base: T, mainMethod, 0, leftColWidth)
+
+ def pluralize(s: String, n: Int) = {
+ if (n == 1) s else s + "s"
+ }
+
+ mainMethod.invoke(base, scriptArgs) match{
+ case Router.Result.Success(x) => Res.Success(x)
+ case Router.Result.Error.Exception(x: AmmoniteExit) => Res.Success(x.value)
+ case Router.Result.Error.Exception(x) => Res.Exception(x, "")
+ case Router.Result.Error.MismatchedArguments(missing, unknown, duplicate, incomplete) =>
+ val missingStr =
+ if (missing.isEmpty) ""
+ else {
+ val chunks =
+ for (x <- missing)
+ yield "--" + x.name + ": " + x.typeString
+
+ val argumentsStr = pluralize("argument", chunks.length)
+ s"Missing $argumentsStr: (${chunks.mkString(", ")})" + Util.newLine
+ }
+
+
+ val unknownStr =
+ if (unknown.isEmpty) ""
+ else {
+ val argumentsStr = pluralize("argument", unknown.length)
+ s"Unknown $argumentsStr: " + unknown.map(literalize(_)).mkString(" ") + Util.newLine
+ }
+
+ val duplicateStr =
+ if (duplicate.isEmpty) ""
+ else {
+ val lines =
+ for ((sig, options) <- duplicate)
+ yield {
+ s"Duplicate arguments for (--${sig.name}: ${sig.typeString}): " +
+ options.map(literalize(_)).mkString(" ") + Util.newLine
+ }
+
+ lines.mkString
+
+ }
+ val incompleteStr = incomplete match{
+ case None => ""
+ case Some(sig) =>
+ s"Option (--${sig.name}: ${sig.typeString}) is missing a corresponding value" +
+ Util.newLine
+
+ }
+
+ Res.Failure(
+ Util.normalizeNewlines(
+ s"""$missingStr$unknownStr$duplicateStr$incompleteStr
+ |Arguments provided did not match expected signature:
+ |
+ |$expectedMsg
+ |""".stripMargin
+ )
+ )
+
+ case Router.Result.Error.InvalidArguments(x) =>
+ val argumentsStr = pluralize("argument", x.length)
+ val thingies = x.map{
+ case Router.Result.ParamError.Invalid(p, v, ex) =>
+ val literalV = literalize(v)
+ val rendered = {renderArgShort(p)}
+ s"$rendered: ${p.typeString} = $literalV failed to parse with $ex"
+ case Router.Result.ParamError.DefaultFailed(p, ex) =>
+ s"${renderArgShort(p)}'s default value failed to evaluate with $ex"
+ }
+
+ Res.Failure(
+ Util.normalizeNewlines(
+ s"""The following $argumentsStr failed to parse:
+ |
+ |${thingies.mkString(Util.newLine)}
+ |
+ |expected signature:
+ |
+ |$expectedMsg
+ """.stripMargin
+ )
+ )
+ }
+ }
+
+ def softWrap(s: String, leftOffset: Int, maxWidth: Int) = {
+ val oneLine = s.lines.mkString(" ").split(' ')
+
+ lazy val indent = " " * leftOffset
+
+ val output = new StringBuilder(oneLine.head)
+ var currentLineWidth = oneLine.head.length
+ for(chunk <- oneLine.tail){
+ val addedWidth = currentLineWidth + chunk.length + 1
+ if (addedWidth > maxWidth){
+ output.append(Util.newLine + indent)
+ output.append(chunk)
+ currentLineWidth = chunk.length
+ } else{
+ currentLineWidth = addedWidth
+ output.append(' ')
+ output.append(chunk)
+ }
+ }
+ output.mkString
+ }
+ def renderArgShort[T](arg: ArgSig[T, _]) = "--" + backtickWrap(arg.name)
+ def renderArg[T](base: T,
+ arg: ArgSig[T, _],
+ leftOffset: Int,
+ wrappedWidth: Int): (String, String) = {
+ val suffix = arg.default match{
+ case Some(f) => " (default " + f(base) + ")"
+ case None => ""
+ }
+ val docSuffix = arg.doc match{
+ case Some(d) => ": " + d
+ case None => ""
+ }
+ val wrapped = softWrap(
+ arg.typeString + suffix + docSuffix,
+ leftOffset,
+ wrappedWidth - leftOffset
+ )
+ (renderArgShort(arg), wrapped)
+ }
+
+
+ def mainMethodDetails[T](ep: EntryPoint[T]) = {
+ ep.argSignatures.collect{
+ case ArgSig(name, tpe, Some(doc), default) =>
+ Util.newLine + name + " // " + doc
+ }.mkString
+ }
+
+ /**
+ * Additional [[scopt.Read]] instance to teach it how to read Ammonite paths
+ */
+ implicit def pathScoptRead: scopt.Read[Path] = scopt.Read.stringRead.map(Path(_, pwd))
+
+}
diff --git a/core/test/src/mill/define/CacherTests.scala b/core/test/src/mill/define/CacherTests.scala
index 077fea8d..606de846 100644
--- a/core/test/src/mill/define/CacherTests.scala
+++ b/core/test/src/mill/define/CacherTests.scala
@@ -9,7 +9,6 @@ import utest._
import utest.framework.TestPath
import mill.util.TestEvaluator.implicitDisover
-import TargetScopt.millScoptTargetReads
object CacherTests extends TestSuite{
object Base extends Base
trait Base extends TestUtil.BaseModule{
diff --git a/core/test/src/mill/eval/CrossTests.scala b/core/test/src/mill/eval/CrossTests.scala
index 4e772a40..aa12e180 100644
--- a/core/test/src/mill/eval/CrossTests.scala
+++ b/core/test/src/mill/eval/CrossTests.scala
@@ -1,12 +1,11 @@
package mill.eval
import ammonite.ops._
-import mill.define.{Discover, TargetScopt}
+import mill.define.Discover
import mill.util.TestEvaluator
import mill.util.TestEvaluator.implicitDisover
import mill.util.TestGraphs.{crossResolved, doubleCross, nestedCrosses, singleCross}
import utest._
-import TargetScopt.millScoptTargetReads
object CrossTests extends TestSuite{
val tests = Tests{
'singleCross - {
diff --git a/core/test/src/mill/eval/FailureTests.scala b/core/test/src/mill/eval/FailureTests.scala
index 6bf53f7c..90cff686 100644
--- a/core/test/src/mill/eval/FailureTests.scala
+++ b/core/test/src/mill/eval/FailureTests.scala
@@ -6,7 +6,7 @@ import mill.eval.Result.OuterStack
import utest._
import utest.framework.TestPath
import mill.util.TestEvaluator.implicitDisover
-import mill.define.TargetScopt.millScoptTargetReads
+
object FailureTests extends TestSuite{
val tests = Tests{
diff --git a/core/test/src/mill/eval/ModuleTests.scala b/core/test/src/mill/eval/ModuleTests.scala
index 278b46cc..c6125b32 100644
--- a/core/test/src/mill/eval/ModuleTests.scala
+++ b/core/test/src/mill/eval/ModuleTests.scala
@@ -6,7 +6,6 @@ import mill.T
import mill.define.Discover
import mill.util.TestEvaluator.implicitDisover
import utest._
-import mill.define.TargetScopt.millScoptTargetReads
object ModuleTests extends TestSuite{
object ExternalModule extends mill.define.ExternalModule {
diff --git a/core/test/src/mill/eval/TaskTests.scala b/core/test/src/mill/eval/TaskTests.scala
index ea82677d..114a2910 100644
--- a/core/test/src/mill/eval/TaskTests.scala
+++ b/core/test/src/mill/eval/TaskTests.scala
@@ -5,7 +5,6 @@ import ammonite.ops._
import mill.T
import mill.util.TestEvaluator.implicitDisover
import mill.util.TestEvaluator
-import mill.define.TargetScopt.millScoptTargetReads
object TaskTests extends TestSuite{
val tests = Tests{
object build extends mill.util.TestUtil.BaseModule{
diff --git a/core/test/src/mill/main/MainTests.scala b/core/test/src/mill/main/MainTests.scala
index e1a419cb..22f93ae0 100644
--- a/core/test/src/mill/main/MainTests.scala
+++ b/core/test/src/mill/main/MainTests.scala
@@ -4,7 +4,6 @@ import mill.define.{Discover, Segment, Task}
import mill.util.TestGraphs._
import mill.util.TestEvaluator.implicitDisover
import utest._
-import mill.define.TargetScopt.millScoptTargetReads
object MainTests extends TestSuite{
def check[T <: mill.Module](module: T)(
diff --git a/core/test/src/mill/util/TestUtil.scala b/core/test/src/mill/util/TestUtil.scala
index 9a5baf11..7ef43943 100644
--- a/core/test/src/mill/util/TestUtil.scala
+++ b/core/test/src/mill/util/TestUtil.scala
@@ -1,6 +1,6 @@
package mill.util
-import ammonite.main.Router.Overrides
+import mill.main.Router.Overrides
import ammonite.ops.pwd
import mill.define._
import mill.eval.Result
diff --git a/scalalib/src/mill/scalalib/GenIdea.scala b/scalalib/src/mill/scalalib/GenIdea.scala
index 2f76b666..4b283e7c 100644
--- a/scalalib/src/mill/scalalib/GenIdea.scala
+++ b/scalalib/src/mill/scalalib/GenIdea.scala
@@ -12,15 +12,23 @@ import mill.util.Strict.Agg
object GenIdeaModule extends ExternalModule {
- def idea() = T.command{ mill.scalalib.GenIdea() }
+
+ def idea(ev: Evaluator[Any]) = T.command{
+ mill.scalalib.GenIdea(
+ implicitly,
+ ev.rootModule,
+ ev.discover
+ )
+ }
+
+ implicit def millScoptEvaluatorReads[T] = new mill.main.EvaluatorScopt[T]()
def millDiscover = Discover[this.type]
}
object GenIdea {
- def apply()(implicit ctx: Log,
- rootModule0: BaseModule.Implicit,
- discover: Discover[_]): Unit = {
- val rootModule = rootModule0.value
+ def apply(ctx: Log,
+ rootModule: BaseModule,
+ discover: Discover[_]): Unit = {
val pp = new scala.xml.PrettyPrinter(999, 4)
rm! pwd/".idea"
rm! pwd/".idea_modules"
diff --git a/scalalib/src/mill/scalalib/PublishModule.scala b/scalalib/src/mill/scalalib/PublishModule.scala
index 993fe7e6..e7f36609 100644
--- a/scalalib/src/mill/scalalib/PublishModule.scala
+++ b/scalalib/src/mill/scalalib/PublishModule.scala
@@ -2,7 +2,7 @@ package mill
package scalalib
import ammonite.ops._
-import mill.define.{ExternalModule, TargetScopt, Task}
+import mill.define.{ExternalModule, Task}
import mill.eval.{PathRef, Result}
import mill.scalalib.publish.{Artifact, SonatypePublisher}
import mill.util.Loose.Agg
@@ -88,7 +88,7 @@ trait PublishModule extends ScalaModule { outer =>
object PublishModule extends ExternalModule{
def publishAll(sonatypeCreds: String,
gpgPassphrase: String,
- publishArtifacts: TargetScopt.Targets[(mill.scalalib.publish.Artifact, Seq[(PathRef, String)])],
+ publishArtifacts: mill.main.MagicScopt.Tasks[(mill.scalalib.publish.Artifact, Seq[(PathRef, String)])],
sonatypeUri: String = "https://oss.sonatype.org/service/local",
sonatypeSnapshotUri: String = "https://oss.sonatype.org/content/repositories/snapshots") = T.command{
val x: Seq[(Seq[(Path, String)], Artifact)] = Task.sequence(publishArtifacts.items)().map{
@@ -104,6 +104,7 @@ object PublishModule extends ExternalModule{
x:_*
)
}
+ implicit def millScoptTargetReads[T] = new mill.main.MagicScopt[T]()
def millDiscover: mill.define.Discover[this.type] = mill.define.Discover[this.type]
} \ No newline at end of file