Skip to content

Commit 6f3dd65

Browse files
authored
Merge pull request NixOS#12755 from NixOS/mergify/bp/2.27-maintenance/pr-12105
local-derivation-goal: improve "illegal reference" error (backport NixOS#12105)
2 parents 01ffee0 + cadfed6 commit 6f3dd65

File tree

6 files changed

+75
-2
lines changed

6 files changed

+75
-2
lines changed

src/libstore/unix/build/local-derivation-goal.cc

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2920,8 +2920,12 @@ void LocalDerivationGoal::checkOutputs(const std::map<std::string, ValidPathInfo
29202920
spec.insert(worker.store.parseStorePath(i));
29212921
else if (auto output = get(outputs, i))
29222922
spec.insert(output->path);
2923-
else
2924-
throw BuildError("derivation contains an illegal reference specifier '%s'", i);
2923+
else {
2924+
std::string outputsListing = concatMapStringsSep(", ", outputs, [](auto & o) { return o.first; });
2925+
throw BuildError("derivation '%s' output check for '%s' contains an illegal reference specifier '%s',"
2926+
" expected store path or output name (one of [%s])",
2927+
worker.store.printStorePath(drvPath), outputName, i, outputsListing);
2928+
}
29252929
}
29262930

29272931
auto used = recursive

src/libutil-tests/strings.cc

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,42 @@ TEST(concatStringsSep, buildSingleString)
8080
ASSERT_EQ(concatStringsSep(",", strings), "this");
8181
}
8282

83+
TEST(concatMapStringsSep, empty)
84+
{
85+
Strings strings;
86+
87+
ASSERT_EQ(concatMapStringsSep(",", strings, [](const std::string & s) { return s; }), "");
88+
}
89+
90+
TEST(concatMapStringsSep, justOne)
91+
{
92+
Strings strings;
93+
strings.push_back("this");
94+
95+
ASSERT_EQ(concatMapStringsSep(",", strings, [](const std::string & s) { return s; }), "this");
96+
}
97+
98+
TEST(concatMapStringsSep, two)
99+
{
100+
Strings strings;
101+
strings.push_back("this");
102+
strings.push_back("that");
103+
104+
ASSERT_EQ(concatMapStringsSep(",", strings, [](const std::string & s) { return s; }), "this,that");
105+
}
106+
107+
TEST(concatMapStringsSep, map)
108+
{
109+
std::map<std::string, std::string> strings;
110+
strings["this"] = "that";
111+
strings["1"] = "one";
112+
113+
ASSERT_EQ(
114+
concatMapStringsSep(
115+
", ", strings, [](const std::pair<std::string, std::string> & s) { return s.first + " -> " + s.second; }),
116+
"1 -> one, this -> that");
117+
}
118+
83119
/* ----------------------------------------------------------------------------
84120
* dropEmptyInitThenConcatStringsSep
85121
* --------------------------------------------------------------------------*/

src/libutil/strings.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ basicSplitString(std::basic_string_view<OsChar> s, std::basic_string_view<OsChar
3737
template std::string concatStringsSep(std::string_view, const std::list<std::string> &);
3838
template std::string concatStringsSep(std::string_view, const std::set<std::string> &);
3939
template std::string concatStringsSep(std::string_view, const std::vector<std::string> &);
40+
template std::string concatStringsSep(std::string_view, const boost::container::small_vector<std::string, 64> &);
4041

4142
typedef std::string_view strings_2[2];
4243
template std::string concatStringsSep(std::string_view, const strings_2 &);

src/libutil/strings.hh

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
#include <string>
77
#include <vector>
88

9+
#include <boost/container/small_vector.hpp>
10+
911
namespace nix {
1012

1113
/*
@@ -54,6 +56,21 @@ std::string concatStringsSep(const std::string_view sep, const C & ss);
5456
extern template std::string concatStringsSep(std::string_view, const std::list<std::string> &);
5557
extern template std::string concatStringsSep(std::string_view, const std::set<std::string> &);
5658
extern template std::string concatStringsSep(std::string_view, const std::vector<std::string> &);
59+
extern template std::string concatStringsSep(std::string_view, const boost::container::small_vector<std::string, 64> &);
60+
61+
/**
62+
* Apply a function to the `iterable`'s items and concat them with `separator`.
63+
*/
64+
template<class C, class F>
65+
std::string concatMapStringsSep(std::string_view separator, const C & iterable, F fn)
66+
{
67+
boost::container::small_vector<std::string, 64> strings;
68+
strings.reserve(iterable.size());
69+
for (const auto & elem : iterable) {
70+
strings.push_back(fn(elem));
71+
}
72+
return concatStringsSep(separator, strings);
73+
}
5774

5875
/**
5976
* Ignore any empty strings at the start of the list, and then concatenate the

tests/functional/check-refs.nix

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,13 @@ rec {
7979
buildCommand = ''echo ${dep} > "''${outputs[out]}"'';
8080
};
8181

82+
test12 = makeTest 12 {
83+
builder = builtins.toFile "builder.sh" "mkdir $out $lib";
84+
outputs = [
85+
"out"
86+
"lib"
87+
];
88+
disallowedReferences = [ "dev" ];
89+
};
90+
8291
}

tests/functional/check-refs.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,9 @@ if ! isTestOnNixOS; then
6060
fi
6161

6262
fi
63+
64+
if isDaemonNewer "2.28pre20241225"; then
65+
# test12 should fail (syntactically invalid).
66+
expectStderr 1 nix-build -vvv -o "$RESULT" check-refs.nix -A test12 >"$TEST_ROOT/test12.stderr"
67+
grepQuiet -F "output check for 'lib' contains an illegal reference specifier 'dev', expected store path or output name (one of [lib, out])" < "$TEST_ROOT/test12.stderr"
68+
fi

0 commit comments

Comments
 (0)