blob: 7179951d41cf0b90e4142fbc78634280f7bee906 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
# Takes a path to nixpkgs and a path to the json-encoded list of attributes to check.
# Returns an value containing information on each requested attribute,
# which is decoded on the Rust side.
# See ./eval.rs for the meaning of the returned values
{
attrsPath,
nixpkgsPath,
}:
let
attrs = builtins.fromJSON (builtins.readFile attrsPath);
nixpkgsPathLength = builtins.stringLength (toString nixpkgsPath) + 1;
removeNixpkgsPrefix = builtins.substring nixpkgsPathLength (-1);
# We need access to the `callPackage` arguments of each attribute.
# The only way to do so is to override `callPackage` with our own version that adds this information to the result,
# and then try to access this information.
overlay = final: prev: {
# Information for attributes defined using `callPackage`
callPackage = fn: args:
addVariantInfo (prev.callPackage fn args) {
Manual = {
path =
if builtins.isPath fn then
removeNixpkgsPrefix (toString fn)
else
null;
empty_arg =
args == { };
};
};
# Information for attributes that are auto-called from pkgs/by-name.
# This internal attribute is only used by pkgs/by-name
_internalCallByNamePackageFile = file:
addVariantInfo (prev._internalCallByNamePackageFile file) {
Auto = null;
};
};
# We can't just replace attribute values with their info in the overlay,
# because attributes can depend on other attributes, so this would break evaluation.
addVariantInfo = value: variant:
if builtins.isAttrs value then
value // {
_callPackageVariant = variant;
}
else
# It's very rare that callPackage doesn't return an attribute set, but it can occur.
# In such a case we can't really return anything sensible that would include the info,
# so just don't return the info and let the consumer handle it.
value;
pkgs = import nixpkgsPath {
# Don't let the users home directory influence this result
config = { };
overlays = [ overlay ];
# We check evaluation and callPackage only for x86_64-linux.
# Not ideal, but hard to fix
system = "x86_64-linux";
};
attrInfo = name: value:
if ! builtins.isAttrs value then
{
NonAttributeSet = null;
}
else if ! value ? _callPackageVariant then
{
NonCallPackage = null;
}
else
{
CallPackage = {
call_package_variant = value._callPackageVariant;
is_derivation = pkgs.lib.isDerivation value;
location = builtins.unsafeGetAttrPos name pkgs;
};
};
byNameAttrs = builtins.listToAttrs (map (name: {
inherit name;
value.ByName =
if ! pkgs ? ${name} then
{ Missing = null; }
else
{ Existing = attrInfo name pkgs.${name}; };
}) attrs);
# Information on all attributes that exist but are not in pkgs/by-name.
# We need this to enforce pkgs/by-name for new packages
nonByNameAttrs = builtins.mapAttrs (name: value:
let
output = attrInfo name value;
result = builtins.tryEval (builtins.deepSeq output null);
in
{
NonByName =
if result.success then
{ EvalSuccess = output; }
else
{ EvalFailure = null; };
}
) (builtins.removeAttrs pkgs attrs);
# All attributes
attributes = byNameAttrs // nonByNameAttrs;
in
# We output them in the form [ [ <name> <value> ] ]` such that the Rust side
# doesn't need to sort them again to get deterministic behavior (good for testing)
map (name: [
name
attributes.${name}
]) (builtins.attrNames attributes)
|