Unverified Commit 38ccab2e authored by Silvan Mosberger's avatar Silvan Mosberger Committed by GitHub
Browse files

Full treewide Nix format and enforcement [skip treewide] (#380990)

parents 95dd26b1 49cf5474
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -248,3 +248,6 @@ da9a092c34cef6947d7aee2b134f61df45171631
# python-packages: sort with keep-sorted
fd14c067813572afc03ddbf7cdedc3eab5a59954
783add849cbca228a36ffdf407e5d380dc2fe6c4

# treewide format of all Nix files
374e6bcc403e02a35e07b650463c01a52b13a7c8 # !autorebase nix-shell --run treefmt
+13 −69
Original line number Diff line number Diff line
# This file was copied mostly from check-maintainers-sorted.yaml.
# NOTE: Formatting with the RFC-style nixfmt command is not yet stable. See
# https://github.com/NixOS/rfcs/pull/166.
# Because of this, this action is not yet enabled for all files -- only for
# those who have opted in.
# NOTE: Formatting with the RFC-style nixfmt command is not yet stable.
# See https://github.com/NixOS/rfcs/pull/166.

name: Check that Nix files are formatted

@@ -20,80 +17,27 @@ jobs:
    name: nixfmt-check
    runs-on: ubuntu-24.04
    needs: get-merge-commit
    if: "needs.get-merge-commit.outputs.mergedSha && !contains(github.event.pull_request.title, '[skip treewide]')"
    if: needs.get-merge-commit.outputs.mergedSha
    steps:
      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
        with:
          ref: ${{ needs.get-merge-commit.outputs.mergedSha }}
          # Fetches the merge commit and its parents
          fetch-depth: 2

      - name: Checking out target branch
        run: |
          target=$(mktemp -d)
          targetRev=$(git rev-parse HEAD^1)
          git worktree add "$target" "$targetRev"
          echo "targetRev=$targetRev" >> "$GITHUB_ENV"
          echo "target=$target" >> "$GITHUB_ENV"

      - name: Get Nixpkgs revision for nixfmt
        run: |
          # pin to a commit from nixpkgs-unstable to avoid e.g. building nixfmt
          # from staging
          # This should not be a URL, because it would allow PRs to run arbitrary code in CI!
          rev=$(jq -r .rev ci/pinned-nixpkgs.json)
          echo "url=https://github.com/NixOS/nixpkgs/archive/$rev.tar.gz" >> "$GITHUB_ENV"

      - uses: cachix/install-nix-action@02a151ada4993995686f9ed4f1be7cfbb229e56f # v31
        with:
          extra_nix_config: sandbox = true
          nix_path: nixpkgs=${{ env.url }}

      - name: Install nixfmt
        run: "nix-env -f '<nixpkgs>' -iAP nixfmt-rfc-style"

      - name: Check that Nix files are formatted according to the RFC style
      - name: Check that Nix files are formatted
        run: |
          unformattedFiles=()

          # TODO: Make this more parallel

          # Loop through all Nix files touched by the PR
          while readarray -d '' -n 2 entry && (( ${#entry[@]} != 0 )); do
            type=${entry[0]}
            file=${entry[1]}
            case $type in
              A*)
                source=""
                dest=$file
                ;;
              M*)
                source=$file
                dest=$file
                ;;
              C*|R*)
                source=$file
                read -r -d '' dest
                ;;
              *)
                echo "Ignoring file $file with type $type"
                continue
            esac

            # Ignore files that weren't already formatted
            if [[ -n "$source" ]] && ! nixfmt --check ${{ env.target }}/"$source" 2>/dev/null; then
              echo "Ignoring file $file because it's not formatted in the target commit"
            elif ! nixfmt --check "$dest"; then
              unformattedFiles+=("$dest")
            fi
          done < <(git diff -z --name-status ${{ env.targetRev }} -- '*.nix')

          if (( "${#unformattedFiles[@]}" > 0 )); then
            echo "Some new/changed Nix files are not properly formatted"
            echo "Please format them using the Nixpkgs-specific \`nixfmt\` by going to the Nixpkgs root directory, running \`nix-shell\`, then:"
            echo
            echo "nixfmt ${unformattedFiles[*]@Q}"
            echo
          # Note that it's fine to run this on untrusted code because:
          # - There's no secrets accessible here
          # - The build is sandboxed
          if ! nix-build ci -A fmt.check; then
            echo "Some Nix files are not properly formatted"
            echo "Please format them by going to the Nixpkgs root directory and running one of:"
            echo "  nix-shell --run treefmt"
            echo "  nix develop --command treefmt"
            echo "  nix fmt"
            echo "Make sure your branch is up to date with master; rebase if not."
            echo "If you're having trouble, please ping @NixOS/nix-formatting"
            exit 1
