From 246ef4c8295d5410c90e7c1daa134680b4919302 Mon Sep 17 00:00:00 2001 From: Arkadiusz Jedrzejewski Date: Sun, 15 Mar 2026 17:21:35 +0100 Subject: [PATCH] Basic env and description --- .envrc | 12 +++ .gitignore | 166 +--------------------------------------- .pre-commit-config.yaml | 37 +++++++++ README.md | 78 ++++++++++++++++++- devenv.nix | 14 ++++ devenv.yaml | 8 ++ kronos/__init__.py | 0 kronos/main.py | 11 +++ pyproject.toml | 74 ++++++++++++++++++ 9 files changed, 237 insertions(+), 163 deletions(-) create mode 100644 .envrc create mode 100644 .pre-commit-config.yaml create mode 100644 devenv.nix create mode 100644 devenv.yaml create mode 100644 kronos/__init__.py create mode 100755 kronos/main.py create mode 100644 pyproject.toml diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..cc5c18b --- /dev/null +++ b/.envrc @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +export DIRENV_WARN_TIMEOUT=20s + +eval "$(devenv direnvrc)" + +# `use devenv` supports the same options as the `devenv shell` command. +# +# To silence all output, use `--quiet`. +# +# Example usage: use devenv --quiet --impure --option services.postgres.enable:bool true +use devenv diff --git a/.gitignore b/.gitignore index ab3e8ce..ba0403c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,164 +1,6 @@ -# ---> Python -# Byte-compiled / optimized / DLL files +.devenv* +devenv.lock +.direnv* +uv.lock __pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -share/python-wheels/ *.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -*.py,cover -.hypothesis/ -.pytest_cache/ -cover/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -db.sqlite3 -db.sqlite3-journal - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -.pybuilder/ -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# poetry -# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -#poetry.lock - -# pdm -# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. -#pdm.lock -# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it -# in version control. -# https://pdm.fming.dev/latest/usage/project/#working-with-version-control -.pdm.toml -.pdm-python -.pdm-build/ - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - -# Environments -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -# pytype static type analyzer -.pytype/ - -# Cython debug symbols -cython_debug/ - -# PyCharm -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ - diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..e552a88 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,37 @@ +default_stages: [pre-commit, pre-push] +repos: + - repo: local + hooks: + - id: trailing-whitespace + name: Trim trailing space + entry: trailing-whitespace-fixer + language: system + types: [file, text] + + - id: end-of-file-fixer + name: Fix end of files + description: Ensures that a file is either empty, or ends with one newline. + entry: end-of-file-fixer + language: system + types: [file, text] + + - id: check-merge-conflict + name: Check for merge conflicts + description: Check for files that contain merge conflict strings. + entry: check-merge-conflict + language: system + types: [file, text] + + - id: ruff-format + name: Ruff format + description: Format. + entry: ruff format --check --config pyproject.toml + language: system + types: [python] + + - id: ruff-lint + name: Ruff linter + description: Lint. + entry: ruff check --force-exclude --config pyproject.toml + language: system + types: [python] diff --git a/README.md b/README.md index dab0e60..3dcafbc 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,79 @@ # kronos -Share events between services. \ No newline at end of file +Share events between services. + +## Setup + +Nix is required. + +- Set up environment. + +```bash +direnv allow +``` + +- Set up pre-commit hooks. + +```bash +pre-commit install +``` + +- Install as editable package. + +```bash +pip install -e . +``` + +## Run + +Once installed, run: + +```bash +kronos +``` + +TODO: add parameters. +TODO: add info on how to run as a Podman service. + +## High level design + +`kronos` is an application able to sync events from a single source of truth to multiple consumer services. +E.g., an event defined by Mobilizon is modified -> Discord, Meetup, any other, are updated. + +It is deployed as a Docker container, running as a service. +Persistent storage is required for SQLite database. +Secrets management is used to handle credentials. +`systemd` timer is configured to trigger the app. +E.g., `kronos` is being run every three hours to perform events update. + +Each app run performs the following: +- Request event data from source of truth service (e.g., Mobilizon). +- Compare event data between received and stored in the database. + - Update if new data available (last change date is later than known). + - Stop execution otherwise. +- Send updates event data to consumers. + +```plain +┌───────────────────────────────────────────────────────────────────────────────────────────────┐ +│ │ +│ CONTAINER │ +│ │ +│ ┌───────────────┐ ┌────────┐ │ +│ │ │ │ │ │ +│ │ systemd timer │ │ volume │ │ +│ │ │ │ │ │ +│ └───────┬───────┘ └────┬───┘ │ +│ │ │ │ +│ ┌────────────────────┴────────────────────────────┼─────────────────────────────────────────┐ │ +│ │ │ │ │ +│ │ APP │ │ │ +│ │ ┌───────────────┐ ┌────┴─────┐ ┌────────────────┐ │ │ +│ │ trigger │ │ event data │ │ event data │ │ │ │ +│ │ ──────────►│ data provider ├──────────────►│ database ├───────────────►│ data consumers │ │ │ +│ │ │ │ │ │ │ │ │ │ +│ │ └───────────────┘ └──────────┘ └────────────────┘ │ │ +│ │ │ │ +│ └───────────────────────────────────────────────────────────────────────────────────────────┘ │ +│ │ +└───────────────────────────────────────────────────────────────────────────────────────────────┘ +``` diff --git a/devenv.nix b/devenv.nix new file mode 100644 index 0000000..a3ed509 --- /dev/null +++ b/devenv.nix @@ -0,0 +1,14 @@ +{ + name = "kronos"; + + languages.python = { + enable = true; + venv.enable = true; + version = "3.13.0"; + uv = { + enable = true; + sync.enable = true; + sync.allExtras = true; + }; + }; +} diff --git a/devenv.yaml b/devenv.yaml new file mode 100644 index 0000000..184b866 --- /dev/null +++ b/devenv.yaml @@ -0,0 +1,8 @@ +inputs: + nixpkgs: + url: github:cachix/devenv-nixpkgs/rolling + nixpkgs-python: + url: github:cachix/nixpkgs-python + inputs: + nixpkgs: + follows: nixpkgs diff --git a/kronos/__init__.py b/kronos/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/kronos/main.py b/kronos/main.py new file mode 100755 index 0000000..8aae611 --- /dev/null +++ b/kronos/main.py @@ -0,0 +1,11 @@ +from argparse import ArgumentParser + + +def _main(): + parser = ArgumentParser(prog="kronos", description="Share events between services.") + parser.add_argument("--name") + _args = parser.parse_args() + + +if __name__ == "__main__": + _main() diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..c55d976 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,74 @@ +[project] +name = "kronos" +version = "0.1.0" +description = "Share events between services." +authors = [{ name = "Hackerspace Trójmiasto" }] +readme = "README.md" +license = { file = "LICENSE" } + +requires-python = ">=3.13" + +dependencies = [] + +[dependency-groups] +dev = ["pre-commit", "pre-commit-hooks", "pytest", "ruff"] + +[project.scripts] +kronos = "kronos.main:_main" + +[tool.ruff] +exclude = [ + ".bzr", + ".direnv", + ".eggs", + ".git", + ".git-rewrite", + ".hg", + ".ipynb_checkpoints", + ".mypy_cache", + ".nox", + ".pants.d", + ".pyenv", + ".pytest_cache", + ".pytype", + ".ruff_cache", + ".svn", + ".tox", + ".venv", + ".vscode", + "__pypackages__", + "_build", + "buck-out", + "build", + "dist", + "node_modules", + "site-packages", + "venv", +] + +line-length = 100 +indent-width = 4 +target-version = "py313" + +[tool.ruff.lint] +select = [ + # pycodestyle + "E", + "W", + # pyflakes + "F", + # pylint + "PL", +] +ignore = [] +fixable = ["ALL"] +unfixable = [] +dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" + +[tool.ruff.format] +quote-style = "double" +indent-style = "space" +skip-magic-trailing-comma = false +line-ending = "auto" +docstring-code-format = false +docstring-code-line-length = "dynamic"