Skip to content

Commit 7db9c65

Browse files
committed
Allow flake inputs to be fetched at build time
This only works for non-flake inputs. Example: inputs.repo1 = { type = "github"; owner = "DeterminateSystems"; repo = "blabla"; flake = false; buildTime = true; }; `call-flake.nix` maps this to a builtin:fetch-tree derivation. Thus you can pass it to other derivations, and it will be fetched at build time rather than eval time. (It will still be fetched at eval time to create/update locks.) Importing from such an input triggers IFD.
1 parent 7dfd8e8 commit 7db9c65

File tree

5 files changed

+34
-5
lines changed

5 files changed

+34
-5
lines changed

src/libflake/call-flake.nix

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,17 @@ let
5050
if node ? parent then parentDir + ("/" + dir) else dir;
5151

5252
sourceInfo =
53-
if overrides ? ${key} then
53+
if node.buildTime or false then
54+
derivation {
55+
name = "source";
56+
builder = "builtin:fetch-tree";
57+
system = "builtin";
58+
__structuredAttrs = true;
59+
input = node.locked;
60+
outputHashMode = "recursive";
61+
outputHash = node.locked.narHash;
62+
}
63+
else if overrides ? ${key} then
5464
overrides.${key}.sourceInfo
5565
else if node.locked.type == "path" && builtins.substring 0 1 node.locked.path != "/" then
5666
parentNode.sourceInfo
@@ -97,6 +107,7 @@ let
97107
result =
98108
if node.flake or true then
99109
assert builtins.isFunction flake.outputs;
110+
assert !(node.buildTime or false);
100111
result
101112
else
102113
sourceInfo;

src/libflake/flake.cc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ static FlakeInput parseFlakeInput(
171171
auto sUrl = state.symbols.create("url");
172172
auto sFlake = state.symbols.create("flake");
173173
auto sFollows = state.symbols.create("follows");
174+
auto sBuildTime = state.symbols.create("buildTime");
174175

175176
fetchers::Attrs attrs;
176177
std::optional<std::string> url;
@@ -195,6 +196,9 @@ static FlakeInput parseFlakeInput(
195196
} else if (attr.name == sFlake) {
196197
expectType(state, nBool, *attr.value, attr.pos);
197198
input.isFlake = attr.value->boolean();
199+
} else if (attr.name == sBuildTime) {
200+
expectType(state, nBool, *attr.value, attr.pos);
201+
input.buildTime = attr.value->boolean();
198202
} else if (attr.name == sInputs) {
199203
input.overrides = parseFlakeInputs(state, attr.value, attr.pos, lockRootAttrPath, flakeDir, false).first;
200204
} else if (attr.name == sFollows) {
@@ -667,6 +671,7 @@ LockedFlake lockFlake(
667671
oldLock->lockedRef,
668672
oldLock->originalRef,
669673
oldLock->isFlake,
674+
oldLock->buildTime,
670675
oldLock->parentInputAttrPath);
671676

672677
node->inputs.insert_or_assign(id, childNode);
@@ -776,6 +781,7 @@ LockedFlake lockFlake(
776781
inputFlake.lockedRef,
777782
ref,
778783
true,
784+
input.buildTime,
779785
overridenParentPath);
780786

781787
node->inputs.insert_or_assign(id, childNode);
@@ -823,7 +829,7 @@ LockedFlake lockFlake(
823829
}
824830
}();
825831

826-
auto childNode = make_ref<LockedNode>(lockedRef, ref, false, overridenParentPath);
832+
auto childNode = make_ref<LockedNode>(lockedRef, ref, false, input.buildTime, overridenParentPath);
827833

828834
nodePaths.emplace(childNode, path);
829835

src/libflake/include/nix/flake/flake.hh

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,18 @@ typedef std::map<FlakeId, FlakeInput> FlakeInputs;
4343
struct FlakeInput
4444
{
4545
std::optional<FlakeRef> ref;
46+
4647
/**
47-
* true = process flake to get outputs
48-
*
49-
* false = (fetched) static source path
48+
* Whether to call the `flake.nix` file in this input to get its outputs.
5049
*/
5150
bool isFlake = true;
51+
52+
/**
53+
* Whether to fetch this input at evaluation time or at build
54+
* time.
55+
*/
56+
bool buildTime = false;
57+
5258
std::optional<InputAttrPath> follows;
5359
FlakeInputs overrides;
5460
};

src/libflake/include/nix/flake/lockfile.hh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ struct LockedNode : Node
3737
{
3838
FlakeRef lockedRef, originalRef;
3939
bool isFlake = true;
40+
bool buildTime = false;
4041

4142
/* The node relative to which relative source paths
4243
(e.g. 'path:../foo') are interpreted. */
@@ -46,10 +47,12 @@ struct LockedNode : Node
4647
const FlakeRef & lockedRef,
4748
const FlakeRef & originalRef,
4849
bool isFlake = true,
50+
bool buildTime = false,
4951
std::optional<InputAttrPath> parentInputAttrPath = {})
5052
: lockedRef(std::move(lockedRef))
5153
, originalRef(std::move(originalRef))
5254
, isFlake(isFlake)
55+
, buildTime(buildTime)
5356
, parentInputAttrPath(std::move(parentInputAttrPath))
5457
{ }
5558

src/libflake/lockfile.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ LockedNode::LockedNode(
4444
: lockedRef(getFlakeRef(fetchSettings, json, "locked", "info")) // FIXME: remove "info"
4545
, originalRef(getFlakeRef(fetchSettings, json, "original", nullptr))
4646
, isFlake(json.find("flake") != json.end() ? (bool) json["flake"] : true)
47+
, buildTime(json.find("buildTime") != json.end() ? (bool) json["buildTime"] : false)
4748
, parentInputAttrPath(json.find("parent") != json.end() ? (std::optional<InputAttrPath>) json["parent"] : std::nullopt)
4849
{
4950
if (!lockedRef.input.isLocked() && !lockedRef.input.isRelative()) {
@@ -216,6 +217,8 @@ std::pair<nlohmann::json, LockFile::KeyMap> LockFile::toJSON() const
216217
n["locked"].erase("__final");
217218
if (!lockedNode->isFlake)
218219
n["flake"] = false;
220+
if (lockedNode->buildTime)
221+
n["buildTime"] = true;
219222
if (lockedNode->parentInputAttrPath)
220223
n["parent"] = *lockedNode->parentInputAttrPath;
221224
}

0 commit comments

Comments
 (0)