diff mbox series

[2/2] b4: add --config option to set config options on the command-line

Message ID 20240118202544.2019009-3-jani.nikula@intel.com (mailing list archive)
State Accepted
Headers show
Series b4: Add support for setting config on the command-line | expand

Commit Message

Jani Nikula Jan. 18, 2024, 8:25 p.m. UTC
It's useful to be able to set and override configuration options on the
command-line. Add the --config and -c options to do this. This is
similar to the git -c option.

The basic form is 'b4 -c name=value'. Mimic git -c option for the 'b4 -c
name' and 'b4 -c name=' forms to set the value to 'true' and the empty
string, respectively. The name is also the same section.key dotted
format as in git -c. For example, 'b4 -c
b4.midmask=https://some.host/%s'.

The argparse action class is handy for special parsing. For details, see
[1] and [2]. This stores a dict of the config options set on the command
line to cmdargs.config, mapping the full dotted keys to values. Relevant
parts for main, user and sendemail configs will be set using
_cmdline_config_override().

[1] https://docs.python.org/3/library/argparse.html#action
[2] https://docs.python.org/3/library/argparse.html#action-classes

Signed-off-by: Jani Nikula <jani.nikula@intel.com>
---
 b4/__init__.py  | 23 +++++++++++++++++++++++
 b4/command.py   | 24 ++++++++++++++++++++++++
 docs/config.rst |  5 +++++
 3 files changed, 52 insertions(+)
diff mbox series

Patch

diff --git a/b4/__init__.py b/b4/__init__.py
index f62ec11f965b..38a248aa8ca4 100644
--- a/b4/__init__.py
+++ b/b4/__init__.py
@@ -2729,6 +2729,22 @@  def setup_config(cmdargs: argparse.Namespace):
     _setup_sendemail_config(cmdargs)
 
 
+def _cmdline_config_override(cmdargs: argparse.Namespace, config: dict, section: str):
+    """Use cmdline.config to set and override config values for section."""
+    if not cmdargs.config:
+        return
+
+    section += '.'
+
+    config_override = {
+        key[len(section):]: val
+        for key, val in cmdargs.config.items()
+        if key.startswith(section)
+    }
+
+    config.update(config_override)
+
+
 def git_set_config(fullpath: Optional[str], param: str, value: str, operation: str = '--replace-all'):
     args = ['config', operation, param, value]
     ecode, out = git_run_command(fullpath, args)
@@ -2800,6 +2816,8 @@  def _setup_main_config(cmdargs: argparse.Namespace):
         gpgcfg = get_config_from_git(r'gpg\..*', {'program': 'gpg'})
         config['gpgbin'] = gpgcfg['program']
 
+    _cmdline_config_override(cmdargs, config, 'b4')
+
     MAIN_CONFIG = config
 
 
@@ -2896,6 +2914,8 @@  def _setup_user_config(cmdargs: argparse.Namespace):
     if 'email' not in USER_CONFIG:
         USER_CONFIG['email'] = os.environ['EMAIL']
 
+    _cmdline_config_override(cmdargs, USER_CONFIG, 'user')
+
 
 def get_user_config() -> dict:
     return USER_CONFIG
@@ -3532,6 +3552,9 @@  def _setup_sendemail_config(cmdargs: argparse.Namespace):
         sectname = 'sendemail'
     logger.debug('Using values from %s', sectname)
 
+    # Note: This can't handle identity, need to use sendemail.key directly
+    _cmdline_config_override(cmdargs, sconfig, 'sendemail')
+
     SENDEMAIL_CONFIG = sconfig
 
 
diff --git a/b4/command.py b/b4/command.py
index 07b6d67735dc..96d585f6983e 100644
--- a/b4/command.py
+++ b/b4/command.py
@@ -111,6 +111,24 @@  def cmd_diff(cmdargs):
     b4.diff.main(cmdargs)
 
 
+class ConfigOption(argparse.Action):
+    """Action class for storing key=value arguments in a dict."""
+    def __call__(self, parser, namespace, keyval, option_string=None):
+        config = getattr(namespace, self.dest, None)
+
+        if config is None:
+            config = dict()
+            setattr(namespace, self.dest, config)
+
+        if '=' in keyval:
+            key, value = keyval.split('=', maxsplit=1)
+        else:
+            # mimic git -c option
+            key, value = keyval, 'true'
+
+        config[key] = value
+
+
 def setup_parser() -> argparse.ArgumentParser:
     # noinspection PyTypeChecker
     parser = argparse.ArgumentParser(
@@ -132,6 +150,12 @@  def setup_parser() -> argparse.ArgumentParser:
                         help='Disable TTY detection for stdin')
     parser.add_argument('--use-web-endpoint', dest='send_web', action='store_true', default=False,
                         help="Force going through the web endpoint")
+    parser.add_argument('-c', '--config', metavar='NAME=VALUE', action=ConfigOption,
+                        help='''Set config option NAME to VALUE. Override value
+                        from config files. NAME is in dotted section.key
+                        format. Using NAME= and omitting VALUE will set the
+                        value to the empty string. Using NAME and omitting
+                        =VALUE will set the value to "true".''')
 
     subparsers = parser.add_subparsers(help='sub-command help', dest='subcmd')
 
diff --git a/docs/config.rst b/docs/config.rst
index 8936d2274734..c46d43a16ac0 100644
--- a/docs/config.rst
+++ b/docs/config.rst
@@ -12,6 +12,11 @@  Since the purpose of b4 is to work with git repositories, this allows
 the usual fall-through configuration that can be overridden by more
 local settings on the repository level.
 
+Additionally, you can set and override configuration options on the command-line
+using the ``--config`` (or ``-c``) option, for example::
+
+    b4 --config b4.midmask=https://some.host/%s
+
 Per-project defaults
 ~~~~~~~~~~~~~~~~~~~~
 .. note::