Skip to content

Commit 2b5a1a9

Browse files
authored
Merge pull request #15349 from roberth/fix-cli-messages
Fix package-related CLI messages
2 parents b0c932d + eda9c01 commit 2b5a1a9

113 files changed

Lines changed: 914 additions & 2 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ src/.wraplock
1616
/tests/functional/lang/*.err
1717
/tests/functional/lang/*.ast
1818

19+
# /tests/functional/cli-characterisation/
20+
/tests/functional/cli-characterisation/*.out
21+
/tests/functional/cli-characterisation/*.err
22+
1923
/outputs
2024

2125
*~

src/libexpr/eval.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2419,10 +2419,11 @@ std::string_view EvalState::forceStringNoCtx(Value & v, const PosIdx pos, std::s
24192419
{
24202420
auto s = forceString(v, pos, errorCtx);
24212421
if (v.context()) {
2422+
auto ctxElem = NixStringContextElem::parse((*v.context()->begin())->view());
24222423
error<EvalError>(
24232424
"the string '%1%' is not allowed to refer to a store path (such as '%2%')",
24242425
v.string_view(),
2425-
(*v.context()->begin())->view())
2426+
ctxElem.display(*store))
24262427
.withTrace(pos, errorCtx)
24272428
.debugThrow();
24282429
}

src/libexpr/get-drvs.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ StorePath PackageInfo::queryOutPath() const
101101
i->pos, *i->value, context, "while evaluating the output path of a derivation");
102102
}
103103
if (!outPath)
104-
throw UnimplementedError("CA derivations are not yet supported");
104+
throw Error("derivation does not have attribute 'outPath'");
105105
return *outPath;
106106
}
107107

src/libexpr/include/nix/expr/value/context.hh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,14 @@ struct NixStringContextElem
8383
static NixStringContextElem
8484
parse(std::string_view s, const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings);
8585
std::string to_string() const;
86+
87+
/**
88+
* Render for use in error messages and other user-facing output.
89+
*
90+
* Uses store paths and `DerivedPath` syntax, unlike `to_string()`
91+
* which uses the internal encoding.
92+
*/
93+
std::string display(const StoreDirConfig & store) const;
8694
};
8795

