-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathdefault.nix
More file actions
153 lines (140 loc) · 5.1 KB
/
default.nix
File metadata and controls
153 lines (140 loc) · 5.1 KB
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# Flake-inputs adapter.
#
# Mirrors flake inputs resolution without fetching or locking.
# Expects pre-fetched sources (npins, unflake, local paths, anything with .outPath).
#
# sources: attrset of name -> sourceInfo (e.g. from npins)
# inputs: attrset mirroring the `inputs` block of a flake.nix:
# someLib.outPath = ./someLib; local checkout (loaded as flake if possible)
# b.follows = "a"; alias to allInputs.a
# b.follows = "a/x/y"; nested follows
# b.follows = ""; intentionally empty
# a.inputs.b.follows = "nixpkgs"; per-sub-input follows override
# a = { outPath = ./a; inputs.b.follows = "x"; }; outPath + sub-input overrides
# a = anyValue; direct value (function, attrset, …)
sources: inputsOverrides:
let
inputs =
if builtins.isAttrs inputsOverrides then inputsOverrides else (__functor allInputs) inputsOverrides;
splitPath = s: builtins.filter builtins.isString (builtins.split "/" s);
isFollows = v: builtins.isAttrs v && v ? follows;
specKeys = [
"follows"
"inputs"
];
# A spec is an attrset whose only keys are "follows" and/or "inputs",
# where every inputs.* value is itself a follows spec.
# Anything with outPath, lib, packages, … is a direct value, not a spec.
isSpec =
v:
builtins.isAttrs v
&& builtins.all (x: builtins.elem x specKeys) (builtins.attrNames v)
&& (!(v ? inputs) || builtins.all (k: isFollows v.inputs.${k}) (builtins.attrNames v.inputs));
# Returns the resolved input, or null if any segment in the path is missing.
walkPath =
path:
let
segs = splitPath path;
root = allInputs.${builtins.head segs} or null;
in
builtins.foldl' (node: seg: if node == null then null else node.inputs.${seg} or null) root (
builtins.tail segs
);
# Per-sub-input override spec from inputs.${hostName}.inputs.${subName}.
# Works regardless of whether the decl entry also has outPath or other fields.
overrideSubSpec =
hostName: subName:
let
entry = inputs.${hostName} or null;
in
if entry != null && builtins.isAttrs entry && entry ? inputs then
entry.inputs.${subName} or null
else
null;
# Resolve an inputs entry to an actual input value, or null if unresolvable.
# Values with outPath but no _type go through mkInput so their flake.nix is loaded.
resolveInput =
name: v:
if builtins.isFunction v then
resolveInput name (v sources.${name})
else if isFollows v then
if v.follows == "" then { } else walkPath v.follows
else if isSpec v then
resolvedSources.${name} or { }
else if v ? outPath && !(v ? _type) then
mkInput name v
else
v;
resolveSubInput =
hostName: subName: declaredSpec:
let
ov = overrideSubSpec hostName subName;
spec = if ov != null then ov else declaredSpec;
walked = if isFollows spec then walkPath spec.follows else null;
fromAll = allInputs.${subName} or null;
in
if isFollows spec then
if spec.follows == "" then
{ }
else if walked == null then
{ }
else
walked
else if fromAll == null then
{ }
else
fromAll;
mkInput =
name: sourceInfo:
let
isFlake = sourceInfo.flake or true;
flakePath = sourceInfo.outPath + "/flake.nix";
flakeExists = sourceInfo ? outPath && builtins.pathExists flakePath;
in
if isFlake && flakeExists then
mkFlakeInput name sourceInfo (import flakePath)
else
sourceInfo // { inherit sourceInfo; };
mkFlakeInput =
name: sourceInfo: flake:
let
specs = flake.inputs or { };
inputs = builtins.mapAttrs (sub: spec: resolveSubInput name sub spec) specs;
indirect = builtins.mapAttrs (sub: _: resolveSubInput name sub { }) (
builtins.functionArgs flake.outputs
);
outputs = flake.outputs (indirect // inputs // { inherit self; });
self =
sourceInfo
// outputs
// {
_type = "flake";
inherit inputs outputs sourceInfo;
};
in
self;
resolvedSources = builtins.mapAttrs mkInput sources;
# Shallow merge is correct: each key is fully resolved before this point.
# Sub-input overrides (inputs.foo.inputs.bar.follows) are injected into
# resolvedSources at resolution time via overrideSubSpec, so no deep merge
# of resolvedSources and resolvedInputs is needed or wanted.
resolvedInputs = builtins.mapAttrs resolveInput inputs;
allInputs = resolvedSources // resolvedInputs;
__functor =
allInputs: outputsFn:
let
# inputs mirrors a real flake: self is included so modules can access
# inputs.self.inputs, inputs.self.outputs, and inputs.self.outPath.
inputs = allInputs // {
inherit self;
};
outputs = outputsFn inputs;
# self exposes .inputs and .outputs like a real flake self, with all
# output attributes merged at top level for direct attribute access.
self = outputs // {
inherit inputs outputs;
};
in
self;
in
allInputs // { inherit __functor; }