mirror of
https://github.com/ae-utbm/sith.git
synced 2025-03-10 07:17:11 +00:00
Launch multiple honcho files depending on the context
This commit is contained in:
parent
87f790a044
commit
6b27a97e7b
@ -13,5 +13,5 @@ CACHE_URL=redis://127.0.0.1:${REDIS_PORT}/0
|
|||||||
|
|
||||||
# Used to select which other services to run alongside
|
# Used to select which other services to run alongside
|
||||||
# manage.py, pytest and runserver
|
# manage.py, pytest and runserver
|
||||||
PROCFILE_FULL=Procfile.full
|
PROCFILE_STATIC=Procfile.static
|
||||||
PROCFILE_MINIMAL=Procfile.minimal
|
PROCFILE_SERVICE=Procfile.service
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
bundler: npm run serve
|
|
||||||
redis: redis-server --port $REDIS_PORT
|
|
1
Procfile.static
Normal file
1
Procfile.static
Normal file
@ -0,0 +1 @@
|
|||||||
|
bundler: npm run serve
|
@ -88,15 +88,15 @@ tous ces services sont déjà configurés.
|
|||||||
Pour désactiver Honcho il suffit de ne sélectionner aucun `PROCFILE_` dans la config.
|
Pour désactiver Honcho il suffit de ne sélectionner aucun `PROCFILE_` dans la config.
|
||||||
|
|
||||||
```dotenv
|
```dotenv
|
||||||
PROCFILE_FULL=
|
PROCFILE_STATIC=
|
||||||
PROCFILE_MINIMAL=
|
PROCFILE_SERVICE=
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
|
|
||||||
Si honcho ne tourne plus, la recompilation automatique
|
Si `PROCFILE_STATIC` est désactivé, la recompilation automatique
|
||||||
des fichiers statiques ne se fait plus.
|
des fichiers statiques ne se fait plus.
|
||||||
Si vous en avez besoin et que vous travaillez sans honcho,
|
Si vous en avez besoin et que vous travaillez sans `PROCFILE_STATIC`,
|
||||||
vous devez ouvrir une autre fenêtre de votre terminal
|
vous devez ouvrir une autre fenêtre de votre terminal
|
||||||
et lancer la commande `npm run serve`
|
et lancer la commande `npm run serve`
|
||||||
|
|
||||||
|
@ -82,8 +82,8 @@ sith/
|
|||||||
├── pyproject.toml (31)
|
├── pyproject.toml (31)
|
||||||
├── .venv/ (32)
|
├── .venv/ (32)
|
||||||
├── .python-version (33)
|
├── .python-version (33)
|
||||||
├── Procfile.full (34)
|
├── Procfile.static (34)
|
||||||
├── Procfile.minimal (35)
|
├── Procfile.service (35)
|
||||||
└── README.md
|
└── README.md
|
||||||
```
|
```
|
||||||
</div>
|
</div>
|
||||||
@ -142,10 +142,10 @@ sith/
|
|||||||
de certaines d'entre elles.
|
de certaines d'entre elles.
|
||||||
32. Dossier d'environnement virtuel généré par uv
|
32. Dossier d'environnement virtuel généré par uv
|
||||||
33. Fichier qui contrôle quelle version de python utiliser pour le projet
|
33. Fichier qui contrôle quelle version de python utiliser pour le projet
|
||||||
34. Fichier qui contrôle les services additionnels à lancer
|
34. Fichier qui contrôle les commandes à lancer pour gérer la compilation
|
||||||
avec le serveur de développement. Serveurs + gestion des statics.
|
automatique des static et autres services nécessaires à la command runserver.
|
||||||
35. Fichier qui contrôle les services additionnels à lancer
|
35. Fichier qui contrôle les services tiers nécessaires au fonctionnement
|
||||||
avec les autres commandes (pytest, shell…). Serveurs uniquement.
|
du Sith tel que redis.
|
||||||
|
|
||||||
## L'application principale
|
## L'application principale
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ import sys
|
|||||||
from django.utils.autoreload import DJANGO_AUTORELOAD_ENV
|
from django.utils.autoreload import DJANGO_AUTORELOAD_ENV
|
||||||
|
|
||||||
from sith.composer import start_composer, stop_composer
|
from sith.composer import start_composer, stop_composer
|
||||||
from sith.settings import PROCFILE_FULL, PROCFILE_MINIMAL
|
from sith.settings import PROCFILE_SERVICE
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
logging.basicConfig(encoding="utf-8", level=logging.INFO)
|
logging.basicConfig(encoding="utf-8", level=logging.INFO)
|
||||||
@ -30,9 +30,8 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
from django.core.management import execute_from_command_line
|
from django.core.management import execute_from_command_line
|
||||||
|
|
||||||
procfile = PROCFILE_FULL if sys.argv[1] == "runserver" else PROCFILE_MINIMAL
|
if os.environ.get(DJANGO_AUTORELOAD_ENV) is None and PROCFILE_SERVICE is not None:
|
||||||
if os.environ.get(DJANGO_AUTORELOAD_ENV) is None and procfile is not None:
|
start_composer(PROCFILE_SERVICE)
|
||||||
start_composer(procfile)
|
_ = atexit.register(stop_composer, procfile=PROCFILE_SERVICE)
|
||||||
_ = atexit.register(stop_composer)
|
|
||||||
|
|
||||||
execute_from_command_line(sys.argv)
|
execute_from_command_line(sys.argv)
|
||||||
|
@ -9,30 +9,37 @@ import psutil
|
|||||||
from sith import settings
|
from sith import settings
|
||||||
|
|
||||||
|
|
||||||
def get_pid() -> int | None:
|
def get_pid_file(procfile: Path) -> Path:
|
||||||
|
"""Get the PID file associated with a procfile"""
|
||||||
|
return settings.BASE_DIR / procfile.with_suffix(f"{procfile.suffix}.pid")
|
||||||
|
|
||||||
|
|
||||||
|
def get_pid(procfile: Path) -> int | None:
|
||||||
"""Read the PID file to get the currently running composer if it exists"""
|
"""Read the PID file to get the currently running composer if it exists"""
|
||||||
if not settings.COMPOSER_PID_PATH.exists():
|
file = get_pid_file(procfile)
|
||||||
|
if not file.exists():
|
||||||
return None
|
return None
|
||||||
with open(settings.COMPOSER_PID_PATH, "r", encoding="utf8") as f:
|
with open(file, "r", encoding="utf8") as f:
|
||||||
return int(f.read())
|
return int(f.read())
|
||||||
|
|
||||||
|
|
||||||
def write_pid(pid: int):
|
def write_pid(procfile: Path, pid: int):
|
||||||
"""Write currently running composer pid in PID file"""
|
"""Write currently running composer pid in PID file"""
|
||||||
if not settings.COMPOSER_PID_PATH.exists():
|
file = get_pid_file(procfile)
|
||||||
settings.COMPOSER_PID_PATH.parent.mkdir(parents=True, exist_ok=True)
|
if not file.exists():
|
||||||
with open(settings.COMPOSER_PID_PATH, "w", encoding="utf8") as f:
|
file.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
with open(file, "w", encoding="utf8") as f:
|
||||||
_ = f.write(str(pid))
|
_ = f.write(str(pid))
|
||||||
|
|
||||||
|
|
||||||
def delete_pid():
|
def delete_pid(procfile: Path):
|
||||||
"""Delete PID file for cleanup"""
|
"""Delete PID file for cleanup"""
|
||||||
settings.COMPOSER_PID_PATH.unlink(missing_ok=True)
|
get_pid_file(procfile).unlink(missing_ok=True)
|
||||||
|
|
||||||
|
|
||||||
def is_composer_running() -> bool:
|
def is_composer_running(procfile: Path) -> bool:
|
||||||
"""Check if the process in the PID file is running"""
|
"""Check if the process in the PID file is running"""
|
||||||
pid = get_pid()
|
pid = get_pid(procfile)
|
||||||
if pid is None:
|
if pid is None:
|
||||||
return False
|
return False
|
||||||
try:
|
try:
|
||||||
@ -45,25 +52,29 @@ def start_composer(procfile: Path):
|
|||||||
"""Starts the composer and stores the PID as an environment variable
|
"""Starts the composer and stores the PID as an environment variable
|
||||||
This allows for running smoothly with the django reloader
|
This allows for running smoothly with the django reloader
|
||||||
"""
|
"""
|
||||||
if is_composer_running():
|
if is_composer_running(procfile):
|
||||||
logging.info(f"Composer is already running with pid {get_pid()}")
|
|
||||||
logging.info(
|
logging.info(
|
||||||
f"If this is a mistake, please delete {settings.COMPOSER_PID_PATH} and restart the process"
|
f"Composer for {procfile} is already running with pid {get_pid(procfile)}"
|
||||||
|
)
|
||||||
|
logging.info(
|
||||||
|
f"If this is a mistake, please delete {get_pid_file(procfile)} and restart the process"
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
process = subprocess.Popen(
|
process = subprocess.Popen(
|
||||||
[sys.executable, "-m", "honcho", "-f", str(procfile), "start"],
|
[sys.executable, "-m", "honcho", "-f", str(procfile), "start"],
|
||||||
)
|
)
|
||||||
write_pid(process.pid)
|
write_pid(procfile, process.pid)
|
||||||
|
|
||||||
|
|
||||||
def stop_composer():
|
def stop_composer(procfile: Path):
|
||||||
"""Stops the composer if it was started before"""
|
"""Stops the composer if it was started before"""
|
||||||
if is_composer_running():
|
if is_composer_running(procfile):
|
||||||
process = psutil.Process(get_pid())
|
process = psutil.Process(get_pid(procfile))
|
||||||
if process.parent() != psutil.Process():
|
if process.parent() != psutil.Process():
|
||||||
logging.info("Currently running composer is controlled by another process")
|
logging.info(
|
||||||
|
f"Currently running composer for {procfile} is controlled by another process"
|
||||||
|
)
|
||||||
return
|
return
|
||||||
process.send_signal(signal.SIGTERM)
|
process.send_signal(signal.SIGTERM)
|
||||||
_ = process.wait()
|
_ = process.wait()
|
||||||
delete_pid()
|
delete_pid(procfile)
|
||||||
|
@ -3,7 +3,7 @@ import atexit
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from .composer import start_composer, stop_composer
|
from .composer import start_composer, stop_composer
|
||||||
from .settings import PROCFILE_MINIMAL
|
from .settings import PROCFILE_SERVICE
|
||||||
|
|
||||||
# it's the first hook loaded by pytest and can only
|
# it's the first hook loaded by pytest and can only
|
||||||
# be defined in a proper pytest plugin
|
# be defined in a proper pytest plugin
|
||||||
@ -15,6 +15,6 @@ from .settings import PROCFILE_MINIMAL
|
|||||||
@pytest.hookimpl(tryfirst=True)
|
@pytest.hookimpl(tryfirst=True)
|
||||||
def pytest_load_initial_conftests(early_config, parser, args):
|
def pytest_load_initial_conftests(early_config, parser, args):
|
||||||
"""Hook that loads the composer before the pytest-django plugin"""
|
"""Hook that loads the composer before the pytest-django plugin"""
|
||||||
if PROCFILE_MINIMAL is not None:
|
if PROCFILE_SERVICE is not None:
|
||||||
start_composer(PROCFILE_MINIMAL)
|
start_composer(PROCFILE_SERVICE)
|
||||||
_ = atexit.register(stop_composer)
|
_ = atexit.register(stop_composer, procfile=PROCFILE_SERVICE)
|
||||||
|
@ -64,11 +64,8 @@ def optional_file_parser(value: str) -> Path | None:
|
|||||||
BASE_DIR = Path(__file__).parent.parent.resolve()
|
BASE_DIR = Path(__file__).parent.parent.resolve()
|
||||||
|
|
||||||
# Composer settings
|
# Composer settings
|
||||||
PROCFILE_FULL = env.optional_file("PROCFILE_FULL", None)
|
PROCFILE_STATIC = env.optional_file("PROCFILE_STATIC", None)
|
||||||
PROCFILE_MINIMAL = env.optional_file("PROCFILE_MINIMAL", None)
|
PROCFILE_SERVICE = env.optional_file("PROCFILE_SERVICE", None)
|
||||||
|
|
||||||
## File path used to avoid running the composer multiple times at the same time
|
|
||||||
COMPOSER_PID_PATH = env.path("COMPOSER_PID_PATH", BASE_DIR / "composer.pid")
|
|
||||||
|
|
||||||
# Quick-start development settings - unsuitable for production
|
# Quick-start development settings - unsuitable for production
|
||||||
# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
|
# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
|
import atexit
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
from django.contrib.staticfiles.management.commands.runserver import (
|
from django.contrib.staticfiles.management.commands.runserver import (
|
||||||
Command as Runserver,
|
Command as Runserver,
|
||||||
)
|
)
|
||||||
|
from django.utils.autoreload import DJANGO_AUTORELOAD_ENV
|
||||||
|
|
||||||
|
from sith.composer import start_composer, stop_composer
|
||||||
from staticfiles.processors import OpenApi
|
from staticfiles.processors import OpenApi
|
||||||
|
|
||||||
|
|
||||||
@ -10,4 +16,10 @@ class Command(Runserver):
|
|||||||
|
|
||||||
def run(self, **options):
|
def run(self, **options):
|
||||||
OpenApi.compile()
|
OpenApi.compile()
|
||||||
|
if (
|
||||||
|
os.environ.get(DJANGO_AUTORELOAD_ENV) is None
|
||||||
|
and settings.PROCFILE_STATIC is not None
|
||||||
|
):
|
||||||
|
start_composer(settings.PROCFILE_STATIC)
|
||||||
|
_ = atexit.register(stop_composer, procfile=settings.PROCFILE_STATIC)
|
||||||
super().run(**options)
|
super().run(**options)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user