autocal layout first design
This commit is contained in:
@@ -1,34 +1,80 @@
|
||||
"""Resolve app, config, and output paths for editable and frozen runs."""
|
||||
"""Resolve app, config, and output paths for editable and frozen runs.
|
||||
|
||||
Several desktop products share this package. Which one a process belongs to is
|
||||
decided once, at start-up:
|
||||
|
||||
* ``ORISYS_APP_ID`` — the directory name under ``apps/`` (e.g. ``studio``,
|
||||
``autocal``). Set it **before** importing anything from this package; an app
|
||||
that changes it later gets whichever root was resolved first, because these
|
||||
helpers are called during import of logging/prefs.
|
||||
* Otherwise the historic behaviour applies, which resolves ``apps/studio``.
|
||||
That keeps existing callers working without them passing anything.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
#: Environment variable naming the app directory under ``apps/``.
|
||||
APP_ID_ENV = "ORISYS_APP_ID"
|
||||
|
||||
#: Fallback app when ``ORISYS_APP_ID`` is unset — the first product built here.
|
||||
DEFAULT_APP_ID = "studio"
|
||||
|
||||
|
||||
def is_frozen() -> bool:
|
||||
return bool(getattr(sys, "frozen", False))
|
||||
|
||||
|
||||
def _studio_root_from_shared() -> Path:
|
||||
"""Repo layout: shared/src/orisys_app_shared -> apps/studio."""
|
||||
def app_id() -> str:
|
||||
"""The app directory name for this process."""
|
||||
return os.environ.get(APP_ID_ENV, "").strip() or DEFAULT_APP_ID
|
||||
|
||||
|
||||
def apps_dir() -> Path:
|
||||
"""The ``apps/`` directory of the source tree."""
|
||||
here = Path(__file__).resolve()
|
||||
# .../orisys-app/shared/src/orisys_app_shared/paths.py
|
||||
# .../orisys-app/shared/src/orisys_app_shared/paths.py -> .../orisys-app
|
||||
repo_root = here.parents[3]
|
||||
return repo_root / "apps" / "studio"
|
||||
return repo_root / "apps"
|
||||
|
||||
|
||||
def _default_app_root_from_shared(app_id_value: str) -> Path:
|
||||
"""Repo layout: shared/src/orisys_app_shared -> apps/<app>."""
|
||||
return apps_dir() / app_id_value
|
||||
|
||||
|
||||
def app_root() -> Path:
|
||||
"""Return the studio app root (editable) or EXE directory (frozen)."""
|
||||
"""Return this app's root (editable) or the EXE directory (frozen)."""
|
||||
if is_frozen():
|
||||
return Path(sys.executable).resolve().parent
|
||||
# Prefer cwd override when launched from apps/studio
|
||||
|
||||
wanted = app_id()
|
||||
|
||||
# Launched from inside an app directory (``python apps/<app>/run.py``).
|
||||
cwd = Path.cwd().resolve()
|
||||
if (cwd / "config").is_dir() and (cwd / "run.py").is_file():
|
||||
return cwd
|
||||
if (cwd / "apps" / "studio" / "config").is_dir():
|
||||
return cwd / "apps" / "studio"
|
||||
return _studio_root_from_shared()
|
||||
|
||||
# Launched from the repo root.
|
||||
candidate = cwd / "apps" / wanted
|
||||
if (candidate / "config").is_dir():
|
||||
return candidate
|
||||
|
||||
# A named app that is not where we expected must not silently fall back to
|
||||
# another product's config: that would write one app's preferences into
|
||||
# another's tree.
|
||||
if wanted == DEFAULT_APP_ID:
|
||||
return _default_app_root_from_shared(wanted)
|
||||
unresolved = _default_app_root_from_shared(wanted)
|
||||
if (unresolved / "config").is_dir():
|
||||
return unresolved
|
||||
raise FileNotFoundError(
|
||||
f"{APP_ID_ENV}={wanted!r} does not name an app with a config directory "
|
||||
f"(looked in {cwd / 'apps' / wanted} and {unresolved})"
|
||||
)
|
||||
|
||||
|
||||
def config_dir() -> Path:
|
||||
|
||||
Reference in New Issue
Block a user