Add "nix search" command
This commit is contained in:
		
							parent
							
								
									3162ad5ff4
								
							
						
					
					
						commit
						90825dea51
					
				
					 9 changed files with 263 additions and 102 deletions
				
			
		|  | @ -9,7 +9,34 @@ | |||
| namespace nix { | ||||
| 
 | ||||
| 
 | ||||
| string DrvInfo::queryDrvPath() | ||||
| DrvInfo::DrvInfo(EvalState & state, const string & attrPath, Bindings * attrs) | ||||
|     : state(&state), attrs(attrs), attrPath(attrPath) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| string DrvInfo::queryName() const | ||||
| { | ||||
|     if (name == "" && attrs) { | ||||
|         auto i = attrs->find(state->sName); | ||||
|         if (i == attrs->end()) throw TypeError("derivation name missing"); | ||||
|         name = state->forceStringNoCtx(*i->value); | ||||
|     } | ||||
|     return name; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| string DrvInfo::querySystem() const | ||||
| { | ||||
|     if (system == "" && attrs) { | ||||
|         auto i = attrs->find(state->sSystem); | ||||
|         system = i == attrs->end() ? "unknown" : state->forceStringNoCtx(*i->value, *i->pos); | ||||
|     } | ||||
|     return system; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| string DrvInfo::queryDrvPath() const | ||||
| { | ||||
|     if (drvPath == "" && attrs) { | ||||
|         Bindings::iterator i = attrs->find(state->sDrvPath); | ||||
|  | @ -20,7 +47,7 @@ string DrvInfo::queryDrvPath() | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| string DrvInfo::queryOutPath() | ||||
| string DrvInfo::queryOutPath() const | ||||
| { | ||||
|     if (outPath == "" && attrs) { | ||||
|         Bindings::iterator i = attrs->find(state->sOutPath); | ||||
|  | @ -76,7 +103,7 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool onlyOutputsToInstall) | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| string DrvInfo::queryOutputName() | ||||
| string DrvInfo::queryOutputName() const | ||||
| { | ||||
|     if (outputName == "" && attrs) { | ||||
|         Bindings::iterator i = attrs->find(state->sOutputName); | ||||
|  | @ -225,17 +252,12 @@ static bool getDerivation(EvalState & state, Value & v, | |||
|         if (done.find(v.attrs) != done.end()) return false; | ||||
|         done.insert(v.attrs); | ||||
| 
 | ||||
|         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"); | ||||
|         DrvInfo drv(state, attrPath, v.attrs); | ||||
| 
 | ||||
|         Bindings::iterator i2 = v.attrs->find(state.sSystem); | ||||
| 
 | ||||
|         DrvInfo drv(state, state.forceStringNoCtx(*i->value), attrPath, | ||||
|             i2 == v.attrs->end() ? "unknown" : state.forceStringNoCtx(*i2->value, *i2->pos), | ||||
|             v.attrs); | ||||
|         drv.queryName(); | ||||
| 
 | ||||
|         drvs.push_back(drv); | ||||
| 
 | ||||
|         return false; | ||||
| 
 | ||||
|     } catch (AssertionError & e) { | ||||
|  |  | |||
|  | @ -17,31 +17,32 @@ public: | |||
| private: | ||||
|     EvalState * state; | ||||
| 
 | ||||
|     string drvPath; | ||||
|     string outPath; | ||||
|     string outputName; | ||||
|     mutable string name; | ||||
|     mutable string system; | ||||
|     mutable string drvPath; | ||||
|     mutable string outPath; | ||||
|     mutable string outputName; | ||||
|     Outputs outputs; | ||||
| 
 | ||||
|     bool failed; // set if we get an AssertionError
 | ||||
|     bool failed = false; // set if we get an AssertionError
 | ||||
| 
 | ||||
|     Bindings * attrs, * meta; | ||||
|     Bindings * attrs = nullptr, * meta = nullptr; | ||||
| 
 | ||||
|     Bindings * getMeta(); | ||||
| 
 | ||||
|     bool checkMeta(Value & v); | ||||
| 
 | ||||
| public: | ||||
|     string name; | ||||
|     string attrPath; /* path towards the derivation */ | ||||
|     string system; | ||||
| 
 | ||||
|     DrvInfo(EvalState & state) : state(&state), failed(false), attrs(0), meta(0) { }; | ||||
|     DrvInfo(EvalState & state, const string & name, const string & attrPath, const string & system, Bindings * attrs) | ||||
|         : state(&state), failed(false), attrs(attrs), meta(0), name(name), attrPath(attrPath), system(system) { }; | ||||
|     DrvInfo(EvalState & state) : state(&state) { }; | ||||
|     DrvInfo(EvalState & state, const string & attrPath, Bindings * attrs); | ||||
| 
 | ||||
|     string queryDrvPath(); | ||||
|     string queryOutPath(); | ||||
|     string queryOutputName(); | ||||
|     string queryName() const; | ||||
|     string querySystem() const; | ||||
|     string queryDrvPath() const; | ||||
|     string queryOutPath() const; | ||||
|     string queryOutputName() const; | ||||
|     /** Return the list of outputs. The "outputs to install" are determined by `mesa.outputsToInstall`. */ | ||||
|     Outputs queryOutputs(bool onlyOutputsToInstall = false); | ||||
| 
 | ||||
|  | @ -58,15 +59,9 @@ public: | |||
|     MetaValue queryMetaInfo(EvalState & state, const string & name) const; | ||||
|     */ | ||||
| 
 | ||||
|     void setDrvPath(const string & s) | ||||
|     { | ||||
|         drvPath = s; | ||||
|     } | ||||
| 
 | ||||
|     void setOutPath(const string & s) | ||||
|     { | ||||
|         outPath = s; | ||||
|     } | ||||
|     void setName(const string & s) { name = s; } | ||||
|     void setDrvPath(const string & s) { drvPath = s; } | ||||
|     void setOutPath(const string & s) { outPath = s; } | ||||
| 
 | ||||
|     void setFailed() { failed = true; }; | ||||
|     bool hasFailed() { return failed; }; | ||||
|  |  | |||
|  | @ -66,6 +66,7 @@ void Args::printHelp(const string & programName, std::ostream & out) | |||
|         std::cout << renderLabels({exp.label}); | ||||
|         // FIXME: handle arity > 1
 | ||||
|         if (exp.arity == 0) std::cout << "..."; | ||||
|         if (exp.optional) std::cout << "?"; | ||||
|     } | ||||
|     std::cout << "\n"; | ||||
| 
 | ||||
|  |  | |||
|  | @ -164,9 +164,9 @@ public: | |||
|     } | ||||
| 
 | ||||
|     /* Expect a string argument. */ | ||||
|     void expectArg(const std::string & label, string * dest) | ||||
|     void expectArg(const std::string & label, string * dest, bool optional = false) | ||||
|     { | ||||
|         expectedArgs.push_back(ExpectedArg{label, 1, false, [=](Strings ss) { | ||||
|         expectedArgs.push_back(ExpectedArg{label, 1, optional, [=](Strings ss) { | ||||
|             *dest = ss.front(); | ||||
|         }}); | ||||
|     } | ||||
|  |  | |||
|  | @ -186,7 +186,7 @@ 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->querySystem() != systemFilter) | ||||
|             elems.erase(i); | ||||
|     } | ||||
| } | ||||
|  | @ -247,7 +247,7 @@ static DrvInfos filterBySelector(EvalState & state, const DrvInfos & allElems, | |||
|         for (DrvInfos::const_iterator j = allElems.begin(); | ||||
|              j != allElems.end(); ++j, ++n) | ||||
|         { | ||||
|             DrvName drvName(j->name); | ||||
|             DrvName drvName(j->queryName()); | ||||
|             if (i.matches(drvName)) { | ||||
|                 i.hits++; | ||||
|                 matches.push_back(std::pair<DrvInfo, unsigned int>(*j, n)); | ||||
|  | @ -269,36 +269,36 @@ static DrvInfos filterBySelector(EvalState & state, const DrvInfos & allElems, | |||
|             StringSet multiple; | ||||
| 
 | ||||
|             for (auto & j : matches) { | ||||
|                 DrvName drvName(j.first.name); | ||||
|                 DrvName drvName(j.first.queryName()); | ||||
|                 int d = 1; | ||||
| 
 | ||||
|                 Newest::iterator k = newest.find(drvName.name); | ||||
| 
 | ||||
|                 if (k != newest.end()) { | ||||
|                     d = j.first.system == k->second.first.system ? 0 : | ||||
|                         j.first.system == settings.thisSystem ? 1 : | ||||
|                         k->second.first.system == settings.thisSystem ? -1 : 0; | ||||
|                     d = j.first.querySystem() == k->second.first.querySystem() ? 0 : | ||||
|                         j.first.querySystem() == settings.thisSystem ? 1 : | ||||
|                         k->second.first.querySystem() == settings.thisSystem ? -1 : 0; | ||||
|                     if (d == 0) | ||||
|                         d = comparePriorities(state, j.first, k->second.first); | ||||
|                     if (d == 0) | ||||
|                         d = compareVersions(drvName.version, DrvName(k->second.first.name).version); | ||||
|                         d = compareVersions(drvName.version, DrvName(k->second.first.queryName()).version); | ||||
|                 } | ||||
| 
 | ||||
|                 if (d > 0) { | ||||
|                     newest.erase(drvName.name); | ||||
|                     newest.insert(Newest::value_type(drvName.name, j)); | ||||
|                     multiple.erase(j.first.name); | ||||
|                     multiple.erase(j.first.queryName()); | ||||
|                 } else if (d == 0) { | ||||
|                     multiple.insert(j.first.name); | ||||
|                     multiple.insert(j.first.queryName()); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             matches.clear(); | ||||
|             for (auto & j : newest) { | ||||
|                 if (multiple.find(j.second.first.name) != multiple.end()) | ||||
|                 if (multiple.find(j.second.first.queryName()) != multiple.end()) | ||||
|                     printInfo( | ||||
|                         format("warning: there are multiple derivations named ‘%1%’; using the first one") | ||||
|                         % j.second.first.name); | ||||
|                         "warning: there are multiple derivations named ‘%1%’; using the first one", | ||||
|                         j.second.first.queryName()); | ||||
|                 matches.push_back(j.second); | ||||
|             } | ||||
|         } | ||||
|  | @ -386,7 +386,8 @@ static void queryInstSources(EvalState & state, | |||
|                 if (dash != string::npos) | ||||
|                     name = string(name, dash + 1); | ||||
| 
 | ||||
|                 DrvInfo elem(state, name, "", "", 0); | ||||
|                 DrvInfo elem(state, "", nullptr); | ||||
|                 elem.setName(name); | ||||
| 
 | ||||
|                 if (isDerivation(path)) { | ||||
|                     elem.setDrvPath(path); | ||||
|  | @ -468,8 +469,8 @@ static void installDerivations(Globals & globals, | |||
|            path is not the one we want (e.g., `java-front' versus | ||||
|            `java-front-0.9pre15899'). */ | ||||
|         if (globals.forceName != "") | ||||
|             i.name = globals.forceName; | ||||
|         newNames.insert(DrvName(i.name).name); | ||||
|             i.setName(globals.forceName); | ||||
|         newNames.insert(DrvName(i.queryName()).name); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -484,17 +485,17 @@ static void installDerivations(Globals & globals, | |||
|             DrvInfos installedElems = queryInstalled(*globals.state, profile); | ||||
| 
 | ||||
|             for (auto & i : installedElems) { | ||||
|                 DrvName drvName(i.name); | ||||
|                 DrvName drvName(i.queryName()); | ||||
|                 if (!globals.preserveInstalled && | ||||
|                     newNames.find(drvName.name) != newNames.end() && | ||||
|                     !keep(i)) | ||||
|                     printInfo(format("replacing old ‘%1%’") % i.name); | ||||
|                     printInfo("replacing old ‘%s’", i.queryName()); | ||||
|                 else | ||||
|                     allElems.push_back(i); | ||||
|             } | ||||
| 
 | ||||
|             for (auto & i : newElems) | ||||
|                 printInfo(format("installing ‘%1%’") % i.name); | ||||
|                 printInfo("installing ‘%s’", i.queryName()); | ||||
|         } | ||||
| 
 | ||||
|         printMissing(*globals.state, newElems); | ||||
|  | @ -548,7 +549,7 @@ static void upgradeDerivations(Globals & globals, | |||
|         /* Go through all installed derivations. */ | ||||
|         DrvInfos newElems; | ||||
|         for (auto & i : installedElems) { | ||||
|             DrvName drvName(i.name); | ||||
|             DrvName drvName(i.queryName()); | ||||
| 
 | ||||
|             try { | ||||
| 
 | ||||
|  | @ -569,7 +570,7 @@ static void upgradeDerivations(Globals & globals, | |||
|                 for (auto j = availElems.begin(); j != availElems.end(); ++j) { | ||||
|                     if (comparePriorities(*globals.state, i, *j) > 0) | ||||
|                         continue; | ||||
|                     DrvName newName(j->name); | ||||
|                     DrvName newName(j->queryName()); | ||||
|                     if (newName.name == drvName.name) { | ||||
|                         int d = compareVersions(drvName.version, newName.version); | ||||
|                         if ((upgradeType == utLt && d < 0) || | ||||
|  | @ -596,14 +597,13 @@ static void upgradeDerivations(Globals & globals, | |||
|                 { | ||||
|                     const char * action = compareVersions(drvName.version, bestVersion) <= 0 | ||||
|                         ? "upgrading" : "downgrading"; | ||||
|                     printInfo( | ||||
|                         format("%1% ‘%2%’ to ‘%3%’") | ||||
|                         % action % i.name % bestElem->name); | ||||
|                     printInfo("%1% ‘%2%’ to ‘%3%’", | ||||
|                         action, i.queryName(), bestElem->queryName()); | ||||
|                     newElems.push_back(*bestElem); | ||||
|                 } else newElems.push_back(i); | ||||
| 
 | ||||
|             } catch (Error & e) { | ||||
|                 e.addPrefix(format("while trying to find an upgrade for ‘%1%’:\n") % i.name); | ||||
|                 e.addPrefix(fmt("while trying to find an upgrade for ‘%s’:\n", i.queryName())); | ||||
|                 throw; | ||||
|             } | ||||
|         } | ||||
|  | @ -663,10 +663,10 @@ static void opSetFlag(Globals & globals, Strings opFlags, Strings opArgs) | |||
| 
 | ||||
|         /* Update all matching derivations. */ | ||||
|         for (auto & i : installedElems) { | ||||
|             DrvName drvName(i.name); | ||||
|             DrvName drvName(i.queryName()); | ||||
|             for (auto & j : selectors) | ||||
|                 if (j.matches(drvName)) { | ||||
|                     printInfo(format("setting flag on ‘%1%’") % i.name); | ||||
|                     printInfo("setting flag on ‘%1%’", i.queryName()); | ||||
|                     j.hits++; | ||||
|                     setMetaFlag(*globals.state, i, flagName, flagValue); | ||||
|                     break; | ||||
|  | @ -702,7 +702,7 @@ static void opSet(Globals & globals, Strings opFlags, Strings opArgs) | |||
|     DrvInfo & drv(elems.front()); | ||||
| 
 | ||||
|     if (globals.forceName != "") | ||||
|         drv.name = globals.forceName; | ||||
|         drv.setName(globals.forceName); | ||||
| 
 | ||||
|     if (drv.queryDrvPath() != "") { | ||||
|         PathSet paths = {drv.queryDrvPath()}; | ||||
|  | @ -732,7 +732,7 @@ static void uninstallDerivations(Globals & globals, Strings & selectors, | |||
|         DrvInfos newElems; | ||||
| 
 | ||||
|         for (auto & i : installedElems) { | ||||
|             DrvName drvName(i.name); | ||||
|             DrvName drvName(i.queryName()); | ||||
|             bool found = false; | ||||
|             for (auto & j : selectors) | ||||
|                 /* !!! the repeated calls to followLinksToStorePath()
 | ||||
|  | @ -740,7 +740,7 @@ static void uninstallDerivations(Globals & globals, Strings & selectors, | |||
|                 if ((isPath(j) && i.queryOutPath() == globals.state->store->followLinksToStorePath(j)) | ||||
|                     || DrvName(j).matches(drvName)) | ||||
|                 { | ||||
|                     printInfo(format("uninstalling ‘%1%’") % i.name); | ||||
|                     printInfo("uninstalling ‘%s’", i.queryName()); | ||||
|                     found = true; | ||||
|                     break; | ||||
|                 } | ||||
|  | @ -771,9 +771,11 @@ static bool cmpChars(char a, char b) | |||
| 
 | ||||
| static bool cmpElemByName(const DrvInfo & a, const DrvInfo & b) | ||||
| { | ||||
|     auto a_name = a.queryName(); | ||||
|     auto b_name = b.queryName(); | ||||
|     return lexicographical_compare( | ||||
|         a.name.begin(), a.name.end(), | ||||
|         b.name.begin(), b.name.end(), cmpChars); | ||||
|         a_name.begin(), a_name.end(), | ||||
|         b_name.begin(), b_name.end(), cmpChars); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -822,13 +824,13 @@ typedef enum { cvLess, cvEqual, cvGreater, cvUnavail } VersionDiff; | |||
| static VersionDiff compareVersionAgainstSet( | ||||
|     const DrvInfo & elem, const DrvInfos & elems, string & version) | ||||
| { | ||||
|     DrvName name(elem.name); | ||||
|     DrvName name(elem.queryName()); | ||||
| 
 | ||||
|     VersionDiff diff = cvUnavail; | ||||
|     version = "?"; | ||||
| 
 | ||||
|     for (auto & i : elems) { | ||||
|         DrvName name2(i.name); | ||||
|         DrvName name2(i.queryName()); | ||||
|         if (name.name == name2.name) { | ||||
|             int d = compareVersions(name.version, name2.version); | ||||
|             if (d < 0) { | ||||
|  | @ -857,8 +859,8 @@ static void queryJSON(Globals & globals, vector<DrvInfo> & elems) | |||
|     for (auto & i : elems) { | ||||
|         JSONObject pkgObj = topObj.object(i.attrPath); | ||||
| 
 | ||||
|         pkgObj.attr("name", i.name); | ||||
|         pkgObj.attr("system", i.system); | ||||
|         pkgObj.attr("name", i.queryName()); | ||||
|         pkgObj.attr("system", i.querySystem()); | ||||
| 
 | ||||
|         JSONObject metaObj = pkgObj.object("meta"); | ||||
|         StringSet metaNames = i.queryMetaNames(); | ||||
|  | @ -866,7 +868,7 @@ static void queryJSON(Globals & globals, vector<DrvInfo> & elems) | |||
|             auto placeholder = metaObj.placeholder(j); | ||||
|             Value * v = i.queryMeta(j); | ||||
|             if (!v) { | ||||
|                 printError(format("derivation ‘%1%’ has invalid meta attribute ‘%2%’") % i.name % j); | ||||
|                 printError("derivation ‘%s’ has invalid meta attribute ‘%s’", i.queryName(), j); | ||||
|                 placeholder.write(nullptr); | ||||
|             } else { | ||||
|                 PathSet context; | ||||
|  | @ -963,7 +965,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) | |||
|             try { | ||||
|                 paths.insert(i.queryOutPath()); | ||||
|             } catch (AssertionError & e) { | ||||
|                 printMsg(lvlTalkative, format("skipping derivation named ‘%1%’ which gives an assertion failure") % i.name); | ||||
|                 printMsg(lvlTalkative, "skipping derivation named ‘%s’ which gives an assertion failure", i.queryName()); | ||||
|                 i.setFailed(); | ||||
|             } | ||||
|         validPaths = globals.state->store->queryValidPaths(paths); | ||||
|  | @ -1024,9 +1026,9 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) | |||
|                 columns.push_back(i.attrPath); | ||||
| 
 | ||||
|             if (xmlOutput) | ||||
|                 attrs["name"] = i.name; | ||||
|                 attrs["name"] = i.queryName(); | ||||
|             else if (printName) | ||||
|                 columns.push_back(i.name); | ||||
|                 columns.push_back(i.queryName()); | ||||
| 
 | ||||
|             if (compareVersions) { | ||||
|                 /* Compare this element against the versions of the
 | ||||
|  | @ -1059,10 +1061,10 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) | |||
|             } | ||||
| 
 | ||||
|             if (xmlOutput) { | ||||
|                 if (i.system != "") attrs["system"] = i.system; | ||||
|                 if (i.querySystem() != "") attrs["system"] = i.querySystem(); | ||||
|             } | ||||
|             else if (printSystem) | ||||
|                 columns.push_back(i.system); | ||||
|                 columns.push_back(i.querySystem()); | ||||
| 
 | ||||
|             if (printDrvPath) { | ||||
|                 string drvPath = i.queryDrvPath(); | ||||
|  | @ -1110,7 +1112,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) | |||
|                             attrs2["name"] = j; | ||||
|                             Value * v = i.queryMeta(j); | ||||
|                             if (!v) | ||||
|                                 printError(format("derivation ‘%1%’ has invalid meta attribute ‘%2%’") % i.name % j); | ||||
|                                 printError("derivation ‘%s’ has invalid meta attribute ‘%s’", i.queryName(), j); | ||||
|                             else { | ||||
|                                 if (v->type == tString) { | ||||
|                                     attrs2["type"] = "string"; | ||||
|  | @ -1161,9 +1163,9 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) | |||
|             cout.flush(); | ||||
| 
 | ||||
|         } catch (AssertionError & e) { | ||||
|             printMsg(lvlTalkative, format("skipping derivation named ‘%1%’ which gives an assertion failure") % i.name); | ||||
|             printMsg(lvlTalkative, "skipping derivation named ‘%1%’ which gives an assertion failure", i.queryName()); | ||||
|         } catch (Error & e) { | ||||
|             e.addPrefix(format("while querying the derivation named ‘%1%’:\n") % i.name); | ||||
|             e.addPrefix(fmt("while querying the derivation named ‘%1%’:\n", i.queryName())); | ||||
|             throw; | ||||
|         } | ||||
|     } | ||||
|  |  | |||
|  | @ -56,9 +56,10 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, | |||
|         state.mkAttrs(v, 16); | ||||
| 
 | ||||
|         mkString(*state.allocAttr(v, state.sType), "derivation"); | ||||
|         mkString(*state.allocAttr(v, state.sName), i.name); | ||||
|         if (!i.system.empty()) | ||||
|             mkString(*state.allocAttr(v, state.sSystem), i.system); | ||||
|         mkString(*state.allocAttr(v, state.sName), i.queryName()); | ||||
|         auto system = i.querySystem(); | ||||
|         if (!system.empty()) | ||||
|             mkString(*state.allocAttr(v, state.sSystem), system); | ||||
|         mkString(*state.allocAttr(v, state.sOutPath), i.queryOutPath()); | ||||
|         if (drvPath != "") | ||||
|             mkString(*state.allocAttr(v, state.sDrvPath), i.queryDrvPath()); | ||||
|  |  | |||
|  | @ -62,17 +62,13 @@ struct Installable | |||
|     } | ||||
| }; | ||||
| 
 | ||||
| /* A command that operates on a list of "installables", which can be
 | ||||
|    store paths, attribute paths, Nix expressions, etc. */ | ||||
| struct InstallablesCommand : virtual Args, StoreCommand | ||||
| struct SourceExprCommand : virtual Args, StoreCommand | ||||
| { | ||||
|     std::vector<std::shared_ptr<Installable>> installables; | ||||
|     Path file; | ||||
| 
 | ||||
|     InstallablesCommand() | ||||
|     SourceExprCommand() | ||||
|     { | ||||
|         mkFlag('f', "file", "file", "evaluate FILE rather than the default", &file); | ||||
|         expectArgs("installables", &_installables); | ||||
|     } | ||||
| 
 | ||||
|     /* Return a value representing the Nix expression from which we
 | ||||
|  | @ -81,14 +77,32 @@ struct InstallablesCommand : virtual Args, StoreCommand | |||
|        = import ...; bla = import ...; }’. */ | ||||
|     Value * getSourceExpr(EvalState & state); | ||||
| 
 | ||||
|     ref<EvalState> getEvalState(); | ||||
| 
 | ||||
| private: | ||||
| 
 | ||||
|     std::shared_ptr<EvalState> evalState; | ||||
| 
 | ||||
|     Value * vSourceExpr = 0; | ||||
| }; | ||||
| 
 | ||||
| /* A command that operates on a list of "installables", which can be
 | ||||
|    store paths, attribute paths, Nix expressions, etc. */ | ||||
| struct InstallablesCommand : virtual Args, SourceExprCommand | ||||
| { | ||||
|     std::vector<std::shared_ptr<Installable>> installables; | ||||
| 
 | ||||
|     InstallablesCommand() | ||||
|     { | ||||
|         expectArgs("installables", &_installables); | ||||
|     } | ||||
| 
 | ||||
|     std::vector<std::shared_ptr<Installable>> parseInstallables(ref<Store> store, Strings ss); | ||||
| 
 | ||||
|     enum ToStorePathsMode { Build, NoBuild, DryRun }; | ||||
| 
 | ||||
|     PathSet toStorePaths(ref<Store> store, ToStorePathsMode mode); | ||||
| 
 | ||||
|     ref<EvalState> getEvalState(); | ||||
| 
 | ||||
|     void prepare() override; | ||||
| 
 | ||||
|     virtual bool useDefaultInstallables() { return true; } | ||||
|  | @ -96,10 +110,6 @@ struct InstallablesCommand : virtual Args, StoreCommand | |||
| private: | ||||
| 
 | ||||
|     Strings _installables; | ||||
| 
 | ||||
|     std::shared_ptr<EvalState> evalState; | ||||
| 
 | ||||
|     Value * vSourceExpr = 0; | ||||
| }; | ||||
| 
 | ||||
| /* A command that operates on zero or more store paths. */ | ||||
|  |  | |||
|  | @ -12,7 +12,7 @@ | |||
| 
 | ||||
| namespace nix { | ||||
| 
 | ||||
| Value * InstallablesCommand::getSourceExpr(EvalState & state) | ||||
| Value * SourceExprCommand::getSourceExpr(EvalState & state) | ||||
| { | ||||
|     if (vSourceExpr) return vSourceExpr; | ||||
| 
 | ||||
|  | @ -59,6 +59,13 @@ Value * InstallablesCommand::getSourceExpr(EvalState & state) | |||
|     return vSourceExpr; | ||||
| } | ||||
| 
 | ||||
| ref<EvalState> SourceExprCommand::getEvalState() | ||||
| { | ||||
|     if (!evalState) | ||||
|         evalState = std::make_shared<EvalState>(Strings{}, getStore()); | ||||
|     return ref<EvalState>(evalState); | ||||
| } | ||||
| 
 | ||||
| struct InstallableStoreDrv : Installable | ||||
| { | ||||
|     Path storePath; | ||||
|  | @ -237,13 +244,6 @@ PathSet InstallablesCommand::toStorePaths(ref<Store> store, ToStorePathsMode mod | |||
|     return outPaths; | ||||
| } | ||||
| 
 | ||||
| ref<EvalState> InstallablesCommand::getEvalState() | ||||
| { | ||||
|     if (!evalState) | ||||
|         evalState = std::make_shared<EvalState>(Strings{}, getStore()); | ||||
|     return ref<EvalState>(evalState); | ||||
| } | ||||
| 
 | ||||
| void InstallablesCommand::prepare() | ||||
| { | ||||
|     installables = parseInstallables(getStore(), _installables); | ||||
|  |  | |||
							
								
								
									
										130
									
								
								src/nix/search.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								src/nix/search.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,130 @@ | |||
| #include "command.hh" | ||||
| #include "globals.hh" | ||||
| #include "eval.hh" | ||||
| #include "eval-inline.hh" | ||||
| #include "names.hh" | ||||
| #include "get-drvs.hh" | ||||
| 
 | ||||
| #include <regex> | ||||
| 
 | ||||
| using namespace nix; | ||||
| 
 | ||||
| std::string hilite(const std::string & s, const std::smatch & m) | ||||
| { | ||||
|     return | ||||
|         m.empty() | ||||
|         ? s | ||||
|         : std::string(m.prefix()) | ||||
|           + ANSI_RED + std::string(m.str()) + ANSI_NORMAL | ||||
|           + std::string(m.suffix()); | ||||
| } | ||||
| 
 | ||||
| struct CmdSearch : SourceExprCommand | ||||
| { | ||||
|     std::string re; | ||||
| 
 | ||||
|     CmdSearch() | ||||
|     { | ||||
|         expectArg("regex", &re, true); | ||||
|     } | ||||
| 
 | ||||
|     std::string name() override | ||||
|     { | ||||
|         return "search"; | ||||
|     } | ||||
| 
 | ||||
|     std::string description() override | ||||
|     { | ||||
|         return "query available packages"; | ||||
|     } | ||||
| 
 | ||||
|     void run(ref<Store> store) override | ||||
|     { | ||||
|         settings.readOnlyMode = true; | ||||
| 
 | ||||
|         std::regex regex(re, std::regex::extended | std::regex::icase); | ||||
| 
 | ||||
|         auto state = getEvalState(); | ||||
| 
 | ||||
|         std::function<void(Value *, std::string, bool)> doExpr; | ||||
| 
 | ||||
|         bool first = true; | ||||
| 
 | ||||
|         doExpr = [&](Value * v, std::string attrPath, bool toplevel) { | ||||
|             debug("at attribute ‘%s’", attrPath); | ||||
| 
 | ||||
|             try { | ||||
| 
 | ||||
|                 state->forceValue(*v); | ||||
| 
 | ||||
|                 if (v->type == tLambda && toplevel) { | ||||
|                     Value * v2 = state->allocValue(); | ||||
|                     state->autoCallFunction(*state->allocBindings(1), *v, *v2); | ||||
|                     v = v2; | ||||
|                     state->forceValue(*v); | ||||
|                 } | ||||
| 
 | ||||
|                 if (state->isDerivation(*v)) { | ||||
| 
 | ||||
|                     DrvInfo drv(*state, attrPath, v->attrs); | ||||
| 
 | ||||
|                     DrvName parsed(drv.queryName()); | ||||
| 
 | ||||
|                     std::smatch attrPathMatch; | ||||
|                     std::regex_search(attrPath, attrPathMatch, regex); | ||||
| 
 | ||||
|                     auto name = parsed.name; | ||||
|                     std::smatch nameMatch; | ||||
|                     std::regex_search(name, nameMatch, regex); | ||||
| 
 | ||||
|                     std::string description = drv.queryMetaString("description"); | ||||
|                     std::replace(description.begin(), description.end(), '\n', ' '); | ||||
|                     std::smatch descriptionMatch; | ||||
|                     std::regex_search(description, descriptionMatch, regex); | ||||
| 
 | ||||
|                     if (!attrPathMatch.empty() | ||||
|                         || !nameMatch.empty() | ||||
|                         || !descriptionMatch.empty()) | ||||
|                     { | ||||
|                         if (!first) std::cout << "\n"; | ||||
|                         first = false; | ||||
| 
 | ||||
|                         std::cout << fmt( | ||||
|                             "Attribute name: %s\n" | ||||
|                             "Package name: %s\n" | ||||
|                             "Version: %s\n" | ||||
|                             "Description: %s\n", | ||||
|                             hilite(attrPath, attrPathMatch), | ||||
|                             hilite(name, nameMatch), | ||||
|                             parsed.version, | ||||
|                             hilite(description, descriptionMatch)); | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 else if (v->type == tAttrs) { | ||||
| 
 | ||||
|                     if (!toplevel) { | ||||
|                         auto attrs = v->attrs; | ||||
|                         Bindings::iterator j = attrs->find(state->symbols.create("recurseForDerivations")); | ||||
|                         if (j == attrs->end() || !state->forceBool(*j->value, *j->pos)) return; | ||||
|                     } | ||||
| 
 | ||||
|                     Bindings::iterator j = v->attrs->find(state->symbols.create("_toplevel")); | ||||
|                     bool toplevel2 = j != v->attrs->end() && state->forceBool(*j->value, *j->pos); | ||||
| 
 | ||||
|                     for (auto & i : *v->attrs) { | ||||
|                         doExpr(i.value, | ||||
|                             attrPath == "" ? (std::string) i.name : attrPath + "." + (std::string) i.name, | ||||
|                             toplevel2); | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|             } catch (AssertionError & e) { | ||||
|             } | ||||
|         }; | ||||
| 
 | ||||
|         doExpr(getSourceExpr(*state), "", true); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| static RegisterCommand r1(make_ref<CmdSearch>()); | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue