Config API, Part I

This patch eliminates the global configuration variables `opt` and `g`, making
all functions and class instances locally configurable.  Configuration data is
passed to functions and constructors via the `cfg` parameter and made available
to methods in `self.cfg`.

Local configuration free from dependence on the command line will enable the
creation of multiple, independently configured instances of MMGen’s data
objects within a single process.

Potential applications include testing (tracking wallets configured to interact
with spawned processes, for example) and the use of MMGen as a library for
other projects.

This patch completes most of the work required to enable the API.  The full
implementation will appear in a forthcoming commit.
This commit is contained in:
The MMGen Project 2023-03-28 18:14:37 +00:00
commit c7adb56e38
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
197 changed files with 2218 additions and 2078 deletions

View file

@ -17,11 +17,11 @@ opts_data = {
}
}
cmd_args = opts.init(opts_data)
cfg = opts.init(opts_data)
from mmgen.fileutil import get_lines_from_file
lines = get_lines_from_file(cmd_args[0])
start = (1,0)[bool(opt.include_first_line)]
lines = get_lines_from_file( cfg, cfg._args[0] )
start = (1,0)[bool(cfg.include_first_line)]
a = make_chksum_6(' '.join(lines[start:]).encode())
if start == 1:
b = lines[0]

View file

@ -175,19 +175,20 @@ contract Token is ERC20Interface, Owned, SafeMath {
}
""" % req_solc_ver_pat
def create_src(proto,template,token_data,owner_addr):
def create_src(cfg,template,token_data):
def gen():
for k in token_data.fields:
field = getattr(token_data,k)
if k == 'owner_addr':
owner_addr = cfg._args[0]
from mmgen.addr import is_coin_addr
if not is_coin_addr( proto, owner_addr.lower() ):
die(1,f'{owner_addr}: not a valid {proto.coin} coin address')
if not is_coin_addr( cfg._proto, owner_addr.lower() ):
die(1,f'{owner_addr}: not a valid {cfg._proto.coin} coin address')
val = '0x' + owner_addr
else:
val = (
getattr(opt,k)
getattr(cfg,k)
or getattr(field,'default',None)
or die(1,f'The --{k} option must be specified')
)
@ -231,10 +232,10 @@ def check_solc_version():
Msg(f'solc version ({version_str}) does not match requirement ({req_solc_ver_pat})')
return False
def compile_code(code):
def compile_code(cfg,code):
cmd = ['solc','--optimize','--bin','--overwrite']
if not opt.stdout:
cmd += ['--output-dir', opt.outdir or '.']
if not cfg.stdout:
cmd += ['--output-dir', cfg.outdir or '.']
cmd += ['-']
msg(f"Executing: {' '.join(cmd)}")
cp = run(cmd,input=code.encode(),stdout=PIPE,stderr=PIPE)
@ -247,37 +248,34 @@ def compile_code(code):
if err:
ymsg('Solidity compiler produced the following warning:')
msg(err)
if opt.stdout:
if cfg.stdout:
o = out.split('\n')
return {k:o[i+2] for k in ('SafeMath','Owned','Token') for i in range(len(o)) if k in o[i]}
else:
vmsg(out)
cfg._util.vmsg(out)
if __name__ == '__main__':
cmd_args = opts.init(opts_data)
cfg = opts.init(opts_data)
if opt.check_solc_version:
if cfg.check_solc_version:
sys.exit(0 if check_solc_version() else 1)
from mmgen.protocol import init_proto_from_opts
proto = init_proto_from_opts()
if not proto.coin in ('ETH','ETC'):
if not cfg._proto.coin in ('ETH','ETC'):
die(1,'--coin option must be ETH or ETC')
if not len(cmd_args) == 1:
if not len(cfg._args) == 1:
opts.usage()
code = create_src( proto, solidity_code_template, token_data, cmd_args[0] )
code = create_src( cfg, solidity_code_template, token_data )
if opt.preprocess:
if cfg.preprocess:
Msg(code)
sys.exit(0)
out = compile_code(code)
out = compile_code( cfg, code )
if opt.stdout:
if cfg.stdout:
print(json.dumps(out))
msg('Contract successfully compiled')

View file

@ -22,13 +22,13 @@ opts_data = {
}
}
cmd_args = opts.init(opts_data)
cfg = opts.init(opts_data)
import asyncio
from mmgen.tx import CompletedTX
if len(cmd_args) != 1:
if len(cfg._args) != 1:
opts.usage()
tx = asyncio.run(CompletedTX(cmd_args[0],quiet_open=True))
tx.file.write(ask_tty=False,ask_overwrite=not opt.quiet,ask_write=not opt.quiet)
tx = asyncio.run(CompletedTX(cfg._args[0],quiet_open=True))
tx.file.write(ask_tty=False,ask_overwrite=not cfg.quiet,ask_write=not cfg.quiet)

View file

@ -51,12 +51,12 @@ opts_data = {
}
}
cmd_args = opts.init(opts_data)
cfg = opts.init(opts_data)
if gc.platform == 'linux' and os.getenv('USER') != 'root':
die(1,'This program must be run as root')
if len(cmd_args):
if len(cfg._args):
opts.usage()
mod_dir = os.path.split(normalize_path(modpath_save))[0]
@ -77,13 +77,13 @@ for d in (ulb,mod_pardir):
# add files only, not directories
del_list += [os.path.join(d,e) for e in os.listdir(d) if is_reg(os.path.join(d,e)) and e[:6] == 'mmgen-']
if opt.list_paths:
if cfg.list_paths:
die(1,'\n'.join(del_list))
if not opt.no_prompt:
if not cfg.no_prompt:
m = 'Deleting the following paths and files:\n {}\nProceed?'
from mmgen.ui import keypress_confirm
if not keypress_confirm(m.format('\n '.join(del_list))):
if not keypress_confirm( cfg, m.format('\n '.join(del_list)) ):
die(1,'Exiting at user request')
import shutil