8896
/**

src/libexpr/value/context.cc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "nix/util/util.hh"
22
#include "nix/expr/value/context.hh"
3+
#include "nix/store/store-dir-config.hh"
34

45
#include <optional>
56

@@ -96,4 +97,19 @@ std::string NixStringContextElem::to_string() const
9697
return res;
9798
}
9899

100+
std::string NixStringContextElem::display(const StoreDirConfig & store) const
101+
{
102+
return std::visit(
103+
overloaded{
104+
[&](const NixStringContextElem::Opaque & o) -> std::string {
105+
return SingleDerivedPath{o}.to_string(store);
106+
},
107+
[&](const NixStringContextElem::DrvDeep & d) -> std::string {
108+
return store.printStorePath(d.drvPath) + " (deep)";
109+
},
110+
[&](const NixStringContextElem::Built & b) -> std::string { return SingleDerivedPath{b}.to_string(store); },
111+
},
112+
raw);
113+
}
114+
99115
} // namespace nix
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#!/usr/bin/env bash
2+
3+
# Characterization tests for nix-env, nix-build, and nix-instantiate.
4+
# Captures error messages, output formats, and edge-case behavior.
5+
#
6+
# Expected output files in: cli-characterisation/
7+
# Regenerate with: _NIX_TEST_ACCEPT=1 meson test -C build cli-characterisation
8+
9+
source common.sh
10+
11+
source characterisation/framework.sh
12+
13+
set +x
14+
15+
badDiff=0
16+
badExitCode=0
17+
18+
# Normalize store paths, hashes, source paths, and system
19+
normalize() {
20+
sed -i \
21+
-e "s|${NIX_STORE_DIR:-/nix/store}/[a-z0-9]\{32\}|/test-root/store/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|g" \
22+
-e "s|$TEST_ROOT|/test-root|g" \
23+
-e "s|$(pwd)|/pwd|g" \
24+
-e "s|$system|SYSTEM|g" \
25+
-e "s|/nix/store/[a-z0-9]\{32\}|/nix/store/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|g" \
26+
-e "s|/test-root/store/[a-z0-9]\{32\}|/test-root/store/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|g" \
27+
-e "s|'[a-z0-9]\{32\}-|'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-|g" \
28+
"$@"
29+
}
30+
31+
diffAndAccept() {
32+
local testName="$1"
33+
local got="cli-characterisation/$testName.$2"
34+
local expected="cli-characterisation/$testName.$3"
35+
diffAndAcceptInner "$testName" "$got" "$expected"
36+
}
37+
38+
clearProfiles
39+
40+
# Each test case has a descriptor: cli-characterisation/<name>.cmd
41+
# containing: <expected-exit-code> <command...>
42+
#
43+
# stdout -> <name>.out, stderr -> <name>.err
44+
# Both are compared against <name>.out.exp / <name>.err.exp
45+
46+
for cmdFile in cli-characterisation/*.cmd; do
47+
testName=$(basename "$cmdFile" .cmd)
48+
echo "testing $testName"
49+
50+
# read returns 1 on EOF without trailing newline; handle it
51+
read -r expectedExit cmd < "$cmdFile" || [[ -n "$expectedExit" ]]
52+
53+
if
54+
# shellcheck disable=SC2086 # word splitting of cmd is intended
55+
expect "$expectedExit" $cmd \
56+
1> "cli-characterisation/$testName.out" \
57+
2> "cli-characterisation/$testName.err"
58+
then
59+
normalize "cli-characterisation/$testName.out" "cli-characterisation/$testName.err"
60+
diffAndAccept "$testName" out out.exp
61+
diffAndAccept "$testName" err err.exp
62+
else
63+
echo "FAIL: $testName exited with wrong code"
64+
badExitCode=1
65+
fi
66+
done
67+
68+
# --- Multi-step tests that need a real .drv path in the store ---
69+
70+
drvPath=$(nix-instantiate ./cli-characterisation/simple.nix)
71+
72+
# Constructor: "building more than one derivation output is not supported"
73+
testName=nix-build-multi-output
74+
echo "testing $testName"
75+
if
76+
expect 1 nix-build "$drvPath!out,bin" \
77+
1> "cli-characterisation/$testName.out" \
78+
2> "cli-characterisation/$testName.err"
79+
then
80+
normalize "cli-characterisation/$testName.out" "cli-characterisation/$testName.err"
81+
diffAndAccept "$testName" out out.exp
82+
diffAndAccept "$testName" err err.exp
83+
else
84+
echo "FAIL: $testName exited with wrong code"
85+
badExitCode=1
86+
fi
87+
88+
# Constructor: "derivation does not have output"
89+
testName=nix-build-bad-output
90+
echo "testing $testName"
91+
if
92+
expect 1 nix-build "$drvPath!nonexistent" \
93+
1> "cli-characterisation/$testName.out" \
94+
2> "cli-characterisation/$testName.err"
95+
then
96+
normalize "cli-characterisation/$testName.out" "cli-characterisation/$testName.err"
97+
diffAndAccept "$testName" out out.exp
98+
diffAndAccept "$testName" err err.exp
99+
else
100+
echo "FAIL: $testName exited with wrong code"
101+
badExitCode=1
102+
fi
103+
104+
characterisationTestExit
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
with import ../config.nix;
2+
mkDerivation {
3+
name =
4+
assert false;
5+
"assert-fail-1.0";
6+
buildCommand = "mkdir -p $out";
7+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
type = "derivation";
3+
name = "bad-drvpath-1.0";
4+
outPath = builtins.toFile "out" "";
5+
drvPath = builtins.toFile "not-a-drv" "";
6+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
type = "derivation";
3+
name = "bad-output-specified-type-1.0";
4+
outPath = builtins.toFile "out" "";
5+
outputs = [ "out" ];
6+
out = {
7+
outPath = builtins.toFile "out" "";
8+
};
9+
outputSpecified = "yes";
10+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
type = "derivation";
3+
name = "bad-output-specified-1.0";
4+
outPath = builtins.toFile "out" "";
5+
outputs = [ "out" ];
6+
outputSpecified = true;
7+
outputName = "nonexistent";
8+
}

0 commit comments

Comments
 (0)