-
-
Notifications
You must be signed in to change notification settings - Fork 16.6k
pkgs/README.md: discourage overrideAttrs within Nixpkgs #421201
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
base: master
Are you sure you want to change the base?
Conversation
Update: beyond near misses, it has actually happened three times now with the same duplicated libxml2 override. |
Ah, that Edge PR. Btw, this also reminded me I have to rewrite my Rofi PR (I have |
I think that if we introduce versioned attributes in |
I could consider dropping the mention of overridePythonAttrs for the time being if it's not clear what to do for it yet. |
Hmm. I've always thought the security-related aspect of this should be addressed by a good security scanner that can descend into more than just attr-accessible derivations. As far as accidental breakage goes due to a maintainer not realising that their package is being overridden elsewhere, that's what I think such a broad declaration is in danger of damaging something that I consider to be one of nix's superpowers - the ability to get awkward software with awkward dependencies packaged. Moving all variants of a package to be located with the package also surely means we'll have to expose it as an external attr, which means we'll end up with more |
That only works for packages with a low rebuild count. |
Sure, but staging breakages eventually get thrown up by hydra. As far as the breakage argument goes though, I feel it's rather "caveat emptor" - the risk is with the depending package if they're going to use |
Yes, that's what I like about |
I also think it's a problem when you outlaw/discourage something that's so heavily used across nixpkgs, including by what I'd call "exemplar" packages. What are we then saying to people who are trying to learn from other, well regarded, packages? "We wouldn't accept this today"? Well then we wouldn't be accepting some of our core packages like LLVM either. Does the alternative we're proposing to people actually lead to a better situation, if it's even a sufficient replacement? If not, we're just leaving people in limbo. |
This is not how maintainers feel in practice. And maintainers (domain experts) also need to have a chance to say no to irresponsible overrides of packages, like how we have the "no new downstream kernels" rule. With overrideAttrs rather than proper abstractions, there's no possibility of quality control for these overrides. |
If a user has a need for the attr, they'll use it. The only difference from today will be that there'll be an incentive to reuse existing overrides rather than adding more mostly-duplicated closure-bloating overrides that could have been unified. |
When we were putting together this idea on Matrix, we discovered that there are actually very few unique occurrences of overrideAttrs in Nixpkgs when you take into account that something like 80% are overrides of generated packages that could be replaced in bulk with a better abstraction. Several of us had the intention of gradually working through all those and implementing better alternatives. But I opened the documentation PR first, explaining the rationale, because the alternative was explaining it separately on every one of those PRs. Nobody intends to have packages using overrideAttrs around in Nixpkgs contrary to the guidelines forever. |
I agree with this - it does not feel like you can do an update of a widely-used package without bearing some responsibility for altered versions of it throughout the tree. This leads to an unfortunate responsibility-without-authority situation where there is at least partial maintenance responsibility for overrides in downstream packages despite the fact that maintainers of dependencies don't really have a strong right to be super opinionated about what a downstream package does.
Triaging I do agree with @risicle that having alternate versions of a package instead of a local Having specific versioned packages at least makes it clear when this happening and what needs fixing, and it also gives the maintainers more of a chance to be notified of it and reject it if necessary. We already have an explicit guideline to avoid having multiple versions of packages when possible, which a separate version more clearly violates than a quick There are cases where an old version of a package is strongly desired to not be readily accessible by maintainers of that package or its containing package set, but is unavoidable in a downstream context. For instance, These cases are just bad in general and we should do what we can to avoid them, but vendoring the old version as (It doesn't fix the case where changes in dependencies of that vendored package themselves break it, which indeed happened with |
@@ -454,6 +454,23 @@ See the Nixpkgs manual for more details on [standard meta-attributes](https://ni | |||
|
|||
Import From Derivation can be worked around in some cases by committing generated intermediate files to version control and reading those instead. | |||
|
|||
## `overrideAttrs` and `overridePythonAttrs` | |||
|
|||
Please do not introduce new uses of `overrideAttrs` or `overridePythonAttrs` in Nixpkgs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see why we wouldn't allow them for the specific use case of defining versioned attributes. Should we rather duplicate an entire expression even if only version and hash need to be changed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be better to introduce an .override
parameter to select between the versions, or to have some other internal logic for it like a generic builder function. Actually I can’t remember seeing many instances of overrideAttrs
being used this way at all; maybe it’s more common in the Python package set.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is also already addressed in the text, and it does not say to duplicate an entire expression:
If you need a different version of a dependency, first try modifying your package to work with the version in Nixpkgs — it's often not very hard! — and if that's not possible, try to factor out a function that can build multiple versions of the package, including the main version.
I'm open to feedback on that advice though! I agree with Emily that it's not common for centralized version overrides of packages (as opposed to sneaky hidden overrides in leaf packages) to use overrideAttrs in the first place. Again, if overridePythonAttrs is different, I'd be happy to exclude it and just address overrideAttrs for the time being.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's an example:
nixpkgs/pkgs/top-level/python-packages.nix
Lines 3189 to 3197 in 30db601
cython_3_1 = cython.overridePythonAttrs rec { | |
version = "3.1.1"; | |
src = pkgs.fetchFromGitHub { | |
owner = "cython"; | |
repo = "cython"; | |
tag = version; | |
hash = "sha256-KdRYPH3Do3KntgqLGIUSeD6DjmXNdFjI2ZSszzMjF6k="; | |
}; | |
}; |
I prefer to keep using
overridePythonAttrs
here because we'll soon get rid of cython_3_1
again and I don't want to go back an forth between a normal expression and one that uses a "function that can build multiple versions of the package".I also don't see why this situation would be unique to Python packages, see e.g.
nixpkgs/pkgs/by-name/ni/nim-unwrapped-2_0/package.nix
Lines 8 to 10 in 30db601
nim-unwrapped-2_2.overrideAttrs ( | |
finalAttrs: previousAttrs: { | |
version = "2.0.16"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't want to go back an forth between a normal expression and one that uses a "function that can build multiple versions of the package".
I don't know about cython, but for things like compilers and interpreters more generally, my experience is that we are either consistently strict about only packaging a single version (like Rust), or we are open to packaging multiple versions, and usually do. In the latter case, I'd keep the generic function around even if there happens to only be a single version packaged for some amount of time, since it's likely that in the near future there will again be multiple versions. Nim looks like it would be one of those situations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I thought you meant overrideAttrs
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@alyssais Maybe we should remove the verbiage about avoiding copy‐paste here? It’s generally better to do, but it’s not related to overrideAttrs
specifically, and I feel there are some cases where overrideAttrs
avoidance is most easily accomplished by copy‐paste (cf. the vendored package example in my tl;dr comment).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which verbiage specifically?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I misread it the first time I think. But I think we can make this paragraph more generic by just mentioning packaging the other version and not being prescriptive about how:
If you need a different version of a dependency, first try modifying your package to work with the version in Nixpkgs — it's often not very hard! — and if that's not possible, try to factor out a function that can build multiple versions of the package, including the main version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. You're both right that there's no one-size-fits-all approach here, so I've made it more vague.
Re: triage and finding issues in general, while I greatly appreciate that Nixpkgs is a place where any contributor is allowed to change whatever part of the stack they need to (given review and consensus), I want to strongly push back on the idea that maintainers of dependencies can reasonably be expected to be responsible for their downstream closures. This scales okay for a package with only a handful of users, but breaks down when there are thousands of downstream packages, especially if any of them happen to poke directly into internals in a way that the upstream maintainer may not even have been aware of. Of course there is greater responsibility in maintaining a package that is widely used - it is proper that such maintainers are diligent about potential breaking changes and perform some kind of assessment of their likely scope. But there is a reason there are only maybe a dozen regular contributors at most to the This is partly a tooling problem: we need to land I don't have a complete, readymade solution, be t I think every solution will have to involve acknowledging that upstream maintainers have only limited responsibilities to downstream packages, that it is reasonable to expect downstream maintainers to take responsibility for resolving those issues in a way they does not add undue burden to the upstream maintainer, and that we can't force every maintainer to maintain a version of their package both before and after a change without very good reason. Of course, there can be no hard rules here, and in a project as interconnected as ours there is always negotiation both ups and down the stack. But the current situation where maintainers of leaf packages can do pretty much whatever and upstream maintainers just have to deal with it is not good. It's hard enough to maintain those core parts of the stack without it also implying responsibility for the rest of it too. I think less |
This comes up quite a lot in review, and we've just had a close call with a known vulnerable library version almost being reintroduced without appropriate knownVulnerabilities markings in an override in the expression for a leaf package. Let's take the first step towards preventing that sort of thing happening again.
|
||
Instead, keep all instances of the same package next to each other, and try to minimize how many different instances of a package are in Nixpkgs. | ||
If you need a patch applied to a dependency, discuss with the maintainer of that dependency whether it would be acceptable to apply to the main version of the package. | ||
If you need a different version of a dependency, first try modifying your package to work with the version in Nixpkgs — it's often not very hard! — and if that's not possible, add a proper versioned package for what you need. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This also has a maintainability burden, so even if it is possible it might or might not be the best idea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with the perspective laid out here.
I would like to merge this at NixCon this week. I encourage anyone who thinks that we should not merge it to place an ❌ with the reasons they think we shouldn't do so in the intervening time. |
This comes up quite a lot in review, and we've just had a close call with a known vulnerable library version almost being reintroduced without appropriate knownVulnerabilities markings in an override in the expression for a leaf package. Let's take the first step towards preventing that sort of thing happening again.
Things done
nix.conf
? (See Nix manual)sandbox = relaxed
sandbox = true
nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD"
. Note: all changes have to be committed, also see nixpkgs-review usage./result/bin/
)Add a 👍 reaction to pull requests you find important.