aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libexpr/flake/flake.cc53
-rw-r--r--src/libexpr/flake/flake.hh5
-rw-r--r--src/libexpr/flake/lockfile.cc16
-rw-r--r--src/libexpr/flake/lockfile.hh2
-rw-r--r--src/nix/installables.cc8
-rw-r--r--tests/flakes.sh7
6 files changed, 76 insertions, 15 deletions
diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc
index c752eeedc..a8f05efb6 100644
--- a/src/libexpr/flake/flake.cc
+++ b/src/libexpr/flake/flake.cc
@@ -394,7 +394,13 @@ LockedFlake lockFlake(
continue;
}
- auto oldLock = oldLocks.inputs.find(id);
+ /* Do we have an entry in the existing lock file? And
+ we don't have a --update-input flag for this
+ input? */
+ auto oldLock =
+ lockFlags.inputUpdates.count(inputPath)
+ ? oldLocks.inputs.end()
+ : oldLocks.inputs.find(id);
if (oldLock != oldLocks.inputs.end() && oldLock->second.originalRef == input.ref && !hasOverride) {
/* Copy the input from the old lock file if its
@@ -402,22 +408,39 @@ LockedFlake lockFlake(
from a higher level flake. */
newLocks.inputs.insert_or_assign(id, oldLock->second);
- /* However there may be new overrides on the
- inputs of this flake, so we need to check those
- (without fetching this flake - we need to be
- lazy). */
- FlakeInputs fakeInputs;
+ /* If we have an --update-input flag for an input
+ of this input, then we must fetch the flake to
+ to update it. */
+ auto lb = lockFlags.inputUpdates.lower_bound(inputPath);
- for (auto & i : oldLock->second.inputs) {
- fakeInputs.emplace(i.first, FlakeInput {
- .ref = i.second.originalRef
- });
- }
+ auto hasChildUpdate =
+ lb != lockFlags.inputUpdates.end()
+ && lb->size() > inputPath.size()
+ && std::equal(inputPath.begin(), inputPath.end(), lb->begin());
+
+ if (hasChildUpdate) {
+ auto inputFlake = getFlake(state, oldLock->second.ref, false, flakeCache);
+
+ updateLocks(inputFlake.inputs,
+ (const LockedInputs &) oldLock->second,
+ newLocks.inputs.find(id)->second,
+ inputPath);
- updateLocks(fakeInputs,
- oldLock->second,
- newLocks.inputs.find(id)->second,
- inputPath);
+ } else {
+ /* No need to fetch this flake, we can be
+ lazy. However there may be new overrides on
+ the inputs of this flake, so we need to
+ check those. */
+ FlakeInputs fakeInputs;
+
+ for (auto & i : oldLock->second.inputs)
+ fakeInputs.emplace(i.first, FlakeInput { .ref = i.second.originalRef });
+
+ updateLocks(fakeInputs,
+ oldLock->second,
+ newLocks.inputs.find(id)->second,
+ inputPath);
+ }
} else {
/* We need to update/create a new lock file
diff --git a/src/libexpr/flake/flake.hh b/src/libexpr/flake/flake.hh
index 355e22adc..fd03faf13 100644
--- a/src/libexpr/flake/flake.hh
+++ b/src/libexpr/flake/flake.hh
@@ -78,7 +78,12 @@ struct LockFlags
allowed. */
bool allowMutable = true;
+ /* Flake inputs to be overriden. */
std::map<InputPath, FlakeRef> inputOverrides;
+
+ /* Flake inputs to be updated. This means that any existing lock
+ for those inputs will be ignored. */
+ std::set<InputPath> inputUpdates;
};
LockedFlake lockFlake(
diff --git a/src/libexpr/flake/lockfile.cc b/src/libexpr/flake/lockfile.cc
index b92ffb70e..edb7628fd 100644
--- a/src/libexpr/flake/lockfile.cc
+++ b/src/libexpr/flake/lockfile.cc
@@ -72,6 +72,22 @@ std::optional<LockedInput *> LockedInputs::findInput(const InputPath & path)
return (LockedInput *) pos;
}
+void LockedInputs::removeInput(const InputPath & path)
+{
+ assert(!path.empty());
+
+ LockedInputs * pos = this;
+
+ for (size_t n = 0; n < path.size(); n++) {
+ auto i = pos->inputs.find(path[n]);
+ if (i == pos->inputs.end()) return;
+ if (n + 1 == path.size())
+ pos->inputs.erase(i);
+ else
+ pos = &i->second;
+ }
+}
+
nlohmann::json LockFile::toJson() const
{
auto json = LockedInputs::toJson();
diff --git a/src/libexpr/flake/lockfile.hh b/src/libexpr/flake/lockfile.hh
index 626c7d9e0..ff1181d13 100644
--- a/src/libexpr/flake/lockfile.hh
+++ b/src/libexpr/flake/lockfile.hh
@@ -27,6 +27,8 @@ struct LockedInputs
bool isImmutable() const;
std::optional<LockedInput *> findInput(const InputPath & path);
+
+ void removeInput(const InputPath & path);
};
/* Lock file information about a flake input. */
diff --git a/src/nix/installables.cc b/src/nix/installables.cc
index 24eb739f5..77a43ef2a 100644
--- a/src/nix/installables.cc
+++ b/src/nix/installables.cc
@@ -40,6 +40,14 @@ MixFlakeOptions::MixFlakeOptions()
.set(&lockFlags.useRegistries, false);
mkFlag()
+ .longName("update-input")
+ .description("update a specific flake input")
+ .label("input-path")
+ .handler([&](std::vector<std::string> ss) {
+ lockFlags.inputUpdates.insert(flake::parseInputPath(ss[0]));
+ });
+
+ mkFlag()
.longName("override-input")
.description("override a specific flake input (e.g. 'dwarffs/nixpkgs')")
.arity(2)
diff --git a/tests/flakes.sh b/tests/flakes.sh
index 3eae73cdf..6d2ee80f1 100644
--- a/tests/flakes.sh
+++ b/tests/flakes.sh
@@ -610,3 +610,10 @@ nix flake update $flake3Dir --override-input flake2/flake1 flake1
nix flake update $flake3Dir --override-input flake2/flake1 flake1/master/$hash1
[[ $(jq .inputs.flake2.inputs.flake1.url $flake3Dir/flake.lock) =~ flake1.*rev=$hash1 ]]
+
+# Test --update-input.
+nix flake update $flake3Dir
+[[ $(jq .inputs.flake2.inputs.flake1.url $flake3Dir/flake.lock) =~ flake1.*rev=$hash1 ]]
+
+nix flake update $flake3Dir --update-input flake2/flake1
+[[ $(jq .inputs.flake2.inputs.flake1.url $flake3Dir/flake.lock) =~ flake1.*rev=$hash2 ]]