-
Notifications
You must be signed in to change notification settings - Fork 35.6k
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
Refactor: Add Flags enum to ArgsManager class #16097
Conversation
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
src/util/system.cpp
Outdated
@@ -319,6 +318,27 @@ ArgsManager::ArgsManager() : | |||
"-port", "-bind", | |||
"-rpcport", "-rpcbind", | |||
"-wallet", | |||
}, | |||
|
|||
m_allowed_negated_args{ |
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.
The problem described in the PR is real but I don't think the change implemented is the simplest or best fix. Having a new whitelist of options located in a separate part of the code from where the options are used and defined adds complexity, inconsistency, and action at distance to already very confusing code.
If someone specifies -nopid
, it is wrong to create a pid file called 0
, but a simpler and more useful fix would be to be not write a pid file instead of adding a new logic in a different part of the code to print a "negating not allowed" error.
But the -pid
argument case actually seems atypical here. More cases where negated arguments are handled incorrectly (like -incrementalrelayfee
) seem like simple misuses of the IsArgSet function, which is misnamed and doesn't do what people think it does. I'd replace the IsArgSet
function with separate ArgHasValue
and ArgIsSpecified
functions and use ArgHasValue
instead of ArgIsSpecified
everywhere or almost everywhere the code currently using ArgIsSet.
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.
m_allowed_negated_args
is used in the same manner as m_network_only_args
(see #11862) and it seems consistent, IMO.
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.
adds complexity, inconsistency, and action at distance to already very confusing code
Agree with @ryanofsky. I'd rather see an approach like #16416 (comment)
Beside the fact that m_network_only_args
is very small, I think it could be improved like my comment above - move that flag to the Arg
structure.
Currently ArgsManager::Arg
has:
bool m_debug_only;
And I think it could be changed to something like:
enum Flags {
NONE = 0x00,
DEBUG_ONLY = 0x01,
NETWORK_ONLY = 0x2,
ALLOW_NEGATED = 0x04,
};
Flags m_flags;
Or just add more members.
e2ebf75
to
cc19d49
Compare
@ryanofsky Thank you for your review.
Agree that
I don't think this approach will compeltely fix the problem described in this PR. |
cc19d49
to
90dfd23
Compare
Done. |
Thanks for the update! I still see several problems with this approach, but I think they can be fixed and I have specific suggestions below that I think will put this PR in a good state and make it easier to review. Here are the problems that I see presently (90dfd23):
I think all of these problems are fixable. Here are my suggestions:
ALLOW_BOOL = 0x01,
ALLOW_INT = 0x02,
ALLOW_STRING = 0x4,
ALLOW_ANY = ALLOW_BOOL | ALLOW_INT | ALLOW_STRING,
DEBUG_ONLY = 0x100,
NETWORK_ONLY = 0x200,
Overall, I think this is moving in a good direction and adding the flags really helps. But the more we can move in the direction of simple bool/int/string option types, and have negation taken care of on the front end, rather than leaking into entire codebase, the better state this code will be in, and less weird behavior we will have in the future. |
@ryanofsky Thank you for your review. I really appreciate it.
We have over two hundred target lines of code. Proposed approach does not allow to apply a scripted-diff, unfortunately. Thoughts? |
Agree. Going to implement it.
I'd prefer to use it. It complements the
Using the
|
That's the whole point! It's good to use scripted diffs in refactoring commits, but there should be no scripted diff for the behavior change. The code changes in the behavior change PR should just look like: -gArgs.AddArg("-changetype=<n>", ALLOW_ANY, ...);
+gArgs.AddArg("-changetype=<n>", ALLOW_STRING, ...); -gArgs.AddArg("-dbcache=<n>", ALLOW_ANY, ...);
+gArgs.AddArg("-dbcache=<n>", ALLOW_INT, ...); So it is easy for reviewers to verify that new errors triggered on options that currently allow negation are appropriate and appropriately documented in release notes. There should not be 200 lines targeted. Every existing boolean option, every existing list option, most string options, and many int options that accept 0 should continue to allow negation.
Just like IsArgSet which is misused many places, misunderstood and should be eliminated. If you look at google flags api, qsettings, python argparse, the standard everywhere is bool/number/string representations, not "is negated" queries for code reading the values. My refactoring PR #15934 is a major step in this direction internally replacing our vector representation of negated values with plain, typed Nothing I'm suggesting here involves changing or limiting behavior in any way. I'm just suggesting to use normal, sane terminology, so we have a more usable api and so the IsArgSet IsArgNegated bugs you are fixing now don't get reintroduced in the future.
That's exactly what I'm suggesting, except spelling I didn't fully describe in my previous comment how the suggested flags should behave, so I'll do that now to avoid unnecessary confusion. I don't think the extra error checks I'm describing here need to be implemented now. It'd be fine to implement them in future PRs that actually start adding
Except for one detail, adding these checks should have no effect when ALLOW_ANY is specified, so even if these checks are added now, this can remain a pure refactoring PR and not change behavior. The detail is that we currently accept |
Really nice @ryanofsky. Maybe it could also have a |
Yes I think that'd be a good flag, and I also like your idea adding support to declare default values. Best if this PR scope doesn't expand too much, but going forward, the more things about options that can be declared up front, the less complicated code reading options has to be and the less chance for inconsistencies and bugs. |
👍 Another flag (otherwise I may forget it) could be |
Sorry, I'd suggest closing #16469. The quote above is a little ambiguous, but I was trying to suggest splitting behavior changes into a separate PRs from the requested flags refactor, not creating multiple refactoring PRs. It's good to make behavior changes in small independent PRs so they don't get missed by reviewers and so there aren't multiple confusing discussion about different behaviors. It generally takes a lot less mental effort to review a pure refactoring PR than it does to review a refactoring PR mixed with behavior changes, so there shouldn't be any problem with including a small list initialization refactor in the same PR that does the requested flag refactor. |
Agree with @ryanofsky |
- added args parameter - renamed to InterpretOption() - removed code duplication
-BEGIN VERIFY SCRIPT- sed -i 's/const bool debug_only,/unsigned int flags, &/' src/util/system.h src/util/system.cpp sed -i -E 's/(true|false), OptionsCategory::/ArgsManager::ALLOW_ANY, &/' $(git grep --files-with-matches 'AddArg(' src) -END VERIFY SCRIPT-
* merge bitcoin#16097: Check IsArgKnown() early * merge bitcoin#16097: Refactor InterpretNegatedOption() function * merge bitcoin#16097: Add Flags enum to ArgsManager * scripted-diff: Use Flags enum in AddArg() -BEGIN VERIFY SCRIPT- sed -i 's/const bool debug_only,/unsigned int flags, &/' src/util/system.h src/util/system.cpp sed -i -E 's/(true|false), OptionsCategory::/ArgsManager::ALLOW_ANY, &/' $(git grep --files-with-matches 'AddArg(' src) -END VERIFY SCRIPT- * scripted-diff: Use ArgsManager::DEBUG_ONLY flag -BEGIN VERIFY SCRIPT- sed -i 's/unsigned int flags, const bool debug_only,/unsigned int flags,/' src/util/system.h src/util/system.cpp sed -i 's/ArgsManager::NONE, debug_only/flags, false/' src/util/system.cpp sed -i 's/arg.second.m_debug_only/(arg.second.m_flags \& ArgsManager::DEBUG_ONLY)/' src/util/system.cpp sed -i 's/ArgsManager::ALLOW_ANY, true, OptionsCategory::/ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::/' $(git grep --files-with-matches 'AddArg(' src) sed -i 's/ArgsManager::ALLOW_ANY, false, OptionsCategory::/ArgsManager::ALLOW_ANY, OptionsCategory::/' $(git grep --files-with-matches 'AddArg(' src) -END VERIFY SCRIPT- * merge bitcoin#16097: Remove unused m_debug_only member from Arg struct * merge bitcoin#16097: Use ArgsManager::NETWORK_ONLY flag * merge bitcoin#16097: Replace IsArgKnown() with FlagsOfKnownArg() * merge bitcoin#16097: Revamp option negating policy * merge bitcoin#16097: Make tests arg type specific
* merge bitcoin#16097: Check IsArgKnown() early * merge bitcoin#16097: Refactor InterpretNegatedOption() function * merge bitcoin#16097: Add Flags enum to ArgsManager * scripted-diff: Use Flags enum in AddArg() -BEGIN VERIFY SCRIPT- sed -i 's/const bool debug_only,/unsigned int flags, &/' src/util/system.h src/util/system.cpp sed -i -E 's/(true|false), OptionsCategory::/ArgsManager::ALLOW_ANY, &/' $(git grep --files-with-matches 'AddArg(' src) -END VERIFY SCRIPT- * scripted-diff: Use ArgsManager::DEBUG_ONLY flag -BEGIN VERIFY SCRIPT- sed -i 's/unsigned int flags, const bool debug_only,/unsigned int flags,/' src/util/system.h src/util/system.cpp sed -i 's/ArgsManager::NONE, debug_only/flags, false/' src/util/system.cpp sed -i 's/arg.second.m_debug_only/(arg.second.m_flags \& ArgsManager::DEBUG_ONLY)/' src/util/system.cpp sed -i 's/ArgsManager::ALLOW_ANY, true, OptionsCategory::/ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::/' $(git grep --files-with-matches 'AddArg(' src) sed -i 's/ArgsManager::ALLOW_ANY, false, OptionsCategory::/ArgsManager::ALLOW_ANY, OptionsCategory::/' $(git grep --files-with-matches 'AddArg(' src) -END VERIFY SCRIPT- * merge bitcoin#16097: Remove unused m_debug_only member from Arg struct * merge bitcoin#16097: Use ArgsManager::NETWORK_ONLY flag * merge bitcoin#16097: Replace IsArgKnown() with FlagsOfKnownArg() * merge bitcoin#16097: Revamp option negating policy * merge bitcoin#16097: Make tests arg type specific
Summary: --- This is a backport of bitcoin/bitcoin@e0d187d See bitcoin/bitcoin#16097 - added args parameter - renamed to InterpretOption() - removed code duplication Test plan: --- * `ninja all check-all`
Summary: --- This is a backport of bitcoin/bitcoin@265c1b5 See bitcoin/bitcoin#16097 Test plan: --- * `ninja all check-all`
Summary: --- This is a backport of bitcoin/bitcoin@9a12733 See bitcoin/bitcoin#16097 Test plan: --- * `ninja all check-all`
Summary --- This is a backport of bitcoin/bitcoin@dde80c2 See bitcoin/bitcoin#16097 Test plan --- * `ninja all check-all`
Summary --- This is a backport of bitcoin/bitcoin@db08edb See bitcoin/bitcoin#16097 Test plan --- * `ninja all check-all`
Summary --- This is a backport of bitcoin/bitcoin@b70cc5d See bitcoin/bitcoin#16097 Test plan --- * `ninja all check-all`
Summary --- This is a backport of bitcoin/bitcoin@e6f649c See bitcoin/bitcoin#16097 Test plan --- * `ninja all check-all`
This PR adds the
Flags
enum to theArgsManager
class. Also them_flags
member is added to theArg
struct. Flags denote an allowed type of an arg value and special hints.This PR is only a refactoring and does not change behavior.