mirror of
https://github.com/nix-community/home-manager.git
synced 2026-10-02 19:49:18 +00:00
jaq 3.1.1 reads TOML through toml-span, which does not deserialize date or time values. An existing TOML file containing one makes the merge refuse, so activation fails on every switch until the value is removed. The file itself is left untouched. Document the limitation and test that the refused merge leaves the file byte-identical. If a later jaq parses these values, they would pass through JSON as strings, so the test is expected to fail then and prompt a review of the documented behavior.
209 lines
6.9 KiB
Nix
209 lines
6.9 KiB
Nix
# Tests for the activation snippet generated by mkImpureConfigMerger. It is
|
|
# run the way home activation runs it: as a script with the home-manager bash
|
|
# helpers available, against files in a temporary home.
|
|
{
|
|
lib,
|
|
pkgs,
|
|
...
|
|
}:
|
|
|
|
let
|
|
mkMerger =
|
|
format: static:
|
|
lib.hm.generators.mkImpureConfigMerger {
|
|
inherit pkgs format;
|
|
empty = "{}";
|
|
# The trailing comment must not break the filter the operation is
|
|
# embedded in.
|
|
jqOperation = "$dynamic * $static # recursive merge";
|
|
path = "/@TMPDIR@/hm-user/.config/testmerger/settings.${format}";
|
|
staticSettings = builtins.toFile "static-settings.${format}" static;
|
|
};
|
|
|
|
# Mirror the activation script environment: set -euo pipefail is active and
|
|
# home-manager.sh provides errorEcho.
|
|
mkScript =
|
|
name: snippet:
|
|
pkgs.writeScript name ''
|
|
set -euo pipefail
|
|
errorEcho() { echo "$*" >&2; }
|
|
${snippet}
|
|
'';
|
|
|
|
mergeJson = mkScript "merge-json" (mkMerger "json" (builtins.toJSON { nixManaged = true; }));
|
|
mergeToml = mkScript "merge-toml" (mkMerger "toml" "nixManaged = true\n");
|
|
|
|
# Messages must print the path literally instead of evaluating it.
|
|
mergeOddPath = mkScript "merge-odd-path" (
|
|
lib.hm.generators.mkImpureConfigMerger {
|
|
inherit pkgs;
|
|
format = "json";
|
|
empty = "{}";
|
|
jqOperation = "$dynamic * $static";
|
|
path = "/@TMPDIR@/hm-user/odd $(touch marker)/settings.json";
|
|
staticSettings = builtins.toFile "static-settings.json" "{}";
|
|
}
|
|
);
|
|
|
|
largeStatic = builtins.toJSON { nixManaged = lib.genList (i: i) 40000; };
|
|
largeStaticFile = builtins.toFile "static-settings.json" largeStatic;
|
|
mergeLargeStatic = mkScript "merge-large-static" (mkMerger "json" largeStatic);
|
|
|
|
# jaq prints the first object of this stream before failing on the
|
|
# truncated second one, so checking only the reader output would accept a
|
|
# partial read.
|
|
truncatedJson = builtins.toFile "truncated.json" ''
|
|
{"keep":true}
|
|
{"lost":
|
|
'';
|
|
|
|
userToml = builtins.toFile "user.toml" ''
|
|
userSetting = 5
|
|
'';
|
|
|
|
expectedJson = builtins.toFile "expected.json" ''
|
|
{
|
|
"nixManaged": true
|
|
}
|
|
'';
|
|
|
|
expectedToml = builtins.toFile "expected.toml" ''
|
|
nixManaged = true
|
|
'';
|
|
|
|
expectedUserToml = builtins.toFile "expected-user.toml" ''
|
|
userSetting = 5
|
|
nixManaged = true
|
|
'';
|
|
|
|
mergeYaml = mkScript "merge-yaml" (
|
|
mkMerger "yaml" ''
|
|
managed:
|
|
key: nix
|
|
''
|
|
);
|
|
|
|
userYaml = builtins.toFile "user.yaml" ''
|
|
user:
|
|
theme: dark
|
|
recent:
|
|
- /a
|
|
- /b
|
|
'';
|
|
|
|
expectedYaml = builtins.toFile "expected.yaml" ''
|
|
---
|
|
user:
|
|
theme: dark
|
|
recent:
|
|
- /a
|
|
- /b
|
|
managed:
|
|
key: nix
|
|
...
|
|
'';
|
|
|
|
userDateToml = builtins.toFile "user-date.toml" ''
|
|
# Keep this file intact when jaq cannot parse its date value.
|
|
date = 1979-05-27T07:32:00Z
|
|
userSetting = 5
|
|
'';
|
|
in
|
|
{
|
|
nmt.script = ''
|
|
substitute ${mergeJson} $TMPDIR/merge-json --subst-var TMPDIR
|
|
substitute ${mergeToml} $TMPDIR/merge-toml --subst-var TMPDIR
|
|
substitute ${mergeLargeStatic} $TMPDIR/merge-large-static --subst-var TMPDIR
|
|
chmod +x $TMPDIR/merge-json $TMPDIR/merge-toml $TMPDIR/merge-large-static
|
|
|
|
mkdir -p $TMPDIR/hm-user/.config/testmerger
|
|
jsonSettings=$TMPDIR/hm-user/.config/testmerger/settings.json
|
|
tomlSettings=$TMPDIR/hm-user/.config/testmerger/settings.toml
|
|
|
|
# A reader that emits JSON before failing must fail activation and keep
|
|
# the original file instead of merging the partial output.
|
|
cat ${truncatedJson} > $jsonSettings
|
|
if $TMPDIR/merge-json > /dev/null 2>&1; then
|
|
fail "Merging a truncated JSON stream must fail activation"
|
|
fi
|
|
assertFileContent $jsonSettings ${truncatedJson}
|
|
|
|
printf '%s\n' '{"a":1}' '{"b":2}' > $jsonSettings
|
|
cp $jsonSettings $TMPDIR/original.json
|
|
if $TMPDIR/merge-json > /dev/null 2> $TMPDIR/merge-error; then
|
|
fail "Merging multiple JSON values must fail activation"
|
|
fi
|
|
assertFileContent $jsonSettings $TMPDIR/original.json
|
|
grep -qF "$jsonSettings" $TMPDIR/merge-error \
|
|
|| fail "A failed merge must name the config file"
|
|
|
|
${lib.getExe pkgs.jaq} -cn '{userSetting: [range(0; 40000)]}' > $jsonSettings
|
|
if [ "$(wc -c < $jsonSettings)" -le 131072 ]; then
|
|
fail "The existing JSON file must exceed 128 KiB"
|
|
fi
|
|
$TMPDIR/merge-json
|
|
${lib.getExe pkgs.jaq} -e '.userSetting == [range(0; 40000)] and .nixManaged == true' $jsonSettings > /dev/null
|
|
|
|
if [ "$(wc -c < ${largeStaticFile})" -le 131072 ]; then
|
|
fail "The Nix-declared JSON settings must exceed 128 KiB"
|
|
fi
|
|
echo '{"userSetting":true}' > $jsonSettings
|
|
$TMPDIR/merge-large-static
|
|
${lib.getExe pkgs.jaq} -e '.userSetting == true and .nixManaged == [range(0; 40000)]' $jsonSettings > /dev/null
|
|
|
|
substitute ${mergeOddPath} $TMPDIR/merge-odd-path --subst-var TMPDIR
|
|
chmod +x $TMPDIR/merge-odd-path
|
|
oddSettings='/'"$TMPDIR"'/hm-user/odd $(touch marker)/settings.json'
|
|
DRY_RUN=1 $TMPDIR/merge-odd-path > $TMPDIR/odd-output
|
|
mkdir -p "$(dirname "$oddSettings")"
|
|
echo '{' > "$oddSettings"
|
|
if $TMPDIR/merge-odd-path 2>> $TMPDIR/odd-output; then
|
|
fail "Merging a malformed file must fail activation"
|
|
fi
|
|
[[ ! -e marker ]] || fail "Messages must not run commands in the path"
|
|
grep -qF 'odd $(touch marker)/settings.json' $TMPDIR/odd-output \
|
|
|| fail "Messages must contain the literal path"
|
|
|
|
# A missing JSON target installs the generated settings.
|
|
rm -f $jsonSettings
|
|
$TMPDIR/merge-json
|
|
assertFileContent $jsonSettings ${expectedJson}
|
|
|
|
# A missing TOML target installs the generated settings instead of
|
|
# failing on a file seeded with the JSON `empty` value.
|
|
$TMPDIR/merge-toml
|
|
assertFileContent $tomlSettings ${expectedToml}
|
|
|
|
# Existing user settings survive the merge.
|
|
cat ${userToml} > $tomlSettings
|
|
$TMPDIR/merge-toml
|
|
assertFileContent $tomlSettings ${expectedUserToml}
|
|
|
|
# A zero-byte file is treated as `empty`.
|
|
: > $tomlSettings
|
|
$TMPDIR/merge-toml
|
|
assertFileContent $tomlSettings ${expectedToml}
|
|
|
|
# jaq 3.1.1 cannot parse TOML dates. If a newer jaq can, they would pass
|
|
# through JSON as strings and come back as TOML strings, so this failing
|
|
# means the documented limitation needs revisiting.
|
|
cat ${userDateToml} > $tomlSettings
|
|
if $TMPDIR/merge-toml > /dev/null 2>&1; then
|
|
fail "Merging TOML with a date value must fail activation"
|
|
fi
|
|
assertFileContent $tomlSettings ${userDateToml}
|
|
|
|
substitute ${mergeYaml} $TMPDIR/merge-yaml --subst-var TMPDIR
|
|
chmod +x $TMPDIR/merge-yaml
|
|
yamlSettings=$TMPDIR/hm-user/.config/testmerger/settings.yaml
|
|
|
|
# YAML is written in block style, and merging the written file again
|
|
# leaves it unchanged.
|
|
cat ${userYaml} > $yamlSettings
|
|
$TMPDIR/merge-yaml
|
|
assertFileContent $yamlSettings ${expectedYaml}
|
|
$TMPDIR/merge-yaml
|
|
assertFileContent $yamlSettings ${expectedYaml}
|
|
'';
|
|
}
|