2023-02-05 12:16:17 -05:00
|
|
|
#include "command-installable-value.hh"
|
2017-07-17 19:02:56 +02:00
|
|
|
#include "globals.hh"
|
|
|
|
#include "eval.hh"
|
|
|
|
#include "eval-inline.hh"
|
2023-07-31 09:19:19 -04:00
|
|
|
#include "eval-settings.hh"
|
2017-07-17 19:02:56 +02:00
|
|
|
#include "names.hh"
|
|
|
|
#include "get-drvs.hh"
|
2017-07-18 17:30:09 +02:00
|
|
|
#include "common-args.hh"
|
2018-05-12 20:00:59 +02:00
|
|
|
#include "shared.hh"
|
2020-04-20 15:27:09 +02:00
|
|
|
#include "eval-cache.hh"
|
|
|
|
#include "attr-path.hh"
|
2022-04-21 11:58:40 +02:00
|
|
|
#include "hilite.hh"
|
2017-07-17 19:02:56 +02:00
|
|
|
|
|
|
|
#include <regex>
|
2017-07-26 17:21:46 +02:00
|
|
|
#include <fstream>
|
2022-11-16 16:49:49 +01:00
|
|
|
#include <nlohmann/json.hpp>
|
2017-07-17 19:02:56 +02:00
|
|
|
|
2024-07-13 00:13:58 +02:00
|
|
|
#include "strings.hh"
|
|
|
|
|
2017-07-17 19:02:56 +02:00
|
|
|
using namespace nix;
|
2022-11-16 16:49:49 +01:00
|
|
|
using json = nlohmann::json;
|
2017-07-17 19:02:56 +02:00
|
|
|
|
2018-05-12 20:00:59 +02:00
|
|
|
std::string wrap(std::string prefix, std::string s)
|
|
|
|
{
|
2022-06-05 18:45:58 +02:00
|
|
|
return concatStrings(prefix, s, ANSI_NORMAL);
|
2018-05-12 20:00:59 +02:00
|
|
|
}
|
|
|
|
|
2023-02-05 12:16:17 -05:00
|
|
|
struct CmdSearch : InstallableValueCommand, MixJSON
|
2017-07-17 19:02:56 +02:00
|
|
|
{
|
2018-04-18 21:08:35 +02:00
|
|
|
std::vector<std::string> res;
|
2022-06-05 18:45:58 +02:00
|
|
|
std::vector<std::string> excludeRes;
|
2017-07-17 19:02:56 +02:00
|
|
|
|
|
|
|
CmdSearch()
|
|
|
|
{
|
2018-04-18 21:08:35 +02:00
|
|
|
expectArgs("regex", &res);
|
2022-06-05 18:45:58 +02:00
|
|
|
addFlag(Flag {
|
|
|
|
.longName = "exclude",
|
|
|
|
.shortName = 'e',
|
|
|
|
.description = "Hide packages whose attribute path, name or description contain *regex*.",
|
|
|
|
.labels = {"regex"},
|
2022-06-20 18:00:32 +02:00
|
|
|
.handler = {[this](std::string s) {
|
|
|
|
excludeRes.push_back(s);
|
|
|
|
}},
|
2022-06-05 18:45:58 +02:00
|
|
|
});
|
2017-07-17 19:02:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string description() override
|
|
|
|
{
|
2020-12-08 18:09:30 +01:00
|
|
|
return "search for packages";
|
2017-07-17 19:02:56 +02:00
|
|
|
}
|
|
|
|
|
2020-12-08 18:09:30 +01:00
|
|
|
std::string doc() override
|
2017-09-07 20:42:11 +02:00
|
|
|
{
|
2020-12-08 18:09:30 +01:00
|
|
|
return
|
|
|
|
#include "search.md"
|
|
|
|
;
|
2017-09-07 20:42:11 +02:00
|
|
|
}
|
|
|
|
|
2020-04-16 15:36:15 +02:00
|
|
|
Strings getDefaultFlakeAttrPaths() override
|
|
|
|
{
|
2020-04-20 15:27:09 +02:00
|
|
|
return {
|
2023-01-23 23:07:34 +08:00
|
|
|
"packages." + settings.thisSystem.get(),
|
|
|
|
"legacyPackages." + settings.thisSystem.get()
|
2020-04-20 15:27:09 +02:00
|
|
|
};
|
2020-04-16 15:36:15 +02:00
|
|
|
}
|
|
|
|
|
2023-02-05 12:16:17 -05:00
|
|
|
void run(ref<Store> store, ref<InstallableValue> installable) override
|
2017-07-17 19:02:56 +02:00
|
|
|
{
|
|
|
|
settings.readOnlyMode = true;
|
2021-09-22 17:15:07 +02:00
|
|
|
evalSettings.enableImportFromDerivation.setDefault(false);
|
2017-07-17 19:02:56 +02:00
|
|
|
|
2023-11-27 23:09:32 +01:00
|
|
|
// Recommend "^" here instead of ".*" due to differences in resulting highlighting
|
2020-04-20 15:27:09 +02:00
|
|
|
if (res.empty())
|
2023-11-27 23:09:32 +01:00
|
|
|
throw UsageError("Must provide at least one regex! To match all packages, use '%s'.", "nix search <installable> ^");
|
2018-04-18 21:08:35 +02:00
|
|
|
|
|
|
|
std::vector<std::regex> regexes;
|
2022-06-05 18:45:58 +02:00
|
|
|
std::vector<std::regex> excludeRegexes;
|
2018-04-18 21:08:35 +02:00
|
|
|
regexes.reserve(res.size());
|
2022-06-05 18:45:58 +02:00
|
|
|
excludeRegexes.reserve(excludeRes.size());
|
2018-02-25 16:38:13 -06:00
|
|
|
|
2020-04-16 15:36:15 +02:00
|
|
|
for (auto & re : res)
|
2018-04-18 21:08:35 +02:00
|
|
|
regexes.push_back(std::regex(re, std::regex::extended | std::regex::icase));
|
2017-07-17 19:02:56 +02:00
|
|
|
|
2022-06-05 18:45:58 +02:00
|
|
|
for (auto & re : excludeRes)
|
|
|
|
excludeRegexes.emplace_back(re, std::regex::extended | std::regex::icase);
|
|
|
|
|
2017-07-17 19:02:56 +02:00
|
|
|
auto state = getEvalState();
|
|
|
|
|
2022-11-16 16:49:49 +01:00
|
|
|
std::optional<nlohmann::json> jsonOut;
|
|
|
|
if (json) jsonOut = json::object();
|
2017-07-18 17:30:09 +02:00
|
|
|
|
2020-04-20 15:27:09 +02:00
|
|
|
uint64_t results = 0;
|
2017-07-19 16:06:10 +02:00
|
|
|
|
2021-02-03 21:22:11 -06:00
|
|
|
std::function<void(eval_cache::AttrCursor & cursor, const std::vector<Symbol> & attrPath, bool initialRecurse)> visit;
|
2017-07-17 19:02:56 +02:00
|
|
|
|
2021-02-03 21:22:11 -06:00
|
|
|
visit = [&](eval_cache::AttrCursor & cursor, const std::vector<Symbol> & attrPath, bool initialRecurse)
|
2020-04-20 15:27:09 +02:00
|
|
|
{
|
2022-04-22 21:45:39 +02:00
|
|
|
auto attrPathS = state->symbols.resolve(attrPath);
|
|
|
|
|
2020-04-20 15:27:09 +02:00
|
|
|
Activity act(*logger, lvlInfo, actUnknown,
|
2024-07-13 00:13:58 +02:00
|
|
|
fmt("evaluating '%s'", concatStringsSep(".", attrPathS)));
|
2017-07-17 19:02:56 +02:00
|
|
|
try {
|
2020-04-20 15:27:09 +02:00
|
|
|
auto recurse = [&]()
|
|
|
|
{
|
|
|
|
for (const auto & attr : cursor.getAttrs()) {
|
2022-04-22 21:45:39 +02:00
|
|
|
auto cursor2 = cursor.getAttr(state->symbols[attr]);
|
2020-04-20 15:27:09 +02:00
|
|
|
auto attrPath2(attrPath);
|
|
|
|
attrPath2.push_back(attr);
|
2021-02-03 21:22:11 -06:00
|
|
|
visit(*cursor2, attrPath2, false);
|
2020-04-20 15:27:09 +02:00
|
|
|
}
|
|
|
|
};
|
2017-07-17 19:02:56 +02:00
|
|
|
|
2020-04-20 15:27:09 +02:00
|
|
|
if (cursor.isDerivation()) {
|
2022-04-20 16:39:47 +02:00
|
|
|
DrvName name(cursor.getAttr(state->sName)->getString());
|
2017-07-17 19:02:56 +02:00
|
|
|
|
2022-04-20 16:39:47 +02:00
|
|
|
auto aMeta = cursor.maybeGetAttr(state->sMeta);
|
|
|
|
auto aDescription = aMeta ? aMeta->maybeGetAttr(state->sDescription) : nullptr;
|
2020-04-20 15:27:09 +02:00
|
|
|
auto description = aDescription ? aDescription->getString() : "";
|
|
|
|
std::replace(description.begin(), description.end(), '\n', ' ');
|
2024-07-12 22:09:27 +02:00
|
|
|
auto attrPath2 = dropEmptyInitThenConcatStringsSep(".", attrPathS);
|
2017-07-17 19:02:56 +02:00
|
|
|
|
2022-01-19 17:46:29 +01:00
|
|
|
std::vector<std::smatch> attrPathMatches;
|
|
|
|
std::vector<std::smatch> descriptionMatches;
|
|
|
|
std::vector<std::smatch> nameMatches;
|
|
|
|
bool found = false;
|
2017-07-17 19:02:56 +02:00
|
|
|
|
2022-06-05 18:45:58 +02:00
|
|
|
for (auto & regex : excludeRegexes) {
|
|
|
|
if (
|
|
|
|
std::regex_search(attrPath2, regex)
|
|
|
|
|| std::regex_search(name.name, regex)
|
|
|
|
|| std::regex_search(description, regex))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-04-20 15:27:09 +02:00
|
|
|
for (auto & regex : regexes) {
|
2022-01-19 17:46:29 +01:00
|
|
|
found = false;
|
2022-01-24 14:47:34 +01:00
|
|
|
auto addAll = [&found](std::sregex_iterator it, std::vector<std::smatch> & vec) {
|
2022-01-19 19:59:02 +01:00
|
|
|
const auto end = std::sregex_iterator();
|
2022-01-24 14:47:34 +01:00
|
|
|
while (it != end) {
|
2022-01-19 19:59:02 +01:00
|
|
|
vec.push_back(*it++);
|
|
|
|
found = true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-01-24 14:47:34 +01:00
|
|
|
addAll(std::sregex_iterator(attrPath2.begin(), attrPath2.end(), regex), attrPathMatches);
|
|
|
|
addAll(std::sregex_iterator(name.name.begin(), name.name.end(), regex), nameMatches);
|
|
|
|
addAll(std::sregex_iterator(description.begin(), description.end(), regex), descriptionMatches);
|
2022-01-19 17:46:29 +01:00
|
|
|
|
2022-01-24 14:47:34 +01:00
|
|
|
if (!found)
|
2022-01-19 17:46:29 +01:00
|
|
|
break;
|
2018-04-18 21:08:35 +02:00
|
|
|
}
|
2017-07-17 19:02:56 +02:00
|
|
|
|
2022-01-19 17:46:29 +01:00
|
|
|
if (found)
|
|
|
|
{
|
2020-04-20 15:27:09 +02:00
|
|
|
results++;
|
2017-07-18 17:30:09 +02:00
|
|
|
if (json) {
|
2022-11-16 16:49:49 +01:00
|
|
|
(*jsonOut)[attrPath2] = {
|
|
|
|
{"pname", name.name},
|
|
|
|
{"version", name.version},
|
|
|
|
{"description", description},
|
|
|
|
};
|
2017-07-18 17:30:09 +02:00
|
|
|
} else {
|
2022-06-05 18:48:48 +02:00
|
|
|
auto name2 = hiliteMatches(name.name, nameMatches, ANSI_GREEN, "\e[0;2m");
|
2020-09-25 11:30:04 -04:00
|
|
|
if (results > 1) logger->cout("");
|
|
|
|
logger->cout(
|
2020-04-24 14:42:17 +02:00
|
|
|
"* %s%s",
|
2022-06-05 18:48:48 +02:00
|
|
|
wrap("\e[0;1m", hiliteMatches(attrPath2, attrPathMatches, ANSI_GREEN, "\e[0;1m")),
|
2020-04-24 14:42:17 +02:00
|
|
|
name.version != "" ? " (" + name.version + ")" : "");
|
2020-04-20 15:27:09 +02:00
|
|
|
if (description != "")
|
2020-09-25 11:30:04 -04:00
|
|
|
logger->cout(
|
2022-06-05 18:48:48 +02:00
|
|
|
" %s", hiliteMatches(description, descriptionMatches, ANSI_GREEN, ANSI_NORMAL));
|
2017-07-26 17:21:46 +02:00
|
|
|
}
|
|
|
|
}
|
2017-07-17 19:02:56 +02:00
|
|
|
}
|
|
|
|
|
2020-04-20 15:27:09 +02:00
|
|
|
else if (
|
|
|
|
attrPath.size() == 0
|
2022-04-22 21:45:39 +02:00
|
|
|
|| (attrPathS[0] == "legacyPackages" && attrPath.size() <= 2)
|
|
|
|
|| (attrPathS[0] == "packages" && attrPath.size() <= 2))
|
2020-04-20 15:27:09 +02:00
|
|
|
recurse();
|
2017-07-17 19:02:56 +02:00
|
|
|
|
2021-02-03 21:22:11 -06:00
|
|
|
else if (initialRecurse)
|
|
|
|
recurse();
|
|
|
|
|
2022-04-22 21:45:39 +02:00
|
|
|
else if (attrPathS[0] == "legacyPackages" && attrPath.size() > 2) {
|
2022-04-26 14:01:21 +02:00
|
|
|
auto attr = cursor.maybeGetAttr(state->sRecurseForDerivations);
|
2020-04-27 16:29:26 +02:00
|
|
|
if (attr && attr->getBool())
|
|
|
|
recurse();
|
2017-07-17 19:02:56 +02:00
|
|
|
}
|
|
|
|
|
2020-04-20 15:27:09 +02:00
|
|
|
} catch (EvalError & e) {
|
2022-04-22 21:45:39 +02:00
|
|
|
if (!(attrPath.size() > 0 && attrPathS[0] == "legacyPackages"))
|
2017-07-19 16:06:10 +02:00
|
|
|
throw;
|
2017-07-17 19:02:56 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-04-14 14:04:19 +02:00
|
|
|
for (auto & cursor : installable->getCursors(*state))
|
|
|
|
visit(*cursor, cursor->getAttrPath(), true);
|
2017-07-26 17:21:46 +02:00
|
|
|
|
2023-03-02 15:02:24 +01:00
|
|
|
if (json)
|
|
|
|
logger->cout("%s", *jsonOut);
|
2022-11-16 16:49:49 +01:00
|
|
|
|
2020-05-07 12:13:16 +02:00
|
|
|
if (!json && !results)
|
2018-05-12 20:00:59 +02:00
|
|
|
throw Error("no results for the given search term(s)!");
|
2017-07-17 19:02:56 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-10-06 13:36:55 +02:00
|
|
|
static auto rCmdSearch = registerCommand<CmdSearch>("search");
|