aboutsummaryrefslogtreecommitdiff
path: root/src/nix/search.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/nix/search.cc')
-rw-r--r--src/nix/search.cc130
1 files changed, 130 insertions, 0 deletions
diff --git a/src/nix/search.cc b/src/nix/search.cc
new file mode 100644
index 000000000..813f6d0a6
--- /dev/null
+++ b/src/nix/search.cc
@@ -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>());