support negated command-line options
- all options without parameters may be negated by prefixing the option name
with ‘no-’
- if the option name itself begins with ‘no-’, then the option is negated
by removing the ‘no-’ prefix
- negation may be used to override options set in the cfg file
- command-line options may also be overridden, with the last-listed option
taking precedence
- as with ordinary options, substring matching is supported
Examples:
OPTION NEGATED OPTION
--no-license --license
--no-license --lic
--quiet --no-quiet
--quiet --no-q
Testing:
$ test/cmdtest.py opts cfgfile
This commit is contained in:
parent
34deadb0f5
commit
df3559d420
6 changed files with 63 additions and 3 deletions
|
|
@ -1 +1 @@
|
|||
15.1.dev6
|
||||
15.1.dev7
|
||||
|
|
|
|||
|
|
@ -25,6 +25,16 @@ from collections import namedtuple
|
|||
|
||||
from .cfg import gc
|
||||
|
||||
def negated_opts(opts, data={}):
|
||||
if data:
|
||||
return data
|
||||
else:
|
||||
data.update(dict(
|
||||
((k[3:] if k.startswith('no-') else f'no-{k}'), v)
|
||||
for k, v in opts.items()
|
||||
if len(k) > 1 and not v.has_parm))
|
||||
return data
|
||||
|
||||
def get_opt_by_substring(opt, opts):
|
||||
matches = [o for o in opts if o.startswith(opt)]
|
||||
if len(matches) == 1:
|
||||
|
|
@ -67,6 +77,12 @@ def process_uopts(opts_data, opts):
|
|||
if parm:
|
||||
die('CmdlineOptError', f'option --{_opt} requires no parameter')
|
||||
yield (opts[_opt].name, True)
|
||||
elif (
|
||||
(_opt := opt) in negated_opts(opts)
|
||||
or (_opt := get_opt_by_substring(_opt, negated_opts(opts)))):
|
||||
if parm:
|
||||
die('CmdlineOptError', f'option --{_opt} requires no parameter')
|
||||
yield (negated_opts(opts)[_opt].name, False)
|
||||
else:
|
||||
die('CmdlineOptError', f'--{opt}: unrecognized option')
|
||||
elif arg[0] == '-' and len(arg) > 1:
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@ class CmdTestCfgFile(CmdTestBase):
|
|||
('coin_specific_vars', (40, 'setting coin-specific vars', [])),
|
||||
('chain_names', (40, 'setting chain names', [])),
|
||||
('mnemonic_entry_modes', (40, 'setting mnemonic entry modes', [])),
|
||||
('opt_override1', (40, 'cfg file opts not overridden', [])),
|
||||
('opt_override2', (40, 'negative cmdline opts overriding cfg file opts', [])),
|
||||
)
|
||||
|
||||
def __init__(self, trunner, cfgs, spawn):
|
||||
|
|
@ -276,3 +278,20 @@ class CmdTestCfgFile(CmdTestBase):
|
|||
|
||||
t.skip_ok = True
|
||||
return t
|
||||
|
||||
def opt_override1(self):
|
||||
self.write_to_cfgfile('usr', ['no_license true', 'scroll true'])
|
||||
t = self.spawn_test(
|
||||
args = ['print_cfg', 'scroll', 'no_license'])
|
||||
t.expect('scroll: True')
|
||||
t.expect('no_license: True')
|
||||
return t
|
||||
|
||||
def opt_override2(self):
|
||||
self.write_to_cfgfile('usr', ['no_license true', 'scroll true'])
|
||||
t = self.spawn_test(
|
||||
args = ['print_cfg', 'scroll', 'no_license'],
|
||||
opts = ['--no-scrol', '--lic'])
|
||||
t.expect('scroll: False')
|
||||
t.expect('no_license: False')
|
||||
return t
|
||||
|
|
|
|||
|
|
@ -41,6 +41,11 @@ class CmdTestOpts(CmdTestBase):
|
|||
('opt_good17', (41, 'good cmdline opt (param with equals signs)', [])),
|
||||
('opt_good18', (41, 'good cmdline opt (param with equals signs)', [])),
|
||||
('opt_good19', (41, 'good cmdline opt (param with equals signs)', [])),
|
||||
('opt_good20', (41, 'good cmdline opt (opt + negated opt)', [])),
|
||||
('opt_good21', (41, 'good cmdline opt (negated negative opt)', [])),
|
||||
('opt_good22', (41, 'good cmdline opt (opt + negated opt [substring])', [])),
|
||||
('opt_good23', (41, 'good cmdline opt (negated negative opt [substring])', [])),
|
||||
('opt_good24', (41, 'good cmdline opt (negated opt + opt [substring])', [])),
|
||||
('opt_bad_param', (41, 'bad global opt (--pager=1)', [])),
|
||||
('opt_bad_infile', (41, 'bad infile parameter', [])),
|
||||
('opt_bad_outdir', (41, 'bad outdir parameter', [])),
|
||||
|
|
@ -208,6 +213,21 @@ class CmdTestOpts(CmdTestBase):
|
|||
def opt_good19(self):
|
||||
return self.check_vals(['-x', 'x=1,y=2,z=3'], (('cfg.point', 'x=1,y=2,z=3'),))
|
||||
|
||||
def opt_good20(self):
|
||||
return self.check_vals(['--pager', '--no-pager'], (('cfg.pager', 'False'),))
|
||||
|
||||
def opt_good21(self):
|
||||
return self.check_vals(['--foobleize'], (('cfg.no_foobleize', 'False'),))
|
||||
|
||||
def opt_good22(self):
|
||||
return self.check_vals(['--quiet', '--no-q'], (('cfg.quiet', 'False'),))
|
||||
|
||||
def opt_good23(self):
|
||||
return self.check_vals(['--foobl'], (('cfg.no_foobleize', 'False'),))
|
||||
|
||||
def opt_good24(self):
|
||||
return self.check_vals(['--no-pag', '--pag'], (('cfg.pager', 'True'),))
|
||||
|
||||
def opt_bad_param(self):
|
||||
return self.do_run(['--pager=1'], 'no parameter', 1)
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,10 @@ msg(f'Sys cfg file: {os.path.relpath(cf_sys.fn)}')
|
|||
msg(f'Sample cfg file: {os.path.relpath(cf_sample.fn)}')
|
||||
|
||||
if op:
|
||||
if op == 'parse_test':
|
||||
if op == 'print_cfg':
|
||||
for name in args:
|
||||
msg('{} {}'.format(name+':', getattr(cfg, name)))
|
||||
elif op == 'parse_test':
|
||||
ps = cf_sample.get_lines()
|
||||
msg(f'parsed chunks: {len(ps)}')
|
||||
pu = cf_usr.get_lines()
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ opts_data = {
|
|||
-d, --outdir= d Use outdir 'd'
|
||||
-C, --print-checksum Print a checksum
|
||||
-E, --fee-estimate-mode=M Specify the network fee estimate mode.
|
||||
-F, --no-foobleize Do not foobleize the output, even on user request
|
||||
-H, --hidden-incog-input-params=f,o Read hidden incognito data from file
|
||||
'f' at offset 'o' (comma-separated)
|
||||
-k, --keep-label Reuse label of input wallet for output wallet
|
||||
|
|
@ -68,7 +69,8 @@ for k in (
|
|||
'max_temp',
|
||||
'coin',
|
||||
'pager',
|
||||
'point'):
|
||||
'point',
|
||||
'no_foobleize'):
|
||||
msg('{:30} {}'.format(f'cfg.{k}:', getattr(cfg, k)))
|
||||
|
||||
msg('')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue