Browse Source

opts.py: refactor `usage()`, `version()`, `show_hash_presets()`

The MMGen Project 5 months ago
parent
commit
f6843a3fcd

+ 5 - 0
mmgen/cfg.py

@@ -543,6 +543,11 @@ class Config(Lockable):
 		# Check user-set opts without modifying them
 		check_opts(self)
 
+	def _usage(self):
+		from .help import make_usage_str
+		print(make_usage_str(self, caller='user'))
+		sys.exit(1) # called only on bad invocation
+
 	def _set_cfg_from_env(self):
 		for name,val in ((k,v) for k,v in os.environ.items() if k.startswith('MMGEN_')):
 			if name == 'MMGEN_DEBUG_ALL':

+ 2 - 2
mmgen/fileutil.py

@@ -129,9 +129,9 @@ def get_seed_file(cfg,nargs,wallets=None,invoked_as=None):
 	if len(wallets) + (wd_from_opt or bool(wf)) < nargs:
 		if not wf:
 			msg('No default wallet found, and no other seed source was specified')
-		cfg._opts.usage()
+		cfg._usage()
 	elif len(wallets) > nargs:
-		cfg._opts.usage()
+		cfg._usage()
 	elif len(wallets) == nargs and wf and invoked_as != 'gen':
 		cfg._util.qmsg('Warning: overriding default wallet with user-supplied wallet')
 

+ 38 - 0
mmgen/help/__init__.py

