-
-
Notifications
You must be signed in to change notification settings - Fork 14.2k
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
__cleanAttrs
: Clean packages that don't expose all internals
#217243
Conversation
c9f1919
to
f4823d6
Compare
05f723b
to
4002775
Compare
In |
Do we want to make |
I don't think we'll do this anytime soon, if at all. Applying that change too soon would mean that we fail to pay attention to the actual usage of some packages' attributes, which would be bad for users. |
So we should document that it should never be set in any package in nixpkgs without strong reasoning? |
The implementation with dynamic attributes is a little weird, but it performs better by avoiding some attrset copying and sorting, `//`.
Then every package that wants to opt in would have to do it in the first release. I don't think that's a good approach, and the cost of I'd like to avoid blowing up the scope and merge this soon. It adds the mechanism, but avoids changing the policy, so that we can
|
For me this translates into more work and discussions. Sometimes I know that the solution I am drafting is hacky and I decided for myself that it is better than the available alternatives. I don't want to contact another person to expose some variable(s) for that though. I personally would want a setting to just disable cleanAttrs everywhere and give me access to everything, as I don't really care if something is marked as an interface or not. For example this would majorly break nix-update and complicate it. |
@@ -165,6 +165,10 @@ In addition to numerous new and upgraded packages, this release has the followin | |||
|
|||
- Pantheon now defaults to Mutter 42 and GNOME settings daemon 42, all Pantheon packages are now tracking elementary OS 7 updates. | |||
|
|||
- `mkDerivation` does not have to leak implementation details anymore. | |||
|
|||
Passing [`__cleanAttrs = true`](https://nixos.org/manual/nixpkgs/unstable/#var-__cleanAttrs) to `mkDerivation` returns a minimal set of package attributes that can be extended via [`passthru`](https://nixos.org/manual/nixpkgs/unstable/#var-stdenv-passthru). This reduces confusion for package users and allows for confident use of non-standard attributes provided by a package. It also gives package authors more confidence in modifying the builder environment without breaking consumers of their package, and it is slightly more efficient. |
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 really don't like the wording of this. It encourages people to just set cleanAttrs for all their packages, only to later get feedback from people that they need x, y, z back.
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.
How about this?
Passing [`__cleanAttrs = true`](https://nixos.org/manual/nixpkgs/unstable/#var-__cleanAttrs) to `mkDerivation` returns a minimal set of package attributes that can be extended via [`passthru`](https://nixos.org/manual/nixpkgs/unstable/#var-stdenv-passthru). This reduces confusion for package users and allows for confident use of non-standard attributes provided by a package. It also gives package authors more confidence in modifying the builder environment without breaking consumers of their package, and it is slightly more efficient. | |
Passing [`__cleanAttrs = true`](https://nixos.org/manual/nixpkgs/unstable/#var-__cleanAttrs) to `mkDerivation` returns a minimal set of package attributes that can be extended via [`passthru`](https://nixos.org/manual/nixpkgs/unstable/#var-stdenv-passthru). For new packages, this reduces confusion for package users and allows for confident use of non-standard attributes provided by a package. It also gives package authors more confidence in modifying the builder environment without breaking consumers of their package, and it is slightly more efficient. It may be applied to existing packages with great care, as other users may unknowingly rely on internals. To uncover such usages without breaking their code, you may first pass `__cleanAttrs = "warn"` instead. |
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.
That sounds better. 👍🏼
# We allow `hello.src` to be used in tests and examples, despite __cleanAttrs | ||
passthru.src = finalAttrs.src; |
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.
IMO src should always be passed through. eg you sometimes want to (re-)build it and as I understand it, that would after that no longer be possible which would suck.
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.
src
-> internals.src
should be fine for individual "override" packages you write.
There is no general way to get all sources in using just the expression language, so we don't lose the capability to generically retrieve all sources, because we never had that in the language. Simply put, not all packages have a src
, and not all sources appear in src
, and you can hide "anything" in a dependency of a derivation a string context.
This task is better achieved by analyzing the .drv
graph, you can find all the derivation input sources (file references and builtin fetcher results) and fixed output derivations. You may even do this from within a derivation.
You'll still be able to do this, by using attributes such as Also if you're very confident about your use case, you could just open a PR. It doesn't have to some sort of drawn out discussion.
What do you mean with reflections? I'm not in favor of such a global flag, because it is not necessary and it will make some expressions that do or do not use the flag incompatible. (Configuration should always be a last resort)
It'd be fine for It would be nicer if the language integrations and |
Totally forgot about that. 😓 Then this should be okay merge.
I think nix-update exactly was build out of that problem that no such general attribute existed. |
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'm a bit worried that people will start using __cleanAttrs = true
on existing packages, breaking a lot of things without warnings downstream (and for every user complaining about an attribute gone missing there's 10 more in the back that never reported it). We'd have to trust reviewers to not merge such changes. Better of course would be CI, but that adds a lot of complexity.
Other than that this looks pretty good to me, I like the salve mundi!
|
||
New packages may pass `__cleanAttrs = true;` to `mkDerivation`, so that it will return a minimal set of package attributes, which package authors can extend via [`passthru`](#var-stdenv-passthru). | ||
|
||
Existing packages may be modified to pass `__cleanAttrs = "warn";`, so that the legacy attributes remain available, but they will print a helpful warning when they are accessed. Doing this is best avoided until the packaging function used supports recursively defined arguments like [`mkDerivation` does](#mkderivation-recursive-attributes). |
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.
Doing this is best avoided until the packaging function used supports recursively defined arguments like
mkDerivation
does
Which packaging function?
# optional, but specified in our case | ||
"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.
I don't see why version
should get propagated here.
in | ||
|
||
lib.extendDerivation | ||
validity.handled | ||
({ | ||
( | ||
lib.optionalAttrs (__cleanAttrs != true) (maybeWarnCleanAttrs { |
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 removes inputDerivation
when __cleanAttrs == true
, I'm not sure if that makes sense, since .inputDerivation
is meant to be a public stable interface. While it might not be needed anymore since mkShell
is now buildable, I'm not sure if this should be decided here.
( | ||
( | ||
if __cleanAttrs == true | ||
then builtins.intersectAttrs { version = null; } drvAttrs |
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.
Why is version propagated? I guess it's somewhat important and stable enough. Should definitely be a comment here
restore-default-greeting = callPackage ./test.nix { | ||
hello = finalAttrs.finalPackage.overrideAttrs (o: { | ||
passthru = o.passthru // { | ||
greeting = null; | ||
}; | ||
}); | ||
}; |
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.
What's this for?
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.
not everyone speaks latin 😄
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.
That is a good point. It could come across as elitist, especially in this context now that I think about it more.
Something like Esperanto would be nicer, or Lojban, or Tolkien's Elvish. Or maybe it should just be hello_with_bells_and_whistles
, although I don't know if _
for variations should be followed by snake case or camelCase.
Why is this hard...
May the first confirmation win:
suilad-ambar
: is this a correct Elvish package name?coi-munje
: is this a correct Lojban package name?
I don't like the Esperanto version because it's basically Romance language vocabulary. Nothing wrong with that, but if it's not going to be English, I don't want to bias it. Sue me. ;)
@@ -362,6 +364,42 @@ Unless set to `false`, some build systems with good support for parallel buildin | |||
|
|||
### Special variables {#special-variables} | |||
|
|||
#### `__cleanAttrs` {#var-__cleanAttrs} | |||
|
|||
By default, `mkDerivation` will expose its arguments in the returned package attribute set. This is unnecessary and leads to some confusion and doubt. |
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.
By default, `mkDerivation` will expose its arguments in the returned package attribute set. This is unnecessary and leads to some confusion and doubt. | |
By default, `mkDerivation` will expose its arguments in the returned package attribute set. | |
This is often unnecessary and may lead to confusion about what's relevant for consumers. |
We should soften that a bit, because I don't see evidence for the originally definitive-sounding statement.
|
||
##### What to do when warned {#warning-package-attr-impl-detail} | ||
|
||
If you encounter the warning `The attribute ... of package ... is an implementation detail`, you are invited to help us explicitly support ways in which a package attribute set may used, so that Nixpkgs contributors and users will be aware of your use case. |
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 could be phrased to be more immediately actionable.
If you encounter the warning `The attribute ... of package ... is an implementation detail`, you are invited to help us explicitly support ways in which a package attribute set may used, so that Nixpkgs contributors and users will be aware of your use case. | |
If you encounter the warning `The attribute ... of package ... is an implementation detail`, please make Nixpkgs contributors and users aware of your particular use case, and help providing explicit ways to use package attribute sets, by opening an [issue](https://github.com/NixOS/nixpkgs/issues) or (https://github.com/NixOS/nixpkgs/pulls). |
This pull request has been mentioned on NixOS Discourse. There might be relevant details there: https://discourse.nixos.org/t/2023-05-16-nixpkgs-architecture-team-meeting-38/28223/1 |
This pull request has been mentioned on NixOS Discourse. There might be relevant details there: https://discourse.nixos.org/t/zurich-23-05-zhf-hackathon-and-workshop-report/29093/1 |
#271241 (comment) shows that access to values computed by Perhaps it'd be better to avoid cleanAttrs and instead move to a module-like situation, where the functions are flattened to a single fixed-point, and the attrsets are unflattened so that what used to be layers between the functions are just groups of attributes. mk2Derivation({ pythonAttrs, setup, drvAttrs, public }:
# Don't need to get stuff from four levels deep
# setup: the generic shell script from "stdenv"
setup.configureFlags = ... (optional drvAttrs.doCheck "--enable-tests") ...;
setup.doCheck = true; # like mkDerivation { doCheck } argument
# No more passthru. It's symmetric now.
public.tests = callPackage ./tests { mypkg = public; };
) Is the overlay pattern (with 1 layer of hardcoded merging) good enough for this, or do we need more module system-like features... |
How about removing the explicit call to { pythonAttrs, setup, drvAttrs, public }: {
__class = "mk2Derivation";
# Don't need to get stuff from four levels deep
# setup: the generic shell script from "stdenv"
setup.configureFlags = ... (optional drvAttrs.doCheck "--enable-tests") ...;
setup.doCheck = true; # like mkDerivation { doCheck } argument
# No more passthru. It's symmetric now.
public.tests = callPackage ./tests { mypkg = public; };
} That way it would be discoverable how to import this package and it feels like getting one step closer towards better integration with nixos modules. And of course, automatic merging of values would be nice, but maybe it's not a must for the start. I think this would already be a huge improvement over the current situation. |
Not merging those "top level" attributes, of which we have only few, will make any sort of overriding incredibly needlessly labor intensive, while gaining very little in flexibility or performance (if at all).
We already have Whether similarity - let alone compatibility - with the module system is a valid requirement remains to be seen, because we can not degrade performance by any significant amount, due to the scale of a typical package's dependency closure. |
This idea was good, but EDIT: last discussion may resume in #273815 |
Description of changes
What
Clean up the attribute zoo on packages, opt-in.
Why
Automatically exposing internals blurs the line between what's expected to be stable and what's not. Let's not do that.
How
Call
derivationStrict
instead ofderivation
.derivation
is backed byderivationStrict
anyway.When you specify
__cleanAttrs = true;
in amkDerivation
call, you won't be exposing internals.What else
This PR improves memory by some 1-2% and cpu time also improves.
Internals are still accessible via
overrideAttrs
,lib.inspectMkDerivationArgs
andpkgs.inputDerivation
.This relates weakly to a proposed improvement to make Nix take outputs from package attrsets instead of store derivations, as both this PR and the proposal work towards a more accurate as an expression-level package concept.
Things done
sandbox = true
set innix.conf
? (See Nix manual)nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD"
. Note: all changes have to be committed, also see nixpkgs-review usage./result/bin/
)