1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-20 09:19:36 +01:00

Allow overring module options from the command line

E.g.

  $ nix build github:tweag/nix-ux/configs?dir=configs#hello --argstr who Everybody
  $ ./result/bin/hello
  Hello Everybody

This works by generating a new flake that imports the specified one
and sets the specified module options.
This commit is contained in:
Eelco Dolstra 2020-09-24 22:55:30 +02:00
parent b068f96b92
commit dc4a280318
6 changed files with 80 additions and 10 deletions

View file

@ -78,7 +78,7 @@ struct CmdBundle : InstallableCommand
auto bundler = InstallableFlake( auto bundler = InstallableFlake(
evalState, std::move(bundlerFlakeRef), evalState, std::move(bundlerFlakeRef),
Strings{bundlerName == "" ? "defaultBundler" : bundlerName}, Strings{bundlerName == "" ? "defaultBundler" : bundlerName},
Strings({"bundlers."}), lockFlags); Strings({"bundlers."}), lockFlags, nullptr);
Value * arg = evalState->allocValue(); Value * arg = evalState->allocValue();
evalState->mkAttrs(*arg, 2); evalState->mkAttrs(*arg, 2);

View file

@ -395,7 +395,8 @@ struct CmdDevelop : Common, MixEnvironment
installable->nixpkgsFlakeRef(), installable->nixpkgsFlakeRef(),
Strings{"bashInteractive"}, Strings{"bashInteractive"},
Strings{"legacyPackages." + settings.thisSystem.get() + "."}, Strings{"legacyPackages." + settings.thisSystem.get() + "."},
lockFlags); lockFlags,
nullptr);
shell = state->store->printStorePath( shell = state->store->printStorePath(
toStorePath(state->store, Realise::Outputs, OperateOn::Output, bashInstallable)) + "/bin/bash"; toStorePath(state->store, Realise::Outputs, OperateOn::Output, bashInstallable)) + "/bin/bash";

View file

@ -563,7 +563,7 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand
auto installable = InstallableFlake( auto installable = InstallableFlake(
evalState, std::move(templateFlakeRef), evalState, std::move(templateFlakeRef),
Strings{templateName == "" ? "defaultTemplate" : templateName}, Strings{templateName == "" ? "defaultTemplate" : templateName},
Strings(attrsPathPrefixes), lockFlags); Strings(attrsPathPrefixes), lockFlags, nullptr);
auto [cursor, attrPath] = installable.getCursor(*evalState); auto [cursor, attrPath] = installable.getCursor(*evalState);

View file

