]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
patman: Enhance implementation of file-based defaults
authorSimon Glass <sjg@chromium.org>
Sat, 10 May 2025 11:05:07 +0000 (13:05 +0200)
committerSimon Glass <sjg@chromium.org>
Tue, 27 May 2025 09:07:42 +0000 (10:07 +0100)
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>
tools/patman/cmdline.py
tools/patman/settings.py

index 108fa52d8200eb5d72d907c484e3ece3bf2d4f18..8e10c7bb14fde7118eda82479662b872fed536a8 100644 (file)
@@ -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)')
index def932db43a47fd6989e449a79389d042c48bbcb..17229e0d823a1d290ad98f537e92937ed07fd4ab 100644 (file)
@@ -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