From 0da14440c6aa583f84b5d1900013474ab494bcf2 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Fri, 24 May 2019 23:27:37 -0600 Subject: [PATCH] commands: config: add -d and -D options for deleting These allow the user to delete existing options. Signed-off-by: Marti Bolivar --- src/west/commands/config.py | 53 +++++++++++++++++++++++++--- tests/test_config.py | 69 +++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 5 deletions(-) diff --git a/src/west/commands/config.py b/src/west/commands/config.py index 8d209b2..baa8793 100644 --- a/src/west/commands/config.py +++ b/src/west/commands/config.py @@ -8,7 +8,8 @@ import argparse import configparser from west import log -from west.configuration import read_config, update_config, ConfigFile +from west.configuration import read_config, update_config, delete_config, \ + ConfigFile from west.commands import WestCommand, CommandError CONFIG_DESCRIPTION = '''\ @@ -52,6 +53,16 @@ To set a value for , type: To list all options and their values: west config -l + +To delete in the local or global file (wherever it's set +first, not in both; if set locally, global values become visible): + west config -d + +To delete in the global file only: + west config -d --global + +To delete everywhere it's set, including the system file: + west config -D ''' CONFIG_EPILOG = '''\ @@ -98,6 +109,10 @@ class Config(WestCommand): parser.add_argument('-l', '--list', action='store_true', help='list all options and their values') + parser.add_argument('-d', '--delete', action='store_true', + help='delete an option in one config file') + parser.add_argument('-D', '--delete-all', action='store_true', + help="delete an option everywhere it's set") group = parser.add_argument_group( 'configuration file to use (give at most one)') @@ -116,15 +131,22 @@ class Config(WestCommand): return parser def do_run(self, args, user_args): + delete = args.delete or args.delete_all if args.list: if args.name: self.parser.error('-l cannot be combined with name argument') + elif delete: + self.parser.error('-l cannot be combined with -d or -D') elif not args.name: self.parser.error('missing argument name ' '(to list all options and values, use -l)') + elif args.delete and args.delete_all: + self.parser.error('-d cannot be combined with -D') if args.list: self.list(args) + elif delete: + self.delete(args) elif args.value is None: self.read(args) else: @@ -138,6 +160,24 @@ class Config(WestCommand): for k, v in cfg[s].items(): log.inf('{}.{}={}'.format(s, k, v)) + def delete(self, args): + section, key = self._sk(args) + if args.delete_all: + what = ALL + elif args.configfile: + what = args.configfile + else: + what = None # local or global, whichever comes first + + try: + delete_config(section, key, configfile=what) + except KeyError: + log.dbg('{} was not set in requested location(s)'. + format(args.name)) + raise CommandError(returncode=1) + except PermissionError as pe: + self._perm_error(pe, what, section, key) + def read(self, args): section, key = self._sk(args) cfg = configparser.ConfigParser() @@ -155,10 +195,7 @@ class Config(WestCommand): try: update_config(section, key, args.value, configfile=what) except PermissionError as pe: - log.die("can't set {}.{}: permission denied when writing {}{}". - format(section, key, pe.filename, - ('; are you root/administrator?' if what == SYSTEM - else ''))) + self._perm_error(pe, what, section, key) def _sk(self, args): name_list = args.name.split(".", 1) @@ -166,3 +203,9 @@ class Config(WestCommand): self.parser.error('name {} should be in the form
.', exit_code=3) return name_list[0], name_list[1] + + def _perm_error(self, pe, what, section, key): + rootp = ('; are you root/administrator?' if what in [SYSTEM, ALL] + else '') + log.die("can't update {}.{}: permission denied when writing {}{}". + format(section, key, pe.filename, rootp)) diff --git a/tests/test_config.py b/tests/test_config.py index 41baab4..82b36c6 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -342,6 +342,75 @@ def test_delete_local_one(): assert 'pytest' in cfg(f=LOCAL) assert cfg(f=LOCAL)['pytest']['key2'] == 'bar' +def test_delete_cmd_all(): + # west config -D should delete from everywhere + cmd('config --system pytest.key system') + cmd('config --global pytest.key global') + cmd('config --local pytest.key local') + assert cfg(f=ALL)['pytest']['key'] == 'local' + cmd('config -D pytest.key') + assert 'pytest' not in cfg(f=ALL) + with pytest.raises(subprocess.CalledProcessError): + cmd('config -D pytest.key') + +def test_delete_cmd_none(): + # west config -d should delete from lowest-precedence global or + # local file only. + cmd('config --system pytest.key system') + cmd('config --global pytest.key global') + cmd('config --local pytest.key local') + cmd('config -d pytest.key') + assert cmd('config pytest.key').rstrip() == 'global' + cmd('config -d pytest.key') + assert cmd('config pytest.key').rstrip() == 'system' + with pytest.raises(subprocess.CalledProcessError): + cmd('config -d pytest.key') + +def test_delete_cmd_system(): + # west config -d --system should only delete from system + cmd('config --system pytest.key system') + cmd('config --global pytest.key global') + cmd('config --local pytest.key local') + cmd('config -d --system pytest.key') + with pytest.raises(subprocess.CalledProcessError): + cmd('config --system pytest.key') + assert cmd('config --global pytest.key').rstrip() == 'global' + assert cmd('config --local pytest.key').rstrip() == 'local' + +def test_delete_cmd_global(): + # west config -d --global should only delete from global + cmd('config --system pytest.key system') + cmd('config --global pytest.key global') + cmd('config --local pytest.key local') + cmd('config -d --global pytest.key') + assert cmd('config --system pytest.key').rstrip() == 'system' + with pytest.raises(subprocess.CalledProcessError): + cmd('config --global pytest.key') + assert cmd('config --local pytest.key').rstrip() == 'local' + +def test_delete_cmd_local(): + # west config -d --local should only delete from local + cmd('config --system pytest.key system') + cmd('config --global pytest.key global') + cmd('config --local pytest.key local') + cmd('config -d --local pytest.key') + assert cmd('config --system pytest.key').rstrip() == 'system' + assert cmd('config --global pytest.key').rstrip() == 'global' + with pytest.raises(subprocess.CalledProcessError): + cmd('config --local pytest.key') + +def test_delete_cmd_error(): + # Verify illegal combinations of flags error out. + with pytest.raises(subprocess.CalledProcessError) as e: + cmd('config -l -d pytest.key') + assert '-l cannot be combined with -d or -D' in str(e) + with pytest.raises(subprocess.CalledProcessError) as e: + cmd('config -l -D pytest.key') + assert '-l cannot be combined with -d or -D' in str(e) + with pytest.raises(subprocess.CalledProcessError) as e: + cmd('config -d -D pytest.key') + assert '-d cannot be combined with -D' in str(e) + def test_default_config(): # Writing to a value without a config destination should default # to --local.