nixos-option: fix build against nix 2.24

This commit is contained in:
Jörg Thalheim 2024-11-13 20:37:55 +01:00
parent d13c9db8c3
commit 5f9d2d9572
8 changed files with 115 additions and 157 deletions

View File

@ -1,24 +1,28 @@
{ lib
, stdenv
, boost
, cmake
, pkg-config
, installShellFiles
, nix
{
lib,
stdenv,
boost,
meson,
ninja,
pkg-config,
installShellFiles,
nix,
}:
stdenv.mkDerivation {
name = "nixos-option";
src = ./src;
src = ./.;
postInstall = ''
installManPage ${./nixos-option.8}
installManPage ../nixos-option.8
'';
strictDeps = true;
nativeBuildInputs = [
cmake
meson
ninja
pkg-config
installShellFiles
];
@ -26,9 +30,6 @@ stdenv.mkDerivation {
boost
nix
];
cmakeFlags = [
"-DNIX_DEV_INCLUDEPATH=${nix.dev}/include/nix"
];
meta = with lib; {
license = licenses.lgpl2Plus;

View File

@ -0,0 +1,15 @@
project('nixos-option', 'cpp',
version : '0.1.6',
license : 'GPL-3.0',
)
nix_main_dep = dependency('nix-main', required: true)
nix_store_dep = dependency('nix-store', required: true)
nix_expr_dep = dependency('nix-expr', required: true)
nix_cmd_dep = dependency('nix-cmd', required: true)
nix_flake_dep = dependency('nix-flake', required: true)
threads_dep = dependency('threads', required: true)
nlohmann_json_dep = dependency('nlohmann_json', required: true)
boost_dep = dependency('boost', required: true)
subdir('src')

View File

@ -1,11 +0,0 @@
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_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_20)
install (TARGETS nixos-option DESTINATION bin)

View File

@ -2,79 +2,21 @@
// Since they are not, copy/paste them here.
// TODO: Delete these and use the ones in the library as they become available.
#include <nix/config.h> // for nix/globals.hh's reference to SYSTEM
#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/optional/optional.hpp> // for get_pointer
#include <iostream> // for operator<<, basic_...
#include <nix/types.hh> // for Strings
#include <nix/error.hh> // for Error
#include <string> // for string, basic_string
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("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;
}
#include <nix/print.hh> // for Strings
// From nix/src/nix/repl.cc
bool isVarName(const string & s)
bool isVarName(const std::string_view & s)
{
if (s.size() == 0)
return false;
if (s.size() == 0) return false;
if (nix::isReservedKeyword(s)) return false;
char c = s[0];
if ((c >= '0' && c <= '9') || c == '-' || c == '\'')
return false;
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 == '\''))
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;
}

View File

@ -1,9 +1,5 @@
#pragma once
#include <iostream>
#include <nix/types.hh>
#include <string>
nix::Strings parseAttrPath(const std::string & s);
bool isVarName(const std::string & s);
std::ostream & printStringValue(std::ostream & str, const char * string);
bool isVarName(const std::string_view & s);

View File

@ -0,0 +1,20 @@
src = [
'nixos-option.cc',
'libnix-copy-paste.cc',
]
cc = meson.get_compiler('cpp')
executable('nixos-option', src,
dependencies : [
nix_main_dep,
nix_store_dep,
nix_expr_dep,
nix_cmd_dep,
nix_flake_dep,
boost_dep,
nlohmann_json_dep,
threads_dep
],
install: true,
cpp_args: ['-std=c++2a', '--include', 'nix/config.h'])

View File

