import json import logging from pathlib import Path import shlex import subprocess import sys from typing import Sequence _project_root = Path('.').absolute() def get_project_root() -> Path: return _project_root def set_project_root(path: Path) -> None: global _project_root _project_root = path def get_config_cache() -> dict: cache_file = get_project_root() / 'cache' / 'config_cache.json' if not cache_file.exists(): return {} try: with cache_file.open('r') as f: cache = json.load(f) if not isinstance(cache, dict): logging.warning('Config cache is not a dictionary, ignoring it.') return {} return cache except Exception as e: logging.error(f'Error while reading config cache: {e}.') return {} def require_project_file() -> None: if not (get_project_root() / 'SConstruct').exists(): logging.error('This command has to be run inside an existing S++ project folder. Exiting.') sys.exit(1) def exec_checked(args: Sequence[str], **kwargs) -> None: logging.debug('exec_checked: "%s"', shlex.join(args)) subprocess.run(args, stdout=sys.stdout, stderr=sys.stderr, check=True, **kwargs) def exec_get_output(args: Sequence[str], **kwargs) -> str: logging.debug('exec_get_output: "%s"', shlex.join(args)) return subprocess.run(args, text=True, check=True, capture_output=True, **kwargs).stdout def exec_spp(args: Sequence[str], **kwargs): full_cmd = ('scons', '-s', '--disable_auto_update', *args) exec_checked(full_cmd, **kwargs)