-
Notifications
You must be signed in to change notification settings - Fork 0
fix for parsing error handling of an empty command argument #48
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well it's a hack, but it works. I would just simplify catching the exception
tools/main.cpp
Outdated
catch (CLI::ExtrasError &e) { | ||
if (std::string_view{"The following argument was not expected: "} == e.what()) { | ||
return app.exit(CLI::ExtrasError("Empty argument is encountered in the command line", e.get_exit_code())); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to https://github.com/AntelopeIO/antler-proj/blob/main/tools/CLI11.hpp#L902 ExtrasError always contain either The following arguments were
or The following arguments was
catch (CLI::ExtrasError &e) { | |
if (std::string_view{"The following argument was not expected: "} == e.what()) { | |
return app.exit(CLI::ExtrasError("Empty argument is encountered in the command line", e.get_exit_code())); | |
} | |
catch (const CLI::ExtrasError& e) { | |
return app.exit(CLI::ExtrasError("Empty argument is encountered in the command line", e.get_exit_code())); | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to https://github.com/AntelopeIO/antler-proj/blob/main/tools/CLI11.hpp#L902 ExtrasError always contain either
The following arguments were
orThe following arguments was
But we should not change the behavior in case if this exception thrown for non empty arguments. In this case all these arguments should be printed as "The following arguments were not expected: arg1 arg2 etc." or "The following argument was not expected: arg"
We should change the message only in case if it prints "The following argument was not expected: " which happens only if we have one "" (empty argument) in the command line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see. This is bigger hack than I thought.
Isn't there any other way to fix it?
I.e. checking arguments before parsing if any of them is ""
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are "extra" arguments - so they aren't caught by the standard validators.
I've suggested a change (below) that could address this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see. This is bigger hack than I thought. Isn't there any other way to fix it? I.e. checking arguments before parsing if any of them is
""
This is the best solution which I can invent without changing of the CLI11.hpp code.
The problem is not with empty arguments of options, the problem with empty options.
The parser recognize the subcommand, then find all its options and their arguments, and all other text which it can find the parser consider as "extra" arguments, i.e. trash which it shows in the text of the exception when prints the error. All it works if these extra arguments have symbols. But it seems authors of the parser don't know that it possible to declare an empty argument in the command line, so the parser just don't handle this case at all and print nothing instead of name of an argument. In other words everything which is not looks like a known subcommand or option of a subcommand or a parameter of an option considers as an "extra" argument.
tools/main.cpp
Outdated
return app.exit(CLI::ExtrasError("Empty argument is encountered in the command line", e.get_exit_code())); | ||
} | ||
} | ||
catch (const CLI::ParseError &e) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
other references in code are similar to this:
catch (const CLI::ParseError &e) { | |
catch (const CLI::ParseError& e) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree - @mikelik is suggesting the "correct" style.
tools/main.cpp
Outdated
// This hack fix parsing error handling of an empty command argument. Example: antler-proj build ~/path/proj "" | ||
catch (CLI::ExtrasError &e) { | ||
if (std::string_view{"The following argument was not expected: "} == e.what()) { | ||
return app.exit(CLI::ExtrasError("Empty argument is encountered in the command line", e.get_exit_code())); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing an app.exit(e)
.
Also, I agree with @mikelik - we should handle both "was" and "were". Here's a possibility:
// This hack fix parsing error handling of an empty command argument. Example: antler-proj build ~/path/proj "" | |
catch (CLI::ExtrasError &e) { | |
if (std::string_view{"The following argument was not expected: "} == e.what()) { | |
return app.exit(CLI::ExtrasError("Empty argument is encountered in the command line", e.get_exit_code())); | |
} | |
} | |
// Handle empty command argument. Example: `antler-proj build ~/path/proj ""` | |
catch (CLI::ExtrasError& e) { | |
std::string what = e.what(); | |
// trim space | |
while(!what.empty() && what.back() == ' ') | |
what.pop_back(); | |
if( what == "The following argument was not expected:" || what == "The following arguments were not expected:") { | |
return app.exit(CLI::ExtrasError("Empty argument(s) encountered in the command line.", e.get_exit_code())); | |
} | |
app.exit(e); | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Scott is right, if one would pass 2+ empty arguments (which is awkward but possible due to errors in scripts) - it will fail.
But his solution seems to me too verbose and hard to understand from glance. here is mine:
// This hack fix parsing error handling of an empty command argument. Example: antler-proj build ~/path/proj "" | |
catch (CLI::ExtrasError &e) { | |
if (std::string_view{"The following argument was not expected: "} == e.what()) { | |
return app.exit(CLI::ExtrasError("Empty argument is encountered in the command line", e.get_exit_code())); | |
} | |
} | |
// This hack fix parsing error handling of an empty command argument. Example: antler-proj build ~/path/proj "" | |
catch (CLI::ExtrasError &e) { | |
const std::regex rex("The following argument(s)? (was|were)? not expected:\\s+$", std::regex_constants::ECMAScript); | |
if (std::regex_search(e.what(), rex)) { | |
return app.exit(CLI::ExtrasError("Unexpected empty argument is encountered in the command line", e.get_exit_code())); | |
} | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Scott is right, if one would pass 2+ empty arguments (which is awkward but possible due to errors in scripts) - it will fail. But his solution seems to me too verbose and hard to understand from glance. here is mine:
I'm not against of such comprehensive check but if you try to test the cases with more than one empty argument you will see that they processed by the parser earlier and as I understand such exception will be never thrown for antler-proj command syntax.
And I prefer @mikelik and @ScottBailey solutions. Don't want to include a complex library for such simple cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Must add app.exit(e)
to correctly report other errors. Should behave the same when 1 empty argument or 2+ are provided.
Where's the test? A simple one could be added in tools/tests.
@@ -57,7 +57,7 @@ int main(int argc, char** argv) { | |||
app.add_flag_callback("-V,--version", | |||
[&app]() { | |||
std::cout << app.get_name() << " v" << antler::system::version::full() << std::endl; | |||
std::exit(0); // Succesfull exit MUST happen here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
now I feel relief that native English speakers also mess double letters in that word lol
I have added @dimas1185 update from main to avoid a merge collision. |
Co-authored-by: mikelik <mikelik@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
Example: antler-proj build ~/path/proj ""
corresponding to issue #19