Merge remote-tracking branch 'origin/master' into flakes

This commit is contained in:
Eelco Dolstra 2020-06-17 10:26:52 +02:00
commit 1524752c17
139 changed files with 2586 additions and 1707 deletions

3
.gitignore vendored
View file

@ -49,6 +49,9 @@ perl/Makefile.config
# /src/libstore/
*.gen.*
# /src/libutil/
/src/libutil/tests/libutil-tests
/src/nix/nix
# /src/nix-env/

View file

@ -1,7 +1,6 @@
makefiles = \
mk/precompiled-headers.mk \
local.mk \
nix-rust/local.mk \
src/libutil/local.mk \
src/libutil/tests/local.mk \
src/libstore/local.mk \

View file

@ -1,5 +1,5 @@
<nop xmlns="http://docbook.org/ns/docbook">
<arg><option>--help</option></arg>
<arg><option>--version</option></arg>
<arg rep='repeat'>
@ -11,6 +11,10 @@
<arg>
<arg choice='plain'><option>--quiet</option></arg>
</arg>
<arg>
<option>--log-format</option>
<replaceable>format</replaceable>
</arg>
<arg>
<group choice='plain'>
<arg choice='plain'><option>--no-build-output</option></arg>

View file

@ -92,6 +92,37 @@
</varlistentry>
<varlistentry xml:id="opt-log-format"><term><option>--log-format</option> <replaceable>format</replaceable></term>
<listitem>
<para>This option can be used to change the output of the log format, with
<replaceable>format</replaceable> being one of:</para>
<variablelist>
<varlistentry><term>raw</term>
<listitem><para>This is the raw format, as outputted by nix-build.</para></listitem>
</varlistentry>
<varlistentry><term>internal-json</term>
<listitem><para>Outputs the logs in a structured manner. NOTE: the json schema is not guarantees to be stable between releases.</para></listitem>
</varlistentry>
<varlistentry><term>bar</term>
<listitem><para>Only display a progress bar during the builds.</para></listitem>
</varlistentry>
<varlistentry><term>bar-with-logs</term>
<listitem><para>Display the raw logs, with the progress bar at the bottom.</para></listitem>
</varlistentry>
</variablelist>
</listitem>
</varlistentry>
<varlistentry><term><option>--no-build-output</option> / <option>-Q</option></term>
<listitem><para>By default, output written by builders to standard

View file

