chainlib

Generic blockchain access library and tooling
Info | Log | Files | Refs | README | LICENSE

chainlib-man.py (7382B)


      1 #!/usr/bin/python3
      2 
      3 import logging
      4 import os
      5 import sys
      6 import argparse
      7 import tempfile
      8 import shutil
      9 
     10 from hexathon import strip_0x, add_0x
     11 
     12 from chainlib.cli.man import (
     13         EnvDocGenerator,
     14         DocGenerator,
     15         apply_groff,
     16         )
     17 from chainlib.cli.arg import ArgFlag
     18 #from chainlib.cli.base import (
     19 #        argflag_std_base,
     20 #        flag_names,
     21 #        )
     22 from chainlib.cli.arg import ArgumentParser as ChainlibArgumentParser
     23 from chainlib.cli.config import Config
     24         
     25 
     26 logging.basicConfig(level=logging.WARNING)
     27 logg = logging.getLogger()
     28 
     29 
     30 configuration_description = """
     31 .SH CONFIGURATION
     32 
     33 All configuration settings may be overriden both by environment variables, or by overriding settings with the contents of ini-files in the directory defined by the \\fB-c\\fP option.
     34 
     35 The active configuration, with values assigned from environment and arguments, can be output using the \\fB--dumpconfig\\fP \\fIformat\\fP option. Note that entries having keys prefixed with underscore (e.g. _SEQ) are not actual configuration settings, and thus cannot be overridden with environment variables.
     36 
     37 To refer to a configuration setting by environment variables, the \\fIsection\\fP and \\fIkey\\fP are concatenated together with an underscore, and transformed to upper-case. For example, the configuration variable \\fIFOO_BAZ_BAR\\fP refers to an ini-file entry as follows:
     38 
     39 .EX
     40 [foo]
     41 bar_baz = xyzzy
     42 .EE
     43 
     44 In the \\fBENVIRONMENT\\fP section below, the relevant configuration settings for this tool is listed along with a short description of its meaning.
     45 
     46 Some configuration settings may also be overriden by command line options. Also note that the use of the \\fB-n\\fP and \\fB--env-prefix\\fP options affect how environment and configuration is read. The effects of options on how configuration settings are affective is described in the respective \\fBOPTIONS\\fP section.
     47 
     48 """
     49 
     50 seealso_description = """
     51 .SH SEE ALSO
     52 
     53 .BP
     54 confini-dump(1), eth-keyfile(1)
     55 
     56 """
     57 
     58 legal_description = """
     59 .SH LICENSE
     60 
     61 This documentation and its source is licensed under the Creative Commons Attribution-Sharealike 4.0 International license.
     62 
     63 The source code of the tool this documentation describes is licensed under the GNU General Public License 3.0.
     64 
     65 .SH COPYRIGHT
     66 
     67 Louis Holbrook <dev@holbrook.no> (https://holbrook.no)
     68 PGP: 59A844A484AC11253D3A3E9DCDCBD24DD1D0E001
     69 
     70 """
     71 
     72 source_description = """
     73 
     74 .SH SOURCE CODE
     75 
     76 https://git.defalsify.org
     77 
     78 """
     79 
     80 argflag = ArgFlag()
     81 
     82 argparser = argparse.ArgumentParser()
     83 argparser.add_argument('-b', default=add_0x(hex(argflag.get('std_base'))), help='argument flag bitmask')
     84 argparser.add_argument('-c', help='config override directory')
     85 argparser.add_argument('-n', required=True, help='tool name to use for man filename')
     86 argparser.add_argument('-d', default='.', help='output directory')
     87 argparser.add_argument('-v', action='store_true', help='turn on debug logging')
     88 #argparser.add_argument('--overrides-dir', dest='overrides_dir', help='load options description override from file')
     89 argparser.add_argument('--overrides-env-dir', dest='overrides_env_dir', help='load envionment description override config from directory')
     90 argparser.add_argument('--overrides-config-file', dest='overrides_config_file', help='load configuration text from file')
     91 argparser.add_argument('source_dir', help='directory containing sources for the tool man page')
     92 args = argparser.parse_args(sys.argv[1:])
     93 
     94 if args.v:
     95     logg.setLevel(logging.DEBUG)
     96 
     97 b = bytes.fromhex(strip_0x(args.b))
     98 flags = int.from_bytes(b, byteorder='big')
     99 flags_debug = argflag.names(flags)
    100 
    101 logg.debug('apply arg flags {}: {}'.format(flags, ', '.join(flags_debug)))
    102 
    103 # TODO: unfortunately, if arguments are added in chainlib/cli/arg.py  they still also have to be manually added in chainlib/cli/man.py
    104 g = DocGenerator(flags)
    105 
    106 toolname = args.n
    107 g.process()
    108 
    109 def apply_override(g, override_dir):
    110     #if args.overrides_dir != None:
    111     overrides_file = os.path.join(override_dir, toolname + '.overrides')
    112     override = True
    113     f = None
    114     try:
    115         f = open(overrides_file, 'r')
    116     except FileNotFoundError:
    117         logg.debug('no overrides found for {}'.format(toolname))
    118         override = False
    119 
    120     if override:
    121         while True:
    122             s = f.readline()
    123             if len(s) == 0:
    124                 break
    125             v = s.split('\t', maxsplit=4)
    126             fargs = None
    127             try:
    128                 fargs = v[2].rstrip().split(',')
    129             except IndexError:
    130                 fargs = []
    131             argvalue = None
    132             if len(v) == 4:
    133                 argvalue = v[3]
    134             try:
    135                 g.override_arg(v[0], v[1], fargs, argvalue=argvalue)
    136             except KeyError:
    137                 logg.info('adding not previously registered key {} flags: {}'.format(v[0], ','.join(fargs)))
    138                 g.set_arg(v[0], v[1], fargs, argvalue=argvalue)
    139         f.close()
    140     return g
    141 
    142 
    143 def get_head(tool_name, source_dir):
    144     header_file = os.path.join(source_dir, tool_name + '.head.groff') 
    145     f = open(header_file, 'r')
    146     head = f.read()
    147     f.close()
    148     return head
    149 
    150 
    151 def get_examples(tool_name, source_dir):
    152     example_file = os.path.join(source_dir, tool_name + '.examples.groff')
    153     f = None
    154     try:
    155         f = open(example_file, 'r')
    156     except FileNotFoundError:
    157         logg.debug('no examples file found for {}'.format(tool_name))
    158         return None
    159     logg.info('examples file {} found for {}'.format(example_file, tool_name))
    160     examples = f.read()
    161     f.close()
    162     return examples
    163 
    164 
    165 def get_custom(tool_name, source_dir):
    166     custom_file = os.path.join(source_dir, tool_name + '.custom.groff')
    167     f = None
    168     try:
    169         f = open(custom_file, 'r')
    170     except FileNotFoundError:
    171         logg.debug('no custom file found for {}'.format(tool_name))
    172         return None
    173     logg.info('custom file {} found for {}'.format(custom_file, tool_name))
    174     custom = f.read()
    175     f.close()
    176     return custom
    177 
    178 
    179 def get_seealso(tool_name, source_dir):
    180     seealso_file = os.path.join(source_dir, tool_name + '.seealso.groff')
    181     f = None
    182     try:
    183         f = open(seealso_file, 'r')
    184     except FileNotFoundError:
    185         logg.debug('no seealso file found for {}'.format(tool_name))
    186         return None
    187     logg.info('seealso file {} found for {}'.format(seealso_file, tool_name))
    188     seealso = f.read()
    189     f.close()
    190     return seealso
    191 
    192 
    193 g = apply_override(g, args.source_dir)
    194 
    195 ge = EnvDocGenerator(flags, override=args.overrides_env_dir)
    196 ge.process()
    197 
    198 head = get_head(toolname, args.source_dir)
    199 examples = get_examples(toolname, args.source_dir)
    200 custom = get_custom(toolname, args.source_dir)
    201 seealso = get_seealso(toolname, args.source_dir)
    202 
    203 if args.overrides_config_file != None:
    204     f = open(args.overrides_config_file, 'r')
    205     configuration_description = f.read()
    206     f.close()
    207 
    208 (fd, fp) = tempfile.mkstemp()
    209 f = os.fdopen(fd, 'w')
    210 f.write(head)
    211 f.write(str(g))
    212 f.write(configuration_description)
    213 
    214 if custom != None:
    215     f.write(custom)
    216 
    217 if examples != None:
    218     f.write(".SH EXAMPLES\n\n")
    219     f.write(examples)
    220 
    221 if seealso != None:
    222     seealso_description = seealso
    223 
    224 if len(ge) > 0:
    225     f.write(".SH ENVIRONMENT\n\n")
    226     f.write(str(ge))
    227 
    228 f.write(legal_description)
    229 f.write(source_description)
    230 f.write(seealso_description)
    231 f.close()
    232 
    233 dest = os.path.join(args.d, toolname + '.1')
    234 shutil.copyfile(fp, dest)
    235 
    236 os.unlink(fp)