diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index 8af011d549..e9f1063d95 100644 --- a/src/libexpr/get-drvs.cc +++ b/src/libexpr/get-drvs.cc @@ -7,7 +7,7 @@ namespace nix { string DrvInfo::queryDrvPath(EvalState & state) const { - if (drvPath == "") { + if (drvPath == "" && attrs) { Bindings::iterator i = attrs->find(state.sDrvPath); PathSet context; (string &) drvPath = i != attrs->end() ? state.coerceToPath(i->second, context) : ""; @@ -18,7 +18,7 @@ string DrvInfo::queryDrvPath(EvalState & state) const string DrvInfo::queryOutPath(EvalState & state) const { - if (outPath == "") { + if (outPath == "" && attrs) { Bindings::iterator i = attrs->find(state.sOutPath); PathSet context; (string &) outPath = i != attrs->end() ? state.coerceToPath(i->second, context) : ""; @@ -29,7 +29,9 @@ string DrvInfo::queryOutPath(EvalState & state) const MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const { - MetaInfo meta; + if (metaInfoRead) return meta; + + (bool &) metaInfoRead = true; Bindings::iterator a = attrs->find(state.sMeta); if (a == attrs->end()) return meta; /* fine, empty meta information */ @@ -50,7 +52,7 @@ MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const for (unsigned int j = 0; j < i->second.list.length; ++j) value.stringValues.push_back(state.forceStringNoCtx(*i->second.list.elems[j])); } else continue; - meta[i->first] = value; + ((MetaInfo &) meta)[i->first] = value; } return meta; @@ -66,9 +68,11 @@ MetaValue DrvInfo::queryMetaInfo(EvalState & state, const string & name) const void DrvInfo::setMetaInfo(const MetaInfo & meta) { - throw Error("not implemented"); + metaInfoRead = true; + this->meta = meta; + #if 0 - ATermMap metaAttrs; + Value * metaAttrs = state.allocValues(1); foreach (MetaInfo::const_iterator, i, meta) { Expr e; switch (i->second.type) { diff --git a/src/libexpr/get-drvs.hh b/src/libexpr/get-drvs.hh index f7d1987ea3..6f3c381f8e 100644 --- a/src/libexpr/get-drvs.hh +++ b/src/libexpr/get-drvs.hh @@ -29,6 +29,9 @@ struct DrvInfo private: string drvPath; string outPath; + + bool metaInfoRead; + MetaInfo meta; public: string name; @@ -38,6 +41,8 @@ public: /* !!! make this private */ Bindings * attrs; + DrvInfo() : metaInfoRead(false) { }; + string queryDrvPath(EvalState & state) const; string queryOutPath(EvalState & state) const; MetaInfo queryMetaInfo(EvalState & state) const; diff --git a/src/nix-env/user-env.cc b/src/nix-env/user-env.cc index 0e1fce650c..8bb760094d 100644 --- a/src/nix-env/user-env.cc +++ b/src/nix-env/user-env.cc @@ -5,22 +5,165 @@ namespace nix { +static void readLegacyManifest(const Path & path, DrvInfos & elems); + + DrvInfos queryInstalled(EvalState & state, const Path & userEnv) { + DrvInfos elems; + Path path = userEnv + "/manifest"; if (!pathExists(path)) return DrvInfos(); /* not an error, assume nothing installed */ - throw Error("not implemented"); -#if 0 - Expr e = ATreadFromNamedFile(path.c_str()); - if (!e) throw Error(format("cannot read Nix expression from `%1%'") % path); + readLegacyManifest(path, elems); - DrvInfos elems; - // !!! getDerivations(state, e, "", ATermMap(1), elems); return elems; -#endif +} + + +/* Code for parsing manifests in the old textual ATerm format. */ + +static void expect(std::istream & str, const string & s) +{ + char s2[s.size()]; + str.read(s2, s.size()); + if (string(s2, s.size()) != s) + throw Error(format("expected string `%1%'") % s); +} + + +static string parseString(std::istream & str) +{ + string res; + expect(str, "\""); + int c; + while ((c = str.get()) != '"') + if (c == '\\') { + c = str.get(); + if (c == 'n') res += '\n'; + else if (c == 'r') res += '\r'; + else if (c == 't') res += '\t'; + else res += c; + } + else res += c; + return res; +} + + +static string parseStr(std::istream & str) +{ + expect(str, "Str("); + string s = parseString(str); + expect(str, ",[])"); + return s; +} + + +static string parseWord(std::istream & str) +{ + string res; + while (isalpha(str.peek())) + res += str.get(); + return res; +} + + +static bool endOfList(std::istream & str) +{ + if (str.peek() == ',') { + str.get(); + return false; + } + if (str.peek() == ']') { + str.get(); + return true; + } + return false; +} + + +static MetaInfo parseMeta(std::istream & str) +{ + MetaInfo meta; + + expect(str, "Attrs(["); + while (!endOfList(str)) { + expect(str, "Bind("); + + MetaValue value; + + string name = parseString(str); + expect(str, ","); + + string type = parseWord(str); + + if (type == "Str") { + expect(str, "("); + value.type = MetaValue::tpString; + value.stringValue = parseString(str); + expect(str, ",[])"); + } + + else if (type == "List") { + expect(str, "(["); + value.type = MetaValue::tpStrings; + while (!endOfList(str)) + value.stringValues.push_back(parseStr(str)); + expect(str, ")"); + } + + else throw Error(format("unexpected token `%1%'") % type); + + expect(str, ",NoPos)"); + meta[name] = value; + } + + expect(str, ")"); + + return meta; +} + + +static void readLegacyManifest(const Path & path, DrvInfos & elems) +{ + string manifest = readFile(path); + std::istringstream str(manifest); + expect(str, "List(["); + + unsigned int n = 0; + + while (!endOfList(str)) { + DrvInfo elem; + expect(str, "Attrs(["); + + while (!endOfList(str)) { + expect(str, "Bind("); + string name = parseString(str); + expect(str, ","); + + if (name == "meta") elem.setMetaInfo(parseMeta(str)); + else { + string value = parseStr(str); + if (name == "name") elem.name = value; + else if (name == "outPath") elem.setOutPath(value); + else if (name == "drvPath") elem.setDrvPath(value); + else if (name == "system") elem.system = value; + } + + expect(str, ",NoPos)"); + } + + expect(str, ")"); + + if (elem.name != "") { + elem.attrPath = int2String(n++); + elems.push_back(elem); + } + } + + expect(str, ")"); }