From e00e4cd149f0738a5b9069fbf0463979446dc5cd Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Mon, 27 Mar 2023 10:48:19 +0000 Subject: [PATCH] opts.py: improve environment var parsing --- mmgen/globalvars.py | 10 +++++++++- mmgen/opts.py | 47 ++++++++++++++++++++++++++------------------- 2 files changed, 36 insertions(+), 21 deletions(-) diff --git a/mmgen/globalvars.py b/mmgen/globalvars.py index 0073cdbe..0357b700 100755 --- a/mmgen/globalvars.py +++ b/mmgen/globalvars.py @@ -82,6 +82,7 @@ class GlobalContext(Lockable): debug_tw = False quiet = False no_license = False + force_color = False force_256_color = False testnet = False regtest = False @@ -112,10 +113,13 @@ class GlobalContext(Lockable): # test suite: bogus_send = False + bogus_unspent_data = '' debug_utf8 = False exec_wrapper = False test_suite = False + test_suite_cfgtest = False test_suite_deterministic = False + test_suite_pexpect = False test_suite_popen_spawn = False hold_protect_disable = False @@ -246,10 +250,13 @@ class GlobalContext(Lockable): 'MMGEN_COLUMNS', 'MMGEN_TEST_SUITE', + 'MMGEN_TEST_SUITE_CFGTEST', 'MMGEN_TEST_SUITE_DETERMINISTIC', + 'MMGEN_TEST_SUITE_PEXPECT', 'MMGEN_TEST_SUITE_POPEN_SPAWN', 'MMGEN_BLACKLIST_DAEMONS', 'MMGEN_BOGUS_SEND', + 'MMGEN_BOGUS_UNSPENT_DATA', 'MMGEN_DEBUG', 'MMGEN_DEBUG_OPTS', 'MMGEN_DEBUG_RPC', @@ -257,9 +264,10 @@ class GlobalContext(Lockable): 'MMGEN_DEBUG_TW', 'MMGEN_DEBUG_UTF8', 'MMGEN_DEBUG_SUBSEED', + 'MMGEN_FORCE_COLOR', + 'MMGEN_FORCE_256_COLOR', 'MMGEN_HOLD_PROTECT_DISABLE', 'MMGEN_QUIET', - 'MMGEN_FORCE_256_COLOR', 'MMGEN_MIN_URANDCHARS', 'MMGEN_NO_LICENSE', 'MMGEN_RPC_HOST', diff --git a/mmgen/opts.py b/mmgen/opts.py index dc646278..471b2f6a 100755 --- a/mmgen/opts.py +++ b/mmgen/opts.py @@ -161,7 +161,7 @@ def set_for_type(val,refval,desc,invert_bool=False,src=None): ' in {!r}'.format(src) if src else '', type(refval).__name__) ) -def override_globals_from_cfg_file(ucfg,autoset_opts,need_proto): +def override_globals_from_cfg_file(ucfg,autoset_opts,env_globals,need_proto): if need_proto: from .protocol import init_proto for d in ucfg.get_lines(): @@ -185,7 +185,8 @@ def override_globals_from_cfg_file(ucfg,autoset_opts,need_proto): from .util import die die( 'CfgFileParseError', f'Parse error in file {ucfg.fn!r}, line {d.lineno}' ) val_conv = set_for_type(val,refval,attr,src=ucfg.fn) - setattr(cls,attr,val_conv) + if attr not in env_globals: + setattr(cls,attr,val_conv) elif d.name in g.autoset_opts: autoset_opts[d.name] = d.value else: @@ -193,20 +194,23 @@ def override_globals_from_cfg_file(ucfg,autoset_opts,need_proto): die( 'CfgFileParseError', f'{d.name!r}: unrecognized option in {ucfg.fn!r}, line {d.lineno}' ) def override_globals_and_set_opts_from_env(opt): - for name in g.env_opts: + for name,val in ((k,v) for k,v in os.environ.items() if k.startswith('MMGEN_')): if name == 'MMGEN_DEBUG_ALL': continue - disable = name[:14] == 'MMGEN_DISABLE_' - val = os.getenv(name) # os.getenv() returns None if env var is unset - if val: # exclude empty string values; string value of '0' or 'false' sets variable to False - gname = name[(6,14)[disable]:].lower() - if hasattr(g,gname): - setattr(g,gname,set_for_type(val,getattr(g,gname),name,disable)) - elif hasattr(opt,gname): - if getattr(opt,gname) is None: # env must not override cmdline! - setattr(opt,gname,val) - else: - raise ValueError(f'Name {gname} not present in globals or opts') + elif name in g.env_opts: + if val: # ignore empty string values; string value of '0' or 'false' sets variable to False + disable = name.startswith('MMGEN_DISABLE_') + gname = name[(6,14)[disable]:].lower() + if hasattr(g,gname): + setattr(g,gname,set_for_type(val,getattr(g,gname),name,disable)) + yield gname + elif hasattr(opt,gname): + if getattr(opt,gname) is None: # env must not override cmdline! + setattr(opt,gname,val) + else: + raise ValueError(f'Name {gname!r} not present in globals or opts') + else: + raise ValueError(f'{name!r} is not a valid MMGen environment variable') def show_common_opts_diff(): @@ -330,6 +334,9 @@ def init( version() # exits # === begin global var initialization === # + + env_globals = tuple(override_globals_and_set_opts_from_env(opt)) + """ NB: user opt --data-dir is actually data_dir_root - data_dir is data_dir_root plus optionally 'regtest' or 'testnet', so for mainnet @@ -343,7 +350,7 @@ def init( """ if opt.data_dir: g.data_dir_root = os.path.normpath(os.path.abspath(opt.data_dir)) - elif os.getenv('MMGEN_TEST_SUITE'): + elif g.test_suite: from test.include.common import get_test_data_dir g.data_dir_root = get_test_data_dir() else: @@ -363,12 +370,12 @@ def init( if not (opt.skip_cfg_file or opt.bob or opt.alice or g.prog_name == 'mmgen-regtest'): from .cfg import cfg_file # check for changes in system template file - term must be initialized - # workaround: g.test_suite is needed by cfg.py, but g is not set from environment yet - g.test_suite = False if os.getenv('MMGEN_TEST_SUITE') in (None,'','false','0') else True cfg_file('sample') - override_globals_from_cfg_file( cfg_file('usr'), cfgfile_autoset_opts, need_proto ) - - override_globals_and_set_opts_from_env(opt) + override_globals_from_cfg_file( + cfg_file('usr'), + cfgfile_autoset_opts, + env_globals, + need_proto ) # Set globals from opts, setting type from original global value # Do here, before opts are set from globals below