@ -78,7 +78,6 @@
then nlohmann_json
else nlohmann_json.override { multipleHeaders = true; })
nlohmann_json
rustc cargo
# Tests
git
@ -134,8 +133,6 @@
chmod u+w $out/lib/*.so.*
patchelf --set-rpath $out/lib:${stdenv.cc.cc.lib}/lib $out/lib/libboost_thread.so.*
''}
ln -sfn ${final.nixVendoredCrates}/vendor/ nix-rust/vendor
'';
configureFlags = configureFlags ++
@ -190,68 +187,10 @@
};
# Create a "vendor" directory that contains the crates listed in
# Cargo.lock, and include it in the Nix tarball. This allows Nix
# to be built without network access.
nixVendoredCrates =
let
lockFile = builtins.fromTOML (builtins.readFile nix-rust/Cargo.lock);
files = map (pkg: import <nix/fetchurl.nix> {
url = "https://crates.io/api/v1/crates/${pkg.name}/${pkg.version}/download";
sha256 = lockFile.metadata."checksum ${pkg.name} ${pkg.version} (registry+https://github.com/rust-lang/crates.io-index)";
}) (builtins.filter (pkg: pkg.source or "" == "registry+https://github.com/rust-lang/crates.io-index") lockFile.package);
in final.runCommand "cargo-vendor-dir" {}
''
mkdir -p $out/vendor
cat > $out/vendor/config <<EOF
[source.crates-io]
replace-with = "vendored-sources"
[source.vendored-sources]
directory = "vendor"
EOF
${toString (builtins.map (file: ''
mkdir $out/vendor/tmp
tar xvf ${file} -C $out/vendor/tmp
dir=$(echo $out/vendor/tmp/*)
# Add just enough metadata to keep Cargo happy.
printf '{"files":{},"package":"${file.outputHash}"}' > "$dir/.cargo-checksum.json"
# Clean up some cruft from the winapi crates. FIXME: find
# a way to remove winapi* from our dependencies.
if [[ $dir =~ /winapi ]]; then
find $dir -name "*.a" -print0 | xargs -0 rm -f --
fi
mv "$dir" $out/vendor/
rm -rf $out/vendor/tmp
'') files)}
'';
};
hydraJobs = {
vendoredCrates =
with nixpkgsFor.x86_64-linux;
runCommand "vendored-crates" {}
''
mkdir -p $out/nix-support
name=nix-vendored-crates-${version}
fn=$out/$name.tar.xz
tar cvfJ $fn -C ${nixVendoredCrates} vendor \
--owner=0 --group=0 --mode=u+rw,uga+r \
--transform "s,vendor,$name,"
echo "file crates-tarball $fn" >> $out/nix-support/hydra-build-products
'';
# Binary package for various platforms.
build = nixpkgs.lib.genAttrs systems (system: nixpkgsFor.${system}.nix);
@ -360,11 +299,6 @@
src = self;
preConfigure =
''
ln -sfn ${nixVendoredCrates}/vendor/ nix-rust/vendor
'';
enableParallelBuilding = true;
buildInputs = buildDeps ++ propagatedDeps;
@ -487,7 +421,7 @@
stdenv.mkDerivation {
name = "nix";
buildInputs = buildDeps ++ propagatedDeps ++ perlDeps ++ [ pkgs.rustfmt ];
buildInputs = buildDeps ++ propagatedDeps ++ perlDeps;
inherit configureFlags;

View file

@ -142,8 +142,12 @@ $oldName =~ s/"//g;
sub getStorePath {
my ($jobName) = @_;
my $buildInfo = decode_json(fetch("$evalUrl/job/$jobName", 'application/json'));
die unless $buildInfo->{buildproducts}->{1}->{type} eq "nix-build";
return $buildInfo->{buildproducts}->{1}->{path};
for my $product (values %{$buildInfo->{buildproducts}}) {
next unless $product->{type} eq "nix-build";
next if $product->{path} =~ /[a-z]+$/;
return $product->{path};
}
die;
}
write_file("$nixpkgsDir/nixos/modules/installer/tools/nix-fallback-paths.nix",

View file

@ -125,7 +125,8 @@ define build-library
$(1)_PATH := $$(_d)/$$($(1)_NAME).a
$$($(1)_PATH): $$($(1)_OBJS) | $$(_d)/
$(trace-ar) $(AR) crs $$@ $$?
$(trace-ld) $(LD) -Ur -o $$(_d)/$$($(1)_NAME).o $$?
$(trace-ar) $(AR) crs $$@ $$(_d)/$$($(1)_NAME).o
$(1)_LDFLAGS_USE += $$($(1)_PATH) $$($(1)_LDFLAGS)

View file

@ -80,7 +80,7 @@ SV * queryReferences(char * path)
SV * queryPathHash(char * path)
PPCODE:
try {
auto s = store()->queryPathInfo(store()->parseStorePath(path))->narHash.to_string();
auto s = store()->queryPathInfo(store()->parseStorePath(path))->narHash.to_string(Base32, true);
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
} catch (Error & e) {
croak("%s", e.what());
@ -106,7 +106,7 @@ SV * queryPathInfo(char * path, int base32)
XPUSHs(&PL_sv_undef);
else
XPUSHs(sv_2mortal(newSVpv(store()->printStorePath(*info->deriver).c_str(), 0)));
auto s = info->narHash.to_string(base32 ? Base32 : Base16);
auto s = info->narHash.to_string(base32 ? Base32 : Base16, true);
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
mXPUSHi(info->registrationTime);
mXPUSHi(info->narSize);

View file

@ -200,9 +200,12 @@ static int _main(int argc, char * * argv)
} catch (std::exception & e) {
auto msg = chomp(drainFD(5, false));
printError("cannot build on '%s': %s%s",
bestMachine->storeUri, e.what(),
(msg.empty() ? "" : ": " + msg));
logError({
.name = "Remote build",
.hint = hintfmt("cannot build on '%s': %s%s",
bestMachine->storeUri, e.what(),
(msg.empty() ? "" : ": " + msg))
});
bestMachine->enabled = false;
continue;
}
@ -241,7 +244,7 @@ connected:
uploadLock = -1;
BasicDerivation drv(readDerivation(*store, store->realStoreDir + "/" + std::string(drvPath->to_string())));
auto drv = store->readDerivation(*drvPath);
drv.inputSrcs = store->parseStorePathSet(inputs);
auto result = sshStore->buildDerivation(*drvPath, drv);

View file

@ -1,66 +0,0 @@
#include "error.hh"
#include "nixexpr.hh"
#include <iostream>
#include <optional>
int main()
{
using namespace nix;
// In each program where errors occur, this has to be set.
ErrorInfo::programName = std::optional("error-demo");
// Error in a program; no hint and no nix code.
printErrorInfo(
ErrorInfo { .level = elError,
.name = "name",
.description = "error description",
});
// Warning with name, description, and hint.
// The hintfmt function makes all the substituted text yellow.
printErrorInfo(
ErrorInfo { .level = elWarning,
.name = "name",
.description = "error description",
.hint = std::optional(
hintfmt("there was a %1%", "warning")),
});
// Warning with nix file, line number, column, and the lines of
// code where a warning occurred.
SymbolTable testTable;
auto problem_file = testTable.create("myfile.nix");
printErrorInfo(
ErrorInfo{
.level = elWarning,
.name = "warning name",
.description = "warning description",
.hint = hintfmt("this hint has %1% templated %2%!!", "yellow", "values"),
.nixCode = NixCode {
.errPos = Pos(problem_file, 40, 13),
.prevLineOfCode = std::nullopt,
.errLineOfCode = "this is the problem line of code",
.nextLineOfCode = std::nullopt
}});
// Error with previous and next lines of code.
printErrorInfo(
ErrorInfo{
.level = elError,
.name = "error name",
.description = "error description",
.hint = hintfmt("this hint has %1% templated %2%!!", "yellow", "values"),
.nixCode = NixCode {
.errPos = Pos(problem_file, 40, 13),
.prevLineOfCode = std::optional("previous line of code"),
.errLineOfCode = "this is the problem line of code",
.nextLineOfCode = std::optional("next line of code"),
}});
return 0;
}

View file

@ -1,12 +0,0 @@
programs += error-demo
error-demo_DIR := $(d)
error-demo_SOURCES := \
$(wildcard $(d)/*.cc) \
error-demo_CXXFLAGS += -I src/libutil -I src/libexpr
error-demo_LIBS = libutil libexpr
error-demo_LDFLAGS = -pthread $(SODIUM_LIBS) $(EDITLINE_LIBS) $(BOOST_LDFLAGS) -lboost_context -lboost_thread -lboost_system

View file

@ -19,7 +19,7 @@ static Strings parseAttrPath(std::string_view s)
++i;
while (1) {
if (i == s.end())
throw Error(format("missing closing quote in selection path '%1%'") % s);
throw Error("missing closing quote in selection path '%1%'", s);
if (*i == '"') break;
cur.push_back(*i++);
}
@ -69,11 +69,11 @@ std::pair<Value *, Pos> findAlongAttrPath(EvalState & state, const string & attr
if (v->type != tAttrs)
throw TypeError(
format("the expression selected by the selection path '%1%' should be a set but is %2%")
% attrPath % showType(*v));
"the expression selected by the selection path '%1%' should be a set but is %2%",
attrPath,
showType(*v));
if (attr.empty())
throw Error(format("empty attribute name in selection path '%1%'") % attrPath);
throw Error("empty attribute name in selection path '%1%'", attrPath);
Bindings::iterator a = v->attrs->find(state.symbols.create(attr));
if (a == v->attrs->end())
@ -86,9 +86,9 @@ std::pair<Value *, Pos> findAlongAttrPath(EvalState & state, const string & attr
if (!v->isList())
throw TypeError(
format("the expression selected by the selection path '%1%' should be a list but is %2%")
% attrPath % showType(*v));
"the expression selected by the selection path '%1%' should be a list but is %2%",
attrPath,
showType(*v));
if (attrIndex >= v->listSize())
throw AttrPathNotFound("list index %1% in selection path '%2%' is out of range", attrIndex, attrPath);

View file

@ -76,7 +76,11 @@ public:
{
auto a = get(name);
if (!a)
throw Error("attribute '%s' missing, at %s", name, pos);
throw Error({
.hint = hintfmt("attribute '%s' missing", name),
.nixCode = NixCode { .errPos = pos }
});
return *a;
}

View file

@ -7,20 +7,26 @@
namespace nix {
LocalNoInlineNoReturn(void throwEvalError(const char * s, const Pos & pos))
LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s))
{
throw EvalError(format(s) % pos);
throw EvalError({
.hint = hintfmt(s),
.nixCode = NixCode { .errPos = pos }
});
}
LocalNoInlineNoReturn(void throwTypeError(const char * s, const Value & v))
{
throw TypeError(format(s) % showType(v));
throw TypeError(s, showType(v));
}
LocalNoInlineNoReturn(void throwTypeError(const char * s, const Value & v, const Pos & pos))
LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const Value & v))
{
throw TypeError(format(s) % showType(v) % pos);
throw TypeError({
.hint = hintfmt(s, showType(v)),
.nixCode = NixCode { .errPos = pos }
});
}
@ -43,7 +49,7 @@ void EvalState::forceValue(Value & v, const Pos & pos)
else if (v.type == tApp)
callFunction(*v.app.left, *v.app.right, v, noPos);
else if (v.type == tBlackhole)
throwEvalError("infinite recursion encountered, at %1%", pos);
throwEvalError(pos, "infinite recursion encountered");
}
@ -59,7 +65,7 @@ inline void EvalState::forceAttrs(Value & v, const Pos & pos)
{
forceValue(v, pos);
if (v.type != tAttrs)
throwTypeError("value is %1% while a set was expected, at %2%", v, pos);
throwTypeError(pos, "value is %1% while a set was expected", v);
}
@ -75,7 +81,7 @@ inline void EvalState::forceList(Value & v, const Pos & pos)
{
forceValue(v, pos);
if (!v.isList())
throwTypeError("value is %1% while a list was expected, at %2%", v, pos);
throwTypeError(pos, "value is %1% while a list was expected", v);
}
/* Note: Various places expect the allocated memory to be zeroed. */

