aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr/flake
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2020-10-26 20:45:39 +0100
committerEelco Dolstra <edolstra@gmail.com>2020-10-26 20:45:39 +0100
commit343239fc8a1993f707a990c2cd54a41f1fa3de99 (patch)
tree2c301b436ef4bc58b1ce3fec3225a2285dc7dbca /src/libexpr/flake
parent731edf0d9be27d1a64c9645595c7efba31dde2b1 (diff)
Allow nix.conf options to be set in flake.nix
This makes it possible to have per-project configuration in flake.nix, e.g. binary caches and other stuff: nixConfig.bash-prompt-suffix = "ngi# "; nixConfig.substituters = [ "https://cache.ngi0.nixos.org/" ];
Diffstat (limited to 'src/libexpr/flake')
-rw-r--r--src/libexpr/flake/flake.cc70
-rw-r--r--src/libexpr/flake/flake.hh11
2 files changed, 76 insertions, 5 deletions
diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc
index ca3b185f9..bdcf63c21 100644
--- a/src/libexpr/flake/flake.cc
+++ b/src/libexpr/flake/flake.cc
@@ -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);
@@ -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
@@ -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);
}
@@ -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.
+ 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);
+ }
+}
+
}
diff --git a/src/libexpr/flake/flake.hh b/src/libexpr/flake/flake.hh
index cf62c7741..7eebd9044 100644
--- a/src/libexpr/flake/flake.hh
+++ b/src/libexpr/flake/flake.hh
@@ -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)
@@ -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();
};