From 4af8dbf8964924dc3d2ec2bbfa159dae288b29fc Mon Sep 17 00:00:00 2001 From: Chuck Date: Fri, 6 Sep 2019 09:45:05 -0700 Subject: [PATCH] Reformat for 4-space indentation Specifically, with clang-format --style='{ IndentWidth: 4, BreakBeforeBraces: Mozilla, ColumnLimit: 120, PointerAlignment: Middle }' which was the clang-format invocation that produced the fewest diffs on the nix source out of ~20 that I tried. --- .../tools/nixos-option/libnix-copy-paste.cc | 104 +- .../tools/nixos-option/libnix-copy-paste.hh | 6 +- .../tools/nixos-option/nixos-option.cc | 953 +++++++++--------- 3 files changed, 534 insertions(+), 529 deletions(-) diff --git a/nixos/modules/installer/tools/nixos-option/libnix-copy-paste.cc b/nixos/modules/installer/tools/nixos-option/libnix-copy-paste.cc index 81de5ff8523..875c07da639 100644 --- a/nixos/modules/installer/tools/nixos-option/libnix-copy-paste.cc +++ b/nixos/modules/installer/tools/nixos-option/libnix-copy-paste.cc @@ -21,61 +21,63 @@ using nix::Strings; using std::string; // From nix/src/libexpr/attr-path.cc -Strings parseAttrPath(const string &s) { - Strings res; - string cur; - string::const_iterator i = s.begin(); - while (i != s.end()) { - if (*i == '.') { - res.push_back(cur); - cur.clear(); - } else if (*i == '"') { - ++i; - while (1) { - if (i == s.end()) - throw Error(format("missing closing quote in selection path '%1%'") % - s); - if (*i == '"') - break; - cur.push_back(*i++); - } - } else - cur.push_back(*i); - ++i; - } - if (!cur.empty()) - res.push_back(cur); - return res; +Strings parseAttrPath(const string & s) +{ + Strings res; + string cur; + string::const_iterator i = s.begin(); + while (i != s.end()) { + if (*i == '.') { + res.push_back(cur); + cur.clear(); + } else if (*i == '"') { + ++i; + while (1) { + if (i == s.end()) + throw Error(format("missing closing quote in selection path '%1%'") % s); + if (*i == '"') + break; + cur.push_back(*i++); + } + } else + cur.push_back(*i); + ++i; + } + if (!cur.empty()) + res.push_back(cur); + return res; } // From nix/src/nix/repl.cc -bool isVarName(const string &s) { - if (s.size() == 0) - return false; - char c = s[0]; - if ((c >= '0' && c <= '9') || c == '-' || c == '\'') - return false; - for (auto &i : s) - if (!((i >= 'a' && i <= 'z') || (i >= 'A' && i <= 'Z') || - (i >= '0' && i <= '9') || i == '_' || i == '-' || i == '\'')) - return false; - return true; +bool isVarName(const string & s) +{ + if (s.size() == 0) + return false; + char c = s[0]; + if ((c >= '0' && c <= '9') || c == '-' || c == '\'') + return false; + for (auto & i : s) + if (!((i >= 'a' && i <= 'z') || (i >= 'A' && i <= 'Z') || (i >= '0' && i <= '9') || i == '_' || i == '-' || + i == '\'')) + return false; + return true; } // From nix/src/nix/repl.cc -std::ostream &printStringValue(std::ostream &str, const char *string) { - str << "\""; - for (const char *i = string; *i; i++) - if (*i == '\"' || *i == '\\') - str << "\\" << *i; - else if (*i == '\n') - str << "\\n"; - else if (*i == '\r') - str << "\\r"; - else if (*i == '\t') - str << "\\t"; - else - str << *i; - str << "\""; - return str; +std::ostream & printStringValue(std::ostream & str, const char * string) +{ + str << "\""; + for (const char * i = string; *i; i++) + if (*i == '\"' || *i == '\\') + str << "\\" << *i; + else if (*i == '\n') + str << "\\n"; + else if (*i == '\r') + str << "\\r"; + else if (*i == '\t') + str << "\\t"; + else + str << *i; + str << "\""; + return str; } diff --git a/nixos/modules/installer/tools/nixos-option/libnix-copy-paste.hh b/nixos/modules/installer/tools/nixos-option/libnix-copy-paste.hh index 225e8b1b87e..2274e9a0f85 100644 --- a/nixos/modules/installer/tools/nixos-option/libnix-copy-paste.hh +++ b/nixos/modules/installer/tools/nixos-option/libnix-copy-paste.hh @@ -4,6 +4,6 @@ #include #include -nix::Strings parseAttrPath(const std::string &s); -bool isVarName(const std::string &s); -std::ostream &printStringValue(std::ostream &str, const char *string); +nix::Strings parseAttrPath(const std::string & s); +bool isVarName(const std::string & s); +std::ostream & printStringValue(std::ostream & str, const char * string); diff --git a/nixos/modules/installer/tools/nixos-option/nixos-option.cc b/nixos/modules/installer/tools/nixos-option/nixos-option.cc index 49da3ce6874..fe44a347aef 100644 --- a/nixos/modules/installer/tools/nixos-option/nixos-option.cc +++ b/nixos/modules/installer/tools/nixos-option/nixos-option.cc @@ -42,166 +42,170 @@ using nix::UsageError; using nix::Value; // An ostream wrapper to handle nested indentation -class Out { -public: - class Separator {}; - const static Separator sep; - enum LinePolicy { ONE_LINE, MULTI_LINE }; - explicit Out(std::ostream &ostream) - : ostream(ostream), policy(ONE_LINE), write_since_sep(true) {} - Out(Out &o, std::string const &start, std::string const &end, - LinePolicy policy); - Out(Out &o, std::string const &start, std::string const &end, int count) - : Out(o, start, end, count < 2 ? ONE_LINE : MULTI_LINE) {} - Out(Out const &) = delete; - Out(Out &&) = default; - Out &operator=(Out const &) = delete; - Out &operator=(Out &&) = delete; - ~Out() { ostream << end; } +class Out +{ + public: + class Separator + {}; + const static Separator sep; + enum LinePolicy + { + ONE_LINE, + MULTI_LINE + }; + explicit Out(std::ostream & ostream) : ostream(ostream), policy(ONE_LINE), write_since_sep(true) {} + Out(Out & o, std::string const & start, std::string const & end, LinePolicy policy); + Out(Out & o, std::string const & start, std::string const & end, int count) + : Out(o, start, end, count < 2 ? ONE_LINE : MULTI_LINE) + {} + Out(Out const &) = delete; + Out(Out &&) = default; + Out & operator=(Out const &) = delete; + Out & operator=(Out &&) = delete; + ~Out() { ostream << end; } -private: - std::ostream &ostream; - std::string indentation; - std::string end; - LinePolicy policy; - bool write_since_sep; - template friend Out &operator<<(Out &o, T thing); + private: + std::ostream & ostream; + std::string indentation; + std::string end; + LinePolicy policy; + bool write_since_sep; + template friend Out & operator<<(Out & o, T thing); }; -template Out &operator<<(Out &o, T thing) { - if (!o.write_since_sep && o.policy == Out::MULTI_LINE) { - o.ostream << o.indentation; - } - o.write_since_sep = true; - o.ostream << thing; - return o; +template Out & operator<<(Out & o, T thing) +{ + if (!o.write_since_sep && o.policy == Out::MULTI_LINE) { + o.ostream << o.indentation; + } + o.write_since_sep = true; + o.ostream << thing; + return o; } -template <> -Out &operator<<(Out &o, Out::Separator /* thing */) { - o.ostream << (o.policy == Out::ONE_LINE ? " " : "\n"); - o.write_since_sep = false; - return o; +template <> Out & operator<<(Out & o, Out::Separator /* thing */) +{ + o.ostream << (o.policy == Out::ONE_LINE ? " " : "\n"); + o.write_since_sep = false; + return o; } -Out::Out(Out &o, std::string const &start, std::string const &end, - LinePolicy policy) - : ostream(o.ostream), - indentation(policy == ONE_LINE ? o.indentation : o.indentation + " "), - end(policy == ONE_LINE ? end : o.indentation + end), policy(policy), - write_since_sep(true) { - o << start; - *this << Out::sep; +Out::Out(Out & o, std::string const & start, std::string const & end, LinePolicy policy) + : ostream(o.ostream), indentation(policy == ONE_LINE ? o.indentation : o.indentation + " "), + end(policy == ONE_LINE ? end : o.indentation + end), policy(policy), write_since_sep(true) +{ + o << start; + *this << Out::sep; } // Stuff needed for evaluation -struct Context { - Context(EvalState *state, Bindings *autoArgs, Value options_root, - Value config_root) - : state(state), autoArgs(autoArgs), options_root(options_root), - config_root(config_root), - underscore_type(state->symbols.create("_type")) {} - EvalState *state; - Bindings *autoArgs; - Value options_root; - Value config_root; - Symbol underscore_type; +struct Context +{ + Context(EvalState * state, Bindings * autoArgs, Value options_root, Value config_root) + : state(state), autoArgs(autoArgs), options_root(options_root), config_root(config_root), + underscore_type(state->symbols.create("_type")) + {} + EvalState * state; + Bindings * autoArgs; + Value options_root; + Value config_root; + Symbol underscore_type; }; -Value evaluateValue(Context *ctx, Value *v) { - ctx->state->forceValue(*v); - if (ctx->autoArgs->empty()) { - return *v; - } - Value called{}; - ctx->state->autoCallFunction(*ctx->autoArgs, *v, called); - return called; +Value evaluateValue(Context * ctx, Value * v) +{ + ctx->state->forceValue(*v); + if (ctx->autoArgs->empty()) { + return *v; + } + Value called{}; + ctx->state->autoCallFunction(*ctx->autoArgs, *v, called); + return called; } -bool isOption(Context *ctx, Value const &v) { - if (v.type != tAttrs) { - return false; - } - auto const &actual_type = v.attrs->find(ctx->underscore_type); - if (actual_type == v.attrs->end()) { - return false; - } - try { - Value evaluated_type = evaluateValue(ctx, actual_type->value); - if (evaluated_type.type != tString) { - return false; +bool isOption(Context * ctx, Value const & v) +{ + if (v.type != tAttrs) { + return false; + } + auto const & actual_type = v.attrs->find(ctx->underscore_type); + if (actual_type == v.attrs->end()) { + return false; + } + try { + Value evaluated_type = evaluateValue(ctx, actual_type->value); + if (evaluated_type.type != tString) { + return false; + } + return evaluated_type.string.s == static_cast("option"); + } catch (Error &) { + return false; } - return evaluated_type.string.s == static_cast("option"); - } catch (Error &) { - return false; - } } // Add quotes to a component of a path. // These are needed for paths like: // fileSystems."/".fsType // systemd.units."dbus.service".text -std::string quoteAttribute(std::string const &attribute) { - if (isVarName(attribute)) { - return attribute; - } - std::ostringstream buf; - printStringValue(buf, attribute.c_str()); - return buf.str(); -} - -std::string const appendPath(std::string const &prefix, - std::string const &suffix) { - if (prefix.empty()) { - return quoteAttribute(suffix); - } - return prefix + "." + quoteAttribute(suffix); -} - -bool forbiddenRecursionName(std::string name) { - return (!name.empty() && name[0] == '_') || name == "haskellPackages"; -} - -void recurse(const std::function)> &f, - Context *ctx, Value v, std::string const &path) { - std::variant evaluated; - try { - evaluated = evaluateValue(ctx, &v); - } catch (Error &e) { - evaluated = e; - } - if (!f(path, evaluated)) { - return; - } - if (std::holds_alternative(evaluated)) { - return; - } - Value const &evaluated_value = std::get(evaluated); - if (evaluated_value.type != tAttrs) { - return; - } - for (auto const &child : evaluated_value.attrs->lexicographicOrder()) { - if (forbiddenRecursionName(child->name)) { - continue; +std::string quoteAttribute(std::string const & attribute) +{ + if (isVarName(attribute)) { + return attribute; + } + std::ostringstream buf; + printStringValue(buf, attribute.c_str()); + return buf.str(); +} + +std::string const appendPath(std::string const & prefix, std::string const & suffix) +{ + if (prefix.empty()) { + return quoteAttribute(suffix); + } + return prefix + "." + quoteAttribute(suffix); +} + +bool forbiddenRecursionName(std::string name) { return (!name.empty() && name[0] == '_') || name == "haskellPackages"; } + +void recurse(const std::function)> & f, Context * ctx, + Value v, std::string const & path) +{ + std::variant evaluated; + try { + evaluated = evaluateValue(ctx, &v); + } catch (Error & e) { + evaluated = e; + } + if (!f(path, evaluated)) { + return; + } + if (std::holds_alternative(evaluated)) { + return; + } + Value const & evaluated_value = std::get(evaluated); + if (evaluated_value.type != tAttrs) { + return; + } + for (auto const & child : evaluated_value.attrs->lexicographicOrder()) { + if (forbiddenRecursionName(child->name)) { + continue; + } + recurse(f, ctx, *child->value, appendPath(path, child->name)); } - recurse(f, ctx, *child->value, appendPath(path, child->name)); - } } // Calls f on all the option names -void mapOptions(const std::function &f, - Context *ctx, Value root) { - recurse( - [f, ctx](std::string const &path, std::variant v) { - bool isOpt = std::holds_alternative(v) || - isOption(ctx, std::get(v)); - if (isOpt) { - f(path); - } - return !isOpt; - }, - ctx, root, ""); +void mapOptions(const std::function & f, Context * ctx, Value root) +{ + recurse( + [f, ctx](std::string const & path, std::variant v) { + bool isOpt = std::holds_alternative(v) || isOption(ctx, std::get(v)); + if (isOpt) { + f(path); + } + return !isOpt; + }, + ctx, root, ""); } // Calls f on all the config values inside one option. @@ -225,364 +229,363 @@ void mapOptions(const std::function &f, // users.users.nixbld1 = ... .. ... // ... // users.users.systemd-timesync = ... .. ... -void mapConfigValuesInOption( - const std::function v)> &f, - std::string const &path, Context *ctx) { - Value *option; - try { - option = - findAlongAttrPath(*ctx->state, path, *ctx->autoArgs, ctx->config_root); - } catch (Error &e) { - f(path, e); - return; - } - recurse( - [f, ctx](std::string const &path, std::variant v) { - bool leaf = std::holds_alternative(v) || - std::get(v).type != tAttrs || - ctx->state->isDerivation(std::get(v)); - if (!leaf) { - return true; // Keep digging +void mapConfigValuesInOption(const std::function v)> & f, + std::string const & path, Context * ctx) +{ + Value * option; + try { + option = findAlongAttrPath(*ctx->state, path, *ctx->autoArgs, ctx->config_root); + } catch (Error & e) { + f(path, e); + return; + } + recurse( + [f, ctx](std::string const & path, std::variant v) { + bool leaf = std::holds_alternative(v) || std::get(v).type != tAttrs || + ctx->state->isDerivation(std::get(v)); + if (!leaf) { + return true; // Keep digging + } + f(path, v); + return false; + }, + ctx, *option, path); +} + +std::string describeError(Error const & e) { return "«error: " + e.msg() + "»"; } + +void describeDerivation(Context * ctx, Out & out, Value v) +{ + // Copy-pasted from nix/src/nix/repl.cc :( + Bindings::iterator i = v.attrs->find(ctx->state->sDrvPath); + PathSet pathset; + try { + Path drvPath = i != v.attrs->end() ? ctx->state->coerceToPath(*i->pos, *i->value, pathset) : "???"; + out << "«derivation " << drvPath << "»"; + } catch (Error & e) { + out << describeError(e); + } +} + +Value parseAndEval(EvalState * state, std::string const & expression, std::string const & path) +{ + Value v{}; + state->eval(state->parseExprFromString(expression, absPath(path)), v); + return v; +} + +void printValue(Context * ctx, Out & out, std::variant maybe_value, std::string const & path); + +void printUnsortedList(Context * ctx, Out & out, Value & v) +{ + Out list_out(out, "[", "]", v.listSize()); + for (unsigned int n = 0; n < v.listSize(); ++n) { + printValue(ctx, list_out, *v.listElems()[n], ""); + list_out << Out::sep; + } +} + +void printSortedList(Context * ctx, Out & out, Value & v) +{ + std::vector results; + for (unsigned int n = 0; n < v.listSize(); ++n) { + std::ostringstream buf; + Out buf_out(buf); + printValue(ctx, buf_out, *v.listElems()[n], ""); + results.push_back(buf.str()); + } + std::sort(results.begin(), results.end()); + Out list_out(out, "[", "]", v.listSize()); + for (auto const & v : results) { + list_out << v << Out::sep; + } +} + +bool shouldSort(Context * ctx, Value & v) +{ + // Some lists should clearly be printed in sorted order, like + // environment.systemPackages. Some clearly should not, like + // services.xserver.multitouch.buttonsMap. As a conservative heuristic, sort + // lists of derivations. + return v.listSize() > 0 && ctx->state->isDerivation(*v.listElems()[0]); +} + +void printList(Context * ctx, Out & out, Value & v) +{ + if (shouldSort(ctx, v)) { + printSortedList(ctx, out, v); + } else { + printUnsortedList(ctx, out, v); + } +} + +void printAttrs(Context * ctx, Out & out, Value & v, std::string const & path) +{ + Out attrs_out(out, "{", "}", v.attrs->size()); + for (const auto & a : v.attrs->lexicographicOrder()) { + std::string name = a->name; + attrs_out << name << " = "; + printValue(ctx, attrs_out, *a->value, appendPath(path, name)); + attrs_out << ";" << Out::sep; + } +} + +void multiLineStringEscape(Out & out, std::string const & s) +{ + int i; + for (i = 1; i < s.size(); i++) { + if (s[i - 1] == '$' && s[i] == '{') { + out << "''${"; + i++; + } else if (s[i - 1] == '\'' && s[i] == '\'') { + out << "'''"; + i++; + } else { + out << s[i - 1]; } - f(path, v); - return false; - }, - ctx, *option, path); -} - -std::string describeError(Error const &e) { return "«error: " + e.msg() + "»"; } - -void describeDerivation(Context *ctx, Out &out, Value v) { - // Copy-pasted from nix/src/nix/repl.cc :( - Bindings::iterator i = v.attrs->find(ctx->state->sDrvPath); - PathSet pathset; - try { - Path drvPath = i != v.attrs->end() - ? ctx->state->coerceToPath(*i->pos, *i->value, pathset) - : "???"; - out << "«derivation " << drvPath << "»"; - } catch (Error &e) { - out << describeError(e); - } -} - -Value parseAndEval(EvalState *state, std::string const &expression, - std::string const &path) { - Value v{}; - state->eval(state->parseExprFromString(expression, absPath(path)), v); - return v; -} - -void printValue(Context *ctx, Out &out, std::variant maybe_value, - std::string const &path); - -void printUnsortedList(Context *ctx, Out &out, Value &v) { - Out list_out(out, "[", "]", v.listSize()); - for (unsigned int n = 0; n < v.listSize(); ++n) { - printValue(ctx, list_out, *v.listElems()[n], ""); - list_out << Out::sep; - } -} - -void printSortedList(Context *ctx, Out &out, Value &v) { - std::vector results; - for (unsigned int n = 0; n < v.listSize(); ++n) { - std::ostringstream buf; - Out buf_out(buf); - printValue(ctx, buf_out, *v.listElems()[n], ""); - results.push_back(buf.str()); - } - std::sort(results.begin(), results.end()); - Out list_out(out, "[", "]", v.listSize()); - for (auto const &v : results) { - list_out << v << Out::sep; - } -} - -bool shouldSort(Context *ctx, Value &v) { - // Some lists should clearly be printed in sorted order, like - // environment.systemPackages. Some clearly should not, like - // services.xserver.multitouch.buttonsMap. As a conservative heuristic, sort - // lists of derivations. - return v.listSize() > 0 && ctx->state->isDerivation(*v.listElems()[0]); -} - -void printList(Context *ctx, Out &out, Value &v) { - if (shouldSort(ctx, v)) { - printSortedList(ctx, out, v); - } else { - printUnsortedList(ctx, out, v); - } -} - -void printAttrs(Context *ctx, Out &out, Value &v, std::string const &path) { - Out attrs_out(out, "{", "}", v.attrs->size()); - for (const auto &a : v.attrs->lexicographicOrder()) { - std::string name = a->name; - attrs_out << name << " = "; - printValue(ctx, attrs_out, *a->value, appendPath(path, name)); - attrs_out << ";" << Out::sep; - } -} - -void multiLineStringEscape(Out &out, std::string const &s) { - int i; - for (i = 1; i < s.size(); i++) { - if (s[i - 1] == '$' && s[i] == '{') { - out << "''${"; - i++; - } else if (s[i - 1] == '\'' && s[i] == '\'') { - out << "'''"; - i++; - } else { - out << s[i - 1]; } - } - if (i == s.size()) { - out << s[i - 1]; - } -} - -void printMultiLineString(Out &out, Value const &v) { - std::string s = v.string.s; - Out str_out(out, "''", "''", Out::MULTI_LINE); - std::string::size_type begin = 0; - while (begin < s.size()) { - std::string::size_type end = s.find('\n', begin); - if (end == std::string::npos) { - multiLineStringEscape(str_out, s.substr(begin, s.size() - begin)); - break; + if (i == s.size()) { + out << s[i - 1]; } - multiLineStringEscape(str_out, s.substr(begin, end - begin)); - str_out << Out::sep; - begin = end + 1; - } } -void printValue(Context *ctx, Out &out, std::variant maybe_value, - std::string const &path) { - try { - if (std::holds_alternative(maybe_value)) { - throw Error{std::get(maybe_value)}; +void printMultiLineString(Out & out, Value const & v) +{ + std::string s = v.string.s; + Out str_out(out, "''", "''", Out::MULTI_LINE); + std::string::size_type begin = 0; + while (begin < s.size()) { + std::string::size_type end = s.find('\n', begin); + if (end == std::string::npos) { + multiLineStringEscape(str_out, s.substr(begin, s.size() - begin)); + break; + } + multiLineStringEscape(str_out, s.substr(begin, end - begin)); + str_out << Out::sep; + begin = end + 1; } - Value v = evaluateValue(ctx, &std::get(maybe_value)); - if (ctx->state->isDerivation(v)) { - describeDerivation(ctx, out, v); - } else if (v.isList()) { - printList(ctx, out, v); - } else if (v.type == tAttrs) { - printAttrs(ctx, out, v, path); - } else if (v.type == tString && - std::string(v.string.s).find('\n') != std::string::npos) { - printMultiLineString(out, v); - } else { - ctx->state->forceValueDeep(v); - out << v; +} + +void printValue(Context * ctx, Out & out, std::variant maybe_value, std::string const & path) +{ + try { + if (std::holds_alternative(maybe_value)) { + throw Error{std::get(maybe_value)}; + } + Value v = evaluateValue(ctx, &std::get(maybe_value)); + if (ctx->state->isDerivation(v)) { + describeDerivation(ctx, out, v); + } else if (v.isList()) { + printList(ctx, out, v); + } else if (v.type == tAttrs) { + printAttrs(ctx, out, v, path); + } else if (v.type == tString && std::string(v.string.s).find('\n') != std::string::npos) { + printMultiLineString(out, v); + } else { + ctx->state->forceValueDeep(v); + out << v; + } + } catch (Error & e) { + if (e.msg() == "The option `" + path + "' is used but not defined.") { + // 93% of errors are this, and just letting this message through would be + // misleading. These values may or may not actually be "used" in the + // config. The thing throwing the error message assumes that if anything + // ever looks at this value, it is a "use" of this value. But here in + // nixos-option, we are looking at this value only to print it. + // In order to avoid implying that this undefined value is actually + // referenced, eat the underlying error message and emit "«not defined»". + out << "«not defined»"; + } else { + out << describeError(e); + } } - } catch (Error &e) { - if (e.msg() == "The option `" + path + "' is used but not defined.") { - // 93% of errors are this, and just letting this message through would be - // misleading. These values may or may not actually be "used" in the - // config. The thing throwing the error message assumes that if anything - // ever looks at this value, it is a "use" of this value. But here in - // nixos-option, we are looking at this value only to print it. - // In order to avoid implying that this undefined value is actually - // referenced, eat the underlying error message and emit "«not defined»". - out << "«not defined»"; - } else { - out << describeError(e); +} + +void printConfigValue(Context * ctx, Out & out, std::string const & path, std::variant v) +{ + out << path << " = "; + printValue(ctx, out, std::move(v), path); + out << ";\n"; +} + +void printAll(Context * ctx, Out & out) +{ + mapOptions( + [ctx, &out](std::string const & option_path) { + mapConfigValuesInOption( + [ctx, &out](std::string const & config_path, std::variant v) { + printConfigValue(ctx, out, config_path, v); + }, + option_path, ctx); + }, + ctx, ctx->options_root); +} + +void printAttr(Context * ctx, Out & out, std::string const & path, Value * root) +{ + try { + printValue(ctx, out, *findAlongAttrPath(*ctx->state, path, *ctx->autoArgs, *root), path); + } catch (Error & e) { + out << describeError(e); } - } } -void printConfigValue(Context *ctx, Out &out, std::string const &path, - std::variant v) { - out << path << " = "; - printValue(ctx, out, std::move(v), path); - out << ";\n"; +void printOption(Context * ctx, Out & out, std::string const & path, Value * option) +{ + out << "Value:\n"; + printAttr(ctx, out, path, &ctx->config_root); + + out << "\n\nDefault:\n"; + printAttr(ctx, out, "default", option); + + out << "\n\nType:\n"; + printAttr(ctx, out, "type.description", option); + + out << "\n\nExample:\n"; + printAttr(ctx, out, "example", option); + + out << "\n\nDescription:\n"; + printAttr(ctx, out, "description", option); + + out << "\n\nDeclared by:\n"; + printAttr(ctx, out, "declarations", option); + + out << "\n\nDefined by:\n"; + printAttr(ctx, out, "files", option); + out << "\n"; } -void printAll(Context *ctx, Out &out) { - mapOptions( - [ctx, &out](std::string const &option_path) { - mapConfigValuesInOption( - [ctx, &out](std::string const &config_path, - std::variant v) { - printConfigValue(ctx, out, config_path, v); - }, - option_path, ctx); - }, - ctx, ctx->options_root); -} - -void printAttr(Context *ctx, Out &out, std::string const &path, Value *root) { - try { - printValue(ctx, out, - *findAlongAttrPath(*ctx->state, path, *ctx->autoArgs, *root), - path); - } catch (Error &e) { - out << describeError(e); - } -} - -void printOption(Context *ctx, Out &out, std::string const &path, - Value *option) { - out << "Value:\n"; - printAttr(ctx, out, path, &ctx->config_root); - - out << "\n\nDefault:\n"; - printAttr(ctx, out, "default", option); - - out << "\n\nType:\n"; - printAttr(ctx, out, "type.description", option); - - out << "\n\nExample:\n"; - printAttr(ctx, out, "example", option); - - out << "\n\nDescription:\n"; - printAttr(ctx, out, "description", option); - - out << "\n\nDeclared by:\n"; - printAttr(ctx, out, "declarations", option); - - out << "\n\nDefined by:\n"; - printAttr(ctx, out, "files", option); - out << "\n"; -} - -void printListing(Out &out, Value *v) { - // Print this header on stderr rather than stdout because the old shell script - // implementation did. I don't know why. - std::cerr << "This attribute set contains:\n"; - for (const auto &a : v->attrs->lexicographicOrder()) { - std::string name = a->name; - if (!name.empty() && name[0] != '_') { - out << name << "\n"; +void printListing(Out & out, Value * v) +{ + // Print this header on stderr rather than stdout because the old shell script + // implementation did. I don't know why. + std::cerr << "This attribute set contains:\n"; + for (const auto & a : v->attrs->lexicographicOrder()) { + std::string name = a->name; + if (!name.empty() && name[0] != '_') { + out << name << "\n"; + } } - } } // Carefully walk an option path, looking for sub-options when a path walks past // an option value. -Value findAlongOptionPath(Context *ctx, std::string const &path) { - Strings tokens = parseAttrPath(path); - Value v = ctx->options_root; - for (auto i = tokens.begin(); i != tokens.end(); i++) { - bool last_attribute = std::next(i) == tokens.end(); - auto const &attr = *i; - v = evaluateValue(ctx, &v); - if (attr.empty()) { - throw Error("empty attribute name in selection path '" + path + "'"); +Value findAlongOptionPath(Context * ctx, std::string const & path) +{ + Strings tokens = parseAttrPath(path); + Value v = ctx->options_root; + for (auto i = tokens.begin(); i != tokens.end(); i++) { + bool last_attribute = std::next(i) == tokens.end(); + auto const & attr = *i; + v = evaluateValue(ctx, &v); + if (attr.empty()) { + throw Error("empty attribute name in selection path '" + path + "'"); + } + if (isOption(ctx, v) && !last_attribute) { + Value getSubOptions = + evaluateValue(ctx, findAlongAttrPath(*ctx->state, "type.getSubOptions", *ctx->autoArgs, v)); + if (getSubOptions.type != tLambda) { + throw Error("Option's type.getSubOptions isn't a function at '" + attr + "' in path '" + path + "'"); + } + Value emptyString{}; + nix::mkString(emptyString, ""); + ctx->state->callFunction(getSubOptions, emptyString, v, nix::Pos{}); + // Note that we've consumed attr, but didn't actually use it. + } else if (v.type != tAttrs) { + throw Error("attribute '" + attr + "' in path '" + path + + "' attempts to index a value that should be a set but is " + showType(v)); + } else { + auto const & next = v.attrs->find(ctx->state->symbols.create(attr)); + if (next == v.attrs->end()) { + throw Error("attribute '" + attr + "' in path '" + path + "' not found"); + } + v = *next->value; + } } - if (isOption(ctx, v) && !last_attribute) { - Value getSubOptions = evaluateValue( - ctx, findAlongAttrPath(*ctx->state, "type.getSubOptions", - *ctx->autoArgs, v)); - if (getSubOptions.type != tLambda) { - throw Error("Option's type.getSubOptions isn't a function at '" + attr + - "' in path '" + path + "'"); - } - Value emptyString{}; - nix::mkString(emptyString, ""); - ctx->state->callFunction(getSubOptions, emptyString, v, nix::Pos{}); - // Note that we've consumed attr, but didn't actually use it. - } else if (v.type != tAttrs) { - throw Error("attribute '" + attr + "' in path '" + path + - "' attempts to index a value that should be a set but is " + - showType(v)); + return v; +} + +void printOne(Context * ctx, Out & out, std::string const & path) +{ + try { + Value option = findAlongOptionPath(ctx, path); + option = evaluateValue(ctx, &option); + if (isOption(ctx, option)) { + printOption(ctx, out, path, &option); + } else { + printListing(out, &option); + } + } catch (Error & e) { + std::cerr << "error: " << e.msg() + << "\nAn error occurred while looking for attribute names. Are " + "you sure that '" + << path << "' exists?\n"; + } +} + +int main(int argc, char ** argv) +{ + bool all = false; + std::string path = "."; + std::string options_expr = "(import {}).options"; + std::string config_expr = "(import {}).config"; + std::vector args; + + struct MyArgs : nix::LegacyArgs, nix::MixEvalArgs + { + using nix::LegacyArgs::LegacyArgs; + }; + + MyArgs myArgs(nix::baseNameOf(argv[0]), [&](Strings::iterator & arg, const Strings::iterator & end) { + if (*arg == "--help") { + nix::showManPage("nixos-option"); + } else if (*arg == "--version") { + nix::printVersion("nixos-option"); + } else if (*arg == "--all") { + all = true; + } else if (*arg == "--path") { + path = nix::getArg(*arg, arg, end); + } else if (*arg == "--options_expr") { + options_expr = nix::getArg(*arg, arg, end); + } else if (*arg == "--config_expr") { + config_expr = nix::getArg(*arg, arg, end); + } else if (!arg->empty() && arg->at(0) == '-') { + return false; + } else { + args.push_back(*arg); + } + return true; + }); + + myArgs.parseCmdline(nix::argvToStrings(argc, argv)); + + nix::initPlugins(); + nix::initGC(); + nix::settings.readOnlyMode = true; + auto store = nix::openStore(); + auto state = std::make_unique(myArgs.searchPath, store); + + Value options_root = parseAndEval(state.get(), options_expr, path); + Value config_root = parseAndEval(state.get(), config_expr, path); + + Context ctx{state.get(), myArgs.getAutoArgs(*state), options_root, config_root}; + Out out(std::cout); + + if (all) { + if (!args.empty()) { + throw UsageError("--all cannot be used with arguments"); + } + printAll(&ctx, out); } else { - auto const &next = v.attrs->find(ctx->state->symbols.create(attr)); - if (next == v.attrs->end()) { - throw Error("attribute '" + attr + "' in path '" + path + - "' not found"); - } - v = *next->value; + if (args.empty()) { + printOne(&ctx, out, ""); + } + for (auto const & arg : args) { + printOne(&ctx, out, arg); + } } - } - return v; -} - -void printOne(Context *ctx, Out &out, std::string const &path) { - try { - Value option = findAlongOptionPath(ctx, path); - option = evaluateValue(ctx, &option); - if (isOption(ctx, option)) { - printOption(ctx, out, path, &option); - } else { - printListing(out, &option); - } - } catch (Error &e) { - std::cerr << "error: " << e.msg() - << "\nAn error occurred while looking for attribute names. Are " - "you sure that '" - << path << "' exists?\n"; - } -} - -int main(int argc, char **argv) { - bool all = false; - std::string path = "."; - std::string options_expr = "(import {}).options"; - std::string config_expr = "(import {}).config"; - std::vector args; - - struct MyArgs : nix::LegacyArgs, nix::MixEvalArgs { - using nix::LegacyArgs::LegacyArgs; - }; - - MyArgs myArgs(nix::baseNameOf(argv[0]), - [&](Strings::iterator &arg, const Strings::iterator &end) { - if (*arg == "--help") { - nix::showManPage("nixos-option"); - } else if (*arg == "--version") { - nix::printVersion("nixos-option"); - } else if (*arg == "--all") { - all = true; - } else if (*arg == "--path") { - path = nix::getArg(*arg, arg, end); - } else if (*arg == "--options_expr") { - options_expr = nix::getArg(*arg, arg, end); - } else if (*arg == "--config_expr") { - config_expr = nix::getArg(*arg, arg, end); - } else if (!arg->empty() && arg->at(0) == '-') { - return false; - } else { - args.push_back(*arg); - } - return true; - }); - - myArgs.parseCmdline(nix::argvToStrings(argc, argv)); - - nix::initPlugins(); - nix::initGC(); - nix::settings.readOnlyMode = true; - auto store = nix::openStore(); - auto state = std::make_unique(myArgs.searchPath, store); - - Value options_root = parseAndEval(state.get(), options_expr, path); - Value config_root = parseAndEval(state.get(), config_expr, path); - - Context ctx{state.get(), myArgs.getAutoArgs(*state), options_root, - config_root}; - Out out(std::cout); - - if (all) { - if (!args.empty()) { - throw UsageError("--all cannot be used with arguments"); - } - printAll(&ctx, out); - } else { - if (args.empty()) { - printOne(&ctx, out, ""); - } - for (auto const &arg : args) { - printOne(&ctx, out, arg); - } - } - - ctx.state->printStats(); - - return 0; + + ctx.state->printStats(); + + return 0; }