libexpr: standardize on strings for attr cache traversal

it's all strings anyway. the db stores strings, the cli wants to
interact with attr paths as strings, so we will just use strings

Change-Id: Id9ea07d92343de77e8d47af8fec1e86ae225e9a1
This commit is contained in:
eldritch horrors 2024-12-03 20:38:41 +01:00
parent dd7d7450a5
commit 9a3e3a5560
12 changed files with 155 additions and 207 deletions

View file

@ -118,8 +118,8 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
std::optional<NixInt::Inner> priority;
if (attr->maybeGetAttr(state->s.outputSpecified)) {
} else if (auto aMeta = attr->maybeGetAttr(state->s.meta)) {
if (attr->maybeGetAttr("outputSpecified")) {
} else if (auto aMeta = attr->maybeGetAttr("meta")) {
if (auto aPriority = aMeta->maybeGetAttr("priority"))
priority = aPriority->getInt().value;
}
@ -130,12 +130,12 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
.outputs = std::visit(overloaded {
[&](const ExtendedOutputsSpec::Default & d) -> OutputsSpec {
std::set<std::string> outputsToInstall;
if (auto aOutputSpecified = attr->maybeGetAttr(state->s.outputSpecified)) {
if (auto aOutputSpecified = attr->maybeGetAttr("outputSpecified")) {
if (aOutputSpecified->getBool()) {
if (auto aOutputName = attr->maybeGetAttr("outputName"))
outputsToInstall = { aOutputName->getString() };
}
} else if (auto aMeta = attr->maybeGetAttr(state->s.meta)) {
} else if (auto aMeta = attr->maybeGetAttr("meta")) {
if (auto aOutputsToInstall = aMeta->maybeGetAttr("outputsToInstall"))
for (auto & s : aOutputsToInstall->getListOfStrings())
outputsToInstall.insert(s);
@ -184,7 +184,7 @@ InstallableFlake::getCursors()
for (auto & attrPath : attrPaths) {
debug("trying flake output attribute '%s'", attrPath);
auto attr = root->findAlongAttrPath(parseAttrPath(*state, attrPath));
auto attr = root->findAlongAttrPath(parseAttrPath(attrPath));
if (attr) {
res.push_back(ref(*attr));
} else {

View file

@ -305,13 +305,13 @@ void completeFlakeRefWithFragment(
attrPathPrefixes.push_back("");
for (auto & attrPathPrefixS : attrPathPrefixes) {
auto attrPathPrefix = parseAttrPath(*evalState, attrPathPrefixS);
auto attrPathPrefix = parseAttrPath(attrPathPrefixS);
auto attrPathS = attrPathPrefixS + std::string(fragment);
auto attrPath = parseAttrPath(*evalState, attrPathS);
auto attrPath = parseAttrPath(attrPathS);
std::string lastAttr;
if (!attrPath.empty() && !attrPathS.ends_with(".")) {
lastAttr = evalState->symbols[attrPath.back()];
lastAttr = attrPath.back();
attrPath.pop_back();
}
@ -319,11 +319,11 @@ void completeFlakeRefWithFragment(
if (!attr) continue;
for (auto & attr2 : (*attr)->getAttrs()) {
if (std::string_view(evalState->symbols[attr2]).starts_with(lastAttr)) {
auto attrPath2 = (*attr)->getAttrPath(attr2);
if (std::string_view attr2s = attr2; attr2s.starts_with(lastAttr)) {
auto attrPath2 = (*attr)->getAttrPath(attr2s);
/* Strip the attrpath prefix. */
attrPath2.erase(attrPath2.begin(), attrPath2.begin() + attrPathPrefix.size());
completions.add(flakeRefS + "#" + prefixRoot + concatStringsSep(".", evalState->symbols.resolve(attrPath2)));
completions.add(flakeRefS + "#" + prefixRoot + concatStringsSep(".", attrPath2));
}
}
}
@ -332,7 +332,7 @@ void completeFlakeRefWithFragment(
attrpaths. */
if (fragment.empty()) {
for (auto & attrPath : defaultFlakeAttrPaths) {
auto attr = root->findAlongAttrPath(parseAttrPath(*evalState, attrPath));
auto attr = root->findAlongAttrPath(parseAttrPath(attrPath));
if (!attr) continue;
completions.add(flakeRefS + "#" + prefixRoot);
}

View file

@ -5,7 +5,7 @@
namespace nix {
static Strings parseAttrPath(std::string_view s)
Strings parseAttrPath(std::string_view s)
{
Strings res;
std::string cur;
@ -31,15 +31,6 @@ static Strings parseAttrPath(std::string_view s)
}
std::vector<Symbol> parseAttrPath(EvalState & state, std::string_view s)
{
std::vector<Symbol> res;
for (auto & a : parseAttrPath(s))
res.push_back(state.symbols.create(a));
return res;
}
std::pair<Value *, PosIdx> findAlongAttrPath(EvalState & state, const std::string & attrPath,
Bindings & autoArgs, Value & vIn)
{

View file

@ -22,6 +22,6 @@ std::pair<Value *, PosIdx> findAlongAttrPath(
*/
std::pair<SourcePath, uint32_t> findPackageFilename(EvalState & state, Value & v, std::string what);
std::vector<Symbol> parseAttrPath(EvalState & state, std::string_view s);
Strings parseAttrPath(std::string_view s);
}

View file

@ -35,15 +35,11 @@ struct AttrDb
std::unique_ptr<Sync<State>> _state;
SymbolTable & symbols;
AttrDb(
const Store & cfg,
const Hash & fingerprint,
SymbolTable & symbols)
const Hash & fingerprint)
: cfg(cfg)
, _state(std::make_unique<Sync<State>>())
, symbols(symbols)
{
auto state(_state->lock());
@ -98,7 +94,7 @@ struct AttrDb
AttrId setAttrs(
AttrKey key,
const std::vector<Symbol> & attrs)
const fullattr_t & attrs)
{
return doSQLite([&]()
{
@ -106,17 +102,17 @@ struct AttrDb
state->insertAttribute.use()
(key.first)
(symbols[key.second])
(key.second)
(AttrType::FullAttrs)
(0, false).exec();
AttrId rowId = state->db.getLastInsertedRowId();
assert(rowId);
for (auto & attr : attrs)
for (auto & attr : attrs.p)
state->insertAttribute.use()
(rowId)
(symbols[attr])
(attr)
(AttrType::Placeholder)
(0, false).exec();
@ -141,14 +137,14 @@ struct AttrDb
}
state->insertAttributeWithContext.use()
(key.first)
(symbols[key.second])
(key.second)
(AttrType::String)
(s)
(ctx).exec();
} else {
state->insertAttribute.use()
(key.first)
(symbols[key.second])
(key.second)
(AttrType::String)
(s).exec();
}
@ -167,7 +163,7 @@ struct AttrDb
state->insertAttribute.use()
(key.first)
(symbols[key.second])
(key.second)
(AttrType::Bool)
(b ? 1 : 0).exec();
@ -185,7 +181,7 @@ struct AttrDb
state->insertAttribute.use()
(key.first)
(symbols[key.second])
(key.second)
(AttrType::Int)
(n).exec();
@ -203,7 +199,7 @@ struct AttrDb
state->insertAttribute.use()
(key.first)
(symbols[key.second])
(key.second)
(AttrType::ListOfStrings)
(concatStringsSep("\t", l)).exec();
@ -219,7 +215,7 @@ struct AttrDb
state->insertAttribute.use()
(key.first)
(symbols[key.second])
(key.second)
(AttrType::Placeholder)
(0, false).exec();
@ -235,7 +231,7 @@ struct AttrDb
state->insertAttribute.use()
(key.first)
(symbols[key.second])
(key.second)
(AttrType::Missing)
(0, false).exec();
@ -251,7 +247,7 @@ struct AttrDb
state->insertAttribute.use()
(key.first)
(symbols[key.second])
(key.second)
(AttrType::Misc)
(0, false).exec();
@ -267,7 +263,7 @@ struct AttrDb
state->insertAttribute.use()
(key.first)
(symbols[key.second])
(key.second)
(AttrType::Failed)
(0, false).exec();
@ -279,7 +275,7 @@ struct AttrDb
{
auto state(_state->lock());
auto queryAttribute(state->queryAttribute.use()(key.first)(symbols[key.second]));
auto queryAttribute(state->queryAttribute.use()(key.first)(key.second));
if (!queryAttribute.next()) return {};
auto rowId = (AttrId) queryAttribute.getInt(0);
@ -290,10 +286,10 @@ struct AttrDb
return {{rowId, placeholder_t()}};
case AttrType::FullAttrs: {
// FIXME: expensive, should separate this out.
std::vector<Symbol> attrs;
fullattr_t attrs;
auto queryAttributes(state->queryAttributes.use()(rowId));
while (queryAttributes.next())
attrs.emplace_back(symbols.create(queryAttributes.getStr(0)));
attrs.p.emplace_back(queryAttributes.getStr(0));
return {{rowId, attrs}};
}
case AttrType::String: {
@ -323,11 +319,10 @@ struct AttrDb
static std::shared_ptr<AttrDb> makeAttrDb(
const Store & cfg,
const Hash & fingerprint,
SymbolTable & symbols)
const Hash & fingerprint)
{
try {
return std::make_shared<AttrDb>(cfg, fingerprint, symbols);
return std::make_shared<AttrDb>(cfg, fingerprint);
} catch (SQLiteError &) {
ignoreExceptionExceptInterrupt();
return nullptr;
@ -348,7 +343,7 @@ EvalCache::EvalCache(
std::optional<std::reference_wrapper<const Hash>> useCache,
EvalState & state,
RootLoader rootLoader)
: db(useCache ? makeAttrDb(*state.store, *useCache, state.symbols) : nullptr)
: db(useCache ? makeAttrDb(*state.store, *useCache) : nullptr)
, state(state)
, rootLoader(rootLoader)
{
@ -382,7 +377,7 @@ AttrCursor::AttrCursor(
AttrKey AttrCursor::getKey()
{
if (!parent)
return {0, root->state.s.epsilon};
return {0, ""};
if (!parent->first->cachedValue) {
parent->first->cachedValue = root->db->getAttr(parent->first->getKey());
assert(parent->first->cachedValue);
@ -396,7 +391,7 @@ Value & AttrCursor::getValue()
if (parent) {
auto & vParent = parent->first->getValue();
root->state.forceAttrs(vParent, noPos, "while searching for an attribute");
auto attr = vParent.attrs->get(parent->second);
auto attr = vParent.attrs->get(root->state.symbols.create(parent->second));
if (!attr)
throw Error("attribute '%s' is unexpectedly missing", getAttrPathStr());
_value = allocRootValue(attr->value);
@ -406,7 +401,7 @@ Value & AttrCursor::getValue()
return **_value;
}
std::vector<Symbol> AttrCursor::getAttrPath() const
std::vector<std::string> AttrCursor::getAttrPath() const
{
if (parent) {
auto attrPath = parent->first->getAttrPath();
@ -416,21 +411,21 @@ std::vector<Symbol> AttrCursor::getAttrPath() const
return {};
}
std::vector<Symbol> AttrCursor::getAttrPath(Symbol name) const
std::vector<std::string> AttrCursor::getAttrPath(std::string_view name) const
{
auto attrPath = getAttrPath();
attrPath.push_back(name);
attrPath.emplace_back(name);
return attrPath;
}
std::string AttrCursor::getAttrPathStr() const
{
return concatStringsSep(".", root->state.symbols.resolve(getAttrPath()));
return concatStringsSep(".", getAttrPath());
}
std::string AttrCursor::getAttrPathStr(Symbol name) const
std::string AttrCursor::getAttrPathStr(std::string_view name) const
{
return concatStringsSep(".", root->state.symbols.resolve(getAttrPath(name)));
return concatStringsSep(".", getAttrPath(name));
}
Value & AttrCursor::forceValue()
@ -469,27 +464,23 @@ Value & AttrCursor::forceValue()
return v;
}
Suggestions AttrCursor::getSuggestionsForAttr(Symbol name)
Suggestions AttrCursor::getSuggestionsForAttr(const std::string & name)
{
auto attrNames = getAttrs();
std::set<std::string> strAttrNames;
for (auto & name : attrNames)
strAttrNames.insert(root->state.symbols[name]);
return Suggestions::bestMatches(strAttrNames, root->state.symbols[name]);
return Suggestions::bestMatches({attrNames.begin(), attrNames.end()}, name);
}
std::shared_ptr<AttrCursor> AttrCursor::maybeGetAttr(Symbol name)
std::shared_ptr<AttrCursor> AttrCursor::maybeGetAttr(const std::string & name)
{
if (root->db) {
if (!cachedValue)
cachedValue = root->db->getAttr(getKey());
if (cachedValue) {
if (auto attrs = std::get_if<std::vector<Symbol>>(&cachedValue->second)) {
for (auto & attr : *attrs)
if (auto attrs = std::get_if<fullattr_t>(&cachedValue->second)) {
for (auto & attr : attrs->p)
if (attr == name)
return std::make_shared<AttrCursor>(root, std::make_pair(shared_from_this(), attr));
return std::make_shared<AttrCursor>(root, std::make_pair(shared_from_this(), name));
return nullptr;
} else if (std::get_if<placeholder_t>(&cachedValue->second)) {
auto attr = root->db->getAttr({cachedValue->first, name});
@ -516,7 +507,7 @@ std::shared_ptr<AttrCursor> AttrCursor::maybeGetAttr(Symbol name)
return nullptr;
//errors.make<TypeError>("'%s' is not an attribute set", getAttrPathStr()).debugThrow();
auto attr = v.attrs->get(name);
auto attr = v.attrs->get(root->state.symbols.create(name));
if (!attr) {
if (root->db) {
@ -538,12 +529,7 @@ std::shared_ptr<AttrCursor> AttrCursor::maybeGetAttr(Symbol name)
root, std::make_pair(shared_from_this(), name), attr->value, std::move(cachedValue2));
}
std::shared_ptr<AttrCursor> AttrCursor::maybeGetAttr(std::string_view name)
{
return maybeGetAttr(root->state.symbols.create(name));
}
ref<AttrCursor> AttrCursor::getAttr(Symbol name)
ref<AttrCursor> AttrCursor::getAttr(const std::string & name)
{
auto p = maybeGetAttr(name);
if (!p)
@ -551,12 +537,7 @@ ref<AttrCursor> AttrCursor::getAttr(Symbol name)
return ref(p);
}
ref<AttrCursor> AttrCursor::getAttr(std::string_view name)
{
return getAttr(root->state.symbols.create(name));
}
OrSuggestions<ref<AttrCursor>> AttrCursor::findAlongAttrPath(const std::vector<Symbol> & attrPath)
OrSuggestions<ref<AttrCursor>> AttrCursor::findAlongAttrPath(const Strings & attrPath)
{
auto res = shared_from_this();
for (auto & attr : attrPath) {
@ -717,15 +698,15 @@ std::vector<std::string> AttrCursor::getListOfStrings()
return res;
}
std::vector<Symbol> AttrCursor::getAttrs()
std::vector<std::string> AttrCursor::getAttrs()
{
if (root->db) {
if (!cachedValue)
cachedValue = root->db->getAttr(getKey());
if (cachedValue && !std::get_if<placeholder_t>(&cachedValue->second)) {
if (auto attrs = std::get_if<std::vector<Symbol>>(&cachedValue->second)) {
if (auto attrs = std::get_if<fullattr_t>(&cachedValue->second)) {
debug("using cached attrset attribute '%s'", getAttrPathStr());
return *attrs;
return attrs->p;
} else
root->state.errors.make<TypeError>("'%s' is not an attribute set", getAttrPathStr()).debugThrow();
}
@ -736,18 +717,15 @@ std::vector<Symbol> AttrCursor::getAttrs()
if (v.type() != nAttrs)
root->state.errors.make<TypeError>("'%s' is not an attribute set", getAttrPathStr()).debugThrow();
std::vector<Symbol> attrs;
fullattr_t attrs;
for (auto & attr : *getValue().attrs)
attrs.push_back(attr.name);
std::sort(attrs.begin(), attrs.end(), [&](Symbol a, Symbol b) {
std::string_view sa = root->state.symbols[a], sb = root->state.symbols[b];
return sa < sb;
});
attrs.p.push_back(root->state.symbols[attr.name]);
std::sort(attrs.p.begin(), attrs.p.end());
if (root->db)
cachedValue = {root->db->setAttrs(getKey(), attrs), attrs};
return attrs;
return attrs.p;
}
bool AttrCursor::isDerivation()
@ -758,7 +736,7 @@ bool AttrCursor::isDerivation()
StorePath AttrCursor::forceDerivation()
{
auto aDrvPath = getAttr(root->state.s.drvPath);
auto aDrvPath = getAttr("drvPath");
auto drvPath = root->state.store->parseStorePath(aDrvPath->getString());
if (!root->state.store->isValidPath(drvPath) && !settings.readOnlyMode) {
/* The eval cache contains 'drvPath', but the actual path has

View file

@ -69,16 +69,17 @@ enum AttrType {
};
struct placeholder_t {};
struct fullattr_t { std::vector<std::string> p; };
struct missing_t {};
struct misc_t {};
struct failed_t {};
struct int_t { NixInt x; };
typedef uint64_t AttrId;
typedef std::pair<AttrId, Symbol> AttrKey;
typedef std::pair<AttrId, std::string> AttrKey;
typedef std::pair<std::string, NixStringContext> string_t;
typedef std::variant<
std::vector<Symbol>,
fullattr_t,
string_t,
placeholder_t,
missing_t,
@ -94,7 +95,7 @@ class AttrCursor : public std::enable_shared_from_this<AttrCursor>
friend class EvalCache;
ref<EvalCache> root;
typedef std::optional<std::pair<std::shared_ptr<AttrCursor>, Symbol>> Parent;
typedef std::optional<std::pair<std::shared_ptr<AttrCursor>, std::string>> Parent;
Parent parent;
RootValue _value;
std::optional<std::pair<AttrId, AttrValue>> cachedValue;
@ -111,29 +112,25 @@ public:
Value * value = nullptr,
std::optional<std::pair<AttrId, AttrValue>> && cachedValue = {});
std::vector<Symbol> getAttrPath() const;
std::vector<std::string> getAttrPath() const;
std::vector<Symbol> getAttrPath(Symbol name) const;
std::vector<std::string> getAttrPath(std::string_view name) const;
std::string getAttrPathStr() const;
std::string getAttrPathStr(Symbol name) const;
std::string getAttrPathStr(std::string_view name) const;
Suggestions getSuggestionsForAttr(Symbol name);
Suggestions getSuggestionsForAttr(const std::string & name);
std::shared_ptr<AttrCursor> maybeGetAttr(Symbol name);
std::shared_ptr<AttrCursor> maybeGetAttr(const std::string & name);
std::shared_ptr<AttrCursor> maybeGetAttr(std::string_view name);
ref<AttrCursor> getAttr(Symbol name);
ref<AttrCursor> getAttr(std::string_view name);
ref<AttrCursor> getAttr(const std::string & name);
/**
* Get an attribute along a chain of attrsets. Note that this does
* not auto-call functors or functions.
*/
OrSuggestions<ref<AttrCursor>> findAlongAttrPath(const std::vector<Symbol> & attrPath);
OrSuggestions<ref<AttrCursor>> findAlongAttrPath(const Strings & attrPath);
std::string getString();
@ -145,7 +142,7 @@ public:
std::vector<std::string> getListOfStrings();
std::vector<Symbol> getAttrs();
std::vector<std::string> getAttrs();
bool isDerivation();

View file

@ -228,7 +228,6 @@ StaticSymbols::StaticSymbols(SymbolTable & symbols)
, recurseForDerivations(symbols.create("recurseForDerivations"))
, description(symbols.create("description"))
, self(symbols.create("self"))
, epsilon(symbols.create(""))
, startSet(symbols.create("startSet"))
, operator_(symbols.create("operator"))
, key(symbols.create("key"))

View file

@ -210,7 +210,7 @@ struct StaticSymbols
ignoreNulls, file, line, column, functor, toString, right, wrong, structuredAttrs,
allowedReferences, allowedRequisites, disallowedReferences, disallowedRequisites, maxSize,
maxClosureSize, builder, args, contentAddressed, impure, outputHash, outputHashAlgo,
outputHashMode, recurseForDerivations, description, self, epsilon, startSet, operator_, key,
outputHashMode, recurseForDerivations, description, self, startSet, operator_, key,
path, prefix, outputSpecified;
const Expr::AstSymbols exprSymbols;

View file

@ -97,15 +97,6 @@ public:
return Symbol(idx + 1);
}
std::vector<SymbolStr> resolve(const std::vector<Symbol> & symbols) const
{
std::vector<SymbolStr> result;
result.reserve(symbols.size());
for (auto sym : symbols)
result.push_back((*this)[sym]);
return result;
}
SymbolStr operator[](Symbol s) const
{
if (s.id == 0 || s.id > store.size())

View file

@ -59,7 +59,7 @@ UnresolvedApp InstallableValue::toApp()
auto type = cursor->getAttr("type")->getString();
std::string expected = !attrPath.empty() &&
(state->symbols[attrPath[0]] == "apps" || state->symbols[attrPath[0]] == "defaultApp")
(attrPath[0] == "apps" || attrPath[0] == "defaultApp")
? "app" : "derivation";
if (type != expected)
throw Error("attribute '%s' should have type '%s'", cursor->getAttrPathStr(), expected);
@ -99,11 +99,11 @@ UnresolvedApp InstallableValue::toApp()
else if (type == "derivation") {
auto drvPath = cursor->forceDerivation();
auto outPath = cursor->getAttr(state->s.outPath)->getString();
auto outputName = cursor->getAttr(state->s.outputName)->getString();
auto name = cursor->getAttr(state->s.name)->getString();
auto outPath = cursor->getAttr("outPath")->getString();
auto outputName = cursor->getAttr("outputName")->getString();
auto name = cursor->getAttr("name")->getString();
auto aPname = cursor->maybeGetAttr("pname");
auto aMeta = cursor->maybeGetAttr(state->s.meta);
auto aMeta = cursor->maybeGetAttr("meta");
auto aMainProgram = aMeta ? aMeta->maybeGetAttr("mainProgram") : nullptr;
auto mainProgram =
aMainProgram

View file

@ -1136,8 +1136,8 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
std::function<bool(
eval_cache::AttrCursor & visitor,
const std::vector<Symbol> &attrPath,
const Symbol &attr)> hasContent;
std::vector<std::string> attrPath,
const std::string &attr)> hasContent;
// For frameworks it's important that structures are as lazy as possible
// to prevent infinite recursions, performance issues and errors that
@ -1147,39 +1147,36 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
// so we omit them.
hasContent = [&](
eval_cache::AttrCursor & visitor,
const std::vector<Symbol> &attrPath,
const Symbol &attr) -> bool
std::vector<std::string> attrPath,
const std::string &attr) -> bool
{
auto attrPath2(attrPath);
attrPath2.push_back(attr);
auto attrPathS = state->symbols.resolve(attrPath2);
const auto & attrName = state->symbols[attr];
attrPath.push_back(attr);
auto visitor2 = visitor.getAttr(attrName);
auto visitor2 = visitor.getAttr(attr);
try {
if ((attrPathS[0] == "apps"
|| attrPathS[0] == "checks"
|| attrPathS[0] == "devShells"
|| attrPathS[0] == "legacyPackages"
|| attrPathS[0] == "packages")
&& (attrPathS.size() == 1 || attrPathS.size() == 2)) {
if ((attrPath[0] == "apps"
|| attrPath[0] == "checks"
|| attrPath[0] == "devShells"
|| attrPath[0] == "legacyPackages"
|| attrPath[0] == "packages")
&& (attrPath.size() == 1 || attrPath.size() == 2)) {
for (const auto &subAttr : visitor2->getAttrs()) {
if (hasContent(*visitor2, attrPath2, subAttr)) {
if (hasContent(*visitor2, attrPath, subAttr)) {
return true;
}
}
return false;
}
if ((attrPathS.size() == 1)
&& (attrPathS[0] == "formatter"
|| attrPathS[0] == "nixosConfigurations"
|| attrPathS[0] == "nixosModules"
|| attrPathS[0] == "overlays"
if ((attrPath.size() == 1)
&& (attrPath[0] == "formatter"
|| attrPath[0] == "nixosConfigurations"
|| attrPath[0] == "nixosModules"
|| attrPath[0] == "overlays"
)) {
for (const auto &subAttr : visitor2->getAttrs()) {
if (hasContent(*visitor2, attrPath2, subAttr)) {
if (hasContent(*visitor2, attrPath, subAttr)) {
return true;
}
}
@ -1198,54 +1195,51 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
std::function<nlohmann::json(
eval_cache::AttrCursor & visitor,
const std::vector<Symbol> & attrPath,
const std::vector<std::string> & attrPath,
const std::string & headerPrefix,
const std::string & nextPrefix)> visit;
visit = [&](
eval_cache::AttrCursor & visitor,
const std::vector<Symbol> & attrPath,
const std::vector<std::string> & attrPath,
const std::string & headerPrefix,
const std::string & nextPrefix)
-> nlohmann::json
{
auto j = nlohmann::json::object();
auto attrPathS = state->symbols.resolve(attrPath);
Activity act(*logger, lvlInfo, actUnknown,
fmt("evaluating '%s'", concatStringsSep(".", attrPathS)));
fmt("evaluating '%s'", concatStringsSep(".", attrPath)));
try {
auto recurse = [&]()
{
if (!json)
logger->cout("%s", headerPrefix);
std::vector<Symbol> attrs;
std::vector<std::string> attrs;
for (const auto &attr : visitor.getAttrs()) {
if (hasContent(visitor, attrPath, attr))
attrs.push_back(attr);
}
for (const auto & [i, attr] : enumerate(attrs)) {
const auto & attrName = state->symbols[attr];
bool last = i + 1 == attrs.size();
auto visitor2 = visitor.getAttr(attrName);
auto visitor2 = visitor.getAttr(attr);
auto attrPath2(attrPath);
attrPath2.push_back(attr);
auto j2 = visit(*visitor2, attrPath2,
fmt(ANSI_GREEN "%s%s" ANSI_NORMAL ANSI_BOLD "%s" ANSI_NORMAL, nextPrefix, last ? treeLast : treeConn, attrName),
fmt(ANSI_GREEN "%s%s" ANSI_NORMAL ANSI_BOLD "%s" ANSI_NORMAL, nextPrefix, last ? treeLast : treeConn, attr),
nextPrefix + (last ? treeNull : treeLine));
if (json) j.emplace(attrName, std::move(j2));
if (json) j.emplace(attr, std::move(j2));
}
};
auto showDerivation = [&]()
{
auto name = visitor.getAttr(state->s.name)->getString();
auto name = visitor.getAttr("name")->getString();
std::optional<std::string> description;
if (auto aMeta = visitor.maybeGetAttr(state->s.meta)) {
if (auto aDescription = aMeta->maybeGetAttr(state->s.description))
if (auto aMeta = visitor.maybeGetAttr("meta")) {
if (auto aDescription = aMeta->maybeGetAttr("description"))
description = aDescription->getString();
}
@ -1256,10 +1250,10 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
j.emplace("description", *description);
} else {
auto type =
attrPath.size() == 2 && attrPathS[0] == "devShell" ? "development environment" :
attrPath.size() >= 2 && attrPathS[0] == "devShells" ? "development environment" :
attrPath.size() == 3 && attrPathS[0] == "checks" ? "derivation" :
attrPath.size() >= 1 && attrPathS[0] == "hydraJobs" ? "derivation" :
attrPath.size() == 2 && attrPath[0] == "devShell" ? "development environment" :
attrPath.size() >= 2 && attrPath[0] == "devShells" ? "development environment" :
attrPath.size() == 3 && attrPath[0] == "checks" ? "derivation" :
attrPath.size() >= 1 && attrPath[0] == "hydraJobs" ? "derivation" :
"package";
std::string output = fmt("%s: %s '%s'", headerPrefix, type, name);
@ -1300,34 +1294,34 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
if (attrPath.size() == 0
|| (attrPath.size() == 1 && (
attrPathS[0] == "defaultPackage"
|| attrPathS[0] == "devShell"
|| attrPathS[0] == "formatter"
|| attrPathS[0] == "nixosConfigurations"
|| attrPathS[0] == "nixosModules"
|| attrPathS[0] == "defaultApp"
|| attrPathS[0] == "templates"
|| attrPathS[0] == "overlays"))
attrPath[0] == "defaultPackage"
|| attrPath[0] == "devShell"
|| attrPath[0] == "formatter"
|| attrPath[0] == "nixosConfigurations"
|| attrPath[0] == "nixosModules"
|| attrPath[0] == "defaultApp"
|| attrPath[0] == "templates"
|| attrPath[0] == "overlays"))
|| ((attrPath.size() == 1 || attrPath.size() == 2)
&& (attrPathS[0] == "checks"
|| attrPathS[0] == "packages"
|| attrPathS[0] == "devShells"
|| attrPathS[0] == "apps"))
&& (attrPath[0] == "checks"
|| attrPath[0] == "packages"
|| attrPath[0] == "devShells"
|| attrPath[0] == "apps"))
)
{
recurse();
}
else if (
(attrPath.size() == 2 && (attrPathS[0] == "defaultPackage" || attrPathS[0] == "devShell" || attrPathS[0] == "formatter"))
|| (attrPath.size() == 3 && (attrPathS[0] == "checks" || attrPathS[0] == "packages" || attrPathS[0] == "devShells"))
(attrPath.size() == 2 && (attrPath[0] == "defaultPackage" || attrPath[0] == "devShell" || attrPath[0] == "formatter"))
|| (attrPath.size() == 3 && (attrPath[0] == "checks" || attrPath[0] == "packages" || attrPath[0] == "devShells"))
)
{
if (!showAllSystems && std::string(attrPathS[1]) != localSystem) {
if (!showAllSystems && attrPath[1] != localSystem) {
if (!json)
logger->cout(fmt("%s " ANSI_WARNING "omitted" ANSI_NORMAL " (use '--all-systems' to show)", headerPrefix));
else {
logger->warn(fmt("%s omitted (use '--all-systems' to show)", concatStringsSep(".", attrPathS)));
logger->warn(fmt("%s omitted (use '--all-systems' to show)", concatStringsSep(".", attrPath)));
}
} else {
if (visitor.isDerivation())
@ -1337,27 +1331,27 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
}
}
else if (attrPath.size() > 0 && attrPathS[0] == "hydraJobs") {
else if (attrPath.size() > 0 && attrPath[0] == "hydraJobs") {
if (visitor.isDerivation())
showDerivation();
else
recurse();
}
else if (attrPath.size() > 0 && attrPathS[0] == "legacyPackages") {
else if (attrPath.size() > 0 && attrPath[0] == "legacyPackages") {
if (attrPath.size() == 1)
recurse();
else if (!showLegacy){
if (!json)
logger->cout(fmt("%s " ANSI_WARNING "omitted" ANSI_NORMAL " (use '--legacy' to show)", headerPrefix));
else {
logger->warn(fmt("%s omitted (use '--legacy' to show)", concatStringsSep(".", attrPathS)));
logger->warn(fmt("%s omitted (use '--legacy' to show)", concatStringsSep(".", attrPath)));
}
} else if (!showAllSystems && std::string(attrPathS[1]) != localSystem) {
} else if (!showAllSystems && attrPath[1] != localSystem) {
if (!json)
logger->cout(fmt("%s " ANSI_WARNING "omitted" ANSI_NORMAL " (use '--all-systems' to show)", headerPrefix));
else {
logger->warn(fmt("%s omitted (use '--all-systems' to show)", concatStringsSep(".", attrPathS)));
logger->warn(fmt("%s omitted (use '--all-systems' to show)", concatStringsSep(".", attrPath)));
}
} else {
if (visitor.isDerivation())
@ -1369,8 +1363,8 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
}
else if (
(attrPath.size() == 2 && attrPathS[0] == "defaultApp") ||
(attrPath.size() == 3 && attrPathS[0] == "apps"))
(attrPath.size() == 2 && attrPath[0] == "defaultApp") ||
(attrPath.size() == 3 && attrPath[0] == "apps"))
{
auto aType = visitor.maybeGetAttr("type");
if (!aType || aType->getString() != "app")
@ -1383,8 +1377,8 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
}
else if (
(attrPath.size() == 1 && attrPathS[0] == "defaultTemplate") ||
(attrPath.size() == 2 && attrPathS[0] == "templates"))
(attrPath.size() == 1 && attrPath[0] == "defaultTemplate") ||
(attrPath.size() == 2 && attrPath[0] == "templates"))
{
auto description = visitor.getAttr("description")->getString();
if (json) {
@ -1397,11 +1391,11 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
else {
auto [type, description] =
(attrPath.size() == 1 && attrPathS[0] == "overlay")
|| (attrPath.size() == 2 && attrPathS[0] == "overlays") ? std::make_pair("nixpkgs-overlay", "Nixpkgs overlay") :
attrPath.size() == 2 && attrPathS[0] == "nixosConfigurations" ? std::make_pair("nixos-configuration", "NixOS configuration") :
(attrPath.size() == 1 && attrPathS[0] == "nixosModule")
|| (attrPath.size() == 2 && attrPathS[0] == "nixosModules") ? std::make_pair("nixos-module", "NixOS module") :
(attrPath.size() == 1 && attrPath[0] == "overlay")
|| (attrPath.size() == 2 && attrPath[0] == "overlays") ? std::make_pair("nixpkgs-overlay", "Nixpkgs overlay") :
attrPath.size() == 2 && attrPath[0] == "nixosConfigurations" ? std::make_pair("nixos-configuration", "NixOS configuration") :
(attrPath.size() == 1 && attrPath[0] == "nixosModule")
|| (attrPath.size() == 2 && attrPath[0] == "nixosModules") ? std::make_pair("nixos-module", "NixOS module") :
std::make_pair("unknown", "unknown");
if (json) {
j.emplace("type", type);
@ -1410,7 +1404,7 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
}
}
} catch (EvalError & e) {
if (!(attrPath.size() > 0 && attrPathS[0] == "legacyPackages"))
if (!(attrPath.size() > 0 && attrPath[0] == "legacyPackages"))
throw;
}

View file

@ -91,33 +91,31 @@ struct CmdSearch : InstallableCommand, MixJSON
uint64_t results = 0;
std::function<void(eval_cache::AttrCursor & cursor, const std::vector<Symbol> & attrPath, bool initialRecurse)> visit;
std::function<void(eval_cache::AttrCursor & cursor, const std::vector<std::string> & attrPath, bool initialRecurse)> visit;
visit = [&](eval_cache::AttrCursor & cursor, const std::vector<Symbol> & attrPath, bool initialRecurse)
visit = [&](eval_cache::AttrCursor & cursor, const std::vector<std::string> & attrPath, bool initialRecurse)
{
auto attrPathS = state->symbols.resolve(attrPath);
Activity act(*logger, lvlInfo, actUnknown,
fmt("evaluating '%s'", concatStringsSep(".", attrPathS)));
fmt("evaluating '%s'", concatStringsSep(".", attrPath)));
try {
auto recurse = [&]()
{
for (const auto & attr : cursor.getAttrs()) {
auto cursor2 = cursor.getAttr(state->symbols[attr]);
auto cursor2 = cursor.getAttr(attr);
auto attrPath2(attrPath);
attrPath2.push_back(attr);
attrPath2.emplace_back(attr);
visit(*cursor2, attrPath2, false);
}
};
if (cursor.isDerivation()) {
DrvName name(cursor.getAttr(state->s.name)->getString());
DrvName name(cursor.getAttr("name")->getString());
auto aMeta = cursor.maybeGetAttr(state->s.meta);
auto aDescription = aMeta ? aMeta->maybeGetAttr(state->s.description) : nullptr;
auto aMeta = cursor.maybeGetAttr("meta");
auto aDescription = aMeta ? aMeta->maybeGetAttr("description") : nullptr;
auto description = aDescription ? aDescription->getString() : "";
std::replace(description.begin(), description.end(), '\n', ' ');
auto attrPath2 = concatStringsSep(".", attrPathS);
auto attrPath2 = concatStringsSep(".", attrPath);
std::vector<std::smatch> attrPathMatches;
std::vector<std::smatch> descriptionMatches;
@ -175,21 +173,21 @@ struct CmdSearch : InstallableCommand, MixJSON
else if (
attrPath.size() == 0
|| (attrPathS[0] == "legacyPackages" && attrPath.size() <= 2)
|| (attrPathS[0] == "packages" && attrPath.size() <= 2))
|| (attrPath[0] == "legacyPackages" && attrPath.size() <= 2)
|| (attrPath[0] == "packages" && attrPath.size() <= 2))
recurse();
else if (initialRecurse)
recurse();
else if (attrPathS[0] == "legacyPackages" && attrPath.size() > 2) {
auto attr = cursor.maybeGetAttr(state->s.recurseForDerivations);
else if (attrPath[0] == "legacyPackages" && attrPath.size() > 2) {
auto attr = cursor.maybeGetAttr("recurseForDerivations");
if (attr && attr->getBool())
recurse();
}
} catch (EvalError & e) {
if (!(attrPath.size() > 0 && attrPathS[0] == "legacyPackages"))
if (!(attrPath.size() > 0 && attrPath[0] == "legacyPackages"))
throw;
}
};