117 lines
3.3 KiB
Python
117 lines
3.3 KiB
Python
"""Executable entry point for CadHubManage."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import multiprocessing
|
|
import os
|
|
import shutil
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
|
|
def _copy_missing_tree(src: Path, dst: Path) -> None:
|
|
if not src.exists():
|
|
return
|
|
|
|
for item in src.rglob("*"):
|
|
rel = item.relative_to(src)
|
|
target = dst / rel
|
|
|
|
if item.is_dir():
|
|
target.mkdir(parents=True, exist_ok=True)
|
|
continue
|
|
|
|
if target.exists():
|
|
continue
|
|
|
|
target.parent.mkdir(parents=True, exist_ok=True)
|
|
shutil.copy2(item, target)
|
|
|
|
|
|
def _materialize_packaged_resources(base_dir: Path) -> None:
|
|
if not getattr(sys, "frozen", False):
|
|
return
|
|
|
|
meipass = Path(getattr(sys, "_MEIPASS", ""))
|
|
if not meipass:
|
|
return
|
|
|
|
packaged_configs = meipass / "configs"
|
|
target_configs = base_dir / "configs"
|
|
_copy_missing_tree(packaged_configs, target_configs)
|
|
|
|
packaged_env_example = meipass / ".env.example"
|
|
target_env_example = base_dir / ".env.example"
|
|
if packaged_env_example.exists() and not target_env_example.exists():
|
|
shutil.copy2(packaged_env_example, target_env_example)
|
|
|
|
(base_dir / "logs" / "operation_logs").mkdir(parents=True, exist_ok=True)
|
|
|
|
|
|
def prepare_environment() -> Path:
|
|
raw_base_dir = os.environ.get("CADHUB_BASE_DIR")
|
|
if raw_base_dir:
|
|
base_dir = Path(raw_base_dir).resolve()
|
|
elif getattr(sys, "frozen", False):
|
|
base_dir = Path(sys.executable).resolve().parent
|
|
else:
|
|
base_dir = Path(__file__).resolve().parent
|
|
|
|
base_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
_materialize_packaged_resources(base_dir)
|
|
|
|
os.environ.setdefault("CADHUB_BASE_DIR", str(base_dir))
|
|
os.chdir(base_dir)
|
|
return base_dir
|
|
|
|
|
|
BASE_DIR = prepare_environment()
|
|
|
|
|
|
from app.main import app # noqa: E402 pylint: disable=wrong-import-position
|
|
from app.config import settings # noqa: E402 pylint: disable=wrong-import-position
|
|
import uvicorn # noqa: E402 pylint: disable=wrong-import-position
|
|
|
|
|
|
def parse_args() -> argparse.Namespace:
|
|
parser = argparse.ArgumentParser(description="CadHubManage offline launcher")
|
|
parser.add_argument("--host", default=settings.host, help="Host address")
|
|
parser.add_argument("--port", type=int, default=settings.port, help="Port number")
|
|
parser.add_argument("--workers", type=int, default=1, help="Number of worker processes")
|
|
parser.add_argument("--reload", action="store_true", help="Enable auto-reload (development only)")
|
|
parser.add_argument(
|
|
"--log-level",
|
|
default=settings.log_level.lower(),
|
|
choices=["critical", "error", "warning", "info", "debug", "trace"],
|
|
help="Logging level",
|
|
)
|
|
return parser.parse_args()
|
|
|
|
|
|
def main() -> None:
|
|
args = parse_args()
|
|
|
|
if args.reload and args.workers != 1:
|
|
print("Reload mode requires workers=1, adjusting automatically.")
|
|
args.workers = 1
|
|
|
|
uvicorn_app = app
|
|
if args.reload or args.workers != 1:
|
|
uvicorn_app = "app.main:app"
|
|
|
|
uvicorn.run(
|
|
uvicorn_app,
|
|
host=args.host,
|
|
port=args.port,
|
|
reload=args.reload,
|
|
workers=args.workers,
|
|
log_level=args.log_level,
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
multiprocessing.freeze_support()
|
|
main()
|