lib.systems.{equals,toLosslessStringMaybe}: init

This commit is contained in:
Robert Hensing 2023-05-14 22:28:31 +02:00
parent 3a86958c97
commit 18c7f6237f
2 changed files with 86 additions and 8 deletions

View File

@ -9,6 +9,39 @@ rec {
examples = import ./examples.nix { inherit lib; };
architectures = import ./architectures.nix { inherit lib; };
/*
Elaborated systems contain functions, which means that they don't satisfy
`==` for a lack of reflexivity.
They might *appear* to satisfy `==` reflexivity when the same exact value is
compared to itself, because object identity is used as an "optimization";
compare the value with a reconstruction of itself, e.g. with `f == a: f a`,
or perhaps calling `elaborate` twice, and one will see reflexivity fail as described.
Hence a custom equality test.
Note that this does not canonicalize the systems, so you'll want to make sure
both arguments have been `elaborate`-d.
*/
equals =
let uncomparable = { canExecute = null; emulator = null; emulatorAvailable = null; isCompatible = null; };
in a: b: a // uncomparable == b // uncomparable;
/*
Try to convert an elaborated system back to a simple string. If not possible,
return null. So we have the property:
sys: _valid_ sys ->
sys == elaborate (toLosslessStringMaybe sys)
NOTE: This property is not guaranteed when `sys` was elaborated by a different
version of Nixpkgs.
*/
toLosslessStringMaybe = sys:
if lib.isString sys then sys
else if equals sys (elaborate sys.system) then sys.system
else null;
/* List of all Nix system doubles the nixpkgs flake will expose the package set
for. All systems listed here must be supported by nixpkgs as `localSystem`.

View File

@ -1,10 +1,6 @@
# We assert that the new algorithmic way of generating these lists matches the
# way they were hard-coded before.
#
# One might think "if we exhaustively test, what's the point of procedurally
# calculating the lists anyway?". The answer is one can mindlessly update these
# tests as new platforms become supported, and then just give the diff a quick
# sanity check before committing :).
# Run:
# [nixpkgs]$ nix-instantiate --eval --strict lib/tests/systems.nix
# Expected output: [], or the failed cases
let
lib = import ../default.nix;
mseteq = x: y: {
@ -12,7 +8,16 @@ let
expected = lib.sort lib.lessThan y;
};
in
with lib.systems.doubles; lib.runTests {
lib.runTests (
# We assert that the new algorithmic way of generating these lists matches the
# way they were hard-coded before.
#
# One might think "if we exhaustively test, what's the point of procedurally
# calculating the lists anyway?". The answer is one can mindlessly update these
# tests as new platforms become supported, and then just give the diff a quick
# sanity check before committing :).
(with lib.systems.doubles; {
testall = mseteq all (linux ++ darwin ++ freebsd ++ openbsd ++ netbsd ++ illumos ++ wasi ++ windows ++ embedded ++ mmix ++ js ++ genode ++ redox);
testarm = mseteq arm [ "armv5tel-linux" "armv6l-linux" "armv6l-netbsd" "armv6l-none" "armv7a-linux" "armv7a-netbsd" "armv7l-linux" "armv7l-netbsd" "arm-none" "armv7a-darwin" ];
@ -39,4 +44,44 @@ with lib.systems.doubles; lib.runTests {
testopenbsd = mseteq openbsd [ "i686-openbsd" "x86_64-openbsd" ];
testwindows = mseteq windows [ "i686-cygwin" "x86_64-cygwin" "i686-windows" "x86_64-windows" ];
testunix = mseteq unix (linux ++ darwin ++ freebsd ++ openbsd ++ netbsd ++ illumos ++ cygwin ++ redox);
})
// {
test_equals_example_x86_64-linux = {
expr = lib.systems.equals (lib.systems.elaborate "x86_64-linux") (lib.systems.elaborate "x86_64-linux");
expected = true;
};
test_toLosslessStringMaybe_example_x86_64-linux = {
expr = lib.systems.toLosslessStringMaybe (lib.systems.elaborate "x86_64-linux");
expected = "x86_64-linux";
};
test_toLosslessStringMaybe_fail = {
expr = lib.systems.toLosslessStringMaybe (lib.systems.elaborate "x86_64-linux" // { something = "extra"; });
expected = null;
};
}
# Generate test cases to assert that a change in any non-function attribute makes a platform unequal
// lib.concatMapAttrs (platformAttrName: origValue: {
${"test_equals_unequal_${platformAttrName}"} =
let modified =
assert origValue != arbitraryValue;
lib.systems.elaborate "x86_64-linux" // { ${platformAttrName} = arbitraryValue; };
arbitraryValue = "<<modified>>";
in {
expr = lib.systems.equals (lib.systems.elaborate "x86_64-linux") modified;
expected = {
# Changes in these attrs are not detectable because they're function.
# The functions should be derived from the data, so this is not a problem.
canExecute = null;
emulator = null;
emulatorAvailable = null;
isCompatible = null;
}?${platformAttrName};
};
}) (lib.systems.elaborate "x86_64-linux" /* arbitrary choice, just to get all the elaborated attrNames */)
)