opts.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. #!/usr/bin/env python3
  2. #
  3. # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
  4. # Copyright (C)2013-2023 The MMGen Project <mmgen@tuta.io>
  5. #
  6. # This program is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation, either version 3 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. """
  19. opts: MMGen-specific command-line options processing after generic processing by share.Opts
  20. """
  21. import sys,os
  22. from .cfg import gc
  23. import mmgen.share.Opts as Opts
  24. def opt_preproc_debug(po):
  25. d = (
  26. ('Cmdline', ' '.join(sys.argv), False),
  27. ('Filtered opts', po.filtered_opts, False),
  28. ('User-selected opts', po.user_opts, False),
  29. ('Cmd args', po.cmd_args, False),
  30. ('Opts', po.opts, True),
  31. )
  32. from .util import Msg,fmt_list
  33. from pprint import pformat
  34. Msg('\n=== opts.py debug ===')
  35. for label,data,pretty in d:
  36. Msg(' {:<20}: {}'.format(label,'\n' + fmt_list(data,fmt='col',indent=' '*8) if pretty else data))
  37. long_opts_data = {
  38. 'text': """
  39. --, --accept-defaults Accept defaults at all prompts
  40. --, --coin=c Choose coin unit. Default: BTC. Current choice: {cu_dfl}
  41. --, --token=t Specify an ERC20 token by address or symbol
  42. --, --color=0|1 Disable or enable color output (enabled by default)
  43. --, --columns=N Force N columns of output with certain commands
  44. --, --scroll Use the curses-like scrolling interface for
  45. tracking wallet views
  46. --, --force-256-color Force 256-color output when color is enabled
  47. --, --pager Pipe output of certain commands to pager (WIP)
  48. --, --data-dir=path Specify {pnm} data directory location
  49. --, --daemon-data-dir=path Specify coin daemon data directory location
  50. --, --daemon-id=ID Specify the coin daemon ID
  51. --, --ignore-daemon-version Ignore coin daemon version check
  52. --, --http-timeout=t Set HTTP timeout in seconds for JSON-RPC connections
  53. --, --no-license Suppress the GPL license prompt
  54. --, --rpc-host=HOST Communicate with coin daemon running on host HOST
  55. --, --rpc-port=PORT Communicate with coin daemon listening on port PORT
  56. --, --rpc-user=USER Authenticate to coin daemon using username USER
  57. --, --rpc-password=PASS Authenticate to coin daemon using password PASS
  58. --, --rpc-backend=backend Use backend 'backend' for JSON-RPC communications
  59. --, --aiohttp-rpc-queue-len=N Use N simultaneous RPC connections with aiohttp
  60. --, --regtest=0|1 Disable or enable regtest mode
  61. --, --testnet=0|1 Disable or enable testnet
  62. --, --skip-cfg-file Skip reading the configuration file
  63. --, --version Print version information and exit
  64. --, --bob Specify user “Bob” in MMGen regtest mode
  65. --, --alice Specify user “Alice” in MMGen regtest mode
  66. --, --carol Specify user “Carol” in MMGen regtest mode
  67. """,
  68. 'code': lambda proto,s: s.format(
  69. pnm = gc.proj_name,
  70. cu_dfl = proto.coin,
  71. )
  72. }
  73. opts_data_dfl = {
  74. 'text': {
  75. 'desc': '',
  76. 'usage':'',
  77. 'options': """
  78. -h, --help Print this help message
  79. --, --longhelp Print help message for long (common) options
  80. """
  81. }
  82. }
  83. class UserOpts:
  84. def __init__(
  85. self,
  86. cfg,
  87. opts_data = None,
  88. init_opts = None, # dict containing opts to pre-initialize
  89. opt_filter = None, # whitelist of opt letters; all others are skipped
  90. parse_only = False,
  91. parsed_opts = None ):
  92. self.opts_data = od = opts_data or opts_data_dfl
  93. self.opt_filter = opt_filter
  94. od['text']['long_options'] = long_opts_data['text']
  95. # Make this available to usage()
  96. self.usage_data = od['text'].get('usage2') or od['text']['usage']
  97. # po: (user_opts,cmd_args,opts,filtered_opts)
  98. po = parsed_opts or Opts.parse_opts(od,opt_filter=opt_filter,parse_only=parse_only)
  99. cfg._args = po.cmd_args
  100. cfg._uopts = uopts = po.user_opts
  101. if init_opts: # initialize user opts to given value
  102. for uopt,val in init_opts.items():
  103. if uopt not in uopts:
  104. uopts[uopt] = val
  105. cfg._opts = self
  106. cfg._parsed_opts = po
  107. cfg._use_env = True
  108. cfg._use_cfg_file = not 'skip_cfg_file' in uopts
  109. if os.getenv('MMGEN_DEBUG_OPTS'):
  110. opt_preproc_debug(po)
  111. if 'version' in uopts:
  112. self.version() # exits
  113. if 'show_hash_presets' in uopts:
  114. self.show_hash_presets() # exits
  115. if parse_only:
  116. return
  117. def init_bottom(self,cfg):
  118. # print help screen only after globals initialized and locked:
  119. if cfg.help or cfg.longhelp:
  120. self.print_help(cfg) # exits
  121. # delete unneeded data:
  122. for k in ('text','notes','code'):
  123. if k in self.opts_data:
  124. del self.opts_data[k]
  125. del Opts.make_help
  126. del Opts.process_uopts
  127. del Opts.parse_opts
  128. def usage(self):
  129. from .util import Die
  130. Die(1,Opts.make_usage_str(gc.prog_name,'user',self.usage_data))
  131. def version(self):
  132. from .util import Die,fmt
  133. Die(0,fmt(f"""
  134. {gc.prog_name.upper()} version {gc.version}
  135. Part of the {gc.proj_name} suite, an online/offline cryptocurrency wallet for the
  136. command line. Copyright (C){gc.Cdates} {gc.author} {gc.email}
  137. """,indent=' ').rstrip())
  138. def print_help(self,cfg):
  139. if not 'code' in self.opts_data:
  140. self.opts_data['code'] = {}
  141. from .protocol import init_proto_from_cfg
  142. proto = init_proto_from_cfg(cfg,need_amt=True)
  143. if getattr(cfg,'longhelp',None):
  144. self.opts_data['code']['long_options'] = long_opts_data['code']
  145. def remove_unneeded_long_opts():
  146. d = self.opts_data['text']['long_options']
  147. if proto.base_proto != 'Ethereum':
  148. d = '\n'.join(''+i for i in d.split('\n') if not '--token' in i)
  149. self.opts_data['text']['long_options'] = d
  150. remove_unneeded_long_opts()
  151. from .ui import do_pager
  152. do_pager(Opts.make_help( cfg, proto, self.opts_data, self.opt_filter ))
  153. sys.exit(0)
  154. def show_hash_presets(self):
  155. fs = ' {:<6} {:<3} {:<2} {}'
  156. from .util import msg
  157. from .crypto import Crypto
  158. msg(' Available parameters for scrypt.hash():')
  159. msg(fs.format('Preset','N','r','p'))
  160. for i in sorted(Crypto.hash_presets.keys()):
  161. msg(fs.format(i,*Crypto.hash_presets[i]))
  162. msg(' N = memory usage (power of two)\n p = iterations (rounds)')
  163. sys.exit(0)