Skip to content

Commit

Permalink
Allow nix.conf options to be set in flake.nix
Browse files Browse the repository at this point in the history
This makes it possible to have per-project configuration in flake.nix,
e.g. binary caches and other stuff:

  nixConfig.bash-prompt-suffix = "�[1;35mngi# �[0m";
  nixConfig.substituters = [ "https://cache.ngi0.nixos.org/" ];
  • Loading branch information
edolstra committed Oct 26, 2020
1 parent 731edf0 commit 343239f
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 6 deletions.
70 changes: 66 additions & 4 deletions src/libexpr/flake/flake.cc
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,17 @@ static std::tuple<fetchers::Tree, FlakeRef, FlakeRef> fetchOrSubstituteTree(
return {std::move(tree), resolvedRef, lockedRef};
}

static void expectType(EvalState & state, ValueType type,
Value & value, const Pos & pos)
static void forceTrivialValue(EvalState & state, Value & value, const Pos & pos)
{
if (value.type == tThunk && value.isTrivial())
state.forceValue(value, pos);
}


static void expectType(EvalState & state, ValueType type,
Value & value, const Pos & pos)
{
forceTrivialValue(state, value, pos);
if (value.type != type)
throw Error("expected %s but got %s at %s",
showType(type), showType(value.type), pos);
Expand Down Expand Up @@ -114,7 +120,6 @@ static FlakeInput parseFlakeInput(EvalState & state,
expectType(state, tString, *attr.value, *attr.pos);
input.follows = parseInputPath(attr.value->string.s);
} else {
state.forceValue(*attr.value);
if (attr.value->type == tString)
attrs.emplace(attr.name, attr.value->string.s);
else
Expand Down Expand Up @@ -223,10 +228,41 @@ static Flake getFlake(
} else
throw Error("flake '%s' lacks attribute 'outputs'", lockedRef);

auto sNixConfig = state.symbols.create("nixConfig");

if (auto nixConfig = vInfo.attrs->get(sNixConfig)) {
expectType(state, tAttrs, *nixConfig->value, *nixConfig->pos);

for (auto & option : *nixConfig->value->attrs) {
forceTrivialValue(state, *option.value, *option.pos);
if (option.value->type == tString)
flake.config.options.insert({option.name, state.forceStringNoCtx(*option.value, *option.pos)});
else if (option.value->type == tInt)
flake.config.options.insert({option.name, state.forceInt(*option.value, *option.pos)});
else if (option.value->type == tBool)
flake.config.options.insert({option.name, state.forceBool(*option.value, *option.pos)});
else if (option.value->isList()) {
std::vector<std::string> ss;
for (unsigned int n = 0; n < option.value->listSize(); ++n) {
auto elem = option.value->listElems()[n];
if (elem->type != tString)
throw TypeError("list element in flake configuration option '%s' is %s while a string is expected",
option.name, showType(*option.value));
ss.push_back(state.forceStringNoCtx(*elem, *option.pos));
}
flake.config.options.insert({option.name, ss});
}
else
throw TypeError("flake configuration option '%s' is %s",
option.name, showType(*option.value));
}
}

for (auto & attr : *vInfo.attrs) {
if (attr.name != state.sDescription &&
attr.name != sInputs &&
attr.name != sOutputs)
attr.name != sOutputs &&
attr.name != sNixConfig)
throw Error("flake '%s' has an unsupported attribute '%s', at %s",
lockedRef, attr.name, *attr.pos);
}
Expand Down Expand Up @@ -599,4 +635,30 @@ Fingerprint LockedFlake::getFingerprint() const

Flake::~Flake() { }

void ConfigFile::apply()
{
for (auto & [name, value] : options) {
// FIXME: support 'trusted-public-keys' (and other options), but make it TOFU.

This comment has been minimized.

Copy link
@blaggacao

blaggacao Jan 20, 2021

Contributor

Is the current workaround nix --option require-sigs false ...? Lack of this currently makes for some awkward UX: it readily asks to trust those (and persist the trust), but then seems to just silently not work — no hint about why.

if (name != "bash-prompt-suffix" &&
name != "bash-prompt" &&
name != "substituters" &&
name != "extra-substituters")
{
warn("ignoring untrusted flake configuration option '%s'", name);
continue;
}
// FIXME: Move into libutil/config.cc.
if (auto s = std::get_if<std::string>(&value))
globalConfig.set(name, *s);
else if (auto n = std::get_if<int64_t>(&value))
globalConfig.set(name, fmt("%d", n));
else if (auto b = std::get_if<Explicit<bool>>(&value))
globalConfig.set(name, b->t ? "true" : "false");
else if (auto ss = std::get_if<std::vector<std::string>>(&value))
globalConfig.set(name, concatStringsSep(" ", *ss)); // FIXME: evil
else
assert(false);
}
}

}
11 changes: 10 additions & 1 deletion src/libexpr/flake/flake.hh
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,16 @@ struct FlakeInput
FlakeInputs overrides;
};

// The Flake structure is the main internal representation of a flake.nix file.
struct ConfigFile
{
using ConfigValue = std::variant<std::string, int64_t, Explicit<bool>, std::vector<std::string>>;

std::map<std::string, ConfigValue> options;

void apply();
};

/* The contents of a flake.nix file. */
struct Flake
{
FlakeRef originalRef; // the original flake specification (by the user)
Expand All @@ -57,6 +65,7 @@ struct Flake
std::optional<std::string> description;
std::shared_ptr<const fetchers::Tree> sourceInfo;
FlakeInputs inputs;
ConfigFile config; // 'nixConfig' attribute
~Flake();
};

Expand Down
5 changes: 4 additions & 1 deletion src/nix/installables.cc
Original file line number Diff line number Diff line change
Expand Up @@ -533,8 +533,11 @@ InstallableFlake::getCursors(EvalState & state)

std::shared_ptr<flake::LockedFlake> InstallableFlake::getLockedFlake() const
{
if (!_lockedFlake)
if (!_lockedFlake) {
_lockedFlake = std::make_shared<flake::LockedFlake>(lockFlake(*state, flakeRef, lockFlags));
_lockedFlake->flake.config.apply();
// FIXME: send new config to the daemon.

This comment has been minimized.

Copy link
@Kha

Kha Nov 19, 2020

Contributor

Do I understand this FIXME correctly in that setting e.g. nixConfig.substituters will not do anything on a multi-user install yet?

This comment has been minimized.

Copy link
@edolstra

edolstra Nov 20, 2020

Author Member

Yes, that's correct.

This comment has been minimized.

Copy link
@Radvendii

Radvendii Nov 5, 2021

Contributor

Fixed in #5504

}
return _lockedFlake;
}

Expand Down

1 comment on commit 343239f

@nixos-discourse
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This commit has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/bundling-binary-caches-into-flakes/12486/2

Please sign in to comment.