@ -1,16 +1,8 @@
#include <nix/config.h> // for nix/globals.hh's reference to SYSTEM
#include <exception> // for exception_ptr, current_exception
#include <functional> // for function
#include <iostream> // for operator<<, basic_ostream, ostrin...
#include <iterator> // for next
#include <list> // for _List_iterator
#include <memory> // for allocator, unique_ptr, make_unique
#include <new> // for operator new
#include <nix/args.hh> // for argvToStrings, UsageError
#include <nix/attr-path.hh> // for findAlongAttrPath
#include <nix/attr-path.hh> // for findAlongAttrPath, parseAttrPath
#include <nix/attr-set.hh> // for Attr, Bindings, Bindings::iterator
#include <nix/common-eval-args.hh> // for MixEvalArgs
#include <nix/eval-gc.hh> // for initGC, initNix
#include <nix/eval-inline.hh> // for EvalState::forceValue
#include <nix/eval.hh> // for EvalState, initGC, operator<<
#include <nix/globals.hh> // for initPlugins, Settings, settings
@ -23,8 +15,6 @@
#include <nix/value.hh> // for Value, Value::(anonymous), Value:...
#include <string> // for string, operator+, operator==
#include <utility> // for move
#include <variant> // for get, holds_alternative, variant
#include <vector> // for vector<>::iterator, vector
#include "libnix-copy-paste.hh"
@ -119,7 +109,7 @@ Out::Out(Out & o, const std::string & start, const std::string & end, LinePolicy
Value evaluateValue(Context & ctx, Value & v)
{
ctx.state.forceValue(v, [&]() { return v.determinePos(nix::noPos); });
ctx.state.forceValue(v, v.determinePos(nix::noPos));
if (ctx.autoArgs.empty()) {
return v;
}
@ -133,8 +123,8 @@ bool isOption(Context & ctx, const Value & v)
if (v.type() != nAttrs) {
return false;
}
const auto & actualType = v.attrs->find(ctx.underscoreType);
if (actualType == v.attrs->end()) {
const auto & actualType = v.attrs()->find(ctx.underscoreType);
if (actualType == v.attrs()->end()) {
return false;
}
try {
@ -142,7 +132,7 @@ bool isOption(Context & ctx, const Value & v)
if (evaluatedType.type() != nString) {
return false;
}
return static_cast<std::string>(evaluatedType.string.s) == "option";
return evaluatedType.string_view() == "option";
} catch (Error &) {
return false;
}
@ -152,17 +142,17 @@ bool isOption(Context & ctx, const Value & v)
// These are needed for paths like:
// fileSystems."/".fsType
// systemd.units."dbus.service".text
std::string quoteAttribute(const std::string & attribute)
std::string quoteAttribute(const std::string_view & attribute)
{
if (isVarName(attribute)) {
return attribute;
return std::string(attribute);
}
std::ostringstream buf;
printStringValue(buf, attribute.c_str());
nix::printLiteralString(buf, attribute);
return buf.str();
}
const std::string appendPath(const std::string & prefix, const std::string & suffix)
const std::string appendPath(const std::string & prefix, const std::string_view & suffix)
{
if (prefix.empty()) {
return quoteAttribute(suffix);
@ -174,7 +164,7 @@ bool forbiddenRecursionName(const nix::Symbol symbol, const nix::SymbolTable & s
// 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];
const std::string_view & name = symbolTable[symbol];
// TODO: figure out why haskellPackages is not recursed here
return (!name.empty() && name[0] == '_') || name == "haskellPackages";
}
@ -198,34 +188,35 @@ void recurse(const std::function<bool(const std::string & path, std::variant<Val
if (evaluated_value.type() != nAttrs) {
return;
}
for (const auto & child : evaluated_value.attrs->lexicographicOrder(ctx.state.symbols)) {
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, ctx.state.symbols[child->name]));
std::string_view name = ctx.state.symbols[child->name];
recurse(f, ctx, *child->value, appendPath(path, name));
}
}
bool optionTypeIs(Context & ctx, Value & v, const std::string & soughtType)
{
try {
const auto & typeLookup = v.attrs->find(ctx.state.sType);
if (typeLookup == v.attrs->end()) {
const auto & typeLookup = v.attrs()->find(ctx.state.sType);
if (typeLookup == v.attrs()->end()) {
return false;
}
Value type = evaluateValue(ctx, *typeLookup->value);
if (type.type() != nAttrs) {
return false;
}
const auto & nameLookup = type.attrs->find(ctx.state.sName);
if (nameLookup == type.attrs->end()) {
const auto & nameLookup = type.attrs()->find(ctx.state.sName);
if (nameLookup == type.attrs()->end()) {
return false;
}
Value name = evaluateValue(ctx, *nameLookup->value);
if (name.type() != nString) {
return false;
}
return name.string.s == soughtType;
return name.string_view() == soughtType;
} catch (Error &) {
return false;
}
@ -242,7 +233,7 @@ Value getSubOptions(Context & ctx, Value & option)
{
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");
throw OptionPathError(ctx.state, "Option's type.getSubOptions isn't a function");
}
Value emptyString{};
emptyString.mkString("");
@ -260,40 +251,40 @@ struct FindAlongOptionPathRet
};
FindAlongOptionPathRet findAlongOptionPath(Context & ctx, const std::string & path)
{
Strings tokens = parseAttrPath(path);
std::vector<Symbol> tokens = nix::parseAttrPath(ctx.state, path);
Value v = ctx.optionsRoot;
std::string processedPath;
for (auto i = tokens.begin(); i != tokens.end(); i++) {
const auto & attr = *i;
const std::string_view attr = ctx.state.symbols[*i];
try {
bool lastAttribute = std::next(i) == tokens.end();
v = evaluateValue(ctx, v);
if (attr.empty()) {
throw OptionPathError("empty attribute name");
throw OptionPathError(ctx.state, "empty attribute name");
}
if (isOption(ctx, v) && optionTypeIs(ctx, v, "submodule")) {
v = getSubOptions(ctx, v);
}
if (isOption(ctx, v) && isAggregateOptionType(ctx, v)) {
auto subOptions = getSubOptions(ctx, v);
if (lastAttribute && subOptions.attrs->empty()) {
if (lastAttribute && subOptions.attrs()->empty()) {
break;
}
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() != nAttrs) {
throw OptionPathError("Value is %s while a set was expected", showType(v));
throw OptionPathError(ctx.state, "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);
const auto & next = v.attrs()->find(ctx.state.symbols.create(attr));
if (next == v.attrs()->end()) {
throw OptionPathError(ctx.state, "Attribute not found", attr, path);
}
v = *next->value;
}
processedPath = appendPath(processedPath, attr);
} catch (OptionPathError & e) {
throw OptionPathError("At '%s' in path '%s': %s", attr, path, e.msg());
throw OptionPathError(ctx.state, "At '%s' in path '%s': %s", attr, path, e.msg());
}
}
return {v, processedPath};
@ -367,21 +358,23 @@ 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 :(
// Copy-pasted from nix/src/nix/repl.cc printDerivation() :(
std::optional<nix::StorePath> storePath = std::nullopt;
if (auto i = v.attrs()->get(ctx.state.sDrvPath)) {
nix::NixStringContext context;
storePath = ctx.state.coerceToStorePath(i->pos, *i->value, context, "while evaluating the drvPath of a derivation");
}
out << "«derivation ";
Bindings::iterator i = v.attrs->find(ctx.state.sDrvPath);
nix::NixStringContext strContext;
if (i != v.attrs->end())
out << ctx.state.store->printStorePath(ctx.state.coerceToStorePath(i->pos, *i->value, strContext, "while evaluating the drvPath of a derivation"));
else
out << "???";
if (storePath) {
out << " " << ctx.state.store->printStorePath(*storePath);
}
out << "»";
}
Value parseAndEval(EvalState & state, const std::string & expression, const std::string & path)
{
Value v{};
state.eval(state.parseExprFromString(expression, nix::SourcePath(nix::CanonPath::fromCwd(path))), v);
state.eval(state.parseExprFromString(expression, state.rootPath(".")), v);
return v;
}
@ -398,10 +391,10 @@ 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(ctx.state.symbols)) {
Out attrsOut(out, "{", "}", v.attrs()->size());
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];
std::string_view name = ctx.state.symbols[a->name];
attrsOut << name << " = ";
printValue(ctx, attrsOut, *a->value, appendPath(path, name));
attrsOut << ";" << Out::sep;
@ -409,9 +402,9 @@ void printAttrs(Context & ctx, Out & out, Value & v, const std::string & path)
}
}
void multiLineStringEscape(Out & out, const std::string & s)
void multiLineStringEscape(Out & out, const std::string_view & s)
{
int i;
size_t i;
for (i = 1; i < s.size(); i++) {
if (s[i - 1] == '$' && s[i] == '{') {
out << "''${";
@ -430,7 +423,7 @@ void multiLineStringEscape(Out & out, const std::string & s)
void printMultiLineString(Out & out, const Value & v)
{
std::string s = v.string.s;
std::string_view s = v.string_view();
Out strOut(out, "''", "''", Out::MULTI_LINE);
std::string::size_type begin = 0;
while (begin < s.size()) {
@ -458,11 +451,11 @@ void printValue(Context & ctx, Out & out, std::variant<Value, std::exception_ptr
printList(ctx, out, v);
} else if (v.type() == nAttrs) {
printAttrs(ctx, out, v, path);
} else if (v.type() == nString && std::string(v.string.s).find('\n') != std::string::npos) {
} else if (v.type() == nString && std::string(v.string_view()).find('\n') != std::string::npos) {
printMultiLineString(out, v);
} else {
ctx.state.forceValueDeep(v);
v.print(ctx.state.symbols, out.ostream);
v.print(ctx.state, out.ostream);
}
} catch (ThrownError & e) {
if (e.msg() == "The option `" + path + "' was accessed but has no value defined. Try setting the option.") {
@ -560,8 +553,8 @@ void printOption(Context & ctx, Out & out, const std::string & path, Value & opt
void printListing(Context & ctx, Out & out, Value & v)
{
out << "This attribute set contains:\n";
for (const auto & a : v.attrs->lexicographicOrder(ctx.state.symbols)) {
const std::string & name = ctx.state.symbols[a->name];
for (const auto & a : v.attrs()->lexicographicOrder(ctx.state.symbols)) {
const std::string_view & name = ctx.state.symbols[a->name];
if (!name.empty() && name[0] != '_') {
out << name << "\n";
}
@ -630,7 +623,11 @@ int main(int argc, char ** argv)
nix::initGC();
nix::settings.readOnlyMode = true;
auto store = nix::openStore();
auto state = std::make_unique<EvalState>(myArgs.searchPath, store);
auto evalStore = myArgs.evalStoreUrl ? nix::openStore(*myArgs.evalStoreUrl)
: nix::openStore();
auto state = nix::make_ref<nix::EvalState>(
myArgs.lookupPath, evalStore, nix::fetchSettings, nix::evalSettings);
Value optionsRoot = parseAndEval(*state, optionsExpr, path);
Value configRoot = parseAndEval(*state, configExpr, path);
@ -646,7 +643,7 @@ int main(int argc, char ** argv)
print(ctx, out, arg);
}
ctx.state.printStats();
ctx.state.maybePrintStats();
return 0;
}

View File

@ -18681,9 +18681,7 @@ with pkgs;
nix-linter = haskell.lib.compose.justStaticExecutables (haskellPackages.nix-linter);
nixos-option = callPackage ../tools/nix/nixos-option {
nix = nixVersions.nix_2_18;
};
nixos-option = callPackage ../tools/nix/nixos-option { };
nix-pin = callPackage ../tools/package-management/nix-pin { };