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

Treewide Nix reformat pass 1 [skip treewide] #322537

Merged
merged 2 commits into from
Dec 10, 2024

Conversation

infinisil
Copy link
Member

@infinisil infinisil commented Jun 26, 2024

This is the next step towards accepted NixOS/rfcs#166 after #322512 and #326407, see also #322520 and NixOS/nixfmt#153 🎉.

After final improvements to the official formatter implementation, this commit now performs the first treewide reformat of Nix files using it. This is part of the implementation of NixOS/rfcs#166.

Only "inactive" files are reformatted, meaning only files that aren't being touched by any PR with activity in the past 2 months. This is to avoid conflicts for PRs that might soon be merged. Later we can do a full treewide reformat to get the rest, which should not cause as many conflicts.

A CI check has already been running for some time to ensure that new and already-formatted files are formatted, so the files being reformatted here should also stay formatted.

The @NixOS/nix-formatting will approve/merge this PR.

Verification

The reformatting commit is fully auto-generated by the code in https://github.com/infinisil/treewide-nixpkgs-reformat-script, see the commit message on how to do a complete verification.

Things done


This work is sponsored by Antithesis

Add a 👍 reaction to pull requests you find important.

@infinisil infinisil mentioned this pull request Jun 26, 2024
7 tasks
@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/formatting-team-meeting-2024-06-25/47661/1

@infinisil infinisil added the significant Novel ideas, large API changes, notable refactorings, issues with RFC potential, etc. label Jun 26, 2024
@oxalica
Copy link
Contributor

oxalica commented Jun 28, 2024

I'd say we should block on NixOS/nixfmt#153. There are also many issues about either awkward formatting result or implementation correctness. It's no good to race reformatting everything before that.

This was done with this script in ~40 seconds

This sounds too long to me. If the whole-repo checking takes too long, it blocks auto-checking in git commit hook.
fd -e nix --exec-batch nixfmt takes 1:49.27 (~110s) on my machine and nixfmt is single-threaded. nixfmt --check on formatted files takes almost the same time.

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/tweag-nix-dev-update-57/47823/1

@infinisil
Copy link
Member Author

@oxalica The reason I'm pushing for this is because there's a lot of churn from people reformatting individual parts on their own, @mweinelt can attest to that. Let's not let perfect be the enemy of good, the formatter works and is unlikely to change drastically. We should definitely block on correctness bugs like NixOS/nixfmt#197 though, this is being worked on :)

Regarding the time it takes for a full format, the solution I'd propose is to use a pre-commit hook that only formats files that were changed. This also nicely aligns with CI only requiring changed files to be formatted. I'd be okay with blocking on that for this PR, I'll add it to the TODO items.

In addition to that, if CI fails, it shows the nixfmt command needed to make CI pass, only listing the files that need reformatting, see here.

Alternative: treefmt

One could also imagine using treefmt because it caches results, but this will be slightly problematic when we change the formatter in the future and need to do the same multi-pass approach to avoid merge conflicts. There's going to be times when not the entire codebase is formatted in the same way, and treefmt would mess that up.

@oxalica
Copy link
Contributor

oxalica commented Jun 28, 2024

use a pre-commit hook that only formats files that were changed

That's kinda non-trivial to me, and you need to retrieve file list from git log on an unknown number of commits. Would be good to have an example (maybe in README) for copy-paste.

Also I opened NixOS/nixfmt#211 for tracking this.

@infinisil
Copy link
Member Author

That's kinda non-trivial to me, and you need to retrieve file list from git log on an unknown number of commits. Would be good to have an example (maybe in README) for copy-paste.

Since it's the pre-commit hook, we only have to worry about the single commit that is being made, so I don't think it will be bad, but I'll see it when I try 😆. And we can use a shellHook automatically pre-commit hooks upon entering the shell, e.g. https://github.com/cachix/git-hooks.nix also works in that way.

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/brainstorming-for-rfc-assimilate-home-manager-into-nixpkgs-monorepo/48230/13

@Aleksanaa
Copy link
Member