+19 −2
Original line number Diff line number Diff line
@@ -531,14 +531,31 @@ If you removed packages or made some major NixOS changes, write about it in the

Names of files and directories should be in lowercase, with dashes between words — not in camel case. For instance, it should be `all-packages.nix`, not `allPackages.nix` or `AllPackages.nix`.

### Formatting

CI [enforces](./.github/workflows/check-nix-format.yml) all Nix files to be
formatted using the [official Nix formatter](https://github.com/NixOS/nixfmt).

You can ensure this locally using either of these commands:
```
nix-shell --run treefmt
nix develop --command treefmt
nix fmt
```

If you're starting your editor in `nix-shell` or `nix develop`,
you can also set it up to automatically format the file with `treefmt` on save.

If you have any problems with formatting, please ping the
[formatting team](https://nixos.org/community/teams/formatting/) via
[@NixOS/nix-formatting](https://github.com/orgs/NixOS/teams/nix-formatting).

### Syntax

- Set up [editorconfig](https://editorconfig.org/) for your editor, such that [the settings](./.editorconfig) are automatically applied.

- Use `lowerCamelCase` for variable names, not `UpperCamelCase`. Note, this rule does not apply to package attribute names, which instead follow the rules in [package naming](./pkgs/README.md#package-naming).

- New files must be formatted by entering the `nix-shell` from the repository root and running `nixfmt`.

- Functions should list their expected arguments as precisely as possible. That is, write

  ```nix
+44 −1
Original line number Diff line number Diff line
@@ -21,9 +21,52 @@ let
    config = { };
    overlays = [ ];
  };

  fmt =
    let
      treefmtNixSrc = fetchTarball {
        # Master at 2025-02-12
        url = "https://github.com/numtide/treefmt-nix/archive/4f09b473c936d41582dd744e19f34ec27592c5fd.tar.gz";
        sha256 = "051vh6raskrxw5k6jncm8zbk9fhbzgm1gxpq9gm5xw1b6wgbgcna";
      };
      treefmtEval = (import treefmtNixSrc).evalModule pkgs {
        # Important: The auto-rebase script uses `git filter-branch --tree-filter`,
        # which creates trees within the Git repository under `.git-rewrite/t`,
        # notably without having a `.git` themselves.
        # So if this projectRootFile were the default `.git/config`,
        # having the auto-rebase script use treefmt on such a tree would make it
        # format all files in the _parent_ Git tree as well.
        projectRootFile = ".git-blame-ignore-revs";

        # Be a bit more verbose by default, so we can see progress happening
        settings.verbose = 1;

        # By default it's info, which is too noisy since we have many unmatched files
        settings.on-unmatched = "debug";

        # This uses nixfmt-rfc-style underneath,
        # the default formatter for Nix code.
        # See https://github.com/NixOS/nixfmt
        programs.nixfmt.enable = true;
      };
      fs = pkgs.lib.fileset;
      nixFilesSrc = fs.toSource {
        root = ../.;
        fileset = fs.difference (fs.unions [
          (fs.fileFilter (file: file.hasExt "nix") ../.)
          ../.git-blame-ignore-revs
        ]) (fs.maybeMissing ../.git);
      };
    in
    {
      shell = treefmtEval.config.build.devShell;
      pkg = treefmtEval.config.build.wrapper;
      check = treefmtEval.config.build.check nixFilesSrc;
    };

in
{
  inherit pkgs;
  inherit pkgs fmt;
  requestReviews = pkgs.callPackage ./request-reviews { };
  codeownersValidator = pkgs.callPackage ./codeowners-validator { };
  eval = pkgs.callPackage ./eval { };
+139 −100
Original line number Diff line number Diff line
@@ -3,17 +3,21 @@
{
  description = "A collection of packages for the Nix package manager";

  outputs = { self }:
  outputs =
    { self }:
    let
      libVersionInfoOverlay = import ./lib/flake-version-info.nix self;
      lib = (import ./lib).extend libVersionInfoOverlay;

      forAllSystems = lib.genAttrs lib.systems.flakeExposed;

      jobs = forAllSystems (system: import ./pkgs/top-level/release.nix {
      jobs = forAllSystems (
        system:
        import ./pkgs/top-level/release.nix {
          nixpkgs = self;
          inherit system;
      });
        }
      );
    in
    {
      /**
@@ -26,7 +30,8 @@
      */
      # DON'T USE lib.extend TO ADD NEW FUNCTIONALITY.
      # THIS WAS A MISTAKE. See the warning in lib/default.nix.
      lib = lib.extend (final: prev: {
      lib = lib.extend (
        final: prev: {

          /**
            Other NixOS-provided functionality, such as [`runTest`](https://nixos.org/manual/nixos/unstable/#sec-call-nixos-test-outside-nixos).
@@ -56,7 +61,8 @@
            - `system`: Legacy alias for `nixpkgs.hostPlatform`, but this is already set in the generated `hardware-configuration.nix`, included by `configuration.nix`.
            - `pkgs`: Legacy alias for `nixpkgs.pkgs`; use `nixpkgs.pkgs` and `nixosModules.readOnlyPkgs` instead.
          */
        nixosSystem = args:
          nixosSystem =
            args:
            import ./nixos/lib/eval-config.nix (
              {
                lib = final;
@@ -72,17 +78,31 @@
                  #
                  # See: failed attempt to make pkgs.path not copy when using flakes:
                  # https://github.com/NixOS/nixpkgs/pull/153594#issuecomment-1023287913
                ({ config, pkgs, lib, ... }: {
                  (
                    {
                      config,
                      pkgs,
                      lib,
                      ...
                    }:
                    {
                      config.nixpkgs.flake.source = self.outPath;
                })
                    }
                  )
                ];
            } // builtins.removeAttrs args [ "modules" ]
              }
              // builtins.removeAttrs args [ "modules" ]
            );
        }
      );
      });

      checks = forAllSystems (system: {
      checks = forAllSystems (
        system:
        {
          tarball = jobs.${system}.tarball;
      } // lib.optionalAttrs
        }
        //
          lib.optionalAttrs
            (
              self.legacyPackages.${system}.stdenv.hostPlatform.isLinux
              # Exclude power64 due to "libressl is not available on the requested hostPlatform" with hostPlatform being power64
@@ -92,34 +112,45 @@
              # Test that ensures that the nixosSystem function can accept a lib argument
              # Note: prefer not to extend or modify `lib`, especially if you want to share reusable modules
              #       alternatives include: `import` a file, or put a custom library in an option or in `_module.args.<libname>`
        nixosSystemAcceptsLib = (self.lib.nixosSystem {
              nixosSystemAcceptsLib =
                (self.lib.nixosSystem {
                  pkgs = self.legacyPackages.${system};
          lib = self.lib.extend (final: prev: {
                  lib = self.lib.extend (
                    final: prev: {
                      ifThisFunctionIsMissingTheTestFails = final.id;
          });
                    }
                  );
                  modules = [
                    ./nixos/modules/profiles/minimal.nix
            ({ lib, ... }: lib.ifThisFunctionIsMissingTheTestFails {
                    (
                      { lib, ... }:
                      lib.ifThisFunctionIsMissingTheTestFails {
                        # Define a minimal config without eval warnings
                        nixpkgs.hostPlatform = "x86_64-linux";
                        boot.loader.grub.enable = false;
                        fileSystems."/".device = "nodev";
                        # See https://search.nixos.org/options?show=system.stateVersion&query=stateversion
                        system.stateVersion = lib.trivial.release; # DON'T do this in real configs!
            })
                      }
                    )
                  ];
                }).config.system.build.toplevel;
      });
            }
      );

      htmlDocs = {
        nixpkgsManual = builtins.mapAttrs (_: jobSet: jobSet.manual) jobs;
        nixosManual = (import ./nixos/release-small.nix {
        nixosManual =
          (import ./nixos/release-small.nix {
            nixpkgs = self;
          }).nixos.manual;
      };

      devShells = forAllSystems (system:
        { } // lib.optionalAttrs
      devShells = forAllSystems (
        system:
        { }
        //
          lib.optionalAttrs
            (
              # Exclude armv6l-linux because "Package ‘ghc-9.6.6’ in .../pkgs/development/compilers/ghc/common-hadrian.nix:579 is not available on the requested hostPlatform"
              system != "armv6l-linux"
@@ -129,9 +160,14 @@
              && !self.legacyPackages.${system}.stdenv.hostPlatform.isFreeBSD
            )
            {
          /** A shell to get tooling for Nixpkgs development. See nixpkgs/shell.nix. */
              /**
                A shell to get tooling for Nixpkgs development. See nixpkgs/shell.nix.
              */
              default = import ./shell.nix { inherit system; };
        });
            }
      );

      formatter = forAllSystems (system: (import ./ci { inherit system; }).fmt.pkg);

      /**
        A nested structure of [packages](https://nix.dev/manual/nix/latest/glossary#package-attribute-set) and other values.
@@ -152,10 +188,13 @@
        evaluation. Evaluating the attribute value tends to require a significant
        amount of computation, even considering lazy evaluation.
      */
      legacyPackages = forAllSystems (system:
        (import ./. { inherit system; }).extend (final: prev: {
      legacyPackages = forAllSystems (
        system:
        (import ./. { inherit system; }).extend (
          final: prev: {
            lib = prev.lib.extend libVersionInfoOverlay;
        })
          }
        )
      );

      /**
Loading