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 { | 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) { |     if (drvPath == "" && attrs) { | ||||||
|         Bindings::iterator i = attrs->find(state->sDrvPath); |         Bindings::iterator i = attrs->find(state->sDrvPath); | ||||||
|  | @ -20,7 +47,7 @@ string DrvInfo::queryDrvPath() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| string DrvInfo::queryOutPath() | string DrvInfo::queryOutPath() const | ||||||
| { | { | ||||||
|     if (outPath == "" && attrs) { |     if (outPath == "" && attrs) { | ||||||
|         Bindings::iterator i = attrs->find(state->sOutPath); |         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) { |     if (outputName == "" && attrs) { | ||||||
|         Bindings::iterator i = attrs->find(state->sOutputName); |         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; |         if (done.find(v.attrs) != done.end()) return false; | ||||||
|         done.insert(v.attrs); |         done.insert(v.attrs); | ||||||
| 
 | 
 | ||||||
|         Bindings::iterator i = v.attrs->find(state.sName); |         DrvInfo drv(state, attrPath, v.attrs); | ||||||
|         /* !!! We really would like to have a decent back trace here. */ |  | ||||||
|         if (i == v.attrs->end()) throw TypeError("derivation name missing"); |  | ||||||
| 
 | 
 | ||||||
|         Bindings::iterator i2 = v.attrs->find(state.sSystem); |         drv.queryName(); | ||||||
| 
 |  | ||||||
|         DrvInfo drv(state, state.forceStringNoCtx(*i->value), attrPath, |  | ||||||
|             i2 == v.attrs->end() ? "unknown" : state.forceStringNoCtx(*i2->value, *i2->pos), |  | ||||||
|             v.attrs); |  | ||||||
| 
 | 
 | ||||||
|         drvs.push_back(drv); |         drvs.push_back(drv); | ||||||
|  | 
 | ||||||
|         return false; |         return false; | ||||||
| 
 | 
 | ||||||
|     } catch (AssertionError & e) { |     } catch (AssertionError & e) { | ||||||
|  |  | ||||||
|  | @ -17,31 +17,32 @@ public: | ||||||
| private: | private: | ||||||
|     EvalState * state; |     EvalState * state; | ||||||
| 
 | 
 | ||||||
|     string drvPath; |     mutable string name; | ||||||
|     string outPath; |     mutable string system; | ||||||
|     string outputName; |     mutable string drvPath; | ||||||
|  |     mutable string outPath; | ||||||
|  |     mutable string outputName; | ||||||
|     Outputs outputs; |     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(); |     Bindings * getMeta(); | ||||||
| 
 | 
 | ||||||
|     bool checkMeta(Value & v); |     bool checkMeta(Value & v); | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
|     string name; |  | ||||||
|     string attrPath; /* path towards the derivation */ |     string attrPath; /* path towards the derivation */ | ||||||
|     string system; |  | ||||||
| 
 | 
 | ||||||
|     DrvInfo(EvalState & state) : state(&state), failed(false), attrs(0), meta(0) { }; |     DrvInfo(EvalState & state) : state(&state) { }; | ||||||
|     DrvInfo(EvalState & state, const string & name, const string & attrPath, const string & system, Bindings * attrs) |     DrvInfo(EvalState & state, const string & attrPath, Bindings * attrs); | ||||||
|         : state(&state), failed(false), attrs(attrs), meta(0), name(name), attrPath(attrPath), system(system) { }; |  | ||||||
| 
 | 
 | ||||||
|     string queryDrvPath(); |     string queryName() const; | ||||||
|     string queryOutPath(); |     string querySystem() const; | ||||||
|     string queryOutputName(); |     string queryDrvPath() const; | ||||||
|  |     string queryOutPath() const; | ||||||
|  |     string queryOutputName() const; | ||||||
|     /** Return the list of outputs. The "outputs to install" are determined by `mesa.outputsToInstall`. */ |     /** Return the list of outputs. The "outputs to install" are determined by `mesa.outputsToInstall`. */ | ||||||
|     Outputs queryOutputs(bool onlyOutputsToInstall = false); |     Outputs queryOutputs(bool onlyOutputsToInstall = false); | ||||||
| 
 | 
 | ||||||
|  | @ -58,15 +59,9 @@ public: | ||||||
|     MetaValue queryMetaInfo(EvalState & state, const string & name) const; |     MetaValue queryMetaInfo(EvalState & state, const string & name) const; | ||||||
|     */ |     */ | ||||||
| 
 | 
 | ||||||
|     void setDrvPath(const string & s) |     void setName(const string & s) { name = s; } | ||||||
|     { |     void setDrvPath(const string & s) { drvPath = s; } | ||||||
|         drvPath = s; |     void setOutPath(const string & s) { outPath = s; } | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     void setOutPath(const string & s) |  | ||||||
|     { |  | ||||||
|         outPath = s; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     void setFailed() { failed = true; }; |     void setFailed() { failed = true; }; | ||||||
|     bool hasFailed() { return failed; }; |     bool hasFailed() { return failed; }; | ||||||
|  |  | ||||||
|  | @ -66,6 +66,7 @@ void Args::printHelp(const string & programName, std::ostream & out) | ||||||
|         std::cout << renderLabels({exp.label}); |         std::cout << renderLabels({exp.label}); | ||||||
|         // FIXME: handle arity > 1
 |         // FIXME: handle arity > 1
 | ||||||
|         if (exp.arity == 0) std::cout << "..."; |         if (exp.arity == 0) std::cout << "..."; | ||||||
|  |         if (exp.optional) std::cout << "?"; | ||||||
|     } |     } | ||||||
|     std::cout << "\n"; |     std::cout << "\n"; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -164,9 +164,9 @@ public: | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /* Expect a string argument. */ |     /* 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(); |             *dest = ss.front(); | ||||||
|         }}); |         }}); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -186,7 +186,7 @@ static void loadDerivations(EvalState & state, Path nixExprPath, | ||||||
|        system. */ |        system. */ | ||||||
|     for (DrvInfos::iterator i = elems.begin(), j; i != elems.end(); i = j) { |     for (DrvInfos::iterator i = elems.begin(), j; i != elems.end(); i = j) { | ||||||
|         j = i; j++; |         j = i; j++; | ||||||
|         if (systemFilter != "*" && i->system != systemFilter) |         if (systemFilter != "*" && i->querySystem() != systemFilter) | ||||||
|             elems.erase(i); |             elems.erase(i); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -247,7 +247,7 @@ static DrvInfos filterBySelector(EvalState & state, const DrvInfos & allElems, | ||||||
|         for (DrvInfos::const_iterator j = allElems.begin(); |         for (DrvInfos::const_iterator j = allElems.begin(); | ||||||
|              j != allElems.end(); ++j, ++n) |              j != allElems.end(); ++j, ++n) | ||||||
|         { |         { | ||||||
|             DrvName drvName(j->name); |             DrvName drvName(j->queryName()); | ||||||
|             if (i.matches(drvName)) { |             if (i.matches(drvName)) { | ||||||
|                 i.hits++; |                 i.hits++; | ||||||
|                 matches.push_back(std::pair<DrvInfo, unsigned int>(*j, n)); |                 matches.push_back(std::pair<DrvInfo, unsigned int>(*j, n)); | ||||||
|  | @ -269,36 +269,36 @@ static DrvInfos filterBySelector(EvalState & state, const DrvInfos & allElems, | ||||||
|             StringSet multiple; |             StringSet multiple; | ||||||
| 
 | 
 | ||||||
|             for (auto & j : matches) { |             for (auto & j : matches) { | ||||||
|                 DrvName drvName(j.first.name); |                 DrvName drvName(j.first.queryName()); | ||||||
|                 int d = 1; |                 int d = 1; | ||||||
| 
 | 
 | ||||||
|                 Newest::iterator k = newest.find(drvName.name); |                 Newest::iterator k = newest.find(drvName.name); | ||||||
| 
 | 
 | ||||||
|                 if (k != newest.end()) { |                 if (k != newest.end()) { | ||||||
|                     d = j.first.system == k->second.first.system ? 0 : |                     d = j.first.querySystem() == k->second.first.querySystem() ? 0 : | ||||||
|                         j.first.system == settings.thisSystem ? 1 : |                         j.first.querySystem() == settings.thisSystem ? 1 : | ||||||
|                         k->second.first.system == settings.thisSystem ? -1 : 0; |                         k->second.first.querySystem() == settings.thisSystem ? -1 : 0; | ||||||
|                     if (d == 0) |                     if (d == 0) | ||||||
|                         d = comparePriorities(state, j.first, k->second.first); |                         d = comparePriorities(state, j.first, k->second.first); | ||||||
|                     if (d == 0) |                     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) { |                 if (d > 0) { | ||||||
|                     newest.erase(drvName.name); |                     newest.erase(drvName.name); | ||||||
|                     newest.insert(Newest::value_type(drvName.name, j)); |                     newest.insert(Newest::value_type(drvName.name, j)); | ||||||
|                     multiple.erase(j.first.name); |                     multiple.erase(j.first.queryName()); | ||||||
|                 } else if (d == 0) { |                 } else if (d == 0) { | ||||||
|                     multiple.insert(j.first.name); |                     multiple.insert(j.first.queryName()); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             matches.clear(); |             matches.clear(); | ||||||
|             for (auto & j : newest) { |             for (auto & j : newest) { | ||||||
|                 if (multiple.find(j.second.first.name) != multiple.end()) |                 if (multiple.find(j.second.first.queryName()) != multiple.end()) | ||||||
|                     printInfo( |                     printInfo( | ||||||
|                         format("warning: there are multiple derivations named ‘%1%’; using the first one") |                         "warning: there are multiple derivations named ‘%1%’; using the first one", | ||||||
|                         % j.second.first.name); |                         j.second.first.queryName()); | ||||||
|                 matches.push_back(j.second); |                 matches.push_back(j.second); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | @ -386,7 +386,8 @@ static void queryInstSources(EvalState & state, | ||||||
|                 if (dash != string::npos) |                 if (dash != string::npos) | ||||||
|                     name = string(name, dash + 1); |                     name = string(name, dash + 1); | ||||||
| 
 | 
 | ||||||
|                 DrvInfo elem(state, name, "", "", 0); |                 DrvInfo elem(state, "", nullptr); | ||||||
|  |                 elem.setName(name); | ||||||
| 
 | 
 | ||||||
|                 if (isDerivation(path)) { |                 if (isDerivation(path)) { | ||||||
|                     elem.setDrvPath(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 |            path is not the one we want (e.g., `java-front' versus | ||||||
|            `java-front-0.9pre15899'). */ |            `java-front-0.9pre15899'). */ | ||||||
|         if (globals.forceName != "") |         if (globals.forceName != "") | ||||||
|             i.name = globals.forceName; |             i.setName(globals.forceName); | ||||||
|         newNames.insert(DrvName(i.name).name); |         newNames.insert(DrvName(i.queryName()).name); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -484,17 +485,17 @@ static void installDerivations(Globals & globals, | ||||||
|             DrvInfos installedElems = queryInstalled(*globals.state, profile); |             DrvInfos installedElems = queryInstalled(*globals.state, profile); | ||||||
| 
 | 
 | ||||||
|             for (auto & i : installedElems) { |             for (auto & i : installedElems) { | ||||||
|                 DrvName drvName(i.name); |                 DrvName drvName(i.queryName()); | ||||||
|                 if (!globals.preserveInstalled && |                 if (!globals.preserveInstalled && | ||||||
|                     newNames.find(drvName.name) != newNames.end() && |                     newNames.find(drvName.name) != newNames.end() && | ||||||
|                     !keep(i)) |                     !keep(i)) | ||||||
|                     printInfo(format("replacing old ‘%1%’") % i.name); |                     printInfo("replacing old ‘%s’", i.queryName()); | ||||||
|                 else |                 else | ||||||
|                     allElems.push_back(i); |                     allElems.push_back(i); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             for (auto & i : newElems) |             for (auto & i : newElems) | ||||||
|                 printInfo(format("installing ‘%1%’") % i.name); |                 printInfo("installing ‘%s’", i.queryName()); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         printMissing(*globals.state, newElems); |         printMissing(*globals.state, newElems); | ||||||
|  | @ -548,7 +549,7 @@ static void upgradeDerivations(Globals & globals, | ||||||
|         /* Go through all installed derivations. */ |         /* Go through all installed derivations. */ | ||||||
|         DrvInfos newElems; |         DrvInfos newElems; | ||||||
|         for (auto & i : installedElems) { |         for (auto & i : installedElems) { | ||||||
|             DrvName drvName(i.name); |             DrvName drvName(i.queryName()); | ||||||
| 
 | 
 | ||||||
|             try { |             try { | ||||||
| 
 | 
 | ||||||
|  | @ -569,7 +570,7 @@ static void upgradeDerivations(Globals & globals, | ||||||
|                 for (auto j = availElems.begin(); j != availElems.end(); ++j) { |                 for (auto j = availElems.begin(); j != availElems.end(); ++j) { | ||||||
|                     if (comparePriorities(*globals.state, i, *j) > 0) |                     if (comparePriorities(*globals.state, i, *j) > 0) | ||||||
|                         continue; |                         continue; | ||||||
|                     DrvName newName(j->name); |                     DrvName newName(j->queryName()); | ||||||
|                     if (newName.name == drvName.name) { |                     if (newName.name == drvName.name) { | ||||||
|                         int d = compareVersions(drvName.version, newName.version); |                         int d = compareVersions(drvName.version, newName.version); | ||||||
|                         if ((upgradeType == utLt && d < 0) || |                         if ((upgradeType == utLt && d < 0) || | ||||||
|  | @ -596,14 +597,13 @@ static void upgradeDerivations(Globals & globals, | ||||||
|                 { |                 { | ||||||
|                     const char * action = compareVersions(drvName.version, bestVersion) <= 0 |                     const char * action = compareVersions(drvName.version, bestVersion) <= 0 | ||||||
|                         ? "upgrading" : "downgrading"; |                         ? "upgrading" : "downgrading"; | ||||||
|                     printInfo( |                     printInfo("%1% ‘%2%’ to ‘%3%’", | ||||||
|                         format("%1% ‘%2%’ to ‘%3%’") |                         action, i.queryName(), bestElem->queryName()); | ||||||
|                         % action % i.name % bestElem->name); |  | ||||||
|                     newElems.push_back(*bestElem); |                     newElems.push_back(*bestElem); | ||||||
|                 } else newElems.push_back(i); |                 } else newElems.push_back(i); | ||||||
| 
 | 
 | ||||||
|             } catch (Error & e) { |             } 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; |                 throw; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | @ -663,10 +663,10 @@ static void opSetFlag(Globals & globals, Strings opFlags, Strings opArgs) | ||||||
| 
 | 
 | ||||||
|         /* Update all matching derivations. */ |         /* Update all matching derivations. */ | ||||||
|         for (auto & i : installedElems) { |         for (auto & i : installedElems) { | ||||||
|             DrvName drvName(i.name); |             DrvName drvName(i.queryName()); | ||||||
|             for (auto & j : selectors) |             for (auto & j : selectors) | ||||||
|                 if (j.matches(drvName)) { |                 if (j.matches(drvName)) { | ||||||
|                     printInfo(format("setting flag on ‘%1%’") % i.name); |                     printInfo("setting flag on ‘%1%’", i.queryName()); | ||||||
|                     j.hits++; |                     j.hits++; | ||||||
|                     setMetaFlag(*globals.state, i, flagName, flagValue); |                     setMetaFlag(*globals.state, i, flagName, flagValue); | ||||||
|                     break; |                     break; | ||||||
|  | @ -702,7 +702,7 @@ static void opSet(Globals & globals, Strings opFlags, Strings opArgs) | ||||||
|     DrvInfo & drv(elems.front()); |     DrvInfo & drv(elems.front()); | ||||||
| 
 | 
 | ||||||
|     if (globals.forceName != "") |     if (globals.forceName != "") | ||||||
|         drv.name = globals.forceName; |         drv.setName(globals.forceName); | ||||||
| 
 | 
 | ||||||
|     if (drv.queryDrvPath() != "") { |     if (drv.queryDrvPath() != "") { | ||||||
|         PathSet paths = {drv.queryDrvPath()}; |         PathSet paths = {drv.queryDrvPath()}; | ||||||
|  | @ -732,7 +732,7 @@ static void uninstallDerivations(Globals & globals, Strings & selectors, | ||||||
|         DrvInfos newElems; |         DrvInfos newElems; | ||||||
| 
 | 
 | ||||||
|         for (auto & i : installedElems) { |         for (auto & i : installedElems) { | ||||||
|             DrvName drvName(i.name); |             DrvName drvName(i.queryName()); | ||||||
|             bool found = false; |             bool found = false; | ||||||
|             for (auto & j : selectors) |             for (auto & j : selectors) | ||||||
|                 /* !!! the repeated calls to followLinksToStorePath()
 |                 /* !!! 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)) |                 if ((isPath(j) && i.queryOutPath() == globals.state->store->followLinksToStorePath(j)) | ||||||
|                     || DrvName(j).matches(drvName)) |                     || DrvName(j).matches(drvName)) | ||||||
|                 { |                 { | ||||||
|                     printInfo(format("uninstalling ‘%1%’") % i.name); |                     printInfo("uninstalling ‘%s’", i.queryName()); | ||||||
|                     found = true; |                     found = true; | ||||||
|                     break; |                     break; | ||||||
|                 } |                 } | ||||||
|  | @ -771,9 +771,11 @@ static bool cmpChars(char a, char b) | ||||||
| 
 | 
 | ||||||
| static bool cmpElemByName(const DrvInfo & a, const DrvInfo & b) | static bool cmpElemByName(const DrvInfo & a, const DrvInfo & b) | ||||||
| { | { | ||||||
|  |     auto a_name = a.queryName(); | ||||||
|  |     auto b_name = b.queryName(); | ||||||
|     return lexicographical_compare( |     return lexicographical_compare( | ||||||
|         a.name.begin(), a.name.end(), |         a_name.begin(), a_name.end(), | ||||||
|         b.name.begin(), b.name.end(), cmpChars); |         b_name.begin(), b_name.end(), cmpChars); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -822,13 +824,13 @@ typedef enum { cvLess, cvEqual, cvGreater, cvUnavail } VersionDiff; | ||||||
| static VersionDiff compareVersionAgainstSet( | static VersionDiff compareVersionAgainstSet( | ||||||
|     const DrvInfo & elem, const DrvInfos & elems, string & version) |     const DrvInfo & elem, const DrvInfos & elems, string & version) | ||||||
| { | { | ||||||
|     DrvName name(elem.name); |     DrvName name(elem.queryName()); | ||||||
| 
 | 
 | ||||||
|     VersionDiff diff = cvUnavail; |     VersionDiff diff = cvUnavail; | ||||||
|     version = "?"; |     version = "?"; | ||||||
| 
 | 
 | ||||||
|     for (auto & i : elems) { |     for (auto & i : elems) { | ||||||
|         DrvName name2(i.name); |         DrvName name2(i.queryName()); | ||||||
|         if (name.name == name2.name) { |         if (name.name == name2.name) { | ||||||
|             int d = compareVersions(name.version, name2.version); |             int d = compareVersions(name.version, name2.version); | ||||||
|             if (d < 0) { |             if (d < 0) { | ||||||
|  | @ -857,8 +859,8 @@ static void queryJSON(Globals & globals, vector<DrvInfo> & elems) | ||||||
|     for (auto & i : elems) { |     for (auto & i : elems) { | ||||||
|         JSONObject pkgObj = topObj.object(i.attrPath); |         JSONObject pkgObj = topObj.object(i.attrPath); | ||||||
| 
 | 
 | ||||||
|         pkgObj.attr("name", i.name); |         pkgObj.attr("name", i.queryName()); | ||||||
|         pkgObj.attr("system", i.system); |         pkgObj.attr("system", i.querySystem()); | ||||||
| 
 | 
 | ||||||
|         JSONObject metaObj = pkgObj.object("meta"); |         JSONObject metaObj = pkgObj.object("meta"); | ||||||
|         StringSet metaNames = i.queryMetaNames(); |         StringSet metaNames = i.queryMetaNames(); | ||||||
|  | @ -866,7 +868,7 @@ static void queryJSON(Globals & globals, vector<DrvInfo> & elems) | ||||||
|             auto placeholder = metaObj.placeholder(j); |             auto placeholder = metaObj.placeholder(j); | ||||||
|             Value * v = i.queryMeta(j); |             Value * v = i.queryMeta(j); | ||||||
|             if (!v) { |             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); |                 placeholder.write(nullptr); | ||||||
|             } else { |             } else { | ||||||
|                 PathSet context; |                 PathSet context; | ||||||
|  | @ -963,7 +965,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) | ||||||
|             try { |             try { | ||||||
|                 paths.insert(i.queryOutPath()); |                 paths.insert(i.queryOutPath()); | ||||||
|             } catch (AssertionError & e) { |             } 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(); |                 i.setFailed(); | ||||||
|             } |             } | ||||||
|         validPaths = globals.state->store->queryValidPaths(paths); |         validPaths = globals.state->store->queryValidPaths(paths); | ||||||
|  | @ -1024,9 +1026,9 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) | ||||||
|                 columns.push_back(i.attrPath); |                 columns.push_back(i.attrPath); | ||||||
| 
 | 
 | ||||||
|             if (xmlOutput) |             if (xmlOutput) | ||||||
|                 attrs["name"] = i.name; |                 attrs["name"] = i.queryName(); | ||||||
|             else if (printName) |             else if (printName) | ||||||
|                 columns.push_back(i.name); |                 columns.push_back(i.queryName()); | ||||||
| 
 | 
 | ||||||
|             if (compareVersions) { |             if (compareVersions) { | ||||||
|                 /* Compare this element against the versions of the
 |                 /* Compare this element against the versions of the
 | ||||||
|  | @ -1059,10 +1061,10 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if (xmlOutput) { |             if (xmlOutput) { | ||||||
|                 if (i.system != "") attrs["system"] = i.system; |                 if (i.querySystem() != "") attrs["system"] = i.querySystem(); | ||||||
|             } |             } | ||||||
|             else if (printSystem) |             else if (printSystem) | ||||||
|                 columns.push_back(i.system); |                 columns.push_back(i.querySystem()); | ||||||
| 
 | 
 | ||||||
|             if (printDrvPath) { |             if (printDrvPath) { | ||||||
|                 string drvPath = i.queryDrvPath(); |                 string drvPath = i.queryDrvPath(); | ||||||
|  | @ -1110,7 +1112,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) | ||||||
|                             attrs2["name"] = j; |                             attrs2["name"] = j; | ||||||
|                             Value * v = i.queryMeta(j); |                             Value * v = i.queryMeta(j); | ||||||
|                             if (!v) |                             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 { |                             else { | ||||||
|                                 if (v->type == tString) { |                                 if (v->type == tString) { | ||||||
|                                     attrs2["type"] = "string"; |                                     attrs2["type"] = "string"; | ||||||
|  | @ -1161,9 +1163,9 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) | ||||||
|             cout.flush(); |             cout.flush(); | ||||||
| 
 | 
 | ||||||
|         } catch (AssertionError & e) { |         } 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) { |         } 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; |             throw; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -56,9 +56,10 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, | ||||||
|         state.mkAttrs(v, 16); |         state.mkAttrs(v, 16); | ||||||
| 
 | 
 | ||||||
|         mkString(*state.allocAttr(v, state.sType), "derivation"); |         mkString(*state.allocAttr(v, state.sType), "derivation"); | ||||||
|         mkString(*state.allocAttr(v, state.sName), i.name); |         mkString(*state.allocAttr(v, state.sName), i.queryName()); | ||||||
|         if (!i.system.empty()) |         auto system = i.querySystem(); | ||||||
|             mkString(*state.allocAttr(v, state.sSystem), i.system); |         if (!system.empty()) | ||||||
|  |             mkString(*state.allocAttr(v, state.sSystem), system); | ||||||
|         mkString(*state.allocAttr(v, state.sOutPath), i.queryOutPath()); |         mkString(*state.allocAttr(v, state.sOutPath), i.queryOutPath()); | ||||||
|         if (drvPath != "") |         if (drvPath != "") | ||||||
|             mkString(*state.allocAttr(v, state.sDrvPath), i.queryDrvPath()); |             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
 | struct SourceExprCommand : virtual Args, StoreCommand | ||||||
|    store paths, attribute paths, Nix expressions, etc. */ |  | ||||||
| struct InstallablesCommand : virtual Args, StoreCommand |  | ||||||
| { | { | ||||||
|     std::vector<std::shared_ptr<Installable>> installables; |  | ||||||
|     Path file; |     Path file; | ||||||
| 
 | 
 | ||||||
|     InstallablesCommand() |     SourceExprCommand() | ||||||
|     { |     { | ||||||
|         mkFlag('f', "file", "file", "evaluate FILE rather than the default", &file); |         mkFlag('f', "file", "file", "evaluate FILE rather than the default", &file); | ||||||
|         expectArgs("installables", &_installables); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /* Return a value representing the Nix expression from which we
 |     /* Return a value representing the Nix expression from which we
 | ||||||
|  | @ -81,14 +77,32 @@ struct InstallablesCommand : virtual Args, StoreCommand | ||||||
|        = import ...; bla = import ...; }’. */ |        = import ...; bla = import ...; }’. */ | ||||||
|     Value * getSourceExpr(EvalState & state); |     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); |     std::vector<std::shared_ptr<Installable>> parseInstallables(ref<Store> store, Strings ss); | ||||||
| 
 | 
 | ||||||
|     enum ToStorePathsMode { Build, NoBuild, DryRun }; |     enum ToStorePathsMode { Build, NoBuild, DryRun }; | ||||||
| 
 | 
 | ||||||
|     PathSet toStorePaths(ref<Store> store, ToStorePathsMode mode); |     PathSet toStorePaths(ref<Store> store, ToStorePathsMode mode); | ||||||
| 
 | 
 | ||||||
|     ref<EvalState> getEvalState(); |  | ||||||
| 
 |  | ||||||
|     void prepare() override; |     void prepare() override; | ||||||
| 
 | 
 | ||||||
|     virtual bool useDefaultInstallables() { return true; } |     virtual bool useDefaultInstallables() { return true; } | ||||||
|  | @ -96,10 +110,6 @@ struct InstallablesCommand : virtual Args, StoreCommand | ||||||
| private: | private: | ||||||
| 
 | 
 | ||||||
|     Strings _installables; |     Strings _installables; | ||||||
| 
 |  | ||||||
|     std::shared_ptr<EvalState> evalState; |  | ||||||
| 
 |  | ||||||
|     Value * vSourceExpr = 0; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /* A command that operates on zero or more store paths. */ | /* A command that operates on zero or more store paths. */ | ||||||
|  |  | ||||||
|  | @ -12,7 +12,7 @@ | ||||||
| 
 | 
 | ||||||
| namespace nix { | namespace nix { | ||||||
| 
 | 
 | ||||||
| Value * InstallablesCommand::getSourceExpr(EvalState & state) | Value * SourceExprCommand::getSourceExpr(EvalState & state) | ||||||
| { | { | ||||||
|     if (vSourceExpr) return vSourceExpr; |     if (vSourceExpr) return vSourceExpr; | ||||||
| 
 | 
 | ||||||
|  | @ -59,6 +59,13 @@ Value * InstallablesCommand::getSourceExpr(EvalState & state) | ||||||
|     return vSourceExpr; |     return vSourceExpr; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | ref<EvalState> SourceExprCommand::getEvalState() | ||||||
|  | { | ||||||
|  |     if (!evalState) | ||||||
|  |         evalState = std::make_shared<EvalState>(Strings{}, getStore()); | ||||||
|  |     return ref<EvalState>(evalState); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| struct InstallableStoreDrv : Installable | struct InstallableStoreDrv : Installable | ||||||
| { | { | ||||||
|     Path storePath; |     Path storePath; | ||||||
|  | @ -237,13 +244,6 @@ PathSet InstallablesCommand::toStorePaths(ref<Store> store, ToStorePathsMode mod | ||||||
|     return outPaths; |     return outPaths; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ref<EvalState> InstallablesCommand::getEvalState() |  | ||||||
| { |  | ||||||
|     if (!evalState) |  | ||||||
|         evalState = std::make_shared<EvalState>(Strings{}, getStore()); |  | ||||||
|     return ref<EvalState>(evalState); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void InstallablesCommand::prepare() | void InstallablesCommand::prepare() | ||||||
| { | { | ||||||
|     installables = parseInstallables(getStore(), _installables); |     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