diff --git a/flake.nix b/flake.nix index e25fe6a6f..0f79d7769 100644 --- a/flake.nix +++ b/flake.nix @@ -27,6 +27,7 @@ } ++ [ ({ lib, ... }: { nixpkgs.source = lib.mkDefault nixpkgs; + nixpkgs.flake.source = lib.mkDefault nixpkgs; system.checks.verifyNixPath = lib.mkDefault false; diff --git a/modules/module-list.nix b/modules/module-list.nix index 0b62158a8..48880f073 100644 --- a/modules/module-list.nix +++ b/modules/module-list.nix @@ -47,6 +47,7 @@ ./nix/linux-builder.nix ./nix/nix-darwin.nix ./nix/nixpkgs.nix + ./nix/nixpkgs-flake.nix ./environment ./fonts ./launchd diff --git a/modules/nix/nixpkgs-flake.nix b/modules/nix/nixpkgs-flake.nix new file mode 100644 index 000000000..bb7c1b0a2 --- /dev/null +++ b/modules/nix/nixpkgs-flake.nix @@ -0,0 +1,105 @@ +{ config, options, lib, ... }: + +with lib; + +let + cfg = config.nixpkgs.flake; +in +{ + options.nixpkgs.flake = { + source = mkOption { + # In newer Nix versions, particularly with lazy trees, outPath of + # flakes becomes a Nix-language path object. We deliberately allow this + # to gracefully come through the interface in discussion with @roberth. + # + # See: https://github.com/NixOS/nixpkgs/pull/278522#discussion_r1460292639 + type = types.nullOr (types.either types.str types.path); + + default = null; + defaultText = "if (using nix-darwin.lib.darwinSystem) then nixpkgs.source else null"; + + example = ''builtins.fetchTarball { name = "source"; sha256 = "${lib.fakeHash}"; url = "https://github.com/nixos/nixpkgs/archive/somecommit.tar.gz"; }''; + + description = '' + The path to the nixpkgs sources used to build the system. This is automatically set up to be + the store path of the nixpkgs flake used to build the system if using + `nixpkgs.lib.darwinSystem`, and is otherwise null by default. + + This can also be optionally set if the nix-darwin system is not built with a flake but still uses + pinned sources: set this to the store path for the nixpkgs sources used to build the system, + as may be obtained by `builtins.fetchTarball`, for example. + + Note: the name of the store path must be "source" due to + . + ''; + }; + + setNixPath = mkOption { + type = types.bool; + + default = cfg.source != null; + defaultText = "config.nixpkgs.flake.source != null"; + + description = '' + Whether to set {env}`NIX_PATH` to include `nixpkgs=flake:nixpkgs` such that `` + lookups receive the version of nixpkgs that the system was built with, in concert with + {option}`nixpkgs.flake.setFlakeRegistry`. + + This is on by default for nix-darwin configurations built with flakes. + + This makes {command}`nix-build '' -A hello` work out of the box on flake systems. + + Note that this option makes the nix-darwin closure depend on the nixpkgs sources, which may add + undesired closure size if the system will not have any nix commands run on it. + ''; + }; + + setFlakeRegistry = mkOption { + type = types.bool; + + default = cfg.source != null; + defaultText = "config.nixpkgs.flake.source != null"; + + description = '' + Whether to pin nixpkgs in the system-wide flake registry (`/etc/nix/registry.json`) to the + store path of the sources of nixpkgs used to build the nix-darwin system. + + This is on by default for nix-darwin configurations built with flakes. + + This option makes {command}`nix run nixpkgs#hello` reuse dependencies from the system, avoid + refetching nixpkgs, and have a consistent result every time. + + Note that this option makes the nix-darwin closure depend on the nixpkgs sources, which may add + undesired closure size if the system will not have any nix commands run on it. + ''; + }; + }; + + config = mkIf (cfg.source != null) (mkMerge [ + { + assertions = [ + { + assertion = cfg.setNixPath -> cfg.setFlakeRegistry; + message = '' + Setting `nixpkgs.flake.setNixPath` requires that `nixpkgs.flake.setFlakeRegistry` also + be set, since it is implemented in terms of indirection through the flake registry. + ''; + } + ]; + } + (mkIf cfg.setFlakeRegistry { + nix.registry.nixpkgs.to = mkDefault { + type = "path"; + path = cfg.source; + }; + }) + (mkIf cfg.setNixPath { + # N.B. This does not include darwin-config in NIX_PATH unlike modules/nix/default.nix + # because we would need some kind of evil shim taking the *calling* flake's self path, + # perhaps, to ever make that work (in order to know where the Nix expr for the system came + # from and how to call it). + nix.nixPath = mkDefault ([ "nixpkgs=flake:nixpkgs" ] + ++ optional config.nix.channel.enable "/nix/var/nix/profiles/per-user/root/channels"); + }) + ]); +}