From 59c5bfc86b75247cb48539eeaaea2a3c5f320b1d Mon Sep 17 00:00:00 2001 From: Chuck Date: Thu, 5 Sep 2019 17:29:01 -0700 Subject: nixos/nixos-option: Rewrite in a more suitable language Also add --all, which shows the value of all options. Diffing the --all output on either side of contemplated changes is a lovely way to better understand what's going on inside nixos. --- nixos/modules/installer/tools/nixos-option.sh | 327 ------------ .../installer/tools/nixos-option/CMakeLists.txt | 8 + .../installer/tools/nixos-option/default.nix | 8 + .../tools/nixos-option/libnix-copy-paste.cc | 81 +++ .../tools/nixos-option/libnix-copy-paste.hh | 9 + .../installer/tools/nixos-option/nixos-option.cc | 585 +++++++++++++++++++++ nixos/modules/installer/tools/tools.nix | 5 +- 7 files changed, 692 insertions(+), 331 deletions(-) delete mode 100644 nixos/modules/installer/tools/nixos-option.sh create mode 100644 nixos/modules/installer/tools/nixos-option/CMakeLists.txt create mode 100644 nixos/modules/installer/tools/nixos-option/default.nix create mode 100644 nixos/modules/installer/tools/nixos-option/libnix-copy-paste.cc create mode 100644 nixos/modules/installer/tools/nixos-option/libnix-copy-paste.hh create mode 100644 nixos/modules/installer/tools/nixos-option/nixos-option.cc (limited to 'nixos/modules') diff --git a/nixos/modules/installer/tools/nixos-option.sh b/nixos/modules/installer/tools/nixos-option.sh deleted file mode 100644 index 4560e9c7403a..000000000000 --- a/nixos/modules/installer/tools/nixos-option.sh +++ /dev/null @@ -1,327 +0,0 @@ -#! @shell@ -e - -# FIXME: rewrite this in a more suitable language. - -usage () { - exec man nixos-option - exit 1 -} - -##################### -# Process Arguments # -##################### - -xml=false -verbose=false -nixPath="" - -option="" -exit_code=0 - -argfun="" -for arg; do - if test -z "$argfun"; then - case $arg in - -*) - sarg="$arg" - longarg="" - while test "$sarg" != "-"; do - case $sarg in - --*) longarg=$arg; sarg="--";; - -I) argfun="include_nixpath";; - -*) usage;; - esac - # remove the first letter option - sarg="-${sarg#??}" - done - ;; - *) longarg=$arg;; - esac - for larg in $longarg; do - case $larg in - --xml) xml=true;; - --verbose) verbose=true;; - --help) usage;; - -*) usage;; - *) if test -z "$option"; then - option="$larg" - else - usage - fi;; - esac - done - else - case $argfun in - set_*) - var=$(echo $argfun | sed 's,^set_,,') - eval $var=$arg - ;; - include_nixpath) - nixPath="-I $arg $nixPath" - ;; - esac - argfun="" - fi -done - -if $verbose; then - set -x -else - set +x -fi - -############################# -# Process the configuration # -############################# - -evalNix(){ - # disable `-e` flag, it's possible that the evaluation of `nix-instantiate` fails (e.g. due to broken pkgs) - set +e - result=$(nix-instantiate ${nixPath:+$nixPath} - --eval-only "$@" 2>&1) - exit_code=$? - set -e - - if test $exit_code -eq 0; then - sed '/^warning: Nix search path/d' <&2 <" - else if strict then - if isAttrs x then mapAttrs (n: cleanOutput) x - else if isList x then map cleanOutput x - else x - else x; -in - cleanOutput value -EOF -} - -evalOpt(){ - evalAttr "option" "" "$@" -} - -evalCfg(){ - local strict="$1" - evalAttr "config" "$strict" -} - -findSources(){ - local suffix=$1 - evalNix --strict <,0,g; :inner; s/{[^\{\}]*};/0;/g; t inner;' | \ - evalNix --strict -} - -# map a simple list which contains strings or paths. -nixMap() { - local fun="$1" - local list="$2" - local elem - for elem in $list; do - test $elem = '[' -o $elem = ']' && continue; - $fun $elem - done -} - -# This duplicates the work made below, but it is useful for processing -# the output of nixos-option with other tools such as nixos-gui. -if $xml; then - evalNix --xml --no-location < /dev/null)" = '"option"'; then - echo "Value:" - evalCfg 1 - - echo - - echo "Default:" - if default=$(evalOpt "default" - 2> /dev/null); then - echo "$default" - else - echo "" - fi - echo - if example=$(evalOpt "example" - 2> /dev/null); then - echo "Example:" - echo "$example" - echo - fi - echo "Description:" - echo - echo $(evalOpt "description") - - echo $desc; - - printPath () { echo " $1"; } - - echo "Declared by:" - nixMap printPath "$(findSources "declarations")" - echo - echo "Defined by:" - nixMap printPath "$(findSources "files")" - echo - -else - # echo 1>&2 "Warning: This value is not an option." - - result=$(evalCfg "") - if [ ! -z "$result" ]; then - names=$(attrNames "$result" 2> /dev/null) - echo 1>&2 "This attribute set contains:" - escapeQuotes () { eval echo "$1"; } - nixMap escapeQuotes "$names" - else - echo 1>&2 "An error occurred while looking for attribute names. Are you sure that '$option' exists?" - fi -fi - -exit $exit_code diff --git a/nixos/modules/installer/tools/nixos-option/CMakeLists.txt b/nixos/modules/installer/tools/nixos-option/CMakeLists.txt new file mode 100644 index 000000000000..e5834598c4fd --- /dev/null +++ b/nixos/modules/installer/tools/nixos-option/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required (VERSION 2.6) +project (nixos-option) + +add_executable(nixos-option nixos-option.cc libnix-copy-paste.cc) +target_link_libraries(nixos-option PRIVATE -lnixmain -lnixexpr -lnixstore -lnixutil) +target_compile_features(nixos-option PRIVATE cxx_std_17) + +install (TARGETS nixos-option DESTINATION bin) diff --git a/nixos/modules/installer/tools/nixos-option/default.nix b/nixos/modules/installer/tools/nixos-option/default.nix new file mode 100644 index 000000000000..6464a91052cc --- /dev/null +++ b/nixos/modules/installer/tools/nixos-option/default.nix @@ -0,0 +1,8 @@ +{stdenv, boost, cmake, pkgconfig, nix, ... }: +stdenv.mkDerivation rec { + name = "nixos-option"; + src = ./.; + nativeBuildInputs = [ cmake pkgconfig ]; + buildInputs = [ boost nix ]; + enableParallelBuilding = true; +} diff --git a/nixos/modules/installer/tools/nixos-option/libnix-copy-paste.cc b/nixos/modules/installer/tools/nixos-option/libnix-copy-paste.cc new file mode 100644 index 000000000000..81de5ff8523b --- /dev/null +++ b/nixos/modules/installer/tools/nixos-option/libnix-copy-paste.cc @@ -0,0 +1,81 @@ +// These are useful methods inside the nix library that ought to be exported. +// Since they are not, copy/paste them here. +// TODO: Delete these and use the ones in the library as they become available. + +#include // for nix/globals.hh's reference to SYSTEM + +#include "libnix-copy-paste.hh" +#include // for basic_altstringbuf... +#include // for basic_altstringbuf... +#include // for basic_format +#include // for format +#include // for basic_format::basi... +#include // for get_pointer +#include // for operator<<, basic_... +#include // for Strings, Error +#include // for string, basic_string + +using boost::format; +using nix::Error; +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; +} + +// 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; +} + +// 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; +} diff --git a/nixos/modules/installer/tools/nixos-option/libnix-copy-paste.hh b/nixos/modules/installer/tools/nixos-option/libnix-copy-paste.hh new file mode 100644 index 000000000000..225e8b1b87ee --- /dev/null +++ b/nixos/modules/installer/tools/nixos-option/libnix-copy-paste.hh @@ -0,0 +1,9 @@ +#pragma once + +#include +#include +#include + +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 new file mode 100644 index 000000000000..c778596d6150 --- /dev/null +++ b/nixos/modules/installer/tools/nixos-option/nixos-option.cc @@ -0,0 +1,585 @@ +#include // for nix/globals.hh's reference to SYSTEM + +#include // for sort +#include // for function +#include // for operator<<, basic_ostream, ostrin... +#include // for next +#include // for _List_iterator +#include // for allocator, unique_ptr, make_unique +#include // for argvToStrings, UsageError +#include // for findAlongAttrPath +#include // for Attr, Bindings, Bindings::iterator +#include // for MixEvalArgs +#include // for EvalState::forceValue +#include // for EvalState, initGC, operator<< +#include // for initPlugins, Settings, settings +#include // for Pos +#include // for getArg, LegacyArgs, printVersion +#include // for openStore +#include // for Symbol, SymbolTable +#include // for Error, Path, Strings, PathSet +#include // for absPath, baseNameOf +#include // for Value, Value::(anonymous), Value:... +#include // for string, operator+, operator== +#include // for move +#include // for get, holds_alternative, variant +#include // for vector<>::iterator, vector + +#include "libnix-copy-paste.hh" + +using nix::absPath; +using nix::Bindings; +using nix::Error; +using nix::EvalState; +using nix::Path; +using nix::PathSet; +using nix::Strings; +using nix::Symbol; +using nix::tAttrs; +using nix::tLambda; +using nix::tString; +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; } + +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, 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; +} + +// 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; +}; + +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; + } + 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; + } + 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, ""); +} + +// Calls f on all the config values inside one option. +// Simple options have one config value inside, like sound.enable = true. +// Compound options have multiple config values. For example, the option +// "users.users" has about 1000 config values inside it: +// users.users.avahi.createHome = false; +// users.users.avahi.cryptHomeLuks = null; +// users.users.avahi.description = "`avahi-daemon' privilege separation user"; +// ... +// users.users.avahi.openssh.authorizedKeys.keyFiles = [ ]; +// users.users.avahi.openssh.authorizedKeys.keys = [ ]; +// ... +// users.users.avahi.uid = 10; +// users.users.avahi.useDefaultShell = false; +// users.users.cups.createHome = false; +// ... +// users.users.cups.useDefaultShell = false; +// users.users.gdm = ... ... ... +// users.users.messagebus = ... .. ... +// 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 + } + 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; + } + 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)}; + } + 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-options-summary, 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 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\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"; + } + } +} + +// 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 + "'"); + } + 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; + } + } + 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-options-summary"); + } else if (*arg == "--version") { + nix::printVersion("nixos-options-summary"); + } 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; +} diff --git a/nixos/modules/installer/tools/tools.nix b/nixos/modules/installer/tools/tools.nix index 052e7fdd4fc1..e4db39b5c810 100644 --- a/nixos/modules/installer/tools/tools.nix +++ b/nixos/modules/installer/tools/tools.nix @@ -41,10 +41,7 @@ let inherit (config.system.nixos-generate-config) configuration; }; - nixos-option = makeProg { - name = "nixos-option"; - src = ./nixos-option.sh; - }; + nixos-option = pkgs.callPackage ./nixos-option { }; nixos-version = makeProg { name = "nixos-version"; -- cgit 1.4.1 From 26c45dfec2716b1508e5d7ac8efdbdf570f2eb99 Mon Sep 17 00:00:00 2001 From: Chuck Date: Fri, 6 Sep 2019 01:25:00 -0700 Subject: nixos/nixos-option: Show options' types #27920 --- nixos/modules/installer/tools/nixos-option/nixos-option.cc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'nixos/modules') diff --git a/nixos/modules/installer/tools/nixos-option/nixos-option.cc b/nixos/modules/installer/tools/nixos-option/nixos-option.cc index c778596d6150..6787c73e164e 100644 --- a/nixos/modules/installer/tools/nixos-option/nixos-option.cc +++ b/nixos/modules/installer/tools/nixos-option/nixos-option.cc @@ -434,6 +434,9 @@ void printOption(Context *ctx, Out &out, std::string const &path, 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); -- cgit 1.4.1 From 74f05df671e6381c1515fc9da72c44051ef8753c Mon Sep 17 00:00:00 2001 From: Chuck Date: Fri, 6 Sep 2019 02:50:50 -0700 Subject: nixos/nixos-option: Fix references to old name --- nixos/modules/installer/tools/nixos-option/nixos-option.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'nixos/modules') diff --git a/nixos/modules/installer/tools/nixos-option/nixos-option.cc b/nixos/modules/installer/tools/nixos-option/nixos-option.cc index 6787c73e164e..49da3ce68749 100644 --- a/nixos/modules/installer/tools/nixos-option/nixos-option.cc +++ b/nixos/modules/installer/tools/nixos-option/nixos-option.cc @@ -386,7 +386,7 @@ void printValue(Context *ctx, Out &out, std::variant maybe_value, // 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-options-summary, we are looking at this value only to print it. + // 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»"; @@ -534,9 +534,9 @@ int main(int argc, char **argv) { MyArgs myArgs(nix::baseNameOf(argv[0]), [&](Strings::iterator &arg, const Strings::iterator &end) { if (*arg == "--help") { - nix::showManPage("nixos-options-summary"); + nix::showManPage("nixos-option"); } else if (*arg == "--version") { - nix::printVersion("nixos-options-summary"); + nix::printVersion("nixos-option"); } else if (*arg == "--all") { all = true; } else if (*arg == "--path") { -- cgit 1.4.1 From 4af8dbf8964924dc3d2ec2bbfa159dae288b29fc Mon Sep 17 00:00:00 2001 From: Chuck Date: Fri, 6 Sep 2019 09:45:05 -0700 Subject: 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 +- .../installer/tools/nixos-option/nixos-option.cc | 877 +++++++++++---------- 3 files changed, 496 insertions(+), 491 deletions(-) (limited to 'nixos/modules') 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 81de5ff8523b..875c07da6399 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 225e8b1b87ee..2274e9a0f853 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 49da3ce68749..fe44a347aefe 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; } - -private: - std::ostream &ostream; - std::string indentation; - std::string end; - LinePolicy policy; - bool write_since_sep; - template friend Out &operator<<(Out &o, T thing); +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); }; -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 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); +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"; -} +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; +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 - } - f(path, v); - return false; - }, - ctx, *option, path); +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); - } +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; +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 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 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; - } +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]); +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 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 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]; +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]; } - } - 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; +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; } - 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)}; - } - 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); +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); + } } - } } -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 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 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 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); +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\nDefault:\n"; + printAttr(ctx, out, "default", option); - out << "\n\nType:\n"; - printAttr(ctx, out, "type.description", option); + out << "\n\nType:\n"; + printAttr(ctx, out, "type.description", option); - out << "\n\nExample:\n"; - printAttr(ctx, out, "example", option); + out << "\n\nExample:\n"; + printAttr(ctx, out, "example", option); - out << "\n\nDescription:\n"; - printAttr(ctx, out, "description", option); + out << "\n\nDescription:\n"; + printAttr(ctx, out, "description", option); - out << "\n\nDeclared by:\n"; - printAttr(ctx, out, "declarations", option); + out << "\n\nDeclared by:\n"; + printAttr(ctx, out, "declarations", option); - out << "\n\nDefined by:\n"; - printAttr(ctx, out, "files", option); - out << "\n"; + 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 + "'"); - } - 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; +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; + } } - } - return 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); +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"; } - } 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); +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(); + ctx.state->printStats(); - return 0; + return 0; } -- cgit 1.4.1 From 36c00c108076915b0074fefc8ae5bb8baba476fa Mon Sep 17 00:00:00 2001 From: Chuck Date: Fri, 6 Sep 2019 09:51:08 -0700 Subject: Use format strings, not concatenation, in error messages --- nixos/modules/installer/tools/nixos-option/nixos-option.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'nixos/modules') diff --git a/nixos/modules/installer/tools/nixos-option/nixos-option.cc b/nixos/modules/installer/tools/nixos-option/nixos-option.cc index fe44a347aefe..d72a2ae3f8db 100644 --- a/nixos/modules/installer/tools/nixos-option/nixos-option.cc +++ b/nixos/modules/installer/tools/nixos-option/nixos-option.cc @@ -479,25 +479,25 @@ Value findAlongOptionPath(Context * ctx, std::string const & path) auto const & attr = *i; v = evaluateValue(ctx, &v); if (attr.empty()) { - throw Error("empty attribute name in selection path '" + path + "'"); + throw Error("empty attribute name in selection path '%s'", 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 + "'"); + throw Error("Option's type.getSubOptions isn't a function at '%s' in path '%s'", attr, 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)); + throw Error("attribute '%s' in path '%s' attempts to index a value that should be a set but is %s", attr, + path, 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"); + throw Error("attribute '%s' in path '%s' not found", attr, path); } v = *next->value; } -- cgit 1.4.1 From e1ecc2b6c1fe10acf2a1f63f027f002ff4b9ff7c Mon Sep 17 00:00:00 2001 From: Chuck Date: Fri, 6 Sep 2019 09:58:34 -0700 Subject: Remove list sorting --- .../installer/tools/nixos-option/nixos-option.cc | 37 +--------------------- 1 file changed, 1 insertion(+), 36 deletions(-) (limited to 'nixos/modules') diff --git a/nixos/modules/installer/tools/nixos-option/nixos-option.cc b/nixos/modules/installer/tools/nixos-option/nixos-option.cc index d72a2ae3f8db..01eb0d5ddd18 100644 --- a/nixos/modules/installer/tools/nixos-option/nixos-option.cc +++ b/nixos/modules/installer/tools/nixos-option/nixos-option.cc @@ -1,6 +1,5 @@ #include // for nix/globals.hh's reference to SYSTEM -#include // for sort #include // for function #include // for operator<<, basic_ostream, ostrin... #include // for next @@ -276,7 +275,7 @@ Value parseAndEval(EvalState * state, std::string const & expression, std::strin void printValue(Context * ctx, Out & out, std::variant maybe_value, std::string const & path); -void printUnsortedList(Context * ctx, Out & out, Value & v) +void printList(Context * ctx, Out & out, Value & v) { Out list_out(out, "[", "]", v.listSize()); for (unsigned int n = 0; n < v.listSize(); ++n) { @@ -285,40 +284,6 @@ void printUnsortedList(Context * ctx, Out & out, Value & v) } } -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()); -- cgit 1.4.1 From f3eedb6020a0b2bc8a5ce19cf9761fc60d2873f8 Mon Sep 17 00:00:00 2001 From: Chuck Date: Fri, 6 Sep 2019 09:59:45 -0700 Subject: Parallel build is the default, so no need to specify --- nixos/modules/installer/tools/nixos-option/default.nix | 1 - 1 file changed, 1 deletion(-) (limited to 'nixos/modules') diff --git a/nixos/modules/installer/tools/nixos-option/default.nix b/nixos/modules/installer/tools/nixos-option/default.nix index 6464a91052cc..2ba5e73d7c07 100644 --- a/nixos/modules/installer/tools/nixos-option/default.nix +++ b/nixos/modules/installer/tools/nixos-option/default.nix @@ -4,5 +4,4 @@ stdenv.mkDerivation rec { src = ./.; nativeBuildInputs = [ cmake pkgconfig ]; buildInputs = [ boost nix ]; - enableParallelBuilding = true; } -- cgit 1.4.1 From 23369829579594bd8fd1b9423e399f2aeaca5488 Mon Sep 17 00:00:00 2001 From: Chuck Date: Fri, 6 Sep 2019 10:29:32 -0700 Subject: Add license This is important because this contains some code copied from nix (as an interim expediency until that functionality can be exported via nix's API). The license specified here must be compatible with this borrowing. Select the same license that nix is released under: lgpl2Plus. --- nixos/modules/installer/tools/nixos-option/default.nix | 3 +++ 1 file changed, 3 insertions(+) (limited to 'nixos/modules') diff --git a/nixos/modules/installer/tools/nixos-option/default.nix b/nixos/modules/installer/tools/nixos-option/default.nix index 2ba5e73d7c07..87ba38c29cad 100644 --- a/nixos/modules/installer/tools/nixos-option/default.nix +++ b/nixos/modules/installer/tools/nixos-option/default.nix @@ -4,4 +4,7 @@ stdenv.mkDerivation rec { src = ./.; nativeBuildInputs = [ cmake pkgconfig ]; buildInputs = [ boost nix ]; + meta { + license = stdenv.lib.licenses.lgpl2Plus; + } } -- cgit 1.4.1 From d89ccc1554d9b4e8064c9d07bf23652a3bd52fce Mon Sep 17 00:00:00 2001 From: Chuck Date: Fri, 6 Sep 2019 10:46:45 -0700 Subject: Correct syntax for license specification --- nixos/modules/installer/tools/nixos-option/default.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'nixos/modules') diff --git a/nixos/modules/installer/tools/nixos-option/default.nix b/nixos/modules/installer/tools/nixos-option/default.nix index 87ba38c29cad..2c2674ad28d2 100644 --- a/nixos/modules/installer/tools/nixos-option/default.nix +++ b/nixos/modules/installer/tools/nixos-option/default.nix @@ -4,7 +4,7 @@ stdenv.mkDerivation rec { src = ./.; nativeBuildInputs = [ cmake pkgconfig ]; buildInputs = [ boost nix ]; - meta { + meta = { license = stdenv.lib.licenses.lgpl2Plus; - } + }; } -- cgit 1.4.1 From c7c684aaa3e165287be4b9d8345481e1d85c04e8 Mon Sep 17 00:00:00 2001 From: Chuck Date: Fri, 6 Sep 2019 11:37:48 -0700 Subject: Preserve type of rethrown exceptions --- .../installer/tools/nixos-option/nixos-option.cc | 38 ++++++++++++---------- 1 file changed, 20 insertions(+), 18 deletions(-) (limited to 'nixos/modules') diff --git a/nixos/modules/installer/tools/nixos-option/nixos-option.cc b/nixos/modules/installer/tools/nixos-option/nixos-option.cc index 01eb0d5ddd18..5886ee6959bd 100644 --- a/nixos/modules/installer/tools/nixos-option/nixos-option.cc +++ b/nixos/modules/installer/tools/nixos-option/nixos-option.cc @@ -1,10 +1,12 @@ #include // for nix/globals.hh's reference to SYSTEM +#include // for exception_ptr, current_exception #include // for function #include // for operator<<, basic_ostream, ostrin... #include // for next #include // for _List_iterator #include // for allocator, unique_ptr, make_unique +#include // for operator new #include // for argvToStrings, UsageError #include // for findAlongAttrPath #include // for Attr, Bindings, Bindings::iterator @@ -166,19 +168,19 @@ std::string const appendPath(std::string const & prefix, std::string const & suf bool forbiddenRecursionName(std::string name) { return (!name.empty() && name[0] == '_') || name == "haskellPackages"; } -void recurse(const std::function)> & f, Context * ctx, +void recurse(const std::function)> & f, Context * ctx, Value v, std::string const & path) { - std::variant evaluated; + std::variant evaluated; try { evaluated = evaluateValue(ctx, &v); - } catch (Error & e) { - evaluated = e; + } catch (Error &) { + evaluated = std::current_exception(); } if (!f(path, evaluated)) { return; } - if (std::holds_alternative(evaluated)) { + if (std::holds_alternative(evaluated)) { return; } Value const & evaluated_value = std::get(evaluated); @@ -197,8 +199,8 @@ void recurse(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)); + [f, ctx](std::string const & path, std::variant v) { + bool isOpt = std::holds_alternative(v) || isOption(ctx, std::get(v)); if (isOpt) { f(path); } @@ -228,19 +230,19 @@ void mapOptions(const std::function & f, Context // users.users.nixbld1 = ... .. ... // ... // users.users.systemd-timesync = ... .. ... -void mapConfigValuesInOption(const std::function v)> & f, +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); + } catch (Error &) { + f(path, std::current_exception()); return; } recurse( - [f, ctx](std::string const & path, std::variant v) { - bool leaf = std::holds_alternative(v) || std::get(v).type != tAttrs || + [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 @@ -273,7 +275,7 @@ Value parseAndEval(EvalState * state, std::string const & expression, std::strin return v; } -void printValue(Context * ctx, Out & out, std::variant maybe_value, std::string const & path); +void printValue(Context * ctx, Out & out, std::variant maybe_value, std::string const & path); void printList(Context * ctx, Out & out, Value & v) { @@ -331,11 +333,11 @@ void printMultiLineString(Out & out, Value const & v) } } -void printValue(Context * ctx, Out & out, std::variant maybe_value, std::string const & path) +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)}; + if (std::holds_alternative(maybe_value)) { + std::rethrow_exception(std::get(maybe_value)); } Value v = evaluateValue(ctx, &std::get(maybe_value)); if (ctx->state->isDerivation(v)) { @@ -366,7 +368,7 @@ void printValue(Context * ctx, Out & out, std::variant maybe_value } } -void printConfigValue(Context * ctx, Out & out, std::string const & path, std::variant v) +void printConfigValue(Context * ctx, Out & out, std::string const & path, std::variant v) { out << path << " = "; printValue(ctx, out, std::move(v), path); @@ -378,7 +380,7 @@ 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) { + [ctx, &out](std::string const & config_path, std::variant v) { printConfigValue(ctx, out, config_path, v); }, option_path, ctx); -- cgit 1.4.1 From 0adf77e2eeb5227666f54ac6476884f9ddb63bee Mon Sep 17 00:00:00 2001 From: Chuck Date: Fri, 6 Sep 2019 11:38:29 -0700 Subject: Narrow the «not defined» check to just ThrownError MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nixos/modules/installer/tools/nixos-option/nixos-option.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'nixos/modules') diff --git a/nixos/modules/installer/tools/nixos-option/nixos-option.cc b/nixos/modules/installer/tools/nixos-option/nixos-option.cc index 5886ee6959bd..1fde8986fdf5 100644 --- a/nixos/modules/installer/tools/nixos-option/nixos-option.cc +++ b/nixos/modules/installer/tools/nixos-option/nixos-option.cc @@ -352,7 +352,7 @@ void printValue(Context * ctx, Out & out, std::variantstate->forceValueDeep(v); out << v; } - } catch (Error & e) { + } catch (ThrownError & 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 @@ -365,6 +365,8 @@ void printValue(Context * ctx, Out & out, std::variant Date: Fri, 6 Sep 2019 12:27:34 -0700 Subject: Fix missing "using ThrownError" --- nixos/modules/installer/tools/nixos-option/nixos-option.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'nixos/modules') diff --git a/nixos/modules/installer/tools/nixos-option/nixos-option.cc b/nixos/modules/installer/tools/nixos-option/nixos-option.cc index 1fde8986fdf5..383755f884a1 100644 --- a/nixos/modules/installer/tools/nixos-option/nixos-option.cc +++ b/nixos/modules/installer/tools/nixos-option/nixos-option.cc @@ -37,6 +37,7 @@ using nix::PathSet; using nix::Strings; using nix::Symbol; using nix::tAttrs; +using nix::ThrownError; using nix::tLambda; using nix::tString; using nix::UsageError; -- cgit 1.4.1 From 88349921a46fb303c134f568fbe9d5ba88bb2b6a Mon Sep 17 00:00:00 2001 From: Chuck Date: Fri, 6 Sep 2019 14:30:27 -0700 Subject: clang-format --- nixos/modules/installer/tools/nixos-option/nixos-option.cc | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'nixos/modules') diff --git a/nixos/modules/installer/tools/nixos-option/nixos-option.cc b/nixos/modules/installer/tools/nixos-option/nixos-option.cc index 383755f884a1..8e2a8f5c018e 100644 --- a/nixos/modules/installer/tools/nixos-option/nixos-option.cc +++ b/nixos/modules/installer/tools/nixos-option/nixos-option.cc @@ -169,8 +169,8 @@ std::string const appendPath(std::string const & prefix, std::string const & suf 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) +void recurse(const std::function)> & f, + Context * ctx, Value v, std::string const & path) { std::variant evaluated; try { @@ -231,8 +231,9 @@ void mapOptions(const std::function & f, Context // users.users.nixbld1 = ... .. ... // ... // users.users.systemd-timesync = ... .. ... -void mapConfigValuesInOption(const std::function v)> & f, - std::string const & path, Context * ctx) +void mapConfigValuesInOption( + const std::function v)> & f, + std::string const & path, Context * ctx) { Value * option; try { @@ -276,7 +277,8 @@ Value parseAndEval(EvalState * state, std::string const & expression, std::strin return v; } -void printValue(Context * ctx, Out & out, std::variant maybe_value, std::string const & path); +void printValue(Context * ctx, Out & out, std::variant maybe_value, + std::string const & path); void printList(Context * ctx, Out & out, Value & v) { @@ -338,7 +340,7 @@ void printValue(Context * ctx, Out & out, std::variant(maybe_value)) { - std::rethrow_exception(std::get(maybe_value)); + std::rethrow_exception(std::get(maybe_value)); } Value v = evaluateValue(ctx, &std::get(maybe_value)); if (ctx->state->isDerivation(v)) { -- cgit 1.4.1 From b8db81573a1e5a4e26da10d778d4400684a96832 Mon Sep 17 00:00:00 2001 From: Chuck Date: Fri, 6 Sep 2019 14:32:22 -0700 Subject: Support submodules (Fixes #13121) --- .../installer/tools/nixos-option/nixos-option.cc | 56 ++++++++++++++++++---- 1 file changed, 46 insertions(+), 10 deletions(-) (limited to 'nixos/modules') diff --git a/nixos/modules/installer/tools/nixos-option/nixos-option.cc b/nixos/modules/installer/tools/nixos-option/nixos-option.cc index 8e2a8f5c018e..755c2f0b0027 100644 --- a/nixos/modules/installer/tools/nixos-option/nixos-option.cc +++ b/nixos/modules/installer/tools/nixos-option/nixos-option.cc @@ -440,6 +440,45 @@ void printListing(Out & out, Value * v) } } +bool optionTypeIs(Context * ctx, Value & v, std::string const & sought_type) +{ + try { + auto const & type_lookup = v.attrs->find(ctx->state->sType); + if (type_lookup == v.attrs->end()) { + return false; + } + Value type = evaluateValue(ctx, type_lookup->value); + if (type.type != tAttrs) { + return false; + } + auto const & name_lookup = type.attrs->find(ctx->state->sName); + if (name_lookup == type.attrs->end()) { + return false; + } + Value name = evaluateValue(ctx, name_lookup->value); + if (name.type != tString) { + return false; + } + return name.string.s == sought_type; + } catch (Error &) { + return false; + } +} + +Value getSubOptions(Context * ctx, Value & option) +{ + Value getSubOptions = + evaluateValue(ctx, findAlongAttrPath(*ctx->state, "type.getSubOptions", *ctx->autoArgs, option)); + if (getSubOptions.type != tLambda) { + throw Error("Option's type.getSubOptions isn't a function"); + } + Value emptyString{}; + nix::mkString(emptyString, ""); + Value v; + ctx->state->callFunction(getSubOptions, emptyString, v, nix::Pos{}); + return v; +} + // 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) @@ -453,16 +492,13 @@ Value findAlongOptionPath(Context * ctx, std::string const & path) if (attr.empty()) { throw Error("empty attribute name in selection path '%s'", 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 '%s' in path '%s'", attr, 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. + if (isOption(ctx, v) && optionTypeIs(ctx, v, "submodule")) { + v = getSubOptions(ctx, v); + } + if (isOption(ctx, v) && optionTypeIs(ctx, v, "loaOf") && !last_attribute) { + v = getSubOptions(ctx, v); + // Note that we've consumed attr, but didn't actually use it. This is the path component that's looked up + // in the list or attribute set that doesn't name an option -- the "root" in "users.users.root.name". } else if (v.type != tAttrs) { throw Error("attribute '%s' in path '%s' attempts to index a value that should be a set but is %s", attr, path, showType(v)); -- cgit 1.4.1 From c352bfeaf096ed11560624b8c5034ba0ed0723b7 Mon Sep 17 00:00:00 2001 From: Chuck Date: Mon, 16 Sep 2019 08:15:28 -0700 Subject: Switch from east const to west const For consistency with the Nix C++ convention. :~( --- .../installer/tools/nixos-option/nixos-option.cc | 76 +++++++++++----------- 1 file changed, 38 insertions(+), 38 deletions(-) (limited to 'nixos/modules') diff --git a/nixos/modules/installer/tools/nixos-option/nixos-option.cc b/nixos/modules/installer/tools/nixos-option/nixos-option.cc index 755c2f0b0027..79a58e510afc 100644 --- a/nixos/modules/installer/tools/nixos-option/nixos-option.cc +++ b/nixos/modules/installer/tools/nixos-option/nixos-option.cc @@ -56,13 +56,13 @@ class Out 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(Out & o, const std::string & start, const std::string & end, LinePolicy policy); + Out(Out & o, const std::string & start, const std::string & end, int count) : Out(o, start, end, count < 2 ? ONE_LINE : MULTI_LINE) {} - Out(Out const &) = delete; + Out(const Out &) = delete; Out(Out &&) = default; - Out & operator=(Out const &) = delete; + Out & operator=(const Out &) = delete; Out & operator=(Out &&) = delete; ~Out() { ostream << end; } @@ -92,7 +92,7 @@ template <> Out & operator<<(Out & o, Out::Separator /* thing */ return o; } -Out::Out(Out & o, std::string const & start, std::string const & end, LinePolicy policy) +Out::Out(Out & o, const std::string & start, const std::string & 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) { @@ -125,12 +125,12 @@ Value evaluateValue(Context * ctx, Value * v) return called; } -bool isOption(Context * ctx, Value const & v) +bool isOption(Context * ctx, const Value & v) { if (v.type != tAttrs) { return false; } - auto const & actual_type = v.attrs->find(ctx->underscore_type); + const auto & actual_type = v.attrs->find(ctx->underscore_type); if (actual_type == v.attrs->end()) { return false; } @@ -149,7 +149,7 @@ bool isOption(Context * ctx, Value const & v) // These are needed for paths like: // fileSystems."/".fsType // systemd.units."dbus.service".text -std::string quoteAttribute(std::string const & attribute) +std::string quoteAttribute(const std::string & attribute) { if (isVarName(attribute)) { return attribute; @@ -159,7 +159,7 @@ std::string quoteAttribute(std::string const & attribute) return buf.str(); } -std::string const appendPath(std::string const & prefix, std::string const & suffix) +const std::string appendPath(const std::string & prefix, const std::string & suffix) { if (prefix.empty()) { return quoteAttribute(suffix); @@ -169,8 +169,8 @@ std::string const appendPath(std::string const & prefix, std::string const & suf 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) +void recurse(const std::function)> & f, + Context * ctx, Value v, const std::string & path) { std::variant evaluated; try { @@ -184,11 +184,11 @@ void recurse(const std::function(evaluated)) { return; } - Value const & evaluated_value = std::get(evaluated); + const Value & evaluated_value = std::get(evaluated); if (evaluated_value.type != tAttrs) { return; } - for (auto const & child : evaluated_value.attrs->lexicographicOrder()) { + for (const auto & child : evaluated_value.attrs->lexicographicOrder()) { if (forbiddenRecursionName(child->name)) { continue; } @@ -197,10 +197,10 @@ void recurse(const std::function & f, Context * ctx, Value root) +void mapOptions(const std::function & f, Context * ctx, Value root) { recurse( - [f, ctx](std::string const & path, std::variant v) { + [f, ctx](const std::string & path, std::variant v) { bool isOpt = std::holds_alternative(v) || isOption(ctx, std::get(v)); if (isOpt) { f(path); @@ -232,8 +232,8 @@ void mapOptions(const std::function & f, Context // ... // users.users.systemd-timesync = ... .. ... void mapConfigValuesInOption( - const std::function v)> & f, - std::string const & path, Context * ctx) + const std::function v)> & f, + const std::string & path, Context * ctx) { Value * option; try { @@ -243,7 +243,7 @@ void mapConfigValuesInOption( return; } recurse( - [f, ctx](std::string const & path, std::variant v) { + [f, ctx](const std::string & path, std::variant v) { bool leaf = std::holds_alternative(v) || std::get(v).type != tAttrs || ctx->state->isDerivation(std::get(v)); if (!leaf) { @@ -255,7 +255,7 @@ void mapConfigValuesInOption( ctx, *option, path); } -std::string describeError(Error const & e) { return "«error: " + e.msg() + "»"; } +std::string describeError(const Error & e) { return "«error: " + e.msg() + "»"; } void describeDerivation(Context * ctx, Out & out, Value v) { @@ -270,7 +270,7 @@ void describeDerivation(Context * ctx, Out & out, Value v) } } -Value parseAndEval(EvalState * state, std::string const & expression, std::string const & path) +Value parseAndEval(EvalState * state, const std::string & expression, const std::string & path) { Value v{}; state->eval(state->parseExprFromString(expression, absPath(path)), v); @@ -278,7 +278,7 @@ Value parseAndEval(EvalState * state, std::string const & expression, std::strin } void printValue(Context * ctx, Out & out, std::variant maybe_value, - std::string const & path); + const std::string & path); void printList(Context * ctx, Out & out, Value & v) { @@ -289,7 +289,7 @@ void printList(Context * ctx, Out & out, Value & v) } } -void printAttrs(Context * ctx, Out & out, Value & v, std::string const & path) +void printAttrs(Context * ctx, Out & out, Value & v, const std::string & path) { Out attrs_out(out, "{", "}", v.attrs->size()); for (const auto & a : v.attrs->lexicographicOrder()) { @@ -300,7 +300,7 @@ void printAttrs(Context * ctx, Out & out, Value & v, std::string const & path) } } -void multiLineStringEscape(Out & out, std::string const & s) +void multiLineStringEscape(Out & out, const std::string & s) { int i; for (i = 1; i < s.size(); i++) { @@ -319,7 +319,7 @@ void multiLineStringEscape(Out & out, std::string const & s) } } -void printMultiLineString(Out & out, Value const & v) +void printMultiLineString(Out & out, const Value & v) { std::string s = v.string.s; Out str_out(out, "''", "''", Out::MULTI_LINE); @@ -336,7 +336,7 @@ void printMultiLineString(Out & out, Value const & v) } } -void printValue(Context * ctx, Out & out, std::variant maybe_value, std::string const & path) +void printValue(Context * ctx, Out & out, std::variant maybe_value, const std::string & path) { try { if (std::holds_alternative(maybe_value)) { @@ -373,7 +373,7 @@ void printValue(Context * ctx, Out & out, std::variant v) +void printConfigValue(Context * ctx, Out & out, const std::string & path, std::variant v) { out << path << " = "; printValue(ctx, out, std::move(v), path); @@ -383,9 +383,9 @@ void printConfigValue(Context * ctx, Out & out, std::string const & path, std::v void printAll(Context * ctx, Out & out) { mapOptions( - [ctx, &out](std::string const & option_path) { + [ctx, &out](const std::string & option_path) { mapConfigValuesInOption( - [ctx, &out](std::string const & config_path, std::variant v) { + [ctx, &out](const std::string & config_path, std::variant v) { printConfigValue(ctx, out, config_path, v); }, option_path, ctx); @@ -393,7 +393,7 @@ void printAll(Context * ctx, Out & out) ctx, ctx->options_root); } -void printAttr(Context * ctx, Out & out, std::string const & path, Value * root) +void printAttr(Context * ctx, Out & out, const std::string & path, Value * root) { try { printValue(ctx, out, *findAlongAttrPath(*ctx->state, path, *ctx->autoArgs, *root), path); @@ -402,7 +402,7 @@ void printAttr(Context * ctx, Out & out, std::string const & path, Value * root) } } -void printOption(Context * ctx, Out & out, std::string const & path, Value * option) +void printOption(Context * ctx, Out & out, const std::string & path, Value * option) { out << "Value:\n"; printAttr(ctx, out, path, &ctx->config_root); @@ -440,10 +440,10 @@ void printListing(Out & out, Value * v) } } -bool optionTypeIs(Context * ctx, Value & v, std::string const & sought_type) +bool optionTypeIs(Context * ctx, Value & v, const std::string & sought_type) { try { - auto const & type_lookup = v.attrs->find(ctx->state->sType); + const auto & type_lookup = v.attrs->find(ctx->state->sType); if (type_lookup == v.attrs->end()) { return false; } @@ -451,7 +451,7 @@ bool optionTypeIs(Context * ctx, Value & v, std::string const & sought_type) if (type.type != tAttrs) { return false; } - auto const & name_lookup = type.attrs->find(ctx->state->sName); + const auto & name_lookup = type.attrs->find(ctx->state->sName); if (name_lookup == type.attrs->end()) { return false; } @@ -481,13 +481,13 @@ Value getSubOptions(Context * ctx, Value & option) // 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) +Value findAlongOptionPath(Context * ctx, const std::string & 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; + const auto & attr = *i; v = evaluateValue(ctx, &v); if (attr.empty()) { throw Error("empty attribute name in selection path '%s'", path); @@ -503,7 +503,7 @@ Value findAlongOptionPath(Context * ctx, std::string const & path) throw Error("attribute '%s' in path '%s' attempts to index a value that should be a set but is %s", attr, path, showType(v)); } else { - auto const & next = v.attrs->find(ctx->state->symbols.create(attr)); + const auto & next = v.attrs->find(ctx->state->symbols.create(attr)); if (next == v.attrs->end()) { throw Error("attribute '%s' in path '%s' not found", attr, path); } @@ -513,7 +513,7 @@ Value findAlongOptionPath(Context * ctx, std::string const & path) return v; } -void printOne(Context * ctx, Out & out, std::string const & path) +void printOne(Context * ctx, Out & out, const std::string & path) { try { Value option = findAlongOptionPath(ctx, path); @@ -588,7 +588,7 @@ int main(int argc, char ** argv) if (args.empty()) { printOne(&ctx, out, ""); } - for (auto const & arg : args) { + for (const auto & arg : args) { printOne(&ctx, out, arg); } } -- cgit 1.4.1 From aa8e1d5f1e44d5b24538f4b105b9323bd586be61 Mon Sep 17 00:00:00 2001 From: Chuck Date: Mon, 16 Sep 2019 08:39:20 -0700 Subject: Always say which path component had trouble --- .../installer/tools/nixos-option/nixos-option.cc | 48 ++++++++++++---------- 1 file changed, 27 insertions(+), 21 deletions(-) (limited to 'nixos/modules') diff --git a/nixos/modules/installer/tools/nixos-option/nixos-option.cc b/nixos/modules/installer/tools/nixos-option/nixos-option.cc index 79a58e510afc..fc9315423dd0 100644 --- a/nixos/modules/installer/tools/nixos-option/nixos-option.cc +++ b/nixos/modules/installer/tools/nixos-option/nixos-option.cc @@ -31,6 +31,7 @@ using nix::absPath; using nix::Bindings; using nix::Error; +using nix::EvalError; using nix::EvalState; using nix::Path; using nix::PathSet; @@ -465,12 +466,14 @@ bool optionTypeIs(Context * ctx, Value & v, const std::string & sought_type) } } +MakeError(OptionPathError, EvalError); + Value getSubOptions(Context * ctx, Value & option) { Value getSubOptions = evaluateValue(ctx, findAlongAttrPath(*ctx->state, "type.getSubOptions", *ctx->autoArgs, option)); if (getSubOptions.type != tLambda) { - throw Error("Option's type.getSubOptions isn't a function"); + throw OptionPathError("Option's type.getSubOptions isn't a function"); } Value emptyString{}; nix::mkString(emptyString, ""); @@ -486,28 +489,31 @@ Value findAlongOptionPath(Context * ctx, const std::string & 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(); const auto & attr = *i; - v = evaluateValue(ctx, &v); - if (attr.empty()) { - throw Error("empty attribute name in selection path '%s'", path); - } - if (isOption(ctx, v) && optionTypeIs(ctx, v, "submodule")) { - v = getSubOptions(ctx, v); - } - if (isOption(ctx, v) && optionTypeIs(ctx, v, "loaOf") && !last_attribute) { - v = getSubOptions(ctx, v); - // Note that we've consumed attr, but didn't actually use it. This is the path component that's looked up - // in the list or attribute set that doesn't name an option -- the "root" in "users.users.root.name". - } else if (v.type != tAttrs) { - throw Error("attribute '%s' in path '%s' attempts to index a value that should be a set but is %s", attr, - path, showType(v)); - } else { - const auto & next = v.attrs->find(ctx->state->symbols.create(attr)); - if (next == v.attrs->end()) { - throw Error("attribute '%s' in path '%s' not found", attr, path); + try { + bool last_attribute = std::next(i) == tokens.end(); + v = evaluateValue(ctx, &v); + if (attr.empty()) { + throw OptionPathError("empty attribute name"); + } + if (isOption(ctx, v) && optionTypeIs(ctx, v, "submodule")) { + v = getSubOptions(ctx, v); + } + if (isOption(ctx, v) && optionTypeIs(ctx, v, "loaOf") && !last_attribute) { + v = getSubOptions(ctx, v); + // Note that we've consumed attr, but didn't actually use it. This is the path component that's looked + // up in the list or attribute set that doesn't name an option -- the "root" in "users.users.root.name". + } else if (v.type != tAttrs) { + throw OptionPathError("Value is %s while a set was expected", showType(v)); + } else { + const auto & next = v.attrs->find(ctx->state->symbols.create(attr)); + if (next == v.attrs->end()) { + throw OptionPathError("Attribute not found", attr, path); + } + v = *next->value; } - v = *next->value; + } catch (OptionPathError & e) { + throw OptionPathError("At '%s' in path '%s': %s", attr, path, e.msg()); } } return v; -- cgit 1.4.1 From 88183eb484e14eb12aecd2788f6178fe95ec6256 Mon Sep 17 00:00:00 2001 From: Chuck Date: Mon, 16 Sep 2019 08:44:33 -0700 Subject: Per reviewer request, cast the other side. I don't think this matters. As long as one or the other of these is a std::string, I get an operator== that looks at content rather than pointer equality. I picked casting the constant over casting the dynamic thing in hopes that the compiler would have a better chance at optimizing away any runtime cost. Deferring to reviewer. --- nixos/modules/installer/tools/nixos-option/nixos-option.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nixos/modules') diff --git a/nixos/modules/installer/tools/nixos-option/nixos-option.cc b/nixos/modules/installer/tools/nixos-option/nixos-option.cc index fc9315423dd0..536d67c2d09a 100644 --- a/nixos/modules/installer/tools/nixos-option/nixos-option.cc +++ b/nixos/modules/installer/tools/nixos-option/nixos-option.cc @@ -140,7 +140,7 @@ bool isOption(Context * ctx, const Value & v) if (evaluated_type.type != tString) { return false; } - return evaluated_type.string.s == static_cast("option"); + return static_cast(evaluated_type.string.s) == "option"; } catch (Error &) { return false; } -- cgit 1.4.1 From c457766a1f3034eb0ae5e30d7524c05cf4925dea Mon Sep 17 00:00:00 2001 From: Chuck Date: Mon, 16 Sep 2019 09:04:28 -0700 Subject: Use std::get_if --- nixos/modules/installer/tools/nixos-option/nixos-option.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'nixos/modules') diff --git a/nixos/modules/installer/tools/nixos-option/nixos-option.cc b/nixos/modules/installer/tools/nixos-option/nixos-option.cc index 536d67c2d09a..b81342715c29 100644 --- a/nixos/modules/installer/tools/nixos-option/nixos-option.cc +++ b/nixos/modules/installer/tools/nixos-option/nixos-option.cc @@ -340,8 +340,8 @@ void printMultiLineString(Out & out, const Value & v) void printValue(Context * ctx, Out & out, std::variant maybe_value, const std::string & path) { try { - if (std::holds_alternative(maybe_value)) { - std::rethrow_exception(std::get(maybe_value)); + if (auto ex = std::get_if(&maybe_value)) { + std::rethrow_exception(*ex); } Value v = evaluateValue(ctx, &std::get(maybe_value)); if (ctx->state->isDerivation(v)) { -- cgit 1.4.1 From c967e3fd3e2a4f311dc5f6676fff1c1266b20663 Mon Sep 17 00:00:00 2001 From: Chuck Date: Mon, 16 Sep 2019 09:10:29 -0700 Subject: Hold state and autoArgs by reference Switch from convention "appease clang-tidy --checks='*'" to "References are like non-nullptr pointers". The clang-tidy check "google-runtime-references" complains about non-const reference arguments, but this is not a convention used in Nix. --- .../installer/tools/nixos-option/nixos-option.cc | 50 +++++++++++----------- 1 file changed, 25 insertions(+), 25 deletions(-) (limited to 'nixos/modules') diff --git a/nixos/modules/installer/tools/nixos-option/nixos-option.cc b/nixos/modules/installer/tools/nixos-option/nixos-option.cc index b81342715c29..4c8dc1ec42c3 100644 --- a/nixos/modules/installer/tools/nixos-option/nixos-option.cc +++ b/nixos/modules/installer/tools/nixos-option/nixos-option.cc @@ -104,12 +104,12 @@ Out::Out(Out & o, const std::string & start, const std::string & end, LinePolicy // Stuff needed for evaluation struct Context { - Context(EvalState * state, Bindings * autoArgs, Value options_root, Value config_root) + 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")) + underscore_type(state.symbols.create("_type")) {} - EvalState * state; - Bindings * autoArgs; + EvalState & state; + Bindings & autoArgs; Value options_root; Value config_root; Symbol underscore_type; @@ -117,12 +117,12 @@ struct Context Value evaluateValue(Context * ctx, Value * v) { - ctx->state->forceValue(*v); - if (ctx->autoArgs->empty()) { + ctx->state.forceValue(*v); + if (ctx->autoArgs.empty()) { return *v; } Value called{}; - ctx->state->autoCallFunction(*ctx->autoArgs, *v, called); + ctx->state.autoCallFunction(ctx->autoArgs, *v, called); return called; } @@ -238,7 +238,7 @@ void mapConfigValuesInOption( { Value * option; try { - option = findAlongAttrPath(*ctx->state, path, *ctx->autoArgs, ctx->config_root); + option = findAlongAttrPath(ctx->state, path, ctx->autoArgs, ctx->config_root); } catch (Error &) { f(path, std::current_exception()); return; @@ -246,7 +246,7 @@ void mapConfigValuesInOption( recurse( [f, ctx](const std::string & path, std::variant v) { bool leaf = std::holds_alternative(v) || std::get(v).type != tAttrs || - ctx->state->isDerivation(std::get(v)); + ctx->state.isDerivation(std::get(v)); if (!leaf) { return true; // Keep digging } @@ -261,20 +261,20 @@ std::string describeError(const Error & 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); + 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) : "???"; + 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, const std::string & expression, const std::string & path) +Value parseAndEval(EvalState & state, const std::string & expression, const std::string & path) { Value v{}; - state->eval(state->parseExprFromString(expression, absPath(path)), v); + state.eval(state.parseExprFromString(expression, absPath(path)), v); return v; } @@ -344,7 +344,7 @@ void printValue(Context * ctx, Out & out, std::variant(maybe_value)); - if (ctx->state->isDerivation(v)) { + if (ctx->state.isDerivation(v)) { describeDerivation(ctx, out, v); } else if (v.isList()) { printList(ctx, out, v); @@ -353,7 +353,7 @@ void printValue(Context * ctx, Out & out, std::variantstate->forceValueDeep(v); + ctx->state.forceValueDeep(v); out << v; } } catch (ThrownError & e) { @@ -397,7 +397,7 @@ void printAll(Context * ctx, Out & out) void printAttr(Context * ctx, Out & out, const std::string & path, Value * root) { try { - printValue(ctx, out, *findAlongAttrPath(*ctx->state, path, *ctx->autoArgs, *root), path); + printValue(ctx, out, *findAlongAttrPath(ctx->state, path, ctx->autoArgs, *root), path); } catch (Error & e) { out << describeError(e); } @@ -444,7 +444,7 @@ void printListing(Out & out, Value * v) bool optionTypeIs(Context * ctx, Value & v, const std::string & sought_type) { try { - const auto & type_lookup = v.attrs->find(ctx->state->sType); + const auto & type_lookup = v.attrs->find(ctx->state.sType); if (type_lookup == v.attrs->end()) { return false; } @@ -452,7 +452,7 @@ bool optionTypeIs(Context * ctx, Value & v, const std::string & sought_type) if (type.type != tAttrs) { return false; } - const auto & name_lookup = type.attrs->find(ctx->state->sName); + const auto & name_lookup = type.attrs->find(ctx->state.sName); if (name_lookup == type.attrs->end()) { return false; } @@ -471,14 +471,14 @@ MakeError(OptionPathError, EvalError); Value getSubOptions(Context * ctx, Value & option) { Value getSubOptions = - evaluateValue(ctx, findAlongAttrPath(*ctx->state, "type.getSubOptions", *ctx->autoArgs, option)); + evaluateValue(ctx, findAlongAttrPath(ctx->state, "type.getSubOptions", ctx->autoArgs, option)); if (getSubOptions.type != tLambda) { throw OptionPathError("Option's type.getSubOptions isn't a function"); } Value emptyString{}; nix::mkString(emptyString, ""); Value v; - ctx->state->callFunction(getSubOptions, emptyString, v, nix::Pos{}); + ctx->state.callFunction(getSubOptions, emptyString, v, nix::Pos{}); return v; } @@ -506,7 +506,7 @@ Value findAlongOptionPath(Context * ctx, const std::string & path) } else if (v.type != tAttrs) { throw OptionPathError("Value is %s while a set was expected", showType(v)); } else { - const auto & next = v.attrs->find(ctx->state->symbols.create(attr)); + const auto & next = v.attrs->find(ctx->state.symbols.create(attr)); if (next == v.attrs->end()) { throw OptionPathError("Attribute not found", attr, path); } @@ -579,10 +579,10 @@ int main(int argc, char ** argv) 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); + Value options_root = parseAndEval(*state, options_expr, path); + Value config_root = parseAndEval(*state, config_expr, path); - Context ctx{state.get(), myArgs.getAutoArgs(*state), options_root, config_root}; + Context ctx{*state, *myArgs.getAutoArgs(*state), options_root, config_root}; Out out(std::cout); if (all) { @@ -599,7 +599,7 @@ int main(int argc, char ** argv) } } - ctx.state->printStats(); + ctx.state.printStats(); return 0; } -- cgit 1.4.1 From 3d3ce8df7f29418c28ba02d28927e1a52f6db1e9 Mon Sep 17 00:00:00 2001 From: Chuck Date: Mon, 16 Sep 2019 09:19:13 -0700 Subject: Pass Context by reference Switch from convention "appease clang-tidy --checks='*'" to "References are like non-nullptr pointers". The clang-tidy check "google-runtime-references" complains about non-const reference arguments, but this is not a convention used in Nix. --- .../installer/tools/nixos-option/nixos-option.cc | 87 +++++++++++----------- 1 file changed, 43 insertions(+), 44 deletions(-) (limited to 'nixos/modules') diff --git a/nixos/modules/installer/tools/nixos-option/nixos-option.cc b/nixos/modules/installer/tools/nixos-option/nixos-option.cc index 4c8dc1ec42c3..bdcfffb47afb 100644 --- a/nixos/modules/installer/tools/nixos-option/nixos-option.cc +++ b/nixos/modules/installer/tools/nixos-option/nixos-option.cc @@ -115,23 +115,23 @@ struct Context Symbol underscore_type; }; -Value evaluateValue(Context * ctx, Value * v) +Value evaluateValue(Context & ctx, Value * v) { - ctx->state.forceValue(*v); - if (ctx->autoArgs.empty()) { + ctx.state.forceValue(*v); + if (ctx.autoArgs.empty()) { return *v; } Value called{}; - ctx->state.autoCallFunction(ctx->autoArgs, *v, called); + ctx.state.autoCallFunction(ctx.autoArgs, *v, called); return called; } -bool isOption(Context * ctx, const Value & v) +bool isOption(Context & ctx, const Value & v) { if (v.type != tAttrs) { return false; } - const auto & actual_type = v.attrs->find(ctx->underscore_type); + const auto & actual_type = v.attrs->find(ctx.underscore_type); if (actual_type == v.attrs->end()) { return false; } @@ -171,7 +171,7 @@ const std::string appendPath(const std::string & prefix, const std::string & suf bool forbiddenRecursionName(std::string name) { return (!name.empty() && name[0] == '_') || name == "haskellPackages"; } void recurse(const std::function)> & f, - Context * ctx, Value v, const std::string & path) + Context & ctx, Value v, const std::string & path) { std::variant evaluated; try { @@ -198,10 +198,10 @@ void recurse(const std::function & f, Context * ctx, Value root) +void mapOptions(const std::function & f, Context & ctx, Value root) { recurse( - [f, ctx](const std::string & path, std::variant v) { + [f, &ctx](const std::string & path, std::variant v) { bool isOpt = std::holds_alternative(v) || isOption(ctx, std::get(v)); if (isOpt) { f(path); @@ -234,11 +234,11 @@ void mapOptions(const std::function & f, Context // users.users.systemd-timesync = ... .. ... void mapConfigValuesInOption( const std::function v)> & f, - const std::string & path, Context * ctx) + const std::string & path, Context & ctx) { Value * option; try { - option = findAlongAttrPath(ctx->state, path, ctx->autoArgs, ctx->config_root); + option = findAlongAttrPath(ctx.state, path, ctx.autoArgs, ctx.config_root); } catch (Error &) { f(path, std::current_exception()); return; @@ -246,7 +246,7 @@ void mapConfigValuesInOption( recurse( [f, ctx](const std::string & path, std::variant v) { bool leaf = std::holds_alternative(v) || std::get(v).type != tAttrs || - ctx->state.isDerivation(std::get(v)); + ctx.state.isDerivation(std::get(v)); if (!leaf) { return true; // Keep digging } @@ -258,13 +258,13 @@ void mapConfigValuesInOption( std::string describeError(const Error & e) { return "«error: " + e.msg() + "»"; } -void describeDerivation(Context * ctx, Out & out, Value v) +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); + 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) : "???"; + Path drvPath = i != v.attrs->end() ? ctx.state.coerceToPath(*i->pos, *i->value, pathset) : "???"; out << "«derivation " << drvPath << "»"; } catch (Error & e) { out << describeError(e); @@ -278,10 +278,10 @@ Value parseAndEval(EvalState & state, const std::string & expression, const std: return v; } -void printValue(Context * ctx, Out & out, std::variant maybe_value, +void printValue(Context & ctx, Out & out, std::variant maybe_value, const std::string & path); -void printList(Context * ctx, Out & out, Value & v) +void printList(Context & ctx, Out & out, Value & v) { Out list_out(out, "[", "]", v.listSize()); for (unsigned int n = 0; n < v.listSize(); ++n) { @@ -290,7 +290,7 @@ void printList(Context * ctx, Out & out, Value & v) } } -void printAttrs(Context * ctx, Out & out, Value & v, const std::string & path) +void printAttrs(Context & ctx, Out & out, Value & v, const std::string & path) { Out attrs_out(out, "{", "}", v.attrs->size()); for (const auto & a : v.attrs->lexicographicOrder()) { @@ -337,14 +337,14 @@ void printMultiLineString(Out & out, const Value & v) } } -void printValue(Context * ctx, Out & out, std::variant maybe_value, const std::string & path) +void printValue(Context & ctx, Out & out, std::variant maybe_value, const std::string & path) { try { if (auto ex = std::get_if(&maybe_value)) { std::rethrow_exception(*ex); } Value v = evaluateValue(ctx, &std::get(maybe_value)); - if (ctx->state.isDerivation(v)) { + if (ctx.state.isDerivation(v)) { describeDerivation(ctx, out, v); } else if (v.isList()) { printList(ctx, out, v); @@ -353,7 +353,7 @@ void printValue(Context * ctx, Out & out, std::variantstate.forceValueDeep(v); + ctx.state.forceValueDeep(v); out << v; } } catch (ThrownError & e) { @@ -374,39 +374,39 @@ void printValue(Context * ctx, Out & out, std::variant v) +void printConfigValue(Context & ctx, Out & out, const std::string & path, std::variant v) { out << path << " = "; printValue(ctx, out, std::move(v), path); out << ";\n"; } -void printAll(Context * ctx, Out & out) +void printAll(Context & ctx, Out & out) { mapOptions( - [ctx, &out](const std::string & option_path) { + [&ctx, &out](const std::string & option_path) { mapConfigValuesInOption( - [ctx, &out](const std::string & config_path, std::variant v) { + [&ctx, &out](const std::string & config_path, std::variant v) { printConfigValue(ctx, out, config_path, v); }, option_path, ctx); }, - ctx, ctx->options_root); + ctx, ctx.options_root); } -void printAttr(Context * ctx, Out & out, const std::string & path, Value * root) +void printAttr(Context & ctx, Out & out, const std::string & path, Value * root) { try { - printValue(ctx, out, *findAlongAttrPath(ctx->state, path, ctx->autoArgs, *root), path); + printValue(ctx, out, *findAlongAttrPath(ctx.state, path, ctx.autoArgs, *root), path); } catch (Error & e) { out << describeError(e); } } -void printOption(Context * ctx, Out & out, const std::string & path, Value * option) +void printOption(Context & ctx, Out & out, const std::string & path, Value * option) { out << "Value:\n"; - printAttr(ctx, out, path, &ctx->config_root); + printAttr(ctx, out, path, &ctx.config_root); out << "\n\nDefault:\n"; printAttr(ctx, out, "default", option); @@ -441,10 +441,10 @@ void printListing(Out & out, Value * v) } } -bool optionTypeIs(Context * ctx, Value & v, const std::string & sought_type) +bool optionTypeIs(Context & ctx, Value & v, const std::string & sought_type) { try { - const auto & type_lookup = v.attrs->find(ctx->state.sType); + const auto & type_lookup = v.attrs->find(ctx.state.sType); if (type_lookup == v.attrs->end()) { return false; } @@ -452,7 +452,7 @@ bool optionTypeIs(Context * ctx, Value & v, const std::string & sought_type) if (type.type != tAttrs) { return false; } - const auto & name_lookup = type.attrs->find(ctx->state.sName); + const auto & name_lookup = type.attrs->find(ctx.state.sName); if (name_lookup == type.attrs->end()) { return false; } @@ -468,26 +468,25 @@ bool optionTypeIs(Context * ctx, Value & v, const std::string & sought_type) MakeError(OptionPathError, EvalError); -Value getSubOptions(Context * ctx, Value & option) +Value getSubOptions(Context & ctx, Value & option) { - Value getSubOptions = - evaluateValue(ctx, findAlongAttrPath(ctx->state, "type.getSubOptions", ctx->autoArgs, option)); + Value getSubOptions = evaluateValue(ctx, findAlongAttrPath(ctx.state, "type.getSubOptions", ctx.autoArgs, option)); if (getSubOptions.type != tLambda) { throw OptionPathError("Option's type.getSubOptions isn't a function"); } Value emptyString{}; nix::mkString(emptyString, ""); Value v; - ctx->state.callFunction(getSubOptions, emptyString, v, nix::Pos{}); + ctx.state.callFunction(getSubOptions, emptyString, v, nix::Pos{}); return v; } // Carefully walk an option path, looking for sub-options when a path walks past // an option value. -Value findAlongOptionPath(Context * ctx, const std::string & path) +Value findAlongOptionPath(Context & ctx, const std::string & path) { Strings tokens = parseAttrPath(path); - Value v = ctx->options_root; + Value v = ctx.options_root; for (auto i = tokens.begin(); i != tokens.end(); i++) { const auto & attr = *i; try { @@ -506,7 +505,7 @@ Value findAlongOptionPath(Context * ctx, const std::string & path) } else if (v.type != tAttrs) { throw OptionPathError("Value is %s while a set was expected", showType(v)); } else { - const auto & next = v.attrs->find(ctx->state.symbols.create(attr)); + const auto & next = v.attrs->find(ctx.state.symbols.create(attr)); if (next == v.attrs->end()) { throw OptionPathError("Attribute not found", attr, path); } @@ -519,7 +518,7 @@ Value findAlongOptionPath(Context * ctx, const std::string & path) return v; } -void printOne(Context * ctx, Out & out, const std::string & path) +void printOne(Context & ctx, Out & out, const std::string & path) { try { Value option = findAlongOptionPath(ctx, path); @@ -589,13 +588,13 @@ int main(int argc, char ** argv) if (!args.empty()) { throw UsageError("--all cannot be used with arguments"); } - printAll(&ctx, out); + printAll(ctx, out); } else { if (args.empty()) { - printOne(&ctx, out, ""); + printOne(ctx, out, ""); } for (const auto & arg : args) { - printOne(&ctx, out, arg); + printOne(ctx, out, arg); } } -- cgit 1.4.1 From 94a068fe36f8b369071d8185f584d31923f7b00e Mon Sep 17 00:00:00 2001 From: Chuck Date: Mon, 16 Sep 2019 09:24:26 -0700 Subject: Pass values by reference Switch from convention "appease clang-tidy --checks='*'" to "References are like non-nullptr pointers". The clang-tidy check "google-runtime-references" complains about non-const reference arguments, but this is not a convention used in Nix. --- .../installer/tools/nixos-option/nixos-option.cc | 40 +++++++++++----------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'nixos/modules') diff --git a/nixos/modules/installer/tools/nixos-option/nixos-option.cc b/nixos/modules/installer/tools/nixos-option/nixos-option.cc index bdcfffb47afb..5fd8f69d8004 100644 --- a/nixos/modules/installer/tools/nixos-option/nixos-option.cc +++ b/nixos/modules/installer/tools/nixos-option/nixos-option.cc @@ -115,14 +115,14 @@ struct Context Symbol underscore_type; }; -Value evaluateValue(Context & ctx, Value * v) +Value evaluateValue(Context & ctx, Value & v) { - ctx.state.forceValue(*v); + ctx.state.forceValue(v); if (ctx.autoArgs.empty()) { - return *v; + return v; } Value called{}; - ctx.state.autoCallFunction(ctx.autoArgs, *v, called); + ctx.state.autoCallFunction(ctx.autoArgs, v, called); return called; } @@ -136,7 +136,7 @@ bool isOption(Context & ctx, const Value & v) return false; } try { - Value evaluated_type = evaluateValue(ctx, actual_type->value); + Value evaluated_type = evaluateValue(ctx, *actual_type->value); if (evaluated_type.type != tString) { return false; } @@ -175,7 +175,7 @@ void recurse(const std::function evaluated; try { - evaluated = evaluateValue(ctx, &v); + evaluated = evaluateValue(ctx, v); } catch (Error &) { evaluated = std::current_exception(); } @@ -343,7 +343,7 @@ void printValue(Context & ctx, Out & out, std::variant(&maybe_value)) { std::rethrow_exception(*ex); } - Value v = evaluateValue(ctx, &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()) { @@ -394,19 +394,19 @@ void printAll(Context & ctx, Out & out) ctx, ctx.options_root); } -void printAttr(Context & ctx, Out & out, const std::string & path, Value * root) +void printAttr(Context & ctx, Out & out, const std::string & path, Value & root) { try { - printValue(ctx, out, *findAlongAttrPath(ctx.state, path, ctx.autoArgs, *root), path); + printValue(ctx, out, *findAlongAttrPath(ctx.state, path, ctx.autoArgs, root), path); } catch (Error & e) { out << describeError(e); } } -void printOption(Context & ctx, Out & out, const std::string & path, Value * option) +void printOption(Context & ctx, Out & out, const std::string & path, Value & option) { out << "Value:\n"; - printAttr(ctx, out, path, &ctx.config_root); + printAttr(ctx, out, path, ctx.config_root); out << "\n\nDefault:\n"; printAttr(ctx, out, "default", option); @@ -428,12 +428,12 @@ void printOption(Context & ctx, Out & out, const std::string & path, Value * opt out << "\n"; } -void printListing(Out & out, Value * v) +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()) { + for (const auto & a : v.attrs->lexicographicOrder()) { std::string name = a->name; if (!name.empty() && name[0] != '_') { out << name << "\n"; @@ -448,7 +448,7 @@ bool optionTypeIs(Context & ctx, Value & v, const std::string & sought_type) if (type_lookup == v.attrs->end()) { return false; } - Value type = evaluateValue(ctx, type_lookup->value); + Value type = evaluateValue(ctx, *type_lookup->value); if (type.type != tAttrs) { return false; } @@ -456,7 +456,7 @@ bool optionTypeIs(Context & ctx, Value & v, const std::string & sought_type) if (name_lookup == type.attrs->end()) { return false; } - Value name = evaluateValue(ctx, name_lookup->value); + Value name = evaluateValue(ctx, *name_lookup->value); if (name.type != tString) { return false; } @@ -470,7 +470,7 @@ MakeError(OptionPathError, EvalError); Value getSubOptions(Context & ctx, Value & option) { - Value getSubOptions = evaluateValue(ctx, findAlongAttrPath(ctx.state, "type.getSubOptions", ctx.autoArgs, option)); + Value getSubOptions = evaluateValue(ctx, *findAlongAttrPath(ctx.state, "type.getSubOptions", ctx.autoArgs, option)); if (getSubOptions.type != tLambda) { throw OptionPathError("Option's type.getSubOptions isn't a function"); } @@ -491,7 +491,7 @@ Value findAlongOptionPath(Context & ctx, const std::string & path) const auto & attr = *i; try { bool last_attribute = std::next(i) == tokens.end(); - v = evaluateValue(ctx, &v); + v = evaluateValue(ctx, v); if (attr.empty()) { throw OptionPathError("empty attribute name"); } @@ -522,11 +522,11 @@ void printOne(Context & ctx, Out & out, const std::string & path) { try { Value option = findAlongOptionPath(ctx, path); - option = evaluateValue(ctx, &option); + option = evaluateValue(ctx, option); if (isOption(ctx, option)) { - printOption(ctx, out, path, &option); + printOption(ctx, out, path, option); } else { - printListing(out, &option); + printListing(out, option); } } catch (Error & e) { std::cerr << "error: " << e.msg() -- cgit 1.4.1 From 2ddd2d07601d11f31f9bffa61060d680a1708b4c Mon Sep 17 00:00:00 2001 From: Chuck Date: Mon, 16 Sep 2019 09:35:38 -0700 Subject: Explain why header goes on stderr --- nixos/modules/installer/tools/nixos-option/nixos-option.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'nixos/modules') diff --git a/nixos/modules/installer/tools/nixos-option/nixos-option.cc b/nixos/modules/installer/tools/nixos-option/nixos-option.cc index 5fd8f69d8004..174b7a0cbb62 100644 --- a/nixos/modules/installer/tools/nixos-option/nixos-option.cc +++ b/nixos/modules/installer/tools/nixos-option/nixos-option.cc @@ -430,8 +430,8 @@ void printOption(Context & ctx, Out & out, const std::string & path, Value & opt 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. + // Print this header on stderr rather than stdout, presumably to make it + // slightly easier to consume this output in other tools. std::cerr << "This attribute set contains:\n"; for (const auto & a : v.attrs->lexicographicOrder()) { std::string name = a->name; -- cgit 1.4.1 From 84d55716a9899954bc05b000287a54a59ee5aefe Mon Sep 17 00:00:00 2001 From: Chuck Date: Mon, 16 Sep 2019 09:36:00 -0700 Subject: Don't print header on stderr Automated consumers can use 'sed 1d' or similar to remove this header. This probably makes this output *easier* to consume correctly. Having this header show up in consumers' terminal or log output is probably not useful, but hiding it without hiding all error messages would have been more troublesome that just stripping it from stdout. I.e., previously, unsophisticated use would show undesired output: $ some-other-tool This attribute set contains: This attribute set contains: This attribute set contains: This attribute set contains: The simplest way to hide this undesired output would have been nixos-option ... 2>/dev/null, which would hide all error messages. We do not wish to encourage that. Correct use would have been something like: nixos-option ... 2> >( grep --line-buffered -v 'This attribute set contains:') After this change, correct use is simpler: nixos-option ... | sed 1d or nixos-option ... | sed '1/This attribute set contains:/d' if the caller don't know if this invocation of nixos-option will yield an attribute listing or an option description. --- nixos/modules/installer/tools/nixos-option/nixos-option.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'nixos/modules') diff --git a/nixos/modules/installer/tools/nixos-option/nixos-option.cc b/nixos/modules/installer/tools/nixos-option/nixos-option.cc index 174b7a0cbb62..2b95f9c98333 100644 --- a/nixos/modules/installer/tools/nixos-option/nixos-option.cc +++ b/nixos/modules/installer/tools/nixos-option/nixos-option.cc @@ -430,9 +430,7 @@ void printOption(Context & ctx, Out & out, const std::string & path, Value & opt void printListing(Out & out, Value & v) { - // Print this header on stderr rather than stdout, presumably to make it - // slightly easier to consume this output in other tools. - std::cerr << "This attribute set contains:\n"; + out << "This attribute set contains:\n"; for (const auto & a : v.attrs->lexicographicOrder()) { std::string name = a->name; if (!name.empty() && name[0] != '_') { -- cgit 1.4.1 From 4d17d5b31f196416ee4be50b0f7b125966ea210f Mon Sep 17 00:00:00 2001 From: Chuck Date: Mon, 16 Sep 2019 09:56:07 -0700 Subject: snake_case -> camelCase --- .../installer/tools/nixos-option/nixos-option.cc | 115 ++++++++++----------- 1 file changed, 57 insertions(+), 58 deletions(-) (limited to 'nixos/modules') diff --git a/nixos/modules/installer/tools/nixos-option/nixos-option.cc b/nixos/modules/installer/tools/nixos-option/nixos-option.cc index 2b95f9c98333..58d66bad1c65 100644 --- a/nixos/modules/installer/tools/nixos-option/nixos-option.cc +++ b/nixos/modules/installer/tools/nixos-option/nixos-option.cc @@ -56,7 +56,7 @@ class Out ONE_LINE, MULTI_LINE }; - explicit Out(std::ostream & ostream) : ostream(ostream), policy(ONE_LINE), write_since_sep(true) {} + explicit Out(std::ostream & ostream) : ostream(ostream), policy(ONE_LINE), writeSinceSep(true) {} Out(Out & o, const std::string & start, const std::string & end, LinePolicy policy); Out(Out & o, const std::string & start, const std::string & end, int count) : Out(o, start, end, count < 2 ? ONE_LINE : MULTI_LINE) @@ -72,16 +72,16 @@ class Out std::string indentation; std::string end; LinePolicy policy; - bool write_since_sep; + bool writeSinceSep; 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) { + if (!o.writeSinceSep && o.policy == Out::MULTI_LINE) { o.ostream << o.indentation; } - o.write_since_sep = true; + o.writeSinceSep = true; o.ostream << thing; return o; } @@ -89,13 +89,13 @@ template Out & operator<<(Out & o, T thing) template <> Out & operator<<(Out & o, Out::Separator /* thing */) { o.ostream << (o.policy == Out::ONE_LINE ? " " : "\n"); - o.write_since_sep = false; + o.writeSinceSep = false; return o; } Out::Out(Out & o, const std::string & start, const std::string & 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) + end(policy == ONE_LINE ? end : o.indentation + end), policy(policy), writeSinceSep(true) { o << start; *this << Out::sep; @@ -104,15 +104,15 @@ Out::Out(Out & o, const std::string & start, const std::string & end, LinePolicy // 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")) + Context(EvalState & state, Bindings & autoArgs, Value optionsRoot, Value configRoot) + : state(state), autoArgs(autoArgs), optionsRoot(optionsRoot), configRoot(configRoot), + underscoreType(state.symbols.create("_type")) {} EvalState & state; Bindings & autoArgs; - Value options_root; - Value config_root; - Symbol underscore_type; + Value optionsRoot; + Value configRoot; + Symbol underscoreType; }; Value evaluateValue(Context & ctx, Value & v) @@ -131,16 +131,16 @@ bool isOption(Context & ctx, const Value & v) if (v.type != tAttrs) { return false; } - const auto & actual_type = v.attrs->find(ctx.underscore_type); - if (actual_type == v.attrs->end()) { + const auto & atualType = v.attrs->find(ctx.underscoreType); + if (atualType == v.attrs->end()) { return false; } try { - Value evaluated_type = evaluateValue(ctx, *actual_type->value); - if (evaluated_type.type != tString) { + Value evaluatedType = evaluateValue(ctx, *atualType->value); + if (evaluatedType.type != tString) { return false; } - return static_cast(evaluated_type.string.s) == "option"; + return static_cast(evaluatedType.string.s) == "option"; } catch (Error &) { return false; } @@ -238,7 +238,7 @@ void mapConfigValuesInOption( { Value * option; try { - option = findAlongAttrPath(ctx.state, path, ctx.autoArgs, ctx.config_root); + option = findAlongAttrPath(ctx.state, path, ctx.autoArgs, ctx.configRoot); } catch (Error &) { f(path, std::current_exception()); return; @@ -278,26 +278,25 @@ Value parseAndEval(EvalState & state, const std::string & expression, const std: return v; } -void printValue(Context & ctx, Out & out, std::variant maybe_value, - const std::string & path); +void printValue(Context & ctx, Out & out, std::variant maybeValue, const std::string & path); void printList(Context & ctx, Out & out, Value & v) { - Out list_out(out, "[", "]", v.listSize()); + Out listOut(out, "[", "]", v.listSize()); for (unsigned int n = 0; n < v.listSize(); ++n) { - printValue(ctx, list_out, *v.listElems()[n], ""); - list_out << Out::sep; + printValue(ctx, listOut, *v.listElems()[n], ""); + listOut << Out::sep; } } void printAttrs(Context & ctx, Out & out, Value & v, const std::string & path) { - Out attrs_out(out, "{", "}", v.attrs->size()); + Out attrsOut(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; + attrsOut << name << " = "; + printValue(ctx, attrsOut, *a->value, appendPath(path, name)); + attrsOut << ";" << Out::sep; } } @@ -323,27 +322,27 @@ void multiLineStringEscape(Out & out, const std::string & s) void printMultiLineString(Out & out, const Value & v) { std::string s = v.string.s; - Out str_out(out, "''", "''", Out::MULTI_LINE); + Out strOut(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)); + multiLineStringEscape(strOut, s.substr(begin, s.size() - begin)); break; } - multiLineStringEscape(str_out, s.substr(begin, end - begin)); - str_out << Out::sep; + multiLineStringEscape(strOut, s.substr(begin, end - begin)); + strOut << Out::sep; begin = end + 1; } } -void printValue(Context & ctx, Out & out, std::variant maybe_value, const std::string & path) +void printValue(Context & ctx, Out & out, std::variant maybeValue, const std::string & path) { try { - if (auto ex = std::get_if(&maybe_value)) { + if (auto ex = std::get_if(&maybeValue)) { std::rethrow_exception(*ex); } - Value v = evaluateValue(ctx, std::get(maybe_value)); + Value v = evaluateValue(ctx, std::get(maybeValue)); if (ctx.state.isDerivation(v)) { describeDerivation(ctx, out, v); } else if (v.isList()) { @@ -384,14 +383,14 @@ void printConfigValue(Context & ctx, Out & out, const std::string & path, std::v void printAll(Context & ctx, Out & out) { mapOptions( - [&ctx, &out](const std::string & option_path) { + [&ctx, &out](const std::string & optionPath) { mapConfigValuesInOption( - [&ctx, &out](const std::string & config_path, std::variant v) { - printConfigValue(ctx, out, config_path, v); + [&ctx, &out](const std::string & configPath, std::variant v) { + printConfigValue(ctx, out, configPath, v); }, - option_path, ctx); + optionPath, ctx); }, - ctx, ctx.options_root); + ctx, ctx.optionsRoot); } void printAttr(Context & ctx, Out & out, const std::string & path, Value & root) @@ -406,7 +405,7 @@ void printAttr(Context & ctx, Out & out, const std::string & path, Value & root) void printOption(Context & ctx, Out & out, const std::string & path, Value & option) { out << "Value:\n"; - printAttr(ctx, out, path, ctx.config_root); + printAttr(ctx, out, path, ctx.configRoot); out << "\n\nDefault:\n"; printAttr(ctx, out, "default", option); @@ -439,26 +438,26 @@ void printListing(Out & out, Value & v) } } -bool optionTypeIs(Context & ctx, Value & v, const std::string & sought_type) +bool optionTypeIs(Context & ctx, Value & v, const std::string & soughtType) { try { - const auto & type_lookup = v.attrs->find(ctx.state.sType); - if (type_lookup == v.attrs->end()) { + const auto & typeLookup = v.attrs->find(ctx.state.sType); + if (typeLookup == v.attrs->end()) { return false; } - Value type = evaluateValue(ctx, *type_lookup->value); + Value type = evaluateValue(ctx, *typeLookup->value); if (type.type != tAttrs) { return false; } - const auto & name_lookup = type.attrs->find(ctx.state.sName); - if (name_lookup == type.attrs->end()) { + const auto & nameLookup = type.attrs->find(ctx.state.sName); + if (nameLookup == type.attrs->end()) { return false; } - Value name = evaluateValue(ctx, *name_lookup->value); + Value name = evaluateValue(ctx, *nameLookup->value); if (name.type != tString) { return false; } - return name.string.s == sought_type; + return name.string.s == soughtType; } catch (Error &) { return false; } @@ -484,11 +483,11 @@ Value getSubOptions(Context & ctx, Value & option) Value findAlongOptionPath(Context & ctx, const std::string & path) { Strings tokens = parseAttrPath(path); - Value v = ctx.options_root; + Value v = ctx.optionsRoot; for (auto i = tokens.begin(); i != tokens.end(); i++) { const auto & attr = *i; try { - bool last_attribute = std::next(i) == tokens.end(); + bool lastAttribute = std::next(i) == tokens.end(); v = evaluateValue(ctx, v); if (attr.empty()) { throw OptionPathError("empty attribute name"); @@ -496,7 +495,7 @@ Value findAlongOptionPath(Context & ctx, const std::string & path) if (isOption(ctx, v) && optionTypeIs(ctx, v, "submodule")) { v = getSubOptions(ctx, v); } - if (isOption(ctx, v) && optionTypeIs(ctx, v, "loaOf") && !last_attribute) { + if (isOption(ctx, v) && optionTypeIs(ctx, v, "loaOf") && !lastAttribute) { v = getSubOptions(ctx, v); // Note that we've consumed attr, but didn't actually use it. This is the path component that's looked // up in the list or attribute set that doesn't name an option -- the "root" in "users.users.root.name". @@ -538,8 +537,8 @@ 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::string optionsExpr = "(import {}).options"; + std::string configExpr = "(import {}).config"; std::vector args; struct MyArgs : nix::LegacyArgs, nix::MixEvalArgs @@ -557,9 +556,9 @@ int main(int argc, char ** argv) } else if (*arg == "--path") { path = nix::getArg(*arg, arg, end); } else if (*arg == "--options_expr") { - options_expr = nix::getArg(*arg, arg, end); + optionsExpr = nix::getArg(*arg, arg, end); } else if (*arg == "--config_expr") { - config_expr = nix::getArg(*arg, arg, end); + configExpr = nix::getArg(*arg, arg, end); } else if (!arg->empty() && arg->at(0) == '-') { return false; } else { @@ -576,10 +575,10 @@ int main(int argc, char ** argv) auto store = nix::openStore(); auto state = std::make_unique(myArgs.searchPath, store); - Value options_root = parseAndEval(*state, options_expr, path); - Value config_root = parseAndEval(*state, config_expr, path); + Value optionsRoot = parseAndEval(*state, optionsExpr, path); + Value configRoot = parseAndEval(*state, configExpr, path); - Context ctx{*state, *myArgs.getAutoArgs(*state), options_root, config_root}; + Context ctx{*state, *myArgs.getAutoArgs(*state), optionsRoot, configRoot}; Out out(std::cout); if (all) { -- cgit 1.4.1 From 56462408700a39bf49d130a862570ebf48b8e17c Mon Sep 17 00:00:00 2001 From: Chuck Date: Mon, 16 Sep 2019 10:01:40 -0700 Subject: Only print example when there is one --- .../modules/installer/tools/nixos-option/nixos-option.cc | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'nixos/modules') diff --git a/nixos/modules/installer/tools/nixos-option/nixos-option.cc b/nixos/modules/installer/tools/nixos-option/nixos-option.cc index 58d66bad1c65..3261b263c2f2 100644 --- a/nixos/modules/installer/tools/nixos-option/nixos-option.cc +++ b/nixos/modules/installer/tools/nixos-option/nixos-option.cc @@ -402,6 +402,15 @@ void printAttr(Context & ctx, Out & out, const std::string & path, Value & root) } } +bool has_example(Context & ctx, Value & option) { + try { + findAlongAttrPath(ctx.state, "example", ctx.autoArgs, option); + return true; + } catch (Error &) { + return false; + } +} + void printOption(Context & ctx, Out & out, const std::string & path, Value & option) { out << "Value:\n"; @@ -413,8 +422,10 @@ void printOption(Context & ctx, Out & out, const std::string & path, Value & opt out << "\n\nType:\n"; printAttr(ctx, out, "type.description", option); - out << "\n\nExample:\n"; - printAttr(ctx, out, "example", option); + if (has_example(ctx, option)) { + out << "\n\nExample:\n"; + printAttr(ctx, out, "example", option); + } out << "\n\nDescription:\n"; printAttr(ctx, out, "description", option); -- cgit 1.4.1 From 57a5752300c3157fe0c2ddea06f694bc78e9ba91 Mon Sep 17 00:00:00 2001 From: Chuck Date: Mon, 16 Sep 2019 10:35:51 -0700 Subject: Add maintainer --- maintainers/maintainer-list.nix | 6 ++++++ nixos/modules/installer/tools/nixos-option/default.nix | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'nixos/modules') diff --git a/maintainers/maintainer-list.nix b/maintainers/maintainer-list.nix index 1f2cdda41d16..e73e99b47b4b 100644 --- a/maintainers/maintainer-list.nix +++ b/maintainers/maintainer-list.nix @@ -1194,6 +1194,12 @@ githubId = 30435868; name = "Okina Matara"; }; + chkno = { + email = "chuck@intelligence.org"; + github = "chkno"; + githubId = 1118859; + name = "Scott Worley"; + }; choochootrain = { email = "hurshal@imap.cc"; github = "choochootrain"; diff --git a/nixos/modules/installer/tools/nixos-option/default.nix b/nixos/modules/installer/tools/nixos-option/default.nix index 2c2674ad28d2..753fd92c7bbf 100644 --- a/nixos/modules/installer/tools/nixos-option/default.nix +++ b/nixos/modules/installer/tools/nixos-option/default.nix @@ -1,4 +1,4 @@ -{stdenv, boost, cmake, pkgconfig, nix, ... }: +{lib, stdenv, boost, cmake, pkgconfig, nix, ... }: stdenv.mkDerivation rec { name = "nixos-option"; src = ./.; @@ -6,5 +6,6 @@ stdenv.mkDerivation rec { buildInputs = [ boost nix ]; meta = { license = stdenv.lib.licenses.lgpl2Plus; + maintainers = with lib.maintainers; [ chkno ]; }; } -- cgit 1.4.1 From a3e31df4d779943cd462a36d63bb88cc4c3c66ed Mon Sep 17 00:00:00 2001 From: Chuck Date: Tue, 17 Sep 2019 17:36:26 -0700 Subject: (clang-format for has_example) --- .../modules/installer/tools/nixos-option/nixos-option.cc | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'nixos/modules') diff --git a/nixos/modules/installer/tools/nixos-option/nixos-option.cc b/nixos/modules/installer/tools/nixos-option/nixos-option.cc index 3261b263c2f2..778b7e326170 100644 --- a/nixos/modules/installer/tools/nixos-option/nixos-option.cc +++ b/nixos/modules/installer/tools/nixos-option/nixos-option.cc @@ -402,13 +402,14 @@ void printAttr(Context & ctx, Out & out, const std::string & path, Value & root) } } -bool has_example(Context & ctx, Value & option) { - try { - findAlongAttrPath(ctx.state, "example", ctx.autoArgs, option); - return true; - } catch (Error &) { - return false; - } +bool has_example(Context & ctx, Value & option) +{ + try { + findAlongAttrPath(ctx.state, "example", ctx.autoArgs, option); + return true; + } catch (Error &) { + return false; + } } void printOption(Context & ctx, Out & out, const std::string & path, Value & option) -- cgit 1.4.1 From 445145d5b9a33a9ded5a6928c52ddaeb862a8a8e Mon Sep 17 00:00:00 2001 From: Chuck Date: Tue, 17 Sep 2019 17:36:48 -0700 Subject: Support aggregate types attrsOf and listOf --- nixos/modules/installer/tools/nixos-option/nixos-option.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'nixos/modules') diff --git a/nixos/modules/installer/tools/nixos-option/nixos-option.cc b/nixos/modules/installer/tools/nixos-option/nixos-option.cc index 778b7e326170..c0c9ec0e5b4c 100644 --- a/nixos/modules/installer/tools/nixos-option/nixos-option.cc +++ b/nixos/modules/installer/tools/nixos-option/nixos-option.cc @@ -475,6 +475,11 @@ bool optionTypeIs(Context & ctx, Value & v, const std::string & soughtType) } } +bool isAggregateOptionType(Context & ctx, Value & v) +{ + return optionTypeIs(ctx, v, "attrsOf") || optionTypeIs(ctx, v, "listOf") || optionTypeIs(ctx, v, "loaOf"); +} + MakeError(OptionPathError, EvalError); Value getSubOptions(Context & ctx, Value & option) @@ -507,7 +512,7 @@ Value findAlongOptionPath(Context & ctx, const std::string & path) if (isOption(ctx, v) && optionTypeIs(ctx, v, "submodule")) { v = getSubOptions(ctx, v); } - if (isOption(ctx, v) && optionTypeIs(ctx, v, "loaOf") && !lastAttribute) { + if (isOption(ctx, v) && isAggregateOptionType(ctx, v) && !lastAttribute) { v = getSubOptions(ctx, v); // Note that we've consumed attr, but didn't actually use it. This is the path component that's looked // up in the list or attribute set that doesn't name an option -- the "root" in "users.users.root.name". -- cgit 1.4.1 From 1e7985942b4f156d20ce2ddac9fc133a9091ed5b Mon Sep 17 00:00:00 2001 From: Chuck Date: Fri, 20 Sep 2019 13:37:12 -0700 Subject: snake_case -> camelCase --- nixos/modules/installer/tools/nixos-option/nixos-option.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'nixos/modules') diff --git a/nixos/modules/installer/tools/nixos-option/nixos-option.cc b/nixos/modules/installer/tools/nixos-option/nixos-option.cc index c0c9ec0e5b4c..9b92dc829cd1 100644 --- a/nixos/modules/installer/tools/nixos-option/nixos-option.cc +++ b/nixos/modules/installer/tools/nixos-option/nixos-option.cc @@ -402,7 +402,7 @@ void printAttr(Context & ctx, Out & out, const std::string & path, Value & root) } } -bool has_example(Context & ctx, Value & option) +bool hasExample(Context & ctx, Value & option) { try { findAlongAttrPath(ctx.state, "example", ctx.autoArgs, option); @@ -423,7 +423,7 @@ void printOption(Context & ctx, Out & out, const std::string & path, Value & opt out << "\n\nType:\n"; printAttr(ctx, out, "type.description", option); - if (has_example(ctx, option)) { + if (hasExample(ctx, option)) { out << "\n\nExample:\n"; printAttr(ctx, out, "example", option); } -- cgit 1.4.1