[PATCH 14/20] patman: Split parser creation from parsing
Simon Glass
sjg at chromium.org
Thu May 8 09:28:38 CEST 2025
Tests may want to parse their own arguments. Refactor the parser code to
support this and allow settings to receive arguments as well.
Signed-off-by: Simon Glass <sjg at chromium.org>
---
tools/patman/cmdline.py | 32 +++++++++++++++++++++++++-------
tools/patman/settings.py | 28 ++++++++++++++++++----------
tools/patman/test_settings.py | 2 +-
3 files changed, 44 insertions(+), 18 deletions(-)
diff --git a/tools/patman/cmdline.py b/tools/patman/cmdline.py
index cf32716b8e0..e5ac4fb1684 100644
--- a/tools/patman/cmdline.py
+++ b/tools/patman/cmdline.py
@@ -20,13 +20,11 @@ from patman import settings
PATMAN_DIR = pathlib.Path(__file__).parent
HAS_TESTS = os.path.exists(PATMAN_DIR / "func_test.py")
-def parse_args():
- """Parse command line arguments from sys.argv[]
+def setup_parser():
+ """Set up command-line parser
Returns:
- tuple containing:
- options: command line options
- args: command lin arguments
+ argparse.Parser object
"""
epilog = '''Create patches from commits in a branch, check them and email
them as specified by tags you place in the commits. Use -n to do a dry
@@ -132,14 +130,34 @@ def parse_args():
help='Force overwriting an existing branch')
status.add_argument('-T', '--single-thread', action='store_true',
help='Disable multithreading when reading patchwork')
+ return parser
+
+
+def parse_args(argv=None, config_fname=None, parser=None):
+ """Parse command line arguments from sys.argv[]
+
+ Args:
+ argv (str or None): Arguments to process, or None to use sys.argv[1:]
+ config_fname (str): Config file to read, or None for default, or False
+ for an empty config
+
+ Returns:
+ tuple containing:
+ options: command line options
+ args: command lin arguments
+ """
+ if not parser:
+ parser = setup_parser()
# Parse options twice: first to get the project and second to handle
# defaults properly (which depends on project)
# Use parse_known_args() in case 'cmd' is omitted
- argv = sys.argv[1:]
+ if not argv:
+ argv = sys.argv[1:]
+
args, rest = parser.parse_known_args(argv)
if hasattr(args, 'project'):
- settings.Setup(parser, args.project)
+ settings.Setup(parser, args.project, argv, config_fname)
args, rest = parser.parse_known_args(argv)
# If we have a command, it is safe to parse all arguments
diff --git a/tools/patman/settings.py b/tools/patman/settings.py
index d66b22be1df..7a0866cd370 100644
--- a/tools/patman/settings.py
+++ b/tools/patman/settings.py
@@ -226,7 +226,7 @@ nxp = Zhikang Zhang <zhikang.zhang at nxp.com>
f.close()
-def _UpdateDefaults(main_parser, config):
+def _UpdateDefaults(main_parser, config, argv):
"""Update the given OptionParser defaults based on config.
We'll walk through all of the settings from all parsers.
@@ -242,6 +242,7 @@ def _UpdateDefaults(main_parser, config):
updated.
config: An instance of _ProjectConfigParser that we will query
for settings.
+ argv (list of str or None): Arguments to parse
"""
# Find all the parsers and subparsers
parsers = [main_parser]
@@ -252,6 +253,7 @@ def _UpdateDefaults(main_parser, config):
# Collect the defaults from each parser
defaults = {}
parser_defaults = []
+ argv = list(argv)
for parser in parsers:
pdefs = parser.parse_known_args()[0]
parser_defaults.append(pdefs)
@@ -273,9 +275,11 @@ def _UpdateDefaults(main_parser, config):
# 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):
parser.set_defaults(**{k: v for k, v in defaults.items()
if k in pdefs})
+ return defaults
def _ReadAliasFile(fname):
@@ -334,7 +338,7 @@ def GetItems(config, section):
return []
-def Setup(parser, project_name, config_fname=None):
+def Setup(parser, project_name, argv, config_fname=None):
"""Set up the settings module by reading config files.
Unless `config_fname` is specified, a `.patman` config file local
@@ -347,8 +351,9 @@ def Setup(parser, project_name, config_fname=None):
parser: The parser to update.
project_name: Name of project that we're working on; we'll look
for sections named "project_section" as well.
- config_fname: Config filename to read. An error is raised if it
- does not exist.
+ config_fname: Config filename to read, or None for default, or False
+ for an empty config. An error is raised if it does not exist.
+ argv (list of str or None): Arguments to parse, or None for default
"""
# First read the git alias file if available
_ReadAliasFile('doc/git-mailrc')
@@ -357,12 +362,15 @@ def Setup(parser, project_name, config_fname=None):
if config_fname and not os.path.exists(config_fname):
raise Exception(f'provided {config_fname} does not exist')
- if not config_fname:
+ if config_fname is None:
config_fname = '%s/.patman' % os.getenv('HOME')
- has_config = os.path.exists(config_fname)
-
git_local_config_fname = os.path.join(gitutil.get_top_level(), '.patman')
- has_git_local_config = os.path.exists(git_local_config_fname)
+
+ has_config = False
+ has_git_local_config = False
+ if config_fname is not False:
+ has_config = os.path.exists(config_fname)
+ has_git_local_config = os.path.exists(git_local_config_fname)
# Read the git local config last, so that its values override
# those of the global config, if any.
@@ -371,7 +379,7 @@ def Setup(parser, project_name, config_fname=None):
if has_git_local_config:
config.read(git_local_config_fname)
- if not (has_config or has_git_local_config):
+ if config_fname is not False and not (has_config or has_git_local_config):
print("No config file found.\nCreating ~/.patman...\n")
CreatePatmanConfigFile(config_fname)
@@ -382,7 +390,7 @@ def Setup(parser, project_name, config_fname=None):
for name, value in GetItems(config, 'bounces'):
bounces.add(value)
- _UpdateDefaults(parser, config)
+ return _UpdateDefaults(parser, config, argv)
# These are the aliases we understand, indexed by alias. Each member is a list.
diff --git a/tools/patman/test_settings.py b/tools/patman/test_settings.py
index 06b7cbc3ab6..c117836de31 100644
--- a/tools/patman/test_settings.py
+++ b/tools/patman/test_settings.py
@@ -49,7 +49,7 @@ def test_git_local_config():
dest='check_patch', default=True)
# Test "global" config is used.
- settings.Setup(parser, 'unknown', global_config.name)
+ settings.Setup(parser, 'unknown', None, global_config.name)
args, _ = parser.parse_known_args([])
assert args.project == 'u-boot'
send_args, _ = send.parse_known_args([])
--
2.43.0
More information about the U-Boot
mailing list