chore: startup path anchoring, env parsing and gitignore
- Launcher guards Python 3.13 before importing the package and chdirs to the repo root so cwd-relative default paths resolve consistently. - main() logs the resolved .env path and warns on a missing static dir or a short auth token; env_file reads utf-8-sig so a BOM doesn't drop the first variable. - .gitignore covers .claude/settings.local.json and .impeccable/.
This commit is contained in:
parent
3535bfee15
commit
6ab6da3719
4 changed files with 38 additions and 3 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -31,6 +31,10 @@ artifacts/
|
|||
tmp_*
|
||||
tmp_dbg_img/
|
||||
|
||||
# Local tool state (do not rely on the machine-global gitignore)
|
||||
.claude/settings.local.json
|
||||
.impeccable/
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
|
|
|||
|
|
@ -1,6 +1,14 @@
|
|||
from pathlib import Path
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Guard BEFORE importing rights_filter so a 3.13-only syntax in the package
|
||||
# surfaces this friendly message instead of a raw SyntaxError/ImportError.
|
||||
if sys.version_info < (3, 13):
|
||||
sys.exit(
|
||||
"Copyrighter requires Python 3.13+ — activate the offline venv "
|
||||
"(see docs/operations/offline-install.md)."
|
||||
)
|
||||
|
||||
ROOT = Path(__file__).resolve().parent
|
||||
SRC = ROOT / "src"
|
||||
|
|
@ -12,4 +20,8 @@ from rights_filter.server.__main__ import main
|
|||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Anchor the working directory to the repo root so the cwd-relative default
|
||||
# paths (data/, web/operator-gui) resolve the same regardless of where the
|
||||
# launcher was invoked from.
|
||||
os.chdir(ROOT)
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -33,7 +33,12 @@ def main() -> None:
|
|||
parser.add_argument("--env", default=".env")
|
||||
args = parser.parse_args()
|
||||
|
||||
load_env_file(Path(args.env), os.environ)
|
||||
env_path = Path(args.env)
|
||||
load_env_file(env_path, os.environ)
|
||||
# Log the resolved env path (and whether it was found) so an operator running
|
||||
# from an unexpected directory can see which .env — if any — was actually
|
||||
# loaded, rather than silently getting no token / disabled providers.
|
||||
print(f".env: {env_path.resolve()} ({'loaded' if env_path.exists() else 'not found'})")
|
||||
provider_runtime = build_provider_runtime(os.environ)
|
||||
print("Provider readiness: " + _provider_readiness(provider_runtime))
|
||||
image_store = LocalSubmissionImageStore(Path(args.images))
|
||||
|
|
@ -44,13 +49,25 @@ def main() -> None:
|
|||
auth_token = os.environ.get("COPYRIGHTER_AUTH_TOKEN", "").strip() or None
|
||||
if auth_token is None:
|
||||
print("WARNING: COPYRIGHTER_AUTH_TOKEN not set — data routes are unauthenticated.")
|
||||
elif len(auth_token) < 32:
|
||||
print(
|
||||
"WARNING: COPYRIGHTER_AUTH_TOKEN is shorter than 32 characters — "
|
||||
"use a longer, high-entropy token (e.g. `python -c \"import secrets; print(secrets.token_urlsafe(32))\"`)."
|
||||
)
|
||||
|
||||
static_path = Path(args.static)
|
||||
if not static_path.exists():
|
||||
print(
|
||||
f"WARNING: static GUI directory not found: {static_path.resolve()} — "
|
||||
"the operator UI will return 404. Pass --static or run from the repo root."
|
||||
)
|
||||
|
||||
server = build_server(
|
||||
host=args.host,
|
||||
port=args.port,
|
||||
store=store,
|
||||
image_store=image_store,
|
||||
static_dir=Path(args.static),
|
||||
static_dir=static_path,
|
||||
auth_token=auth_token,
|
||||
)
|
||||
print(f"Copyrighter API server listening on http://{args.host}:{args.port}")
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ def load_env_file(path: Path | str, environ: MutableMapping[str, str]) -> None:
|
|||
if not env_path.exists():
|
||||
return
|
||||
|
||||
for raw_line in env_path.read_text(encoding="utf-8").splitlines():
|
||||
# utf-8-sig so a BOM on the file doesn't get glued to the first key (which
|
||||
# would silently drop the first variable — it would never match its name).
|
||||
for raw_line in env_path.read_text(encoding="utf-8-sig").splitlines():
|
||||
line = raw_line.strip()
|
||||
if not line or line.startswith("#"):
|
||||
continue
|
||||
|
|
|
|||
Loading…
Reference in a new issue