__init__.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. #!/usr/bin/env python3
  2. #
  3. # MMGen Wallet, a terminal-based cryptocurrency wallet
  4. # Copyright (C)2013-2024 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. help: help notes for MMGen suite commands
  20. """
  21. import sys
  22. from ..cfg import gc
  23. def version(cfg):
  24. from ..util import fmt
  25. print(fmt(f"""
  26. {gc.prog_name.upper()} version {gc.version}
  27. Part of {gc.proj_name} Wallet, an online/offline cryptocurrency wallet for the
  28. command line. Copyright (C){gc.Cdates} {gc.author} {gc.email}
  29. """, indent=' ').rstrip())
  30. sys.exit(0)
  31. def show_hash_presets(cfg):
  32. fs = ' {:<6} {:<3} {:<2} {}'
  33. from ..util import msg
  34. from ..crypto import Crypto
  35. msg(' Available parameters for scrypt.hash():')
  36. msg(fs.format('Preset', 'N', 'r', 'p'))
  37. for i in sorted(Crypto.hash_presets.keys()):
  38. msg(fs.format(i, *Crypto.hash_presets[i]))
  39. msg(' N = memory usage (power of two)\n p = iterations (rounds)')
  40. sys.exit(0)
  41. def make_usage_str(cfg, caller):
  42. indent, col1_w = {
  43. 'help': (2, len(gc.prog_name) + 1),
  44. 'user': (0, len('USAGE:')),
  45. }[caller]
  46. def gen():
  47. ulbl = 'USAGE:'
  48. for line in [cfg._usage_data.strip()] if isinstance(cfg._usage_data, str) else cfg._usage_data:
  49. yield f'{ulbl:{col1_w}} {gc.prog_name} {line}'
  50. ulbl = ''
  51. return ('\n' + (' ' * indent)).join(gen())
  52. def usage(cfg):
  53. print(make_usage_str(cfg, caller='user'))
  54. sys.exit(0)
  55. class Help:
  56. def make(self, cfg, opts, proto):
  57. def gen_arg_tuple(func, text):
  58. def help_notes(k):
  59. import importlib
  60. return getattr(importlib.import_module(
  61. f'{opts.help_pkg}.help_notes').help_notes(proto, cfg), k)()
  62. def help_mod(modname):
  63. import importlib
  64. return importlib.import_module(
  65. f'{opts.help_pkg}.{modname}').help(proto, cfg)
  66. d = {
  67. 'proto': proto,
  68. 'help_notes': help_notes,
  69. 'help_mod': help_mod,
  70. 'cfg': cfg,
  71. }
  72. for arg in func.__code__.co_varnames:
  73. yield d[arg] if arg in d else text
  74. def gen_output():
  75. yield ' {} {}'.format(gc.prog_name.upper() + ':', text['desc'].strip())
  76. yield make_usage_str(cfg, caller='help')
  77. yield help_type.upper().replace('_', ' ') + ':'
  78. # process code for options
  79. opts_text = nl.join(self.gen_text(opts))
  80. if help_type in code:
  81. yield code[help_type](*tuple(gen_arg_tuple(code[help_type], opts_text)))
  82. else:
  83. yield opts_text
  84. # process code for notes
  85. if help_type == 'options' and 'notes' in text:
  86. if 'notes' in code:
  87. yield from code['notes'](*tuple(gen_arg_tuple(code['notes'], text['notes']))).splitlines()
  88. else:
  89. yield from text['notes'].splitlines()
  90. text = opts.opts_data['text']
  91. code = opts.opts_data['code']
  92. help_type = self.help_type
  93. nl = '\n '
  94. return nl.join(gen_output()) + '\n'
  95. class CmdHelp(Help):
  96. help_type = 'options'
  97. def gen_text(self, opts):
  98. opt_filter = opts.opt_filter
  99. from ..opts import cmd_opts_pat
  100. skipping = False
  101. for line in opts.opts_data['text']['options'].strip().splitlines():
  102. if m := cmd_opts_pat.match(line):
  103. if opt_filter:
  104. if m[1] in opt_filter:
  105. skipping = False
  106. else:
  107. skipping = True
  108. continue
  109. yield '{} --{} {}'.format(
  110. (f'-{m[1]},', ' ')[m[1] == '-'],
  111. m[2],
  112. m[4])
  113. elif not skipping:
  114. yield line
  115. class GlobalHelp(Help):
  116. help_type = 'global_options'
  117. def gen_text(self, opts):
  118. from ..opts import global_opts_pat
  119. for line in opts.global_opts_data['text'][1:-2].splitlines():
  120. if m := global_opts_pat.match(line):
  121. if m[1] in opts.global_opts_filter.coin and m[2] in opts.global_opts_filter.cmd:
  122. yield ' --{} {}'.format(m[3], m[5])
  123. skipping = False
  124. else:
  125. skipping = True
  126. elif not skipping:
  127. yield line[4:]
  128. def print_help(cfg, opts):
  129. from ..protocol import init_proto_from_cfg
  130. proto = init_proto_from_cfg(cfg, need_amt=True)
  131. if not 'code' in opts.opts_data:
  132. opts.opts_data['code'] = {}
  133. if cfg.help:
  134. cls = CmdHelp
  135. else:
  136. opts.opts_data['code']['global_options'] = opts.global_opts_data['code']
  137. cls = GlobalHelp
  138. from ..ui import do_pager
  139. do_pager(cls().make(cfg, opts, proto))
  140. sys.exit(0)