forked from lix-project/lix
Ensure that attrsets are sorted
Previously you had to remember to call value->attrs->sort() after populating value->attrs. Now there is a BindingsBuilder helper that wraps Bindings and ensures that sort() is called before you can use it.
This commit is contained in:
parent
1ffacad8a5
commit
6d9a6d2cc3
|
@ -41,16 +41,39 @@ Value * EvalState::allocAttr(Value & vAttrs, const Symbol & name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Value * EvalState::allocAttr(Value & vAttrs, const std::string & name)
|
Value * EvalState::allocAttr(Value & vAttrs, std::string_view name)
|
||||||
{
|
{
|
||||||
return allocAttr(vAttrs, symbols.create(name));
|
return allocAttr(vAttrs, symbols.create(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Value & BindingsBuilder::alloc(const Symbol & name, ptr<Pos> pos)
|
||||||
|
{
|
||||||
|
auto value = state.allocValue();
|
||||||
|
bindings->push_back(Attr(name, value, pos));
|
||||||
|
return *value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Value & BindingsBuilder::alloc(std::string_view name, ptr<Pos> pos)
|
||||||
|
{
|
||||||
|
return alloc(state.symbols.create(name), pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Bindings::sort()
|
void Bindings::sort()
|
||||||
{
|
{
|
||||||
std::sort(begin(), end());
|
std::sort(begin(), end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Value & Value::mkAttrs(BindingsBuilder & bindings)
|
||||||
|
{
|
||||||
|
clearValue();
|
||||||
|
internalType = tAttrs;
|
||||||
|
attrs = bindings.finish();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,5 +113,39 @@ public:
|
||||||
friend class EvalState;
|
friend class EvalState;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* A wrapper around Bindings that ensures that its always in sorted
|
||||||
|
order at the end. The only way to consume a BindingsBuilder is to
|
||||||
|
call finish(), which sorts the bindings. */
|
||||||
|
class BindingsBuilder
|
||||||
|
{
|
||||||
|
EvalState & state;
|
||||||
|
Bindings * bindings;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
BindingsBuilder(EvalState & state, Bindings * bindings)
|
||||||
|
: state(state), bindings(bindings)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void insert(Symbol name, Value * value, ptr<Pos> pos = ptr(&noPos))
|
||||||
|
{
|
||||||
|
insert(Attr(name, value, pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert(const Attr & attr)
|
||||||
|
{
|
||||||
|
bindings->push_back(attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Value & alloc(const Symbol & name, ptr<Pos> pos = ptr(&noPos));
|
||||||
|
|
||||||
|
Value & alloc(std::string_view name, ptr<Pos> pos = ptr(&noPos));
|
||||||
|
|
||||||
|
Bindings * finish()
|
||||||
|
{
|
||||||
|
bindings->sort();
|
||||||
|
return bindings;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,17 +73,16 @@ MixEvalArgs::MixEvalArgs()
|
||||||
|
|
||||||
Bindings * MixEvalArgs::getAutoArgs(EvalState & state)
|
Bindings * MixEvalArgs::getAutoArgs(EvalState & state)
|
||||||
{
|
{
|
||||||
Bindings * res = state.allocBindings(autoArgs.size());
|
auto res = state.buildBindings(autoArgs.size());
|
||||||
for (auto & i : autoArgs) {
|
for (auto & i : autoArgs) {
|
||||||
Value * v = state.allocValue();
|
auto v = state.allocValue();
|
||||||
if (i.second[0] == 'E')
|
if (i.second[0] == 'E')
|
||||||
state.mkThunk_(*v, state.parseExprFromString(string(i.second, 1), absPath(".")));
|
state.mkThunk_(*v, state.parseExprFromString(string(i.second, 1), absPath(".")));
|
||||||
else
|
else
|
||||||
mkString(*v, string(i.second, 1));
|
mkString(*v, string(i.second, 1));
|
||||||
res->push_back(Attr(state.symbols.create(i.first), v));
|
res.insert(state.symbols.create(i.first), v);
|
||||||
}
|
}
|
||||||
res->sort();
|
return res.finish();
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Path lookupFileArg(EvalState & state, string s)
|
Path lookupFileArg(EvalState & state, string s)
|
||||||
|
|
|
@ -772,18 +772,30 @@ void mkString(Value & v, const char * s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Value::mkString(std::string_view s)
|
||||||
|
{
|
||||||
|
mkString(dupStringWithLen(s.data(), s.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Value & mkString(Value & v, std::string_view s, const PathSet & context)
|
Value & mkString(Value & v, std::string_view s, const PathSet & context)
|
||||||
{
|
{
|
||||||
v.mkString(dupStringWithLen(s.data(), s.size()));
|
v.mkString(s, context);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Value::mkString(std::string_view s, const PathSet & context)
|
||||||
|
{
|
||||||
|
mkString(s);
|
||||||
if (!context.empty()) {
|
if (!context.empty()) {
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
v.string.context = (const char * *)
|
string.context = (const char * *)
|
||||||
allocBytes((context.size() + 1) * sizeof(char *));
|
allocBytes((context.size() + 1) * sizeof(char *));
|
||||||
for (auto & i : context)
|
for (auto & i : context)
|
||||||
v.string.context[n++] = dupString(i.c_str());
|
string.context[n++] = dupString(i.c_str());
|
||||||
v.string.context[n] = 0;
|
string.context[n] = 0;
|
||||||
}
|
}
|
||||||
return v;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -882,11 +894,11 @@ void EvalState::mkThunk_(Value & v, Expr * expr)
|
||||||
void EvalState::mkPos(Value & v, ptr<Pos> pos)
|
void EvalState::mkPos(Value & v, ptr<Pos> pos)
|
||||||
{
|
{
|
||||||
if (pos->file.set()) {
|
if (pos->file.set()) {
|
||||||
mkAttrs(v, 3);
|
auto attrs = buildBindings(3);
|
||||||
mkString(*allocAttr(v, sFile), pos->file);
|
attrs.alloc(sFile).mkString(pos->file);
|
||||||
mkInt(*allocAttr(v, sLine), pos->line);
|
attrs.alloc(sLine).mkInt(pos->line);
|
||||||
mkInt(*allocAttr(v, sColumn), pos->column);
|
attrs.alloc(sColumn).mkInt(pos->column);
|
||||||
v.attrs->sort();
|
v.mkAttrs(attrs);
|
||||||
} else
|
} else
|
||||||
mkNull(v);
|
mkNull(v);
|
||||||
}
|
}
|
||||||
|
@ -1341,7 +1353,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
|
||||||
/* Nope, so show the first unexpected argument to the
|
/* Nope, so show the first unexpected argument to the
|
||||||
user. */
|
user. */
|
||||||
for (auto & i : *args[0]->attrs)
|
for (auto & i : *args[0]->attrs)
|
||||||
if (lambda.formals->argNames.find(i.name) == lambda.formals->argNames.end())
|
if (!lambda.formals->argNames.count(i.name))
|
||||||
throwTypeError(pos, "%1% called with unexpected argument '%2%'", lambda, i.name);
|
throwTypeError(pos, "%1% called with unexpected argument '%2%'", lambda, i.name);
|
||||||
abort(); // can't happen
|
abort(); // can't happen
|
||||||
}
|
}
|
||||||
|
@ -1484,22 +1496,20 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value * actualArgs = allocValue();
|
auto attrs = buildBindings(std::max(static_cast<uint32_t>(fun.lambda.fun->formals->formals.size()), args.size()));
|
||||||
mkAttrs(*actualArgs, std::max(static_cast<uint32_t>(fun.lambda.fun->formals->formals.size()), args.size()));
|
|
||||||
|
|
||||||
if (fun.lambda.fun->formals->ellipsis) {
|
if (fun.lambda.fun->formals->ellipsis) {
|
||||||
// If the formals have an ellipsis (eg the function accepts extra args) pass
|
// If the formals have an ellipsis (eg the function accepts extra args) pass
|
||||||
// all available automatic arguments (which includes arguments specified on
|
// all available automatic arguments (which includes arguments specified on
|
||||||
// the command line via --arg/--argstr)
|
// the command line via --arg/--argstr)
|
||||||
for (auto& v : args) {
|
for (auto & v : args)
|
||||||
actualArgs->attrs->push_back(v);
|
attrs.insert(v);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, only pass the arguments that the function accepts
|
// Otherwise, only pass the arguments that the function accepts
|
||||||
for (auto & i : fun.lambda.fun->formals->formals) {
|
for (auto & i : fun.lambda.fun->formals->formals) {
|
||||||
Bindings::iterator j = args.find(i.name);
|
Bindings::iterator j = args.find(i.name);
|
||||||
if (j != args.end()) {
|
if (j != args.end()) {
|
||||||
actualArgs->attrs->push_back(*j);
|
attrs.insert(*j);
|
||||||
} else if (!i.def) {
|
} else if (!i.def) {
|
||||||
throwMissingArgumentError(i.pos, R"(cannot evaluate a function that has an argument without a value ('%1%')
|
throwMissingArgumentError(i.pos, R"(cannot evaluate a function that has an argument without a value ('%1%')
|
||||||
|
|
||||||
|
@ -1512,9 +1522,7 @@ https://nixos.org/manual/nix/stable/#ss-functions.)", i.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
actualArgs->attrs->sort();
|
callFunction(fun, allocValue()->mkAttrs(attrs), res, noPos);
|
||||||
|
|
||||||
callFunction(fun, *actualArgs, res, noPos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1719,7 +1727,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
||||||
auto path = canonPath(s.str());
|
auto path = canonPath(s.str());
|
||||||
mkPath(v, path.c_str());
|
mkPath(v, path.c_str());
|
||||||
} else
|
} else
|
||||||
mkString(v, s.str(), context);
|
v.mkString(s.str(), context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -339,10 +339,15 @@ public:
|
||||||
Env & allocEnv(size_t size);
|
Env & allocEnv(size_t size);
|
||||||
|
|
||||||
Value * allocAttr(Value & vAttrs, const Symbol & name);
|
Value * allocAttr(Value & vAttrs, const Symbol & name);
|
||||||
Value * allocAttr(Value & vAttrs, const std::string & name);
|
Value * allocAttr(Value & vAttrs, std::string_view name);
|
||||||
|
|
||||||
Bindings * allocBindings(size_t capacity);
|
Bindings * allocBindings(size_t capacity);
|
||||||
|
|
||||||
|
BindingsBuilder buildBindings(size_t capacity)
|
||||||
|
{
|
||||||
|
return BindingsBuilder(*this, allocBindings(capacity));
|
||||||
|
}
|
||||||
|
|
||||||
void mkList(Value & v, size_t length);
|
void mkList(Value & v, size_t length);
|
||||||
void mkAttrs(Value & v, size_t capacity);
|
void mkAttrs(Value & v, size_t capacity);
|
||||||
void mkThunk_(Value & v, Expr * expr);
|
void mkThunk_(Value & v, Expr * expr);
|
||||||
|
|
|
@ -254,15 +254,14 @@ bool DrvInfo::queryMetaBool(const string & name, bool def)
|
||||||
void DrvInfo::setMeta(const string & name, Value * v)
|
void DrvInfo::setMeta(const string & name, Value * v)
|
||||||
{
|
{
|
||||||
getMeta();
|
getMeta();
|
||||||
Bindings * old = meta;
|
auto attrs = state->buildBindings(1 + (meta ? meta->size() : 0));
|
||||||
meta = state->allocBindings(1 + (old ? old->size() : 0));
|
|
||||||
Symbol sym = state->symbols.create(name);
|
Symbol sym = state->symbols.create(name);
|
||||||
if (old)
|
if (meta)
|
||||||
for (auto i : *old)
|
for (auto i : *meta)
|
||||||
if (i.name != sym)
|
if (i.name != sym)
|
||||||
meta->push_back(i);
|
attrs.insert(i);
|
||||||
if (v) meta->push_back(Attr(sym, v));
|
if (v) attrs.insert(sym, v);
|
||||||
meta->sort();
|
meta = attrs.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -125,13 +125,15 @@ static Path realisePath(EvalState & state, const Pos & pos, Value & v, const Rea
|
||||||
the actual path.
|
the actual path.
|
||||||
|
|
||||||
The 'drv' and 'drvPath' outputs must correspond. */
|
The 'drv' and 'drvPath' outputs must correspond. */
|
||||||
static void mkOutputString(EvalState & state, Value & v,
|
static void mkOutputString(
|
||||||
const StorePath & drvPath, const BasicDerivation & drv,
|
EvalState & state,
|
||||||
std::pair<string, DerivationOutput> o)
|
BindingsBuilder & attrs,
|
||||||
|
const StorePath & drvPath,
|
||||||
|
const BasicDerivation & drv,
|
||||||
|
const std::pair<string, DerivationOutput> & o)
|
||||||
{
|
{
|
||||||
auto optOutputPath = o.second.path(*state.store, drv.name, o.first);
|
auto optOutputPath = o.second.path(*state.store, drv.name, o.first);
|
||||||
mkString(
|
attrs.alloc(o.first).mkString(
|
||||||
*state.allocAttr(v, state.symbols.create(o.first)),
|
|
||||||
optOutputPath
|
optOutputPath
|
||||||
? state.store->printStorePath(*optOutputPath)
|
? state.store->printStorePath(*optOutputPath)
|
||||||
/* Downstream we would substitute this for an actual path once
|
/* Downstream we would substitute this for an actual path once
|
||||||
|
@ -172,23 +174,19 @@ static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vS
|
||||||
if (auto optStorePath = isValidDerivationInStore()) {
|
if (auto optStorePath = isValidDerivationInStore()) {
|
||||||
auto storePath = *optStorePath;
|
auto storePath = *optStorePath;
|
||||||
Derivation drv = state.store->readDerivation(storePath);
|
Derivation drv = state.store->readDerivation(storePath);
|
||||||
Value & w = *state.allocValue();
|
auto attrs = state.buildBindings(3 + drv.outputs.size());
|
||||||
state.mkAttrs(w, 3 + drv.outputs.size());
|
attrs.alloc(state.sDrvPath).mkString(path, {"=" + path});
|
||||||
Value * v2 = state.allocAttr(w, state.sDrvPath);
|
attrs.alloc(state.sName).mkString(drv.env["name"]);
|
||||||
mkString(*v2, path, {"=" + path});
|
auto & outputsVal = attrs.alloc(state.sOutputs);
|
||||||
v2 = state.allocAttr(w, state.sName);
|
state.mkList(outputsVal, drv.outputs.size());
|
||||||
mkString(*v2, drv.env["name"]);
|
|
||||||
Value * outputsVal =
|
|
||||||
state.allocAttr(w, state.symbols.create("outputs"));
|
|
||||||
state.mkList(*outputsVal, drv.outputs.size());
|
|
||||||
unsigned int outputs_index = 0;
|
|
||||||
|
|
||||||
for (const auto & o : drv.outputs) {
|
for (const auto & [i, o] : enumerate(drv.outputs)) {
|
||||||
mkOutputString(state, w, storePath, drv, o);
|
mkOutputString(state, attrs, storePath, drv, o);
|
||||||
outputsVal->listElems()[outputs_index] = state.allocValue();
|
(outputsVal.listElems()[i] = state.allocValue())->mkString(o.first);
|
||||||
mkString(*(outputsVal->listElems()[outputs_index++]), o.first);
|
|
||||||
}
|
}
|
||||||
w.attrs->sort();
|
|
||||||
|
auto w = state.allocValue();
|
||||||
|
w->mkAttrs(attrs);
|
||||||
|
|
||||||
if (!state.vImportedDrvToDerivation) {
|
if (!state.vImportedDrvToDerivation) {
|
||||||
state.vImportedDrvToDerivation = allocRootValue(state.allocValue());
|
state.vImportedDrvToDerivation = allocRootValue(state.allocValue());
|
||||||
|
@ -198,7 +196,7 @@ static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vS
|
||||||
}
|
}
|
||||||
|
|
||||||
state.forceFunction(**state.vImportedDrvToDerivation, pos);
|
state.forceFunction(**state.vImportedDrvToDerivation, pos);
|
||||||
mkApp(v, **state.vImportedDrvToDerivation, w);
|
mkApp(v, **state.vImportedDrvToDerivation, *w);
|
||||||
state.forceAttrs(v, pos);
|
state.forceAttrs(v, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -802,16 +800,16 @@ static RegisterPrimOp primop_floor({
|
||||||
* else => {success=false; value=false;} */
|
* else => {success=false; value=false;} */
|
||||||
static void prim_tryEval(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
static void prim_tryEval(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
state.mkAttrs(v, 2);
|
auto attrs = state.buildBindings(2);
|
||||||
try {
|
try {
|
||||||
state.forceValue(*args[0], pos);
|
state.forceValue(*args[0], pos);
|
||||||
v.attrs->push_back(Attr(state.sValue, args[0]));
|
attrs.insert(state.sValue, args[0]);
|
||||||
mkBool(*state.allocAttr(v, state.symbols.create("success")), true);
|
mkBool(attrs.alloc("success"), true);
|
||||||
} catch (AssertionError & e) {
|
} catch (AssertionError & e) {
|
||||||
mkBool(*state.allocAttr(v, state.sValue), false);
|
mkBool(attrs.alloc(state.sValue), false);
|
||||||
mkBool(*state.allocAttr(v, state.symbols.create("success")), false);
|
mkBool(attrs.alloc("success"), false);
|
||||||
}
|
}
|
||||||
v.attrs->sort();
|
v.mkAttrs(attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_tryEval({
|
static RegisterPrimOp primop_tryEval({
|
||||||
|
@ -839,7 +837,7 @@ static RegisterPrimOp primop_tryEval({
|
||||||
static void prim_getEnv(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
static void prim_getEnv(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
string name = state.forceStringNoCtx(*args[0], pos);
|
string name = state.forceStringNoCtx(*args[0], pos);
|
||||||
mkString(v, evalSettings.restrictEval || evalSettings.pureEval ? "" : getEnv(name).value_or(""));
|
v.mkString(evalSettings.restrictEval || evalSettings.pureEval ? "" : getEnv(name).value_or(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_getEnv({
|
static RegisterPrimOp primop_getEnv({
|
||||||
|
@ -1265,11 +1263,11 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
|
||||||
drvHashes.lock()->insert_or_assign(drvPath, h);
|
drvHashes.lock()->insert_or_assign(drvPath, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
state.mkAttrs(v, 1 + drv.outputs.size());
|
auto attrs = state.buildBindings(1 + drv.outputs.size());
|
||||||
mkString(*state.allocAttr(v, state.sDrvPath), drvPathS, {"=" + drvPathS});
|
attrs.alloc(state.sDrvPath).mkString(drvPathS, {"=" + drvPathS});
|
||||||
for (auto & i : drv.outputs)
|
for (auto & i : drv.outputs)
|
||||||
mkOutputString(state, v, drvPath, drv, i);
|
mkOutputString(state, attrs, drvPath, drv, i);
|
||||||
v.attrs->sort();
|
v.mkAttrs(attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_derivationStrict(RegisterPrimOp::Info {
|
static RegisterPrimOp primop_derivationStrict(RegisterPrimOp::Info {
|
||||||
|
@ -1579,20 +1577,20 @@ static void prim_readDir(EvalState & state, const Pos & pos, Value * * args, Val
|
||||||
}
|
}
|
||||||
|
|
||||||
DirEntries entries = readDirectory(path);
|
DirEntries entries = readDirectory(path);
|
||||||
state.mkAttrs(v, entries.size());
|
|
||||||
|
auto attrs = state.buildBindings(entries.size());
|
||||||
|
|
||||||
for (auto & ent : entries) {
|
for (auto & ent : entries) {
|
||||||
Value * ent_val = state.allocAttr(v, state.symbols.create(ent.name));
|
|
||||||
if (ent.type == DT_UNKNOWN)
|
if (ent.type == DT_UNKNOWN)
|
||||||
ent.type = getFileType(path + "/" + ent.name);
|
ent.type = getFileType(path + "/" + ent.name);
|
||||||
ent_val->mkString(
|
attrs.alloc(ent.name).mkString(
|
||||||
ent.type == DT_REG ? "regular" :
|
ent.type == DT_REG ? "regular" :
|
||||||
ent.type == DT_DIR ? "directory" :
|
ent.type == DT_DIR ? "directory" :
|
||||||
ent.type == DT_LNK ? "symlink" :
|
ent.type == DT_LNK ? "symlink" :
|
||||||
"unknown");
|
"unknown");
|
||||||
}
|
}
|
||||||
|
|
||||||
v.attrs->sort();
|
v.mkAttrs(attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_readDir({
|
static RegisterPrimOp primop_readDir({
|
||||||
|
@ -2308,7 +2306,7 @@ static void prim_listToAttrs(EvalState & state, const Pos & pos, Value * * args,
|
||||||
{
|
{
|
||||||
state.forceList(*args[0], pos);
|
state.forceList(*args[0], pos);
|
||||||
|
|
||||||
state.mkAttrs(v, args[0]->listSize());
|
auto attrs = state.buildBindings(args[0]->listSize());
|
||||||
|
|
||||||
std::set<Symbol> seen;
|
std::set<Symbol> seen;
|
||||||
|
|
||||||
|
@ -2334,11 +2332,11 @@ static void prim_listToAttrs(EvalState & state, const Pos & pos, Value * * args,
|
||||||
v2->attrs,
|
v2->attrs,
|
||||||
pos
|
pos
|
||||||
);
|
);
|
||||||
v.attrs->push_back(Attr(sym, j2->value, j2->pos));
|
attrs.insert(sym, j2->value, j2->pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
v.attrs->sort();
|
v.mkAttrs(attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_listToAttrs({
|
static RegisterPrimOp primop_listToAttrs({
|
||||||
|
@ -2445,14 +2443,11 @@ static void prim_functionArgs(EvalState & state, const Pos & pos, Value * * args
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.mkAttrs(v, args[0]->lambda.fun->formals->formals.size());
|
auto attrs = state.buildBindings(args[0]->lambda.fun->formals->formals.size());
|
||||||
for (auto & i : args[0]->lambda.fun->formals->formals) {
|
for (auto & i : args[0]->lambda.fun->formals->formals)
|
||||||
// !!! should optimise booleans (allocate only once)
|
// !!! should optimise booleans (allocate only once)
|
||||||
Value * value = state.allocValue();
|
mkBool(attrs.alloc(i.name, ptr(&i.pos)), i.def);
|
||||||
v.attrs->push_back(Attr(i.name, value, ptr(&i.pos)));
|
v.mkAttrs(attrs);
|
||||||
mkBool(*value, i.def);
|
|
||||||
}
|
|
||||||
v.attrs->sort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_functionArgs({
|
static RegisterPrimOp primop_functionArgs({
|
||||||
|
@ -3003,21 +2998,21 @@ static void prim_partition(EvalState & state, const Pos & pos, Value * * args, V
|
||||||
wrong.push_back(vElem);
|
wrong.push_back(vElem);
|
||||||
}
|
}
|
||||||
|
|
||||||
state.mkAttrs(v, 2);
|
auto attrs = state.buildBindings(2);
|
||||||
|
|
||||||
Value * vRight = state.allocAttr(v, state.sRight);
|
auto & vRight = attrs.alloc(state.sRight);
|
||||||
auto rsize = right.size();
|
auto rsize = right.size();
|
||||||
state.mkList(*vRight, rsize);
|
state.mkList(vRight, rsize);
|
||||||
if (rsize)
|
if (rsize)
|
||||||
memcpy(vRight->listElems(), right.data(), sizeof(Value *) * rsize);
|
memcpy(vRight.listElems(), right.data(), sizeof(Value *) * rsize);
|
||||||
|
|
||||||
Value * vWrong = state.allocAttr(v, state.sWrong);
|
auto & vWrong = attrs.alloc(state.sWrong);
|
||||||
auto wsize = wrong.size();
|
auto wsize = wrong.size();
|
||||||
state.mkList(*vWrong, wsize);
|
state.mkList(vWrong, wsize);
|
||||||
if (wsize)
|
if (wsize)
|
||||||
memcpy(vWrong->listElems(), wrong.data(), sizeof(Value *) * wsize);
|
memcpy(vWrong.listElems(), wrong.data(), sizeof(Value *) * wsize);
|
||||||
|
|
||||||
v.attrs->sort();
|
v.mkAttrs(attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_partition({
|
static RegisterPrimOp primop_partition({
|
||||||
|
@ -3734,10 +3729,10 @@ static void prim_parseDrvName(EvalState & state, const Pos & pos, Value * * args
|
||||||
{
|
{
|
||||||
string name = state.forceStringNoCtx(*args[0], pos);
|
string name = state.forceStringNoCtx(*args[0], pos);
|
||||||
DrvName parsed(name);
|
DrvName parsed(name);
|
||||||
state.mkAttrs(v, 2);
|
auto attrs = state.buildBindings(2);
|
||||||
mkString(*state.allocAttr(v, state.sName), parsed.name);
|
attrs.alloc(state.sName).mkString(parsed.name);
|
||||||
mkString(*state.allocAttr(v, state.symbols.create("version")), parsed.version);
|
attrs.alloc("version").mkString(parsed.version);
|
||||||
v.attrs->sort();
|
v.mkAttrs(attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_parseDrvName({
|
static RegisterPrimOp primop_parseDrvName({
|
||||||
|
@ -3883,11 +3878,10 @@ void EvalState::createBaseEnv()
|
||||||
mkList(v, searchPath.size());
|
mkList(v, searchPath.size());
|
||||||
int n = 0;
|
int n = 0;
|
||||||
for (auto & i : searchPath) {
|
for (auto & i : searchPath) {
|
||||||
auto v2 = v.listElems()[n++] = allocValue();
|
auto attrs = buildBindings(2);
|
||||||
mkAttrs(*v2, 2);
|
attrs.alloc("path").mkString(i.second);
|
||||||
mkString(*allocAttr(*v2, symbols.create("path")), i.second);
|
attrs.alloc("prefix").mkString(i.first);
|
||||||
mkString(*allocAttr(*v2, symbols.create("prefix")), i.first);
|
(v.listElems()[n++] = allocValue())->mkAttrs(attrs);
|
||||||
v2->attrs->sort();
|
|
||||||
}
|
}
|
||||||
addConstant("__nixPath", v);
|
addConstant("__nixPath", v);
|
||||||
|
|
||||||
|
|
|
@ -103,27 +103,26 @@ static void prim_getContext(EvalState & state, const Pos & pos, Value * * args,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
state.mkAttrs(v, contextInfos.size());
|
auto attrs = state.buildBindings(contextInfos.size());
|
||||||
|
|
||||||
auto sPath = state.symbols.create("path");
|
auto sPath = state.symbols.create("path");
|
||||||
auto sAllOutputs = state.symbols.create("allOutputs");
|
auto sAllOutputs = state.symbols.create("allOutputs");
|
||||||
for (const auto & info : contextInfos) {
|
for (const auto & info : contextInfos) {
|
||||||
auto & infoVal = *state.allocAttr(v, state.symbols.create(info.first));
|
auto infoAttrs = state.buildBindings(3);
|
||||||
state.mkAttrs(infoVal, 3);
|
|
||||||
if (info.second.path)
|
if (info.second.path)
|
||||||
mkBool(*state.allocAttr(infoVal, sPath), true);
|
mkBool(infoAttrs.alloc(sPath), true);
|
||||||
if (info.second.allOutputs)
|
if (info.second.allOutputs)
|
||||||
mkBool(*state.allocAttr(infoVal, sAllOutputs), true);
|
mkBool(infoAttrs.alloc(sAllOutputs), true);
|
||||||
if (!info.second.outputs.empty()) {
|
if (!info.second.outputs.empty()) {
|
||||||
auto & outputsVal = *state.allocAttr(infoVal, state.sOutputs);
|
auto & outputsVal = infoAttrs.alloc(state.sOutputs);
|
||||||
state.mkList(outputsVal, info.second.outputs.size());
|
state.mkList(outputsVal, info.second.outputs.size());
|
||||||
size_t i = 0;
|
for (const auto & [i, output] : enumerate(info.second.outputs))
|
||||||
for (const auto & output : info.second.outputs)
|
(outputsVal.listElems()[i] = state.allocValue())->mkString(output);
|
||||||
mkString(*(outputsVal.listElems()[i++] = state.allocValue()), output);
|
|
||||||
}
|
}
|
||||||
infoVal.attrs->sort();
|
attrs.alloc(info.first).mkAttrs(infoAttrs);
|
||||||
}
|
}
|
||||||
v.attrs->sort();
|
|
||||||
|
v.mkAttrs(attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_getContext("__getContext", 1, prim_getContext);
|
static RegisterPrimOp primop_getContext("__getContext", 1, prim_getContext);
|
||||||
|
|
|
@ -70,19 +70,19 @@ static void prim_fetchMercurial(EvalState & state, const Pos & pos, Value * * ar
|
||||||
// FIXME: use name
|
// FIXME: use name
|
||||||
auto [tree, input2] = input.fetch(state.store);
|
auto [tree, input2] = input.fetch(state.store);
|
||||||
|
|
||||||
state.mkAttrs(v, 8);
|
auto attrs2 = state.buildBindings(8);
|
||||||
auto storePath = state.store->printStorePath(tree.storePath);
|
auto storePath = state.store->printStorePath(tree.storePath);
|
||||||
mkString(*state.allocAttr(v, state.sOutPath), storePath, PathSet({storePath}));
|
attrs2.alloc(state.sOutPath).mkString(storePath, {storePath});
|
||||||
if (input2.getRef())
|
if (input2.getRef())
|
||||||
mkString(*state.allocAttr(v, state.symbols.create("branch")), *input2.getRef());
|
attrs2.alloc("branch").mkString(*input2.getRef());
|
||||||
// Backward compatibility: set 'rev' to
|
// Backward compatibility: set 'rev' to
|
||||||
// 0000000000000000000000000000000000000000 for a dirty tree.
|
// 0000000000000000000000000000000000000000 for a dirty tree.
|
||||||
auto rev2 = input2.getRev().value_or(Hash(htSHA1));
|
auto rev2 = input2.getRev().value_or(Hash(htSHA1));
|
||||||
mkString(*state.allocAttr(v, state.symbols.create("rev")), rev2.gitRev());
|
attrs2.alloc("rev").mkString(rev2.gitRev());
|
||||||
mkString(*state.allocAttr(v, state.symbols.create("shortRev")), std::string(rev2.gitRev(), 0, 12));
|
attrs2.alloc("shortRev").mkString(rev2.gitRev().substr(0, 12));
|
||||||
if (auto revCount = input2.getRevCount())
|
if (auto revCount = input2.getRevCount())
|
||||||
mkInt(*state.allocAttr(v, state.symbols.create("revCount")), *revCount);
|
attrs2.alloc("revCount").mkInt(*revCount);
|
||||||
v.attrs->sort();
|
v.mkAttrs(attrs2);
|
||||||
|
|
||||||
state.allowPath(tree.storePath);
|
state.allowPath(tree.storePath);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,49 +21,48 @@ void emitTreeAttrs(
|
||||||
{
|
{
|
||||||
assert(input.isImmutable());
|
assert(input.isImmutable());
|
||||||
|
|
||||||
state.mkAttrs(v, 8);
|
auto attrs = state.buildBindings(8);
|
||||||
|
|
||||||
auto storePath = state.store->printStorePath(tree.storePath);
|
auto storePath = state.store->printStorePath(tree.storePath);
|
||||||
|
|
||||||
mkString(*state.allocAttr(v, state.sOutPath), storePath, PathSet({storePath}));
|
attrs.alloc(state.sOutPath).mkString(storePath, {storePath});
|
||||||
|
|
||||||
// FIXME: support arbitrary input attributes.
|
// FIXME: support arbitrary input attributes.
|
||||||
|
|
||||||
auto narHash = input.getNarHash();
|
auto narHash = input.getNarHash();
|
||||||
assert(narHash);
|
assert(narHash);
|
||||||
mkString(*state.allocAttr(v, state.symbols.create("narHash")),
|
attrs.alloc("narHash").mkString(narHash->to_string(SRI, true));
|
||||||
narHash->to_string(SRI, true));
|
|
||||||
|
|
||||||
if (input.getType() == "git")
|
if (input.getType() == "git")
|
||||||
mkBool(*state.allocAttr(v, state.symbols.create("submodules")),
|
attrs.alloc("submodules").mkBool(
|
||||||
fetchers::maybeGetBoolAttr(input.attrs, "submodules").value_or(false));
|
fetchers::maybeGetBoolAttr(input.attrs, "submodules").value_or(false));
|
||||||
|
|
||||||
if (!forceDirty) {
|
if (!forceDirty) {
|
||||||
|
|
||||||
if (auto rev = input.getRev()) {
|
if (auto rev = input.getRev()) {
|
||||||
mkString(*state.allocAttr(v, state.symbols.create("rev")), rev->gitRev());
|
attrs.alloc("rev").mkString(rev->gitRev());
|
||||||
mkString(*state.allocAttr(v, state.symbols.create("shortRev")), rev->gitShortRev());
|
attrs.alloc("shortRev").mkString(rev->gitShortRev());
|
||||||
} else if (emptyRevFallback) {
|
} else if (emptyRevFallback) {
|
||||||
// Backwards compat for `builtins.fetchGit`: dirty repos return an empty sha1 as rev
|
// Backwards compat for `builtins.fetchGit`: dirty repos return an empty sha1 as rev
|
||||||
auto emptyHash = Hash(htSHA1);
|
auto emptyHash = Hash(htSHA1);
|
||||||
mkString(*state.allocAttr(v, state.symbols.create("rev")), emptyHash.gitRev());
|
attrs.alloc("rev").mkString(emptyHash.gitRev());
|
||||||
mkString(*state.allocAttr(v, state.symbols.create("shortRev")), emptyHash.gitShortRev());
|
attrs.alloc("shortRev").mkString(emptyHash.gitShortRev());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto revCount = input.getRevCount())
|
if (auto revCount = input.getRevCount())
|
||||||
mkInt(*state.allocAttr(v, state.symbols.create("revCount")), *revCount);
|
attrs.alloc("revCount").mkInt(*revCount);
|
||||||
else if (emptyRevFallback)
|
else if (emptyRevFallback)
|
||||||
mkInt(*state.allocAttr(v, state.symbols.create("revCount")), 0);
|
attrs.alloc("revCount").mkInt(0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto lastModified = input.getLastModified()) {
|
if (auto lastModified = input.getLastModified()) {
|
||||||
mkInt(*state.allocAttr(v, state.symbols.create("lastModified")), *lastModified);
|
attrs.alloc("lastModified").mkInt(*lastModified);
|
||||||
mkString(*state.allocAttr(v, state.symbols.create("lastModifiedDate")),
|
attrs.alloc("lastModifiedDate").mkString(
|
||||||
fmt("%s", std::put_time(std::gmtime(&*lastModified), "%Y%m%d%H%M%S")));
|
fmt("%s", std::put_time(std::gmtime(&*lastModified), "%Y%m%d%H%M%S")));
|
||||||
}
|
}
|
||||||
|
|
||||||
v.attrs->sort();
|
v.mkAttrs(attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string fixURI(std::string uri, EvalState & state, const std::string & defaultScheme = "file")
|
std::string fixURI(std::string uri, EvalState & state, const std::string & defaultScheme = "file")
|
||||||
|
|
|
@ -24,15 +24,12 @@ static void prim_fromTOML(EvalState & state, const Pos & pos, Value * * args, Va
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
for (auto & i : table) { (void) i; size++; }
|
for (auto & i : table) { (void) i; size++; }
|
||||||
|
|
||||||
state.mkAttrs(v, size);
|
auto attrs = state.buildBindings(size);
|
||||||
|
|
||||||
for(auto & elem: table) {
|
for(auto & elem : table)
|
||||||
|
visit(attrs.alloc(elem.first), elem.second);
|
||||||
|
|
||||||
auto & v2 = *state.allocAttr(v, state.symbols.create(elem.first));
|
v.mkAttrs(attrs);
|
||||||
visit(v2, elem.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
v.attrs->sort();
|
|
||||||
}
|
}
|
||||||
break;;
|
break;;
|
||||||
case toml::value_t::array:
|
case toml::value_t::array:
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
class BindingsBuilder;
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
tInt = 1,
|
tInt = 1,
|
||||||
|
@ -235,6 +237,10 @@ public:
|
||||||
string.context = context;
|
string.context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mkString(std::string_view s);
|
||||||
|
|
||||||
|
void mkString(std::string_view s, const PathSet & context);
|
||||||
|
|
||||||
inline void mkPath(const char * s)
|
inline void mkPath(const char * s)
|
||||||
{
|
{
|
||||||
clearValue();
|
clearValue();
|
||||||
|
@ -255,6 +261,8 @@ public:
|
||||||
attrs = a;
|
attrs = a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Value & mkAttrs(BindingsBuilder & bindings);
|
||||||
|
|
||||||
inline void mkList(size_t size)
|
inline void mkList(size_t size)
|
||||||
{
|
{
|
||||||
clearValue();
|
clearValue();
|
||||||
|
|
|
@ -258,13 +258,10 @@ static void main_nix_build(int argc, char * * argv)
|
||||||
auto autoArgs = myArgs.getAutoArgs(*state);
|
auto autoArgs = myArgs.getAutoArgs(*state);
|
||||||
|
|
||||||
if (runEnv) {
|
if (runEnv) {
|
||||||
auto newArgs = state->allocBindings(autoArgs->size() + 1);
|
auto newArgs = state->buildBindings(autoArgs->size() + 1);
|
||||||
auto tru = state->allocValue();
|
newArgs.alloc("inNixShell").mkBool(true);
|
||||||
mkBool(*tru, true);
|
for (auto & i : *autoArgs) newArgs.insert(i);
|
||||||
newArgs->push_back(Attr(state->symbols.create("inNixShell"), tru));
|
autoArgs = newArgs.finish();
|
||||||
for (auto & i : *autoArgs) newArgs->push_back(i);
|
|
||||||
newArgs->sort();
|
|
||||||
autoArgs = newArgs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packages) {
|
if (packages) {
|
||||||
|
|
|
@ -98,8 +98,11 @@ static bool isNixExpr(const Path & path, struct stat & st)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static constexpr size_t maxAttrs = 1024;
|
||||||
|
|
||||||
|
|
||||||
static void getAllExprs(EvalState & state,
|
static void getAllExprs(EvalState & state,
|
||||||
const Path & path, StringSet & attrs, Value & v)
|
const Path & path, StringSet & seen, BindingsBuilder & attrs)
|
||||||
{
|
{
|
||||||
StringSet namesSorted;
|
StringSet namesSorted;
|
||||||
for (auto & i : readDirectory(path)) namesSorted.insert(i.name);
|
for (auto & i : readDirectory(path)) namesSorted.insert(i.name);
|
||||||
|
@ -124,22 +127,21 @@ static void getAllExprs(EvalState & state,
|
||||||
string attrName = i;
|
string attrName = i;
|
||||||
if (hasSuffix(attrName, ".nix"))
|
if (hasSuffix(attrName, ".nix"))
|
||||||
attrName = string(attrName, 0, attrName.size() - 4);
|
attrName = string(attrName, 0, attrName.size() - 4);
|
||||||
if (!attrs.insert(attrName).second) {
|
if (!seen.insert(attrName).second) {
|
||||||
printError("warning: name collision in input Nix expressions, skipping '%1%'", path2);
|
printError("warning: name collision in input Nix expressions, skipping '%1%'", path2);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Load the expression on demand. */
|
/* Load the expression on demand. */
|
||||||
Value & vFun = state.getBuiltin("import");
|
auto vArg = state.allocValue();
|
||||||
Value & vArg(*state.allocValue());
|
vArg->mkString(path2);
|
||||||
mkString(vArg, path2);
|
if (seen.size() == maxAttrs)
|
||||||
if (v.attrs->size() == v.attrs->capacity())
|
|
||||||
throw Error("too many Nix expressions in directory '%1%'", path);
|
throw Error("too many Nix expressions in directory '%1%'", path);
|
||||||
mkApp(*state.allocAttr(v, state.symbols.create(attrName)), vFun, vArg);
|
attrs.alloc(attrName).mkApp(&state.getBuiltin("import"), vArg);
|
||||||
}
|
}
|
||||||
else if (S_ISDIR(st.st_mode))
|
else if (S_ISDIR(st.st_mode))
|
||||||
/* `path2' is a directory (with no default.nix in it);
|
/* `path2' is a directory (with no default.nix in it);
|
||||||
recurse into it. */
|
recurse into it. */
|
||||||
getAllExprs(state, path2, attrs, v);
|
getAllExprs(state, path2, seen, attrs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,11 +163,11 @@ static void loadSourceExpr(EvalState & state, const Path & path, Value & v)
|
||||||
~/.nix-defexpr directory that includes some system-wide
|
~/.nix-defexpr directory that includes some system-wide
|
||||||
directory). */
|
directory). */
|
||||||
else if (S_ISDIR(st.st_mode)) {
|
else if (S_ISDIR(st.st_mode)) {
|
||||||
state.mkAttrs(v, 1024);
|
auto attrs = state.buildBindings(maxAttrs);
|
||||||
state.mkList(*state.allocAttr(v, state.symbols.create("_combineChannels")), 0);
|
attrs.alloc("_combineChannels").mkList(0);
|
||||||
StringSet attrs;
|
StringSet seen;
|
||||||
getAllExprs(state, path, attrs, v);
|
getAllExprs(state, path, seen, attrs);
|
||||||
v.attrs->sort();
|
v.mkAttrs(attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
else throw Error("path '%s' is not a directory or a Nix expression", path);
|
else throw Error("path '%s' is not a directory or a Nix expression", path);
|
||||||
|
|
|
@ -50,7 +50,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
||||||
StorePathSet references;
|
StorePathSet references;
|
||||||
Value manifest;
|
Value manifest;
|
||||||
state.mkList(manifest, elems.size());
|
state.mkList(manifest, elems.size());
|
||||||
unsigned int n = 0;
|
size_t n = 0;
|
||||||
for (auto & i : elems) {
|
for (auto & i : elems) {
|
||||||
/* Create a pseudo-derivation containing the name, system,
|
/* Create a pseudo-derivation containing the name, system,
|
||||||
output paths, and optionally the derivation path, as well
|
output paths, and optionally the derivation path, as well
|
||||||
|
@ -59,28 +59,25 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
||||||
DrvInfo::Outputs outputs = i.queryOutputs(true);
|
DrvInfo::Outputs outputs = i.queryOutputs(true);
|
||||||
StringSet metaNames = i.queryMetaNames();
|
StringSet metaNames = i.queryMetaNames();
|
||||||
|
|
||||||
Value & v(*state.allocValue());
|
auto attrs = state.buildBindings(7 + outputs.size());
|
||||||
manifest.listElems()[n++] = &v;
|
|
||||||
state.mkAttrs(v, 7 + outputs.size());
|
|
||||||
|
|
||||||
mkString(*state.allocAttr(v, state.sType), "derivation");
|
attrs.alloc(state.sType).mkString("derivation");
|
||||||
mkString(*state.allocAttr(v, state.sName), i.queryName());
|
attrs.alloc(state.sName).mkString(i.queryName());
|
||||||
auto system = i.querySystem();
|
auto system = i.querySystem();
|
||||||
if (!system.empty())
|
if (!system.empty())
|
||||||
mkString(*state.allocAttr(v, state.sSystem), system);
|
attrs.alloc(state.sSystem).mkString(system);
|
||||||
mkString(*state.allocAttr(v, state.sOutPath), i.queryOutPath());
|
attrs.alloc(state.sOutPath).mkString(i.queryOutPath());
|
||||||
if (drvPath != "")
|
if (drvPath != "")
|
||||||
mkString(*state.allocAttr(v, state.sDrvPath), i.queryDrvPath());
|
attrs.alloc(state.sDrvPath).mkString(i.queryDrvPath());
|
||||||
|
|
||||||
// Copy each output meant for installation.
|
// Copy each output meant for installation.
|
||||||
Value & vOutputs = *state.allocAttr(v, state.sOutputs);
|
auto & vOutputs = attrs.alloc(state.sOutputs);
|
||||||
state.mkList(vOutputs, outputs.size());
|
state.mkList(vOutputs, outputs.size());
|
||||||
unsigned int m = 0;
|
for (const auto & [m, j] : enumerate(outputs)) {
|
||||||
for (auto & j : outputs) {
|
(vOutputs.listElems()[m] = state.allocValue())->mkString(j.first);
|
||||||
mkString(*(vOutputs.listElems()[m++] = state.allocValue()), j.first);
|
auto outputAttrs = state.buildBindings(2);
|
||||||
Value & vOutputs = *state.allocAttr(v, state.symbols.create(j.first));
|
outputAttrs.alloc(state.sOutPath).mkString(j.second);
|
||||||
state.mkAttrs(vOutputs, 2);
|
attrs.alloc(j.first).mkAttrs(outputAttrs);
|
||||||
mkString(*state.allocAttr(vOutputs, state.sOutPath), j.second);
|
|
||||||
|
|
||||||
/* This is only necessary when installing store paths, e.g.,
|
/* This is only necessary when installing store paths, e.g.,
|
||||||
`nix-env -i /nix/store/abcd...-foo'. */
|
`nix-env -i /nix/store/abcd...-foo'. */
|
||||||
|
@ -91,15 +88,16 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the meta attributes.
|
// Copy the meta attributes.
|
||||||
Value & vMeta = *state.allocAttr(v, state.sMeta);
|
auto meta = state.buildBindings(metaNames.size());
|
||||||
state.mkAttrs(vMeta, metaNames.size());
|
|
||||||
for (auto & j : metaNames) {
|
for (auto & j : metaNames) {
|
||||||
Value * v = i.queryMeta(j);
|
Value * v = i.queryMeta(j);
|
||||||
if (!v) continue;
|
if (!v) continue;
|
||||||
vMeta.attrs->push_back(Attr(state.symbols.create(j), v));
|
meta.insert(state.symbols.create(j), v);
|
||||||
}
|
}
|
||||||
vMeta.attrs->sort();
|
|
||||||
v.attrs->sort();
|
attrs.alloc(state.sMeta).mkAttrs(meta);
|
||||||
|
|
||||||
|
(manifest.listElems()[n++] = state.allocValue())->mkAttrs(attrs);
|
||||||
|
|
||||||
if (drvPath != "") references.insert(state.store->parseStorePath(drvPath));
|
if (drvPath != "") references.insert(state.store->parseStorePath(drvPath));
|
||||||
}
|
}
|
||||||
|
@ -118,13 +116,16 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
||||||
|
|
||||||
/* Construct a Nix expression that calls the user environment
|
/* Construct a Nix expression that calls the user environment
|
||||||
builder with the manifest as argument. */
|
builder with the manifest as argument. */
|
||||||
Value args, topLevel;
|
auto attrs = state.buildBindings(3);
|
||||||
state.mkAttrs(args, 3);
|
attrs.alloc("manifest").mkString(
|
||||||
mkString(*state.allocAttr(args, state.symbols.create("manifest")),
|
state.store->printStorePath(manifestFile),
|
||||||
state.store->printStorePath(manifestFile), {state.store->printStorePath(manifestFile)});
|
{state.store->printStorePath(manifestFile)});
|
||||||
args.attrs->push_back(Attr(state.symbols.create("derivations"), &manifest));
|
attrs.insert(state.symbols.create("derivations"), &manifest);
|
||||||
args.attrs->sort();
|
Value args;
|
||||||
mkApp(topLevel, envBuilder, args);
|
args.mkAttrs(attrs);
|
||||||
|
|
||||||
|
Value topLevel;
|
||||||
|
topLevel.mkApp(&envBuilder, &args);
|
||||||
|
|
||||||
/* Evaluate it. */
|
/* Evaluate it. */
|
||||||
debug("evaluating user environment builder");
|
debug("evaluating user environment builder");
|
||||||
|
|
|
@ -78,20 +78,20 @@ struct CmdBundle : InstallableCommand
|
||||||
Strings{bundlerName == "" ? "defaultBundler" : bundlerName},
|
Strings{bundlerName == "" ? "defaultBundler" : bundlerName},
|
||||||
Strings({"bundlers."}), lockFlags);
|
Strings({"bundlers."}), lockFlags);
|
||||||
|
|
||||||
Value * arg = evalState->allocValue();
|
auto attrs = evalState->buildBindings(2);
|
||||||
evalState->mkAttrs(*arg, 2);
|
|
||||||
|
|
||||||
PathSet context;
|
PathSet context;
|
||||||
for (auto & i : app.context)
|
for (auto & i : app.context)
|
||||||
context.insert("=" + store->printStorePath(i.path));
|
context.insert("=" + store->printStorePath(i.path));
|
||||||
mkString(*evalState->allocAttr(*arg, evalState->symbols.create("program")), app.program, context);
|
attrs.alloc("program").mkString(app.program, context);
|
||||||
|
|
||||||
mkString(*evalState->allocAttr(*arg, evalState->symbols.create("system")), settings.thisSystem.get());
|
attrs.alloc("system").mkString(settings.thisSystem.get());
|
||||||
|
|
||||||
arg->attrs->sort();
|
|
||||||
|
|
||||||
auto vRes = evalState->allocValue();
|
auto vRes = evalState->allocValue();
|
||||||
evalState->callFunction(*bundler.toValue(*evalState).first, *arg, *vRes, noPos);
|
evalState->callFunction(
|
||||||
|
*bundler.toValue(*evalState).first,
|
||||||
|
evalState->allocValue()->mkAttrs(attrs),
|
||||||
|
*vRes, noPos);
|
||||||
|
|
||||||
if (!evalState->isDerivation(*vRes))
|
if (!evalState->isDerivation(*vRes))
|
||||||
throw Error("the bundler '%s' does not produce a derivation", bundler.what());
|
throw Error("the bundler '%s' does not produce a derivation", bundler.what());
|
||||||
|
|
|
@ -187,14 +187,11 @@ static void showHelp(std::vector<std::string> subcommand, MultiCommand & topleve
|
||||||
, "/"),
|
, "/"),
|
||||||
*vUtils);
|
*vUtils);
|
||||||
|
|
||||||
auto vArgs = state.allocValue();
|
auto attrs = state.buildBindings(16);
|
||||||
state.mkAttrs(*vArgs, 16);
|
attrs.alloc("command").mkString(toplevel.toJSON().dump());
|
||||||
auto vJson = state.allocAttr(*vArgs, state.symbols.create("command"));
|
|
||||||
mkString(*vJson, toplevel.toJSON().dump());
|
|
||||||
vArgs->attrs->sort();
|
|
||||||
|
|
||||||
auto vRes = state.allocValue();
|
auto vRes = state.allocValue();
|
||||||
state.callFunction(*vGenerateManpage, *vArgs, *vRes, noPos);
|
state.callFunction(*vGenerateManpage, state.allocValue()->mkAttrs(attrs), *vRes, noPos);
|
||||||
|
|
||||||
auto attr = vRes->attrs->get(state.symbols.create(mdName + ".md"));
|
auto attr = vRes->attrs->get(state.symbols.create(mdName + ".md"));
|
||||||
if (!attr)
|
if (!attr)
|
||||||
|
|
Loading…
Reference in a new issue