View file

@ -538,52 +538,74 @@ Value & EvalState::getBuiltin(const string & name)
LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2))
{
throw EvalError(format(s) % s2);
throw EvalError(s, s2);
}
LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, const Pos & pos))
LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2))
{
throw EvalError(format(s) % s2 % pos);
throw EvalError({
.hint = hintfmt(s, s2),
.nixCode = NixCode { .errPos = pos }
});
}
LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, const string & s3))
{
throw EvalError(format(s) % s2 % s3);
throw EvalError(s, s2, s3);
}
LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, const string & s3, const Pos & pos))
LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2, const string & s3))
{
throw EvalError(format(s) % s2 % s3 % pos);
throw EvalError({
.hint = hintfmt(s, s2, s3),
.nixCode = NixCode { .errPos = pos }
});
}
LocalNoInlineNoReturn(void throwEvalError(const char * s, const Symbol & sym, const Pos & p1, const Pos & p2))
LocalNoInlineNoReturn(void throwEvalError(const Pos & p1, const char * s, const Symbol & sym, const Pos & p2))
{
throw EvalError(format(s) % sym % p1 % p2);
// p1 is where the error occurred; p2 is a position mentioned in the message.
throw EvalError({
.hint = hintfmt(s, sym, p2),
.nixCode = NixCode { .errPos = p1 }
});
}
LocalNoInlineNoReturn(void throwTypeError(const char * s, const Pos & pos))
LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s))
{
throw TypeError(format(s) % pos);
throw TypeError({
.hint = hintfmt(s),
.nixCode = NixCode { .errPos = pos }
});
}
LocalNoInlineNoReturn(void throwTypeError(const char * s, const string & s1))
{
throw TypeError(format(s) % s1);
throw TypeError(s, s1);
}
LocalNoInlineNoReturn(void throwTypeError(const char * s, const ExprLambda & fun, const Symbol & s2, const Pos & pos))
LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const ExprLambda & fun, const Symbol & s2))
{
throw TypeError(format(s) % fun.showNamePos() % s2 % pos);
throw TypeError({
.hint = hintfmt(s, fun.showNamePos(), s2),
.nixCode = NixCode { .errPos = pos }
});
}
LocalNoInlineNoReturn(void throwAssertionError(const char * s, const string & s1, const Pos & pos))
LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, const string & s1))
{
throw AssertionError(format(s) % s1 % pos);
throw AssertionError({
.hint = hintfmt(s, s1),
.nixCode = NixCode { .errPos = pos }
});
}
LocalNoInlineNoReturn(void throwUndefinedVarError(const char * s, const string & s1, const Pos & pos))
LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * s, const string & s1))
{
throw UndefinedVarError(format(s) % s1 % pos);
throw UndefinedVarError({
.hint = hintfmt(s, s1),
.nixCode = NixCode { .errPos = pos }
});
}
LocalNoInline(void addErrorPrefix(Error & e, const char * s, const string & s2))
@ -651,7 +673,7 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
return j->value;
}
if (!env->prevWith)
throwUndefinedVarError("undefined variable '%1%' at %2%", var.name, var.pos);
throwUndefinedVarError(var.pos, "undefined variable '%1%'", var.name);
for (size_t l = env->prevWith; l; --l, env = env->up) ;
}
}
@ -854,7 +876,7 @@ inline bool EvalState::evalBool(Env & env, Expr * e, const Pos & pos)
Value v;
e->eval(*this, env, v);
if (v.type != tBool)
throwTypeError("value is %1% while a Boolean was expected, at %2%", v, pos);
throwTypeError(pos, "value is %1% while a Boolean was expected", v);
return v.boolean;
}
@ -968,7 +990,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v)
Symbol nameSym = state.symbols.create(nameVal.string.s);
Bindings::iterator j = v.attrs->find(nameSym);
if (j != v.attrs->end())
throwEvalError("dynamic attribute '%1%' at %2% already defined at %3%", nameSym, i.pos, *j->pos);
throwEvalError(i.pos, "dynamic attribute '%1%' already defined at %2%", nameSym, *j->pos);
i.valueExpr->setName(nameSym);
/* Keep sorted order so find can catch duplicates */
@ -1056,7 +1078,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
} else {
state.forceAttrs(*vAttrs, pos);
if ((j = vAttrs->attrs->find(name)) == vAttrs->attrs->end())
throwEvalError("attribute '%1%' missing, at %2%", name, pos);
throwEvalError(pos, "attribute '%1%' missing", name);
}
vAttrs = j->value;
pos2 = j->pos;
@ -1182,7 +1204,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po
}
if (fun.type != tLambda)
throwTypeError("attempt to call something which is not a function but %1%, at %2%", fun, pos);
throwTypeError(pos, "attempt to call something which is not a function but %1%", fun);
ExprLambda & lambda(*fun.lambda.fun);
@ -1210,8 +1232,8 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po
for (auto & i : lambda.formals->formals) {
Bindings::iterator j = arg.attrs->find(i.name);
if (j == arg.attrs->end()) {
if (!i.def) throwTypeError("%1% called without required argument '%2%', at %3%",
lambda, i.name, pos);
if (!i.def) throwTypeError(pos, "%1% called without required argument '%2%'",
lambda, i.name);
env2.values[displ++] = i.def->maybeThunk(*this, env2);
} else {
attrsUsed++;
@ -1226,7 +1248,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po
user. */
for (auto & i : *arg.attrs)
if (lambda.formals->argNames.find(i.name) == lambda.formals->argNames.end())
throwTypeError("%1% called with unexpected argument '%2%', at %3%", lambda, i.name, pos);
throwTypeError(pos, "%1% called with unexpected argument '%2%'", lambda, i.name);
abort(); // can't happen
}
}
@ -1315,7 +1337,7 @@ void ExprAssert::eval(EvalState & state, Env & env, Value & v)
if (!state.evalBool(env, cond, pos)) {
std::ostringstream out;
cond->show(out);
throwAssertionError("assertion '%1%' failed at %2%", out.str(), pos);
throwAssertionError(pos, "assertion '%1%' failed at %2%", out.str());
}
body->eval(state, env, v);
}
@ -1467,14 +1489,14 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
nf = n;
nf += vTmp.fpoint;
} else
throwEvalError("cannot add %1% to an integer, at %2%", showType(vTmp), pos);
throwEvalError(pos, "cannot add %1% to an integer", showType(vTmp));
} else if (firstType == tFloat) {
if (vTmp.type == tInt) {
nf += vTmp.integer;
} else if (vTmp.type == tFloat) {
nf += vTmp.fpoint;
} else
throwEvalError("cannot add %1% to a float, at %2%", showType(vTmp), pos);
throwEvalError(pos, "cannot add %1% to a float", showType(vTmp));
} else
s << state.coerceToString(pos, vTmp, context, false, firstType == tString);
}
@ -1485,7 +1507,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
mkFloat(v, nf);
else if (firstType == tPath) {
if (!context.empty())
throwEvalError("a string that refers to a store path cannot be appended to a path, at %1%", pos);
throwEvalError(pos, "a string that refers to a store path cannot be appended to a path");
auto path = canonPath(s.str());
mkPath(v, path.c_str());
} else
@ -1534,7 +1556,7 @@ NixInt EvalState::forceInt(Value & v, const Pos & pos)
{
forceValue(v, pos);
if (v.type != tInt)
throwTypeError("value is %1% while an integer was expected, at %2%", v, pos);
throwTypeError(pos, "value is %1% while an integer was expected", v);
return v.integer;
}
@ -1545,7 +1567,7 @@ NixFloat EvalState::forceFloat(Value & v, const Pos & pos)
if (v.type == tInt)
return v.integer;
else if (v.type != tFloat)
throwTypeError("value is %1% while a float was expected, at %2%", v, pos);
throwTypeError(pos, "value is %1% while a float was expected", v);
return v.fpoint;
}
@ -1554,7 +1576,7 @@ bool EvalState::forceBool(Value & v, const Pos & pos)
{
forceValue(v, pos);
if (v.type != tBool)
throwTypeError("value is %1% while a Boolean was expected, at %2%", v, pos);
throwTypeError(pos, "value is %1% while a Boolean was expected", v);
return v.boolean;
}
@ -1569,7 +1591,7 @@ void EvalState::forceFunction(Value & v, const Pos & pos)
{
forceValue(v, pos);
if (v.type != tLambda && v.type != tPrimOp && v.type != tPrimOpApp && !isFunctor(v))
throwTypeError("value is %1% while a function was expected, at %2%", v, pos);
throwTypeError(pos, "value is %1% while a function was expected", v);
}
@ -1578,7 +1600,7 @@ string EvalState::forceString(Value & v, const Pos & pos)
forceValue(v, pos);
if (v.type != tString) {
if (pos)
throwTypeError("value is %1% while a string was expected, at %2%", v, pos);
throwTypeError(pos, "value is %1% while a string was expected", v);
else
throwTypeError("value is %1% while a string was expected", v);
}
@ -1607,8 +1629,8 @@ string EvalState::forceStringNoCtx(Value & v, const Pos & pos)
string s = forceString(v, pos);
if (v.string.context) {
if (pos)
throwEvalError("the string '%1%' is not allowed to refer to a store path (such as '%2%'), at %3%",
v.string.s, v.string.context[0], pos);
throwEvalError(pos, "the string '%1%' is not allowed to refer to a store path (such as '%2%')",
v.string.s, v.string.context[0]);
else
throwEvalError("the string '%1%' is not allowed to refer to a store path (such as '%2%')",
v.string.s, v.string.context[0]);
@ -1664,7 +1686,7 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context,
return *maybeString;
}
auto i = v.attrs->find(sOutPath);
if (i == v.attrs->end()) throwTypeError("cannot coerce a set to a string, at %1%", pos);
if (i == v.attrs->end()) throwTypeError(pos, "cannot coerce a set to a string");
return coerceToString(pos, *i->value, context, coerceMore, copyToStore);
}
@ -1695,7 +1717,7 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context,
}
}
throwTypeError("cannot coerce %1% to a string, at %2%", v, pos);
throwTypeError(pos, "cannot coerce %1% to a string", v);
}
@ -1726,7 +1748,7 @@ Path EvalState::coerceToPath(const Pos & pos, Value & v, PathSet & context)
{
string path = coerceToString(pos, v, context, false, false);
if (path == "" || path[0] != '/')
throwEvalError("string '%1%' doesn't represent an absolute path, at %2%", path, pos);
throwEvalError(pos, "string '%1%' doesn't represent an absolute path", path);
return path;
}
@ -1933,8 +1955,10 @@ void EvalState::printStats()
string ExternalValueBase::coerceToString(const Pos & pos, PathSet & context, bool copyMore, bool copyToStore) const
{
throw TypeError(format("cannot coerce %1% to a string, at %2%") %
showType() % pos);
throw TypeError({
.hint = hintfmt("cannot coerce %1% to a string", showType()),
.nixCode = NixCode { .errPos = pos }
});
}

