diff --git a/CHANGELOG.md b/CHANGELOG.md index f485ca0..8732f39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # xbotlib x.x.x (UNRELEASED) +# xbotlib 0.3.1 (2021-01-12) + +- Support `--no-input` flag and read configuration from the environment + # xbotlib 0.3.0 (2021-01-10) - Error out if you don't provide a `react` implementation diff --git a/README.md b/README.md index cb2c4c8..f279991 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,19 @@ Attributes: - **nickname**: the nickname of the sender - **type**: the type of message (`chat` or `groupchat`) +## Configure your bot + +### Using the environment + +You can pass the `--no-input` option to your script invocation (e.g. `python bot.py --no-input`). + +`xbotlib` will try to read the following configuration values from the environment. + +- **XBOT_JID** +- **XBOT_PASSWORD** +- **XBOT_ROOM** +- **XBOT_NICK** + ## Roadmap See the [issue tracker](https://git.autonomic.zone/decentral1se/xbotlib/issues). diff --git a/pyproject.toml b/pyproject.toml index 31d6027..ce611f5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.masonry.api" [tool.poetry] name = "xbotlib" -version = "0.3.0" +version = "0.3.1" description = "XMPP bots for humans" authors = ["decentral1se "] maintainers = ["decentral1se "] diff --git a/xbotlib.py b/xbotlib.py index 24b5075..a760857 100644 --- a/xbotlib.py +++ b/xbotlib.py @@ -1,7 +1,9 @@ """XMPP bots for humans.""" +from argparse import ArgumentParser, BooleanOptionalAction from configparser import ConfigParser from getpass import getpass +from os import environ from os.path import exists from pathlib import Path @@ -39,23 +41,42 @@ class Bot(ClientXMPP): CONFIG_FILE = "bot.conf" def __init__(self): + self.parse_arguments() self.read_config() self.init_bot() self.register_xmpp_event_handlers() self.register_xmpp_plugins() self.run() + def parse_arguments(self): + """Parse command-line arguments.""" + self.parser = ArgumentParser() + self.parser.add_argument( + "--input", + help="Read configuration from environment", + action=BooleanOptionalAction, + default=True, + ) + self.args = self.parser.parse_args() + def read_config(self): """Read configuration for running bot.""" - config_file_path = Path(self.CONFIG_FILE).absolute() - - if not exists(config_file_path): - self.generate_config() - self.config = ConfigParser() - self.config.read(config_file_path) - def generate_config(self): + config_file_path = Path(self.CONFIG_FILE).absolute() + if not exists(config_file_path) and self.args.input: + self.generate_config_interactively() + + if exists(config_file_path): + self.config.read(config_file_path) + + if self.args.input is False: + self.read_config_from_env() + + if "bot" not in self.config: + raise RuntimeError("Failed to configure bot") + + def generate_config_interactively(self): """Generate bot configuration.""" jid = input("XMPP address (e.g. foo@bar.com): ") or "foo@bar.com" password = ( @@ -75,6 +96,14 @@ class Bot(ClientXMPP): with open("bot.conf", "w") as file_handle: config.write(file_handle) + def read_config_from_env(self): + """Read configuration from the environment.""" + self.config["bot"] = {} + self.config["bot"]["jid"] = environ.get("XBOT_JID") + self.config["bot"]["password"] = environ.get("XBOT_PASSWORD") + self.config["bot"]["room"] = environ.get("XBOT_ROOM") + self.config["bot"]["nick"] = environ.get("XBOT_NICK") + def init_bot(self): """Initialise bot with connection details.""" jid = self.config["bot"]["jid"]