Skip to content

Commit d25a606

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 6643694 commit d25a606

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
@@ -99,6 +99,7 @@ static FlakeInput parseFlakeInput(
9999
auto sUrl = state.symbols.create("url");
100100
auto sFlake = state.symbols.create("flake");
101101
auto sFollows = state.symbols.create("follows");
102+
auto sBuildTime = state.symbols.create("buildTime");
102103

103104
fetchers::Attrs attrs;
104105
std::optional<std::string> url;
@@ -123,6 +124,9 @@ static FlakeInput parseFlakeInput(
123124
} else if (attr.name == sFlake) {
124125
expectType(state, nBool, *attr.value, attr.pos);
125126
input.isFlake = attr.value->boolean();
127+
} else if (attr.name == sBuildTime) {
128+
expectType(state, nBool, *attr.value, attr.pos);
129+
input.buildTime = attr.value->boolean();
126130
} else if (attr.name == sInputs) {
127131
input.overrides = parseFlakeInputs(state, attr.value, attr.pos, lockRootAttrPath, flakeDir, false).first;
128132
} else if (attr.name == sFollows) {
@@ -593,6 +597,7 @@ LockedFlake lockFlake(
593597
oldLock->lockedRef,
594598
oldLock->originalRef,
595599
oldLock->isFlake,
600+
oldLock->buildTime,
596601
oldLock->parentInputAttrPath);
597602

598603
node->inputs.insert_or_assign(id, childNode);
@@ -702,6 +707,7 @@ LockedFlake lockFlake(
702707
inputFlake.lockedRef,
703708
ref,
704709
true,
710+
input.buildTime,
705711
overridenParentPath);
706712

707713
node->inputs.insert_or_assign(id, childNode);
@@ -751,7 +757,7 @@ LockedFlake lockFlake(
751757
}
752758
}();
753759

754-
auto childNode = make_ref<LockedNode>(lockedRef, ref, false, overridenParentPath);
760+
auto childNode = make_ref<LockedNode>(lockedRef, ref, false, input.buildTime, overridenParentPath);
755761

756762
nodePaths.emplace(childNode, path);
757763

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)