Add "nix search" command

This commit is contained in:
Eelco Dolstra 2017-07-17 19:02:56 +02:00
parent 3162ad5ff4
commit 90825dea51
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE
9 changed files with 263 additions and 102 deletions

View file

@ -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) {

View file

@ -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; };

View file

@ -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";

View file

@ -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();
}}); }});
} }

View file

@ -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;
} }
} }

View file

@ -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());

View file

@ -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. */

View file

@ -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
View 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>());