aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2020-01-29 23:12:58 +0100
committerEelco Dolstra <edolstra@gmail.com>2020-01-29 23:14:27 +0100
commitb9fb3720750a24d8b2fbe6b1491696d6a51dcff3 (patch)
tree27bef94799d20261c9b49e43bbcd1907a107fde9 /src/libexpr
parent88b44b1e94735710853bdabb6904073bc77f2ccb (diff)
Add --update-input flag to update a specific flake input
Typical usage: $ nix flake update ~/Misc/eelco-configurations/hagbard --update-input nixpkgs to update the 'nixpkgs' input of a flake while leaving every other input unchanged. The argument is an input path, so you can do e.g. '--update-input dwarffs/nixpkgs' to update an input of an input. Fixes #2928.
Diffstat (limited to 'src/libexpr')
-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
4 files changed, 61 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. */