2022-01-27 17:58:25 +00:00
|
|
|
{ config, lib, pkgs, ... }:
|
|
|
|
|
|
|
|
let
|
|
|
|
|
2024-06-13 01:47:38 +00:00
|
|
|
inherit (lib)
|
|
|
|
boolToString concatStringsSep escape floatToString getVersion isBool
|
|
|
|
isConvertibleWithToString isDerivation isFloat isInt isList isString
|
|
|
|
literalExpression maintainers mapAttrsToList mkDefault mkEnableOption mkIf
|
|
|
|
mkMerge mkOption optionalString toPretty types versionAtLeast;
|
|
|
|
|
2022-01-27 17:58:25 +00:00
|
|
|
cfg = config.nix;
|
|
|
|
|
2022-03-18 02:47:32 +00:00
|
|
|
nixPackage = cfg.package;
|
|
|
|
|
|
|
|
isNixAtLeast = versionAtLeast (getVersion nixPackage);
|
|
|
|
|
2024-06-13 01:47:38 +00:00
|
|
|
nixPath = concatStringsSep ":" cfg.nixPath;
|
|
|
|
|
|
|
|
useXdg = config.nix.enable
|
|
|
|
&& (config.nix.settings.use-xdg-base-directories or false);
|
|
|
|
defexprDir = if useXdg then
|
|
|
|
"${config.xdg.stateHome}/nix/defexpr"
|
|
|
|
else
|
|
|
|
"${config.home.homeDirectory}/.nix-defexpr";
|
|
|
|
|
|
|
|
# The deploy path for declarative channels. The directory name is prefixed
|
|
|
|
# with a number to make it easier for files in defexprDir to control the order
|
|
|
|
# they'll be read relative to each other.
|
|
|
|
channelPath = "${defexprDir}/50-home-manager";
|
|
|
|
|
|
|
|
channelsDrv = let
|
|
|
|
mkEntry = name: drv: {
|
|
|
|
inherit name;
|
|
|
|
path = toString drv;
|
|
|
|
};
|
|
|
|
in pkgs.linkFarm "channels" (lib.mapAttrsToList mkEntry cfg.channels);
|
|
|
|
|
2022-03-18 02:47:32 +00:00
|
|
|
nixConf = assert isNixAtLeast "2.2";
|
|
|
|
let
|
|
|
|
|
|
|
|
mkValueString = v:
|
|
|
|
if v == null then
|
|
|
|
""
|
|
|
|
else if isInt v then
|
|
|
|
toString v
|
|
|
|
else if isBool v then
|
|
|
|
boolToString v
|
|
|
|
else if isFloat v then
|
|
|
|
floatToString v
|
|
|
|
else if isList v then
|
|
|
|
toString v
|
|
|
|
else if isDerivation v then
|
|
|
|
toString v
|
|
|
|
else if builtins.isPath v then
|
|
|
|
toString v
|
|
|
|
else if isString v then
|
|
|
|
v
|
2023-06-09 09:57:20 +00:00
|
|
|
else if isConvertibleWithToString v then
|
2022-03-18 02:47:32 +00:00
|
|
|
toString v
|
|
|
|
else
|
|
|
|
abort "The nix conf value: ${toPretty { } v} can not be encoded";
|
|
|
|
|
|
|
|
mkKeyValue = k: v: "${escape [ "=" ] k} = ${mkValueString v}";
|
|
|
|
|
|
|
|
mkKeyValuePairs = attrs:
|
|
|
|
concatStringsSep "\n" (mapAttrsToList mkKeyValue attrs);
|
|
|
|
|
|
|
|
in pkgs.writeTextFile {
|
|
|
|
name = "nix.conf";
|
|
|
|
text = ''
|
|
|
|
# WARNING: this file is generated from the nix.settings option in
|
|
|
|
# your Home Manager configuration at $XDG_CONFIG_HOME/nix/nix.conf.
|
|
|
|
# Do not edit it!
|
|
|
|
${mkKeyValuePairs cfg.settings}
|
|
|
|
${cfg.extraOptions}
|
|
|
|
'';
|
|
|
|
checkPhase =
|
|
|
|
if pkgs.stdenv.hostPlatform != pkgs.stdenv.buildPlatform then ''
|
|
|
|
echo "Ignoring validation for cross-compilation"
|
2024-02-03 10:14:20 +00:00
|
|
|
'' else
|
|
|
|
let
|
|
|
|
showCommand =
|
|
|
|
if isNixAtLeast "2.20pre" then "config show" else "show-config";
|
|
|
|
in ''
|
|
|
|
echo "Validating generated nix.conf"
|
|
|
|
ln -s $out ./nix.conf
|
|
|
|
set -e
|
|
|
|
set +o pipefail
|
|
|
|
NIX_CONF_DIR=$PWD \
|
|
|
|
${cfg.package}/bin/nix ${showCommand} ${
|
|
|
|
optionalString (isNixAtLeast "2.3pre")
|
|
|
|
"--no-net --option experimental-features nix-command"
|
|
|
|
} \
|
|
|
|
|& sed -e 's/^warning:/error:/' \
|
|
|
|
| (! grep '${
|
|
|
|
if cfg.checkConfig then "^error:" else "^error: unknown setting"
|
|
|
|
}')
|
|
|
|
set -o pipefail
|
|
|
|
'';
|
2022-03-18 02:47:32 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
semanticConfType = with types;
|
|
|
|
let
|
|
|
|
confAtom = nullOr (oneOf [ bool int float str path package ]) // {
|
|
|
|
description =
|
|
|
|
"Nix config atom (null, bool, int, float, str, path or package)";
|
|
|
|
};
|
|
|
|
in attrsOf (either confAtom (listOf confAtom));
|
|
|
|
|
|
|
|
jsonFormat = pkgs.formats.json { };
|
|
|
|
|
2022-01-27 17:58:25 +00:00
|
|
|
in {
|
|
|
|
options.nix = {
|
2023-07-01 23:45:18 +00:00
|
|
|
enable = mkEnableOption ''
|
2022-03-18 02:47:32 +00:00
|
|
|
the Nix configuration module
|
2023-07-01 23:45:18 +00:00
|
|
|
'' // {
|
2022-03-18 02:47:32 +00:00
|
|
|
default = true;
|
|
|
|
visible = false;
|
|
|
|
};
|
|
|
|
|
|
|
|
package = mkOption {
|
|
|
|
type = types.nullOr types.package;
|
|
|
|
default = null;
|
|
|
|
example = literalExpression "pkgs.nix";
|
2023-07-01 23:45:18 +00:00
|
|
|
description = ''
|
2022-03-18 02:47:32 +00:00
|
|
|
The Nix package that the configuration should be generated for.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2024-06-13 01:47:38 +00:00
|
|
|
nixPath = mkOption {
|
|
|
|
type = types.listOf types.str;
|
|
|
|
default = [ ];
|
|
|
|
example = [
|
|
|
|
"$HOME/.nix-defexpr/channels"
|
|
|
|
"darwin-config=$HOME/.config/nixpkgs/darwin-configuration.nix"
|
|
|
|
];
|
|
|
|
description = ''
|
|
|
|
Adds new directories to the Nix expression search path.
|
|
|
|
|
|
|
|
Used by Nix when looking up paths in angular brackets
|
|
|
|
(e.g. `<nixpkgs>`).
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
keepOldNixPath = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = true;
|
|
|
|
example = false;
|
|
|
|
description = ''
|
|
|
|
Whether {option}`nix.nixPath` should keep the previously set values in
|
|
|
|
{env}`NIX_PATH`.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
channels = lib.mkOption {
|
|
|
|
type = with lib.types; attrsOf package;
|
|
|
|
default = { };
|
|
|
|
example = lib.literalExpression "{ inherit nixpkgs; }";
|
|
|
|
description = ''
|
|
|
|
A declarative alternative to Nix channels. Whereas with stock channels,
|
|
|
|
you would register URLs and fetch them into the Nix store with
|
|
|
|
{manpage}`nix-channel(1)`, this option allows you to register the store
|
|
|
|
path directly. One particularly useful example is registering flake
|
|
|
|
inputs as channels.
|
|
|
|
|
|
|
|
This option can coexist with stock Nix channels. If the same channel is
|
|
|
|
defined in both, this option takes precedence.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2022-01-27 17:58:25 +00:00
|
|
|
registry = mkOption {
|
|
|
|
type = types.attrsOf (types.submodule (let
|
|
|
|
inputAttrs = types.attrsOf
|
|
|
|
(types.oneOf [ types.str types.int types.bool types.package ]);
|
|
|
|
in { config, name, ... }: {
|
|
|
|
options = {
|
|
|
|
from = mkOption {
|
|
|
|
type = inputAttrs;
|
|
|
|
example = {
|
|
|
|
type = "indirect";
|
|
|
|
id = "nixpkgs";
|
|
|
|
};
|
2023-07-01 23:45:18 +00:00
|
|
|
description = "The flake reference to be rewritten.";
|
2022-01-27 17:58:25 +00:00
|
|
|
};
|
|
|
|
to = mkOption {
|
|
|
|
type = inputAttrs;
|
|
|
|
example = {
|
|
|
|
type = "github";
|
|
|
|
owner = "my-org";
|
|
|
|
repo = "my-nixpkgs";
|
|
|
|
};
|
2023-07-01 23:45:18 +00:00
|
|
|
description =
|
2023-06-30 23:30:13 +00:00
|
|
|
"The flake reference to which {option}`from>` is to be rewritten.";
|
2022-01-27 17:58:25 +00:00
|
|
|
};
|
|
|
|
flake = mkOption {
|
|
|
|
type = types.nullOr types.attrs;
|
|
|
|
default = null;
|
|
|
|
example = literalExpression "nixpkgs";
|
2023-07-01 23:45:18 +00:00
|
|
|
description = ''
|
2023-06-30 23:30:13 +00:00
|
|
|
The flake input to which {option}`from>` is to be rewritten.
|
2022-01-27 17:58:25 +00:00
|
|
|
'';
|
|
|
|
};
|
|
|
|
exact = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = true;
|
2023-07-01 23:45:18 +00:00
|
|
|
description = ''
|
2023-06-30 23:30:13 +00:00
|
|
|
Whether the {option}`from` reference needs to match exactly. If set,
|
|
|
|
a {option}`from` reference like `nixpkgs` does not
|
|
|
|
match with a reference like `nixpkgs/nixos-20.03`.
|
2022-01-27 17:58:25 +00:00
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
config = {
|
|
|
|
from = mkDefault {
|
|
|
|
type = "indirect";
|
|
|
|
id = name;
|
|
|
|
};
|
|
|
|
to = mkIf (config.flake != null) ({
|
|
|
|
type = "path";
|
|
|
|
path = config.flake.outPath;
|
|
|
|
} // lib.filterAttrs (n: v:
|
|
|
|
n == "lastModified" || n == "rev" || n == "revCount" || n
|
|
|
|
== "narHash") config.flake);
|
|
|
|
};
|
|
|
|
}));
|
|
|
|
default = { };
|
2023-07-01 23:45:18 +00:00
|
|
|
description = ''
|
2022-01-27 17:58:25 +00:00
|
|
|
User level flake registry.
|
|
|
|
'';
|
|
|
|
};
|
2022-03-18 02:47:32 +00:00
|
|
|
|
2022-01-27 17:58:25 +00:00
|
|
|
registryVersion = mkOption {
|
|
|
|
type = types.int;
|
|
|
|
default = 2;
|
|
|
|
internal = true;
|
2023-07-01 23:45:18 +00:00
|
|
|
description = "The flake registry format version.";
|
2022-01-27 17:58:25 +00:00
|
|
|
};
|
2022-03-18 02:47:32 +00:00
|
|
|
|
|
|
|
checkConfig = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = true;
|
2023-07-01 23:45:18 +00:00
|
|
|
description = ''
|
2022-03-18 02:47:32 +00:00
|
|
|
If enabled (the default), checks for data type mismatches and that Nix
|
|
|
|
can parse the generated nix.conf.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
extraOptions = mkOption {
|
|
|
|
type = types.lines;
|
|
|
|
default = "";
|
|
|
|
example = ''
|
|
|
|
keep-outputs = true
|
|
|
|
keep-derivations = true
|
|
|
|
'';
|
2023-07-01 23:45:18 +00:00
|
|
|
description = "Additional text appended to {file}`nix.conf`.";
|
2022-03-18 02:47:32 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
settings = mkOption {
|
|
|
|
type = types.submodule { freeformType = semanticConfType; };
|
|
|
|
default = { };
|
|
|
|
example = literalExpression ''
|
|
|
|
{
|
|
|
|
use-sandbox = true;
|
|
|
|
show-trace = true;
|
|
|
|
system-features = [ "big-parallel" "kvm" "recursive-nix" ];
|
|
|
|
}
|
|
|
|
'';
|
2023-07-01 23:45:18 +00:00
|
|
|
description = ''
|
2023-06-30 22:35:51 +00:00
|
|
|
Configuration for Nix; see {manpage}`nix.conf(5)` for available options.
|
2022-03-18 02:47:32 +00:00
|
|
|
The value declared here will be translated directly to the key-value pairs Nix expects.
|
2023-06-30 22:35:51 +00:00
|
|
|
|
|
|
|
Configuration specified in [](#opt-nix.extraOptions) will be appended
|
2022-03-18 02:47:32 +00:00
|
|
|
verbatim to the resulting config file.
|
|
|
|
'';
|
|
|
|
};
|
2022-01-27 17:58:25 +00:00
|
|
|
};
|
|
|
|
|
2023-02-07 10:35:12 +00:00
|
|
|
config = mkIf cfg.enable (mkMerge [
|
2024-06-13 01:47:38 +00:00
|
|
|
(mkIf (cfg.nixPath != [ ] && !cfg.keepOldNixPath) {
|
|
|
|
home.sessionVariables.NIX_PATH = "${nixPath}";
|
|
|
|
})
|
|
|
|
|
|
|
|
(mkIf (cfg.nixPath != [ ] && cfg.keepOldNixPath) {
|
|
|
|
home.sessionVariables.NIX_PATH = "${nixPath}\${NIX_PATH:+:$NIX_PATH}";
|
|
|
|
})
|
|
|
|
|
|
|
|
(lib.mkIf (cfg.channels != { }) {
|
|
|
|
nix.nixPath = [ channelPath ];
|
|
|
|
home.file."${channelPath}".source = channelsDrv;
|
|
|
|
})
|
|
|
|
|
2023-02-07 10:35:12 +00:00
|
|
|
(mkIf (cfg.registry != { }) {
|
|
|
|
xdg.configFile."nix/registry.json".source =
|
|
|
|
jsonFormat.generate "registry.json" {
|
2022-03-18 02:47:32 +00:00
|
|
|
version = cfg.registryVersion;
|
|
|
|
flakes =
|
|
|
|
mapAttrsToList (n: v: { inherit (v) from to exact; }) cfg.registry;
|
|
|
|
};
|
2023-02-07 10:35:12 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
(mkIf (cfg.settings != { } || cfg.extraOptions != "") {
|
|
|
|
assertions = [{
|
|
|
|
assertion = cfg.package != null;
|
|
|
|
message = ''
|
|
|
|
A corresponding Nix package must be specified via `nix.package` for generating
|
|
|
|
nix.conf.
|
|
|
|
'';
|
|
|
|
}];
|
2022-03-18 02:47:32 +00:00
|
|
|
|
2023-02-07 10:35:12 +00:00
|
|
|
xdg.configFile."nix/nix.conf".source = nixConf;
|
|
|
|
})
|
|
|
|
]);
|
2022-03-18 02:47:32 +00:00
|
|
|
|
2024-07-27 07:35:13 +00:00
|
|
|
meta.maintainers = [ lib.hm.maintainers.polykernel ];
|
2022-01-27 17:58:25 +00:00
|
|
|
}
|