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

Prevent some rebuilds for future Nix reformats #326430

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

infinisil
Copy link
Member

@infinisil infinisil commented Jul 12, 2024

Description of changes

This is motivated by #322537, which I'd like to get close to 0 rebuilds, although due to the nature of that PR not formatting files modified by other PRs, me making this PR makes the other PR avoid these files entirely, so this PR doesn't have to be merged before the other one.

This PR either avoids Nix files ending up in the build result (so that changing them won't cause rebuilds), or formats Nix files in advance, so that they don't need to be changed in the treewide reformat.

This is effectively part of #301014

Things done

  • Built all the changed derivations

This work is sponsored by Antithesis

Add a 👍 reaction to pull requests you find important.

This is a rare case of a Nix file actually ending up in the build result.
We reformat this now, causing a rebuild, so that we won't cause a rebuild
in the treewide reformatting PR.
@Atemu
Copy link
Member

Atemu commented Jul 12, 2024

or formats Nix files in advance, so that they don't need to be changed in the treewide reformat.

This doesn't strike me as a great solution tbh. It just kicks the bucket down the road and will cause rebuilds again when the formatting rules are changed again in the future.

@sternenseemann
Copy link
Member

The cabalSdist test can be made to not depend on the formatting of the generated Nix file by using haskell.lib.compose.overrideSrc at the call site to use a filtered source. If this filtered source is also passed correctly to the other derivation that uses it (near the call site of generated.nix), all should be fine.

See #320572, #321246.

This is a rare case of a Nix file actually ending up in the build result.
We reformat this now, causing a rebuild, so that we won't cause a rebuild
in the treewide reformatting PR.
There's no need to use a Nix file in the path here. By using a different
file we won't cause rebuilds when we change the Nix file, in particular
also when the Nix file is reformatted.
The source included way more files than it really needed.
This commit limits it to exactly those it needs.

This also makes sure that no rebuild is necessary when any Nix
file changes, in particular useful when we reformat the Nix files.
The generated file sets its own directory as the source, including the
generated file itself, which causes rebuilds when that file is
reformatted. We can avoid this by overriding the source with a filtered
version and using that throughout the tests.

See NixOS#320572 for more context
@infinisil
Copy link
Member Author

This doesn't strike me as a great solution tbh. It just kicks the bucket down the road and will cause rebuilds again when the formatting rules are changed again in the future.

Speaking for the formatting team, we don't expect to have to make any significant changes to the format in the foreseeable future. The only changes to expect soon are bug fixes, which won't change much. So I don't think we need to worry very much about it :)

@sternenseemann Thanks, done that in the last commit now!

Copy link
Contributor

@philiptaron philiptaron left a comment

Choose a reason for hiding this comment

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

A few curious comments.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sigh, this is on my list of #208242 things to go make better.

Comment on lines +18 to +25
source=${lib.fileset.toSource {
root = ./.;
fileset = lib.fileset.unions [
(./. + "/${testname}.cmdline")
(./. + "/${testname}.c")
(lib.fileset.maybeMissing (./. + "/${testname}.env"))
];
}}
Copy link
Contributor

Choose a reason for hiding this comment

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

This would be clearer if extracted to another binding.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think this is fine, I don't think much is gained from having an intermediate Nix binding (we already assign it to a bash variable here)

Comment on lines +4 to +15
src = lib.fileset.toSource {
root = ./local;
fileset = lib.fileset.unions [
./local/app
./local/CHANGELOG.md
./local/local.cabal
];
};
# This prevents the source from depending on the formatting of the ./local/generated.nix file
localRaw = haskell.lib.compose.overrideSrc {
inherit src;
} (haskellPackages.callPackage ./local/generated.nix {});
Copy link
Contributor

Choose a reason for hiding this comment

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

Having the src = ./. line in local/generated.nix is not needed now, right? It can be the same as the src above?

Copy link
Member Author

Choose a reason for hiding this comment

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

Since that's technically a generated file, I think it's cleaner to override the source from here instead

Copy link
Contributor

Choose a reason for hiding this comment

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

It's named as such but is in no way generated.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm pretty sure it was generated using cabal2nix, e.g. check see here, but I guess that's not very relevant at this point anyways

@0x4A6F
Copy link
Member

0x4A6F commented Jul 15, 2024

Please also tag @NixOS/nix-formatting for PRs touching that topic.

And fix locations to not break the test.
This is a rare case where another change is required after formatting.
We do this in a separate commit so that we don't need to do it in the
treewide reformatting PR.
@infinisil infinisil requested a review from roberth as a code owner July 16, 2024 17:10
@github-actions github-actions bot added 6.topic: module system About "NixOS" module system internals 6.topic: lib The Nixpkgs function library labels Jul 16, 2024
Copy link
Member

@roberth roberth left a comment

Choose a reason for hiding this comment

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

Not happy about the formatting at all, but I don't want to block the process of implementing formatting, because that would be even worse.
👍 from me.

Comment on lines +12 to +15
&& lib.hasAttrByPath [
"src"
"outputHash"
] value;
Copy link
Member

Choose a reason for hiding this comment

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

As a nixpkgs-fmt user this feels ugly.
I wonder if this would be ok? I think it's cleaner to use the built-in syntax anyway.

Suggested change
&& lib.hasAttrByPath [
"src"
"outputHash"
] value;
&& (value?src.outputHash);

Copy link
Member Author

Choose a reason for hiding this comment

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

Indeed this can be simplified and reformatted to just

  hasChecksum = value: value ? src.outputHash;

Relevant motto from the RFC:

Bad code does not deserve good formatting.

😆

options.nested.nestedLine30 = lib.mkOption {
type = lib.types.int;
};
options.nested.nestedLine30 = lib.mkOption { type = lib.types.int; };
Copy link
Member

Choose a reason for hiding this comment

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

I like my mkOptions multi-line, consistently.
Will I have to adjust?

Copy link
Member Author

@infinisil infinisil Jul 17, 2024

Choose a reason for hiding this comment

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

Oh this is actually an inconsistency in the formatter that should be fixed, because

  options.nested.nestedLine30 = { type = lib.types.int; };

expands to

  options.nested.nestedLine30 = {
    type = lib.types.int;
  };

The same should be done here.

See also this part of the standard

Edit: NixOS/nixfmt#222

Copy link
Member Author

@infinisil infinisil Jul 17, 2024

Choose a reason for hiding this comment

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

Though this is actually less prevalent in practice than it looks like here, because as soon as you have at least two attribute values, it will also get expanded. And effectively all options in NixOS have both a type and a description, which makes two.

Copy link
Member

Choose a reason for hiding this comment

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

I figured it might not be as bad.

Sometimes I start out with only a description or only a type if it's more "technical" like testing or trying something out.
I do anticipate the other attrs, which is why this stood out to me.

''
pkgs = import <nixpkgs> { };
in
pkgs.runCommand "diagnostics-sandbox" { __noChroot = true; } ''
Copy link
Member

Choose a reason for hiding this comment

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

Do we really need to collapse this attrset into a single line format?
This will add a bunch of diff noise when new attrset are added, won't it?

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not sure if we'll go for that in the end, but with NixOS/nixfmt#222 (which also fixes your other complaint), this file would look like this instead:

let
  pkgs = import <nixpkgs> { };
in
pkgs.runCommand "diagnostics-sandbox"
  {
    __noChroot = true;
  }
  ''
    set -x
    # no cache: ${toString builtins.currentTime}
    test -d "$(dirname "$out")/../var/nix"
    touch $out
  ''

@infinisil
Copy link
Member Author

@roberth Even if the formatting isn't perfect, having a standard enforced formatting is better than the current churn. Considering that these cases you highlighted are somewhat rare, I don't think we need to block on this. We can also improve the formatter and then do another reformatting pass later (which will then be much smaller in diff size!). If you have more feedback about the formatting, it would be best to open issues in https://github.com/NixOS/nixfmt instead btw :)

@roberth
Copy link
Member

roberth commented Jul 17, 2024

Even if the formatting isn't perfect, having a standard enforced formatting is better

As you've read, I agreed with this part.
However, considering that this aspect of the formatter is still subject to change, it seems that you have the priority inversed:

than the current churn.

Unnecessary formatter-induced churn is not ok. If the formatter doesn't behave correctly, or some aspects of it are still in development, don't both users with it.
I'm glad we've found this issue early, so that we can resolve it before bothering others with bad layouts and unnecessary churn.

I don't think we need to block on this.

So I think we should block on this, fix the formatter, and do another pass.

Considering that these cases you highlighted are somewhat rare

I assume you haven't run nixfmt on the whole repo.
There's two of them in this small PR, and I would expect more runCommand calls to be affected, because often it's just a single nativeBuildInputs for simple tests.
But you're right, we should be doing more testing ;)

@infinisil
Copy link
Member Author

If the formatter doesn't behave correctly, or some aspects of it are still in development

I'd say we should distinguish between different levels of correctness:

  1. Semantic correctness: That the AST isn't changed and that the formatter is idempotent. We have this verified on all Nixpkgs files since recently (and more recently also with nix-instantiate --parse).
  2. Standard matching: That the formatter adheres to the established standard. This can be very fuzzy in certain edge cases, but as we progressed at establishing the initial standard in [RFC 0166] Nix formatting, take two rfcs#166, @piegamesde did a great job keeping the implementation to match decently closely.
  3. Standard correctness: That the standard doesn't have any inconsistencies in itself. We also tried this during RFC development.

So we have 1 now but probably not 2 or 3. These can arguably never be perfect and take more brainpower to resolve, so it's important to consider the cost/value tradeoff. (And in a twisted way, forcing something imperfect onto people might actually get us more help with improving it :P).

But okay, let's reconsider this and either improve this case or have a better justification for not needing to improve it now.

I assume you haven't run nixfmt on the whole repo.

Complete opposite! We've been automatically running nixfmt on the entirety of Nixpkgs already during development of the RFC to help us decide (e.g. see here), and we're continuing to run it on all PRs that change nixfmt (e.g. see here), and of course there's also the treewide reformatting PR that is being worked on recently 😉

@roberth
Copy link
Member

roberth commented Jul 17, 2024

I assume you haven't run nixfmt on the whole repo.

Complete opposite!

Ah sorry, I was unclear. I meant to refer to this PR specifically, which I conclude is not tree-wide.

doesn't behave correctly

Oh, that was a bit harsh maybe, out of context at least. I meant to refer to your judgement that this may not be the desired behavior.

Anyway, I think we're on the same page now, and I'd really like to thank you for the effort you're putting into this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Todo
Development

Successfully merging this pull request may close these issues.

None yet

7 participants