summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2025-05-10 13:05:07 +0200
committerSimon Glass <sjg@chromium.org>2025-05-27 10:07:42 +0100
commit0ab5e441e7f7433cad6bf16ea509dfc415a18b4f (patch)
tree47de89266f9066e8b3d743d2dcd14e2758bf5b05
parent42588591e2e7a62258cfa7b487b0accad5db3fca (diff)
patman: Enhance implementation of file-based defaults
Patman allows defaults for its command-line flags to be read from a file. The implementation of this does not fully work with subcommands, since we don't want a default for those. Also, it relies on being able to parse any sort of cmdline in order to figure out the options that are available. But in some cases, the cmdline may not parse, e.g. if there are required options, or conflicting options. Add a class which can be safely used to parse any cmdline, since it allows execution to continue even when errors are obtained. Use this to determine the defaults, being careful to skip sub/commands. Another way to handle all of this would be to maintain the defaults separately and insert them into the parser manually. For now, I'm not sure which is best. Signed-off-by: Simon Glass <sjg@chromium.org>
-rw-r--r--tools/patman/cmdline.py21
-rw-r--r--tools/patman/settings.py50
2 files changed, 65 insertions, 6 deletions
diff --git a/tools/patman/cmdline.py b/tools/patman/cmdline.py
index 108fa52d820..8e10c7bb14f 100644
--- a/tools/patman/cmdline.py
+++ b/tools/patman/cmdline.py
@@ -21,6 +21,25 @@ PATMAN_DIR = pathlib.Path(__file__).parent
HAS_TESTS = os.path.exists(PATMAN_DIR / "func_test.py")
+class ErrorCatchingArgumentParser(argparse.ArgumentParser):
+ def __init__(self, **kwargs):
+ self.exit_state = None
+ self.catch_error = False
+ super().__init__(**kwargs)
+
+ def error(self, message):
+ if self.catch_error:
+ self.message = message
+ else:
+ super().error(message)
+
+ def exit(self, status=0, message=None):
+ if self.catch_error:
+ self.exit_state = True
+ else:
+ super().exit(status, message)
+
+
def add_send_args(par):
"""Add arguments for the 'send' command
@@ -150,7 +169,7 @@ def setup_parser():
them as specified by tags you place in the commits. Use -n to do a dry
run first.'''
- parser = argparse.ArgumentParser(epilog=epilog)
+ parser = ErrorCatchingArgumentParser(epilog=epilog)
parser.add_argument(
'-D', '--debug', action='store_true',
help='Enabling debugging (provides a full traceback on error)')
diff --git a/tools/patman/settings.py b/tools/patman/settings.py
index def932db43a..17229e0d823 100644
--- a/tools/patman/settings.py
+++ b/tools/patman/settings.py
@@ -9,8 +9,10 @@ except Exception:
import ConfigParser
import argparse
+from io import StringIO
import os
import re
+import sys
from u_boot_pylib import gitutil
@@ -254,10 +256,44 @@ def _UpdateDefaults(main_parser, config, argv):
defaults = {}
parser_defaults = []
argv = list(argv)
+ orig_argv = argv
+
+ bad = False
+ full_parser_list = []
for parser in parsers:
- pdefs = parser.parse_known_args()[0]
- parser_defaults.append(pdefs)
- defaults.update(vars(pdefs))
+ argv_list = [orig_argv]
+ special_cases = []
+ if hasattr(parser, 'defaults_cmds'):
+ special_cases = parser.defaults_cmds
+ for action in parser._actions:
+ if action.choices:
+ argv_list = []
+ for choice in action.choices:
+ argv = None
+ for case in special_cases:
+ if case[0] == choice:
+ argv = case
+ argv_list.append(argv or [choice])
+
+ for argv in argv_list:
+ parser.message = None
+ old_val = parser.catch_error
+ try:
+ parser.catch_error = True
+ pdefs = parser.parse_known_args(argv)[0]
+ finally:
+ parser.catch_error = old_val
+
+ # if parser.message:
+ # print('bad', argv, parser.message)
+ # bad = True
+
+ parser_defaults.append(pdefs)
+ defaults.update(vars(pdefs))
+ full_parser_list.append(parser)
+ if bad:
+ print('Internal parsing error')
+ sys.exit(1)
# Go through the settings and collect defaults
for name, val in config.items('settings'):
@@ -272,11 +308,15 @@ def _UpdateDefaults(main_parser, config, argv):
defaults[name] = val
else:
print("WARNING: Unknown setting %s" % name)
+ if 'cmd' in defaults:
+ del defaults['cmd']
+ if 'subcmd' in defaults:
+ del defaults['subcmd']
# Set all the defaults and manually propagate them to subparsers
main_parser.set_defaults(**defaults)
- assert len(parsers) == len(parser_defaults)
- for parser, pdefs in zip(parsers, parser_defaults):
+ assert len(full_parser_list) == len(parser_defaults)
+ for parser, pdefs in zip(full_parser_list, parser_defaults):
parser.set_defaults(**{k: v for k, v in defaults.items()
if k in pdefs})
return defaults