amanuensis/amanuensis/__main__.py

140 lines
4.1 KiB
Python

# Standard library imports
import argparse
import os
import traceback
# Module imports
import amanuensis.cli as cli
from amanuensis.cli.helpers import (
USER_ARGS, USER_KWARGS, LEXICON_ARGS, LEXICON_KWARGS)
import amanuensis.config as config
from amanuensis.errors import AmanuensisError
def repl(args):
"""Runs a REPL with the given lexicon"""
# Get all the cli commands' descriptions and add help and exit.
commands = {
name[8:].replace("_", "-"): func.__doc__ for name, func in vars(cli).items()
if name.startswith("command_")}
commands['help'] = "Print this message"
commands['exit'] = "Exit"
print("Amanuensis running on Lexicon {}".format(args.tl_lexicon))
while True:
# Read input in a loop.
try:
data = input("{}> ".format(args.tl_lexicon))
except EOFError:
print()
break
tokens = data.strip().split()
if not data.strip():
pass
elif tokens[0] not in commands:
print("'{}' is not a valid command.".format(tokens[0]))
elif data.strip() == "help":
print("Available commands:")
for name, func in commands.items():
print(" {}: {}".format(name, func))
elif data.strip() == "exit":
print()
break
elif data.strip():
# Execute the command by appending it to the argv the
# REPL was invoked with.
try:
argv = sys.argv[1:] + data.split()
main(argv)
except Exception as e:
traceback.print_exc()
def process_doc(docstring):
return '\n'.join([
line.strip()
for line in (docstring or "").strip().splitlines()
])
def get_parser(valid_commands):
# Set up the top-level parser.
parser = argparse.ArgumentParser(
description=cli.describe_commands(),
formatter_class=argparse.RawDescriptionHelpFormatter)
# The config directory.
parser.add_argument("--config-dir",
dest="config_dir",
default=os.environ.get(config.ENV_CONFIG_DIR, "./config"),
help="The config directory for Amanuensis")
# Logging settings.
parser.add_argument("--verbose", "-v",
action="store_true",
dest="verbose",
help="Enable verbose console logging")
parser.add_argument("--log-file",
dest="log_file",
default=os.environ.get(config.ENV_LOG_FILE),
help="Enable verbose file logging")
parser.add_argument("--log-file-size",
dest="log_file_size",
default=os.environ.get(config.ENV_LOG_FILE_SIZE),
help="Maximum rolling log file size")
parser.add_argument("--log-file-num",
dest="log_file_num",
default=os.environ.get(config.ENV_LOG_FILE_NUM),
help="Maximum rolling file count")
# Lexicon settings.
parser.add_argument(*LEXICON_ARGS, **LEXICON_KWARGS)
parser.add_argument(*USER_ARGS, **USER_KWARGS)
parser.set_defaults(
func=lambda args: repl(args)
if args.tl_lexicon
else parser.print_help())
subp = parser.add_subparsers(
metavar="COMMAND",
dest="command",
help="The command to execute")
# Set up command subparsers.
# command_ functions perform setup or execution depending on
# whether their argument is an ArgumentParser.
for name, func in valid_commands.items():
# Create the subparser, set the docstring as the description.
cmd = subp.add_parser(name,
description=process_doc(func.__doc__),
formatter_class=argparse.RawDescriptionHelpFormatter,
aliases=func.__dict__.get("aliases", []))
# Delegate subparser setup to the command.
func(cmd)
# Store function for later execution.
cmd.set_defaults(func=func)
return parser
def main(argv):
# Enumerate valid commands from the CLI module.
commands = cli.get_commands()
args = get_parser(commands).parse_args(argv)
# If the command is the init command, a config directory will be
# initialized at args.config_dir. Otherwise, initialize configs using
# that directory.
if args.command and args.command != "init":
config.init_config(args)
# If verbose logging, dump args namespace
if args.verbose:
config.logger.debug("amanuensis")
for key, val in vars(args).items():
config.logger.debug(" {}: {}".format(key, val))
# Execute command.
try:
args.func(args)
except AmanuensisError as e:
config.logger.error('Unexpected internal {}: {}'.format(
type(e).__name__, str(e)))
if __name__ == "__main__":
import sys
sys.exit(main(sys.argv[1:]))