mirror of
https://github.com/privatevoid-net/nix-super.git
synced 2024-11-22 14:06:16 +02:00
Merge pull request #9169 from vkryachko/follow_cycle
Detect cycles in flake follows.
This commit is contained in:
commit
c1a1766c46
2 changed files with 52 additions and 4 deletions
|
@ -2,8 +2,10 @@
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
#include "url-parts.hh"
|
#include "url-parts.hh"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
|
||||||
|
#include <iterator>
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
namespace nix::flake {
|
namespace nix::flake {
|
||||||
|
@ -45,16 +47,26 @@ StorePath LockedNode::computeStorePath(Store & store) const
|
||||||
return lockedRef.input.computeStorePath(store);
|
return lockedRef.input.computeStorePath(store);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Node> LockFile::findInput(const InputPath & path)
|
|
||||||
{
|
static std::shared_ptr<Node> doFind(const ref<Node>& root, const InputPath & path, std::vector<InputPath>& visited) {
|
||||||
auto pos = root;
|
auto pos = root;
|
||||||
|
|
||||||
|
auto found = std::find(visited.cbegin(), visited.cend(), path);
|
||||||
|
|
||||||
|
if(found != visited.end()) {
|
||||||
|
std::vector<std::string> cycle;
|
||||||
|
std::transform(found, visited.cend(), std::back_inserter(cycle), printInputPath);
|
||||||
|
cycle.push_back(printInputPath(path));
|
||||||
|
throw Error("follow cycle detected: [%s]", concatStringsSep(" -> ", cycle));
|
||||||
|
}
|
||||||
|
visited.push_back(path);
|
||||||
|
|
||||||
for (auto & elem : path) {
|
for (auto & elem : path) {
|
||||||
if (auto i = get(pos->inputs, elem)) {
|
if (auto i = get(pos->inputs, elem)) {
|
||||||
if (auto node = std::get_if<0>(&*i))
|
if (auto node = std::get_if<0>(&*i))
|
||||||
pos = *node;
|
pos = *node;
|
||||||
else if (auto follows = std::get_if<1>(&*i)) {
|
else if (auto follows = std::get_if<1>(&*i)) {
|
||||||
if (auto p = findInput(*follows))
|
if (auto p = doFind(root, *follows, visited))
|
||||||
pos = ref(p);
|
pos = ref(p);
|
||||||
else
|
else
|
||||||
return {};
|
return {};
|
||||||
|
@ -66,6 +78,12 @@ std::shared_ptr<Node> LockFile::findInput(const InputPath & path)
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Node> LockFile::findInput(const InputPath & path)
|
||||||
|
{
|
||||||
|
std::vector<InputPath> visited;
|
||||||
|
return doFind(root, path, visited);
|
||||||
|
}
|
||||||
|
|
||||||
LockFile::LockFile(const nlohmann::json & json, const Path & path)
|
LockFile::LockFile(const nlohmann::json & json, const Path & path)
|
||||||
{
|
{
|
||||||
auto version = json.value("version", 0);
|
auto version = json.value("version", 0);
|
||||||
|
|
|
@ -167,7 +167,7 @@ nix flake lock "$flakeFollowsA" 2>&1 | grep "warning: input 'B' has an override
|
||||||
#
|
#
|
||||||
# The message was
|
# The message was
|
||||||
# error: input 'B/D' follows a non-existent input 'B/C/D'
|
# error: input 'B/D' follows a non-existent input 'B/C/D'
|
||||||
#
|
#
|
||||||
# Note that for `B` to resolve its follow for `D`, it needs `C/D`, for which it needs to resolve the follow on `C` first.
|
# Note that for `B` to resolve its follow for `D`, it needs `C/D`, for which it needs to resolve the follow on `C` first.
|
||||||
flakeFollowsOverloadA="$TEST_ROOT/follows/overload/flakeA"
|
flakeFollowsOverloadA="$TEST_ROOT/follows/overload/flakeA"
|
||||||
flakeFollowsOverloadB="$TEST_ROOT/follows/overload/flakeA/flakeB"
|
flakeFollowsOverloadB="$TEST_ROOT/follows/overload/flakeA/flakeB"
|
||||||
|
@ -230,3 +230,33 @@ git -C "$flakeFollowsOverloadA" add flake.nix flakeB/flake.nix \
|
||||||
nix flake metadata "$flakeFollowsOverloadA"
|
nix flake metadata "$flakeFollowsOverloadA"
|
||||||
nix flake update "$flakeFollowsOverloadA"
|
nix flake update "$flakeFollowsOverloadA"
|
||||||
nix flake lock "$flakeFollowsOverloadA"
|
nix flake lock "$flakeFollowsOverloadA"
|
||||||
|
|
||||||
|
# Now test follow cycle detection
|
||||||
|
# We construct the following follows graph:
|
||||||
|
#
|
||||||
|
# foo
|
||||||
|
# / ^
|
||||||
|
# / \
|
||||||
|
# v \
|
||||||
|
# bar -> baz
|
||||||
|
# The message was
|
||||||
|
# error: follow cycle detected: [baz -> foo -> bar -> baz]
|
||||||
|
flakeFollowCycle="$TEST_ROOT/follows/followCycle"
|
||||||
|
|
||||||
|
# Test following path flakerefs.
|
||||||
|
mkdir -p "$flakeFollowCycle"
|
||||||
|
|
||||||
|
cat > $flakeFollowCycle/flake.nix <<EOF
|
||||||
|
{
|
||||||
|
description = "Flake A";
|
||||||
|
inputs = {
|
||||||
|
foo.follows = "bar";
|
||||||
|
bar.follows = "baz";
|
||||||
|
baz.follows = "foo";
|
||||||
|
};
|
||||||
|
outputs = { ... }: {};
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
checkRes=$(nix flake lock "$flakeFollowCycle" 2>&1 && fail "nix flake lock should have failed." || true)
|
||||||
|
echo $checkRes | grep -F "error: follow cycle detected: [baz -> foo -> bar -> baz]"
|
||||||
|
|
Loading…
Reference in a new issue