From 02c826ed867068221ae88db04409e0e65148a353 Mon Sep 17 00:00:00 2001 From: TicClick Date: Tue, 15 Dec 2020 11:20:29 +0100 Subject: [PATCH] start with custom config; ditch Makefile --- .vscode/settings.json | 2 +- Makefile | 36 ------------------------ bin.sh | 51 ++++++++++++++++++++++++++++++++++ config/config.example.yaml | 9 ++++-- librarian/main.py | 57 ++++++++++++++++++++++++++++++-------- 5 files changed, 103 insertions(+), 52 deletions(-) delete mode 100644 Makefile create mode 100755 bin.sh diff --git a/.vscode/settings.json b/.vscode/settings.json index f2aa996..5858ba9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,5 @@ { - "python.pythonPath": "runtime/venv/bin/python", + "python.pythonPath": "venv/bin/python3", "python.linting.pylintEnabled": false, "python.linting.flake8Enabled": true, "python.linting.enabled": true, diff --git a/Makefile b/Makefile deleted file mode 100644 index 33f7642..0000000 --- a/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -SYSTEM_PYTHON = python3 - -.PHONY = setup test run coverage cov hcov - -RUNTIME_DIR = runtime -VENV_DIR = ${RUNTIME_DIR}/venv -BIN_DIR = ${VENV_DIR}/bin -VENV_PYTHON = ${BIN_DIR}/python - -JUNK = htmlcov .coverage -RECURSIVE_JUNK = .pytest_cache __pycache__ - -setup: - [ -d runtime ] || ( \ - ${SYSTEM_PYTHON} -m venv ${VENV_DIR} && \ - ${VENV_PYTHON} -m pip install -r requirements.txt \ - ) - -test: setup - ${BIN_DIR}/pytest $(args) - -run: setup - ${VENV_PYTHON} -m librarian.main - -coverage: setup - ${BIN_DIR}/coverage run --source librarian -m pytest - -cov: coverage - ${BIN_DIR}/coverage report -m - -hcov: coverage - ${BIN_DIR}/coverage html && ((which xdg-open && xdg-open htmlcov/index.html) || open htmlcov/index.html) - -clean: - for ITEM in ${JUNK}; do rm -r $${ITEM}; done; \ - for ITEM in ${RECURSIVE_JUNK}; do find . -name $${ITEM} -exec rm -r {} +; done diff --git a/bin.sh b/bin.sh new file mode 100755 index 0000000..a57da7a --- /dev/null +++ b/bin.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash + +set -e + +SYSTEM_PYTHON=python3 +VENV_DIR=venv +BIN_DIR="$VENV_DIR"/bin + +while [[ $# -gt 0 ]]; do + case "$1" in + setup) + [ -d "$VENV_DIR" ] || ( \ + "$SYSTEM_PYTHON" -m venv "$VENV_DIR" && \ + "$BIN_DIR"/pip install -r requirements.txt \ + ) + exit $?;; + + test) + shift + "$BIN_DIR"/pytest "$@" + exit $?;; + + run) + shift + "$BIN_DIR"/python -m librarian.main "$@" + exit $?;; + + coverage) + shift + "$BIN_DIR"/coverage run --source librarian -m pytest + exit $?;; + + cov) + shift + "$BIN_DIR"/coverage report -m + exit $?;; + + hcov) + shift + "$BIN_DIR"/coverage html && ((which xdg-open && xdg-open htmlcov/index.html) || open htmlcov/index.html) + exit $?;; + + clean) + shift + for ITEM in {htmlcov,.coverage}; do rm -r "$ITEM"; done; \ + for ITEM in {.pytest_cache,__pycache__}; do find . -name "$ITEM" -exec rm -r {} +; done + rm -r "$VENV_DIR" + exit $?;; + + esac +done diff --git a/config/config.example.yaml b/config/config.example.yaml index 5376e43..9abc1cc 100644 --- a/config/config.example.yaml +++ b/config/config.example.yaml @@ -13,9 +13,12 @@ discord: review_role_id: 12345 store_in_pins: true +runtime: + dir: /home/username/discord-bot/runtime + storage: - path: "runtime/osuwiki.db" + path: "{runtime}/osuwiki.db" logging: - file: "runtime/librarian.log" - level: DEBUG \ No newline at end of file + file: "{runtime}/librarian.log" + level: DEBUG diff --git a/librarian/main.py b/librarian/main.py index 0bef990..9f2a743 100644 --- a/librarian/main.py +++ b/librarian/main.py @@ -1,6 +1,8 @@ +import argparse import itertools import logging import os +import sys import yaml @@ -16,14 +18,14 @@ PADDING_CHAR = "-" -def setup_logging(source_dir, logging_config, loggers): +def setup_logging(runtime_dir, logging_config, loggers): formatter = logging.Formatter(( "%(asctime)s\t" "%(module)s:%(lineno)d\t" "%(levelname)s\t" "%(message)s" )) - file_name = os.path.join(source_dir, logging_config["file"]) + file_name = os.path.join(runtime_dir, logging_config["file"]) file_handler = logging.FileHandler(file_name, "a") file_handler.setFormatter(formatter) @@ -33,14 +35,9 @@ def setup_logging(source_dir, logging_config, loggers): logger.setLevel(getattr(logging, logging_config["level"])) -def configure_client(): - source_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir) - config_path = os.path.join(source_dir, "config/config.yaml") - with open(config_path, "r") as fd: - config = yaml.safe_load(fd) - +def configure_client(config): setup_logging( - source_dir, config["logging"], + config["runtime"]["dir"], config["logging"], itertools.chain( (logger, github.logger), discord.LOGGERS, ) @@ -52,7 +49,7 @@ def configure_client(): repo=config["github"]["repo"], ) - storage_path = os.path.join(source_dir, config["storage"]["path"]) + storage_path = os.path.join(config["runtime"]["dir"], config["storage"]["path"]) db = storage.Storage(storage_path) client = discord.Client( @@ -67,7 +64,6 @@ def configure_client(): ) client.setup() - return client, config @@ -81,8 +77,45 @@ def run_client(client, config): logger.debug(" Shutdown completed ".center(PADDING, PADDING_CHAR)) +def load_config(config_path): + if config_path.endswith(".example.yaml"): + raise RuntimeError("Can't use example config, see the note on its first line") + + print(f"Loading config from {config_path}") + with open(config_path, "r") as fd: + config = yaml.safe_load(fd) + + runtime = config["runtime"]["dir"] + if not os.path.exists(runtime): # may happen when Python runtime is in a different directory + os.makedirs(runtime) + for path in ("logging.file", "storage.path"): + root = config + parts = path.split(".") + for i, p in enumerate(parts): + if i < len(parts) - 1: + root = root[p] + else: + root[p] = root[p].format(runtime=runtime) + + return config + + +def parse_args(args): + source_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir) + default_config_path = os.path.join(source_dir, "config/config.yaml") + + parser = argparse.ArgumentParser() + parser.add_argument( + "--config", help="Path to the .yaml configuration file", default=default_config_path + ) + return parser.parse_args(args) + + def main(): - run_client(*configure_client()) + args = parse_args(sys.argv[1:]) + config = load_config(args.config) + client, token = configure_client(config) + run_client(client, token) if __name__ == "__main__":