Compare commits
2 Commits
3691f75f81
...
af7f977007
Author | SHA1 | Date | |
---|---|---|---|
|
af7f977007 | ||
|
92fb016014 |
@ -1,17 +1,50 @@
|
|||||||
|
# standard imports
|
||||||
|
import os
|
||||||
|
|
||||||
|
# external imports
|
||||||
|
import confini
|
||||||
|
|
||||||
# local imports
|
# local imports
|
||||||
from .base import (
|
from .base import (
|
||||||
Flag,
|
Flag,
|
||||||
argflag_std_target,
|
argflag_std_target,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
data_dir = os.path.join(script_dir, '..', 'data')
|
||||||
|
|
||||||
|
|
||||||
|
def apply_groff(collection, v, arg=None, typ='arg'):
|
||||||
|
s = ''
|
||||||
|
for flag in collection:
|
||||||
|
if len(s) > 0:
|
||||||
|
s += ', '
|
||||||
|
s += format_groff(flag, v, arg=arg, typ=typ)
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
def format_groff(k, v, arg=None, typ='arg'):
|
||||||
|
s = ''
|
||||||
|
if typ == 'env':
|
||||||
|
s += '\\fI'
|
||||||
|
else:
|
||||||
|
s += '\\fB'
|
||||||
|
s += k
|
||||||
|
if arg != None:
|
||||||
|
s += ' \\fI' + arg
|
||||||
|
s += '\\fP'
|
||||||
|
s = "\n.TP\n" + s + "\n" + v
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
class DocEntry:
|
class DocEntry:
|
||||||
|
|
||||||
def __init__(self, *args, argvalue=None):
|
def __init__(self, *args, argvalue=None, typ='arg'):
|
||||||
self.flags = args
|
self.flags = args
|
||||||
self.v = argvalue
|
self.v = argvalue
|
||||||
self.render = self.get_empty
|
self.render = self.get_empty
|
||||||
self.groff = None
|
self.groff = None
|
||||||
|
self.typ = typ
|
||||||
|
|
||||||
|
|
||||||
def __check_line_default(self, m):
|
def __check_line_default(self, m):
|
||||||
@ -36,20 +69,10 @@ class DocEntry:
|
|||||||
|
|
||||||
|
|
||||||
def get_groff(self):
|
def get_groff(self):
|
||||||
s = ''
|
|
||||||
for flag in self.flags:
|
|
||||||
if len(s) > 0:
|
|
||||||
s += ', '
|
|
||||||
s += '\\fB' + flag
|
|
||||||
if self.v != None:
|
|
||||||
s += ' \\fI' + self.v
|
|
||||||
s += '\\fP'
|
|
||||||
|
|
||||||
v = self.groff
|
v = self.groff
|
||||||
if v == None:
|
if v == None:
|
||||||
v = self.plain
|
v = self.plain
|
||||||
|
s = apply_groff(self.flags, v, arg=self.v, typ=self.typ)
|
||||||
s = "\n.TP\n" + s + "\n" + self.groff
|
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
@ -59,9 +82,12 @@ class DocEntry:
|
|||||||
|
|
||||||
class DocGenerator:
|
class DocGenerator:
|
||||||
|
|
||||||
|
# def __init__(self, arg_flags, config):
|
||||||
def __init__(self, arg_flags):
|
def __init__(self, arg_flags):
|
||||||
|
#self.config = config
|
||||||
self.arg_flags = arg_flags
|
self.arg_flags = arg_flags
|
||||||
self.docs = {}
|
self.docs = {}
|
||||||
|
# self.envs = {}
|
||||||
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
@ -73,7 +99,34 @@ class DocGenerator:
|
|||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
def process(self):
|
def get_args(self):
|
||||||
|
s = ''
|
||||||
|
ks = list(self.docs.keys())
|
||||||
|
ks.sort()
|
||||||
|
for k in ks:
|
||||||
|
s += str(self.docs[k]) + "\n"
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
def override_arg(self, k, v, args):
|
||||||
|
o = self.docs[k]
|
||||||
|
#g.docs[v[0]].groff = v[1].rstrip()
|
||||||
|
o.set_groff(v)
|
||||||
|
l = len(args)
|
||||||
|
if l > 0:
|
||||||
|
o.flags = []
|
||||||
|
for i in range(l):
|
||||||
|
o.flags.append(args[i])
|
||||||
|
|
||||||
|
#
|
||||||
|
# def process_env(self):
|
||||||
|
# for k in self.config.all():
|
||||||
|
# if k[0] == '_':
|
||||||
|
# continue
|
||||||
|
# self.envs[k] = None
|
||||||
|
|
||||||
|
|
||||||
|
def process_arg(self):
|
||||||
if self.arg_flags & Flag.VERBOSE:
|
if self.arg_flags & Flag.VERBOSE:
|
||||||
o = DocEntry('--no-logs')
|
o = DocEntry('--no-logs')
|
||||||
o.set_groff('Turn of logging completely. Negates \\fB-v\\fP and \\fB-vv\\fP')
|
o.set_groff('Turn of logging completely. Negates \\fB-v\\fP and \\fB-vv\\fP')
|
||||||
@ -98,7 +151,7 @@ class DocGenerator:
|
|||||||
self.docs['n'] = o
|
self.docs['n'] = o
|
||||||
|
|
||||||
o = DocEntry('--dumpconfig', argvalue='format')
|
o = DocEntry('--dumpconfig', argvalue='format')
|
||||||
o.set_groff('Load given configuration namespace. Configuration will be loaded from the immediate configuration subdirectory with the same name.')
|
o.set_groff('Output configuration settings rendered from environment and inputs. Valid arguments are \\fIini\\fP for ini file output, and \\fIenv\\fP for environment variable output')
|
||||||
self.docs['dumpconfig'] = o
|
self.docs['dumpconfig'] = o
|
||||||
|
|
||||||
|
|
||||||
@ -211,3 +264,58 @@ class DocGenerator:
|
|||||||
o = DocEntry('-a', '--recipient-address')
|
o = DocEntry('-a', '--recipient-address')
|
||||||
o.set_groff('Network wallet address to operate on. For read calls, this will be the wallet address for which the query is anchored. For transaction calls, it will be the wallet address for which state will be changed.')
|
o.set_groff('Network wallet address to operate on. For read calls, this will be the wallet address for which the query is anchored. For transaction calls, it will be the wallet address for which state will be changed.')
|
||||||
self.docs['a'] = o
|
self.docs['a'] = o
|
||||||
|
|
||||||
|
|
||||||
|
def process(self):
|
||||||
|
self.process_arg()
|
||||||
|
# self.process_env()
|
||||||
|
|
||||||
|
|
||||||
|
class EnvDocGenerator:
|
||||||
|
|
||||||
|
def __init__(self, arg_flags, override=None):
|
||||||
|
self.arg_flags = arg_flags
|
||||||
|
self.envs = {}
|
||||||
|
env_dir = os.path.join(data_dir, 'env')
|
||||||
|
self.config = confini.Config(env_dir, override_dirs=override)
|
||||||
|
self.config.process()
|
||||||
|
|
||||||
|
|
||||||
|
def __add(self, k):
|
||||||
|
v = format_groff(k, self.config.get(k), None, typ='env')
|
||||||
|
self.envs[k] = v
|
||||||
|
|
||||||
|
|
||||||
|
def process(self):
|
||||||
|
ks = []
|
||||||
|
if self.arg_flags & Flag.PROVIDER:
|
||||||
|
ks += [
|
||||||
|
'RPC_PROVIDER',
|
||||||
|
'RPC_DIALECT',
|
||||||
|
]
|
||||||
|
if self.arg_flags & Flag.RPC_AUTH:
|
||||||
|
ks += [
|
||||||
|
'RPC_AUTH',
|
||||||
|
'RPC_CREDENTIALS',
|
||||||
|
]
|
||||||
|
|
||||||
|
if self.arg_flags & Flag.CHAIN_SPEC:
|
||||||
|
ks.append('CHAIN_SPEC')
|
||||||
|
|
||||||
|
if self.arg_flags & Flag.KEY_FILE:
|
||||||
|
ks += [
|
||||||
|
'WALLET_KEY_FILE',
|
||||||
|
'WALLET_PASSPHRASE',
|
||||||
|
]
|
||||||
|
|
||||||
|
for k in ks:
|
||||||
|
self.__add(k)
|
||||||
|
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
s = ''
|
||||||
|
ks = list(self.envs.keys())
|
||||||
|
ks.sort()
|
||||||
|
for k in ks:
|
||||||
|
s += str(self.envs[k]) + "\n"
|
||||||
|
return s
|
||||||
|
14
chainlib/data/env/env.ini
vendored
Normal file
14
chainlib/data/env/env.ini
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
[rpc]
|
||||||
|
provider = Fully-qualified URL to the RPC endpoint of the blockchain node.
|
||||||
|
auth = Authentication method to use for the \fIRPC_PROVIDER\fP. Currently only \fIbasic\fP is supported.
|
||||||
|
credentials = Authentication credentials to use for \fIRPC_AUTH\fP. For \fIbasic\fP authentication the value must be given as \fI<user>:<pass>\fP.
|
||||||
|
dialect = Enables translations of EVM node specific formatting and response codes.
|
||||||
|
scheme = (needs content)
|
||||||
|
verify = (needs content)
|
||||||
|
|
||||||
|
[chain]
|
||||||
|
spec = String specifying the type of chain connected to, in the format \fI<engine>:<fork>:<network_id>:<common_name>\fP. For EVM nodes the \fIengine\fP value will always be \fIevm\fP.
|
||||||
|
|
||||||
|
[wallet]
|
||||||
|
key_file = The wallet key file containing private key to use for transaction signing. Overridden by \fB-y\fP.
|
||||||
|
passphrase = Passphrase to unlock wallet. \fBWARNING:\fP it is \fBunsafe\fP to pass the passphrase as an environment variable. If the key unlocks something of value, the passphrase should rather be in a configuration file, preferably as an encrypted entry. Alternatively, a passphrase can be read from file using the \fB--passphrase-file\fP option. Files containing passphrases should only be accessible by the owner.
|
89
scripts/chainlib-man.py
Normal file
89
scripts/chainlib-man.py
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import argparse
|
||||||
|
import tempfile
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
from hexathon import strip_0x, add_0x
|
||||||
|
|
||||||
|
from chainlib.cli.man import (
|
||||||
|
EnvDocGenerator,
|
||||||
|
DocGenerator,
|
||||||
|
apply_groff,
|
||||||
|
)
|
||||||
|
from chainlib.cli.base import argflag_std_base
|
||||||
|
from chainlib.cli.arg import ArgumentParser as ChainlibArgumentParser
|
||||||
|
from chainlib.eth.cli.config import Config
|
||||||
|
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.WARNING)
|
||||||
|
logg = logging.getLogger()
|
||||||
|
|
||||||
|
argparser = argparse.ArgumentParser()
|
||||||
|
argparser.add_argument('-b', default=add_0x(hex(argflag_std_base)), help='argument flag bitmask')
|
||||||
|
argparser.add_argument('-c', help='config override directory')
|
||||||
|
argparser.add_argument('-n', help='tool name to use for man filename')
|
||||||
|
argparser.add_argument('-d', default='.', help='output directory')
|
||||||
|
argparser.add_argument('-v', action='store_true', help='turn on debug logging')
|
||||||
|
argparser.add_argument('--overrides-file', dest='overrides_file', help='load options description override from file')
|
||||||
|
argparser.add_argument('--overrides-env-dir', dest='overrides_env_dir', help='load envionment description override config from directory')
|
||||||
|
argparser.add_argument('header_file', help='groff file containing heading, synopsis and description')
|
||||||
|
args = argparser.parse_args(sys.argv[1:])
|
||||||
|
|
||||||
|
if args.v:
|
||||||
|
logg.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
|
|
||||||
|
b = bytes.fromhex(strip_0x(args.b))
|
||||||
|
flags = int.from_bytes(b, byteorder='little')
|
||||||
|
|
||||||
|
#empty_args = ChainlibArgumentParser(flags).parse_args([])
|
||||||
|
#config = Config.from_args(empty_args, arg_flags=flags)
|
||||||
|
#g = DocGenerator(flags, config)
|
||||||
|
g = DocGenerator(flags)
|
||||||
|
|
||||||
|
toolname = args.n
|
||||||
|
if toolname == None:
|
||||||
|
parts = os.path.splitext(os.path.basename(args.header_file))
|
||||||
|
toolname = parts[0]
|
||||||
|
|
||||||
|
g.process()
|
||||||
|
|
||||||
|
if args.overrides_file != None:
|
||||||
|
f = open(args.overrides_file, 'r')
|
||||||
|
while True:
|
||||||
|
s = f.readline()
|
||||||
|
if len(s) == 0:
|
||||||
|
break
|
||||||
|
v = s.split('\t', maxsplit=2)
|
||||||
|
fargs = None
|
||||||
|
try:
|
||||||
|
fargs = v[2].rstrip().split(',')
|
||||||
|
except IndexError:
|
||||||
|
fargs = []
|
||||||
|
g.override_arg(v[0], v[1], fargs)
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
|
||||||
|
ge = EnvDocGenerator(flags, override=args.overrides_env_dir)
|
||||||
|
ge.process()
|
||||||
|
|
||||||
|
f = open(args.header_file)
|
||||||
|
head = f.read()
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
(fd, fp) = tempfile.mkstemp()
|
||||||
|
f = os.fdopen(fd, 'w')
|
||||||
|
f.write(head)
|
||||||
|
f.write(str(g))
|
||||||
|
f.write(".SH ENVIRONMENT\n\n")
|
||||||
|
f.write(str(ge))
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
dest = os.path.join(args.d, toolname + '.1')
|
||||||
|
shutil.copyfile(fp, dest)
|
||||||
|
|
||||||
|
os.unlink(fp)
|
@ -1,42 +0,0 @@
|
|||||||
import os
|
|
||||||
import sys
|
|
||||||
import argparse
|
|
||||||
import tempfile
|
|
||||||
import shutil
|
|
||||||
|
|
||||||
from hexathon import strip_0x, add_0x
|
|
||||||
|
|
||||||
from chainlib.cli.man import DocGenerator
|
|
||||||
from chainlib.cli.base import argflag_std_base
|
|
||||||
|
|
||||||
argparser = argparse.ArgumentParser()
|
|
||||||
argparser.add_argument('-b', default=add_0x(hex(argflag_std_base)), help='argument flag bitmask')
|
|
||||||
argparser.add_argument('-n', help='tool name to use for man filename')
|
|
||||||
argparser.add_argument('-d', default='.', help='output directory')
|
|
||||||
argparser.add_argument('header_file', help='groff file containing heading, synopsis and description')
|
|
||||||
args = argparser.parse_args(sys.argv[1:])
|
|
||||||
|
|
||||||
#b = bytes.fromhex(strip_0x(sys.argv[1]))
|
|
||||||
b = bytes.fromhex(strip_0x(args.b))
|
|
||||||
g = DocGenerator(int.from_bytes(b, byteorder='little'))
|
|
||||||
g.process()
|
|
||||||
|
|
||||||
f = open(args.header_file)
|
|
||||||
head = f.read()
|
|
||||||
f.close()
|
|
||||||
|
|
||||||
toolname = args.n
|
|
||||||
if toolname == None:
|
|
||||||
parts = os.path.splitext(os.path.basename(args.header_file))
|
|
||||||
toolname = parts[0]
|
|
||||||
|
|
||||||
(fd, fp) = tempfile.mkstemp()
|
|
||||||
f = os.fdopen(fd, 'w')
|
|
||||||
f.write(head)
|
|
||||||
f.write(str(g))
|
|
||||||
f.close()
|
|
||||||
|
|
||||||
dest = os.path.join(args.d, toolname + '.1')
|
|
||||||
shutil.copyfile(fp, dest)
|
|
||||||
|
|
||||||
os.unlink(fp)
|
|
@ -3,7 +3,7 @@ name=chainlib
|
|||||||
license=WTFPL2
|
license=WTFPL2
|
||||||
author_email=dev@holbrook.no
|
author_email=dev@holbrook.no
|
||||||
description=Generic blockchain access library and tooling
|
description=Generic blockchain access library and tooling
|
||||||
version=0.0.21
|
version=0.0.22
|
||||||
url=https://gitlab.com/chaintools/chainlib
|
url=https://gitlab.com/chaintools/chainlib
|
||||||
author=Louis Holbrook
|
author=Louis Holbrook
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user