[opts]: separate code from text in opts_data

- When parsing opts, opts.init() now looks only at string values from
  opts_data.  Global variables are evaluated only when printing help text,
  after the variables are initialized
This commit is contained in:
The MMGen Project 2019-03-26 12:59:30 +00:00
commit 017ecef3bc
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
27 changed files with 385 additions and 247 deletions

View file

@ -41,12 +41,15 @@ note_secp256k1 = """
If available, the secp256k1 library will be used for address generation.
""".strip()
opts_data = lambda: {
opts_data = {
'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),
'usage':'[opts] [seed source] <index list or range(s)>',
'options': """
'text': {
'desc': """
Generate a range or list of {desc} from an {pnm} wallet,
mnemonic, seed or brainwallet
""".format(desc=gen_desc,pnm=g.proj_name),
'usage':'[opts] [seed source] <index list or range(s)>',
'options': """
-h, --help Print this help message
--, --longhelp Print help message for long options (common options)
-A, --no-addresses Print only secret keys, no addresses
@ -77,14 +80,7 @@ opts_data = lambda: {
(default: {dmat})
-v, --verbose Produce more verbose output
-x, --b16 Print secret keys in hexadecimal too
""".format(
seed_lens=', '.join(map(str,g.seed_lens)),
pnm=g.proj_name,
kgs=' '.join(['{}:{}'.format(n,k) for n,k in enumerate(g.key_generators,1)]),
kg=g.key_generator,
what=gen_what,g=g,
dmat="'{}' or '{}'".format(g.proto.dfl_mmtype,MAT.mmtypes[g.proto.dfl_mmtype]['name'])
),
""",
'notes': """
NOTES FOR THIS COMMAND
@ -105,16 +101,30 @@ ADDRESS TYPES:
{n_bw}
FMT CODES:
{n_fmt}
""".format(
n_secp=note_secp256k1,
n_addrkey=note_addrkey,
n_pw=help_notes('passwd'),
n_bw=help_notes('brainwallet'),
n_fmt='\n '.join(SeedSource.format_fmt_codes().splitlines()),
n_at='\n '.join(["'{}','{:<12} - {}".format(k,v['name']+"'",v['desc']) for k,v in list(MAT.mmtypes.items())]),
o=opts
)
"""
},
'code': {
'options': lambda s: s.format(
seed_lens=', '.join(map(str,g.seed_lens)),
dmat="'{}' or '{}'".format(g.proto.dfl_mmtype,MAT.mmtypes[g.proto.dfl_mmtype]['name']),
kgs=' '.join(['{}:{}'.format(n,k) for n,k in enumerate(g.key_generators,1)]),
kg=g.key_generator,
pnm=g.proj_name,
what=gen_what,
g=g,
),
'notes': lambda s: s.format(
n_secp=note_secp256k1,
n_addrkey=note_addrkey,
n_pw=help_notes('passwd'),
n_bw=help_notes('brainwallet'),
n_fmt='\n '.join(SeedSource.format_fmt_codes().splitlines()),
n_at='\n '.join(["'{}','{:<12} - {}".format(
k,v['name']+"'",v['desc']) for k,v in list(MAT.mmtypes.items())])
)
}
}
cmd_args = opts.init(opts_data,add_opts=['b16'],opt_filter=opt_filter)

View file

@ -47,10 +47,11 @@ option, or a list of non-{pnm} addresses with the '--addrlist' option
# In batch mode, daemon just rescans each address separately anyway, so make
# --batch and --rescan incompatible.
opts_data = lambda: {
'desc': """Import addresses into an {} tracking wallet""".format(g.proj_name),
'usage':'[opts] [mmgen address file]',
'options': """
opts_data = {
'text': {
'desc': """Import addresses into an {} tracking wallet""".format(g.proj_name),
'usage':'[opts] [mmgen address file]',
'options': """
-h, --help Print this help message
--, --longhelp Print help message for long options (common options)
-a, --address=a Import the single coin address 'a'
@ -67,6 +68,7 @@ already in the tracking wallet.
The --batch and --rescan options cannot be used together.
"""
}
}
cmd_args = opts.init(opts_data)

View file

@ -31,10 +31,11 @@ key_fn = 'autosign.key'
from mmgen.common import *
prog_name = os.path.basename(sys.argv[0])
opts_data = lambda: {
'desc': 'Auto-sign MMGen transactions',
'usage':'[opts] [command]',
'options': """
opts_data = {
'text': {
'desc': 'Auto-sign MMGen transactions',
'usage':'[opts] [command]',
'options': """
-h, --help Print this help message
--, --longhelp Print help message for long options (common options)
-c, --coins=c Coins to sign for (comma-separated list)
@ -97,6 +98,7 @@ each signing session.
This command is currently available only on Linux-based platforms.
""".format(pnm=prog_name,wd=wallet_dir,td=tx_dir,kf=key_fn,mp=mountpoint)
}
}
cmd_args = opts.init(opts_data,add_opts=['mmgen_keys_from_file','in_fmt'])

View file

@ -33,12 +33,15 @@ dfl_len = {
'hex': PasswordList.pw_info['hex']['dfl_len']
}
opts_data = lambda: {
opts_data = {
'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),
'usage':'[opts] [seed source] <ID string> <index list or range(s)>',
'options': """
'text': {
'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),
'usage':'[opts] [seed source] <ID string> <index list or range(s)>',
'options': """
-h, --help Print this help message
--, --longhelp Print help message for long options (common options)
-b, --base32 Generate passwords in Base32 format instead of Base58
@ -65,11 +68,7 @@ opts_data = lambda: {
(min={g.min_urandchars}, max={g.max_urandchars}, default={g.usr_randchars})
-S, --stdout Print passwords to stdout
-v, --verbose Produce more verbose output
""".format(
seed_lens=', '.join(map(str,g.seed_lens)),
g=g,pnm=g.proj_name,d58=dfl_len['b58'],d32=dfl_len['b32'],dhex=dfl_len['hex'],
kgs=' '.join(['{}:{}'.format(n,k) for n,k in enumerate(g.key_generators,1)])
),
""",
'notes': """
NOTES FOR THIS COMMAND
@ -84,6 +83,7 @@ Changing either the password format (base32,base58) or length alters the seed
and thus generates a completely new set of passwords.
EXAMPLE:
Generate ten base58 passwords of length {d58} for Alice's email account:
{g.prog_name} alice@nowhere.com 1-10
@ -104,15 +104,25 @@ EXAMPLE:
{n_bw}
FMT CODES:
{n_fmt}
""".format(
o=opts,g=g,d58=dfl_len['b58'],d32=dfl_len['b32'],
ml=MMGenPWIDString.max_len,
fs="', '".join(MMGenPWIDString.forbidden),
n_pw=help_notes('passwd'),
n_bw=help_notes('brainwallet'),
n_fmt='\n '.join(SeedSource.format_fmt_codes().splitlines())
)
"""
},
'code': {
'options': lambda s: s.format(
seed_lens=', '.join(map(str,g.seed_lens)),
g=g,pnm=g.proj_name,d58=dfl_len['b58'],d32=dfl_len['b32'],dhex=dfl_len['hex'],
kgs=' '.join(['{}:{}'.format(n,k) for n,k in enumerate(g.key_generators,1)])
),
'notes': lambda s: s.format(
o=opts,g=g,d58=dfl_len['b58'],d32=dfl_len['b32'],
ml=MMGenPWIDString.max_len,
fs="', '".join(MMGenPWIDString.forbidden),
n_pw=help_notes('passwd'),
n_bw=help_notes('brainwallet'),
n_fmt='\n '.join(SeedSource.format_fmt_codes().splitlines())
)
}
}
cmd_args = opts.init(opts_data,add_opts=['b16'])

View file

@ -23,11 +23,12 @@ mmgen-regtest: Coin daemon regression test mode setup and operations for the MMG
from mmgen.common import *
opts_data = lambda: {
'desc': 'Coin daemon regression test mode setup and operations for the {} suite'.format(g.proj_name),
'usage': '[opts] <command>',
'sets': ( ('yes', True, 'quiet', True), ),
'options': """
opts_data = {
'sets': [('yes', True, 'quiet', True)],
'text': {
'desc': 'Coin daemon regression test mode setup and operations for the {} suite'.format(g.proj_name),
'usage': '[opts] <command>',
'options': """
-h, --help Print this help message
--, --longhelp Print help message for long options (common options)
-e, --empty Don't fund Bob and Alice's wallets on setup
@ -52,6 +53,7 @@ opts_data = lambda: {
show_mempool - show transaction IDs in mempool
cli [arguments] - execute an RPC call with arguments
"""
}
}
cmd_args = opts.init(opts_data)

View file

@ -26,11 +26,14 @@ import time
from mmgen.common import *
opts_data = lambda: {
'desc': """Split funds in a {pnm} wallet after a chain fork using a
timelocked transaction""".format(pnm=g.proj_name),
'usage':'[opts] [output addr1] [output addr2]',
'options': """
opts_data = {
'text': {
'desc': """
Split funds in a {pnm} wallet after a chain fork using a
timelocked transaction
""".format(pnm=g.proj_name),
'usage':'[opts] [output addr1] [output addr2]',
'options': """
-h, --help Print this help message
--, --longhelp Print help message for long options (common options)
-f, --tx-fees= f The transaction fees for each chain (comma-separated)
@ -46,7 +49,7 @@ opts_data = lambda: {
-R, --rpc-host2= h Host the other coin daemon is running on (default: none)
-L, --locktime= t Lock time (block height or unix seconds)
(default: {bh})
""".format(oc=g.proto.forks[-1][2].upper(),bh='current block height'),
""",
'notes': """\n
This command creates two transactions: one (with the timelock) to be broadcast
on the long chain and one on the short chain after a replayable chain fork.
@ -74,6 +77,12 @@ minority chain is ahead of the timelock. If the reorg'd minority chain is
behind the timelock, protection is contingent on getting the non-timelocked
transaction reconfirmed before the timelock expires. Use at your own risk.
""".format(pnm=g.proj_name)
},
'code': {
'options': lambda s: s.format(
oc=g.proto.forks[-1][2].upper(),
bh='current block height'),
}
}
cmd_args = opts.init(opts_data,add_opts=['tx_fee','tx_fee_adj','comment_file'])

View file

@ -53,10 +53,11 @@ def make_cmd_help():
return '\n'.join(out)
opts_data = lambda: {
'desc': 'Perform various {pnm}- and cryptocoin-related operations'.format(pnm=g.proj_name),
'usage': '[opts] <command> <command args>',
'options': """
opts_data = {
'text': {
'desc': 'Perform various {pnm}- and cryptocoin-related operations'.format(pnm=g.proj_name),
'usage': '[opts] <command> <command args>',
'options': """
-d, --outdir= d Specify an alternate directory 'd' for output
-h, --help Print this help message
--, --longhelp Print help message for long options (common options)
@ -70,14 +71,21 @@ opts_data = lambda: {
-t, --type=t Specify address type (valid options: 'legacy',
'compressed', 'segwit', 'bech32', 'zcash_z')
-v, --verbose Produce more verbose output
""".format(g=g),
""",
'notes': """
COMMANDS
{ch}
Type '{pn} help <command>' for help on a particular command
""".format(pn=g.prog_name,ch=make_cmd_help())
"""
},
'code': {
'options': lambda s: s.format(g=g),
'notes': lambda s: s.format(
ch=make_cmd_help(),
pn=g.prog_name)
}
}
cmd_args = opts.init(opts_data,add_opts=['hidden_incog_input_params','in_fmt','use_old_ed25519'])

View file

@ -23,11 +23,16 @@ mmgen-txbump: Increase the fee on a replaceable (replace-by-fee) MMGen
from mmgen.common import *
opts_data = lambda: {
'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), ),
'options': """
opts_data = {
'sets': [('yes', True, 'quiet', True)],
'text': {
'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),
'options': """
-h, --help Print this help message
--, --longhelp Print help message for long options (common options)
-b, --brain-params=l,p Use seed length 'l' and hash preset 'p' for
@ -66,13 +71,19 @@ opts_data = lambda: {
-y, --yes Answer 'yes' to prompts, suppress non-essential output
-z, --show-hash-presets Show information on available hash presets
""",
'options_fmt_args': lambda: dict(
g=g,pnm=g.proj_name,pnl=g.proj_name.lower(),dn=g.proto.daemon_name,
fu=help_notes('rel_fee_desc'),fl=help_notes('fee_spec_letters'),
kgs=' '.join(['{}:{}'.format(n,k) for n,k in enumerate(g.key_generators,1)]),
kg=g.key_generator,
cu=g.coin),
'notes': lambda: '\n' + help_notes('fee') + help_notes('txsign')
'notes': '\n{}{}'
},
'code': {
'options': lambda s: s.format(
g=g,pnm=g.proj_name,pnl=g.proj_name.lower(),dn=g.proto.daemon_name,
fu=help_notes('rel_fee_desc'),fl=help_notes('fee_spec_letters'),
kgs=' '.join(['{}:{}'.format(n,k) for n,k in enumerate(g.key_generators,1)]),
kg=g.key_generator,
cu=g.coin),
'notes': lambda s: s.format(
help_notes('fee'),
help_notes('txsign'))
}
}
cmd_args = opts.init(opts_data)

View file

@ -23,11 +23,12 @@ mmgen-txcreate: Create a cryptocoin transaction with MMGen- and/or non-MMGen
from mmgen.common import *
opts_data = lambda: {
'desc': 'Create a transaction with outputs to specified coin or {g.proj_name} addresses'.format(g=g),
'usage': '[opts] <addr,amt> ... [change addr] [addr file] ...',
'sets': ( ('yes', True, 'quiet', True), ),
'options': """
opts_data = {
'sets': [('yes', True, 'quiet', True)],
'text': {
'desc': 'Create a transaction with outputs to specified coin or {g.proj_name} addresses'.format(g=g),
'usage': '[opts] <addr,amt> ... [change addr] [addr file] ...',
'options': """
-h, --help Print this help message
--, --longhelp Print help message for long options (common options)
-a, --tx-fee-adj= f Adjust transaction fee by factor 'f' (see below)
@ -54,11 +55,18 @@ opts_data = lambda: {
-V, --vsize-adj= f Adjust transaction's estimated vsize by factor 'f'
-y, --yes Answer 'yes' to prompts, suppress non-essential output
""",
'options_fmt_args': lambda: dict(
g=g,cu=g.coin,
fu=help_notes('rel_fee_desc'),
fl=help_notes('fee_spec_letters') ),
'notes': lambda: '\n' + help_notes('txcreate') + help_notes('fee')
'notes': '\n{}{}',
},
'code': {
'options': lambda s: s.format(
fu=help_notes('rel_fee_desc'),
fl=help_notes('fee_spec_letters'),
cu=g.coin,
g=g),
'notes': lambda s: s.format(
help_notes('txcreate'),
help_notes('fee'))
}
}
cmd_args = opts.init(opts_data)

View file

@ -22,11 +22,12 @@ mmgen-txdo: Create, sign and broadcast an online MMGen transaction
from mmgen.common import *
opts_data = lambda: {
'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), ),
'options': """
opts_data = {
'sets': [('yes', True, 'quiet', True)],
'text': {
'desc': 'Create, sign and send an {g.proj_name} transaction'.format(g=g),
'usage': '[opts] <addr,amt> ... [change addr] [addr file] ... [seed source] ...',
'options': """
-h, --help Print this help message
--, --longhelp Print help message for long options (common options)
-a, --tx-fee-adj= f Adjust transaction fee by factor 'f' (see below)
@ -75,14 +76,21 @@ opts_data = lambda: {
-y, --yes Answer 'yes' to prompts, suppress non-essential output
-z, --show-hash-presets Show information on available hash presets
""",
'options_fmt_args': lambda: dict(
g=g,pnm=g.proj_name,pnl=g.proj_name.lower(),
kgs=' '.join(['{}:{}'.format(n,k) for n,k in enumerate(g.key_generators,1)]),
fu=help_notes('rel_fee_desc'),
fl=help_notes('fee_spec_letters'),
kg=g.key_generator,
cu=g.coin),
'notes': lambda: '\n' + help_notes('txcreate') + help_notes('fee') + help_notes('txsign')
'notes': '\n{}{}{}',
},
'code': {
'options': lambda s: s.format(
g=g,pnm=g.proj_name,pnl=g.proj_name.lower(),
kgs=' '.join(['{}:{}'.format(n,k) for n,k in enumerate(g.key_generators,1)]),
fu=help_notes('rel_fee_desc'),
fl=help_notes('fee_spec_letters'),
kg=g.key_generator,
cu=g.coin),
'notes': lambda s: s.format(
help_notes('txcreate'),
help_notes('fee'),
help_notes('txsign'))
}
}
cmd_args = opts.init(opts_data)

View file

@ -22,11 +22,12 @@ mmgen-txsend: Broadcast a transaction signed by 'mmgen-txsign' to the network
from mmgen.common import *
opts_data = lambda: {
'desc': 'Send a cryptocoin transaction signed by {pnm}-txsign'.format(pnm=g.proj_name.lower()),
'usage': '[opts] <signed transaction file>',
'sets': ( ('yes', True, 'quiet', True), ),
'options': """
opts_data = {
'sets': [('yes', True, 'quiet', True)],
'text': {
'desc': 'Send a signed {pnm} cryptocoin transaction'.format(pnm=g.proj_name),
'usage': '[opts] <signed transaction file>',
'options': """
-h, --help Print this help message
--, --longhelp Print help message for long options (common options)
-d, --outdir= d Specify an alternate directory 'd' for output
@ -34,6 +35,7 @@ opts_data = lambda: {
-s, --status Get status of a sent transaction
-y, --yes Answer 'yes' to prompts, suppress non-essential output
"""
}
}
cmd_args = opts.init(opts_data)

View file

@ -23,11 +23,12 @@ mmgen-txsign: Sign a transaction generated by 'mmgen-txcreate'
from mmgen.common import *
# -w, --use-wallet-dat (keys from running coin daemon) removed: use walletdump rpc instead
opts_data = lambda: {
'desc': 'Sign cryptocoin transactions generated by {pnl}-txcreate'.format(pnl=g.proj_name.lower()),
'usage': '[opts] <transaction file>... [seed source]...',
'sets': ( ('yes', True, 'quiet', True), ),
'options': """
opts_data = {
'sets': [('yes', True, 'quiet', True)],
'text': {
'desc': 'Sign cryptocoin transactions generated by {pnl}-txcreate'.format(pnl=g.proj_name.lower()),
'usage': '[opts] <transaction file>... [seed source]...',
'options': """
-h, --help Print this help message
--, --longhelp Print help message for long options (common options)
-b, --brain-params=l,p Use seed length 'l' and hash preset 'p' for
@ -62,13 +63,17 @@ opts_data = lambda: {
-V, --vsize-adj= f Adjust transaction's estimated vsize by factor 'f'
-y, --yes Answer 'yes' to prompts, suppress non-essential output
""",
'options_fmt_args': lambda: dict(
g=g,pnm=g.proj_name,pnl=g.proj_name.lower(),dn=g.proto.daemon_name,
kgs=' '.join(['{}:{}'.format(n,k) for n,k in enumerate(g.key_generators,1)]),
kg=g.key_generator,
cu=g.coin
),
'notes': lambda: '\n' + help_notes('txsign')
'notes': '\n{}'
},
'code': {
'options': lambda s: s.format(
g=g,pnm=g.proj_name,pnl=g.proj_name.lower(),dn=g.proto.daemon_name,
kgs=' '.join(['{}:{}'.format(n,k) for n,k in enumerate(g.key_generators,1)]),
kg=g.key_generator,
cu=g.coin),
'notes': lambda s: s.format(
help_notes('txsign'))
}
}
infiles = opts.init(opts_data,add_opts=['b16'])

View file

@ -55,12 +55,11 @@ elif invoked_as == 'passchg':
else:
die(1,"'{}': unrecognized invocation".format(g.prog_name))
opts_data = lambda: {
# 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),
'usage': usage,
'options': """
opts_data = {
'text': {
'desc': desc.format(pnm=g.proj_name),
'usage': usage,
'options': """
-h, --help Print this help message
--, --longhelp Print help message for long options (common options)
-d, --outdir= d Output files to directory 'd' instead of working dir
@ -90,22 +89,28 @@ opts_data = lambda: {
(min={g.min_urandchars}, max={g.max_urandchars}, default={g.usr_randchars})
-S, --stdout Write wallet data to stdout instead of file
-v, --verbose Produce more verbose output
""".format(
g=g,
iaction=capfirst(iaction),
oaction=capfirst(oaction),
),
""",
'notes': """
{n_pw}{n_bw}
FMT CODES:
{f}
""".format(
f='\n '.join(SeedSource.format_fmt_codes().splitlines()),
n_pw=help_notes('passwd'),
n_bw=('','\n\n' + help_notes('brainwallet'))[bw_note]
)
"""
},
'code': {
'options': lambda s: s.format(
iaction=capfirst(iaction),
oaction=capfirst(oaction),
g=g,
),
'notes': lambda s: s.format(
f='\n '.join(SeedSource.format_fmt_codes().splitlines()),
n_pw=help_notes('passwd'),
n_bw=('','\n\n' + help_notes('brainwallet'))[bw_note]
)
}
}
cmd_args = opts.init(opts_data,opt_filter=opt_filter)

View file

@ -181,10 +181,16 @@ Are you sure you want to continue?
if not keypress_confirm(m,default_yes=True):
sys.exit(0)
def get_common_opts_data():
# most, but not all, of these set the corresponding global var
def common_opts_code(s):
from mmgen.protocol import CoinProtocol
return """
return s.format(
pnm=g.proj_name,pn=g.proto.name,dn=g.proto.daemon_name,
cu_dfl=g.coin,
cu_all=' '.join(CoinProtocol.coins) )
common_opts_data = {
# most, but not all, of these set the corresponding global var
'text': """
--, --accept-defaults Accept defaults at all prompts
--, --coin=c Choose coin unit. Default: {cu_dfl}. Options: {cu_all}
--, --token=t Specify an ERC20 token by address or symbol
@ -203,29 +209,25 @@ def get_common_opts_data():
--, --version Print version information and exit
--, --bob Switch to user "Bob" in MMGen regtest setup
--, --alice Switch to user "Alice" in MMGen regtest setup
""".format( pnm=g.proj_name,pn=g.proto.name,dn=g.proto.daemon_name,
cu_dfl=g.coin,
cu_all=' '.join(CoinProtocol.coins))
""",
'code': common_opts_code
}
def init(opts_f,add_opts=[],opt_filter=None,parse_only=False):
def init(opts_data,add_opts=[],opt_filter=None,parse_only=False):
from mmgen.protocol import CoinProtocol,BitcoinProtocol,init_genonly_altcoins
g.proto = BitcoinProtocol # this must be initialized to something before opts_f is called
opts_data['text']['long_options'] = common_opts_data['text']
opts_data = opts_f()
opts_data['long_options'] = get_common_opts_data()
uopts,args,short_opts,long_opts,skipped_opts,do_help = \
mmgen.share.Opts.parse_opts(sys.argv,opts_data,opt_filter=opt_filter,skip_help=True)
uopts,args,short_opts,long_opts,skipped_opts = \
mmgen.share.Opts.parse_opts(opts_data,opt_filter=opt_filter,parse_only=parse_only)
if parse_only:
return uopts,args,short_opts,long_opts,skipped_opts,do_help
return uopts,args,short_opts,long_opts,skipped_opts
if g.debug_opts: opt_preproc_debug(short_opts,long_opts,skipped_opts,uopts,args)
# Save this for usage()
global usage_txt
usage_txt = opts_data['usage']
usage_txt = opts_data['text']['usage']
# 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)
@ -264,6 +266,7 @@ def init(opts_f,add_opts=[],opt_filter=None,parse_only=False):
if g.regtest: g.testnet = True # These are equivalent for now
from mmgen.protocol import init_genonly_altcoins,CoinProtocol
altcoin_trust_level = init_genonly_altcoins(opt.coin)
# g.testnet is set, so we can set g.proto
@ -272,7 +275,7 @@ def init(opts_f,add_opts=[],opt_filter=None,parse_only=False):
# global sets proto
if g.daemon_data_dir: g.proto.daemon_data_dir = g.daemon_data_dir
# g.proto is set, so we can set g.data_dir
# g.proto is set, so we can set g.data_dir
g.data_dir = os.path.normpath(os.path.join(g.data_dir_root,g.proto.data_subdir))
# If user opt is set, convert its type based on value in mmgen.globalvars (g)
@ -295,14 +298,15 @@ def init(opts_f,add_opts=[],opt_filter=None,parse_only=False):
opt_postproc_initializations()
if do_help: # print help screen only after global vars are initialized
opts_data = opts_f()
opts_data['long_options'] = get_common_opts_data()
if opts_data['do_help']: # print help screen only after global vars are initialized
if not 'code' in opts_data:
opts_data['code'] = {}
opts_data['code']['long_options'] = common_opts_data['code']
if g.debug_utf8:
for k in opts_data:
if type(opts_data[k]) == str:
opts_data[k] += ''
mmgen.share.Opts.parse_opts(sys.argv,opts_data,opt_filter=opt_filter) # exits
mmgen.share.Opts.print_help(opts_data,opt_filter) # exits
if g.bob or g.alice:
g.testnet = True
@ -329,18 +333,15 @@ def init(opts_f,add_opts=[],opt_filter=None,parse_only=False):
my_raw_input('Hit ENTER to continue: ')
if g.debug and g.prog_name != 'test.py':
opt.verbose,opt.quiet = True,None
opt.verbose,opt.quiet = (True,None)
if g.debug_opts: opt_postproc_debug()
# 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]
g.altcoin_data_dir = os.path.join(g.data_dir_root,'altcoins')
warn_altcoins(altcoin_trust_level)
# We don't need this data anymore
del mmgen.share.Opts, opts_data
return args
def opt_is_tx_fee(val,desc):

View file

@ -27,47 +27,57 @@ def usage(opts_data):
print('USAGE: {} {}'.format(opts_data['prog_name'], opts_data['usage']))
sys.exit(2)
def print_help_and_exit(opts_data,longhelp=False):
def print_help(opts_data,opt_filter):
t = opts_data['text']
c = opts_data['code']
# header
pn = opts_data['prog_name']
pn_len = str(len(pn)+2)
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)
o = opts_data[('options','long_options')[longhelp]].strip()
if 'options_fmt_args' in opts_data:
o = o.format(**opts_data['options_fmt_args']())
hdr = ('OPTIONS:',' LONG OPTIONS:')[longhelp]
ls = (' ','')[longhelp]
es = ('',' ')[longhelp]
out += '{ls}{}\n{ls}{es}{}'.format(hdr,('\n'+ls).join(o.splitlines()),ls=ls,es=es)
if 'notes' in opts_data and not longhelp:
n = opts_data['notes']
if isinstance(n, collections.Callable): n = n()
out += '\n ' + '\n '.join(n.rstrip().splitlines())
out = ' {:<{p}} {}\n'.format(pn.upper()+':',t['desc'].strip(),p=len(pn)+1)
out += ' {:<{p}} {} {}\n'.format('USAGE:',pn,t['usage'].strip(),p=len(pn)+1)
# options
if opts_data['do_help'] == 'longhelp':
hdr,ls,es = (' LONG OPTIONS:','',' ')
text = t['long_options'].strip()
code = c['long_options'] if 'long_options' in c else None
else:
hdr,ls,es = ('OPTIONS:',' ','')
text = t['options']
code = c['options'] if 'options' in c else None
ftext = code(text) if code else text
out += '{ls}{}\n{ls}{es}{}'.format(hdr,('\n'+ls).join(ftext.splitlines()),ls=ls,es=es)
# notes
if opts_data['do_help'] == 'help' and 'notes' in t:
ftext = c['notes'](t['notes']) if 'notes' in c else t['notes']
out += '\n ' + '\n '.join(ftext.rstrip().splitlines())
print(out)
sys.exit(0)
def process_opts(argv,opts_data,short_opts,long_opts,skip_help=False):
def process_opts(opts_data,short_opts,long_opts):
import os
opts_data['prog_name'] = os.path.basename(sys.argv[0])
long_opts = [i.replace('_','-') for i in long_opts]
so_str = short_opts.replace('-:','').replace('-','')
try: cl_opts,args = getopt.getopt(argv[1:], so_str, long_opts)
try: cl_opts,args = getopt.getopt(sys.argv[1:], so_str, long_opts)
except getopt.GetoptError as err:
print(str(err))
sys.exit(2)
sopts_list = ':_'.join(['_'.join(list(i)) for i in short_opts.split(':')]).split('_')
opts,skipped_help = {},False
opts = {}
opts_data['do_help'] = False
for opt,arg in cl_opts:
if opt in ('-h','--help'):
if not skip_help: print_help_and_exit(opts_data)
skipped_help = True
opts_data['do_help'] = 'help'
elif opt == '--longhelp':
if not skip_help: print_help_and_exit(opts_data,longhelp=True)
skipped_help = True
opts_data['do_help'] = 'longhelp'
elif opt[:2] == '--' and opt[2:] in long_opts:
opts[opt[2:].replace('-','_')] = True
elif opt[:2] == '--' and opt[2:]+'=' in long_opts:
@ -93,17 +103,18 @@ def process_opts(argv,opts_data,short_opts,long_opts,skip_help=False):
else:
opts[o_out] = v_out
return opts,args,skipped_help
return opts,args
def parse_opts(argv,opts_data,opt_filter=None,skip_help=False):
def parse_opts(opts_data,opt_filter=None,parse_only=False):
import re
pat = r'^-([a-zA-Z0-9-]), --([a-zA-Z0-9-]{2,64})(=| )(.+)'
od_all = []
for k in ['options'] + ([],['long_options'])['long_options' in opts_data]:
for k in ('options','long_options'):
if k not in opts_data['text']: continue
od,skip = [],True
for l in opts_data[k].strip().splitlines():
for l in opts_data['text'][k].strip().splitlines():
m = re.match(pat,l)
if m:
skip = bool(opt_filter) and m.group(1) not in opt_filter
@ -112,15 +123,17 @@ def parse_opts(argv,opts_data,opt_filter=None,skip_help=False):
else:
if not skip: od[-1][3] += '\n' + l
opts_data[k] = '\n'.join(
['{:<3} --{} {}'.format(
('-'+d[0]+',','')[d[0]=='-'],d[1],d[3]) for d in od if d[6] == False]
)
if not parse_only:
opts_data['text'][k] = '\n'.join(
['{:<3} --{} {}'.format(
('-'+d[0]+',','')[d[0]=='-'],d[1],d[3]) for d in od if d[6] == False]
)
od_all += od
short_opts = ''.join([d[0]+d[4] for d in od_all if d[6] == False])
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,skipped_help = process_opts(argv,opts_data,short_opts,long_opts,skip_help=skip_help)
opts,args = process_opts(opts_data,short_opts,long_opts)
return opts,args,short_opts,long_opts,skipped_opts,skipped_help
return opts,args,short_opts,long_opts,skipped_opts

View file

@ -6,13 +6,15 @@ sys.path = [repo_root] + sys.path
from mmgen.common import *
opts_data = lambda: {
'desc': 'Compute checksum for a MMGen data file',
'usage':'[opts] infile',
'options': """
opts_data = {
'text': {
'desc': 'Compute checksum for a MMGen data file',
'usage':'[opts] infile',
'options': """
-h, --help Print this help message.
-i, --include-first-line Include the first line of the file (you probably don't want this)
"""
}
}
cmd_args = opts.init(opts_data)

View file

@ -27,10 +27,11 @@ name = 'MMGen Token'
symbol = 'MMT'
solc_version_pat = r'0.5.[123]'
opts_data = lambda: {
'desc': 'Create an ERC20 token contract',
'usage':'[opts] <owner address>',
'options': """
opts_data = {
'text': {
'desc': 'Create an ERC20 token contract',
'usage':'[opts] <owner address>',
'options': """
-h, --help Print this help message
-o, --outdir= d Specify output directory for *.bin files
-d, --decimals=d Number of decimals for the token (default: {d})
@ -39,7 +40,15 @@ opts_data = lambda: {
-s, --symbol= s Token symbol (default: {s})
-S, --stdout Output data in JSON format to stdout instead of files
-v, --verbose Produce more verbose output
""".format(d=decimals,n=name,s=symbol,t=supply)
"""
},
'code': {
'options': lambda s: s.format(
d=decimals,
n=name,
s=symbol,
t=supply)
}
}
cmd_args = opts.init(opts_data)

View file

@ -22,14 +22,16 @@ tx-btc2bch: Convert MMGen transaction files from BTC to BCH format
from mmgen.common import *
opts_data = lambda: {
'desc': """Convert {pnm} transaction files from BTC to BCH format""".format(pnm=g.proj_name),
'usage':'[opts] [mmgen transaction file]',
'options': """
opts_data = {
'text': {
'desc': """Convert {pnm} transaction files from BTC to BCH format""".format(pnm=g.proj_name),
'usage':'[opts] [mmgen transaction file]',
'options': """
-h, --help Print this help message
--, --longhelp Print help message for long options (common options)
-v, --verbose Produce more verbose output
"""
}
}
cmd_args = opts.init(opts_data)

View file

@ -9,15 +9,17 @@ sys.path = [repo_root] + sys.path
from mmgen.common import *
opts_data = lambda: {
'desc': "Convert MMGen transaction file from v2 format to v3 format",
'usage': "<tx file>",
'options': """
opts_data = {
'text': {
'desc': "Convert MMGen transaction file from v2 format to v3 format",
'usage': "<tx file>",
'options': """
-h, --help Print this help message
-d, --outdir=d Output files to directory 'd' instead of working dir
-q, --quiet Write (and overwrite) files without prompting
-S, --stdout Write data to STDOUT instead of file
"""
}
}
cmd_args = opts.init(opts_data)

View file

@ -40,15 +40,16 @@ modpath_save = sys.modules['mmgen.main'].__spec__.origin
from mmgen.common import *
opts_data = lambda: {
'prog_name': sys.argv[0].split('/')[-1],
'desc': 'Remove MMGen from your system',
'usage': '[opts]',
'options': """
opts_data = {
'text': {
'desc': 'Remove MMGen from your system',
'usage': '[opts]',
'options': """
-h, --help Print this help message
-l, --list-paths List the directories and files that would be deleted
-n, --no-prompt Don't prompt before deleting
"""
}
}
cmd_args = opts.init(opts_data)

View file

@ -31,10 +31,11 @@ from mmgen.common import *
from mmgen.obj import MMGenAddrType
rounds = 100
opts_data = lambda: {
'desc': 'Test address generation in various ways',
'usage':'[options] [spec] [rounds | dump file]',
'options': """
opts_data = {
'text': {
'desc': 'Test address generation in various ways',
'usage':'[options] [spec] [rounds | dump file]',
'options': """
-h, --help Print this help message
-a, --all Test all supported coins for external generator 'ext'
-k, --use-internal-keccak-module Force use of the internal keccak module
@ -68,7 +69,15 @@ EXAMPLES:
+ pycoin (for supported coins) https://github.com/richardkiss/pycoin
+ keyconv (for all other coins) https://github.com/exploitagency/vanitygen-plus
('keyconv' generates uncompressed addresses only)
""".format(prog='gentest.py',pnm=g.proj_name,snum=rounds,dn=g.proto.daemon_name)
"""
},
'code': {
'notes': lambda s: s.format(
prog='gentest.py',
pnm=g.proj_name,
snum=rounds,
dn=g.proto.daemon_name)
}
}
sys.argv = [sys.argv[0]] + ['--skip-cfg-file'] + sys.argv[1:]

View file

@ -30,11 +30,12 @@ from mmgen.common import *
from mmgen.obj import *
from mmgen.seed import *
opts_data = lambda: {
'desc': 'Test MMGen data objects',
'sets': ( ('super_silent', True, 'silent', True), ),
'usage':'[options] [object]',
'options': """
opts_data = {
'sets': [('super_silent', True, 'silent', True)],
'text': {
'desc': 'Test MMGen data objects',
'usage':'[options] [object]',
'options': """
-h, --help Print this help message
--, --longhelp Print help message for long options (common options)
-q, --quiet Produce quieter output
@ -42,6 +43,7 @@ opts_data = lambda: {
-S, --super-silent Silence all output except for errors
-v, --verbose Produce more verbose output
"""
}
}
cmd_args = opts.init(opts_data)

View file

@ -30,10 +30,11 @@ os.environ['MMGEN_TEST_SUITE'] = '1'
from mmgen.common import *
from test.common import init_coverage
opts_data = lambda: {
'desc': 'Test seed scrambling and addrlist data generation for all supported altcoins',
'usage':'[options] [command]',
'options': """
opts_data = {
'text': {
'desc': 'Test seed scrambling and addrlist data generation for all supported altcoins',
'usage':'[options] [command]',
'options': """
-h, --help Print this help message
--, --longhelp Print help message for long options (common options)
-C, --coverage Produce code coverage info using trace module
@ -46,6 +47,7 @@ opts_data = lambda: {
If no command is given, the whole suite of tests is run.
"""
}
}
cmd_args = opts.init(opts_data)

View file

@ -84,10 +84,11 @@ from test.test_py_d.common import *
g.quiet = False # if 'quiet' was set in config file, disable here
os.environ['MMGEN_QUIET'] = '0' # for this script and spawned scripts
opts_data = lambda: {
'desc': 'Test suite for the MMGen suite',
'usage':'[options] [command(s) or metacommand(s)]',
'options': """
opts_data = {
'text': {
'desc': 'Test suite for the MMGen suite',
'usage':'[options] [command(s) or metacommand(s)]',
'options': """
-h, --help Print this help message
--, --longhelp Print help message for long options (common options)
-B, --bech32 Generate and use Bech32 addresses
@ -122,11 +123,17 @@ opts_data = lambda: {
-X, --exit-after=C Exit after command 'C'
-y, --segwit Generate and use Segwit addresses
-Y, --segwit-random Generate and use a random mix of Segwit and Legacy addrs
""".format(tbc='scripts/traceback_run.py',lf=log_file),
'notes': """
""",
'notes': """
If no command is given, the whole test suite is run.
"""
},
'code': {
'options': lambda s: s.format(
tbc='scripts/traceback_run.py',
lf=log_file),
}
}
data_dir = os.path.join('test','data_dir' + ('','')[bool(os.getenv('MMGEN_DEBUG_UTF8'))])

View file

@ -31,10 +31,11 @@ os.environ['MMGEN_TEST_SUITE'] = '1'
from mmgen.common import *
from test.common import *
opts_data = lambda: {
'desc': "Test suite for the 'mmgen-tool' utility",
'usage':'[options] [command]',
'options': """
opts_data = {
'text': {
'desc': "Test suite for the 'mmgen-tool' utility",
'usage':'[options] [command]',
'options': """
-h, --help Print this help message
-C, --coverage Produce code coverage info using trace module
-d, --debug Produce debugging output (stderr from spawned script)
@ -50,6 +51,7 @@ opts_data = lambda: {
If no command is given, the whole suite of tests is run.
"""
}
}
sys.argv = [sys.argv[0]] + ['--skip-cfg-file'] + sys.argv[1:]

View file

@ -40,10 +40,11 @@ from mmgen.seed import is_mnemonic
def is_str(s): return type(s) == str
opts_data = lambda: {
'desc': "Simple test suite for the 'mmgen-tool' utility",
'usage':'[options] [command]',
'options': """
opts_data = {
'text': {
'desc': "Simple test suite for the 'mmgen-tool' utility",
'usage':'[options] [command]',
'options': """
-h, --help Print this help message
-C, --coverage Produce code coverage info using trace module
-d, --die-on-missing Abort if no test data found for given command
@ -63,6 +64,7 @@ opts_data = lambda: {
If no command is given, the whole suite of tests is run.
"""
}
}
sample_text_hexdump = (

View file

@ -30,10 +30,11 @@ os.environ['MMGEN_TEST_SUITE'] = '1'
# Import these _after_ prepending repo_root to sys.path
from mmgen.common import *
opts_data = lambda: {
'desc': "Unit tests for the MMGen suite",
'usage':'[options] [tests]',
'options': """
opts_data = {
'text': {
'desc': "Unit tests for the MMGen suite",
'usage':'[options] [tests]',
'options': """
-h, --help Print this help message
-l, --list List available tests
-n, --names Print command names instead of descriptions
@ -43,6 +44,7 @@ opts_data = lambda: {
'notes': """
If no test is specified, all available tests are run
"""
}
}
sys.argv = [sys.argv[0]] + ['--skip-cfg-file'] + sys.argv[1:]