From fcaa408d005743b34aed8b7e2992ef885b4ce027 Mon Sep 17 00:00:00 2001
From: Silvan Mosberger <silvan.mosberger@tweag.io>
Date: Thu, 12 Oct 2023 01:00:37 +0200
Subject: [PATCH] tests.nixpkgs-check-by-name: auto-calling differentiation

Allows detecting whether attributes are overridden in all-packages.nix.
In a future commit we'll use this to detect empty arguments being set in
all-packages.nix and complain about that.
---
 pkgs/test/nixpkgs-check-by-name/src/eval.nix    | 17 +++++++++++++++++
 pkgs/test/nixpkgs-check-by-name/src/eval.rs     |  7 ++++++-
 .../tests/mock-nixpkgs.nix                      | 11 ++++++++---
 pkgs/top-level/by-name-overlay.nix              | 15 ++++++++++++---
 4 files changed, 43 insertions(+), 7 deletions(-)

diff --git a/pkgs/test/nixpkgs-check-by-name/src/eval.nix b/pkgs/test/nixpkgs-check-by-name/src/eval.nix
index 087b0a519c71..2fa0c5a9709c 100644
--- a/pkgs/test/nixpkgs-check-by-name/src/eval.nix
+++ b/pkgs/test/nixpkgs-check-by-name/src/eval.nix
@@ -35,6 +35,23 @@ let
       else
         # It's very rare that callPackage doesn't return an attribute set, but it can occur.
         variantInfo;
+
+    _internalCallByNamePackageFile = file:
+      let
+        result = super._internalCallByNamePackageFile file;
+        variantInfo._attributeVariant = {
+          # This name is used by the deserializer on the Rust side
+          AutoCalled = null;
+        };
+      in
+      if builtins.isAttrs result then
+        # If this was the last overlay to be applied, we could just only return the `_callPackagePath`,
+        # but that's not the case because stdenv has another overlays on top of user-provided ones.
+        # So to not break the stdenv build we need to return the mostly proper result here
+        result // variantInfo
+      else
+        # It's very rare that callPackage doesn't return an attribute set, but it can occur.
+        variantInfo;
   };
 
   pkgs = import nixpkgsPath {
diff --git a/pkgs/test/nixpkgs-check-by-name/src/eval.rs b/pkgs/test/nixpkgs-check-by-name/src/eval.rs
index 53a813045eee..b1c1a44f8c08 100644
--- a/pkgs/test/nixpkgs-check-by-name/src/eval.rs
+++ b/pkgs/test/nixpkgs-check-by-name/src/eval.rs
@@ -19,7 +19,11 @@ struct AttributeInfo {
 
 #[derive(Deserialize)]
 enum AttributeVariant {
-    /// The attribute is defined as a pkgs.callPackage <path>
+    /// The attribute is auto-called as pkgs.callPackage using pkgs/by-name,
+    /// and it is not overridden by a definition in all-packages.nix
+    AutoCalled,
+    /// The attribute is defined as a pkgs.callPackage <path>,
+    /// and overridden by all-packages.nix
     /// The path is None when the <path> argument isn't a path
     CallPackage { path: Option<PathBuf> },
     /// The attribute is not defined as pkgs.callPackage
@@ -107,6 +111,7 @@ pub fn check_values<W: io::Write>(
 
         if let Some(attribute_info) = actual_files.get(package_name) {
             let valid = match &attribute_info.variant {
+                AttributeVariant::AutoCalled => true,
                 AttributeVariant::CallPackage { path } => {
                     if let Some(call_package_path) = path {
                         absolute_package_file == *call_package_path
diff --git a/pkgs/test/nixpkgs-check-by-name/tests/mock-nixpkgs.nix b/pkgs/test/nixpkgs-check-by-name/tests/mock-nixpkgs.nix
index 50ad67617542..01bb27a48038 100644
--- a/pkgs/test/nixpkgs-check-by-name/tests/mock-nixpkgs.nix
+++ b/pkgs/test/nixpkgs-check-by-name/tests/mock-nixpkgs.nix
@@ -75,9 +75,14 @@ let
 
   # Turns autoCalledPackageFiles into an overlay that `callPackage`'s all of them
   autoCalledPackages = self: super:
-    builtins.mapAttrs (name: file:
-      self.callPackage file { }
-    ) autoCalledPackageFiles;
+    {
+      # Needed to be able to detect empty arguments in all-packages.nix
+      # See a more detailed description in pkgs/top-level/by-name-overlay.nix
+      _internalCallByNamePackageFile = file: self.callPackage file { };
+    }
+    // builtins.mapAttrs
+      (name: self._internalCallByNamePackageFile)
+      autoCalledPackageFiles;
 
   # A list optionally containing the `all-packages.nix` file from the test case as an overlay
   optionalAllPackagesOverlay =
diff --git a/pkgs/top-level/by-name-overlay.nix b/pkgs/top-level/by-name-overlay.nix
index 41944c4e3b01..3df9843d03df 100644
--- a/pkgs/top-level/by-name-overlay.nix
+++ b/pkgs/top-level/by-name-overlay.nix
@@ -45,6 +45,15 @@ in
 # Currently this would be hard to measure until we have more packages
 # and ideally https://github.com/NixOS/nix/pull/8895
 self: super:
-mapAttrs (name: file:
-  self.callPackage file { }
-) packageFiles
+{
+  # This attribute is necessary to allow CI to ensure that all packages defined in `pkgs/by-name`
+  # don't have an overriding definition in `all-packages.nix` with an empty (`{ }`) second `callPackage` argument.
+  # It achieves that with an overlay that modifies both `callPackage` and this attribute to signal whether `callPackage` is used
+  # and whether it's defined by this file here or `all-packages.nix`.
+  # TODO: This can be removed once `pkgs/by-name` can handle custom `callPackage` arguments without `all-packages.nix` (or any other way of achieving the same result).
+  # Because at that point the code in ./stage.nix can be changed to not allow definitions in `all-packages.nix` to override ones from `pkgs/by-name` anymore and throw an error if that happens instead.
+  _internalCallByNamePackageFile = file: self.callPackage file { };
+}
+// mapAttrs
+  (name: self._internalCallByNamePackageFile)
+  packageFiles