View file

@ -127,14 +127,14 @@ or { return OR_KW; }
try {
yylval->n = boost::lexical_cast<int64_t>(yytext);
} catch (const boost::bad_lexical_cast &) {
throw ParseError(format("invalid integer '%1%'") % yytext);
throw ParseError("invalid integer '%1%'", yytext);
}
return INT;
}
{FLOAT} { errno = 0;
yylval->nf = strtod(yytext, 0);
if (errno != 0)
throw ParseError(format("invalid float '%1%'") % yytext);
throw ParseError("invalid float '%1%'", yytext);
return FLOAT;
}
@ -219,4 +219,3 @@ or { return OR_KW; }
}
%%

View file

@ -13,7 +13,7 @@ libexpr_SOURCES := \
libexpr_CXXFLAGS += -I src/libutil -I src/libstore -I src/libfetchers -I src/libmain -I src/libexpr
libexpr_LIBS = libutil libstore libfetchers libnixrust
libexpr_LIBS = libutil libstore libfetchers
libexpr_LDFLAGS =
ifneq ($(OS), FreeBSD)

View file

@ -267,8 +267,11 @@ void ExprVar::bindVars(const StaticEnv & env)
/* Otherwise, the variable must be obtained from the nearest
enclosing `with'. If there is no `with', then we can issue an
"undefined variable" error now. */
if (withLevel == -1) throw UndefinedVarError(format("undefined variable '%1%' at %2%") % name % pos);
if (withLevel == -1)
throw UndefinedVarError({
.hint = hintfmt("undefined variable '%1%'", name),
.nixCode = NixCode { .errPos = pos }
});
fromWith = true;
this->level = withLevel;
}

