Cmd / Cmds: Add config file support

An application based on Cmds will now try to read StringTree
formatted config data from a file $HOME/.<name>rc, and make the data
available via the newly added conf_value() method.

Signed-off-by: Jan Lindemann <jan@janware.com>
This commit is contained in:
Jan Lindemann 2022-12-08 16:44:49 +01:00
commit a4fb791649
2 changed files with 31 additions and 0 deletions

View file

@ -22,6 +22,7 @@ class Cmd(abc.ABC): # export
self.parent = None self.parent = None
self.children: List[Cmd] = [] self.children: List[Cmd] = []
self.child_classes: List[Type[Cmd]] = [] self.child_classes: List[Type[Cmd]] = []
self.app: Optional[Cmds] = None
async def _run(self, args): async def _run(self, args):
pass pass
@ -52,3 +53,9 @@ class Cmd(abc.ABC): # export
# Will be called from App base class constructor and set up the parser hierarchy # Will be called from App base class constructor and set up the parser hierarchy
def add_arguments(self, parser: ArgumentParser) -> None: def add_arguments(self, parser: ArgumentParser) -> None:
pass pass
def conf_value(self, path, default=None):
ret = None if self.app is None else self.app.conf_value(path, default)
if ret is None and default is not None:
return default
return ret

View file

@ -3,9 +3,11 @@
from typing import Optional from typing import Optional
import os, sys, argcomplete, argparse, importlib, inspect, re, pickle, asyncio, cProfile import os, sys, argcomplete, argparse, importlib, inspect, re, pickle, asyncio, cProfile
from argparse import ArgumentParser from argparse import ArgumentParser
from pathlib import Path, PurePath
import jwutils import jwutils
from jwutils.log import * from jwutils.log import *
from jwutils.stree import serdes
class Cmds: # export class Cmds: # export
@ -30,10 +32,19 @@ class Cmds: # export
for sub_cmd in cmd.children: for sub_cmd in cmd.children:
self.__add_cmd_to_parser(sub_cmd, subparsers) self.__add_cmd_to_parser(sub_cmd, subparsers)
def __parse_config(self):
exe_stem = str(PurePath(sys.argv[0]).stem)
path = str(Path.home()) + '/.' + exe_stem + 'rc'
if not os.path.exists(path):
return None, []
slog(DEBUG, 'Reading configuration "{}"'.format(path))
return serdes.read(path, ''), [path]
def __init__(self, description: str = '', filter: str = '^Cmd.*', modules: None=None, eloop: None=None) -> None: def __init__(self, description: str = '', filter: str = '^Cmd.*', modules: None=None, eloop: None=None) -> None:
self.__description = description self.__description = description
self.__filter = filter self.__filter = filter
self.__modules = modules self.__modules = modules
self.__conf, self.__conf_paths = self.__parse_config()
self.__cmds = [] self.__cmds = []
self.eloop = eloop self.eloop = eloop
self.__own_eloop = False self.__own_eloop = False
@ -43,6 +54,7 @@ class Cmds: # export
log_level = "notice" log_level = "notice"
log_flags = 'stderr,position,prio,color' log_flags = 'stderr,position,prio,color'
log_file = None
# poor man's parsing in the absence of a complete command-line definition # poor man's parsing in the absence of a complete command-line definition
for i in range(1, len(sys.argv)): for i in range(1, len(sys.argv)):
if i >= len(sys.argv) - 1: if i >= len(sys.argv) - 1:
@ -64,6 +76,7 @@ class Cmds: # export
self.__parser.add_argument('--log-level', help='Log level', default=log_level) self.__parser.add_argument('--log-level', help='Log level', default=log_level)
self.__parser.add_argument('--backtrace', help='Show exception backtraces', action='store_true', default=False) self.__parser.add_argument('--backtrace', help='Show exception backtraces', action='store_true', default=False)
self.__parser.add_argument('--write-profile', help='Profile code and store output to file', default=None) self.__parser.add_argument('--write-profile', help='Profile code and store output to file', default=None)
self.__parser.add_argument('--log-file', help='Log file', default=log_file)
if self.__modules == None: if self.__modules == None:
self.__modules = [ '__main__' ] self.__modules = [ '__main__' ]
subcmds = set() subcmds = set()
@ -118,6 +131,11 @@ class Cmds: # export
if pr is not None: if pr is not None:
pr.enable() pr.enable()
if self.__conf:
self.__conf.dump(DEBUG, "Configuration")
if self.args.log_file is not None:
add_log_file(self.args.log_file)
try: try:
ret = await self._run(self.args) ret = await self._run(self.args)
except Exception as e: except Exception as e:
@ -144,6 +162,12 @@ class Cmds: # export
self.eloop = None self.eloop = None
self.__own_eloop = False self.__own_eloop = False
def conf_value(self, path, default=None):
ret = None if self.__conf is None else self.__conf.value(path)
if ret is None and default is not None:
return default
return ret
def parser(self) -> ArgumentParser: def parser(self) -> ArgumentParser:
return self.__parser return self.__parser