Skip to content

Commit 89a7afa

Browse files
committed
tests.nixpkgs-check-by-name: Improve code
- Detect manual use of _internalCallByNamePackageFile for packages in `pkgs/by-name` (can't be done for others though) - Separate error message for when attribute locations can't be determined for `pkgs/by-name` attributes - Much better structure of the code in eval.rs, representing more closely what is being checked - Much more extensive comments
1 parent ebbe863 commit 89a7afa

File tree

5 files changed

+335
-221
lines changed

5 files changed

+335
-221
lines changed

pkgs/test/nixpkgs-check-by-name/src/eval.nix

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
# Takes a path to nixpkgs and a path to the json-encoded list of attributes to check.
2-
# Returns an value containing information on each requested attribute,
1+
# Takes a path to nixpkgs and a path to the json-encoded list of `pkgs/by-name` attributes.
2+
# Returns a value containing information on all Nixpkgs attributes
33
# which is decoded on the Rust side.
44
# See ./eval.rs for the meaning of the returned values
55
{
@@ -9,33 +9,28 @@
99
let
1010
attrs = builtins.fromJSON (builtins.readFile attrsPath);
1111

12-
nixpkgsPathLength = builtins.stringLength (toString nixpkgsPath) + 1;
13-
removeNixpkgsPrefix = builtins.substring nixpkgsPathLength (-1);
14-
15-
# We need access to the `callPackage` arguments of each attribute.
16-
# The only way to do so is to override `callPackage` with our own version that adds this information to the result,
17-
# and then try to access this information.
12+
# We need to check whether attributes are defined manually e.g. in
13+
# `all-packages.nix`, automatically by the `pkgs/by-name` overlay, or
14+
# neither. The only way to do so is to override `callPackage` and
15+
# `_internalCallByNamePackageFile` with our own version that adds this
16+
# information to the result, and then try to access it.
1817
overlay = final: prev: {
1918

20-
# Information for attributes defined using `callPackage`
19+
# Adds information to each attribute about whether it's manually defined using `callPackage`
2120
callPackage = fn: args:
2221
addVariantInfo (prev.callPackage fn args) {
23-
Manual = {
24-
path =
25-
if builtins.isPath fn then
26-
removeNixpkgsPrefix (toString fn)
27-
else
28-
null;
29-
empty_arg =
30-
args == { };
31-
};
22+
# This is a manual definition of the attribute, and it's a callPackage, specifically a semantic callPackage
23+
ManualDefinition.is_semantic_call_package = true;
3224
};
3325

34-
# Information for attributes that are auto-called from pkgs/by-name.
35-
# This internal attribute is only used by pkgs/by-name
26+
# Adds information to each attribute about whether it's automatically
27+
# defined by the `pkgs/by-name` overlay. This internal attribute is only
28+
# used by that overlay.
29+
# This overrides the above `callPackage` information (we don't need that
30+
# one, since `pkgs/by-name` always uses `callPackage` underneath.
3631
_internalCallByNamePackageFile = file:
3732
addVariantInfo (prev._internalCallByNamePackageFile file) {
38-
Auto = null;
33+
AutoDefinition = null;
3934
};
4035

4136
};
@@ -50,7 +45,7 @@ let
5045
else
5146
# It's very rare that callPackage doesn't return an attribute set, but it can occur.
5247
# In such a case we can't really return anything sensible that would include the info,
53-
# so just don't return the info and let the consumer handle it.
48+
# so just don't return the value directly and treat it as if it wasn't a callPackage.
5449
value;
5550

5651
pkgs = import nixpkgsPath {
@@ -62,37 +57,42 @@ let
6257
system = "x86_64-linux";
6358
};
6459

65-
attrInfo = name: value:
66-
if ! builtins.isAttrs value then
67-
{
68-
NonAttributeSet = null;
69-
}
70-
else if ! value ? _callPackageVariant then
71-
{
72-
NonCallPackage = null;
73-
}
74-
else
75-
{
76-
CallPackage = {
77-
call_package_variant = value._callPackageVariant;
78-
is_derivation = pkgs.lib.isDerivation value;
79-
location = builtins.unsafeGetAttrPos name pkgs;
60+
# See AttributeInfo in ./eval.rs for the meaning of this
61+
attrInfo = name: value: {
62+
location = builtins.unsafeGetAttrPos name pkgs;
63+
attribute_variant =
64+
if ! builtins.isAttrs value then
65+
{ NonAttributeSet = null; }
66+
else
67+
{
68+
AttributeSet = {
69+
is_derivation = pkgs.lib.isDerivation value;
70+
definition_variant =
71+
if ! value ? _callPackageVariant then
72+
{ ManualDefinition.is_semantic_call_package = false; }
73+
else
74+
value._callPackageVariant;
75+
};
8076
};
81-
};
77+
};
8278

79+
# Information on all attributes that are in pkgs/by-name.
8380
byNameAttrs = builtins.listToAttrs (map (name: {
8481
inherit name;
8582
value.ByName =
8683
if ! pkgs ? ${name} then
8784
{ Missing = null; }
8885
else
86+
# Evaluation failures are not allowed, so don't try to catch them
8987
{ Existing = attrInfo name pkgs.${name}; };
9088
}) attrs);
9189

9290
# Information on all attributes that exist but are not in pkgs/by-name.
9391
# We need this to enforce pkgs/by-name for new packages
9492
nonByNameAttrs = builtins.mapAttrs (name: value:
9593
let
94+
# Packages outside `pkgs/by-name` often fail evaluation,
95+
# so we need to handle that
9696
output = attrInfo name value;
9797
result = builtins.tryEval (builtins.deepSeq output null);
9898
in

0 commit comments

Comments
 (0)