diff --git a/src/libexpr/attr-path.cc b/src/libexpr/attr-path.cc index 73716643..4f28a549 100644 --- a/src/libexpr/attr-path.cc +++ b/src/libexpr/attr-path.cc @@ -6,23 +6,44 @@ namespace nix { +static Strings parseAttrPath(const string & s) +{ + Strings res; + string cur; + string::const_iterator i = s.begin(); + while (i != s.end()) { + if (*i == '.') { + res.push_back(cur); + cur.clear(); + } else if (*i == '"') { + ++i; + while (1) { + if (i == s.end()) + throw Error(format("missing closing quote in selection path `%1%'") % s); + if (*i == '"') break; + cur.push_back(*i++); + } + } else + cur.push_back(*i); + ++i; + } + if (!cur.empty()) res.push_back(cur); + return res; +} + + Value * findAlongAttrPath(EvalState & state, const string & attrPath, Bindings & autoArgs, Value & vIn) { - Strings tokens = tokenizeString(attrPath, "."); + Strings tokens = parseAttrPath(attrPath); Error attrError = Error(format("attribute selection path `%1%' does not match expression") % attrPath); - string curPath; - Value * v = &vIn; foreach (Strings::iterator, i, tokens) { - if (!curPath.empty()) curPath += "."; - curPath += *i; - /* Is *i an index (integer) or a normal attribute name? */ enum { apAttr, apIndex } apType = apAttr; string attr = *i; @@ -43,11 +64,14 @@ Value * findAlongAttrPath(EvalState & state, const string & attrPath, if (v->type != tAttrs) throw TypeError( format("the expression selected by the selection path `%1%' should be a set but is %2%") - % curPath % showType(*v)); + % attrPath % showType(*v)); + + if (attr.empty()) + throw Error(format("empty attribute name in selection path `%1%'") % attrPath); Bindings::iterator a = v->attrs->find(state.symbols.create(attr)); 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 % attrPath); v = &*a->value; } @@ -56,10 +80,10 @@ Value * findAlongAttrPath(EvalState & state, const string & attrPath, if (v->type != tList) throw TypeError( format("the expression selected by the selection path `%1%' should be a list but is %2%") - % curPath % showType(*v)); + % attrPath % showType(*v)); 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 % attrPath); v = v->list.elems[attrIndex]; } diff --git a/tests/export-graph.nix b/tests/export-graph.nix index 3a0b0368..fdac9583 100644 --- a/tests/export-graph.nix +++ b/tests/export-graph.nix @@ -14,13 +14,13 @@ rec { done < refs ''; - runtimeGraph = mkDerivation { + foo."bar.runtimeGraph" = mkDerivation { name = "dependencies"; builder = builtins.toFile "build-graph-builder" "${printRefs}"; exportReferencesGraph = ["refs" (import ./dependencies.nix)]; }; - buildGraph = mkDerivation { + foo."bar.buildGraph" = mkDerivation { name = "dependencies"; builder = builtins.toFile "build-graph-builder" "${printRefs}"; exportReferencesGraph = ["refs" (import ./dependencies.nix).drvPath]; diff --git a/tests/export-graph.sh b/tests/export-graph.sh index 7f6f83d8..a6fd6905 100644 --- a/tests/export-graph.sh +++ b/tests/export-graph.sh @@ -9,7 +9,7 @@ checkRef() { # Test the export of the runtime dependency graph. -outPath=$(nix-build ./export-graph.nix -A runtimeGraph -o $TEST_ROOT/result) +outPath=$(nix-build ./export-graph.nix -A 'foo."bar.runtimeGraph"' -o $TEST_ROOT/result) test $(nix-store -q --references $TEST_ROOT/result | wc -l) = 2 || fail "bad nr of references" @@ -20,7 +20,7 @@ for i in $(cat $outPath); do checkRef $i; done nix-store --gc # should force rebuild of input-1 -outPath=$(nix-build ./export-graph.nix -A buildGraph -o $TEST_ROOT/result) +outPath=$(nix-build ./export-graph.nix -A 'foo."bar.buildGraph"' -o $TEST_ROOT/result) checkRef input-1 checkRef input-1.drv