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:
parent
b068f96b92
commit
dc4a280318
6 changed files with 80 additions and 10 deletions
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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";
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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(); }
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue