about summary refs log tree commit diff
path: root/lib
diff options
context:
space:
mode:
authorArtturi <Artturin@artturin.com>2023-06-15 23:30:49 +0300
committerGitHub <noreply@github.com>2023-06-15 23:30:49 +0300
commit5ff6f51c1c8645d6fad1f95b28195f5a63f520e5 (patch)
treeffb2939ab4f65e32189e154cac1663ac84b5676a /lib
parent95c729c030b3011c5c89107ac9fa30f7249135fe (diff)
parent3150f25faa599c6c6215295144f5c6b4a87eea6e (diff)
downloadnixlib-5ff6f51c1c8645d6fad1f95b28195f5a63f520e5.tar
nixlib-5ff6f51c1c8645d6fad1f95b28195f5a63f520e5.tar.gz
nixlib-5ff6f51c1c8645d6fad1f95b28195f5a63f520e5.tar.bz2
nixlib-5ff6f51c1c8645d6fad1f95b28195f5a63f520e5.tar.lz
nixlib-5ff6f51c1c8645d6fad1f95b28195f5a63f520e5.tar.xz
nixlib-5ff6f51c1c8645d6fad1f95b28195f5a63f520e5.tar.zst
nixlib-5ff6f51c1c8645d6fad1f95b28195f5a63f520e5.zip
Merge pull request #237512 from hercules-ci/lib-system-equals
Diffstat (limited to 'lib')
-rw-r--r--lib/systems/default.nix33
-rw-r--r--lib/tests/release.nix3
-rw-r--r--lib/tests/systems.nix61
3 files changed, 90 insertions, 7 deletions
diff --git a/lib/systems/default.nix b/lib/systems/default.nix
index f4784c61c675..3558ce32fc8c 100644
--- a/lib/systems/default.nix
+++ b/lib/systems/default.nix
@@ -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`.
 
diff --git a/lib/tests/release.nix b/lib/tests/release.nix
index c3bf58db241f..5bade7112f19 100644
--- a/lib/tests/release.nix
+++ b/lib/tests/release.nix
@@ -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}
     '';
diff --git a/lib/tests/systems.nix b/lib/tests/systems.nix
index 2afe128c4208..862496313e90 100644
--- a/lib/tests/systems.nix
+++ b/lib/tests/systems.nix
@@ -1,10 +1,8 @@
-# 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: {
@@ -12,7 +10,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 +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 */)
+
+)