-
-
Notifications
You must be signed in to change notification settings - Fork 382
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Restrict sources and inputs to not accept upstream tasks (#4524)
Fixes #4121 This PR makes `Task.Source`, `Task.Sources`, and `Task.Input` to not accept any upstream tasks. Sources and Inputs thus must be the upstream-most nodes in our task graph: although they still contain values computed during the `resolution` phase, they no longer can contain values computed during `execution`. This is a significant simplification of Mill's internal build graph data model, and I expect it to allow a ton of internal code to be streamlined and simplifierd In practice, following this restriction doesn't seem to be too onerous: 1. You can no longer `override def sources = Task.Sources` with another `Task.Sources` and call `super.sources() ++ Seq(PathRef(...))`. Instead, you need to define a separate `def customSources = Task.Sources{}` and do `override def sources = Task { super.sources() ++ customSources() }` 2. You can no longer `override def sources = Task.Sources { super.sources().flatMap{...} }`. Instead, you need to have a separate `def sourcesFolders: Seq[os.SubPath]` that you can override and manipulate, before it gets fed into `Task.Sources(sourcesFolders*)` once at the end. The various places where we were previously chaining `Task.Sources` or `Task.Input`s together inside Mill's own codebase have been updated to use the new pattern. This was a relatively straightforward and mechanical process. Only `MillBuildRootModule#scriptSources` took a bit more refactoring, which I took as an opportunity to drop the `$file` syntax to allow us to separate `.mill` file discovery and processing (which previously had to be interleaved due to parsing and de-referencing `import $file` statements) There's some inconvenience, but overall this way of doing things is a lot more correct: e.g. 1. Previously, if you did `override def Task.Sources { super.sources().map{...} }`, Mill's task graph would depend on `super.sources()` even if the final paths that end up getting returned to `Task.Sources` do not include the originals due to being transformed somehow. 2. With this PR, you can manipulate `def sourcesFolders` all you want during inheritance using overrides, and only the final `sourceFolders` that get passed to `Task.Sources` ends up being part of the dependency graph. 3. The current `--watch` behavior expects that the paths returned by `Source` and `Sources` are constant, which is not strictly true. It is possible that each time you call `Source`/`Sources` you get a different set of paths, but the current `--watch` behavior does not account for that possibility. With this PR, we formalize the existing assumption that `Source`/`Sources` paths are fixed at module initialization time, and only the content can change. One scenario where we do lose something is `private def pullAndHash = Task.Input {`. This depends on upstream tasks to determine what to pull, and then acts as a `Task.Input`: that means every time you run `./mill foo` that depends on `pullAndHash` it will re-run, and if you run `./mill -w foo` it will run `pullAndHash` continuously in a loop. While whether or not that is good idea for this specific scenario is questionable (dockerhub may [rate limit you](https://medium.com/@PlanB./docker-hubs-new-rate-limits-what-it-means-for-kubernetes-users-2748e9ff632e)!) it does demonstrate a use case that would not be possible if we merge this PR to restrict `Task.Input`s to not allow upstream tasks In general you can still do computations to determine the paths to your `Task.Source` and `Task.Sources` folders, just that these computations must happen during the module-initialization/task-resolution phase rather than during the execution phase This simplification allows significant cleanups 1. `mill.api.TaskResult` is no longer necessary, since we can trivially check the `os.Path`s of `Task.Sources` for updates and the `() => T` of `Task.Input`s for updates without needing to awkwardly capture things in a lambda that we can re-run later 2. `selective.run` no longer needs to run a full evaluation cycle in order to collect the hashes of all the `Task.Input`s and `Task.Sources`, since now you can easily collect those tasks and get each return value individually There are probably other follow ups I can't think of off the top of my head that will become apparent later
- Loading branch information
Showing
62 changed files
with
349 additions
and
484 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.