Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@

/modules/misc/news.nix @rycee

/modules/misc/nix.nix @polykernel
/tests/modules/misc/nix @polykernel

/modules/misc/nixpkgs-disabled.nix @thiagokokada

/modules/misc/numlock.nix @evanjs
Expand Down
162 changes: 157 additions & 5 deletions modules/misc/nix.nix
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,98 @@ let

cfg = config.nix;

nixPackage = cfg.package;

isNixAtLeast = versionAtLeast (getVersion nixPackage);

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
else if isCoercibleToString v then
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"
'' else ''
echo "Validating generated nix.conf"
ln -s $out ./nix.conf
set -e
set +o pipefail
NIX_CONF_DIR=$PWD \
${cfg.package}/bin/nix show-config ${
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
'';
};

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 { };

in {
options.nix = {
enable = mkEnableOption ''
the Nix configuration module
'' // {
default = true;
visible = false;
};

package = mkOption {
type = types.nullOr types.package;
default = null;
example = literalExpression "pkgs.nix";
description = ''
The Nix package that the configuration should be generated for.
'';
};

registry = mkOption {
type = types.attrsOf (types.submodule (let
inputAttrs = types.attrsOf
Expand Down Expand Up @@ -68,19 +158,81 @@ in {
User level flake registry.
'';
};

registryVersion = mkOption {
type = types.int;
default = 2;
internal = true;
description = "The flake registry format version.";
};

checkConfig = mkOption {
type = types.bool;
default = true;
description = ''
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
'';
description =
"Additional text appended to <filename>nix.conf</filename>.";
};

settings = mkOption {
type = types.submodule { freeformType = semanticConfType; };
default = { };
example = literalExpression ''
{
use-sandbox = true;
show-trace = true;
system-features = [ "big-parallel" "kvm" "recursive-nix" ];
}
'';
description = ''
Configuration for Nix, see
<link xlink:href="https://nixos.org/manual/nix/stable/#sec-conf-file"/> or
<citerefentry>
<refentrytitle>nix.conf</refentrytitle>
<manvolnum>5</manvolnum>
</citerefentry> for avalaible options.
The value declared here will be translated directly to the key-value pairs Nix expects.
</para>
<para>
Configuration specified in <option>nix.extraOptions</option> which will be appended
verbatim to the resulting config file.
'';
};
};

config = mkIf (cfg.registry != { }) {
xdg.configFile."nix/registry.json".text = builtins.toJSON {
version = cfg.registryVersion;
flakes =
mapAttrsToList (n: v: { inherit (v) from to exact; }) cfg.registry;
config = mkIf cfg.enable {
assertions = [{
assertion = cfg.settings == { } || cfg.package != null;
Comment thread
berbiche marked this conversation as resolved.
message = ''
A corresponding Nix package must be specified via `nix.package` for generating
nix.conf.
'';
}];
Comment on lines +216 to +222
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This does not trigger when only extraOptions is set, causing #3644.

Also, is there a reason not to set pkgs.nix as the default package?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The reason pkgs.nix is not set as the default is because the config generation checkPhase depends on the system nix version. The concern was that if the version of default nix package did not match the user's installed nix version, then the show-config nix command could potentially validate against an incompatible config schema. This is an issue when new releases introduce option changes that break backwards compatibility(e.g options being renamed/removed).

We can't assumed that home-manager has access to system state(i.e as a NixOS module) to determine the system nix version so the compromise was made to force the user to determine the version/schema to be used.

Copy link
Copy Markdown
Member

@ncfavier ncfavier Feb 7, 2023

Choose a reason for hiding this comment

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

Fair enough, but we could at least try osConfig.nix.package

EDIT: I guess if that is set then the user probably doesn't want to manage nix per-user...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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


xdg.configFile = {
"nix/registry.json" = mkIf (cfg.registry != { }) {
source = jsonFormat.generate "registry.json" {
version = cfg.registryVersion;
flakes =
mapAttrsToList (n: v: { inherit (v) from to exact; }) cfg.registry;
};
};

"nix/nix.conf" = mkIf (cfg.settings != { }) { source = nixConf; };
Comment thread
berbiche marked this conversation as resolved.
};
};

meta.maintainers = [ maintainers.polykernel ];
}
1 change: 1 addition & 0 deletions tests/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import nmt {
./modules/files
./modules/home-environment
./modules/misc/fontconfig
./modules/misc/nix
./modules/programs/alacritty
./modules/programs/alot
./modules/programs/aria2
Expand Down
5 changes: 5 additions & 0 deletions tests/modules/misc/nix/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
nix-empty-settings = ./empty-settings.nix;
nix-example-settings = ./example-settings.nix;
nix-example-registry = ./example-registry.nix;
}
13 changes: 13 additions & 0 deletions tests/modules/misc/nix/empty-settings.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{ config, lib, pkgs, ... }:

with lib;

{
config = {
nix = { package = config.lib.test.mkStubPackage { }; };

nmt.script = ''
assertPathNotExists home-files/.config/nix
'';
};
}
17 changes: 17 additions & 0 deletions tests/modules/misc/nix/example-registry-expected.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"flakes": [
{
"exact": true,
"from": {
"id": "nixpkgs",
"type": "indirect"
},
"to": {
"owner": "my-org",
"repo": "my-nixpkgs",
"type": "github"
}
}
],
"version": 2
}
25 changes: 25 additions & 0 deletions tests/modules/misc/nix/example-registry.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{ config, lib, pkgs, ... }:

with lib;

{
config = {
nix = {
registry = {
nixpkgs = {
to = {
type = "github";
owner = "my-org";
repo = "my-nixpkgs";
};
};
};
};

nmt.script = ''
assertFileContent \
home-files/.config/nix/registry.json \
${./example-registry-expected.json}
'';
};
}
7 changes: 7 additions & 0 deletions tests/modules/misc/nix/example-settings-expected.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# 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!
show-trace = true
system-features = big-parallel kvm recursive-nix
use-sandbox = true

33 changes: 33 additions & 0 deletions tests/modules/misc/nix/example-settings.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{ config, lib, pkgs, ... }:

with lib;

{
config = {
nix = {
package = config.lib.test.mkStubPackage {
version = lib.getVersion pkgs.nixStable;
buildScript = ''
target=$out/bin/nix
mkdir -p "$(dirname "$target")"

echo -n "true" > "$target"

chmod +x "$target"
'';
};

settings = {
use-sandbox = true;
show-trace = true;
system-features = [ "big-parallel" "kvm" "recursive-nix" ];
};
};

nmt.script = ''
assertFileContent \
home-files/.config/nix/nix.conf \
${./example-settings-expected.conf}
'';
};
}