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
33 changes: 33 additions & 0 deletions lib/systems/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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 removeFunctions = a: lib.filterAttrs (_: v: !builtins.isFunction v) a;
in a: b: removeFunctions a == removeFunctions b;

/*
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`.

Expand Down
3 changes: 3 additions & 0 deletions lib/tests/release.nix
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ let
echo "Running lib/tests/sources.sh"
TEST_LIB=$PWD/lib bash lib/tests/sources.sh

echo "Running lib/tests/systems.nix"
[[ $(nix-instantiate --eval --strict lib/tests/systems.nix | tee /dev/stderr) == '[ ]' ]];

mkdir $out
echo success > $out/${nix.version}
'';
Expand Down
61 changes: 54 additions & 7 deletions lib/tests/systems.nix
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
# We assert that the new algorithmic way of generating these lists matches the
# way they were hard-coded before.
# Run:
# [nixpkgs]$ nix-instantiate --eval --strict lib/tests/systems.nix
# Expected output: [], or the failed cases
#
# 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 :).
# OfBorg runs (approximately) nix-build lib/tests/release.nix
let
lib = import ../default.nix;
mseteq = x: y: {
expr = lib.sort lib.lessThan x;
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" ];
Expand All @@ -39,4 +46,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 = x: "<<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 */)

)