Revamp CLI and add add command
This commit is contained in:
parent
ecd9d67881
commit
69627d3fda
@ -1,42 +1,43 @@
|
||||
# Standard library imports
|
||||
import argparse
|
||||
import os
|
||||
import logging
|
||||
import sys
|
||||
|
||||
# Application imports
|
||||
import cli
|
||||
|
||||
# Globals
|
||||
logger = logging.getLogger("inquisitor.__main__")
|
||||
import configs
|
||||
|
||||
|
||||
def parse_args(valid_commands):
|
||||
command_descs = "\n".join([
|
||||
"- {0}: {1}".format(name, func.__doc__)
|
||||
for name, func in valid_commands.items()])
|
||||
parser = argparse.ArgumentParser(description="Available commands:\n{}\n".format(command_descs), formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
parser.add_argument("command", default="help", help="The command to execute", choices=valid_commands, metavar="COMMAND")
|
||||
parser.add_argument("--srcdir", help="Path to sources folder (default ./sources)", default="./sources")
|
||||
parser.add_argument("--dungeon", help="Path to item cache folder (default ./dungeon)", default="./dungeon")
|
||||
parser.add_argument("--sources", help="Sources to update, by name", nargs="*")
|
||||
parser.add_argument("--log", default="INFO", help="Set the log level (default: INFO)")
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Available commands:\n{}\n".format(command_descs),
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
add_help=False)
|
||||
parser.add_argument("command",
|
||||
nargs="?",
|
||||
default="help",
|
||||
help="The command to execute",
|
||||
choices=valid_commands,
|
||||
metavar="command")
|
||||
parser.add_argument("args",
|
||||
nargs=argparse.REMAINDER,
|
||||
help="Command arguments",
|
||||
metavar="args")
|
||||
parser.add_argument("-v",
|
||||
action="store_true",
|
||||
dest="verbose",
|
||||
help="Enable debug logging")
|
||||
|
||||
args = parser.parse_args()
|
||||
global print_usage
|
||||
print_usage = parser.print_help
|
||||
|
||||
return args
|
||||
|
||||
|
||||
def run_flask_server(args):
|
||||
"""Run the default flask server serving from the specified dungeon."""
|
||||
try:
|
||||
from app import app
|
||||
app.run()
|
||||
return 0
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
return (-1)
|
||||
return parser.parse_args()
|
||||
|
||||
def command_help(args):
|
||||
"""Print this help message and exit."""
|
||||
print_usage()
|
||||
return 0
|
||||
|
||||
def main():
|
||||
# Enumerate valid commands.
|
||||
@ -44,21 +45,19 @@ def main():
|
||||
name[8:] : func
|
||||
for name, func in vars(cli).items()
|
||||
if name.startswith("command_")}
|
||||
commands["run"] = run_flask_server
|
||||
commands['help'] = command_help
|
||||
|
||||
args = parse_args(commands)
|
||||
|
||||
# Configure logging.
|
||||
if args.command != 'run':
|
||||
loglevel = getattr(logging, args.log.upper())
|
||||
if not isinstance(loglevel, int):
|
||||
raise ValueError("Invalid log level: {}".format(args.log))
|
||||
logging.basicConfig(format='[%(levelname)s:%(filename)s:%(lineno)d] %(message)s', level=loglevel)
|
||||
if args.verbose:
|
||||
configs.log_verbose()
|
||||
|
||||
# Execute command.
|
||||
if args.command:
|
||||
return commands[args.command](args)
|
||||
return commands[args.command](args.args)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
sys.exit(main())
|
||||
|
@ -1,60 +1,131 @@
|
||||
# Standard library imports
|
||||
import argparse
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import random
|
||||
|
||||
# Application imports
|
||||
import dungeon as dungeonlib
|
||||
|
||||
# Globals
|
||||
logger = logging.getLogger("inquisitor.cli")
|
||||
from configs import logger, DUNGEON_PATH, SOURCES_PATH
|
||||
|
||||
|
||||
def command_update(args):
|
||||
"""Fetch and store new items from the specified sources."""
|
||||
if not os.path.isdir(args.srcdir):
|
||||
print("update: Error: srcdir must be a directory")
|
||||
return (-1)
|
||||
if not os.path.isdir(args.dungeon):
|
||||
logger.error("update: Error: dungeon must be a directory")
|
||||
return (-1)
|
||||
if not args.sources:
|
||||
logger.error("update: Error: No sources specified")
|
||||
return (-1)
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="inquisitor update",
|
||||
description=command_update.__doc__,
|
||||
add_help=False)
|
||||
parser.add_argument("source",
|
||||
nargs="*",
|
||||
help="Sources to update.")
|
||||
args = parser.parse_args(args)
|
||||
|
||||
# Initialize dungeon.
|
||||
dungeon = dungeonlib.Dungeon(args.dungeon)
|
||||
|
||||
# Process each source argument.
|
||||
for source_arg in args.sources:
|
||||
dungeon.update(source_arg, args)
|
||||
if len(args.source) == 0:
|
||||
parser.print_help()
|
||||
return 0
|
||||
if not os.path.isdir(DUNGEON_PATH):
|
||||
logger.error("Couldn't find dungeon. Set INQUISITOR_DUNGEON or cd to parent folder of ./dungeon")
|
||||
return -1
|
||||
if not os.path.isdir(SOURCES_PATH):
|
||||
logger.error("Couldn't find sources. Set INQUISITOR_SOURCES or cd to parent folder of ./sources")
|
||||
|
||||
# Update sources
|
||||
from importer import update_sources
|
||||
update_sources(*args.source)
|
||||
return 0
|
||||
|
||||
|
||||
def command_deactivate(args):
|
||||
"""Deactivate all items in the specified dungeon cells."""
|
||||
if not os.path.isdir(args.dungeon):
|
||||
logger.error("deactivate: Error: dungeon must be a directory")
|
||||
return (-1)
|
||||
if not args.sources:
|
||||
logger.error("deactivate: Error: No sources specified")
|
||||
return (-1)
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="inquisitor deactivate",
|
||||
description=command_deactivate.__doc__,
|
||||
add_help=False)
|
||||
parser.add_argument("source",
|
||||
nargs="*",
|
||||
help="Cells to deactivate.")
|
||||
args = parser.parse_args(args)
|
||||
|
||||
# Initialize dungeon.
|
||||
dungeon = dungeonlib.Dungeon(args.dungeon)
|
||||
if len(args.source) == 0:
|
||||
parser.print_help()
|
||||
return 0
|
||||
if not os.path.isdir(DUNGEON_PATH):
|
||||
logger.error("Couldn't find dungeon. Set INQUISITOR_DUNGEON or cd to parent folder of ./dungeon")
|
||||
return -1
|
||||
|
||||
# Deactivate all items in each source.
|
||||
for source_name in args.sources:
|
||||
if source_name not in dungeon:
|
||||
print("Error: No source named '{}'".format(source_name))
|
||||
print("Valid source names are: " + " ".join([s for s in dungeon]))
|
||||
continue
|
||||
cell = dungeon[source_name]
|
||||
from loader import load_items
|
||||
for source_name in args.source:
|
||||
path = os.path.join(DUNGEON_PATH, source_name)
|
||||
if not os.path.isdir(path):
|
||||
logger.warning("'{}' is not an extant source".format(source_name))
|
||||
count = 0
|
||||
for item_id in cell:
|
||||
item = cell[item_id]
|
||||
items, _ = load_items(source_name)
|
||||
for item in items.values():
|
||||
if item['active']:
|
||||
item.deactivate()
|
||||
item['active'] = False
|
||||
count += 1
|
||||
logger.info("Deactivated {} items in '{}'".format(count, source_name))
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def command_add(args):
|
||||
"""Creates an item."""
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="inquisitor add",
|
||||
description=command_add.__doc__,
|
||||
add_help=False)
|
||||
parser.add_argument("--id", help="String")
|
||||
parser.add_argument("--source", help="String")
|
||||
parser.add_argument("--title", help="String")
|
||||
parser.add_argument("--link", help="URL")
|
||||
parser.add_argument("--time", type=int, help="Unix timestmap")
|
||||
parser.add_argument("--author", help="String")
|
||||
parser.add_argument("--body", help="HTML")
|
||||
parser.add_argument("--tags", help="Comma-separated list")
|
||||
parser.add_argument("--ttl", type=int, help="Cleanup protection in seconds")
|
||||
args = parser.parse_args(args)
|
||||
|
||||
if not args.title:
|
||||
parser.print_help()
|
||||
return 0
|
||||
if not os.path.isdir(DUNGEON_PATH):
|
||||
logger.error("Couldn't find dungeon. Set INQUISITOR_DUNGEON or cd to parent folder of ./dungeon")
|
||||
return -1
|
||||
|
||||
from importer import populate_new
|
||||
item = {
|
||||
'id': '{:x}'.format(random.getrandbits(16 * 4)),
|
||||
'source': 'inquisitor'
|
||||
}
|
||||
if args.id: item['id'] = str(args.id)
|
||||
if args.source: item['source'] = str(args.source)
|
||||
if args.title: item['title'] = str(args.title)
|
||||
if args.link: item['link'] = str(args.link)
|
||||
if args.time: item['time'] = int(args.time)
|
||||
if args.author: item['author'] = str(args.author)
|
||||
if args.body: item['body'] = str(args.body)
|
||||
if args.tags: item['tags'] = [str(tag) for tag in args.tags]
|
||||
if args.ttl: item['ttl'] = int(args.ttl)
|
||||
populate_new(item)
|
||||
s = json.dumps(item, indent=2)
|
||||
path = os.path.join(DUNGEON_PATH, item['source'], item['id'] + '.item')
|
||||
with open(path, 'w', encoding='utf8') as f:
|
||||
f.write(s)
|
||||
logger.info(item)
|
||||
|
||||
|
||||
# def command_run(args):
|
||||
# """Run the default Flask server."""
|
||||
# pass
|
||||
|
||||
# def run_flask_server(args):
|
||||
# """Run the default flask server serving from the specified dungeon."""
|
||||
# try:
|
||||
# from app import app
|
||||
# app.run()
|
||||
# return 0
|
||||
# except Exception as e:
|
||||
# logger.error(e)
|
||||
# return (-1)
|
||||
|
@ -5,9 +5,19 @@ DUNGEON_PATH = os.path.abspath(os.environ.get("INQUISITOR_DUNGEON") or "./dungeo
|
||||
SOURCES_PATH = os.path.abspath(os.environ.get("INQUISITOR_SOURCES") or "./sources")
|
||||
|
||||
logger = logging.getLogger("inquisitor")
|
||||
logger.setLevel(logging.INFO)
|
||||
handler = logging.StreamHandler()
|
||||
handler.setLevel(logging.INFO)
|
||||
formatter = logging.Formatter('[{levelname}] {message}', style="{")
|
||||
handler.setFormatter(formatter)
|
||||
logger.addHandler(handler)
|
||||
|
||||
def log_normal():
|
||||
logger.setLevel(logging.INFO)
|
||||
handler.setLevel(logging.INFO)
|
||||
formatter = logging.Formatter('[{levelname}] {message}', style="{")
|
||||
handler.setFormatter(formatter)
|
||||
|
||||
def log_verbose():
|
||||
logger.setLevel(logging.DEBUG)
|
||||
handler.setLevel(logging.DEBUG)
|
||||
formatter = logging.Formatter('[{asctime}] [{levelname}:{filename}:{lineno}] {message}', style="{")
|
||||
handler.setFormatter(formatter)
|
||||
|
||||
log_normal()
|
||||
|
@ -74,7 +74,7 @@ def update_source(source_name, fetch_new):
|
||||
# If the item is new, write it.
|
||||
new_count += 1
|
||||
s = json.dumps(item)
|
||||
path = os.path.join(DUNGEON_PATH, item['source'], item['id'])
|
||||
path = os.path.join(DUNGEON_PATH, item['source'], item['id'] + ".item")
|
||||
with open(path, 'w', encoding="utf8") as f:
|
||||
f.write(s)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user