diff --git a/example/basic/5-nested-modules/baz/src/Baz.scala b/example/basic/5-nested-modules/baz/src/Baz.scala new file mode 100644 index 00000000000..0bb9608c48f --- /dev/null +++ b/example/basic/5-nested-modules/baz/src/Baz.scala @@ -0,0 +1,17 @@ +package baz +import scalatags.Text.all._ +import mainargs.{main, ParserForMethods, arg} + +object Baz { + @main + def main(@arg(name = "bar-text") barText: String, + @arg(name = "qux-text") quxText: String, + @arg(name = "baz-text") bazText: String): Unit = { + foo.qux.Qux.main(barText, quxText) + + val value = p(bazText) + println("Baz.value: " + value) + } + + def main(args: Array[String]): Unit = ParserForMethods(this).runOrExit(args) +} diff --git a/example/basic/5-nested-modules/build.sc b/example/basic/5-nested-modules/build.sc index d4817d0a213..e2b3809c664 100644 --- a/example/basic/5-nested-modules/build.sc +++ b/example/basic/5-nested-modules/build.sc @@ -8,16 +8,16 @@ trait MyModule extends ScalaModule{ ) } -object wrapper extends Module{ - object foo extends MyModule { +object foo extends Module{ + object bar extends MyModule + + object qux extends MyModule { def moduleDeps = Seq(bar) } - - object bar extends MyModule } -object qux extends MyModule { - def moduleDeps = Seq(wrapper.bar, wrapper.foo) +object baz extends MyModule { + def moduleDeps = Seq(foo.bar, foo.qux) } // Modules can be nested arbitrarily deeply within each other. The outer module @@ -31,16 +31,17 @@ object qux extends MyModule { /* Example Usage > ./mill resolve __.run -wrapper.foo.run -wrapper.bar.run +foo.bar.run +foo.qux.run qux.run -> ./mill qux.run --foo-text hello --bar-text world --qux-text today -Foo.value:

hello

-Bar.value:

world

-Qux.value:

today

+> ./mill baz.run --bar-text hello --qux-text world --baz-text today +Bar.value:

hello

+Qux.value:

world

+Baz.value:

today

-> ./mill wrapper.foo.run --text hello -Foo.value:

hello

+> ./mill foo.qux.run --bar-text hello --qux-text world +Bar.value:

hello

+Qux.value:

world

*/ \ No newline at end of file diff --git a/example/basic/5-nested-modules/wrapper/bar/src/Bar.scala b/example/basic/5-nested-modules/foo/bar/src/Bar.scala similarity index 85% rename from example/basic/5-nested-modules/wrapper/bar/src/Bar.scala rename to example/basic/5-nested-modules/foo/bar/src/Bar.scala index 552779c995b..a22925fca2f 100644 --- a/example/basic/5-nested-modules/wrapper/bar/src/Bar.scala +++ b/example/basic/5-nested-modules/foo/bar/src/Bar.scala @@ -1,11 +1,11 @@ -package bar +package foo.bar import scalatags.Text.all._ import mainargs.{main, ParserForMethods} -object Bar { +object Bar { @main def main(text: String): Unit = { - val value = p(text) + val value = h1(text) println("Bar.value: " + value) } diff --git a/example/basic/5-nested-modules/qux/src/Qux.scala b/example/basic/5-nested-modules/foo/qux/src/Qux.scala similarity index 52% rename from example/basic/5-nested-modules/qux/src/Qux.scala rename to example/basic/5-nested-modules/foo/qux/src/Qux.scala index 2bd2f5b1c4d..1819642053e 100644 --- a/example/basic/5-nested-modules/qux/src/Qux.scala +++ b/example/basic/5-nested-modules/foo/qux/src/Qux.scala @@ -1,15 +1,12 @@ -package qux +package foo.qux import scalatags.Text.all._ import mainargs.{main, ParserForMethods, arg} -object Qux { - +object Qux { @main - def main(@arg(name="foo-text") fooText: String, - @arg(name="bar-text") barText: String, - @arg(name="qux-text") quxText: String): Unit = { - foo.Foo.main(fooText) - bar.Bar.main(barText) + def main(@arg(name = "bar-text") barText: String, + @arg(name = "qux-text") quxText: String): Unit = { + foo.bar.Bar.main(barText) val value = p(quxText) println("Qux.value: " + value) diff --git a/example/basic/5-nested-modules/wrapper/foo/src/Foo.scala b/example/basic/5-nested-modules/wrapper/foo/src/Foo.scala deleted file mode 100644 index f7883549e04..00000000000 --- a/example/basic/5-nested-modules/wrapper/foo/src/Foo.scala +++ /dev/null @@ -1,12 +0,0 @@ -package foo -import scalatags.Text.all._ -import mainargs.{main, ParserForMethods} -object Foo { - @main - def main(text: String): Unit = { - val value = h1(text) - println("Foo.value: " + value) - } - - def main(args: Array[String]): Unit = ParserForMethods(this).runOrExit(args) -} diff --git a/example/web/5-webapp-scalajs-shared/build.sc b/example/web/5-webapp-scalajs-shared/build.sc index 9b31895df20..566a57f6ce2 100644 --- a/example/web/5-webapp-scalajs-shared/build.sc +++ b/example/web/5-webapp-scalajs-shared/build.sc @@ -32,8 +32,7 @@ object app extends RootModule with AppScalaModule{ } object shared extends Module{ - trait SharedModule extends AppScalaModule{ - def millSourcePath = super.millSourcePath / os.up + trait SharedModule extends AppScalaModule with PlatformScalaModule { def ivyDeps = Agg( ivy"com.lihaoyi::scalatags::0.12.0", diff --git a/example/web/6-cross-platform-publishing/build.sc b/example/web/6-cross-platform-publishing/build.sc index c0c4682cc49..81c6703bc6f 100644 --- a/example/web/6-cross-platform-publishing/build.sc +++ b/example/web/6-cross-platform-publishing/build.sc @@ -1,13 +1,8 @@ import mill._, scalalib._, scalajslib._, publish._ -object wrapper extends Cross[WrapperModule]("2.13.10", "3.2.2") -class WrapperModule(val crossScalaVersion: String) extends Module { - - trait MyModule extends CrossScalaModule with PublishModule { - def artifactName = millModuleSegments.parts.dropRight(1).last - - def crossScalaVersion = WrapperModule.this.crossScalaVersion - def millSourcePath = super.millSourcePath / os.up +object foo extends Cross[FooModule]("2.13.10", "3.2.2") +class FooModule(val crossScalaVersion: String) extends CrossScalaModule.Base { + trait Shared extends CrossScalaModule with PlatformScalaModule with PublishModule { def publishVersion = "0.0.1" def pomSettings = PomSettings( @@ -25,35 +20,28 @@ class WrapperModule(val crossScalaVersion: String) extends Module { def ivyDeps = Agg(ivy"com.lihaoyi::utest::0.7.11") def testFramework = "utest.runner.Framework" } - - def sources = T.sources { - val platform = millModuleSegments.parts.last - super.sources().flatMap(source => - Seq( - source, - PathRef(source.path / os.up / s"${source.path.last}-${platform}") - ) - ) - } } - trait MyScalaJSModule extends MyModule with ScalaJSModule { + + trait SharedJS extends Shared with ScalaJSModule { def scalaJSVersion = "1.13.0" } - object foo extends Module{ - object jvm extends MyModule{ + object bar extends Module { + object jvm extends Shared + + object js extends SharedJS + } + + object qux extends Module{ + object jvm extends Shared{ def moduleDeps = Seq(bar.jvm) def ivyDeps = super.ivyDeps() ++ Agg(ivy"com.lihaoyi::upickle::3.0.0") } - object js extends MyScalaJSModule { + object js extends SharedJS { def moduleDeps = Seq(bar.js) } } - object bar extends Module{ - object jvm extends MyModule - object js extends MyScalaJSModule - } } // This example demonstrates how to publish Scala modules which are both @@ -62,43 +50,43 @@ class WrapperModule(val crossScalaVersion: String) extends Module { /* Example Usage -> ./mill show wrapper[2.13.10].foo.jvm.sources # mac/linux -wrapper/foo/src -wrapper/foo/src-jvm -wrapper/foo/src-2.13.10 -wrapper/foo/src-2.13.10-jvm -wrapper/foo/src-2.13 -wrapper/foo/src-2.13-jvm -wrapper/foo/src-2 -wrapper/foo/src-2-jvm - -> ./mill show wrapper[3.2.2].bar.js.sources # mac/linux -wrapper/bar/src -wrapper/bar/src-js -wrapper/bar/src-3.2.2 -wrapper/bar/src-3.2.2-js -wrapper/bar/src-3.2 -wrapper/bar/src-3.2-js -wrapper/bar/src-3 -wrapper/bar/src-3-js - -> ./mill wrapper[2.13.10].foo.jvm.run +> ./mill show foo[2.13.10].bar.jvm.sources +foo/bar/src +foo/bar/src-jvm +foo/bar/src-2.13.10 +foo/bar/src-2.13.10-jvm +foo/bar/src-2.13 +foo/bar/src-2.13-jvm +foo/bar/src-2 +foo/bar/src-2-jvm + +> ./mill show foo[3.2.2].qux.js.sources +foo/qux/src +foo/qux/src-js +foo/qux/src-3.2.2 +foo/qux/src-3.2.2-js +foo/qux/src-3.2 +foo/qux/src-3.2-js +foo/qux/src-3 +foo/qux/src-3-js + +> ./mill foo[2.13.10].qux.jvm.run Bar.value:

world Specific code for Scala 2.x

Parsing JSON with ujson.read -Foo.main: Set(

i

,

cow

,

me

) +Qux.main: Set(

i

,

cow

,

me

) -> ./mill wrapper[3.2.2].foo.js.run +> ./mill foo[3.2.2].qux.js.run Bar.value:

world Specific code for Scala 3.x

Parsing JSON with js.JSON.parse -Foo.main: Set(

i

,

cow

,

me

) +Qux.main: Set(

i

,

cow

,

me

) > ./mill __.publishLocal -Publishing Artifact(com.lihaoyi,bar_sjs1_2.13,0.0.1) to ivy repo -Publishing Artifact(com.lihaoyi,bar_2.13,0.0.1) to ivy repo -Publishing Artifact(com.lihaoyi,foo_sjs1_2.13,0.0.1) to ivy repo -Publishing Artifact(com.lihaoyi,foo_2.13,0.0.1) to ivy repo -Publishing Artifact(com.lihaoyi,bar_sjs1_3,0.0.1) to ivy repo -Publishing Artifact(com.lihaoyi,bar_3,0.0.1) to ivy repo -Publishing Artifact(com.lihaoyi,foo_sjs1_3,0.0.1) to ivy repo -Publishing Artifact(com.lihaoyi,foo_3,0.0.1) to ivy repo -*/ \ No newline at end of file +Publishing Artifact(com.lihaoyi,foo-bar_sjs1_2.13,0.0.1) to ivy repo +Publishing Artifact(com.lihaoyi,foo-bar_2.13,0.0.1) to ivy repo +Publishing Artifact(com.lihaoyi,foo-qux_sjs1_2.13,0.0.1) to ivy repo +Publishing Artifact(com.lihaoyi,foo-qux_2.13,0.0.1) to ivy repo +Publishing Artifact(com.lihaoyi,foo-bar_sjs1_3,0.0.1) to ivy repo +Publishing Artifact(com.lihaoyi,foo-bar_3,0.0.1) to ivy repo +Publishing Artifact(com.lihaoyi,foo-qux_sjs1_3,0.0.1) to ivy repo +Publishing Artifact(com.lihaoyi,foo-qux_3,0.0.1) to ivy repo +*/ diff --git a/example/web/6-cross-platform-publishing/wrapper/bar/src-2/BarVersionSpecific.scala b/example/web/6-cross-platform-publishing/foo/bar/src-2/BarVersionSpecific.scala similarity index 100% rename from example/web/6-cross-platform-publishing/wrapper/bar/src-2/BarVersionSpecific.scala rename to example/web/6-cross-platform-publishing/foo/bar/src-2/BarVersionSpecific.scala diff --git a/example/web/6-cross-platform-publishing/wrapper/bar/src-3/BarVersionSpecific.scala b/example/web/6-cross-platform-publishing/foo/bar/src-3/BarVersionSpecific.scala similarity index 100% rename from example/web/6-cross-platform-publishing/wrapper/bar/src-3/BarVersionSpecific.scala rename to example/web/6-cross-platform-publishing/foo/bar/src-3/BarVersionSpecific.scala diff --git a/example/web/6-cross-platform-publishing/wrapper/bar/src/Bar.scala b/example/web/6-cross-platform-publishing/foo/bar/src/Bar.scala similarity index 100% rename from example/web/6-cross-platform-publishing/wrapper/bar/src/Bar.scala rename to example/web/6-cross-platform-publishing/foo/bar/src/Bar.scala diff --git a/example/web/6-cross-platform-publishing/wrapper/bar/test/src/BarTests.scala b/example/web/6-cross-platform-publishing/foo/bar/test/src/BarTests.scala similarity index 100% rename from example/web/6-cross-platform-publishing/wrapper/bar/test/src/BarTests.scala rename to example/web/6-cross-platform-publishing/foo/bar/test/src/BarTests.scala diff --git a/example/web/6-cross-platform-publishing/wrapper/foo/src-js/FooPlatformSpecific.scala b/example/web/6-cross-platform-publishing/foo/qux/src-js/QuxPlatformSpecific.scala similarity index 82% rename from example/web/6-cross-platform-publishing/wrapper/foo/src-js/FooPlatformSpecific.scala rename to example/web/6-cross-platform-publishing/foo/qux/src-js/QuxPlatformSpecific.scala index 8a31c3529da..d9f57981da4 100644 --- a/example/web/6-cross-platform-publishing/wrapper/foo/src-js/FooPlatformSpecific.scala +++ b/example/web/6-cross-platform-publishing/foo/qux/src-js/QuxPlatformSpecific.scala @@ -1,6 +1,6 @@ -package foo +package qux import scala.scalajs.js -object FooPlatformSpecific { +object QuxPlatformSpecific { def parseJsonGetKeys(s: String): Set[String] = { println("Parsing JSON with js.JSON.parse") js.JSON.parse(s).asInstanceOf[js.Dictionary[_]].keys.toSet diff --git a/example/web/6-cross-platform-publishing/wrapper/foo/src-jvm/FooPlatformSpecific.scala b/example/web/6-cross-platform-publishing/foo/qux/src-jvm/QuxPlatformSpecific.scala similarity index 76% rename from example/web/6-cross-platform-publishing/wrapper/foo/src-jvm/FooPlatformSpecific.scala rename to example/web/6-cross-platform-publishing/foo/qux/src-jvm/QuxPlatformSpecific.scala index 6d92e2e15f4..8feff343246 100644 --- a/example/web/6-cross-platform-publishing/wrapper/foo/src-jvm/FooPlatformSpecific.scala +++ b/example/web/6-cross-platform-publishing/foo/qux/src-jvm/QuxPlatformSpecific.scala @@ -1,5 +1,5 @@ -package foo -object FooPlatformSpecific { +package qux +object QuxPlatformSpecific { def parseJsonGetKeys(s: String): Set[String] = { println("Parsing JSON with ujson.read") ujson.read(s).obj.keys.toSet diff --git a/example/web/6-cross-platform-publishing/wrapper/foo/src/Foo.scala b/example/web/6-cross-platform-publishing/foo/qux/src/Qux.scala similarity index 69% rename from example/web/6-cross-platform-publishing/wrapper/foo/src/Foo.scala rename to example/web/6-cross-platform-publishing/foo/qux/src/Qux.scala index aa72b78de72..77bad3e03af 100644 --- a/example/web/6-cross-platform-publishing/wrapper/foo/src/Foo.scala +++ b/example/web/6-cross-platform-publishing/foo/qux/src/Qux.scala @@ -1,9 +1,9 @@ -package foo +package qux import scalatags.Text.all._ -object Foo { +object Qux { def main(args: Array[String]): Unit = { println("Bar.value: " + bar.Bar.value) val string = """{"i": "am", "cow": "hear", "me": "moo"}""" - println("Foo.main: " + FooPlatformSpecific.parseJsonGetKeys(string).map(p(_))) + println("Qux.main: " + QuxPlatformSpecific.parseJsonGetKeys(string).map(p(_))) } } diff --git a/example/web/6-cross-platform-publishing/wrapper/foo/test/src/FooTests.scala b/example/web/6-cross-platform-publishing/foo/qux/test/src/QuxTests.scala similarity index 64% rename from example/web/6-cross-platform-publishing/wrapper/foo/test/src/FooTests.scala rename to example/web/6-cross-platform-publishing/foo/qux/test/src/QuxTests.scala index 7ca5f69ef3d..bdcf6fa9203 100644 --- a/example/web/6-cross-platform-publishing/wrapper/foo/test/src/FooTests.scala +++ b/example/web/6-cross-platform-publishing/foo/qux/test/src/QuxTests.scala @@ -1,10 +1,10 @@ -package foo +package qux import utest._ -object FooTests extends TestSuite { +object QuxTests extends TestSuite { def tests = Tests { test("parseJsonGetKeys") { val string = """{"i": "am", "cow": "hear", "me": "moo}""" - val keys = FooPlatformSpecific.parseJsonGetKeys(string) + val keys = QuxPlatformSpecific.parseJsonGetKeys(string) assert(keys == Set("i", "cow", "me")) keys } diff --git a/scalalib/src/mill/scalalib/CrossModuleBase.scala b/scalalib/src/mill/scalalib/CrossModuleBase.scala index 6cae4fb596d..f608f563aec 100644 --- a/scalalib/src/mill/scalalib/CrossModuleBase.scala +++ b/scalalib/src/mill/scalalib/CrossModuleBase.scala @@ -12,7 +12,8 @@ trait CrossModuleBase extends ScalaModule { protected def scalaVersionDirectoryNames: Seq[String] = ZincWorkerUtil.matchingVersions(crossScalaVersion) - override def artifactName: T[String] = millModuleSegments.parts.init.mkString("-") + protected def wrapperSegments = millModuleSegments.parts + override def artifactNameParts = super.artifactNameParts().patch(wrapperSegments.size - 1, Nil, 1) implicit def crossSbtModuleResolver: Resolver[CrossModuleBase] = new Resolver[CrossModuleBase] { def resolve[V <: CrossModuleBase](c: Cross[V]): V = { diff --git a/scalalib/src/mill/scalalib/CrossScalaModule.scala b/scalalib/src/mill/scalalib/CrossScalaModule.scala index 8edf01d8f87..330331477c1 100644 --- a/scalalib/src/mill/scalalib/CrossScalaModule.scala +++ b/scalalib/src/mill/scalalib/CrossScalaModule.scala @@ -4,9 +4,10 @@ import mill.api.PathRef import mill.T /** - * A [[ScalaModule]] with is suited to be used with [[mill.define.Cross]]. - * It supports additional source directories with the scala version pattern as suffix (`src-{scalaversionprefix}`), - * e.g. + * A [[ScalaModule]] which is suited to be used with [[mill.define.Cross]]. + * It supports additional source directories with the scala version pattern + * as suffix (`src-{scalaversionprefix}`), e.g. + * * - src * - src-2.11 * - src-2.12.3 @@ -25,3 +26,20 @@ trait CrossScalaModule extends ScalaModule with CrossModuleBase { outer => } trait Tests extends CrossScalaModuleTests } + +object CrossScalaModule { + + /** + * Used with a [[mill.define.Cross]] when you want [[CrossScalaModule]]'s + * nested within it + */ + trait Base extends mill.Module { + def crossScalaVersion: String + private def wrapperSegments0 = millModuleSegments.parts + trait CrossScalaModule extends mill.scalalib.CrossScalaModule { + override def wrapperSegments = wrapperSegments0 + def crossScalaVersion = Base.this.crossScalaVersion + + } + } +} diff --git a/scalalib/src/mill/scalalib/JavaModule.scala b/scalalib/src/mill/scalalib/JavaModule.scala index 9e21617b991..c783134f510 100644 --- a/scalalib/src/mill/scalalib/JavaModule.scala +++ b/scalalib/src/mill/scalalib/JavaModule.scala @@ -858,7 +858,9 @@ trait JavaModule * For example, by default a scala module foo.baz might be published as foo-baz_2.12 and a java module would be foo-baz. * Setting this to baz would result in a scala artifact baz_2.12 or a java artifact baz. */ - def artifactName: T[String] = millModuleSegments.parts.mkString("-") + def artifactName: T[String] = artifactNameParts().mkString("-") + + def artifactNameParts: T[Seq[String]] = millModuleSegments.parts /** * The exact id of the artifact to be published. You probably don't want to override this. diff --git a/scalalib/src/mill/scalalib/PlatformScalaModule.scala b/scalalib/src/mill/scalalib/PlatformScalaModule.scala new file mode 100644 index 00000000000..21f42e1e26f --- /dev/null +++ b/scalalib/src/mill/scalalib/PlatformScalaModule.scala @@ -0,0 +1,29 @@ +package mill.scalalib +import mill._ + +/** + * A [[ScalaModule]] intended for defining `.jvm`/`.js`/`.native` submodules + * It supports additional source directories per platform, e.g. `src-jvm/` or + * `src-js/` and can be used inside a [[CrossScalaModule.Base]], to get one + * source folder per platform per version e.g. `src-2.12-jvm/`. + * + * Adjusts the [[millSourcePath]] and [[artifactNameParts]] to ignore the last + * path segment, which is assumed to be the name of the platform the module is + * built against and not something that should affect the filesystem path or + * artifact name + */ +trait PlatformScalaModule extends ScalaModule { + override def millSourcePath = super.millSourcePath / os.up + + override def sources = T.sources { + val platform = millModuleSegments.parts.last + super.sources().flatMap(source => + Seq( + source, + PathRef(source.path / os.up / s"${source.path.last}-${platform}") + ) + ) + } + + override def artifactNameParts = super.artifactNameParts().dropRight(1) +}