Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add command-line parser #123

Merged
merged 39 commits into from
Aug 13, 2021
Merged

Add command-line parser #123

merged 39 commits into from
Aug 13, 2021

Conversation

Xrayez
Copy link
Contributor

@Xrayez Xrayez commented Aug 7, 2021

Port of godotengine/godot#44594 to Godot 3.x to be available in Goost, with another bulk of changes and enhancements.

Co-authored-by: https://github.com/Shatur and https://github.com/lupoDharkael, thanks for the work on this as well, it would be too bad for such a feature to remain in the Limbo.

To-do

  • Further review, adapt and refine implementation.
    • Checkers used Callable, which is not present in Godot 3.x
      decided not to implement for now, see d074e05 (#123).
    • Automatically use default help format.
  • Port/write unit tests in GDScript.
  • Improve documentation.

Xrayez and others added 22 commits August 9, 2021 23:59
Port of godotengine/godot#44594 to Godot 3.x.

Co-authored-by: Shatur95 <[email protected]>
Co-authored-by: lupoDharkael <[email protected]>
Not properly supported in Godot 3.x.
Note: this could be ported to simple `PackedStringArray` equality comparison in Godot 4.0.

[tests skip]
Consistent with other parsers in Godot, such as json/xml.

[tests skip]
Consistent with `Expression.get_error_text()`, and `CommandLineParser`'s own `get_help_text()`.

[tests skip]
`get_values/prefixes()` to `get_value/prefix_list()`, make consistent with other `_list()` methods on Godot.

`get_forwarded_args()` to `get_forwarding_args()`, make consistent with `allow_forwarding_args` property.
These are not so trivial to implement in Godot 3.x since there's no Callable, which is Godot 4.x feature, and it might be better to see whether checher functionality is really needed in the first place, since validation is also possible to do via code after parsing, which is user-specific.
There's not much benefit in separating the two, and in most cases makes API more confusing. Current parsing code validates arguments as well anyways.
Allows to conveniently add new options without instantiating `CommandLineOption` classes manually.
return OK;
}

Error CommandLineParser::validate() {
for (int i = 0; i < _options.size(); ++i) {
Copy link
Contributor

@Shatur Shatur Aug 12, 2021

Choose a reason for hiding this comment

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

You will not able to define a help method and required arguments without validate. This is how it done in other parsers.

Copy link
Contributor Author

@Xrayez Xrayez Aug 12, 2021

Choose a reason for hiding this comment

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

I haven't removed validation code, but merged it at the end of parse(), also renamed validated signal to parsed for options, so more consolidation. As a user, I still don't quite get the usefulness of this to be honest. Could you elaborate?

The validation doesn't look any much different from validation done in parse() to me.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes I understand. But without this separation, if you declare a help command and mark some other command as required, the help command will not work because it will fail on required check.

Copy link
Contributor

@Shatur Shatur Aug 12, 2021

Choose a reason for hiding this comment

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

With this separation you can check for the help / version commands first and then call validate to check if other arguments are valid.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes I understand. But without this separation, if you declare a help command and mark some other command as required, the help command will not work because it will fail on required check.

Alright, yeah I understand this now. But is it only useful for help/version options, or are there other use cases where this separation may be required?

Copy link
Contributor

@Shatur Shatur Aug 12, 2021

Choose a reason for hiding this comment

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

Like this:

Then the text will be hardcoded :)

As I said, we have both add_help_option() and add_version_option() in public API. Those could be treated as special options and be recognized accordingly by the parser.

Then options will have a switch (maybe internal) to skip validation as I mentioned before.

As to me this behavior (with automatic validation skip) will be less obvious then a direct call to detect required variables (e.g. validate). But it just me.

Copy link
Contributor Author

@Xrayez Xrayez Aug 12, 2021

Choose a reason for hiding this comment

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

I've personally never used Boost.program_options, but I did use Python's argparse. There, if you define an option which is required=True, then somehow it still allows to parse --help and it prints a message, so I assume Python does have an internal mechanism to handle such cases. Godot users are more familiar with Python, so I think we should go with this approach.

Also, according to argparse.required documentation:

Required options are generally considered bad form because users expect options to be optional, and thus they should be avoided when possible.

So having API which allows to explicitly validate frowned upon approach for defining options might not be a good idea.

As I said, parse() already does a lot of validation checks for options/arguments prior to validate() (see various internal _validate_* methods), so it's also not 100% clear which checks are purely user-facing to make a better distinction, those that simply set _error_text or just ERR_FAIL_* (incorrect usage of command-line parser itself).

I'd personally like to keep API simpler if there's a possibility to make it simpler without losing functionality. If users say that validate() is needed, it could be added in future versions without breaking compatibility, I guess.

Then options will have a switch (maybe internal) to skip validation as I mentioned before.

I think this is the way to go.

Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm... This makes.
On second thought a command option to skip validation if the command is specified not that bad.

Copy link
Contributor Author

@Xrayez Xrayez Aug 12, 2021

Choose a reason for hiding this comment

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

I have added ability to mark options as "meta", see recent commits. Options that are meta are designed to get information about application itself, so if any such option is detected on the command-line, there's no need to check for required options, because meta options are not designed to interact with user options.

I haven't exposed it as a property, should probably stay internal.

Copy link
Contributor

Choose a reason for hiding this comment

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

Awesome!
I would allow user to set it, cost nothing, but it's up to you.

@Xrayez Xrayez marked this pull request as ready for review August 13, 2021 09:54
@Xrayez
Copy link
Contributor Author

Xrayez commented Aug 13, 2021

I feel like current implementation and API is fine.

So lets merge this and make it go through https://github.com/goostengine/goost-fuzzer to reveal potential crashes in gd3 branch.

Thanks for providing implementation and going through review process, hopefully we have consensus here. 🙂

@Xrayez Xrayez merged commit 6ee605b into gd3 Aug 13, 2021
@Xrayez Xrayez deleted the command-line-parser branch August 13, 2021 12:45
@Shatur
Copy link
Contributor

Shatur commented Aug 13, 2021

Thanks for providing implementation and going through review process, hopefully we have consensus here. 🙂

You are welcome :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature 💡 New feature proposal topic:core
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants