diff options
-rw-r--r-- | nixos/modules/installer/tools/tools.nix | 8 | ||||
-rw-r--r-- | pkgs/tools/nix/nixos-option/CMakeLists.txt | 5 | ||||
-rw-r--r-- | pkgs/tools/nix/nixos-option/default.nix | 12 | ||||
-rw-r--r-- | pkgs/tools/nix/nixos-option/libnix-copy-paste.cc | 9 | ||||
-rw-r--r-- | pkgs/tools/nix/nixos-option/nixos-option.cc | 101 | ||||
-rw-r--r-- | pkgs/top-level/all-packages.nix | 2 |
6 files changed, 74 insertions, 63 deletions
diff --git a/nixos/modules/installer/tools/tools.nix b/nixos/modules/installer/tools/tools.nix index 1e36d10b391f..54b0f81ee780 100644 --- a/nixos/modules/installer/tools/tools.nix +++ b/nixos/modules/installer/tools/tools.nix @@ -42,10 +42,7 @@ let xserverEnabled = config.services.xserver.enable; }; - nixos-option = - if lib.versionAtLeast (lib.getVersion config.nix.package) "2.4pre" - then null - else pkgs.nixos-option; + inherit (pkgs) nixos-option; nixos-version = makeProg { name = "nixos-version"; @@ -232,9 +229,10 @@ in nixos-install nixos-rebuild nixos-generate-config + nixos-option nixos-version nixos-enter - ] ++ lib.optional (nixos-option != null) nixos-option; + ]; documentation.man.man-db.skipPackages = [ nixos-version ]; diff --git a/pkgs/tools/nix/nixos-option/CMakeLists.txt b/pkgs/tools/nix/nixos-option/CMakeLists.txt index e5834598c4fd..3c2223c535a8 100644 --- a/pkgs/tools/nix/nixos-option/CMakeLists.txt +++ b/pkgs/tools/nix/nixos-option/CMakeLists.txt @@ -1,8 +1,11 @@ cmake_minimum_required (VERSION 2.6) project (nixos-option) +set(NIX_DEV_INCLUDEPATH "" CACHE STRING "path to nix include directory") + add_executable(nixos-option nixos-option.cc libnix-copy-paste.cc) -target_link_libraries(nixos-option PRIVATE -lnixmain -lnixexpr -lnixstore -lnixutil) +target_include_directories(nixos-option PUBLIC "${NIX_DEV_INCLUDEPATH}") +target_link_libraries(nixos-option PRIVATE -lnixmain -lnixexpr -lnixstore -lnixutil -lnixcmd) target_compile_features(nixos-option PRIVATE cxx_std_17) install (TARGETS nixos-option DESTINATION bin) diff --git a/pkgs/tools/nix/nixos-option/default.nix b/pkgs/tools/nix/nixos-option/default.nix index a9cc967d7680..56cb3e130038 100644 --- a/pkgs/tools/nix/nixos-option/default.nix +++ b/pkgs/tools/nix/nixos-option/default.nix @@ -1,14 +1,18 @@ -{lib, stdenv, boost, cmake, pkg-config, nix, ... }: +{ lib, stdenv, boost, cmake, pkg-config, nix }: -stdenv.mkDerivation rec { +stdenv.mkDerivation { name = "nixos-option"; + src = ./.; + strictDeps = true; nativeBuildInputs = [ cmake pkg-config ]; buildInputs = [ boost nix ]; + cmakeFlags = [ "-DNIX_DEV_INCLUDEPATH=${nix.dev}/include/nix" ]; + meta = with lib; { license = licenses.lgpl2Plus; - maintainers = with maintainers; [ chkno ]; - platforms = platforms.all; + maintainers = with maintainers; [ ]; + inherit (nix.meta) platforms; }; } diff --git a/pkgs/tools/nix/nixos-option/libnix-copy-paste.cc b/pkgs/tools/nix/nixos-option/libnix-copy-paste.cc index 875c07da6399..ad6084844e57 100644 --- a/pkgs/tools/nix/nixos-option/libnix-copy-paste.cc +++ b/pkgs/tools/nix/nixos-option/libnix-copy-paste.cc @@ -7,15 +7,12 @@ #include "libnix-copy-paste.hh" #include <boost/format/alt_sstream.hpp> // for basic_altstringbuf... #include <boost/format/alt_sstream_impl.hpp> // for basic_altstringbuf... -#include <boost/format/format_class.hpp> // for basic_format -#include <boost/format/format_fwd.hpp> // for format -#include <boost/format/format_implementation.hpp> // for basic_format::basi... #include <boost/optional/optional.hpp> // for get_pointer #include <iostream> // for operator<<, basic_... -#include <nix/types.hh> // for Strings, Error +#include <nix/types.hh> // for Strings +#include <nix/error.hh> // for Error #include <string> // for string, basic_string -using boost::format; using nix::Error; using nix::Strings; using std::string; @@ -34,7 +31,7 @@ Strings parseAttrPath(const string & s) ++i; while (1) { if (i == s.end()) - throw Error(format("missing closing quote in selection path '%1%'") % s); + throw Error("missing closing quote in selection path '%1%'", s); if (*i == '"') break; cur.push_back(*i++); diff --git a/pkgs/tools/nix/nixos-option/nixos-option.cc b/pkgs/tools/nix/nixos-option/nixos-option.cc index f779d82edbd6..e4f7bff3c662 100644 --- a/pkgs/tools/nix/nixos-option/nixos-option.cc +++ b/pkgs/tools/nix/nixos-option/nixos-option.cc @@ -37,13 +37,26 @@ using nix::Path; using nix::PathSet; using nix::Strings; using nix::Symbol; -using nix::tAttrs; +using nix::nAttrs; using nix::ThrownError; using nix::tLambda; -using nix::tString; +using nix::nString; using nix::UsageError; using nix::Value; +struct Context +{ + 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 optionsRoot; + Value configRoot; + Symbol underscoreType; +}; + // An ostream wrapper to handle nested indentation class Out { @@ -74,6 +87,8 @@ class Out LinePolicy policy; bool writeSinceSep; template <typename T> friend Out & operator<<(Out & o, T thing); + + friend void printValue(Context & ctx, Out & out, std::variant<Value, std::exception_ptr> maybeValue, const std::string & path); }; template <typename T> Out & operator<<(Out & o, T thing) @@ -101,23 +116,10 @@ Out::Out(Out & o, const std::string & start, const std::string & end, LinePolicy *this << Out::sep; } -// Stuff needed for evaluation -struct Context -{ - 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 optionsRoot; - Value configRoot; - Symbol underscoreType; -}; Value evaluateValue(Context & ctx, Value & v) { - ctx.state.forceValue(v); + ctx.state.forceValue(v, v.attrs->pos); if (ctx.autoArgs.empty()) { return v; } @@ -128,7 +130,7 @@ Value evaluateValue(Context & ctx, Value & v) bool isOption(Context & ctx, const Value & v) { - if (v.type != tAttrs) { + if (v.type() != nAttrs) { return false; } const auto & actualType = v.attrs->find(ctx.underscoreType); @@ -137,7 +139,7 @@ bool isOption(Context & ctx, const Value & v) } try { Value evaluatedType = evaluateValue(ctx, *actualType->value); - if (evaluatedType.type != tString) { + if (evaluatedType.type() != nString) { return false; } return static_cast<std::string>(evaluatedType.string.s) == "option"; @@ -168,7 +170,14 @@ const std::string appendPath(const std::string & prefix, const std::string & suf return prefix + "." + quoteAttribute(suffix); } -bool forbiddenRecursionName(std::string name) { return (!name.empty() && name[0] == '_') || name == "haskellPackages"; } +bool forbiddenRecursionName(const nix::Symbol symbol, const nix::SymbolTable & symbolTable) { + // note: this is created from a pointer + // According to standard, it may never point to null, and hence attempts to check against nullptr are not allowed. + // However, at the time of writing, I am not certain about the full implications of the omission of a nullptr check here. + const std::string & name = symbolTable[symbol]; + // TODO: figure out why haskellPackages is not recursed here + return (!name.empty() && name[0] == '_') || name == "haskellPackages"; +} void recurse(const std::function<bool(const std::string & path, std::variant<Value, std::exception_ptr>)> & f, Context & ctx, Value v, const std::string & path) @@ -186,14 +195,14 @@ void recurse(const std::function<bool(const std::string & path, std::variant<Val return; } const Value & evaluated_value = std::get<Value>(evaluated); - if (evaluated_value.type != tAttrs) { + if (evaluated_value.type() != nAttrs) { return; } - for (const auto & child : evaluated_value.attrs->lexicographicOrder()) { - if (forbiddenRecursionName(child->name)) { + for (const auto & child : evaluated_value.attrs->lexicographicOrder(ctx.state.symbols)) { + if (forbiddenRecursionName(child->name, ctx.state.symbols)) { continue; } - recurse(f, ctx, *child->value, appendPath(path, child->name)); + recurse(f, ctx, *child->value, appendPath(path, ctx.state.symbols[child->name])); } } @@ -205,7 +214,7 @@ bool optionTypeIs(Context & ctx, Value & v, const std::string & soughtType) return false; } Value type = evaluateValue(ctx, *typeLookup->value); - if (type.type != tAttrs) { + if (type.type() != nAttrs) { return false; } const auto & nameLookup = type.attrs->find(ctx.state.sName); @@ -213,7 +222,7 @@ bool optionTypeIs(Context & ctx, Value & v, const std::string & soughtType) return false; } Value name = evaluateValue(ctx, *nameLookup->value); - if (name.type != tString) { + if (name.type() != nString) { return false; } return name.string.s == soughtType; @@ -231,14 +240,14 @@ 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) { + Value getSubOptions = evaluateValue(ctx, *findAlongAttrPath(ctx.state, "type.getSubOptions", ctx.autoArgs, option).first); + if (getSubOptions.isLambda()) { throw OptionPathError("Option's type.getSubOptions isn't a function"); } Value emptyString{}; - nix::mkString(emptyString, ""); + emptyString.mkString(""); Value v; - ctx.state.callFunction(getSubOptions, emptyString, v, nix::Pos{}); + ctx.state.callFunction(getSubOptions, emptyString, v, nix::PosIdx{}); return v; } @@ -273,7 +282,7 @@ FindAlongOptionPathRet findAlongOptionPath(Context & ctx, const std::string & pa v = subOptions; // 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) { + } else if (v.type() != nAttrs) { throw OptionPathError("Value is %s while a set was expected", showType(v)); } else { const auto & next = v.attrs->find(ctx.state.symbols.create(attr)); @@ -336,14 +345,14 @@ void mapConfigValuesInOption( { Value * option; try { - option = findAlongAttrPath(ctx.state, path, ctx.autoArgs, ctx.configRoot); + option = findAlongAttrPath(ctx.state, path, ctx.autoArgs, ctx.configRoot).first; } catch (Error &) { f(path, std::current_exception()); return; } recurse( [f, ctx](const std::string & path, std::variant<Value, std::exception_ptr> v) { - bool leaf = std::holds_alternative<std::exception_ptr>(v) || std::get<Value>(v).type != tAttrs || + bool leaf = std::holds_alternative<std::exception_ptr>(v) || std::get<Value>(v).type() != nAttrs || ctx.state.isDerivation(std::get<Value>(v)); if (!leaf) { return true; // Keep digging @@ -362,7 +371,7 @@ void describeDerivation(Context & ctx, Out & out, Value v) 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, "while evaluating the drvPath of a derivation") : "???"; out << "«derivation " << drvPath << "»"; } catch (Error & e) { out << describeError(e); @@ -390,9 +399,9 @@ void printList(Context & ctx, Out & out, Value & v) void printAttrs(Context & ctx, Out & out, Value & v, const std::string & path) { Out attrsOut(out, "{", "}", v.attrs->size()); - for (const auto & a : v.attrs->lexicographicOrder()) { - std::string name = a->name; - if (!forbiddenRecursionName(name)) { + for (const auto & a : v.attrs->lexicographicOrder(ctx.state.symbols)) { + if (!forbiddenRecursionName(a->name, ctx.state.symbols)) { + const std::string name = ctx.state.symbols[a->name]; attrsOut << name << " = "; printValue(ctx, attrsOut, *a->value, appendPath(path, name)); attrsOut << ";" << Out::sep; @@ -447,13 +456,13 @@ void printValue(Context & ctx, Out & out, std::variant<Value, std::exception_ptr describeDerivation(ctx, out, v); } else if (v.isList()) { printList(ctx, out, v); - } else if (v.type == tAttrs) { + } else if (v.type() == nAttrs) { printAttrs(ctx, out, v, path); - } else if (v.type == tString && std::string(v.string.s).find('\n') != std::string::npos) { + } else if (v.type() == nString && std::string(v.string.s).find('\n') != std::string::npos) { printMultiLineString(out, v); } else { ctx.state.forceValueDeep(v); - out << v; + v.print(ctx.state.symbols, out.ostream); } } catch (ThrownError & e) { if (e.msg() == "The option `" + path + "' is used but not defined.") { @@ -505,7 +514,7 @@ void printRecursive(Context & ctx, Out & out, const std::string & path) 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).first, path); } catch (Error & e) { out << describeError(e); } @@ -548,11 +557,11 @@ void printOption(Context & ctx, Out & out, const std::string & path, Value & opt out << "\n"; } -void printListing(Out & out, Value & v) +void printListing(Context & ctx, Out & out, Value & v) { out << "This attribute set contains:\n"; - for (const auto & a : v.attrs->lexicographicOrder()) { - std::string name = a->name; + for (const auto & a : v.attrs->lexicographicOrder(ctx.state.symbols)) { + const std::string & name = ctx.state.symbols[a->name]; if (!name.empty() && name[0] != '_') { out << name << "\n"; } @@ -571,7 +580,7 @@ void printOne(Context & ctx, Out & out, const std::string & path) if (isOption(ctx, option)) { printOption(ctx, out, result.path, option); } else { - printListing(out, option); + printListing(ctx, out, option); } } catch (Error & e) { std::cerr << "error: " << e.msg() @@ -594,7 +603,7 @@ int main(int argc, char ** argv) using nix::LegacyArgs::LegacyArgs; }; - MyArgs myArgs(nix::baseNameOf(argv[0]), [&](Strings::iterator & arg, const Strings::iterator & end) { + MyArgs myArgs(std::string(nix::baseNameOf(argv[0])), [&](Strings::iterator & arg, const Strings::iterator & end) { if (*arg == "--help") { nix::showManPage("nixos-option"); } else if (*arg == "--version") { @@ -617,7 +626,7 @@ int main(int argc, char ** argv) myArgs.parseCmdline(nix::argvToStrings(argc, argv)); - nix::initPlugins(); + nix::initNix(); nix::initGC(); nix::settings.readOnlyMode = true; auto store = nix::openStore(); diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 97c8dd4185d7..1a7fb252bad3 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -39986,7 +39986,7 @@ with pkgs; nix-melt = callPackage ../tools/nix/nix-melt { }; - nixos-option = callPackage ../tools/nix/nixos-option { nix = nixVersions.nix_2_3; }; + nixos-option = callPackage ../tools/nix/nixos-option { }; nix-pin = callPackage ../tools/package-management/nix-pin { }; |