@ -13,6 +13,8 @@
#include "url.hh" #include "url.hh"
#include "registry.hh" #include "registry.hh"
#include "../cpptoml/cpptoml.h"
#include <regex> #include <regex>
#include <queue> #include <queue>
@ -549,8 +551,61 @@ InstallableFlake::getCursors(EvalState & state)
std::shared_ptr<flake::LockedFlake> InstallableFlake::getLockedFlake() const std::shared_ptr<flake::LockedFlake> InstallableFlake::getLockedFlake() const
{ {
if (!_lockedFlake) if (!_lockedFlake) {
_lockedFlake = std::make_shared<flake::LockedFlake>(lockFlake(*state, flakeRef, lockFlags)); _lockedFlake = std::make_shared<flake::LockedFlake>(lockFlake(*state, flakeRef, lockFlags));
if (options && options->size()) {
/* Get the modules defined by this flake. */
auto cache = openEvalCache(*state, _lockedFlake);
auto root = cache->getRoot();
auto aModules = root->maybeGetAttr(state->symbols.create("modules"));
if (!aModules)
throw Error("flake '%s' has no modules, so --arg cannot override anything", flakeRef);
auto toml = cpptoml::make_table();
auto base = cpptoml::make_table();
base->insert("type", "path");
base->insert("path", _lockedFlake->flake.sourceInfo->actualPath);
if (_lockedFlake->flake.lockedRef.subdir != "")
base->insert("dir", _lockedFlake->flake.lockedRef.subdir);
// FIXME: copy rev etc.
auto inputs = cpptoml::make_table();
inputs->insert("base", base);
toml->insert("inputs", inputs);
for (auto & moduleName : aModules->getAttrs()) {
auto module = cpptoml::make_table();
auto extends = cpptoml::make_array();
extends->push_back("base#" + (std::string) moduleName);
module->insert("extends", extends);
for (auto & option : options->lexicographicOrder()) {
state->forceValue(*option->value);
if (option->value->type == tString)
module->insert(option->name, state->forceString(*option->value));
else if (option->value->type == tInt)
module->insert(option->name, option->value->integer);
else
throw Error("option '%s' is %s which is not supported",
option->name, showType(*option->value));
}
toml->insert(moduleName, module);
}
auto tempDir = createTempDir();
AutoDelete cleanup(tempDir);
std::ostringstream str;
str << *toml;
debug("writing temporary flake:\n%s", str.str());
writeFile(tempDir + "/nix.toml", str.str());
_lockedFlake = std::make_shared<flake::LockedFlake>(lockFlake(*state,
parseFlakeRef("path://" + tempDir), lockFlags));
}
}
return _lockedFlake; return _lockedFlake;
} }
@ -600,10 +655,14 @@ std::vector<std::shared_ptr<Installable>> SourceExprCommand::parseInstallables(
try { try {
auto [flakeRef, fragment] = parseFlakeRefWithFragment(s, absPath(".")); auto [flakeRef, fragment] = parseFlakeRefWithFragment(s, absPath("."));
auto state = getEvalState();
result.push_back(std::make_shared<InstallableFlake>( result.push_back(std::make_shared<InstallableFlake>(
getEvalState(), std::move(flakeRef), state,
std::move(flakeRef),
fragment == "" ? getDefaultFlakeAttrPaths() : Strings{fragment}, fragment == "" ? getDefaultFlakeAttrPaths() : Strings{fragment},
getDefaultFlakeAttrPathPrefixes(), lockFlags)); getDefaultFlakeAttrPathPrefixes(),
lockFlags,
getAutoArgs(*state)));
continue; continue;
} catch (...) { } catch (...) {
ex = std::current_exception(); ex = std::current_exception();

View file

@ -98,11 +98,17 @@ struct InstallableFlake : InstallableValue
Strings prefixes; Strings prefixes;
const flake::LockFlags & lockFlags; const flake::LockFlags & lockFlags;
mutable std::shared_ptr<flake::LockedFlake> _lockedFlake; mutable std::shared_ptr<flake::LockedFlake> _lockedFlake;
Bindings * options;
InstallableFlake(ref<EvalState> state, FlakeRef && flakeRef, InstallableFlake(
Strings && attrPaths, Strings && prefixes, const flake::LockFlags & lockFlags) ref<EvalState> state,
FlakeRef && flakeRef,
Strings && attrPaths,
Strings && prefixes, const
flake::LockFlags & lockFlags,
Bindings * options)
: InstallableValue(state), flakeRef(flakeRef), attrPaths(attrPaths), : InstallableValue(state), flakeRef(flakeRef), attrPaths(attrPaths),
prefixes(prefixes), lockFlags(lockFlags) prefixes(prefixes), lockFlags(lockFlags), options(options)
{ } { }
std::string what() override { return flakeRef.to_string() + "#" + *attrPaths.begin(); } std::string what() override { return flakeRef.to_string() + "#" + *attrPaths.begin(); }

View file

@ -342,7 +342,11 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf
Activity act(*logger, lvlChatty, actUnknown, Activity act(*logger, lvlChatty, actUnknown,
fmt("checking '%s' for updates", element.source->attrPath)); fmt("checking '%s' for updates", element.source->attrPath));
InstallableFlake installable(getEvalState(), FlakeRef(element.source->originalRef), {element.source->attrPath}, {}, lockFlags); InstallableFlake installable(
getEvalState(),
FlakeRef(element.source->originalRef),
{element.source->attrPath},
{}, lockFlags, nullptr);
auto [attrPath, resolvedRef, drv] = installable.toDerivation(); auto [attrPath, resolvedRef, drv] = installable.toDerivation();