forked from lix-project/lix
Merge pull request #4486 from shlevy/command-plugins-v2
Command plugins
This commit is contained in:
commit
199081ad00
8
doc/manual/src/release-notes/rl-2.4.md
Normal file
8
doc/manual/src/release-notes/rl-2.4.md
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# Release 2.4 (202X-XX-XX)
|
||||||
|
|
||||||
|
- It is now an error to modify the `plugin-files` setting via a
|
||||||
|
command-line flag that appears after the first non-flag argument
|
||||||
|
to any command, including a subcommand to `nix`. For example,
|
||||||
|
`nix-instantiate default.nix --plugin-files ""` must now become
|
||||||
|
`nix-instantiate --plugin-files "" default.nix`.
|
||||||
|
- Plugins that add new `nix` subcommands are now actually respected.
|
|
@ -53,6 +53,9 @@ static int main_build_remote(int argc, char * * argv)
|
||||||
unsetenv("DISPLAY");
|
unsetenv("DISPLAY");
|
||||||
unsetenv("SSH_ASKPASS");
|
unsetenv("SSH_ASKPASS");
|
||||||
|
|
||||||
|
/* If we ever use the common args framework, make sure to
|
||||||
|
remove initPlugins below and initialize settings first.
|
||||||
|
*/
|
||||||
if (argc != 2)
|
if (argc != 2)
|
||||||
throw UsageError("called without required arguments");
|
throw UsageError("called without required arguments");
|
||||||
|
|
||||||
|
|
|
@ -79,4 +79,11 @@ MixCommonArgs::MixCommonArgs(const string & programName)
|
||||||
hiddenCategories.insert(cat);
|
hiddenCategories.insert(cat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MixCommonArgs::initialFlagsProcessed()
|
||||||
|
{
|
||||||
|
initPlugins();
|
||||||
|
pluginsInited();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,14 @@ namespace nix {
|
||||||
//static constexpr auto commonArgsCategory = "Miscellaneous common options";
|
//static constexpr auto commonArgsCategory = "Miscellaneous common options";
|
||||||
static constexpr auto loggingCategory = "Logging-related options";
|
static constexpr auto loggingCategory = "Logging-related options";
|
||||||
|
|
||||||
struct MixCommonArgs : virtual Args
|
class MixCommonArgs : public virtual Args
|
||||||
{
|
{
|
||||||
|
void initialFlagsProcessed() override;
|
||||||
|
public:
|
||||||
string programName;
|
string programName;
|
||||||
MixCommonArgs(const string & programName);
|
MixCommonArgs(const string & programName);
|
||||||
|
protected:
|
||||||
|
virtual void pluginsInited() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MixDryRun : virtual Args
|
struct MixDryRun : virtual Args
|
||||||
|
|
|
@ -243,8 +243,17 @@ void MaxBuildJobsSetting::set(const std::string & str, bool append)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PluginFilesSetting::set(const std::string & str, bool append)
|
||||||
|
{
|
||||||
|
if (pluginsLoaded)
|
||||||
|
throw UsageError("plugin-files set after plugins were loaded, you may need to move the flag before the subcommand");
|
||||||
|
BaseSetting<Paths>::set(str, append);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void initPlugins()
|
void initPlugins()
|
||||||
{
|
{
|
||||||
|
assert(!settings.pluginFiles.pluginsLoaded);
|
||||||
for (const auto & pluginFile : settings.pluginFiles.get()) {
|
for (const auto & pluginFile : settings.pluginFiles.get()) {
|
||||||
Paths pluginFiles;
|
Paths pluginFiles;
|
||||||
try {
|
try {
|
||||||
|
@ -270,6 +279,9 @@ void initPlugins()
|
||||||
unknown settings. */
|
unknown settings. */
|
||||||
globalConfig.reapplyUnknownSettings();
|
globalConfig.reapplyUnknownSettings();
|
||||||
globalConfig.warnUnknownSettings();
|
globalConfig.warnUnknownSettings();
|
||||||
|
|
||||||
|
/* Tell the user if they try to set plugin-files after we've already loaded */
|
||||||
|
settings.pluginFiles.pluginsLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,23 @@ struct MaxBuildJobsSetting : public BaseSetting<unsigned int>
|
||||||
void set(const std::string & str, bool append = false) override;
|
void set(const std::string & str, bool append = false) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct PluginFilesSetting : public BaseSetting<Paths>
|
||||||
|
{
|
||||||
|
bool pluginsLoaded = false;
|
||||||
|
|
||||||
|
PluginFilesSetting(Config * options,
|
||||||
|
const Paths & def,
|
||||||
|
const std::string & name,
|
||||||
|
const std::string & description,
|
||||||
|
const std::set<std::string> & aliases = {})
|
||||||
|
: BaseSetting<Paths>(def, name, description, aliases)
|
||||||
|
{
|
||||||
|
options->addSetting(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(const std::string & str, bool append = false) override;
|
||||||
|
};
|
||||||
|
|
||||||
class Settings : public Config {
|
class Settings : public Config {
|
||||||
|
|
||||||
unsigned int getDefaultCores();
|
unsigned int getDefaultCores();
|
||||||
|
@ -819,7 +836,7 @@ public:
|
||||||
Setting<uint64_t> minFreeCheckInterval{this, 5, "min-free-check-interval",
|
Setting<uint64_t> minFreeCheckInterval{this, 5, "min-free-check-interval",
|
||||||
"Number of seconds between checking free disk space."};
|
"Number of seconds between checking free disk space."};
|
||||||
|
|
||||||
Setting<Paths> pluginFiles{
|
PluginFilesSetting pluginFiles{
|
||||||
this, {}, "plugin-files",
|
this, {}, "plugin-files",
|
||||||
R"(
|
R"(
|
||||||
A list of plugin files to be loaded by Nix. Each of these files will
|
A list of plugin files to be loaded by Nix. Each of these files will
|
||||||
|
|
|
@ -60,6 +60,7 @@ void Args::parseCmdline(const Strings & _cmdline)
|
||||||
verbosity = lvlError;
|
verbosity = lvlError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool argsSeen = false;
|
||||||
for (auto pos = cmdline.begin(); pos != cmdline.end(); ) {
|
for (auto pos = cmdline.begin(); pos != cmdline.end(); ) {
|
||||||
|
|
||||||
auto arg = *pos;
|
auto arg = *pos;
|
||||||
|
@ -88,6 +89,10 @@ void Args::parseCmdline(const Strings & _cmdline)
|
||||||
throw UsageError("unrecognised flag '%1%'", arg);
|
throw UsageError("unrecognised flag '%1%'", arg);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
if (!argsSeen) {
|
||||||
|
argsSeen = true;
|
||||||
|
initialFlagsProcessed();
|
||||||
|
}
|
||||||
pos = rewriteArgs(cmdline, pos);
|
pos = rewriteArgs(cmdline, pos);
|
||||||
pendingArgs.push_back(*pos++);
|
pendingArgs.push_back(*pos++);
|
||||||
if (processArgs(pendingArgs, false))
|
if (processArgs(pendingArgs, false))
|
||||||
|
@ -96,6 +101,9 @@ void Args::parseCmdline(const Strings & _cmdline)
|
||||||
}
|
}
|
||||||
|
|
||||||
processArgs(pendingArgs, true);
|
processArgs(pendingArgs, true);
|
||||||
|
|
||||||
|
if (!argsSeen)
|
||||||
|
initialFlagsProcessed();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Args::processFlag(Strings::iterator & pos, Strings::iterator end)
|
bool Args::processFlag(Strings::iterator & pos, Strings::iterator end)
|
||||||
|
@ -298,8 +306,8 @@ Strings argvToStrings(int argc, char * * argv)
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
MultiCommand::MultiCommand(const Commands & commands)
|
MultiCommand::MultiCommand(const Commands & commands_)
|
||||||
: commands(commands)
|
: commands(commands_)
|
||||||
{
|
{
|
||||||
expectArgs({
|
expectArgs({
|
||||||
.label = "subcommand",
|
.label = "subcommand",
|
||||||
|
|
|
@ -132,6 +132,10 @@ protected:
|
||||||
|
|
||||||
std::set<std::string> hiddenCategories;
|
std::set<std::string> hiddenCategories;
|
||||||
|
|
||||||
|
/* Called after all command line flags before the first non-flag
|
||||||
|
argument (if any) have been processed. */
|
||||||
|
virtual void initialFlagsProcessed() {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void addFlag(Flag && flag);
|
void addFlag(Flag && flag);
|
||||||
|
|
|
@ -240,8 +240,6 @@ static void main_nix_build(int argc, char * * argv)
|
||||||
|
|
||||||
myArgs.parseCmdline(args);
|
myArgs.parseCmdline(args);
|
||||||
|
|
||||||
initPlugins();
|
|
||||||
|
|
||||||
if (packages && fromArgs)
|
if (packages && fromArgs)
|
||||||
throw UsageError("'-p' and '-E' are mutually exclusive");
|
throw UsageError("'-p' and '-E' are mutually exclusive");
|
||||||
|
|
||||||
|
|
|
@ -196,8 +196,6 @@ static int main_nix_channel(int argc, char ** argv)
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
initPlugins();
|
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case cNone:
|
case cNone:
|
||||||
throw UsageError("no command specified");
|
throw UsageError("no command specified");
|
||||||
|
|
|
@ -74,8 +74,6 @@ static int main_nix_collect_garbage(int argc, char * * argv)
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
initPlugins();
|
|
||||||
|
|
||||||
auto profilesDir = settings.nixStateDir + "/profiles";
|
auto profilesDir = settings.nixStateDir + "/profiles";
|
||||||
if (removeOld) removeOldGenerations(profilesDir);
|
if (removeOld) removeOldGenerations(profilesDir);
|
||||||
|
|
||||||
|
|
|
@ -43,8 +43,6 @@ static int main_nix_copy_closure(int argc, char ** argv)
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
initPlugins();
|
|
||||||
|
|
||||||
if (sshHost.empty())
|
if (sshHost.empty())
|
||||||
throw UsageError("no host name specified");
|
throw UsageError("no host name specified");
|
||||||
|
|
||||||
|
|
|
@ -1420,8 +1420,6 @@ static int main_nix_env(int argc, char * * argv)
|
||||||
|
|
||||||
myArgs.parseCmdline(argvToStrings(argc, argv));
|
myArgs.parseCmdline(argvToStrings(argc, argv));
|
||||||
|
|
||||||
initPlugins();
|
|
||||||
|
|
||||||
if (!op) throw UsageError("no operation specified");
|
if (!op) throw UsageError("no operation specified");
|
||||||
|
|
||||||
auto store = openStore();
|
auto store = openStore();
|
||||||
|
|
|
@ -149,8 +149,6 @@ static int main_nix_instantiate(int argc, char * * argv)
|
||||||
|
|
||||||
myArgs.parseCmdline(argvToStrings(argc, argv));
|
myArgs.parseCmdline(argvToStrings(argc, argv));
|
||||||
|
|
||||||
initPlugins();
|
|
||||||
|
|
||||||
if (evalOnly && !wantsReadWrite)
|
if (evalOnly && !wantsReadWrite)
|
||||||
settings.readOnlyMode = true;
|
settings.readOnlyMode = true;
|
||||||
|
|
||||||
|
|
|
@ -1067,8 +1067,6 @@ static int main_nix_store(int argc, char * * argv)
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
initPlugins();
|
|
||||||
|
|
||||||
if (!op) throw UsageError("no operation specified");
|
if (!op) throw UsageError("no operation specified");
|
||||||
|
|
||||||
if (op != opDump && op != opRestore) /* !!! hack */
|
if (op != opDump && op != opRestore) /* !!! hack */
|
||||||
|
|
|
@ -326,8 +326,6 @@ static int main_nix_daemon(int argc, char * * argv)
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
initPlugins();
|
|
||||||
|
|
||||||
runDaemon(stdio);
|
runDaemon(stdio);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -159,6 +159,12 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
|
||||||
#include "nix.md"
|
#include "nix.md"
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Plugins may add new subcommands.
|
||||||
|
void pluginsInited() override
|
||||||
|
{
|
||||||
|
commands = RegisterCommand::getCommandsFor({});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static void showHelp(std::vector<std::string> subcommand)
|
static void showHelp(std::vector<std::string> subcommand)
|
||||||
|
@ -283,8 +289,6 @@ void mainWrapped(int argc, char * * argv)
|
||||||
|
|
||||||
if (completions) return;
|
if (completions) return;
|
||||||
|
|
||||||
initPlugins();
|
|
||||||
|
|
||||||
if (args.showVersion) {
|
if (args.showVersion) {
|
||||||
printVersion(programName);
|
printVersion(programName);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -171,8 +171,6 @@ static int main_nix_prefetch_url(int argc, char * * argv)
|
||||||
|
|
||||||
myArgs.parseCmdline(argvToStrings(argc, argv));
|
myArgs.parseCmdline(argvToStrings(argc, argv));
|
||||||
|
|
||||||
initPlugins();
|
|
||||||
|
|
||||||
if (args.size() > 2)
|
if (args.size() > 2)
|
||||||
throw UsageError("too many arguments");
|
throw UsageError("too many arguments");
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,6 @@ source common.sh
|
||||||
|
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
|
||||||
res=$(nix eval --expr builtins.anotherNull --option setting-set true --option plugin-files $PWD/plugins/libplugintest*)
|
res=$(nix --option setting-set true --option plugin-files $PWD/plugins/libplugintest* eval --expr builtins.anotherNull)
|
||||||
|
|
||||||
[ "$res"x = "nullx" ]
|
[ "$res"x = "nullx" ]
|
||||||
|
|
Loading…
Reference in a new issue