I'd say we should block on NixOS/nixfmt#153. There are also many issues about either awkward formatting result or implementation correctness. It's no good to race reformatting everything before that.

The good thing here is we can skip formatting if something weird really happens, because it doesn't make subsequent CI check fail.

@Pandapip1 Pandapip1 added the 2.status: merge conflict This PR has merge conflicts with the target branch label Jul 4, 2024
@emilazy
Copy link
Member

emilazy commented Jul 8, 2024

I’d like to recommend a pre-push hook instead of a pre-commit one. It would still check all the commits that are to be pushed. The advantage is that it is easier to slice and dice existing commits and make imperfect work‐in‐progress commits to clean up later without having the formatting step get in the way. It also prevents making committing any slower, whereas pushes are already slow. For me, the experience of using a pre-commit hook is like having to satisfy a pedantic spell‐checker while trying to get into a flow state writing a stream‐of‐consciousness draft.

Another advantage is that tools like git-revise cannot necessarily run hooks due to their in‐memory design, which wouldn’t affect a pre-push hook; it’s more reliable to do the checks at the actual publication bottleneck.

If you need any help writing an efficient and correct Git hook for this, please ping me.

@infinisil infinisil force-pushed the enforce-nixfmt-changed-files branch from a22dc49 to a826121 Compare July 11, 2024 23:44
@ofborg ofborg bot removed the 2.status: merge conflict This PR has merge conflicts with the target branch label Jul 11, 2024
@infinisil infinisil force-pushed the enforce-nixfmt-changed-files branch 2 times, most recently from 174e6e4 to 00d4895 Compare July 12, 2024 00:09
@ofborg ofborg bot added 10.rebuild-darwin: 0 This PR does not cause any packages to rebuild on Darwin 10.rebuild-linux: 0 This PR does not cause any packages to rebuild on Linux labels Jul 12, 2024
@infinisil infinisil changed the title Enforce nixfmt for new/changed files, treewide reformat pass 1 [skip treewide] Treewide Nix reformat pass 1 [skip treewide] Jul 12, 2024
@infinisil
Copy link
Member Author

To make this PR easier to review, I split off the enforcement for new files into #326407. So this PR is only for the treewide format now! Also note:

  • I added instructions to the PR description on how the entire contents of this PR can be reproduced, allowing anybody to easily check it
  • Some nixfmt fixes should be merged and propagated before this is merged, see the PR description

After final improvements to the official formatter implementation,
this commit now performs the first treewide reformat of Nix files using it.
This is part of the implementation of RFC 166.

Only "inactive" files are reformatted, meaning only files that
aren't being touched by any PR with activity in the past 2 months.
This is to avoid conflicts for PRs that might soon be merged.
Later we can do a full treewide reformat to get the rest,
which should not cause as many conflicts.

A CI check has already been running for some time to ensure that new and
already-formatted files are formatted, so the files being reformatted here
should also stay formatted.

This commit was automatically created and can be verified using

    nix-build https://github.com/infinisil/treewide-nixpkgs-reformat-script/archive/a08b3a4d199c6124ac5b36a889d9099b4383463f.tar.gz \
      --argstr baseRev b32a094
    result/bin/apply-formatting $NIXPKGS_PATH
@infinisil infinisil force-pushed the enforce-nixfmt-changed-files branch from ff8b477 to 4f0dadb Compare December 10, 2024 19:26
@nix-owners nix-owners bot requested a review from edwtjo December 10, 2024 19:30
…ng{,-next}

By committing all of these together on master, we don't need to deal
with a merge conflict of this file once staging/staging-next is merged together.
@infinisil
Copy link
Member Author

I walked through the methodology of this work with ~12 people in the merge party call, no complaints, merging! 🎉

@infinisil infinisil merged commit 989acfe into NixOS:master Dec 10, 2024
23 of 24 checks passed
@infinisil infinisil deleted the enforce-nixfmt-changed-files branch December 10, 2024 19:50
infinisil added a commit to tweag/nixpkgs that referenced this pull request Dec 10, 2024
…next

The "reformat everything on master/staging/staging-next together"
approach from NixOS#322537 didn't quite
work out: master now can't be automatically merged into staging-next
anymore (same for staging-next into staging).

To resolve this, we're performing two merges:
- This first one to merge the commit on master just before the treewide
  reformat into staging-next
- The following one to merge the treewide reformat commit into
  staging-next, but effectively ignoring all changes from the treewide
  reformat commit
infinisil added a commit to tweag/nixpkgs that referenced this pull request Dec 10, 2024
…next

The "reformat everything on master/staging/staging-next together"
approach from NixOS#322537 didn't quite
work out: master now can't be automatically merged into staging-next
anymore (same for staging-next into staging).

To resolve this, we're performing two merges:
- The first one (see parent commit) to merge the commit on master just before the treewide
  reformat into staging-next
- This one to merge the treewide reformat commit into
  staging-next, but effectively ignoring all changes from the treewide
  reformat commit using `-X ours` when merging (and manually handling
  the few edge cases)
@infinisil
Copy link
Member Author

Turns out the "reformat everything on master/staging/staging-next together" approach didn't quite work out: master couldn't be automatically merged into staging-next anymore (same for staging-next into staging). Thanks to @wegank for taking care of fixing that by manually doing the staging merge!

@mightyiam
Copy link
Member

Thanks to the works of inspired, motivated and provided individuals, we can has nice things! Thanks, everyone involved!

@trofi
Copy link
Contributor

trofi commented Dec 11, 2024

I have about 350 local patches against nixpkgs. Most of them are conflicting now. Is there a standard way to automatically rebase most of them with formatting applied? Or I'll have to hack up something locally?

@arianvp
Copy link
Member

arianvp commented Dec 11, 2024

There's this which might help: #363759

@Pandapip1
Copy link
Contributor

Pandapip1 commented Dec 11, 2024

I have about 350 local patches against nixpkgs. Most of them are conflicting now. Is there a standard way to automatically rebase most of them with formatting applied? Or I'll have to hack up something locally?

If these are generally applicable patch sets, can I suggest that they be sent to nixpkgs? This could have been avoided that way:

Only "inactive" files are reformatted, meaning only files that aren't being touched by any PR with activity in the past 2 months. This is to avoid conflicts for PRs that might soon be merged. Later we can do a full treewide reformat to get the rest, which should not cause as many conflicts.

@trofi
Copy link
Contributor

trofi commented Dec 11, 2024

Is there a standard way to automatically rebase most of them with formatting applied?

Ended up doing the following:

# 1. Create empty commit:
git commit --allow-empty -m "EMPTY commit: will absorb relevant formatting changes"

# 2. Move the empty commit to queue beginning:
git rebase -i --keep-base
# Move "EMPTY commit: will absorb relevant formatting changes" entry from last line to the first line.

# 3. Get affected formatted files. Pick the commit from `.git-blame-ignore-revs` for the relevant branch. For `staging` it is `667d42c00d566e091e6b9a19b365099315d0e611`
FORMATTED_FILES=$(git diff --name-only 667d42c00d566e091e6b9a19b365099315d0e611^..667d42c00d566e091e6b9a19b365099315d0e611 -- $(git diff --name-only origin/staging...staging) | tr $'\n' ' ')`

# 4. Reformat:
FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch --tree-filter "nixfmt $FORMATTED_FILES" -- $(git merge-base origin/staging staging)..
   ...
   Rewrite 6fc0a951e9b7a7e3f80628ca0a6c4c9f54fd2dd6 (56/327) (65 seconds passed, remaining 314 predicted)
   ...
   Rewrite c20df82da66da6521f355af508bfedc047cffa64 (326/326) (1183 seconds passed, remaining 0 predicted)
   Ref 'refs/heads/staging' was rewritten

# 5. Rebase past the reformat (as one would normally do the update):
git rebase -i

# Done

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2.status: merge conflict This PR has merge conflicts with the target branch 10.rebuild-darwin: 11-100 10.rebuild-linux: 11-100 significant Novel ideas, large API changes, notable refactorings, issues with RFC potential, etc.
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.