Added libs
This commit is contained in:
142
app/start.py
Normal file
142
app/start.py
Normal file
@@ -0,0 +1,142 @@
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
from logging.handlers import RotatingFileHandler
|
||||
import shutil
|
||||
import pathlib
|
||||
import urllib.request
|
||||
import subprocess
|
||||
import zipfile
|
||||
import venv
|
||||
from pathlib import Path
|
||||
|
||||
# ==============================
|
||||
# Configuration constants
|
||||
# ==============================
|
||||
ROOT_DIR = Path(__file__).parent.resolve()
|
||||
LIBS_DIR = ROOT_DIR / "libs"
|
||||
LOGS_DIR = ROOT_DIR / "logs"
|
||||
APP_MAIN = LIBS_DIR / "app" / "main.py"
|
||||
APP_ZIP = LIBS_DIR / "app.zip"
|
||||
DEFAULT_REPOSITORY = "https://n0sys.duckdns.org/downloads/libs"
|
||||
ARGS_LIST = ["updateApp=False", "updateLibs=True", "repack=True"]
|
||||
|
||||
# ==============================
|
||||
# Logger setup
|
||||
# ==============================
|
||||
def setup_logger() -> logging.Logger:
|
||||
"""Configure application logger with console and rotating file handlers."""
|
||||
logger = logging.getLogger("start")
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
LOGS_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Log format
|
||||
formatter = logging.Formatter(
|
||||
fmt="%(asctime)s | %(levelname)-8s | %(message)s",
|
||||
datefmt="%Y-%m-%d %H:%M:%S"
|
||||
)
|
||||
|
||||
# Console handler
|
||||
console_handler = logging.StreamHandler()
|
||||
console_handler.setLevel(logging.INFO)
|
||||
console_handler.setFormatter(formatter)
|
||||
logger.addHandler(console_handler)
|
||||
|
||||
# File handler
|
||||
file_handler = RotatingFileHandler(LOGS_DIR / "start.log", maxBytes=5_000_000, backupCount=3, encoding="utf-8")
|
||||
file_handler.setLevel(logging.DEBUG)
|
||||
file_handler.setFormatter(formatter)
|
||||
logger.addHandler(file_handler)
|
||||
|
||||
return logger
|
||||
|
||||
logger = setup_logger()
|
||||
|
||||
# ==============================
|
||||
# Functions
|
||||
# ==============================
|
||||
def start_app():
|
||||
"""Entry point for the launcher"""
|
||||
logger.info("--------- START ---------")
|
||||
logger.debug(f"Root path: {ROOT_DIR}")
|
||||
|
||||
LIBS_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# TODO: remove in production
|
||||
# update_libs()
|
||||
|
||||
create_venv()
|
||||
ensure_app()
|
||||
|
||||
# Import after app is available
|
||||
from libs.app.common.process import new_python_process
|
||||
from libs.app.common.args import read_kargs, kargs_to_array
|
||||
|
||||
args = kargs_to_array()
|
||||
pid = new_python_process(APP_MAIN, str(get_venv_python()), args=args, wait=True, new_console=True)
|
||||
logger.info(f"Main process running. PID {pid} - Args: {args}")
|
||||
logger.info("--------- END ---------")
|
||||
|
||||
|
||||
def get_venv_python():
|
||||
"""Return the path to the venv's Python executable in a cross-platform way"""
|
||||
if os.name == "nt":
|
||||
return ROOT_DIR / ".venv" / "Scripts" / "python.exe"
|
||||
else:
|
||||
return ROOT_DIR / ".venv" / "bin" / "python"
|
||||
|
||||
def update_libs():
|
||||
"""Development only: repack local libs"""
|
||||
if ("updateApp=True" in ARGS_LIST or "updateLibs=True" in ARGS_LIST) and "repack=True" in ARGS_LIST:
|
||||
update_version_script = r"C:\Workspace\utils\updateLibsVersion.py"
|
||||
try:
|
||||
subprocess.run(
|
||||
[str(get_venv_python()), update_version_script],
|
||||
cwd=ROOT_DIR,
|
||||
creationflags=subprocess.CREATE_NEW_CONSOLE,
|
||||
check=True,
|
||||
)
|
||||
except subprocess.CalledProcessError as e:
|
||||
logger.error(f"Error running update libs: {e}")
|
||||
|
||||
def ensure_app():
|
||||
"""Download, extract and install requirements of the application if not already present"""
|
||||
if APP_MAIN.exists():
|
||||
logger.debug("App already present, skipping download.")
|
||||
return
|
||||
|
||||
url = f"{DEFAULT_REPOSITORY}/app/app.zip"
|
||||
logger.info(f"Downloading app from {url} ...")
|
||||
try:
|
||||
urllib.request.urlretrieve(url, APP_ZIP)
|
||||
except Exception as e:
|
||||
logger.exception(f"Failed to download app")
|
||||
raise
|
||||
|
||||
logger.info(f"Extracting {APP_ZIP}...")
|
||||
with zipfile.ZipFile(APP_ZIP, 'r') as zip_ref:
|
||||
zip_ref.extractall(LIBS_DIR)
|
||||
|
||||
logger.info(f"Installing app requirements ...")
|
||||
python_exec = str(get_venv_python())
|
||||
requirements_path = os.path.join(ROOT_DIR, "libs/app/requirements.txt")
|
||||
subprocess.check_call([python_exec, "-m", "pip", "install", "-r", requirements_path])
|
||||
|
||||
|
||||
def create_venv():
|
||||
"""Ensure a local virtual environment exists."""
|
||||
venv_dir = os.path.join(ROOT_DIR, ".venv")
|
||||
if not os.path.exists(venv_dir):
|
||||
logger.debug(f"Creating python venv: {venv_dir}")
|
||||
venv.create(venv_dir, with_pip=True)
|
||||
|
||||
# ==============================
|
||||
# Main
|
||||
# ==============================
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
start_app()
|
||||
except Exception:
|
||||
logger.exception("Error starting application")
|
||||
sys.exit(1)
|
||||
Reference in New Issue
Block a user