View file

@ -2,6 +2,7 @@
#include "value.hh"
#include "symbol-table.hh"
#include "error.hh"
#include <map>
@ -235,8 +236,10 @@ struct ExprLambda : Expr
: pos(pos), arg(arg), matchAttrs(matchAttrs), formals(formals), body(body)
{
if (!arg.empty() && formals && formals->argNames.find(arg) != formals->argNames.end())
throw ParseError(format("duplicate formal function argument '%1%' at %2%")
% arg % pos);
throw ParseError({
.hint = hintfmt("duplicate formal function argument '%1%'", arg),
.nixCode = NixCode { .errPos = pos }
});
};
void setName(Symbol & name);
string showNamePos() const;

View file

@ -31,7 +31,7 @@ namespace nix {
Expr * result;
Path basePath;
Symbol path;
string error;
ErrorInfo error;
Symbol sLetBody;
ParseData(EvalState & state)
: state(state)
@ -64,15 +64,20 @@ namespace nix {
static void dupAttr(const AttrPath & attrPath, const Pos & pos, const Pos & prevPos)
{
throw ParseError(format("attribute '%1%' at %2% already defined at %3%")
% showAttrPath(attrPath) % pos % prevPos);
throw ParseError({
.hint = hintfmt("attribute '%1%' already defined at %2%",
showAttrPath(attrPath), prevPos),
.nixCode = NixCode { .errPos = pos },
});
}
static void dupAttr(Symbol attr, const Pos & pos, const Pos & prevPos)
{
throw ParseError(format("attribute '%1%' at %2% already defined at %3%")
% attr % pos % prevPos);
throw ParseError({
.hint = hintfmt("attribute '%1%' already defined at %2%", attr, prevPos),
.nixCode = NixCode { .errPos = pos },
});
}
@ -140,8 +145,11 @@ static void addAttr(ExprAttrs * attrs, AttrPath & attrPath,
static void addFormal(const Pos & pos, Formals * formals, const Formal & formal)
{
if (!formals->argNames.insert(formal.name).second)
throw ParseError(format("duplicate formal function argument '%1%' at %2%")
% formal.name % pos);
throw ParseError({
.hint = hintfmt("duplicate formal function argument '%1%'",
formal.name),
.nixCode = NixCode { .errPos = pos },
});
formals->formals.push_front(formal);
}
@ -249,8 +257,10 @@ static inline Pos makeCurPos(const YYLTYPE & loc, ParseData * data)
void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * error)
{
data->error = (format("%1%, at %2%")
% error % makeCurPos(*loc, data)).str();
data->error = {
.hint = hintfmt(error),
.nixCode = NixCode { .errPos = makeCurPos(*loc, data) }
};
}
@ -327,8 +337,10 @@ expr_function
{ $$ = new ExprWith(CUR_POS, $2, $4); }
| LET binds IN expr_function
{ if (!$2->dynamicAttrs.empty())
throw ParseError(format("dynamic attributes not allowed in let at %1%")
% CUR_POS);
throw ParseError({
.hint = hintfmt("dynamic attributes not allowed in let"),
.nixCode = NixCode { .errPos = CUR_POS },
});
$$ = new ExprLet($2, $4);
}
| expr_if
@ -405,7 +417,10 @@ expr_simple
| URI {
static bool noURLLiterals = settings.isExperimentalFeatureEnabled("no-url-literals");
if (noURLLiterals)
throw ParseError("URL literals are disabled, at %s", CUR_POS);
throw ParseError({
.hint = hintfmt("URL literals are disabled"),
.nixCode = NixCode { .errPos = CUR_POS }
});
$$ = new ExprString(data->symbols.create($1));
}
| '(' expr ')' { $$ = $2; }
@ -475,8 +490,10 @@ attrs
$$->push_back(AttrName(str->s));
delete str;
} else
throw ParseError(format("dynamic attributes not allowed in inherit at %1%")
% makeCurPos(@2, data));
throw ParseError({
.hint = hintfmt("dynamic attributes not allowed in inherit"),
.nixCode = NixCode { .errPos = makeCurPos(@2, data) },
});
}
| { $$ = new AttrPath; }
;
@ -671,11 +688,13 @@ Path EvalState::findFile(SearchPath & searchPath, const string & path, const Pos
Path res = r.second + suffix;
if (pathExists(res)) return canonPath(res);
}
format f = format(
"file '%1%' was not found in the Nix search path (add it using $NIX_PATH or -I)"
+ string(pos ? ", at %2%" : ""));
f.exceptions(boost::io::all_error_bits ^ boost::io::too_many_args_bit);
throw ThrownError(f % path % pos);
throw ThrownError({
.hint = hintfmt(evalSettings.pureEval
? "cannot look up '<%s>' in pure evaluation mode (use '--impure' to override)"
: "file '%s' was not found in the Nix search path (add it using $NIX_PATH or -I)",
path),
.nixCode = NixCode { .errPos = pos }
});
}
@ -691,7 +710,10 @@ std::pair<bool, std::string> EvalState::resolveSearchPathElem(const SearchPathEl
res = { true, store->toRealPath(fetchers::downloadTarball(
store, resolveUri(elem.second), "source", false).first.storePath) };
} catch (FileTransferError & e) {
printError(format("warning: Nix search path entry '%1%' cannot be downloaded, ignoring") % elem.second);
logWarning({
.name = "Entry download",
.hint = hintfmt("Nix search path entry '%1%' cannot be downloaded, ignoring", elem.second)
});
res = { false, "" };
}
} else {
@ -699,7 +721,10 @@ std::pair<bool, std::string> EvalState::resolveSearchPathElem(const SearchPathEl
if (pathExists(path))
res = { true, path };
else {
printError(format("warning: Nix search path entry '%1%' does not exist, ignoring") % elem.second);
logWarning({
.name = "Entry not found",
.hint = hintfmt("warning: Nix search path entry '%1%' does not exist, ignoring", elem.second)
});
res = { false, "" };
}
}

View file

@ -55,7 +55,7 @@ void EvalState::realiseContext(const PathSet & context)
if (!store->isValidPath(ctx))
throw InvalidPathError(store->printStorePath(ctx));
if (!outputName.empty() && ctx.isDerivation()) {
drvs.push_back(StorePathWithOutputs{ctx.clone(), {outputName}});
drvs.push_back(StorePathWithOutputs{ctx, {outputName}});
/* Add the output of this derivation to the allowed
paths. */
@ -94,8 +94,10 @@ static void prim_scopedImport(EvalState & state, const Pos & pos, Value * * args
try {
state.realiseContext(context);
} catch (InvalidPathError & e) {
throw EvalError(format("cannot import '%1%', since path '%2%' is not valid, at %3%")
% path % e.path % pos);
throw EvalError({
.hint = hintfmt("cannot import '%1%', since path '%2%' is not valid", path, e.path),
.nixCode = NixCode { .errPos = pos }
});
}
Path realPath = state.checkSourcePath(state.toRealPath(path, context));
@ -171,8 +173,12 @@ void prim_importNative(EvalState & state, const Pos & pos, Value * * args, Value
try {
state.realiseContext(context);
} catch (InvalidPathError & e) {
throw EvalError(format("cannot import '%1%', since path '%2%' is not valid, at %3%")
% path % e.path % pos);
throw EvalError({
.hint = hintfmt(
"cannot import '%1%', since path '%2%' is not valid",
path, e.path),
.nixCode = NixCode { .errPos = pos }
});
}
path = state.checkSourcePath(path);
@ -181,17 +187,17 @@ void prim_importNative(EvalState & state, const Pos & pos, Value * * args, Value
void *handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
if (!handle)
throw EvalError(format("could not open '%1%': %2%") % path % dlerror());
throw EvalError("could not open '%1%': %2%", path, dlerror());
dlerror();
ValueInitializer func = (ValueInitializer) dlsym(handle, sym.c_str());
if(!func) {
char *message = dlerror();
if (message)
throw EvalError(format("could not load symbol '%1%' from '%2%': %3%") % sym % path % message);
throw EvalError("could not load symbol '%1%' from '%2%': %3%", sym, path, message);
else
throw EvalError(format("symbol '%1%' from '%2%' resolved to NULL when a function pointer was expected")
% sym % path);
throw EvalError("symbol '%1%' from '%2%' resolved to NULL when a function pointer was expected",
sym, path);
}
(func)(state, v);
@ -207,7 +213,10 @@ void prim_exec(EvalState & state, const Pos & pos, Value * * args, Value & v)
auto elems = args[0]->listElems();
auto count = args[0]->listSize();
if (count == 0) {
throw EvalError(format("at least one argument to 'exec' required, at %1%") % pos);
throw EvalError({
.hint = hintfmt("at least one argument to 'exec' required"),
.nixCode = NixCode { .errPos = pos }
});
}
PathSet context;
auto program = state.coerceToString(pos, *elems[0], context, false, false);
@ -218,8 +227,11 @@ void prim_exec(EvalState & state, const Pos & pos, Value * * args, Value & v)
try {
state.realiseContext(context);
} catch (InvalidPathError & e) {
throw EvalError(format("cannot execute '%1%', since path '%2%' is not valid, at %3%")
% program % e.path % pos);
throw EvalError({
.hint = hintfmt("cannot execute '%1%', since path '%2%' is not valid",
program, e.path),
.nixCode = NixCode { .errPos = pos }
});
}
auto output = runProgram(program, true, commandArgs);
@ -227,13 +239,13 @@ void prim_exec(EvalState & state, const Pos & pos, Value * * args, Value & v)
try {
parsed = state.parseExprFromString(output, pos.file);
} catch (Error & e) {
e.addPrefix(format("While parsing the output from '%1%', at %2%\n") % program % pos);
e.addPrefix(fmt("While parsing the output from '%1%', at %2%\n", program, pos));
throw;
}
try {
state.eval(parsed, v);
} catch (Error & e) {
e.addPrefix(format("While evaluating the output from '%1%', at %2%\n") % program % pos);
e.addPrefix(fmt("While evaluating the output from '%1%', at %2%\n", program, pos));
throw;
}
}
@ -339,7 +351,7 @@ struct CompareValues
if (v1->type == tInt && v2->type == tFloat)
return v1->integer < v2->fpoint;
if (v1->type != v2->type)
throw EvalError(format("cannot compare %1% with %2%") % showType(*v1) % showType(*v2));
throw EvalError("cannot compare %1% with %2%", showType(*v1), showType(*v2));
switch (v1->type) {
case tInt:
return v1->integer < v2->integer;
@ -350,7 +362,7 @@ struct CompareValues
case tPath:
return strcmp(v1->path, v2->path) < 0;
default:
throw EvalError(format("cannot compare %1% with %2%") % showType(*v1) % showType(*v2));
throw EvalError("cannot compare %1% with %2%", showType(*v1), showType(*v2));
}
}
};
@ -371,7 +383,10 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
Bindings::iterator startSet =
args[0]->attrs->find(state.symbols.create("startSet"));
if (startSet == args[0]->attrs->end())
throw EvalError(format("attribute 'startSet' required, at %1%") % pos);
throw EvalError({
.hint = hintfmt("attribute 'startSet' required"),
.nixCode = NixCode { .errPos = pos }
});
state.forceList(*startSet->value, pos);
ValueList workSet;
@ -382,7 +397,10 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
Bindings::iterator op =
args[0]->attrs->find(state.symbols.create("operator"));
if (op == args[0]->attrs->end())
throw EvalError(format("attribute 'operator' required, at %1%") % pos);
throw EvalError({
.hint = hintfmt("attribute 'operator' required"),
.nixCode = NixCode { .errPos = pos }
});
state.forceValue(*op->value, pos);
/* Construct the closure by applying the operator to element of
@ -401,7 +419,10 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
Bindings::iterator key =
e->attrs->find(state.symbols.create("key"));
if (key == e->attrs->end())
throw EvalError(format("attribute 'key' required, at %1%") % pos);
throw EvalError({
.hint = hintfmt("attribute 'key' required"),
.nixCode = NixCode { .errPos = pos }
});
state.forceValue(*key->value, pos);
if (!doneKeys.insert(key->value).second) continue;
@ -431,7 +452,7 @@ static void prim_abort(EvalState & state, const Pos & pos, Value * * args, Value
{
PathSet context;
string s = state.coerceToString(pos, *args[0], context);
throw Abort(format("evaluation aborted with the following error message: '%1%'") % s);
throw Abort("evaluation aborted with the following error message: '%1%'", s);
}
@ -506,9 +527,9 @@ static void prim_trace(EvalState & state, const Pos & pos, Value * * args, Value
{
state.forceValue(*args[0], pos);
if (args[0]->type == tString)
printError(format("trace: %1%") % args[0]->string.s);
printError("trace: %1%", args[0]->string.s);
else
printError(format("trace: %1%") % *args[0]);
printError("trace: %1%", *args[0]);