set shell := [ "bash", "-uc" ]
_default:
    @- just --unsorted --choose
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Justfile
# NOTE: Do not change the contents of this file!
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# VARIABLES
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

PYTHON := if os_family() == "windows" { "py -3" } else { "python3" }
GEN_MODELS := "datamodel-codegen"

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Macros
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

_create-file-if-not-exists fname:
    @touch "{{fname}}";

_create-folder-if-not-exists path:
    @if ! [ -d "{{path}}" ]; then mkdir "{{path}}"; fi

_delete-if-file-exists fname:
    @if [ -f "{{fname}}" ]; then rm "{{fname}}"; fi

_delete-if-folder-exists path:
    @if [ -d "{{path}}" ]; then rm -rf "{{path}}"; fi

_clean-all-files pattern:
    @find . -type f -name "{{pattern}}" -exec basename {} \; 2> /dev/null
    @- find . -type f -name "{{pattern}}" -exec rm {} \; 2> /dev/null

_clean-all-folders pattern:
    @find . -type d -name "{{pattern}}" -exec basename {} \; 2> /dev/null
    @- find . -type d -name "{{pattern}}" -exec rm -rf {} \; 2> /dev/null

_docker-build-and-log service:
    @docker compose up --build -d {{service}} && docker compose logs -f --tail=0 {{service}}

_docker-build-and-interact service container:
    @docker compose up --build -d {{service}} && docker attach {{container}}

_generate-models path name:
    @{{GEN_MODELS}} \
        --input-file-type openapi \
        --encoding "UTF-8" \
        --disable-timestamp \
        --use-schema-description \
        --allow-population-by-field-name \
        --snake-case-field \
        --strict-nullable \
        --target-python-version 3.9 \
        --input {{path}}/{{name}}-schema.yaml \
        --output {{path}}/generated/{{name}}.py

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# TARGETS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# TARGETS: build
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

build: _build-requirements _build-skip-requirements
_build-skip-requirements: build-models
_build-requirements:
    @{{PYTHON}} -m pip install --disable-pip-version-check -r requirements.txt
build-models: _check-system-requirements _build-models-nochecks
_build-models-nochecks:
    @echo "Generate data models from schemata."
    @just _create-folder-if-not-exists "models/generated"
    @- just _generate-models "models" "config"
    @- just _generate-models "models" "commands"

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# TARGETS: run
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

run:
    @{{PYTHON}} main.py

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# TARGETS: tests
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

tests: tests-unit
tests-logs:
    @just _create-logs
    @- just tests
    @just _display-logs
tests-unit-logs:
    @just _create-logs
    @- just tests-unit
    @just _display-logs
tests-unit:
    @{{PYTHON}} -m pytest tests \
        --ignore=tests/integration \
        --cov-reset \
        --cov=. \
        2> /dev/null

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# TARGETS: qa
# NOTE: use for development only.
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

qa:
    @{{PYTHON}} -m coverage report -m
coverage source_path tests_path:
    @just _create-logs
    @-just _coverage-no-logs "{{source_path}}" "{{tests_path}}"
    @just _display-logs
_coverage-no-logs source_path tests_path:
    @{{PYTHON}} -m pytest {{tests_path}} \
        --ignore=tests/integration \
        --cov-reset \
        --cov={{source_path}} \
        --capture=tee-sys \
        2> /dev/null

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# TARGETS: clean
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

clean:
    @-just clean-basic
    @-just clean-sessions
clean-sessions:
    @echo "All sessions will be force removed."
    @- just _delete-if-folder-exists ".secrets" 2> /dev/null
clean-basic:
    @echo "All system artefacts will be force removed."
    @- just _clean-all-files ".DS_Store" 2> /dev/null
    @echo "All test artefacts will be force removed."
    @- just _clean-all-folders ".pytest_cache" 2> /dev/null
    @- just _delete-if-file-exists ".coverage" 2> /dev/null
    @- just _delete-if-folder-exists "logs"
    @echo "All build artefacts will be force removed."
    @- just _clean-all-folders "__pycache__" 2> /dev/null
    @- just _delete-if-folder-exists "models/generated" 2> /dev/null

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# TARGETS: logging, session
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

_create-logs:
    @# For logging purposes (since stdout is rechanneled):
    @just _delete-if-file-exists "logs/debug.log"
    @just _create-folder-if-not-exists "logs"
    @just _create-file-if-not-exists "logs/debug.log"
_display-logs:
    @echo ""
    @echo "Content of logs/debug.log:"
    @echo "----------------"
    @echo ""
    @- cat logs/debug.log
    @echo ""
    @echo "----------------"

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# TARGETS: requirements
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

check-system:
    @echo "Operating System detected: {{os_family()}}."
    @echo "Python command used: {{PYTHON}}."
_check-system-requirements:
    @if ! ( {{GEN_MODELS}} --help >> /dev/null 2> /dev/null ); then \
        echo "Command '{{GEN_MODELS}}' did not work. Ensure that the installation of 'datamodel-code-generator' worked and that system paths are set." \
        exit 1; \
    fi