Work on Values instead of Exprs
This prevents some duplicate evaluation in nix-env and nix-instantiate. Also, when traversing ~/.nix-defexpr, only read regular files with the extension .nix. Previously it was reading files like .../channels/binary-caches/<name>. The only reason this didn't cause problems is pure luck (namely, <name> shadows an actual Nix expression, the binary-caches files happen to be syntactically valid Nix expressions, and we iterate over the directory contents in just the right order).
This commit is contained in:
parent
06bb2d95b4
commit
ef4f5ba85e
4 changed files with 62 additions and 50 deletions
|
@ -6,9 +6,8 @@
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
// !!! Shouldn't we return a pointer to a Value?
|
Value * findAlongAttrPath(EvalState & state, const string & attrPath,
|
||||||
void findAlongAttrPath(EvalState & state, const string & attrPath,
|
Bindings & autoArgs, Value & vIn)
|
||||||
Bindings & autoArgs, Expr * e, Value & v)
|
|
||||||
{
|
{
|
||||||
Strings tokens = tokenizeString<Strings>(attrPath, ".");
|
Strings tokens = tokenizeString<Strings>(attrPath, ".");
|
||||||
|
|
||||||
|
@ -17,7 +16,7 @@ void findAlongAttrPath(EvalState & state, const string & attrPath,
|
||||||
|
|
||||||
string curPath;
|
string curPath;
|
||||||
|
|
||||||
state.mkThunk_(v, e);
|
Value * v = &vIn;
|
||||||
|
|
||||||
foreach (Strings::iterator, i, tokens) {
|
foreach (Strings::iterator, i, tokens) {
|
||||||
|
|
||||||
|
@ -31,10 +30,10 @@ void findAlongAttrPath(EvalState & state, const string & attrPath,
|
||||||
if (string2Int(attr, attrIndex)) apType = apIndex;
|
if (string2Int(attr, attrIndex)) apType = apIndex;
|
||||||
|
|
||||||
/* Evaluate the expression. */
|
/* Evaluate the expression. */
|
||||||
Value vTmp;
|
Value * vNew = state.allocValue();
|
||||||
state.autoCallFunction(autoArgs, v, vTmp);
|
state.autoCallFunction(autoArgs, *v, *vNew);
|
||||||
v = vTmp;
|
v = vNew;
|
||||||
state.forceValue(v);
|
state.forceValue(*v);
|
||||||
|
|
||||||
/* It should evaluate to either an attribute set or an
|
/* It should evaluate to either an attribute set or an
|
||||||
expression, according to what is specified in the
|
expression, according to what is specified in the
|
||||||
|
@ -42,31 +41,33 @@ void findAlongAttrPath(EvalState & state, const string & attrPath,
|
||||||
|
|
||||||
if (apType == apAttr) {
|
if (apType == apAttr) {
|
||||||
|
|
||||||
if (v.type != tAttrs)
|
if (v->type != tAttrs)
|
||||||
throw TypeError(
|
throw TypeError(
|
||||||
format("the expression selected by the selection path `%1%' should be an attribute set but is %2%")
|
format("the expression selected by the selection path `%1%' should be an attribute set but is %2%")
|
||||||
% curPath % showType(v));
|
% curPath % showType(*v));
|
||||||
|
|
||||||
Bindings::iterator a = v.attrs->find(state.symbols.create(attr));
|
Bindings::iterator a = v->attrs->find(state.symbols.create(attr));
|
||||||
if (a == v.attrs->end())
|
if (a == v->attrs->end())
|
||||||
throw Error(format("attribute `%1%' in selection path `%2%' not found") % attr % curPath);
|
throw Error(format("attribute `%1%' in selection path `%2%' not found") % attr % curPath);
|
||||||
v = *a->value;
|
v = &*a->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (apType == apIndex) {
|
else if (apType == apIndex) {
|
||||||
|
|
||||||
if (v.type != tList)
|
if (v->type != tList)
|
||||||
throw TypeError(
|
throw TypeError(
|
||||||
format("the expression selected by the selection path `%1%' should be a list but is %2%")
|
format("the expression selected by the selection path `%1%' should be a list but is %2%")
|
||||||
% curPath % showType(v));
|
% curPath % showType(*v));
|
||||||
|
|
||||||
if (attrIndex >= v.list.length)
|
if (attrIndex >= v->list.length)
|
||||||
throw Error(format("list index %1% in selection path `%2%' is out of range") % attrIndex % curPath);
|
throw Error(format("list index %1% in selection path `%2%' is out of range") % attrIndex % curPath);
|
||||||
|
|
||||||
v = *v.list.elems[attrIndex];
|
v = v->list.elems[attrIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
void findAlongAttrPath(EvalState & state, const string & attrPath,
|
Value * findAlongAttrPath(EvalState & state, const string & attrPath,
|
||||||
Bindings & autoArgs, Expr * e, Value & v);
|
Bindings & autoArgs, Value & vIn);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,18 +94,14 @@ static bool parseInstallSourceOptions(Globals & globals,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool isNixExpr(const Path & path)
|
static bool isNixExpr(const Path & path, struct stat & st)
|
||||||
{
|
{
|
||||||
struct stat st;
|
return S_ISREG(st.st_mode) || (S_ISDIR(st.st_mode) && pathExists(path + "/default.nix"));
|
||||||
if (stat(path.c_str(), &st) == -1)
|
|
||||||
throw SysError(format("getting information about `%1%'") % path);
|
|
||||||
|
|
||||||
return !S_ISDIR(st.st_mode) || pathExists(path + "/default.nix");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void getAllExprs(EvalState & state,
|
static void getAllExprs(EvalState & state,
|
||||||
const Path & path, ExprAttrs & attrs)
|
const Path & path, Value & v)
|
||||||
{
|
{
|
||||||
Strings names = readDirectory(path);
|
Strings names = readDirectory(path);
|
||||||
StringSet namesSorted(names.begin(), names.end());
|
StringSet namesSorted(names.begin(), names.end());
|
||||||
|
@ -122,7 +118,7 @@ static void getAllExprs(EvalState & state,
|
||||||
if (stat(path2.c_str(), &st) == -1)
|
if (stat(path2.c_str(), &st) == -1)
|
||||||
continue; // ignore dangling symlinks in ~/.nix-defexpr
|
continue; // ignore dangling symlinks in ~/.nix-defexpr
|
||||||
|
|
||||||
if (isNixExpr(path2)) {
|
if (isNixExpr(path2, st) && (!S_ISREG(st.st_mode) || hasSuffix(path2, ".nix"))) {
|
||||||
/* Strip off the `.nix' filename suffix (if applicable),
|
/* Strip off the `.nix' filename suffix (if applicable),
|
||||||
otherwise the attribute cannot be selected with the
|
otherwise the attribute cannot be selected with the
|
||||||
`-A' option. Useful if you want to stick a Nix
|
`-A' option. Useful if you want to stick a Nix
|
||||||
|
@ -130,20 +126,28 @@ 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);
|
||||||
attrs.attrs[state.symbols.create(attrName)] =
|
// FIXME: make loading lazy.
|
||||||
ExprAttrs::AttrDef(state.parseExprFromFile(resolveExprPath(absPath(path2))), noPos);
|
Value & v2(*state.allocAttr(v, state.symbols.create(attrName)));
|
||||||
|
state.evalFile(path2, v2);
|
||||||
}
|
}
|
||||||
else
|
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);
|
getAllExprs(state, path2, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static Expr * loadSourceExpr(EvalState & state, const Path & path)
|
static void loadSourceExpr(EvalState & state, const Path & path, Value & v)
|
||||||
{
|
{
|
||||||
if (isNixExpr(path)) return state.parseExprFromFile(resolveExprPath(absPath(path)));
|
struct stat st;
|
||||||
|
if (stat(path.c_str(), &st) == -1)
|
||||||
|
throw SysError(format("getting information about `%1%'") % path);
|
||||||
|
|
||||||
|
if (isNixExpr(path, st)) {
|
||||||
|
state.evalFile(path, v);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* The path is a directory. Put the Nix expressions in the
|
/* The path is a directory. Put the Nix expressions in the
|
||||||
directory in an attribute set, with the file name of each
|
directory in an attribute set, with the file name of each
|
||||||
|
@ -151,11 +155,12 @@ static Expr * loadSourceExpr(EvalState & state, const Path & path)
|
||||||
(but keep the attribute set flat, not nested, to make it easier
|
(but keep the attribute set flat, not nested, to make it easier
|
||||||
for a user to have a ~/.nix-defexpr directory that includes
|
for a user to have a ~/.nix-defexpr directory that includes
|
||||||
some system-wide directory). */
|
some system-wide directory). */
|
||||||
ExprAttrs * attrs = new ExprAttrs;
|
if (S_ISDIR(st.st_mode)) {
|
||||||
attrs->attrs[state.symbols.create("_combineChannels")] =
|
state.mkAttrs(v, 16);
|
||||||
ExprAttrs::AttrDef(new ExprList(), noPos);
|
state.mkList(*state.allocAttr(v, state.symbols.create("_combineChannels")), 0);
|
||||||
getAllExprs(state, path, *attrs);
|
getAllExprs(state, path, v);
|
||||||
return attrs;
|
v.attrs->sort();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -163,8 +168,10 @@ static void loadDerivations(EvalState & state, Path nixExprPath,
|
||||||
string systemFilter, Bindings & autoArgs,
|
string systemFilter, Bindings & autoArgs,
|
||||||
const string & pathPrefix, DrvInfos & elems)
|
const string & pathPrefix, DrvInfos & elems)
|
||||||
{
|
{
|
||||||
Value v;
|
Value vRoot;
|
||||||
findAlongAttrPath(state, pathPrefix, autoArgs, loadSourceExpr(state, nixExprPath), v);
|
loadSourceExpr(state, nixExprPath, vRoot);
|
||||||
|
|
||||||
|
Value & v(*findAlongAttrPath(state, pathPrefix, autoArgs, vRoot));
|
||||||
|
|
||||||
getDerivations(state, v, pathPrefix, autoArgs, elems, true);
|
getDerivations(state, v, pathPrefix, autoArgs, elems, true);
|
||||||
|
|
||||||
|
@ -356,13 +363,15 @@ static void queryInstSources(EvalState & state,
|
||||||
(import ./foo.nix)' = `(import ./foo.nix).bar'. */
|
(import ./foo.nix)' = `(import ./foo.nix).bar'. */
|
||||||
case srcNixExprs: {
|
case srcNixExprs: {
|
||||||
|
|
||||||
Expr * e1 = loadSourceExpr(state, instSource.nixExprPath);
|
Value vArg;
|
||||||
|
loadSourceExpr(state, instSource.nixExprPath, vArg);
|
||||||
|
|
||||||
foreach (Strings::const_iterator, i, args) {
|
foreach (Strings::const_iterator, i, args) {
|
||||||
Expr * e2 = state.parseExprFromString(*i, absPath("."));
|
Expr * eFun = state.parseExprFromString(*i, absPath("."));
|
||||||
Expr * call = new ExprApp(e2, e1);
|
Value vFun, vTmp;
|
||||||
Value v; state.eval(call, v);
|
state.eval(eFun, vFun);
|
||||||
getDerivations(state, v, "", instSource.autoArgs, elems, true);
|
mkApp(vTmp, vFun, vArg);
|
||||||
|
getDerivations(state, vTmp, "", instSource.autoArgs, elems, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -413,10 +422,10 @@ static void queryInstSources(EvalState & state,
|
||||||
}
|
}
|
||||||
|
|
||||||
case srcAttrPath: {
|
case srcAttrPath: {
|
||||||
|
Value vRoot;
|
||||||
|
loadSourceExpr(state, instSource.nixExprPath, vRoot);
|
||||||
foreach (Strings::const_iterator, i, args) {
|
foreach (Strings::const_iterator, i, args) {
|
||||||
Value v;
|
Value & v(*findAlongAttrPath(state, *i, instSource.autoArgs, vRoot));
|
||||||
findAlongAttrPath(state, *i, instSource.autoArgs,
|
|
||||||
loadSourceExpr(state, instSource.nixExprPath), v);
|
|
||||||
getDerivations(state, v, "", instSource.autoArgs, elems, true);
|
getDerivations(state, v, "", instSource.autoArgs, elems, true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -44,9 +44,11 @@ void processExpr(EvalState & state, const Strings & attrPaths,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Value vRoot;
|
||||||
|
state.eval(e, vRoot);
|
||||||
|
|
||||||
foreach (Strings::const_iterator, i, attrPaths) {
|
foreach (Strings::const_iterator, i, attrPaths) {
|
||||||
Value v;
|
Value & v(*findAlongAttrPath(state, *i, autoArgs, vRoot));
|
||||||
findAlongAttrPath(state, *i, autoArgs, e, v);
|
|
||||||
state.forceValue(v);
|
state.forceValue(v);
|
||||||
|
|
||||||
PathSet context;
|
PathSet context;
|
||||||
|
|
Loading…
Reference in a new issue