@@ -20,8 +20,46 @@
 help: help notes for MMGen suite commands
 """
 
+import sys
+
 from ..cfg import gc
 
+def version(cfg):
+	from ..util import fmt
+	print(fmt(f"""
+		{gc.prog_name.upper()} version {gc.version}
+		Part of {gc.proj_name} Wallet, an online/offline cryptocurrency wallet for the
+		command line. Copyright (C){gc.Cdates} {gc.author} {gc.email}
+	""", indent='  ').rstrip())
+	sys.exit(0)
+
+def show_hash_presets(cfg):
+	fs = '      {:<6} {:<3} {:<2} {}'
+	from ..util import msg
+	from ..crypto import Crypto
+	msg('  Available parameters for scrypt.hash():')
+	msg(fs.format('Preset', 'N', 'r', 'p'))
+	for i in sorted(Crypto.hash_presets.keys()):
+		msg(fs.format(i, *Crypto.hash_presets[i]))
+	msg('  N = memory usage (power of two)\n  p = iterations (rounds)')
+	sys.exit(0)
+
+def make_usage_str(cfg, caller):
+	indent, col1_w = {
+		'help': (2, len(gc.prog_name) + 1),
+		'user': (0, len('USAGE:')),
+	}[caller]
+	def gen():
+		ulbl = 'USAGE:'
+		for line in [cfg._usage_data.strip()] if isinstance(cfg._usage_data, str) else cfg._usage_data:
+			yield f'{ulbl:{col1_w}} {gc.prog_name} {line}'
+			ulbl = ''
+	return ('\n' + (' ' * indent)).join(gen())
+
+def usage(cfg):
+	print(make_usage_str(cfg, caller='user'))
+	sys.exit(0)
+
 def help_notes_func(proto,cfg,k):
 
 	def fee_spec_letters(use_quotes=False):

+ 1 - 1
mmgen/main_addrgen.py

@@ -134,7 +134,7 @@ addr_type = MMGenAddrType(
 	errmsg = f'{cfg.type!r}: invalid parameter for --type option' )
 
 if len(cfg._args) < 1:
-	cfg._opts.usage()
+	cfg._usage()
 
 if cfg.keygen_backend:
 	from .keygen import check_backend

+ 1 - 1
mmgen/main_autosign.py

@@ -194,7 +194,7 @@ cfg = Config(
 	},
 	do_post_init = True )
 
-cmd = cfg._args[0] if len(cfg._args) == 1 else 'sign' if not cfg._args else cfg._opts.usage()
+cmd = cfg._args[0] if len(cfg._args) == 1 else 'sign' if not cfg._args else cfg._usage()
 
 if cmd not in Autosign.cmds + Autosign.util_cmds:
 	die(1,f'‘{cmd}’: unrecognized command')

+ 4 - 4
mmgen/main_msg.py

@@ -207,7 +207,7 @@ cfg = Config( opts_data=opts_data, need_amt=False )
 cmd_args = cfg._args
 
 if len(cmd_args) < 2:
-	cfg._opts.usage()
+	cfg._usage()
 
 op = cmd_args.pop(0)
 
@@ -217,15 +217,15 @@ if cfg.msghash_type and op != 'create':
 async def main():
 	if op == 'create':
 		if len(cmd_args) < 2:
-			cfg._opts.usage()
+			cfg._usage()
 		MsgOps.create( cmd_args[0], ' '.join(cmd_args[1:]) )
 	elif op == 'sign':
 		if len(cmd_args) < 1:
-			cfg._opts.usage()
+			cfg._usage()
 		await MsgOps.sign( cmd_args[0], cmd_args[1:] )
 	elif op in ('verify','export'):
 		if len(cmd_args) not in (1,2):
-			cfg._opts.usage()
+			cfg._usage()
 		await getattr(MsgOps,op)( cmd_args[0], cmd_args[1] if len(cmd_args) == 2 else None )
 	else:
 		die(1,f'{op!r}: unrecognized operation')

+ 1 - 1
mmgen/main_passgen.py

@@ -138,7 +138,7 @@ FMT CODES:
 cfg = Config(opts_data=opts_data)
 
 if len(cfg._args) < 2:
-	cfg._opts.usage()
+	cfg._usage()
 
 pw_idxs = AddrIdxList(fmt_str=cfg._args.pop())
 

+ 1 - 1
mmgen/main_regtest.py

@@ -77,7 +77,7 @@ def check_num_args():
 		die(1,m.format(args,'many','more',amax))
 
 if not cmd_args:
-	cfg._opts.usage()
+	cfg._usage()
 elif cmd_args[0] not in MMGenRegtest.usr_cmds:
 	die(1,f'{cmd_args[0]!r}: invalid command')
 elif cmd_args[0] not in ('cli','wallet_cli','balances'):

+ 1 - 1
mmgen/main_seedjoin.py

@@ -111,7 +111,7 @@ def print_shares_info():
 cfg = Config(opts_data=opts_data)
 
 if len(cfg._args) + bool(cfg.hidden_incog_input_params) < 2:
-	cfg._opts.usage()
+	cfg._usage()
 
 if cfg.master_share:
 	master_idx = MasterShareIdx(cfg.master_share)

+ 1 - 1
mmgen/main_tool.py

@@ -359,7 +359,7 @@ if gc.prog_name.endswith('-tool'):
 		sys.exit(0)
 
 	if len(po.cmd_args) < 1:
-		cfg._opts.usage()
+		cfg._usage()
 
 	cmd = po.cmd_args[0]
 

+ 1 - 1
mmgen/main_txsend.py

@@ -78,7 +78,7 @@ elif not cfg._args and cfg.autosign:
 		infile = si.get_unsent()
 		cfg._util.qmsg(f'Got signed transaction file ‘{infile}’')
 else:
-	cfg._opts.usage()
+	cfg._usage()
 
 if not cfg.status:
 	from .ui import do_license_msg

+ 1 - 1
mmgen/main_txsign.py

@@ -102,7 +102,7 @@ cfg = Config(opts_data=opts_data)
 infiles = cfg._args
 
 if not infiles:
-	cfg._opts.usage()
+	cfg._usage()
 
 from .fileutil import check_infile
 for i in infiles:

+ 3 - 3
mmgen/main_wallet.py

@@ -166,17 +166,17 @@ elif invoked_as == 'seedsplit':
 				m2 = 'To generate a master share, omit the seed split specifier.'
 				die(1,m1+'  '+m2)
 		elif not sss:
-			cfg._opts.usage()
+			cfg._usage()
 	elif master_share:
 		sss = SeedSplitSpecifier('1:2')
 	else:
-		cfg._opts.usage()
+		cfg._usage()
 
 from .fileutil import check_infile,get_seed_file
 
 if cmd_args:
 	if invoked_as == 'gen' or len(cmd_args) > 1:
-		cfg._opts.usage()
+		cfg._usage()
 	check_infile(cmd_args[0])
 
 sf = get_seed_file(cfg,nargs,invoked_as=invoked_as)

+ 5 - 5
mmgen/main_xmrwallet.py

@@ -128,7 +128,7 @@ if cmd_args and cfg.autosign and (
 	cmd_args.insert(1,None)
 
 if len(cmd_args) < 2:
-	cfg._opts.usage()
+	cfg._usage()
 
 op     = cmd_args.pop(0)
 infile = cmd_args.pop(0)
@@ -136,22 +136,22 @@ wallets = spec = None
 
 if op in ('relay', 'submit', 'resubmit', 'abort'):
 	if len(cmd_args) != 0:
-		cfg._opts.usage()
+		cfg._usage()
 elif op in ('txview','txlist'):
 	infile = [infile] + cmd_args
 elif op in ('create','sync','list','view','listview','dump','restore'): # kafile_arg_ops
 	if len(cmd_args) > 1:
-		cfg._opts.usage()
+		cfg._usage()
 	wallets = cmd_args.pop(0) if cmd_args else None
 elif op in ('new', 'transfer', 'sweep', 'sweep_all', 'label'):
 	if len(cmd_args) != 1:
-		cfg._opts.usage()
+		cfg._usage()
 	spec = cmd_args[0]
 elif op in ('export-outputs', 'export-outputs-sign', 'import-key-images'):
 	if not cfg.autosign: # --autosign only for now - TODO
 		die(f'--autosign must be used with command {op!r}')
 	if len(cmd_args) > 1:
-		cfg._opts.usage()
+		cfg._usage()
 	wallets = cmd_args.pop(0) if cmd_args else None
 else:
 	die(1,f'{op!r}: unrecognized operation')

+ 7 - 8
mmgen/opts.py

@@ -66,6 +66,7 @@ long_opts_data = {
 --, --tw-name=NAME         Specify alternate name for the BTC/LTC/BCH tracking
                          wallet (default: ‘{tw_name}’)
 --, --skip-cfg-file        Skip reading the configuration file
+--, --usage                Print usage information and exit
 --, --version              Print version information and exit
 --, --bob                  Specify user “Bob” in MMGen regtest mode
 --, --alice                Specify user “Alice” in MMGen regtest mode
@@ -105,9 +106,6 @@ class UserOpts:
 
 		od['text']['long_options'] = long_opts_data['text']
 
-		# Make this available to usage()
-		self.usage_data = od['text'].get('usage2') or od['text']['usage']
-
 		# po: (user_opts,cmd_args,opts,filtered_opts)
 		po = parsed_opts or Opts.parse_opts(od,opt_filter=opt_filter)
 
@@ -123,15 +121,16 @@ class UserOpts:
 		cfg._parsed_opts = po
 		cfg._use_env = True
 		cfg._use_cfg_file = not 'skip_cfg_file' in uopts
+		# Make this available to usage()
+		cfg._usage_data = opts_data['text'].get('usage2') or opts_data['text']['usage']
 
 		if os.getenv('MMGEN_DEBUG_OPTS'):
 			opt_preproc_debug(po)
 
-		if 'version' in uopts:
-			self.version() # exits
-
-		if 'show_hash_presets' in uopts:
-			self.show_hash_presets() # exits
+		for funcname in ('usage', 'version', 'show_hash_presets'):
+			if funcname in uopts:
+				import importlib
+				getattr(importlib.import_module('mmgen.help'), funcname)(cfg) # exits
 
 		if parse_only:
 			return

+ 1 - 1
scripts/create-bip-hd-chain-params.py

@@ -100,7 +100,7 @@ def main():
 	global slip44_data, bip_utils_data
 
 	if len(cfg._args) != 1:
-		cfg._opts.usage()
+		cfg._usage()
 
 	with open(cfg._args[0]) as fh:
 		slip44_data = json.loads(fh.read())

+ 1 - 1
scripts/create-token.py

@@ -275,7 +275,7 @@ def main():
 		die(1,'--coin option must be ETH or ETC')
 
 	if not len(cfg._args) == 1:
-		cfg._opts.usage()
+		cfg._usage()
 
 	code = create_src( cfg, solidity_code_template, token_data )
 

+ 1 - 1
scripts/tx-v2-to-v3.py

@@ -29,7 +29,7 @@ opts_data = {
 cfg = Config(opts_data=opts_data)
 
 if len(cfg._args) != 1:
-	cfg._opts.usage()
+	cfg._usage()
 
 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)

+ 8 - 2
test/cmdtest_py_d/ct_help.py

@@ -25,7 +25,8 @@ class CmdTestHelp(CmdTestBase):
 	networks = ('btc', 'ltc', 'bch', 'eth', 'xmr', 'doge')
 	passthru_opts = ('daemon_data_dir','rpc_port','coin','testnet')
 	cmd_group = (
-		('usage',                (1,'usage message (via bad invocation)',[])),
+		('usage1',                (1,'usage message (via --usage)',[])),
+		('usage2',                (1,'usage message (via bad invocation)',[])),
 		('version',               (1,'version message',[])),
 		('license',               (1,'license message',[])),
 		('helpscreens',           (1,'help screens',             [])),
@@ -37,7 +38,12 @@ class CmdTestHelp(CmdTestBase):
 		('tooltest_help',         (1,"'tooltest.py' help screens",[])),
 	)
 
-	def usage(self):
+	def usage1(self):
+		t = self.spawn('mmgen-txsend', ['--usage'], no_passthru_opts=True)
+		t.expect('USAGE: mmgen-txsend')
+		return t
+
+	def usage2(self):
 		t = self.spawn('mmgen-walletgen', ['foo'], exit_val=1, no_passthru_opts=True)
 		t.expect('USAGE: mmgen-walletgen')
 		return t

+ 1 - 1
test/gentest.py

@@ -479,7 +479,7 @@ def get_protos(proto,addr_type,toolname):
 def parse_args():
 
 	if len(cfg._args) != 2:
-		cfg._opts.usage()
+		cfg._usage()
 
 	arg1,arg2 = cfg._args
 	gen1,gen2,rounds = (0,0,0)

+ 1 - 1
test/include/coin_daemon_control.py

@@ -140,7 +140,7 @@ def main():
 		ids = cfg._args
 		network_ids = CoinDaemon.get_network_ids(cfg)
 		if not ids:
-			cfg._opts.usage()
+			cfg._usage()
 		for i in ids:
 			if i not in network_ids + list(xmr_wallet_network_ids):
 				die(1,f'{i!r}: invalid network ID')