From bebb79ef58ccf7932afab7da84519a97b7932314 Mon Sep 17 00:00:00 2001 From: Sergei Trofimovich Date: Wed, 25 Dec 2024 21:09:58 +0000 Subject: [PATCH 1/7] local-derivation-goal: improve "illegal reference" error Before the change "illegal reference" was hard to interpret as it did not mention what derivation actually hits it. Today's `nixpkgs` example: Before the change: $ nix build --no-link -f. postgresql_14 ... error: derivation contains an illegal reference specifier 'man' After the change: $ nix build --no-link -f. postgresql_14 ... error: derivation '/nix/store/bxp6g57limvwiga61vdlyvhy7i8rp6wd-postgresql-14.15.drv' output check for 'lib' contains an illegal reference specifier 'man', expected store path or output name (one of [debug, dev, doc, lib, out]) (cherry picked from commit bbdc3197a925b56bdec1220089de7622832bd2a3) --- src/libstore/unix/build/local-derivation-goal.cc | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/libstore/unix/build/local-derivation-goal.cc b/src/libstore/unix/build/local-derivation-goal.cc index f8824e9ce..61785990b 100644 --- a/src/libstore/unix/build/local-derivation-goal.cc +++ b/src/libstore/unix/build/local-derivation-goal.cc @@ -2899,8 +2899,17 @@ void LocalDerivationGoal::checkOutputs(const std::mappath); - else - throw BuildError("derivation contains an illegal reference specifier '%s'", i); + else { + std::string allOutputs; + for (auto & o : outputs) { + if (! allOutputs.empty()) + allOutputs.append(", "); + allOutputs.append(o.first); + } + throw BuildError("derivation '%s' output check for '%s' contains an illegal reference specifier '%s'," + " expected store path or output name (one of [%s])", + worker.store.printStorePath(drvPath), outputName, i, allOutputs); + } } auto used = recursive From b96ba519d991832327477fc03a2bbbb3468cca54 Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Sat, 18 Jan 2025 09:44:46 +0100 Subject: [PATCH 2/7] nix-util: Add concatMapStrings (cherry picked from commit f3dbaa3f54c54b0a71e230ab097c9a72d17c3ed9) # Conflicts: # src/libutil-tests/strings.cc # src/libutil/strings.hh --- src/libutil-tests/strings.cc | 487 +++++++++++++++++++++++++++++++++++ src/libutil/strings.hh | 37 +++ 2 files changed, 524 insertions(+) create mode 100644 src/libutil-tests/strings.cc diff --git a/src/libutil-tests/strings.cc b/src/libutil-tests/strings.cc new file mode 100644 index 000000000..33a1fae9b --- /dev/null +++ b/src/libutil-tests/strings.cc @@ -0,0 +1,487 @@ +#include +#include + +#include "strings.hh" +#include "error.hh" + +namespace nix { + +/* ---------------------------------------------------------------------------- + * concatStringsSep + * --------------------------------------------------------------------------*/ + +TEST(concatStringsSep, empty) +{ + Strings strings; + + ASSERT_EQ(concatStringsSep(",", strings), ""); +} + +TEST(concatStringsSep, justOne) +{ + Strings strings; + strings.push_back("this"); + + ASSERT_EQ(concatStringsSep(",", strings), "this"); +} + +TEST(concatStringsSep, emptyString) +{ + Strings strings; + strings.push_back(""); + + ASSERT_EQ(concatStringsSep(",", strings), ""); +} + +TEST(concatStringsSep, emptyStrings) +{ + Strings strings; + strings.push_back(""); + strings.push_back(""); + + ASSERT_EQ(concatStringsSep(",", strings), ","); +} + +TEST(concatStringsSep, threeEmptyStrings) +{ + Strings strings; + strings.push_back(""); + strings.push_back(""); + strings.push_back(""); + + ASSERT_EQ(concatStringsSep(",", strings), ",,"); +} + +TEST(concatStringsSep, buildCommaSeparatedString) +{ + Strings strings; + strings.push_back("this"); + strings.push_back("is"); + strings.push_back("great"); + + ASSERT_EQ(concatStringsSep(",", strings), "this,is,great"); +} + +TEST(concatStringsSep, buildStringWithEmptySeparator) +{ + Strings strings; + strings.push_back("this"); + strings.push_back("is"); + strings.push_back("great"); + + ASSERT_EQ(concatStringsSep("", strings), "thisisgreat"); +} + +TEST(concatStringsSep, buildSingleString) +{ + Strings strings; + strings.push_back("this"); + + ASSERT_EQ(concatStringsSep(",", strings), "this"); +} + +TEST(concatMapStringsSep, empty) +{ + Strings strings; + + ASSERT_EQ(concatMapStringsSep(",", strings, [](const std::string & s) { return s; }), ""); +} + +TEST(concatMapStringsSep, justOne) +{ + Strings strings; + strings.push_back("this"); + + ASSERT_EQ(concatMapStringsSep(",", strings, [](const std::string & s) { return s; }), "this"); +} + +TEST(concatMapStringsSep, two) +{ + Strings strings; + strings.push_back("this"); + strings.push_back("that"); + + ASSERT_EQ(concatMapStringsSep(",", strings, [](const std::string & s) { return s; }), "this,that"); +} + +TEST(concatMapStringsSep, map) +{ + std::map strings; + strings["this"] = "that"; + strings["1"] = "one"; + + ASSERT_EQ( + concatMapStringsSep( + ", ", strings, [](const std::pair & s) { return s.first + " -> " + s.second; }), + "1 -> one, this -> that"); +} + +/* ---------------------------------------------------------------------------- + * dropEmptyInitThenConcatStringsSep + * --------------------------------------------------------------------------*/ + +TEST(dropEmptyInitThenConcatStringsSep, empty) +{ + Strings strings; + + ASSERT_EQ(dropEmptyInitThenConcatStringsSep(",", strings), ""); +} + +TEST(dropEmptyInitThenConcatStringsSep, buildCommaSeparatedString) +{ + Strings strings; + strings.push_back("this"); + strings.push_back("is"); + strings.push_back("great"); + + ASSERT_EQ(dropEmptyInitThenConcatStringsSep(",", strings), "this,is,great"); +} + +TEST(dropEmptyInitThenConcatStringsSep, buildStringWithEmptySeparator) +{ + Strings strings; + strings.push_back("this"); + strings.push_back("is"); + strings.push_back("great"); + + ASSERT_EQ(dropEmptyInitThenConcatStringsSep("", strings), "thisisgreat"); +} + +TEST(dropEmptyInitThenConcatStringsSep, buildSingleString) +{ + Strings strings; + strings.push_back("this"); + strings.push_back(""); + + ASSERT_EQ(dropEmptyInitThenConcatStringsSep(",", strings), "this,"); +} + +TEST(dropEmptyInitThenConcatStringsSep, emptyStrings) +{ + Strings strings; + strings.push_back(""); + strings.push_back(""); + + ASSERT_EQ(dropEmptyInitThenConcatStringsSep(",", strings), ""); +} + +/* ---------------------------------------------------------------------------- + * tokenizeString + * --------------------------------------------------------------------------*/ + +TEST(tokenizeString, empty) +{ + Strings expected = {}; + + ASSERT_EQ(tokenizeString(""), expected); +} + +TEST(tokenizeString, oneSep) +{ + Strings expected = {}; + + ASSERT_EQ(tokenizeString(" "), expected); +} + +TEST(tokenizeString, twoSep) +{ + Strings expected = {}; + + ASSERT_EQ(tokenizeString(" \n"), expected); +} + +TEST(tokenizeString, tokenizeSpacesWithDefaults) +{ + auto s = "foo bar baz"; + Strings expected = {"foo", "bar", "baz"}; + + ASSERT_EQ(tokenizeString(s), expected); +} + +TEST(tokenizeString, tokenizeTabsWithDefaults) +{ + auto s = "foo\tbar\tbaz"; + Strings expected = {"foo", "bar", "baz"}; + + ASSERT_EQ(tokenizeString(s), expected); +} + +TEST(tokenizeString, tokenizeTabsSpacesWithDefaults) +{ + auto s = "foo\t bar\t baz"; + Strings expected = {"foo", "bar", "baz"}; + + ASSERT_EQ(tokenizeString(s), expected); +} + +TEST(tokenizeString, tokenizeTabsSpacesNewlineWithDefaults) +{ + auto s = "foo\t\n bar\t\n baz"; + Strings expected = {"foo", "bar", "baz"}; + + ASSERT_EQ(tokenizeString(s), expected); +} + +TEST(tokenizeString, tokenizeTabsSpacesNewlineRetWithDefaults) +{ + auto s = "foo\t\n\r bar\t\n\r baz"; + Strings expected = {"foo", "bar", "baz"}; + + ASSERT_EQ(tokenizeString(s), expected); + + auto s2 = "foo \t\n\r bar \t\n\r baz"; + Strings expected2 = {"foo", "bar", "baz"}; + + ASSERT_EQ(tokenizeString(s2), expected2); +} + +TEST(tokenizeString, tokenizeWithCustomSep) +{ + auto s = "foo\n,bar\n,baz\n"; + Strings expected = {"foo\n", "bar\n", "baz\n"}; + + ASSERT_EQ(tokenizeString(s, ","), expected); +} + +TEST(tokenizeString, tokenizeSepAtStart) +{ + auto s = ",foo,bar,baz"; + Strings expected = {"foo", "bar", "baz"}; + + ASSERT_EQ(tokenizeString(s, ","), expected); +} + +TEST(tokenizeString, tokenizeSepAtEnd) +{ + auto s = "foo,bar,baz,"; + Strings expected = {"foo", "bar", "baz"}; + + ASSERT_EQ(tokenizeString(s, ","), expected); +} + +TEST(tokenizeString, tokenizeSepEmpty) +{ + auto s = "foo,,baz"; + Strings expected = {"foo", "baz"}; + + ASSERT_EQ(tokenizeString(s, ","), expected); +} + +/* ---------------------------------------------------------------------------- + * splitString + * --------------------------------------------------------------------------*/ + +TEST(splitString, empty) +{ + Strings expected = {""}; + + ASSERT_EQ(splitString("", " \t\n\r"), expected); +} + +TEST(splitString, oneSep) +{ + Strings expected = {"", ""}; + + ASSERT_EQ(splitString(" ", " \t\n\r"), expected); +} + +TEST(splitString, twoSep) +{ + Strings expected = {"", "", ""}; + + ASSERT_EQ(splitString(" \n", " \t\n\r"), expected); +} + +TEST(splitString, tokenizeSpacesWithSpaces) +{ + auto s = "foo bar baz"; + Strings expected = {"foo", "bar", "baz"}; + + ASSERT_EQ(splitString(s, " \t\n\r"), expected); +} + +TEST(splitString, tokenizeTabsWithDefaults) +{ + auto s = "foo\tbar\tbaz"; + // Using it like this is weird, but shows the difference with tokenizeString, which also has this test + Strings expected = {"foo", "bar", "baz"}; + + ASSERT_EQ(splitString(s, " \t\n\r"), expected); +} + +TEST(splitString, tokenizeTabsSpacesWithDefaults) +{ + auto s = "foo\t bar\t baz"; + // Using it like this is weird, but shows the difference with tokenizeString, which also has this test + Strings expected = {"foo", "", "bar", "", "baz"}; + + ASSERT_EQ(splitString(s, " \t\n\r"), expected); +} + +TEST(splitString, tokenizeTabsSpacesNewlineWithDefaults) +{ + auto s = "foo\t\n bar\t\n baz"; + // Using it like this is weird, but shows the difference with tokenizeString, which also has this test + Strings expected = {"foo", "", "", "bar", "", "", "baz"}; + + ASSERT_EQ(splitString(s, " \t\n\r"), expected); +} + +TEST(splitString, tokenizeTabsSpacesNewlineRetWithDefaults) +{ + auto s = "foo\t\n\r bar\t\n\r baz"; + // Using it like this is weird, but shows the difference with tokenizeString, which also has this test + Strings expected = {"foo", "", "", "", "bar", "", "", "", "baz"}; + + ASSERT_EQ(splitString(s, " \t\n\r"), expected); + + auto s2 = "foo \t\n\r bar \t\n\r baz"; + Strings expected2 = {"foo", "", "", "", "", "bar", "", "", "", "", "baz"}; + + ASSERT_EQ(splitString(s2, " \t\n\r"), expected2); +} + +TEST(splitString, tokenizeWithCustomSep) +{ + auto s = "foo\n,bar\n,baz\n"; + Strings expected = {"foo\n", "bar\n", "baz\n"}; + + ASSERT_EQ(splitString(s, ","), expected); +} + +TEST(splitString, tokenizeSepAtStart) +{ + auto s = ",foo,bar,baz"; + Strings expected = {"", "foo", "bar", "baz"}; + + ASSERT_EQ(splitString(s, ","), expected); +} + +TEST(splitString, tokenizeSepAtEnd) +{ + auto s = "foo,bar,baz,"; + Strings expected = {"foo", "bar", "baz", ""}; + + ASSERT_EQ(splitString(s, ","), expected); +} + +TEST(splitString, tokenizeSepEmpty) +{ + auto s = "foo,,baz"; + Strings expected = {"foo", "", "baz"}; + + ASSERT_EQ(splitString(s, ","), expected); +} + +// concatStringsSep sep . splitString sep = id if sep is 1 char +RC_GTEST_PROP(splitString, recoveredByConcatStringsSep, (const std::string & s)) +{ + RC_ASSERT(concatStringsSep("/", splitString(s, "/")) == s); + RC_ASSERT(concatStringsSep("a", splitString(s, "a")) == s); +} + +/* ---------------------------------------------------------------------------- + * shellSplitString + * --------------------------------------------------------------------------*/ + +TEST(shellSplitString, empty) +{ + std::list expected = {}; + + ASSERT_EQ(shellSplitString(""), expected); +} + +TEST(shellSplitString, oneWord) +{ + std::list expected = {"foo"}; + + ASSERT_EQ(shellSplitString("foo"), expected); +} + +TEST(shellSplitString, oneWordQuotedWithSpaces) +{ + std::list expected = {"foo bar"}; + + ASSERT_EQ(shellSplitString("'foo bar'"), expected); +} + +TEST(shellSplitString, oneWordQuotedWithSpacesAndDoubleQuoteInSingleQuote) +{ + std::list expected = {"foo bar\""}; + + ASSERT_EQ(shellSplitString("'foo bar\"'"), expected); +} + +TEST(shellSplitString, oneWordQuotedWithDoubleQuotes) +{ + std::list expected = {"foo bar"}; + + ASSERT_EQ(shellSplitString("\"foo bar\""), expected); +} + +TEST(shellSplitString, twoWords) +{ + std::list expected = {"foo", "bar"}; + + ASSERT_EQ(shellSplitString("foo bar"), expected); +} + +TEST(shellSplitString, twoWordsWithSpacesAndQuotesQuoted) +{ + std::list expected = {"foo bar'", "baz\""}; + + ASSERT_EQ(shellSplitString("\"foo bar'\" 'baz\"'"), expected); +} + +TEST(shellSplitString, emptyArgumentsAreAllowedSingleQuotes) +{ + std::list expected = {"foo", "", "bar", "baz", ""}; + + ASSERT_EQ(shellSplitString("foo '' bar baz ''"), expected); +} + +TEST(shellSplitString, emptyArgumentsAreAllowedDoubleQuotes) +{ + std::list expected = {"foo", "", "bar", "baz", ""}; + + ASSERT_EQ(shellSplitString("foo \"\" bar baz \"\""), expected); +} + +TEST(shellSplitString, singleQuoteDoesNotUseEscapes) +{ + std::list expected = {"foo\\\"bar"}; + + ASSERT_EQ(shellSplitString("'foo\\\"bar'"), expected); +} + +TEST(shellSplitString, doubleQuoteDoesUseEscapes) +{ + std::list expected = {"foo\"bar"}; + + ASSERT_EQ(shellSplitString("\"foo\\\"bar\""), expected); +} + +TEST(shellSplitString, backslashEscapesSpaces) +{ + std::list expected = {"foo bar", "baz", "qux quux"}; + + ASSERT_EQ(shellSplitString("foo\\ bar baz qux\\ quux"), expected); +} + +TEST(shellSplitString, backslashEscapesQuotes) +{ + std::list expected = {"foo\"bar", "baz", "qux'quux"}; + + ASSERT_EQ(shellSplitString("foo\\\"bar baz qux\\'quux"), expected); +} + +TEST(shellSplitString, testUnbalancedQuotes) +{ + ASSERT_THROW(shellSplitString("foo'"), Error); + ASSERT_THROW(shellSplitString("foo\""), Error); + ASSERT_THROW(shellSplitString("foo'bar"), Error); + ASSERT_THROW(shellSplitString("foo\"bar"), Error); + ASSERT_THROW(shellSplitString("foo\"bar\\\""), Error); +} + +} // namespace nix diff --git a/src/libutil/strings.hh b/src/libutil/strings.hh index 3b112c409..06f8c8e88 100644 --- a/src/libutil/strings.hh +++ b/src/libutil/strings.hh @@ -18,4 +18,41 @@ extern template std::string concatStringsSep(std::string_view, const std::list &); extern template std::string concatStringsSep(std::string_view, const std::vector &); +/** + * Apply a function to the `iterable`'s items and concat them with `separator`. + */ +template +std::string concatMapStringsSep(std::string_view separator, const C & iterable, F fn) +{ + std::vector strings; + strings.reserve(iterable.size()); + for (const auto & elem : iterable) { + strings.push_back(fn(elem)); + } + return concatStringsSep(separator, strings); +} + +/** + * Ignore any empty strings at the start of the list, and then concatenate the + * given strings with a separator between the elements. + * + * @deprecated This function exists for historical reasons. You probably just + * want to use `concatStringsSep`. + */ +template +[[deprecated( + "Consider removing the empty string dropping behavior. If acceptable, use concatStringsSep instead.")]] std::string +dropEmptyInitThenConcatStringsSep(const std::string_view sep, const C & ss); + +extern template std::string dropEmptyInitThenConcatStringsSep(std::string_view, const std::list &); +extern template std::string dropEmptyInitThenConcatStringsSep(std::string_view, const std::set &); +extern template std::string dropEmptyInitThenConcatStringsSep(std::string_view, const std::vector &); + +/** + * Shell split string: split a string into shell arguments, respecting quotes and backslashes. + * + * Used for NIX_SSHOPTS handling, which previously used `tokenizeString` and was broken by + * Arguments that need to be passed to ssh with spaces in them. + */ +std::list shellSplitString(std::string_view s); } From c39c47ab11f1181c8e2aa76fd7f45faeb470d5f2 Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Sat, 18 Jan 2025 09:49:25 +0100 Subject: [PATCH 3/7] nix-util: Use small_vector in concatMapStringsSep (cherry picked from commit 32898dc46a21c628d3ae275310307c56cbe8ab03) --- src/libutil/strings.cc | 1 + src/libutil/strings.hh | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libutil/strings.cc b/src/libutil/strings.cc index 7ec618bf4..bbaa59262 100644 --- a/src/libutil/strings.cc +++ b/src/libutil/strings.cc @@ -8,6 +8,7 @@ namespace nix { template std::string concatStringsSep(std::string_view, const Strings &); template std::string concatStringsSep(std::string_view, const StringSet &); template std::string concatStringsSep(std::string_view, const std::vector &); +template std::string concatStringsSep(std::string_view, const boost::container::small_vector &); typedef std::string_view strings_2[2]; template std::string concatStringsSep(std::string_view, const strings_2 &); diff --git a/src/libutil/strings.hh b/src/libutil/strings.hh index 06f8c8e88..d5a23b92e 100644 --- a/src/libutil/strings.hh +++ b/src/libutil/strings.hh @@ -6,6 +6,8 @@ #include #include +#include + namespace nix { /** @@ -17,6 +19,7 @@ std::string concatStringsSep(const std::string_view sep, const C & ss); extern template std::string concatStringsSep(std::string_view, const std::list &); extern template std::string concatStringsSep(std::string_view, const std::set &); extern template std::string concatStringsSep(std::string_view, const std::vector &); +extern template std::string concatStringsSep(std::string_view, const boost::container::small_vector &); /** * Apply a function to the `iterable`'s items and concat them with `separator`. @@ -24,7 +27,7 @@ extern template std::string concatStringsSep(std::string_view, const std::vector template std::string concatMapStringsSep(std::string_view separator, const C & iterable, F fn) { - std::vector strings; + boost::container::small_vector strings; strings.reserve(iterable.size()); for (const auto & elem : iterable) { strings.push_back(fn(elem)); From eea2a10595dee6023d003390a393416e9eba61fc Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Sat, 18 Jan 2025 09:58:17 +0100 Subject: [PATCH 4/7] checkRefs: use concatMapStringsSep (cherry picked from commit 2b4d461c14e01eb86f5b253e7df93c595f45f52e) --- src/libstore/unix/build/local-derivation-goal.cc | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/libstore/unix/build/local-derivation-goal.cc b/src/libstore/unix/build/local-derivation-goal.cc index 61785990b..d622c4c01 100644 --- a/src/libstore/unix/build/local-derivation-goal.cc +++ b/src/libstore/unix/build/local-derivation-goal.cc @@ -2900,15 +2900,10 @@ void LocalDerivationGoal::checkOutputs(const std::mappath); else { - std::string allOutputs; - for (auto & o : outputs) { - if (! allOutputs.empty()) - allOutputs.append(", "); - allOutputs.append(o.first); - } + std::string outputsListing = concatMapStringsSep(", ", outputs, [](auto & o) { return o.first; }); throw BuildError("derivation '%s' output check for '%s' contains an illegal reference specifier '%s'," " expected store path or output name (one of [%s])", - worker.store.printStorePath(drvPath), outputName, i, allOutputs); + worker.store.printStorePath(drvPath), outputName, i, outputsListing); } } From 8a31b9aa3a3fac4105a44e8ef211df4ee6bdfa74 Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Sat, 18 Jan 2025 10:21:08 +0100 Subject: [PATCH 5/7] test illegal reference specifier error message (cherry picked from commit f4def47c899a8f637449a3d3670c843a706218ca) --- tests/functional/check-refs.nix | 6 ++++++ tests/functional/check-refs.sh | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/tests/functional/check-refs.nix b/tests/functional/check-refs.nix index 471d95753..9512c73c1 100644 --- a/tests/functional/check-refs.nix +++ b/tests/functional/check-refs.nix @@ -79,4 +79,10 @@ rec { buildCommand = ''echo ${dep} > "''${outputs[out]}"''; }; + test12 = makeTest 12 { + builder = builtins.toFile "builder.sh" "mkdir $out $lib"; + outputs = ["out" "lib"]; + disallowedReferences = ["dev"]; + }; + } diff --git a/tests/functional/check-refs.sh b/tests/functional/check-refs.sh index 5c3ac915e..8eb93b48d 100755 --- a/tests/functional/check-refs.sh +++ b/tests/functional/check-refs.sh @@ -60,3 +60,7 @@ if ! isTestOnNixOS; then fi fi + +# test12 should fail (syntactically invalid). +expectStderr 1 nix-build -vvv -o "$RESULT" check-refs.nix -A test12 >"$TEST_ROOT/test12.stderr" +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" From c679b2125d6d8db2685736721350ee0a9dea63c3 Mon Sep 17 00:00:00 2001 From: Sergei Trofimovich Date: Mon, 24 Mar 2025 22:34:09 +0000 Subject: [PATCH 6/7] tests/functional/check-refs.sh: guard test12 against too old nix daemon Otherwise without the change the test fails on nix-2.26 as: error: derivation contains an illegal reference specifier 'dev' Note: the error message does not match intended change. (cherry picked from commit 1e7c7244cf6e7f0fba83764153a31a9ff780cb7e) --- tests/functional/check-refs.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/functional/check-refs.sh b/tests/functional/check-refs.sh index 8eb93b48d..590c3fb53 100755 --- a/tests/functional/check-refs.sh +++ b/tests/functional/check-refs.sh @@ -61,6 +61,8 @@ if ! isTestOnNixOS; then fi -# test12 should fail (syntactically invalid). -expectStderr 1 nix-build -vvv -o "$RESULT" check-refs.nix -A test12 >"$TEST_ROOT/test12.stderr" -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" +if isDaemonNewer "2.28pre20241225"; then + # test12 should fail (syntactically invalid). + expectStderr 1 nix-build -vvv -o "$RESULT" check-refs.nix -A test12 >"$TEST_ROOT/test12.stderr" + 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" +fi From cdf4bccc057a7c2801e7fcae2686a877cea0b4eb Mon Sep 17 00:00:00 2001 From: Sergei Trofimovich Date: Mon, 24 Mar 2025 22:45:28 +0000 Subject: [PATCH 7/7] tests/functional/check-refs.nix: format newly added test (cherry picked from commit 4d72e0f73bc31ac200d57caba65f6355760df032) --- tests/functional/check-refs.nix | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/functional/check-refs.nix b/tests/functional/check-refs.nix index 9512c73c1..bdd5c4f8d 100644 --- a/tests/functional/check-refs.nix +++ b/tests/functional/check-refs.nix @@ -81,8 +81,11 @@ rec { test12 = makeTest 12 { builder = builtins.toFile "builder.sh" "mkdir $out $lib"; - outputs = ["out" "lib"]; - disallowedReferences = ["dev"]; + outputs = [ + "out" + "lib" + ]; + disallowedReferences = [ "dev" ]; }; }