From 4085609619d24e9efb9de918bf65959267e2d8e5 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 6 Jun 2023 16:33:37 -0700 Subject: [PATCH 1/3] . --- .../src/mill/define/DynamicModule.scala | 7 ++ .../src/mill/resolve/ResolveCore.scala | 81 ++++++++++++------- .../test/src/mill/main/ResolveTests.scala | 28 +++++++ main/test/src/mill/util/TestGraphs.scala | 18 ++++- 4 files changed, 103 insertions(+), 31 deletions(-) create mode 100644 main/define/src/mill/define/DynamicModule.scala diff --git a/main/define/src/mill/define/DynamicModule.scala b/main/define/src/mill/define/DynamicModule.scala new file mode 100644 index 00000000000..68ae41bd24f --- /dev/null +++ b/main/define/src/mill/define/DynamicModule.scala @@ -0,0 +1,7 @@ +package mill.define + +/** + * A module which you can dynamically disable at runtime + */ +trait DynamicModule extends Module{ +} diff --git a/main/resolve/src/mill/resolve/ResolveCore.scala b/main/resolve/src/mill/resolve/ResolveCore.scala index 012c0b001a3..5134c11ca0d 100644 --- a/main/resolve/src/mill/resolve/ResolveCore.scala +++ b/main/resolve/src/mill/resolve/ResolveCore.scala @@ -146,7 +146,7 @@ private object ResolveCore { segments.value.foldLeft[Either[String, Module]](Right(rootModule)) { case (Right(current), Segment.Label(s)) => assert(s != "_", s) - resolveDirectChildren0(current.getClass, Some(s)) match { + resolveDirectChildren0(rootModule, current.millModuleSegments, current.getClass, Some(s)).flatMap{ case Seq((_, Some(f))) => f(current) case unknown => sys.error( @@ -204,43 +204,64 @@ private object ResolveCore { } } else Right(Nil) - crossesOrErr.map { crosses => - resolveDirectChildren0(cls, nameOpt) - .map { - case (Resolved.Module(s, cls), _) => Resolved.Module(segments ++ s, cls) - case (Resolved.Target(s), _) => Resolved.Target(segments ++ s) - case (Resolved.Command(s), _) => Resolved.Command(segments ++ s) - } - .toSet - .++(crosses) + crossesOrErr.flatMap { crosses => + resolveDirectChildren0(rootModule, segments, cls, nameOpt) + .map( + _.map { + case (Resolved.Module(s, cls), _) => Resolved.Module(segments ++ s, cls) + case (Resolved.Target(s), _) => Resolved.Target(segments ++ s) + case (Resolved.Command(s), _) => Resolved.Command(segments ++ s) + } + .toSet + .++(crosses) + ) } } def resolveDirectChildren0( + rootModule: Module, + segments: Segments, cls: Class[_], nameOpt: Option[String] - ): Seq[(Resolved, Option[Module => Either[String, Module]])] = { + ): Either[String, Seq[(Resolved, Option[Module => Either[String, Module]])]] = { def namePred(n: String) = nameOpt.isEmpty || nameOpt.contains(n) - val modules = Reflect - .reflectNestedObjects0[Module](cls, namePred) - .map { case (name, member) => - Resolved.Module( - Segments.labels(decode(name)), - member match { - case f: java.lang.reflect.Field => f.getType - case f: java.lang.reflect.Method => f.getReturnType - } - ) -> ( - member match { - case f: java.lang.reflect.Field => - Some((x: Module) => catchWrapException(f.get(x).asInstanceOf[Module])) - - case f: java.lang.reflect.Method => - Some((x: Module) => catchWrapException(f.invoke(x).asInstanceOf[Module])) - } - ) + val modulesOrErr: Either[String, Seq[(Resolved, Option[Module => Either[String, Module]])]] = if (classOf[DynamicModule].isAssignableFrom(cls) ) { + instantiateModule(rootModule, segments).map{ + case m: DynamicModule => + m.millModuleDirectChildren + .filter(c => namePred(c.millModuleSegments.parts.last)) + .map(c => + ( + Resolved.Module( + Segments.labels(c.millModuleSegments.parts.last), + c.getClass + ), + Some((x: Module) => Right(c)) + ) + ) } + }else Right { + Reflect + .reflectNestedObjects0[Module](cls, namePred) + .map { case (name, member) => + Resolved.Module( + Segments.labels(decode(name)), + member match { + case f: java.lang.reflect.Field => f.getType + case f: java.lang.reflect.Method => f.getReturnType + } + ) -> ( + member match { + case f: java.lang.reflect.Field => + Some((x: Module) => catchWrapException(f.get(x).asInstanceOf[Module])) + + case f: java.lang.reflect.Method => + Some((x: Module) => catchWrapException(f.invoke(x).asInstanceOf[Module])) + } + ) + } + } val targets = Reflect .reflect(cls, classOf[Target[_]], namePred, noParams = true) @@ -254,7 +275,7 @@ private object ResolveCore { .map(m => decode(m.getName)) .map { name => Resolved.Command(Segments.labels(name)) -> None } - modules ++ targets ++ commands + modulesOrErr.map(_ ++ targets ++ commands) } def notFoundResult(rootModule: Module, querySoFar: Segments, current: Resolved, next: Segment) = { diff --git a/main/resolve/test/src/mill/main/ResolveTests.scala b/main/resolve/test/src/mill/main/ResolveTests.scala index 88fcc6b34d8..546ba922039 100644 --- a/main/resolve/test/src/mill/main/ResolveTests.scala +++ b/main/resolve/test/src/mill/main/ResolveTests.scala @@ -759,5 +759,33 @@ object ResolveTests extends TestSuite { Set("sub.inner.baseTarget") ) } + test("dynamicModule") { + val check = new Checker(dynamicModule) + test - check( + "normal.inner.target", + Right(Set(_.normal.inner.target)), + Set("normal.inner.target") + ) + test - check( + "normal._.target", + Right(Set(_.normal.inner.target)), + Set("normal.inner.target") + ) + test - check( + "niled.inner.target", + Left("Cannot resolve niled.inner.target. Try `mill resolve niled._` to see what's available."), + Set() + ) + test - check( + "niled._.target", + Left("Cannot resolve niled._.target. Try `mill resolve niled._` to see what's available."), + Set() + ) + test - check( + "__.target", + Right(Set(_.normal.inner.target)), + Set("normal.inner.target") + ) + } } } diff --git a/main/test/src/mill/util/TestGraphs.scala b/main/test/src/mill/util/TestGraphs.scala index 256abeda556..209f5002f5f 100644 --- a/main/test/src/mill/util/TestGraphs.scala +++ b/main/test/src/mill/util/TestGraphs.scala @@ -1,6 +1,6 @@ package mill.util import TestUtil.test -import mill.define.{ModuleRef, Command, Cross, Discover, TaskModule} +import mill.define.{Command, Cross, Discover, DynamicModule, ModuleRef, TaskModule} import mill.{Module, T} /** @@ -233,6 +233,22 @@ class TestGraphs() { override lazy val millDiscover = Discover[this.type] } + + object dynamicModule extends TestUtil.BaseModule { + object normal extends DynamicModule { + object inner extends Module{ + def target = T{ 1 } + } + } + object niled extends DynamicModule { + override def millModuleDirectChildren: Seq[Module] = Nil + object inner extends Module { + def target = T{ 1 } + } + } + + override lazy val millDiscover = Discover[this.type] + } } object TestGraphs { From 442e16e1b51e895cc484004a60867e936308ec04 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 6 Jun 2023 16:43:04 -0700 Subject: [PATCH 2/3] . --- main/define/src/mill/define/DynamicModule.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/main/define/src/mill/define/DynamicModule.scala b/main/define/src/mill/define/DynamicModule.scala index 68ae41bd24f..ca03ad175b0 100644 --- a/main/define/src/mill/define/DynamicModule.scala +++ b/main/define/src/mill/define/DynamicModule.scala @@ -1,7 +1,7 @@ package mill.define /** - * A module which you can dynamically disable at runtime + * A module which you can override [[millModuleDirectChildren]] to dynamically + * enable or disable child modules at runtime */ -trait DynamicModule extends Module{ -} +trait DynamicModule extends Module From 7e14b73f2006327ddf2aa28df7bd507c4571da35 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 6 Jun 2023 16:43:32 -0700 Subject: [PATCH 3/3] . --- .../src/mill/resolve/ResolveCore.scala | 78 ++++++++++--------- .../test/src/mill/main/ResolveTests.scala | 4 +- main/test/src/mill/util/TestGraphs.scala | 6 +- 3 files changed, 48 insertions(+), 40 deletions(-) diff --git a/main/resolve/src/mill/resolve/ResolveCore.scala b/main/resolve/src/mill/resolve/ResolveCore.scala index 5134c11ca0d..58fc1980b79 100644 --- a/main/resolve/src/mill/resolve/ResolveCore.scala +++ b/main/resolve/src/mill/resolve/ResolveCore.scala @@ -146,7 +146,12 @@ private object ResolveCore { segments.value.foldLeft[Either[String, Module]](Right(rootModule)) { case (Right(current), Segment.Label(s)) => assert(s != "_", s) - resolveDirectChildren0(rootModule, current.millModuleSegments, current.getClass, Some(s)).flatMap{ + resolveDirectChildren0( + rootModule, + current.millModuleSegments, + current.getClass, + Some(s) + ).flatMap { case Seq((_, Some(f))) => f(current) case unknown => sys.error( @@ -212,8 +217,8 @@ private object ResolveCore { case (Resolved.Target(s), _) => Resolved.Target(segments ++ s) case (Resolved.Command(s), _) => Resolved.Command(segments ++ s) } - .toSet - .++(crosses) + .toSet + .++(crosses) ) } } @@ -226,42 +231,43 @@ private object ResolveCore { ): Either[String, Seq[(Resolved, Option[Module => Either[String, Module]])]] = { def namePred(n: String) = nameOpt.isEmpty || nameOpt.contains(n) - val modulesOrErr: Either[String, Seq[(Resolved, Option[Module => Either[String, Module]])]] = if (classOf[DynamicModule].isAssignableFrom(cls) ) { - instantiateModule(rootModule, segments).map{ - case m: DynamicModule => - m.millModuleDirectChildren - .filter(c => namePred(c.millModuleSegments.parts.last)) - .map(c => - ( - Resolved.Module( - Segments.labels(c.millModuleSegments.parts.last), - c.getClass - ), - Some((x: Module) => Right(c)) + val modulesOrErr: Either[String, Seq[(Resolved, Option[Module => Either[String, Module]])]] = + if (classOf[DynamicModule].isAssignableFrom(cls)) { + instantiateModule(rootModule, segments).map { + case m: DynamicModule => + m.millModuleDirectChildren + .filter(c => namePred(c.millModuleSegments.parts.last)) + .map(c => + ( + Resolved.Module( + Segments.labels(c.millModuleSegments.parts.last), + c.getClass + ), + Some((x: Module) => Right(c)) + ) ) - ) - } - }else Right { - Reflect - .reflectNestedObjects0[Module](cls, namePred) - .map { case (name, member) => - Resolved.Module( - Segments.labels(decode(name)), - member match { - case f: java.lang.reflect.Field => f.getType - case f: java.lang.reflect.Method => f.getReturnType - } - ) -> ( - member match { - case f: java.lang.reflect.Field => - Some((x: Module) => catchWrapException(f.get(x).asInstanceOf[Module])) + } + } else Right { + Reflect + .reflectNestedObjects0[Module](cls, namePred) + .map { case (name, member) => + Resolved.Module( + Segments.labels(decode(name)), + member match { + case f: java.lang.reflect.Field => f.getType + case f: java.lang.reflect.Method => f.getReturnType + } + ) -> ( + member match { + case f: java.lang.reflect.Field => + Some((x: Module) => catchWrapException(f.get(x).asInstanceOf[Module])) - case f: java.lang.reflect.Method => - Some((x: Module) => catchWrapException(f.invoke(x).asInstanceOf[Module])) - } + case f: java.lang.reflect.Method => + Some((x: Module) => catchWrapException(f.invoke(x).asInstanceOf[Module])) + } ) - } - } + } + } val targets = Reflect .reflect(cls, classOf[Target[_]], namePred, noParams = true) diff --git a/main/resolve/test/src/mill/main/ResolveTests.scala b/main/resolve/test/src/mill/main/ResolveTests.scala index 546ba922039..a361b5d0f64 100644 --- a/main/resolve/test/src/mill/main/ResolveTests.scala +++ b/main/resolve/test/src/mill/main/ResolveTests.scala @@ -773,7 +773,9 @@ object ResolveTests extends TestSuite { ) test - check( "niled.inner.target", - Left("Cannot resolve niled.inner.target. Try `mill resolve niled._` to see what's available."), + Left( + "Cannot resolve niled.inner.target. Try `mill resolve niled._` to see what's available." + ), Set() ) test - check( diff --git a/main/test/src/mill/util/TestGraphs.scala b/main/test/src/mill/util/TestGraphs.scala index 209f5002f5f..2c4b7a625cb 100644 --- a/main/test/src/mill/util/TestGraphs.scala +++ b/main/test/src/mill/util/TestGraphs.scala @@ -236,14 +236,14 @@ class TestGraphs() { object dynamicModule extends TestUtil.BaseModule { object normal extends DynamicModule { - object inner extends Module{ - def target = T{ 1 } + object inner extends Module { + def target = T { 1 } } } object niled extends DynamicModule { override def millModuleDirectChildren: Seq[Module] = Nil object inner extends Module { - def target = T{ 1 } + def target = T { 1 } } }