Add support for cross-values support at the task-level #4595
Replies: 4 comments 3 replies
-
ImplementationI think something along those lines should allow to implement that:
About cross-values added in If the leaf tasks have values in the second added field in As a |
Beta Was this translation helpful? Give feedback.
-
Issues / points to pay attention to, that come to mind (Possibly sparse) Matrices of cross valuesWhen several cross-values are involved, users might want to restrict the value of one of the cross value depending on the value of the other. This should be achievable with the proposal above, we should allow to implement things like this. object myModule extends Module {
// Cross task definition that reads two cross values from the context at once
def crossValues = Task.Cross.sparse("foo", "bar")(
("1.2", "2.3"),
("1.3", "3.3"),
("1.4", "4.3")
)
def fooVersion = Task {
crossValues()._1
}
def barVersion = Task {
crossValues()._2
}
} Cross values with the same name but different value listA cross value with the same name can be defined at different places (think object mod1 extends ScalaModule {
def scalaVersion = Task.Cross("scala")("2.12.20", "2.13.16", "3.6.2")
}
object mod2 extends ScalaModule {
def scalaVersion = Task.Cross("scala")("2.13.16", "3.6.2")
}
object mod3 extends ScalaModule {
def scalaVersion = Task.Cross("scala")("2.12.20", "2.13.16", "3.6.2")
def moduleDeps = Seq(
mod1,
mod2
)
} This should fail
This should succeed
Cross values set by tasksobject mod1 extends ScalaModule {
def scalaVersion = Task.Cross("scala")("2.12.20", "2.13.16")
}
object thing extends Module {
// Here we want to compile a cross-compiled module
// only for a specific hardcoded Scala version. Users don't need
// to specify that cross value on the command-line when running
// that command.
def compile213Stuff() = Task.Command {
mod1.compile.cross("scala" -> "2.13.16")()
}
}
// This module isn't cross-compiled, so it tries to
// enforce its Scala version to its moduleDeps beforehand -
// this value doesn't need to be specified on the command-line
// by users in particular
object cli extends ScalaModule {
private def sv = "2.13.16"
def scalaVersion = sv
def moduleDeps = Seq(
mod1.cross("scala" -> sv)
)
}
If we warn users for unused cross parameters, we should warn here if the cross parameter ends up not being used by Making the syntax |
Beta Was this translation helpful? Give feedback.
-
One nice aspect of this proposal is that it's somewhat orthogonal to the current cross modules, so we can have both implementations around for some time. That way, users are not forced to switch to it during a Mill version bump. That should give time to Mill users to switch to the new system, and allow to address any shortcoming that might arise. Such a cross value system makes dealing with cross-values more user friendly IMO, and, perhaps more subjectively, removes what feels to me like an idiosyncrasy in Mill: its handling of cross values, which feels at odd with the overall sleekness of the Mill task system. IMO, such cross values should help increase the adoption of Mill in the Scala open source ecosystem, but also by Mill users more broadly. In the Scala open source ecosystem, the vast majority of projects support multiple Scala versions via cross-compilation. Up to now, the way Mill handled cross values felt somewhat less user friendly than how sbt handles those (which is a pity, given how much more convenient the Mill task system is). This proposal aims at changing that. For Mill users at large, it lowers the cost of adding / removing cross values: no need to introduce intermediary traits if one adds a cross value type, it's just a matter of defining a new task. |
Beta Was this translation helpful? Give feedback.
-
I'm in favor of this proposal in general. Bazel provides something similar with Configurations and Transitions, and in general it works great. It definitely will be a big improvement in ergonomics over use NamespacingIn terms of implementation, it would mean that tasks are no longer uniquely keyed by their As far as syntax goes, at the declaration site I think we might be able to get by without introducing another namespace for the cross values, by using their task selector as the name. e.g. def scalaVersion = Task.Cross("2.12.20", "2.13.16", "3.5.2")
object myModule extends ScalaModule {
def scalaVersion = build.scalaVersion()
} $ ./mill 'myModule.compile,scalaVersion=2.13.16' Or inline object myModule extends ScalaModule {
def scalaVersion = Task.Cross("2.12.20", "2.13.16", "3.5.2")
} $ ./mill 'myModule.compile,myModule.scalaVersion=2.13.16' CLI SyntaxThe syntax is a big clunky and we could probably come up with something better? e.g. $ ./mill myModule.scalaVersion=2.13.16 myModule.compile In either case, we could make missing the In-Code ReferencesAs is the case with Bazel's transitions, any task referencing another task should be able to set a cross value, e.g. def scalaVersion = Task.Cross("2.12.20", "2.13.16", "3.5.2")
object myModule extends ScalaModule {
def scalaVersion = build.scalaVersion()
}
def allJars = Task{
os.copy(myModule.jar(build.scalaVersion := "2.12.20").path, Task.dest / "out-212.jar")
os.copy(myModule.jar(build.scalaVersion := "2.13.16").path, Task.dest / "out-213.jar")
os.copy(myModule.jar(build.scalaVersion := "3.5.2").path, Task.dest / "out-35.jar")
} A task should be able to reference an upstream task with multiple different, as shown above, which would compile |
Beta Was this translation helpful? Give feedback.
-
I'd like to propose to add support for things along those lines to handle cross-values support:
which currently needs to be written as
In particular, this moves the concern of handling cross values from the module level to the task level.
IMO, the proposed syntax is more straightforward. Thanks to it, no refactoring is needed when introducing cross values - it's just a matter of adding a new task, or redefining one.
Users could then do things like
(I'm not sure what would be the best way to pass such cross values on the command-line. This syntax is just a proposal, to set ideas. I'm also not considering default values for these at this point.)
I'm going to post below messages discussing a possible implementation for that, and problems that might arise with it.
Beta Was this translation helpful? Give feedback.
All reactions