From 90825dea518ea078f0783a72cc471a5b3716d198 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 17 Jul 2017 19:02:56 +0200 Subject: Add "nix search" command --- src/nix/command.hh | 34 ++++++++----- src/nix/installables.cc | 16 +++--- src/nix/search.cc | 130 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 160 insertions(+), 20 deletions(-) create mode 100644 src/nix/search.cc (limited to 'src/nix') 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> 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 getEvalState(); + +private: + + std::shared_ptr 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> installables; + + InstallablesCommand() + { + expectArgs("installables", &_installables); + } + std::vector> parseInstallables(ref store, Strings ss); enum ToStorePathsMode { Build, NoBuild, DryRun }; PathSet toStorePaths(ref store, ToStorePathsMode mode); - ref 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; - - 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 SourceExprCommand::getEvalState() +{ + if (!evalState) + evalState = std::make_shared(Strings{}, getStore()); + return ref(evalState); +} + struct InstallableStoreDrv : Installable { Path storePath; @@ -237,13 +244,6 @@ PathSet InstallablesCommand::toStorePaths(ref store, ToStorePathsMode mod return outPaths; } -ref InstallablesCommand::getEvalState() -{ - if (!evalState) - evalState = std::make_shared(Strings{}, getStore()); - return ref(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 + +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) override + { + settings.readOnlyMode = true; + + std::regex regex(re, std::regex::extended | std::regex::icase); + + auto state = getEvalState(); + + std::function 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()); -- cgit 1.4.1