about summary refs log tree commit diff
path: root/src/nix/search.cc
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2017-07-17T17·02+0200
committerEelco Dolstra <edolstra@gmail.com>2017-07-20T11·33+0200
commit90825dea518ea078f0783a72cc471a5b3716d198 (patch)
treeb6f6fed6e8c7a96a6769344060409f19a56290b9 /src/nix/search.cc
parent3162ad5ff497b92fc25cd3f397eaff01d67340cc (diff)
Add "nix search" command
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 000000000000..813f6d0a6226
--- /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>());