concretizer: add mode to reuse dependencies only#30990
Conversation
a0b9ec1 to
cb033f8
Compare
cb033f8 to
a514b38
Compare
a514b38 to
559e141
Compare
|
@alalazo I have fixed the conflicts and rebased to current develop. Any comments about this change? |
559e141 to
e9dbee9
Compare
|
@becker33 can you coordinate your "reuse from local installs/upstreams" vs "reuse from binary cache" with this PR? Just to avoid that we're ending up with |
|
@becker33 you mentioned that this PR would need some work to update for changes in develop since it was created. What changes are required? Would love to get this in soon, as I think this is the most logical default concretization strategy. |
e9dbee9 to
5aa6767
Compare
|
I rebased this to current develop to fix some conflicts. I also did some tests and it still seems to work. |
adamjstewart
left a comment
There was a problem hiding this comment.
I tested this with a few individual packages and a massive environment and it works perfectly, exactly the behavior I would find most intuitive. Great job on this!
| # If we only want to reuse dependencies, remove the root specs | ||
| if self.reuse == "dependencies": | ||
| reusable_specs = [ | ||
| spec for spec in reusable_specs if not any(spec.satisfies(root) for root in specs) | ||
| ] |
There was a problem hiding this comment.
I think this is redundant, since it includes specs that have a root as a dependency. The solve will rule that out, but potentially we have more hashes than we want as facts. Did you try:
| # If we only want to reuse dependencies, remove the root specs | |
| if self.reuse == "dependencies": | |
| reusable_specs = [ | |
| spec for spec in reusable_specs if not any(spec.satisfies(root) for root in specs) | |
| ] | |
| # If we only want to reuse dependencies, remove the root specs | |
| if self.reuse == "dependencies": | |
| reusable_specs = [ | |
| spec for spec in reusable_specs if not any(root in spec for root in specs) | |
| ] |
?
There was a problem hiding this comment.
I might be reading the code wrong but aren't we hitting the anonymous case in __contains__ anyway, which simply calls satisfies: https://github.com/spack/spack/blob/develop/lib/spack/spack/spec.py#L4001-L4002
I would therefore assume that this behaves identically. I also did some tests and couldn't provoke any differences.
There was a problem hiding this comment.
Reusable specs are all concrete specs collected either from the DB or from buildcaches, root specs can't be anonymous. I checked the ASP before posting. Result is the same, we just have a lot of input in the ASP which is useless.
Try for instance:
- Install
hdf5+mpi(fake installs are good for this test) - Create an environment with
hdf5+mpiand zlib as root specs +reuse:dependencies spack solve --show=aspfor the environment
I think you'll see all the specs in there, but hdf5 and zlib There are specs though that reference the non-existing zlib and thus will never be selected.
I think there might be other potential pitfalls we might need to check, e.g. if I can reuse the same package as the root but with different variant in an environment. Going back to the example above do we want to reuse hdf5~mpi if it is installed, since the the root says hdf5+mpi? That matters if we have a root spec that depend on hdf5. I didn't test-drive that case yet.
There was a problem hiding this comment.
I got what you meant now, thanks! I confused myself with the "root specs" in the snippet above and actually tested it outside of an environment (which hits the anonymous spec path).
I now did some tests inside an environment and could reproduce your results. I guess the interaction can be a bit surprising if a common dependency is a root spec: I added a new cmake version but since zlib is a root spec and thus filtered out, cmake gets rebuilt even though it could theoretically be reused. I guess there is no way around that, though.
If I add enzo (which requires hdf5~mpi) in your example above, everything seems to continue working as expected:
==> Error: 'hdf5' required multiple values for single-valued variant 'mpi'
Requested '~mpi' and '+mpi'
I also made the change you suggested and pushed a new version.
130768b to
02e7a56
Compare
|
Any updates on this? I find myself needing this behavior again today. My new use case: I often fix bugs in packages and want to build them to make sure the fix works. I'm faced with two options:
I would love the feature added in this PR (even more so if it becomes the default):
|
I incorporated @alalazo's feedback a while ago, so it should now work better in environments. From my side, this is good to go. |
|
I still run into this every time I update a package: @alalazo ping 🙂 |
|
I'll try to review this one by the end of the week. |
alalazo
left a comment
There was a problem hiding this comment.
LGTM. I left a few minor comments. Let's wait a bit to check if people have opinion on the cli flag, otherwise this is ready to be merged.
| pass | ||
|
|
||
| # If we only want to reuse dependencies, remove the root specs | ||
| if self.reuse == "dependencies": |
There was a problem hiding this comment.
(Comment, not request): If we add more reuse modes, it is worth turning these literal strings into enums.
| subgroup.add_argument( | ||
| "--reuse-deps", | ||
| action=ConfigSetAction, | ||
| dest="concretizer:reuse", | ||
| const="dependencies", | ||
| default=None, | ||
| help="reuse installed dependencies only", |
There was a problem hiding this comment.
(nitpick) Not sure this is the best way to deal with the command line, but I think this should not be a feature blocker. What I wonder is if:
--reuse=<argument>
is better and more scalable in general, and if we can deprecate the current --fresh argument. @tgamblin @becker33 @haampie Any opinion on this?
There was a problem hiding this comment.
I haven't touched this one since @adamjstewart mentioned on Slack that supporting both --reuse and --reuse=foo doesn't seem to be possible.
02e7a56 to
c077f63
Compare
This adds a new mode for `concretizer:reuse` called `dependencies`, which only reuses dependencies. Currently, `spack install foo` will reuse older versions of `foo`, which might be surprising to users.
c077f63 to
ac633d3
Compare
|
Is there any special handling (in this PR or already in Spack) for handling deprecated versions? Like if one of my packages becomes deprecated, I might not want it to be reused even if it's already installed. |
|
I don't know of any existing deprecated logic but I too would love this! |
|
Either way, it shouldn't hold up this PR since we already reuse everything by default. If there isn't logic to avoid deprecated versions yet, we can add it in a follow-up PR. |
|
At the moment are there any blockers for this PR? It looks like perhaps we're waiting on final say about |
I was waiting for that, but since I got no objections to the current state of the PR nor other comments I'll merge this. If objections come up later we can take care of them in a following PR. |
This adds a new mode for `concretizer:reuse` called `dependencies`, which only reuses dependencies. Currently, `spack install foo` will reuse older versions of `foo`, which might be surprising to users.
This adds a new mode for
concretizer:reusecalleddependencies, which only reuses dependencies. Currently,spack install foowill reuse older versions offoo, which might be surprising to users.I'm not entirely happy with the argument name (
--reuse-deps) yet and would argue for making this the default reuse mode.