Defer printing of help screens until global vars are initialized
This commit is contained in:
parent
2873897f68
commit
004536af63
18 changed files with 74 additions and 56 deletions
|
|
@ -41,8 +41,7 @@ note_secp256k1 = """
|
|||
If available, the secp256k1 library will be used for address generation.
|
||||
""".strip()
|
||||
|
||||
|
||||
opts_data = {
|
||||
def opts_data(): return {
|
||||
'sets': [('print_checksum',True,'quiet',True)],
|
||||
'desc': """Generate a range or list of {desc} from an {pnm} wallet,
|
||||
mnemonic, seed or brainwallet""".format(desc=gen_desc,pnm=g.proj_name),
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ from mmgen.obj import TwLabel
|
|||
# In batch mode, bitcoind just rescans each address separately anyway, so make
|
||||
# --batch and --rescan incompatible.
|
||||
|
||||
opts_data = {
|
||||
def opts_data(): return {
|
||||
'desc': """Import addresses (both {pnm} and non-{pnm}) into an {pnm}
|
||||
tracking wallet""".format(pnm=g.proj_name),
|
||||
'usage':'[opts] [mmgen address file]',
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ dfl_len = {
|
|||
'b32': PasswordList.pw_info['b32']['dfl_len']
|
||||
}
|
||||
|
||||
opts_data = {
|
||||
def opts_data(): return {
|
||||
'sets': [('print_checksum',True,'quiet',True)],
|
||||
'desc': """Generate a range or list of passwords from an {pnm} wallet,
|
||||
mnemonic, seed or brainwallet for the given ID string""".format(pnm=g.proj_name),
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ mmgen-tool: Perform various MMGen- and Bitcoin-related operations.
|
|||
from mmgen.common import *
|
||||
import mmgen.tool as tool
|
||||
|
||||
opts_data = {
|
||||
def opts_data(): return {
|
||||
'desc': 'Perform various {pnm}- and Bitcoin-related operations'.format(pnm=g.proj_name),
|
||||
'usage': '[opts] <command> <command args>',
|
||||
'options': """
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ mmgen-txbump: Increase the fee on a replaceable (replace-by-fee) MMGen
|
|||
from mmgen.txcreate import *
|
||||
from mmgen.txsign import *
|
||||
|
||||
opts_data = {
|
||||
def opts_data(): return {
|
||||
'desc': 'Increase the fee on a replaceable (RBF) {g.proj_name} transaction, creating a new transaction, and optionally sign and send the new transaction'.format(g=g),
|
||||
'usage': '[opts] <{g.proj_name} TX file> [seed source] ...'.format(g=g),
|
||||
'sets': ( ('yes', True, 'quiet', True), ),
|
||||
|
|
@ -70,7 +70,7 @@ opts_data = {
|
|||
kg=g.key_generator,
|
||||
cu=g.coin
|
||||
),
|
||||
'notes': '\n' + fee_notes + txsign_notes
|
||||
'notes': '\n' + fee_notes.format(g.coin) + txsign_notes
|
||||
}
|
||||
|
||||
cmd_args = opts.init(opts_data)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ mmgen-txcreate: Create a Bitcoin transaction to and from MMGen- or non-MMGen
|
|||
|
||||
from mmgen.txcreate import *
|
||||
|
||||
opts_data = {
|
||||
def opts_data(): return {
|
||||
'desc': 'Create a transaction with outputs to specified Bitcoin or {g.proj_name} addresses'.format(g=g),
|
||||
'usage': '[opts] <addr,amt> ... [change addr] [addr file] ...',
|
||||
'sets': ( ('yes', True, 'quiet', True), ),
|
||||
|
|
@ -46,7 +46,7 @@ opts_data = {
|
|||
-v, --verbose Produce more verbose output
|
||||
-y, --yes Answer 'yes' to prompts, suppress non-essential output
|
||||
""".format(g=g,cu=g.coin),
|
||||
'notes': '\n' + txcreate_notes + fee_notes
|
||||
'notes': '\n' + txcreate_notes + fee_notes.format(g.coin)
|
||||
}
|
||||
|
||||
cmd_args = opts.init(opts_data)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ mmgen-txdo: Create, sign and broadcast an online MMGen transaction
|
|||
from mmgen.txcreate import *
|
||||
from mmgen.txsign import *
|
||||
|
||||
opts_data = {
|
||||
def opts_data(): return {
|
||||
'desc': 'Create, sign and send an {g.proj_name} transaction'.format(g=g),
|
||||
'usage': '[opts] <addr,amt> ... [change addr] [addr file] ... [seed source] ...',
|
||||
'sets': ( ('yes', True, 'quiet', True), ),
|
||||
|
|
@ -74,7 +74,7 @@ opts_data = {
|
|||
kg=g.key_generator,
|
||||
cu=g.coin
|
||||
),
|
||||
'notes': '\n' + txcreate_notes + fee_notes + txsign_notes
|
||||
'notes': '\n' + txcreate_notes + fee_notes.format(g.coin) + txsign_notes
|
||||
}
|
||||
|
||||
cmd_args = opts.init(opts_data)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ mmgen-txsend: Broadcast a transaction signed by 'mmgen-txsign' to the network
|
|||
from mmgen.common import *
|
||||
from mmgen.tx import *
|
||||
|
||||
opts_data = {
|
||||
def opts_data(): return {
|
||||
'desc': 'Send a Bitcoin transaction signed by {pnm}-txsign'.format(
|
||||
pnm=g.proj_name.lower()),
|
||||
'usage': '[opts] <signed transaction file>',
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ mmgen-txsign: Sign a transaction generated by 'mmgen-txcreate'
|
|||
from mmgen.txsign import *
|
||||
|
||||
# -w, --use-wallet-dat (keys from running bitcoind) removed: use bitcoin-cli walletdump instead
|
||||
opts_data = {
|
||||
def opts_data(): return {
|
||||
'desc': 'Sign Bitcoin transactions generated by {pnl}-txcreate'.format(pnl=pnm.lower()),
|
||||
'usage': '[opts] <transaction file>... [seed source]...',
|
||||
'sets': ( ('yes', True, 'quiet', True), ),
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ elif invoked_as == 'passchg':
|
|||
else:
|
||||
die(1,"'%s': unrecognized invocation" % g.prog_name)
|
||||
|
||||
opts_data = {
|
||||
def opts_data(): return {
|
||||
# Can't use: share/Opts doesn't know anything about fmt codes
|
||||
# 'sets': [('hidden_incog_output_params',bool,'out_fmt','hi')],
|
||||
'desc': desc.format(pnm=g.proj_name),
|
||||
|
|
|
|||
|
|
@ -166,7 +166,10 @@ def override_from_env():
|
|||
gname = name[idx:].lower()
|
||||
setattr(g,gname,set_for_type(val,getattr(g,gname),name,invert_bool))
|
||||
|
||||
def init(opts_data,add_opts=[],opt_filter=None):
|
||||
def init(opts_f,add_opts=[],opt_filter=None):
|
||||
|
||||
opts_data = opts_f()
|
||||
opts_data['long_options'] = common_opts_data
|
||||
|
||||
version_info = """
|
||||
{pgnm_uc} version {g.version}
|
||||
|
|
@ -174,10 +177,8 @@ def init(opts_data,add_opts=[],opt_filter=None):
|
|||
Copyright (C) {g.Cdates} {g.author} {g.email}
|
||||
""".format(pnm=g.proj_name, g=g, pgnm_uc=g.prog_name.upper()).strip()
|
||||
|
||||
opts_data['long_options'] = common_opts_data
|
||||
|
||||
uopts,args,short_opts,long_opts,skipped_opts = \
|
||||
mmgen.share.Opts.parse_opts(sys.argv,opts_data,opt_filter=opt_filter)
|
||||
uopts,args,short_opts,long_opts,skipped_opts,do_help = \
|
||||
mmgen.share.Opts.parse_opts(sys.argv,opts_data,opt_filter=opt_filter,defer_help=True)
|
||||
|
||||
if g.debug: opt_preproc_debug(short_opts,long_opts,skipped_opts,uopts,args)
|
||||
|
||||
|
|
@ -185,11 +186,6 @@ def init(opts_data,add_opts=[],opt_filter=None):
|
|||
global usage_txt
|
||||
usage_txt = opts_data['usage']
|
||||
|
||||
# We don't need this data anymore
|
||||
del mmgen.share.Opts
|
||||
for k in ('prog_name','desc','usage','options','notes'):
|
||||
if k in opts_data: del opts_data[k]
|
||||
|
||||
# Transfer uopts into opt, setting program's opts + required opts to None if not set by user
|
||||
for o in tuple([s.rstrip('=') for s in long_opts] + add_opts + skipped_opts) + \
|
||||
g.required_opts + g.common_opts:
|
||||
|
|
@ -243,6 +239,17 @@ def init(opts_data,add_opts=[],opt_filter=None):
|
|||
|
||||
opt_postproc_initializations()
|
||||
|
||||
if do_help: # print help screen only after global vars are initialized
|
||||
opts_data = opts_f()
|
||||
opts_data['long_options'] = common_opts_data
|
||||
mmgen.share.Opts.parse_opts(sys.argv,opts_data,opt_filter=opt_filter)
|
||||
|
||||
# We don't need this data anymore
|
||||
del mmgen.share.Opts
|
||||
del opts_f
|
||||
for k in ('prog_name','desc','usage','options','notes'):
|
||||
if k in opts_data: del opts_data[k]
|
||||
|
||||
if g.debug: opt_postproc_debug()
|
||||
|
||||
return args
|
||||
|
|
|
|||
19
mmgen/rpc.py
19
mmgen/rpc.py
|
|
@ -75,7 +75,7 @@ class BitcoinRPCConnection(object):
|
|||
if cf['on_fail'] in ('return','silent'):
|
||||
return 'rpcfail',args
|
||||
else:
|
||||
die(*args[1:])
|
||||
die(args[1],yellow(args[2]))
|
||||
|
||||
dmsg('=== request() debug ===')
|
||||
dmsg(' RPC POST data ==> %s\n' % p)
|
||||
|
|
@ -86,10 +86,10 @@ class BitcoinRPCConnection(object):
|
|||
return (float,str)[g.bitcoind_version>=120000](obj)
|
||||
return json.JSONEncoder.default(self, obj)
|
||||
|
||||
# Can't do UTF-8 labels yet: httplib only ascii?
|
||||
# if type(p) != list and p['method'] == 'importaddress':
|
||||
# dump = json.dumps(p,cls=MyJSONEncoder,ensure_ascii=False)
|
||||
# print(dump)
|
||||
# TODO: UTF-8 labels
|
||||
# if type(p) != list and p['method'] == 'importaddress':
|
||||
# dump = json.dumps(p,cls=MyJSONEncoder,ensure_ascii=False)
|
||||
# print(dump)
|
||||
|
||||
dmsg(' RPC AUTHORIZATION data ==> [Basic {}]\n'.format(base64.b64encode(self.auth_str)))
|
||||
try:
|
||||
|
|
@ -98,9 +98,14 @@ class BitcoinRPCConnection(object):
|
|||
'Authorization': 'Basic {}'.format(base64.b64encode(self.auth_str))
|
||||
})
|
||||
except Exception as e:
|
||||
return die_maybe(None,2,'{}\nUnable to connect to bitcoind at {}:{}'.format(e,self.host,self.port))
|
||||
m = '{}\nUnable to connect to bitcoind at {}:{}'
|
||||
return die_maybe(None,2,m.format(e,self.host,self.port))
|
||||
|
||||
r = hc.getresponse() # returns HTTPResponse instance
|
||||
try:
|
||||
r = hc.getresponse() # returns HTTPResponse instance
|
||||
except Exception:
|
||||
m = 'Unable to connect to bitcoind at {}:{} (but port is bound?)'
|
||||
return die_maybe(None,2,m.format(self.host,self.port))
|
||||
|
||||
dmsg(' RPC GETRESPONSE data ==> %s\n' % r.__dict__)
|
||||
|
||||
|
|
|
|||
|
|
@ -27,19 +27,22 @@ def usage(opts_data):
|
|||
print 'USAGE: %s %s' % (opts_data['prog_name'], opts_data['usage'])
|
||||
sys.exit(2)
|
||||
|
||||
def print_help(opts_data,longhelp=False):
|
||||
def print_help_and_exit(opts_data,longhelp=False):
|
||||
pn = opts_data['prog_name']
|
||||
pn_len = str(len(pn)+2)
|
||||
print (' %-'+pn_len+'s %s') % (pn.upper()+':', opts_data['desc'].strip())
|
||||
print (' %-'+pn_len+'s %s %s')%('USAGE:', pn, opts_data['usage'].strip())
|
||||
out = ' {:<{p}} {}\n'.format(pn.upper()+':',opts_data['desc'].strip(),p=pn_len)
|
||||
out += ' {:<{p}} {} {}\n'.format('USAGE:',pn,opts_data['usage'].strip(),p=pn_len)
|
||||
od_opts = opts_data[('options','long_options')[longhelp]].strip().splitlines()
|
||||
sep,m,ls = (('\n ',' OPTIONS:',''),('\n',' LONG OPTIONS:',' '))[longhelp]
|
||||
print m + sep + ls + sep.join(od_opts)
|
||||
hdr = ('OPTIONS:',' LONG OPTIONS:')[longhelp]
|
||||
ls = (' ','')[longhelp]
|
||||
es = ('',' ')[longhelp]
|
||||
out += '{ls}{}\n{ls}{es}{}\n'.format(hdr,('\n'+ls).join(od_opts),ls=ls,es=es)
|
||||
if 'notes' in opts_data and not longhelp:
|
||||
print ' ' + '\n '.join(opts_data['notes'][1:-1].splitlines())
|
||||
out += ' ' + '\n '.join(opts_data['notes'][1:-1].splitlines())
|
||||
print(out)
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def process_opts(argv,opts_data,short_opts,long_opts):
|
||||
def process_opts(argv,opts_data,short_opts,long_opts,defer_help=False):
|
||||
|
||||
import os
|
||||
opts_data['prog_name'] = os.path.basename(sys.argv[0])
|
||||
|
|
@ -51,11 +54,15 @@ def process_opts(argv,opts_data,short_opts,long_opts):
|
|||
print str(err); sys.exit(2)
|
||||
|
||||
sopts_list = ':_'.join(['_'.join(list(i)) for i in short_opts.split(':')]).split('_')
|
||||
opts = {}
|
||||
opts,do_help = {},False
|
||||
|
||||
for opt, arg in cl_opts:
|
||||
if opt in ('-h','--help'): print_help(opts_data); sys.exit(0)
|
||||
elif opt == '--longhelp': print_help(opts_data,longhelp=True); sys.exit(0)
|
||||
for opt,arg in cl_opts:
|
||||
if opt in ('-h','--help'):
|
||||
if not defer_help: print_help_and_exit(opts_data)
|
||||
do_help = True
|
||||
elif opt == '--longhelp':
|
||||
if not defer_help: print_help_and_exit(opts_data,longhelp=True)
|
||||
do_help = True
|
||||
elif opt[:2] == '--' and opt[2:] in long_opts:
|
||||
opts[opt[2:].replace('-','_')] = True
|
||||
elif opt[:2] == '--' and opt[2:]+'=' in long_opts:
|
||||
|
|
@ -82,10 +89,10 @@ def process_opts(argv,opts_data,short_opts,long_opts):
|
|||
else:
|
||||
opts[o_out] = v_out
|
||||
|
||||
return opts,args
|
||||
return opts,args,do_help
|
||||
|
||||
|
||||
def parse_opts(argv,opts_data,opt_filter=None):
|
||||
def parse_opts(argv,opts_data,opt_filter=None,defer_help=False):
|
||||
|
||||
import re
|
||||
pat = r'^-([a-zA-Z0-9-]), --([a-zA-Z0-9-]{2,64})(=| )(.+)'
|
||||
|
|
@ -111,6 +118,7 @@ def parse_opts(argv,opts_data,opt_filter=None):
|
|||
long_opts = [d[1].replace('-','_')+d[5] for d in od_all if d[6] == False]
|
||||
skipped_opts = [d[1].replace('-','_') for d in od_all if d[6] == True]
|
||||
|
||||
opts,args = process_opts(argv,opts_data,short_opts,long_opts)
|
||||
opts,args,do_help = process_opts(argv,opts_data,short_opts,long_opts,defer_help=defer_help)
|
||||
|
||||
return opts,args,short_opts,long_opts,skipped_opts
|
||||
ret = opts,args,short_opts,long_opts,skipped_opts
|
||||
return ret + (do_help,) if defer_help else ret
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ FEE SPECIFICATION: Transaction fees, both on the command line and at the
|
|||
interactive prompt, may be specified as either absolute {} amounts, using
|
||||
a plain decimal number, or as satoshis per byte, using an integer followed by
|
||||
the letter 's'.
|
||||
""".format(g.coin)
|
||||
""" # formatted later, after g.coin is initialized
|
||||
|
||||
wmsg = {
|
||||
'addr_in_addrfile_only': """
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ from mmgen.common import *
|
|||
from mmgen.bitcoin import hex2wif
|
||||
|
||||
rounds = 100
|
||||
opts_data = {
|
||||
def opts_data(): return {
|
||||
'desc': "Test address generation in various ways",
|
||||
'usage':'[options] [spec] [rounds | dump file]',
|
||||
'options': """
|
||||
|
|
|
|||
|
|
@ -88,10 +88,9 @@ class MMGenPexpect(object):
|
|||
NL = '\n'
|
||||
|
||||
data_dir = os.path.join('test','data_dir')
|
||||
add_spawn_args = ' '.join(['{} {}'.format(
|
||||
'--'+k.replace('_','-'),
|
||||
add_spawn_args = ' '.join(['{} {}'.format('--'+k.replace('_','-'),
|
||||
getattr(opt,k) if getattr(opt,k) != True else ''
|
||||
) for k in ('testnet','rpc_host','rpc_port','regtest') if getattr(opt,k)]).split()
|
||||
) for k in ('testnet','rpc_host','rpc_port','regtest','coin') if getattr(opt,k)]).split()
|
||||
add_spawn_args += ['--data-dir',data_dir]
|
||||
|
||||
def __init__(self,name,mmgen_cmd,cmd_args,desc,no_output=False):
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ if not any(e in ('--skip-deps','--resume','-S','-r') for e in sys.argv+shortopts
|
|||
except: pass
|
||||
os.symlink(dd,data_dir)
|
||||
|
||||
opts_data = {
|
||||
def opts_data(): return {
|
||||
'desc': 'Test suite for the MMGen suite',
|
||||
'usage':'[options] [command(s) or metacommand(s)]',
|
||||
'options': """
|
||||
|
|
@ -1035,7 +1035,7 @@ class MMGenTestSuite(object):
|
|||
|
||||
def helpscreens(self,name,arg='--help'):
|
||||
scripts = (
|
||||
'walletgen','walletconv','walletchk','txcreate','txsend','txsign',
|
||||
'walletgen','walletconv','walletchk','txcreate','txsign','txsend','txdo','txbump',
|
||||
'addrgen','addrimport','keygen','passchg','tool','passgen')
|
||||
for s in scripts:
|
||||
t = MMGenExpect(name,('mmgen-'+s),[arg],extra_desc='(mmgen-%s)'%s,no_output=True)
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ cfg = {
|
|||
'addrfile_chk': '6FEF 6FB9 7B13 5D91',
|
||||
}
|
||||
|
||||
opts_data = {
|
||||
def opts_data(): return {
|
||||
'desc': "Test suite for the 'mmgen-tool' utility",
|
||||
'usage':'[options] [command]',
|
||||
'options': """
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue