Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add some helpers to simplify cross-version/cross-platform modules #2406

Merged
merged 8 commits into from
Apr 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions example/basic/5-nested-modules/baz/src/Baz.scala
Original file line number Diff line number Diff line change
@@ -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)
}
29 changes: 15 additions & 14 deletions example/basic/5-nested-modules/build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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: <h1>hello</h1>
Bar.value: <p>world</p>
Qux.value: <p>today</p>
> ./mill baz.run --bar-text hello --qux-text world --baz-text today
Bar.value: <h1>hello</h1>
Qux.value: <p>world</p>
Baz.value: <p>today</p>

> ./mill wrapper.foo.run --text hello
Foo.value: <h1>hello</h1>
> ./mill foo.qux.run --bar-text hello --qux-text world
Bar.value: <h1>hello</h1>
Qux.value: <p>world</p>

*/
Original file line number Diff line number Diff line change
@@ -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)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
12 changes: 0 additions & 12 deletions example/basic/5-nested-modules/wrapper/foo/src/Foo.scala

This file was deleted.

3 changes: 1 addition & 2 deletions example/web/5-webapp-scalajs-shared/build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
106 changes: 47 additions & 59 deletions example/web/6-cross-platform-publishing/build.sc
Original file line number Diff line number Diff line change
@@ -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(
Expand All @@ -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
Expand All @@ -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: <p>world Specific code for Scala 2.x</p>
Parsing JSON with ujson.read
Foo.main: Set(<p>i</p>, <p>cow</p>, <p>me</p>)
Qux.main: Set(<p>i</p>, <p>cow</p>, <p>me</p>)

> ./mill wrapper[3.2.2].foo.js.run
> ./mill foo[3.2.2].qux.js.run
Bar.value: <p>world Specific code for Scala 3.x</p>
Parsing JSON with js.JSON.parse
Foo.main: Set(<p>i</p>, <p>cow</p>, <p>me</p>)
Qux.main: Set(<p>i</p>, <p>cow</p>, <p>me</p>)

> ./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
*/
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
*/
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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(_)))
}
}
Original file line number Diff line number Diff line change
@@ -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
}
Expand Down
3 changes: 2 additions & 1 deletion scalalib/src/mill/scalalib/CrossModuleBase.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
24 changes: 21 additions & 3 deletions scalalib/src/mill/scalalib/CrossScalaModule.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

}
}
}
4 changes: 3 additions & 1 deletion scalalib/src/mill/scalalib/JavaModule.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
29 changes: 29 additions & 0 deletions scalalib/src/mill/scalalib/PlatformScalaModule.scala
Original file line number Diff line number Diff line change
@@ -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)
}