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 a "sticky" property to variants #28630

Merged
merged 6 commits into from
Feb 2, 2022

Conversation

alalazo
Copy link
Member

@alalazo alalazo commented Jan 27, 2022

Refers to #19736
Refers to #26721

This PR adds a new sticky argument to the variant directive. The argument is set to False by default, in which case the semantics of variants during concretization is the usual one. If set to True the variant being marked sticky cannot be changed by clingo during concretization and will either be set to:

  1. An explicit value set in a spec literal
  2. The default value set in package.py or in packages.yaml

Modifications:

@spackbot-app spackbot-app bot added conflicts directives documentation Improvements or additions to documentation new-variant new-version tests General test capability(ies) labels Jan 27, 2022
@alalazo
Copy link
Member Author

alalazo commented Jan 27, 2022

@tgamblin @becker33 I'm waiting for GA to be working again before adding back the variant on CUDA, but the logic to make "sticky" variant work is already here.

The concretizer thus is not free to pick an arbitrary value to work
around conflicts, but will error out instead.
Setting this property on a variant is useful in cases where the
variant allows some dangerous or controversial options (e.g. using unsupported versions
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not very dangerous, is it? It's more about enforcing pedantic rules by default, but still allowing the user to opt out.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's useful when the variant can be dangerous, not that making it sticky is dangerous

@haampie
Copy link
Member

haampie commented Jan 27, 2022

Should it also be tested that packages.yaml values for sticky variants are still preferences, not constraints? E.g. prefer ~x in packages.yaml but +x is "sticky" and there is a conflict on ~x so +x is concretized to nonetheless?

@alalazo
Copy link
Member Author

alalazo commented Jan 27, 2022

@haampie Settings in packages.yaml override the default for package.py (it's already like that).

Comment on lines +421 to +428
def test_sticky_variant_accounts_for_packages_yaml(self):
with spack.config.override(
'packages:sticky-variant', {
'variants': '+allow-gcc'
}
):
s = Spec('sticky-variant %gcc').concretized()
assert s.satisfies('%gcc') and s.satisfies('+allow-gcc')
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test checks that we account for packages.yaml to override the default in package.py

Copy link
Member

@haampie haampie Jan 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I meant the other way around.

In my understanding packages.yaml specifies preferences, whereas the abstract spec input specifies constraints.

Now suppose the expressed preference in packages.yaml for the value of a sticky variant would be unsatisfiable, then I would find it consistent if the value toggled back.

So:

class MyPkg:
    variant('x', default=False, sticky=True)
    conflicts('+x')
packages:
  mypkg:
    variants: '+x'

should concretize to ~x instead of failing?

The reason being: (a) the stickiness applies to the particular variant default value the package author sets, and (b) if we later add support for discriminating between hard constraints in packages.yaml vs soft preferences (as we currently only have), it'd be consistent if everything in packages.yaml remains a preference until then

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The stickiness applies to the variant, packages.yaml can override the default.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, then I'll stop saying packages.yaml specifies preferences 🙃

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I share some of @haampie's concerns here. In all other cases, packages.yaml is a soft preference, I'm not sure it's intuitive that it becomes a hard preference for sticky variants

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So here's how I see it:

  1. The preference is due to the fact that packages.yaml overrides the default in package.py (even when the variant is not sticky)
  2. If the variant is sticky the default value cannot be changed by clingo

The claim in point 1. follows by:

% The default value for a variant in a package is what is prescribed:
%
% 1. On the command line
% 2. In packages.yaml (if there's no command line settings)
% 3. In the package.py file (if there are no settings in
% packages.yaml and the command line)
%
variant_default_value(Package, Variant, Value)
:- variant_default_value_from_package_py(Package, Variant, Value),
not variant_default_value_from_packages_yaml(Package, Variant, _),
not variant_default_value_from_cli(Package, Variant, _).
variant_default_value(Package, Variant, Value)
:- variant_default_value_from_packages_yaml(Package, Variant, Value),
not variant_default_value_from_cli(Package, Variant, _).
variant_default_value(Package, Variant, Value) :- variant_default_value_from_cli(Package, Variant, Value).

Furthermore, if we use the semantics currently proposed here the variant can be sticky whether the packager selects the "permissive" or the "restrictive" behavior as a default in package.py. Think of having:

variant('allow-all-compilers', default=True, sticky=True)

I might want to say:

packages:
  foo:
    variants: ~allow-all-compilers

to prefer the restrictive default. With the semantic you propose instead that would be impossible from packages.yaml (if the permissive semantics is the default in package.py clingo would be happy to switch it in case I try to reset it in packages.yaml).

Copy link
Member

@tgamblin tgamblin Jan 28, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can see what @haampie is saying... kind of. I'm having a hard time coming up with a use case for the soft preference for a sticky variant, though. It seems inconsistent to me that if the variant is sticky, and you override it, that it would not still be sticky. I've always thought of packages.yaml as overriding preferences and not semantics.

Do you have a use case for preference semantics for sticky variants @haampie?

With the hard constraints we are proposing in #27987, you'd be able to do:

packages:
    all:
        require:[+allow-all-compilers]

So we could wait for that.

I do think people will be very confused when they set the value for a sticky variant the current way, and it's no longer sticky when they do that. Also, I can't tell if @haampie expects the soft preferences to only fall back to the sticky default, or if he wants all options to be open to the concretizer once you specify a package preference for a sticky variant.

Personally I think sticky variants always being sticky is fine, because if the user wants soft preference semantics for them in packages.yaml, they can put a list of values instead of a single value. I wouldn't say that for regular variants, because I don't expect the user to list out all values of all variants. But I think it's more intuitive to me if the stickiness is preserved. You have to know the semantics of other variants to use them... why are these different?

But maybe a use case could convince me otherwise?

Copy link
Member

@becker33 becker33 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think @haampie's concern is the main issue going forward with this.

lib/spack/spack/directives.py Outdated Show resolved Hide resolved
Comment on lines +421 to +428
def test_sticky_variant_accounts_for_packages_yaml(self):
with spack.config.override(
'packages:sticky-variant', {
'variants': '+allow-gcc'
}
):
s = Spec('sticky-variant %gcc').concretized()
assert s.satisfies('%gcc') and s.satisfies('+allow-gcc')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I share some of @haampie's concerns here. In all other cases, packages.yaml is a soft preference, I'm not sure it's intuitive that it becomes a hard preference for sticky variants

lib/spack/docs/packaging_guide.rst Outdated Show resolved Hide resolved
@alalazo alalazo marked this pull request as ready for review January 29, 2022 14:40
@alalazo
Copy link
Member Author

alalazo commented Jan 31, 2022

@corbett5 I have seen your comment in #26721 In case you want to try this PR to leave feedback, it should solve the issues seen in #19736 with clingo swapping the default value of the variant to work around the conflict. To allow unsupported compilers in this PR you just need to add:

packages:
  cuda:
    variants:  '+allow-unsupported-compilers'

to your packages.yaml

@becker33 becker33 merged commit cd04109 into spack:develop Feb 2, 2022
@alalazo alalazo deleted the feature/sticky_variants branch February 2, 2022 18:05
RikkiButler20 pushed a commit to RikkiButler20/spack that referenced this pull request Feb 8, 2022
* Add sticky variants

* Add unit tests for sticky variants

* Add documentation for sticky variants

* Revert "Revert 19736 because conflicts are avoided by clingo by default (spack#26721)"

This reverts commit 33ef7d5.

* Add stickiness to "allow-unsupported-compiler"
EthanS94 pushed a commit to EthanS94/spack that referenced this pull request Feb 17, 2022
* Add sticky variants

* Add unit tests for sticky variants

* Add documentation for sticky variants

* Revert "Revert 19736 because conflicts are avoided by clingo by default (spack#26721)"

This reverts commit 33ef7d5.

* Add stickiness to "allow-unsupported-compiler"
olupton pushed a commit to BlueBrain/spack that referenced this pull request Apr 8, 2022
* Add sticky variants

* Add unit tests for sticky variants

* Add documentation for sticky variants

* Revert "Revert 19736 because conflicts are avoided by clingo by default (spack#26721)"

This reverts commit 33ef7d5.

* Add stickiness to "allow-unsupported-compiler"
olupton pushed a commit to BlueBrain/spack that referenced this pull request Apr 11, 2022
* Add sticky variants

* Add unit tests for sticky variants

* Add documentation for sticky variants

* Revert "Revert 19736 because conflicts are avoided by clingo by default (spack#26721)"

This reverts commit 33ef7d5.

* Add stickiness to "allow-unsupported-compiler"
olupton added a commit to BlueBrain/spack that referenced this pull request Apr 12, 2022
* Add a "sticky" property to variants (spack#28630)
* cuda, nvhpc: update recipes from upstream/develop.
* nvhpc: deploy 22.3, drop 21.2 and 22.1
* cuda: deploy 11.6.1 to match nvhpc 22.3
* py-pytorch: update patch checksum.

Co-authored-by: Massimiliano Culpo <massimiliano.culpo@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants