Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion src/libutil/args.cc
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ void RootArgs::parseCmdline(const Strings & _cmdline, bool allowShebang)
} catch (SystemError &) {
}
}

for (auto pos = cmdline.begin(); pos != cmdline.end();) {

auto arg = *pos;
Expand Down Expand Up @@ -354,6 +355,9 @@ void RootArgs::parseCmdline(const Strings & _cmdline, bool allowShebang)

processArgs(pendingArgs, true);

if (!completions)
checkArgs();

initialFlagsProcessed();

/* Now that we are done parsing, make sure that any experimental
Expand Down Expand Up @@ -384,7 +388,7 @@ bool Args::processFlag(Strings::iterator & pos, Strings::iterator end)

auto & rootArgs = getRoot();

auto process = [&](const std::string & name, const Flag & flag) -> bool {
auto process = [&](const std::string & name, Flag & flag) -> bool {
++pos;

if (auto & f = flag.experimentalFeature)
Expand Down Expand Up @@ -413,6 +417,7 @@ bool Args::processFlag(Strings::iterator & pos, Strings::iterator end)
}
if (!anyCompleted)
flag.handler.fun(std::move(args));
flag.timesUsed++;
return true;
};

Expand Down Expand Up @@ -504,6 +509,14 @@ bool Args::processArgs(const Strings & args, bool finish)
return res;
}

void Args::checkArgs()
{
for (auto & [name, flag] : longFlags) {
if (flag->required && flag->timesUsed == 0)
throw UsageError("required argument '--%s' is missing", name);
Comment on lines +515 to +516
Copy link
Member

Choose a reason for hiding this comment

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

Can we list multiple such flags?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, there can be multiple required flags.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah I mean collect them all and throw error with all of them

}
}

nlohmann::json Args::toJSON()
{
auto flags = nlohmann::json::object();
Expand Down Expand Up @@ -643,6 +656,13 @@ bool MultiCommand::processArgs(const Strings & args, bool finish)
return Args::processArgs(args, finish);
}

void MultiCommand::checkArgs()
{
Args::checkArgs();
if (command)
command->second->checkArgs();
}

nlohmann::json MultiCommand::toJSON()
{
auto cmds = nlohmann::json::object();
Expand Down
8 changes: 8 additions & 0 deletions src/libutil/include/nix/util/args.hh
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,12 @@ public:
Strings labels;
Handler handler;
CompleterClosure completer;
bool required = false;

std::optional<ExperimentalFeature> experimentalFeature;

// FIXME: this should be private, but that breaks designated initializers.
size_t timesUsed = 0;
Comment on lines +208 to +210
Copy link
Contributor

Choose a reason for hiding this comment

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

It's really ugly that Flag becomes mutable. Can we avoid this by storing the use-count separately? I would hope that Flag stays an immutable description with a callback. Can't we instead track if the argument has been specified multiple times in the Handler?

Copy link
Member

Choose a reason for hiding this comment

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

Yes I would prefer that too, thanks for catching @xokdvium

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't think it's a problem since Args owns the Flags anyway (i.e. it was already mutable).

};

protected:
Expand Down Expand Up @@ -283,6 +287,8 @@ protected:

StringSet hiddenCategories;

virtual void checkArgs();

/**
* Called after all command line flags before the first non-flag
* argument (if any) have been processed.
Expand Down Expand Up @@ -428,6 +434,8 @@ public:
protected:
std::string commandName = "";
bool aliasUsed = false;

void checkArgs() override;
};

Strings argvToStrings(int argc, char ** argv);
Expand Down
8 changes: 3 additions & 5 deletions src/nix/sigs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ static auto rCmdSign = registerCommand2<CmdSign>({"store", "sign"});

struct CmdKeyGenerateSecret : Command
{
std::optional<std::string> keyName;
std::string keyName;

CmdKeyGenerateSecret()
{
Expand All @@ -153,6 +153,7 @@ struct CmdKeyGenerateSecret : Command
.description = "Identifier of the key (e.g. `cache.example.org-1`).",
.labels = {"name"},
.handler = {&keyName},
.required = true,
});
}

Expand All @@ -170,11 +171,8 @@ struct CmdKeyGenerateSecret : Command

void run() override
{
if (!keyName)
throw UsageError("required argument '--key-name' is missing");

logger->stop();
writeFull(getStandardOutput(), SecretKey::generate(*keyName).to_string());
writeFull(getStandardOutput(), SecretKey::generate(keyName).to_string());
}
};

Expand Down
Loading