From dbce4809918bf5e835cd64aecf9db1d78e4cb691 Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Tue, 15 May 2012 23:00:23 -0400 Subject: [PATCH 01/18] prim_import: Don't build derivations in read-only mode --- src/libexpr/primops.cc | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 4a171a2aeb4..4b41ba87cf6 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -49,14 +49,23 @@ static void prim_import(EvalState & state, Value * * args, Value & v) if (!store->isValidPath(ctx)) throw EvalError(format("cannot import `%1%', since path `%2%' is not valid") % path % ctx); - if (isDerivation(ctx)) - try { - /* !!! If using a substitute, we only need to fetch - the selected output of this derivation. */ - store->buildDerivations(singleton(ctx)); - } catch (Error & e) { - throw ImportError(e.msg()); + if (isDerivation(ctx)) { + string outputName = decodeContext(*i).second; + Derivation drv = derivationFromPath(*store, ctx); + + if (!store->isValidPath(drv.outputs[outputName].path)) { + if (readOnlyMode) + throw ImportError(format("cannot import `%1%', since output `%2%' of derivation `%3%' is not valid") + % path % outputName % ctx); + try { + /* !!! If using a substitute, we only need to fetch + the selected output of this derivation. */ + store->buildDerivations(singleton(ctx)); + } catch (Error & e) { + throw ImportError(e.msg()); + } } + } } state.evalFile(path, v); From 7584a74f7eadb76867015c5f455f466afa07eea0 Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Wed, 16 May 2012 01:25:34 -0400 Subject: [PATCH 02/18] prim_import: Distinguish between failures due to read-only mode and other failures --- src/libexpr/nixexpr.hh | 1 + src/libexpr/primops.cc | 22 +++++++++++++++------- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index 6eb771a726b..f3811ed1484 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -17,6 +17,7 @@ MakeError(ThrownError, AssertionError) MakeError(Abort, EvalError) MakeError(TypeError, EvalError) MakeError(ImportError, EvalError) // error building an imported derivation +MakeError(ImportReadOnlyError, EvalError) // error when trying to import a derivation in read-only mode /* Position objects. */ diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 4b41ba87cf6..1589f365e3a 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -45,18 +45,26 @@ static void prim_import(EvalState & state, Value * * args, Value & v) foreach (PathSet::iterator, i, context) { Path ctx = decodeContext(*i).first; + string outputName = decodeContext(*i).second; assert(isStorePath(ctx)); - if (!store->isValidPath(ctx)) - throw EvalError(format("cannot import `%1%', since path `%2%' is not valid") - % path % ctx); + if (!store->isValidPath(ctx)) { + if (outputName.empty()) + throw EvalError(format("cannot import `%1%', since path `%2%' is not valid") + % path % ctx); + else + throw ImportReadOnlyError(format("cannot import `%1%', since path `%2%' cannot be written to the store in read-only mode") + % path % ctx); + } if (isDerivation(ctx)) { - string outputName = decodeContext(*i).second; Derivation drv = derivationFromPath(*store, ctx); - if (!store->isValidPath(drv.outputs[outputName].path)) { + if (outputName.empty() || + !store->isValidPath(drv.outputs[outputName].path)) { if (readOnlyMode) - throw ImportError(format("cannot import `%1%', since output `%2%' of derivation `%3%' is not valid") - % path % outputName % ctx); + foreach (DerivationOutputs::iterator, j, drv.outputs) + if (!store->isValidPath(j->second.path)) + throw ImportReadOnlyError(format("cannot import `%1%', since derivation `%2%' cannot be realised in read-only mode") + % path % ctx); try { /* !!! If using a substitute, we only need to fetch the selected output of this derivation. */ From da038d91b9b92ebcab6d9ee479f6ae916ea49aeb Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Wed, 16 May 2012 13:22:51 -0400 Subject: [PATCH 03/18] get-drvs: Add infrastructure for queries to work around instatiate failures due to read-only mode --- src/libexpr/get-drvs.cc | 61 ++++++++++++++++++++++++++++++++++++----- src/libexpr/get-drvs.hh | 6 ++-- src/libstore/globals.cc | 1 + src/libstore/globals.hh | 4 +++ src/nix-env/nix-env.cc | 1 + 5 files changed, 64 insertions(+), 9 deletions(-) diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index 6670d0636a1..43525d0946d 100644 --- a/src/libexpr/get-drvs.cc +++ b/src/libexpr/get-drvs.cc @@ -1,6 +1,7 @@ #include "get-drvs.hh" #include "util.hh" #include "eval-inline.hh" +#include "globals.hh" namespace nix { @@ -11,7 +12,13 @@ string DrvInfo::queryDrvPath(EvalState & state) const if (drvPath == "" && attrs) { Bindings::iterator i = attrs->find(state.sDrvPath); PathSet context; - (string &) drvPath = i != attrs->end() ? state.coerceToPath(*i->value, context) : ""; + try { + (string &) drvPath = i != attrs->end() ? state.coerceToPath(*i->value, context) : ""; + } catch (ImportReadOnlyError & e) { + if (!recoverFromReadOnlyErrors) throw; + (string &) drvPath = ""; + (bool &) threwImportReadOnlyError = true; + } } return drvPath; } @@ -22,7 +29,13 @@ string DrvInfo::queryOutPath(EvalState & state) const if (outPath == "" && attrs) { Bindings::iterator i = attrs->find(state.sOutPath); PathSet context; - (string &) outPath = i != attrs->end() ? state.coerceToPath(*i->value, context) : ""; + try { + (string &) outPath = i != attrs->end() ? state.coerceToPath(*i->value, context) : ""; + } catch (ImportReadOnlyError & e) { + if (!recoverFromReadOnlyErrors) throw; + (string &) outPath = ""; + (bool &) threwImportReadOnlyError = true; + } } return outPath; } @@ -37,11 +50,26 @@ MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const Bindings::iterator a = attrs->find(state.sMeta); if (a == attrs->end()) return meta; /* fine, empty meta information */ - state.forceAttrs(*a->value); + try { + state.forceAttrs(*a->value); + } catch (ImportReadOnlyError & e) { + if (!recoverFromReadOnlyErrors) throw; + (bool &) metaThrewImportReadOnlyError = true; + (bool &) threwImportReadOnlyError = true; + return meta; + } foreach (Bindings::iterator, i, *a->value->attrs) { MetaValue value; - state.forceValue(*i->value); + try { + state.forceAttrs(*a->value); + } catch (ImportReadOnlyError & e) { + if (!recoverFromReadOnlyErrors) throw; + (bool &) threwImportReadOnlyError = true; + value.type = MetaValue::tpNeedsRealise; + ((MetaInfo &) meta)[i->name] = value; + continue; + } if (i->value->type == tString) { value.type = MetaValue::tpString; value.stringValue = i->value->string.s; @@ -96,17 +124,29 @@ static bool getDerivation(EvalState & state, Value & v, done.insert(v.attrs); DrvInfo drv; - + Bindings::iterator i = v.attrs->find(state.sName); /* !!! We really would like to have a decent back trace here. */ if (i == v.attrs->end()) throw TypeError("derivation name missing"); - drv.name = state.forceStringNoCtx(*i->value); + try { + drv.name = state.forceStringNoCtx(*i->value); + } catch (ImportReadOnlyError & e) { + if (!recoverFromReadOnlyErrors) throw; + drv.name = ""; + drv.threwImportReadOnlyError = true; + } Bindings::iterator i2 = v.attrs->find(state.sSystem); if (i2 == v.attrs->end()) drv.system = "unknown"; else - drv.system = state.forceStringNoCtx(*i2->value); + try { + drv.system = state.forceStringNoCtx(*i2->value); + } catch (ImportReadOnlyError & e) { + if (!recoverFromReadOnlyErrors) throw; + drv.system = ""; + drv.threwImportReadOnlyError = true; + } drv.attrs = v.attrs; @@ -117,6 +157,9 @@ static bool getDerivation(EvalState & state, Value & v, } catch (AssertionError & e) { return false; + } catch (ImportReadOnlyError & e) { + if (!recoverFromReadOnlyErrors) throw; + return false; } } @@ -179,6 +222,10 @@ static void getDerivations(EvalState & state, Value & vIn, attribute. */ if (v2.type == tAttrs) { Bindings::iterator j = v2.attrs->find(state.symbols.create("recurseForDerivations")); + /* !!! in the weird case where v2.recurseForDerivations + requires evaluating an import of an unrealised derivation + to be evaluated, this will throw in read-only + mode even if read-only recovery was specified */ if (j != v2.attrs->end() && state.forceBool(*j->value)) getDerivations(state, v2, pathPrefix2, autoArgs, drvs, done); } diff --git a/src/libexpr/get-drvs.hh b/src/libexpr/get-drvs.hh index 2d260c57bee..1f07cff2454 100644 --- a/src/libexpr/get-drvs.hh +++ b/src/libexpr/get-drvs.hh @@ -14,7 +14,7 @@ namespace nix { struct MetaValue { - enum { tpNone, tpString, tpStrings, tpInt } type; + enum { tpNone, tpString, tpStrings, tpInt, tpNeedsRealise } type; string stringValue; Strings stringValues; int intValue; @@ -37,11 +37,13 @@ public: string name; string attrPath; /* path towards the derivation */ string system; + bool threwImportReadOnlyError; + bool metaThrewImportReadOnlyError; /* !!! make this private */ Bindings * attrs; - DrvInfo() : metaInfoRead(false), attrs(0) { }; + DrvInfo() : metaInfoRead(false), attrs(0), threwImportReadOnlyError(false), metaThrewImportReadOnlyError(false) { }; string queryDrvPath(EvalState & state) const; string queryOutPath(EvalState & state) const; diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc index 5c22f140664..b361ffd787c 100644 --- a/src/libstore/globals.cc +++ b/src/libstore/globals.cc @@ -26,6 +26,7 @@ Verbosity buildVerbosity = lvlError; unsigned int maxBuildJobs = 1; unsigned int buildCores = 1; bool readOnlyMode = false; +bool recoverFromReadOnlyErrors = false; string thisSystem = "unset"; time_t maxSilentTime = 0; time_t buildTimeout = 0; diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh index 12a9b9ca15c..745627dfc9e 100644 --- a/src/libstore/globals.hh +++ b/src/libstore/globals.hh @@ -64,6 +64,10 @@ extern unsigned int buildCores; database. */ extern bool readOnlyMode; +/* Whether failures due to read-only mode should cause a crash or allow + the tool to try to work around them. */ +extern bool recoverFromReadOnlyErrors; + /* The canonical system name, as returned by config.guess. */ extern string thisSystem; diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index a8d9076cfb8..3cc0db9793a 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -867,6 +867,7 @@ static void opQuery(Globals & globals, enum { sInstalled, sAvailable } source = sInstalled; readOnlyMode = true; /* makes evaluation a bit faster */ + recoverFromReadOnlyErrors = true; for (Strings::iterator i = args.begin(); i != args.end(); ) { string arg = *i++; From 1f17a2489b050831a1f6980c304d4a914922cdc1 Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Tue, 5 Jun 2012 00:00:30 -0400 Subject: [PATCH 04/18] Store read-only errors in a fine-grained structured way rather than using bogus string values --- src/libexpr/get-drvs.cc | 19 ++++++++----------- src/libexpr/get-drvs.hh | 9 ++++++--- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index 43525d0946d..aa82107fe36 100644 --- a/src/libexpr/get-drvs.cc +++ b/src/libexpr/get-drvs.cc @@ -16,8 +16,8 @@ string DrvInfo::queryDrvPath(EvalState & state) const (string &) drvPath = i != attrs->end() ? state.coerceToPath(*i->value, context) : ""; } catch (ImportReadOnlyError & e) { if (!recoverFromReadOnlyErrors) throw; + ((ErrorAttrs &) error).push_back("drvPath"); (string &) drvPath = ""; - (bool &) threwImportReadOnlyError = true; } } return drvPath; @@ -33,8 +33,8 @@ string DrvInfo::queryOutPath(EvalState & state) const (string &) outPath = i != attrs->end() ? state.coerceToPath(*i->value, context) : ""; } catch (ImportReadOnlyError & e) { if (!recoverFromReadOnlyErrors) throw; + ((ErrorAttrs &) error).push_back("drvPath"); (string &) outPath = ""; - (bool &) threwImportReadOnlyError = true; } } return outPath; @@ -54,8 +54,7 @@ MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const state.forceAttrs(*a->value); } catch (ImportReadOnlyError & e) { if (!recoverFromReadOnlyErrors) throw; - (bool &) metaThrewImportReadOnlyError = true; - (bool &) threwImportReadOnlyError = true; + ((ErrorAttrs &) error).push_back("meta"); return meta; } @@ -65,9 +64,7 @@ MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const state.forceAttrs(*a->value); } catch (ImportReadOnlyError & e) { if (!recoverFromReadOnlyErrors) throw; - (bool &) threwImportReadOnlyError = true; - value.type = MetaValue::tpNeedsRealise; - ((MetaInfo &) meta)[i->name] = value; + ((ErrorAttrs &) metaError).push_back("i->name"); continue; } if (i->value->type == tString) { @@ -97,6 +94,8 @@ MetaValue DrvInfo::queryMetaInfo(EvalState & state, const string & name) const void DrvInfo::setMetaInfo(const MetaInfo & meta) { + error.remove("meta"); + metaError.clear(); metaInfoRead = true; this->meta = meta; } @@ -132,8 +131,7 @@ static bool getDerivation(EvalState & state, Value & v, drv.name = state.forceStringNoCtx(*i->value); } catch (ImportReadOnlyError & e) { if (!recoverFromReadOnlyErrors) throw; - drv.name = ""; - drv.threwImportReadOnlyError = true; + drv.error.push_back("name"); } Bindings::iterator i2 = v.attrs->find(state.sSystem); @@ -144,8 +142,7 @@ static bool getDerivation(EvalState & state, Value & v, drv.system = state.forceStringNoCtx(*i2->value); } catch (ImportReadOnlyError & e) { if (!recoverFromReadOnlyErrors) throw; - drv.system = ""; - drv.threwImportReadOnlyError = true; + drv.error.push_back("system"); } drv.attrs = v.attrs; diff --git a/src/libexpr/get-drvs.hh b/src/libexpr/get-drvs.hh index 1f07cff2454..65e8a53248d 100644 --- a/src/libexpr/get-drvs.hh +++ b/src/libexpr/get-drvs.hh @@ -23,6 +23,7 @@ struct MetaValue typedef std::map MetaInfo; +typedef Strings ErrorAttrs; struct DrvInfo { @@ -37,13 +38,13 @@ public: string name; string attrPath; /* path towards the derivation */ string system; - bool threwImportReadOnlyError; - bool metaThrewImportReadOnlyError; + ErrorAttrs error; + ErrorAttrs metaError; /* !!! make this private */ Bindings * attrs; - DrvInfo() : metaInfoRead(false), attrs(0), threwImportReadOnlyError(false), metaThrewImportReadOnlyError(false) { }; + DrvInfo() : metaInfoRead(false), attrs(0) { }; string queryDrvPath(EvalState & state) const; string queryOutPath(EvalState & state) const; @@ -52,11 +53,13 @@ public: void setDrvPath(const string & s) { + error.remove("drvPath"); drvPath = s; } void setOutPath(const string & s) { + error.remove("outPath"); outPath = s; } From 3a5ecba990eeb2b3d9919d1332fad405f5bd6f62 Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Wed, 6 Jun 2012 19:27:17 -0400 Subject: [PATCH 05/18] ErrorAttrs is a set, not a list --- src/libexpr/get-drvs.cc | 14 +++++++------- src/libexpr/get-drvs.hh | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index aa82107fe36..e56ebf49c28 100644 --- a/src/libexpr/get-drvs.cc +++ b/src/libexpr/get-drvs.cc @@ -16,7 +16,7 @@ string DrvInfo::queryDrvPath(EvalState & state) const (string &) drvPath = i != attrs->end() ? state.coerceToPath(*i->value, context) : ""; } catch (ImportReadOnlyError & e) { if (!recoverFromReadOnlyErrors) throw; - ((ErrorAttrs &) error).push_back("drvPath"); + ((ErrorAttrs &) error).insert("drvPath"); (string &) drvPath = ""; } } @@ -33,7 +33,7 @@ string DrvInfo::queryOutPath(EvalState & state) const (string &) outPath = i != attrs->end() ? state.coerceToPath(*i->value, context) : ""; } catch (ImportReadOnlyError & e) { if (!recoverFromReadOnlyErrors) throw; - ((ErrorAttrs &) error).push_back("drvPath"); + ((ErrorAttrs &) error).insert("drvPath"); (string &) outPath = ""; } } @@ -54,7 +54,7 @@ MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const state.forceAttrs(*a->value); } catch (ImportReadOnlyError & e) { if (!recoverFromReadOnlyErrors) throw; - ((ErrorAttrs &) error).push_back("meta"); + ((ErrorAttrs &) error).insert("meta"); return meta; } @@ -64,7 +64,7 @@ MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const state.forceAttrs(*a->value); } catch (ImportReadOnlyError & e) { if (!recoverFromReadOnlyErrors) throw; - ((ErrorAttrs &) metaError).push_back("i->name"); + ((ErrorAttrs &) metaError).insert("i->name"); continue; } if (i->value->type == tString) { @@ -94,7 +94,7 @@ MetaValue DrvInfo::queryMetaInfo(EvalState & state, const string & name) const void DrvInfo::setMetaInfo(const MetaInfo & meta) { - error.remove("meta"); + error.erase("meta"); metaError.clear(); metaInfoRead = true; this->meta = meta; @@ -131,7 +131,7 @@ static bool getDerivation(EvalState & state, Value & v, drv.name = state.forceStringNoCtx(*i->value); } catch (ImportReadOnlyError & e) { if (!recoverFromReadOnlyErrors) throw; - drv.error.push_back("name"); + drv.error.insert("name"); } Bindings::iterator i2 = v.attrs->find(state.sSystem); @@ -142,7 +142,7 @@ static bool getDerivation(EvalState & state, Value & v, drv.system = state.forceStringNoCtx(*i2->value); } catch (ImportReadOnlyError & e) { if (!recoverFromReadOnlyErrors) throw; - drv.error.push_back("system"); + drv.error.insert("system"); } drv.attrs = v.attrs; diff --git a/src/libexpr/get-drvs.hh b/src/libexpr/get-drvs.hh index 65e8a53248d..0123a4dab8c 100644 --- a/src/libexpr/get-drvs.hh +++ b/src/libexpr/get-drvs.hh @@ -23,7 +23,7 @@ struct MetaValue typedef std::map MetaInfo; -typedef Strings ErrorAttrs; +typedef std::set ErrorAttrs; struct DrvInfo { @@ -53,13 +53,13 @@ public: void setDrvPath(const string & s) { - error.remove("drvPath"); + error.erase("drvPath"); drvPath = s; } void setOutPath(const string & s) { - error.remove("outPath"); + error.erase("outPath"); outPath = s; } From 20040e16aa9b7b6f275c6350661f191c2347ed46 Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Wed, 6 Jun 2012 19:43:01 -0400 Subject: [PATCH 06/18] loadDerivations: Don't filter out derivations whose 'system' attribute cannot be evaluated in read-only mode --- src/nix-env/nix-env.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index 3cc0db9793a..c75a6ab785e 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -169,7 +169,8 @@ static void loadDerivations(EvalState & state, Path nixExprPath, system. */ for (DrvInfos::iterator i = elems.begin(), j; i != elems.end(); i = j) { j = i; j++; - if (systemFilter != "*" && i->system != systemFilter) + if (systemFilter != "*" && i->error.find("system") == i->error.end() && + i->system != systemFilter) elems.erase(i); } } From 63a342df52be9561b8aff9c3aa436bf7e34ed1a3 Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Wed, 6 Jun 2012 20:00:57 -0400 Subject: [PATCH 07/18] When sorting DrvInfos by name, put derivations whose names can't be evaluated due to read-only error at the end --- src/nix-env/nix-env.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index c75a6ab785e..997c5d27787 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -760,6 +760,12 @@ static bool cmpChars(char a, char b) static bool cmpElemByName(const DrvInfo & a, const DrvInfo & b) { + if (a.error.find("name") != a.error.end()) + return false; + + if (b.error.find("name") != b.error.end()) + return true; + return lexicographical_compare( a.name.begin(), a.name.end(), b.name.begin(), b.name.end(), cmpChars); From 2b898580f1252f86a95ebd644a8a7288d16a8b9d Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Wed, 6 Jun 2012 20:21:47 -0400 Subject: [PATCH 08/18] isPrebuilt: if outPath can't be evaluated in read-only mode, the path can't be considered prebuilt --- src/nix-env/nix-env.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index 997c5d27787..c096a25a752 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -212,9 +212,12 @@ static int comparePriorities(EvalState & state, static bool isPrebuilt(EvalState & state, const DrvInfo & elem) { + string outpath = elem.queryOutPath(state); + if (elem.error.find("outPath") != elem.error.end()) + return false; return - store->isValidPath(elem.queryOutPath(state)) || - store->hasSubstitutes(elem.queryOutPath(state)); + store->isValidPath(outpath) || + store->hasSubstitutes(outpath); } From 25be0c5db88490039eb453f8e7c668a13609d5e6 Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Wed, 6 Jun 2012 21:44:52 -0400 Subject: [PATCH 09/18] nix-env -q --status: Use exclamation points when information is unavailable due to read-only mode I'm not sure if the exclamation point is valid in the xmlOutput case, this may change in a later commit --- src/nix-env/nix-env.cc | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index c096a25a752..6fdf5181179 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -960,18 +960,28 @@ static void opQuery(Globals & globals, XMLAttrs attrs; if (printStatus) { - bool hasSubs = store->hasSubstitutes(i->queryOutPath(globals.state)); - bool isInstalled = installed.find(i->queryOutPath(globals.state)) != installed.end(); - bool isValid = store->isValidPath(i->queryOutPath(globals.state)); - if (xmlOutput) { - attrs["installed"] = isInstalled ? "1" : "0"; - attrs["valid"] = isValid ? "1" : "0"; - attrs["substitutable"] = hasSubs ? "1" : "0"; - } else - columns.push_back( - (string) (isInstalled ? "I" : "-") - + (isValid ? "P" : "-") - + (hasSubs ? "S" : "-")); + string outpath = i->queryOutPath(globals.state); + if (i->error.find("outPath") == i->error.end()) { + bool hasSubs = store->hasSubstitutes(i->queryOutPath(globals.state)); + bool isInstalled = installed.find(i->queryOutPath(globals.state)) != installed.end(); + bool isValid = store->isValidPath(i->queryOutPath(globals.state)); + if (xmlOutput) { + attrs["installed"] = isInstalled ? "1" : "0"; + attrs["valid"] = isValid ? "1" : "0"; + attrs["substitutable"] = hasSubs ? "1" : "0"; + } else + columns.push_back( + (string) (isInstalled ? "I" : "-") + + (isValid ? "P" : "-") + + (hasSubs ? "S" : "-")); + } else { + if (xmlOutput) { + attrs["installed"] = "!"; + attrs["valid"] = "!"; + attrs["substitutable"] = "!"; + } else + columns.push_back("!!!"); + } } if (xmlOutput) From c90b952a36765a23ac3535544d5da72078a4ca95 Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Wed, 6 Jun 2012 21:59:00 -0400 Subject: [PATCH 10/18] nix-env -q: Print !name-unknown-in-readonly-mode! when the name cannot be evaluated in readonly mode --- src/nix-env/nix-env.cc | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index 6fdf5181179..7b4113c35cc 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -989,10 +989,16 @@ static void opQuery(Globals & globals, else if (printAttrPath) columns.push_back(i->attrPath); - if (xmlOutput) - attrs["name"] = i->name; - else if (printName) - columns.push_back(i->name); + if (i->error.find("name") == i->error.end()) + if (xmlOutput) + attrs["name"] = i->name; + else if (printName) + columns.push_back(i->name); + else + if (xmlOutput) + attrs["name"] = "!name-unknown-in-readonly-mode!"; + else if (printName) + columns.push_back("!name-unknown-in-readonly-mode!"); if (compareVersions) { /* Compare this element against the versions of the From 92e6e91149fd104d3982d6f7e50aad5045971ae9 Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Wed, 6 Jun 2012 22:12:42 -0400 Subject: [PATCH 11/18] compareVersionAgainstSet: Any comparison that includes a derivation whose name cannot be evaluated in readonly mode should keep the VersionDiff unchanged --- src/nix-env/nix-env.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index 7b4113c35cc..6ed997924fc 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -820,12 +820,18 @@ typedef enum { cvLess, cvEqual, cvGreater, cvUnavail } VersionDiff; static VersionDiff compareVersionAgainstSet( const DrvInfo & elem, const DrvInfos & elems, string & version) { - DrvName name(elem.name); - VersionDiff diff = cvUnavail; + + if (elem.error.find("name") != elem.error.end()) + return diff; + + DrvName name(elem.name); + version = "?"; for (DrvInfos::const_iterator i = elems.begin(); i != elems.end(); ++i) { + if (i->error.find("name") != i->error.end()) + continue; DrvName name2(i->name); if (name.name == name2.name) { int d = compareVersions(name.version, name2.version); From b7b3e1fd1efb033526365ce081581816e64436f6 Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Wed, 6 Jun 2012 22:15:19 -0400 Subject: [PATCH 12/18] compareVersionAgainstSet: Ensure 'version' is set before any potential return path --- src/nix-env/nix-env.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index 6ed997924fc..1f3f3df72f2 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -821,14 +821,13 @@ static VersionDiff compareVersionAgainstSet( const DrvInfo & elem, const DrvInfos & elems, string & version) { VersionDiff diff = cvUnavail; + version = "?"; if (elem.error.find("name") != elem.error.end()) return diff; DrvName name(elem.name); - version = "?"; - for (DrvInfos::const_iterator i = elems.begin(); i != elems.end(); ++i) { if (i->error.find("name") != i->error.end()) continue; From 4738d900ac1addef53dc87df0e3a0dc28b4d6f7c Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Wed, 6 Jun 2012 22:25:36 -0400 Subject: [PATCH 13/18] nix-env -q: Print !system-unknown-in-readonly-mode! when the system cannot be evaluated in readonly mode --- src/nix-env/nix-env.cc | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index 1f3f3df72f2..1f926681530 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -1034,11 +1034,14 @@ static void opQuery(Globals & globals, } } - if (xmlOutput) { - if (i->system != "") attrs["system"] = i->system; - } - else if (printSystem) - columns.push_back(i->system); + if (i->error.find("system") == i->error.end()) + if (xmlOutput) { + if (i->system != "") attrs["system"] = i->system; + } + else if (printSystem) + columns.push_back(i->system); + else if(!xmlOutput && printSystem) + columns.push_back("!system-unknown-in-readonly-mode!"); if (printDrvPath) { string drvPath = i->queryDrvPath(globals.state); From 8dbe0cb3fcbc7b4b4262a6ac9636e44c5f35e32a Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Wed, 6 Jun 2012 22:42:00 -0400 Subject: [PATCH 14/18] nix-env -q: Print !drvPath-unknown-in-readonly-mode! when the drvPath cannot be evaluated in readonly mode --- src/nix-env/nix-env.cc | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index 1f926681530..76f189d6b22 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -1040,15 +1040,18 @@ static void opQuery(Globals & globals, } else if (printSystem) columns.push_back(i->system); - else if(!xmlOutput && printSystem) + else if (!xmlOutput && printSystem) columns.push_back("!system-unknown-in-readonly-mode!"); if (printDrvPath) { string drvPath = i->queryDrvPath(globals.state); - if (xmlOutput) { - if (drvPath != "") attrs["drvPath"] = drvPath; - } else - columns.push_back(drvPath == "" ? "-" : drvPath); + if (i->error.find("drvPath") == i->error.end()) + if (xmlOutput) { + if (drvPath != "") attrs["drvPath"] = drvPath; + } else + columns.push_back(drvPath == "" ? "-" : drvPath); + else if (!xmlOutput) + columns.push_back("!drvPath-unknown-in-readonly-mode!"); } if (printOutPath) { From a9ebafde1b076ad75d932214ef03b51b2a0da7a5 Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Wed, 6 Jun 2012 22:51:35 -0400 Subject: [PATCH 15/18] nix-env -q: Print !outPath-unknown-in-readonly-mode! when the outPath cannot be evaluated in readonly mode --- src/nix-env/nix-env.cc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index 76f189d6b22..3a47bc28181 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -1056,10 +1056,13 @@ static void opQuery(Globals & globals, if (printOutPath) { string outPath = i->queryOutPath(globals.state); - if (xmlOutput) { - if (outPath != "") attrs["outPath"] = outPath; - } else - columns.push_back(outPath); + if (i->error.find("outPath") == i->error.end()) + if (xmlOutput) { + if (outPath != "") attrs["outPath"] = outPath; + } else + columns.push_back(outPath); + else if (!xmlOutput) + columns.push_back("!outPath-unknown-in-readonly-mode!"); } if (printDescription) { From 6a6c7299a6ca7458608c1cf1780da6dfe16a2569 Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Wed, 6 Jun 2012 23:22:49 -0400 Subject: [PATCH 16/18] nix-env -q: Handle the various ways meta attributes might throw readonly errors --- src/nix-env/nix-env.cc | 63 ++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index 3a47bc28181..eba8a748df6 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -1067,39 +1067,48 @@ static void opQuery(Globals & globals, if (printDescription) { MetaInfo meta = i->queryMetaInfo(globals.state); - MetaValue value = meta["description"]; - string descr = value.type == MetaValue::tpString ? value.stringValue : ""; - if (xmlOutput) { - if (descr != "") attrs["description"] = descr; - } else - columns.push_back(descr); + if (i->error.find("meta") == i->error.end()) { + MetaValue value = meta["description"]; + if (i->metaError.find("description") == i->metaError.end()) { + string descr = value.type == MetaValue::tpString ? value.stringValue : ""; + if (xmlOutput) { + if (descr != "") attrs["description"] = descr; + } else + columns.push_back(descr); + } else if (!xmlOutput) + columns.push_back("!description-unknown-in-readonly-mode!"); + } else if (!xmlOutput) + columns.push_back("!meta-info-unknown-in-readonly-mode!"); } if (xmlOutput) if (printMeta) { - XMLOpenElement item(xml, "item", attrs); MetaInfo meta = i->queryMetaInfo(globals.state); - for (MetaInfo::iterator j = meta.begin(); j != meta.end(); ++j) { - XMLAttrs attrs2; - attrs2["name"] = j->first; - if (j->second.type == MetaValue::tpString) { - attrs2["type"] = "string"; - attrs2["value"] = j->second.stringValue; - xml.writeEmptyElement("meta", attrs2); - } else if (j->second.type == MetaValue::tpInt) { - attrs2["type"] = "int"; - attrs2["value"] = (format("%1%") % j->second.intValue).str(); - xml.writeEmptyElement("meta", attrs2); - } else if (j->second.type == MetaValue::tpStrings) { - attrs2["type"] = "strings"; - XMLOpenElement m(xml, "meta", attrs2); - foreach (Strings::iterator, k, j->second.stringValues) { - XMLAttrs attrs3; - attrs3["value"] = *k; - xml.writeEmptyElement("string", attrs3); - } + if (i->error.find("meta") == i->error.end()) { + XMLOpenElement item(xml, "item", attrs); + for (MetaInfo::iterator j = meta.begin(); j != meta.end(); ++j) { + XMLAttrs attrs2; + attrs2["name"] = j->first; + if (j->second.type == MetaValue::tpString) { + attrs2["type"] = "string"; + attrs2["value"] = j->second.stringValue; + xml.writeEmptyElement("meta", attrs2); + } else if (j->second.type == MetaValue::tpInt) { + attrs2["type"] = "int"; + attrs2["value"] = (format("%1%") % j->second.intValue).str(); + xml.writeEmptyElement("meta", attrs2); + } else if (j->second.type == MetaValue::tpStrings) { + attrs2["type"] = "strings"; + XMLOpenElement m(xml, "meta", attrs2); + foreach (Strings::iterator, k, j->second.stringValues) { + XMLAttrs attrs3; + attrs3["value"] = *k; + xml.writeEmptyElement("string", attrs3); + } + } } - } + } else + xml.writeEmptyElement("item", attrs); } else xml.writeEmptyElement("item", attrs); From 5f1b71b450a30197bb3ea024d63da7c4c6b17008 Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Wed, 6 Jun 2012 23:31:22 -0400 Subject: [PATCH 17/18] Remove tpNeedsRealise, metaError takes its place --- src/libexpr/get-drvs.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libexpr/get-drvs.hh b/src/libexpr/get-drvs.hh index 0123a4dab8c..6fcfbc3805f 100644 --- a/src/libexpr/get-drvs.hh +++ b/src/libexpr/get-drvs.hh @@ -14,7 +14,7 @@ namespace nix { struct MetaValue { - enum { tpNone, tpString, tpStrings, tpInt, tpNeedsRealise } type; + enum { tpNone, tpString, tpStrings, tpInt } type; string stringValue; Strings stringValues; int intValue; From 63194a4e61ec524b2c546dbb124c426e659fb2ea Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Wed, 6 Jun 2012 23:34:23 -0400 Subject: [PATCH 18/18] Whoops --- src/libexpr/get-drvs.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index e56ebf49c28..330d91d8240 100644 --- a/src/libexpr/get-drvs.cc +++ b/src/libexpr/get-drvs.cc @@ -64,7 +64,7 @@ MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const state.forceAttrs(*a->value); } catch (ImportReadOnlyError & e) { if (!recoverFromReadOnlyErrors) throw; - ((ErrorAttrs &) metaError).insert("i->name"); + ((ErrorAttrs &) metaError).insert(i->name); continue; } if (i->value->type == tString) {