about summary refs log tree commit diff
path: root/src/nix
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
parent3162ad5ff497b92fc25cd3f397eaff01d67340cc (diff)
Add "nix search" command
Diffstat (limited to 'src/nix')
-rw-r--r--src/nix/command.hh34
-rw-r--r--src/nix/installables.cc16
-rw-r--r--src/nix/search.cc130
3 files changed, 160 insertions, 20 deletions
diff --git a/src/nix/command.hh b/src/nix/command.hh
index ae7709b5dc83..536802653819 100644
--- a/src/nix/command.hh
+++ b/src/nix/command.hh
@@ -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. */
diff --git a/src/nix/installables.cc b/src/nix/installables.cc
index 7fad8fe415c6..4da736f4d5c3 100644
--- a/src/nix/installables.cc
+++ b/src/nix/installables.cc
@@ -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);
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>());