|
27 | 27 | # baseline no longer banks free process points; weights redistributed. |
28 | 28 | SCORING_VERSION = "1.2" |
29 | 29 |
|
30 | | -# Conventional install path for the RIMAPI Workshop mod we deploy our fork DLL |
31 | | -# over. Best-effort — if Steam lives elsewhere set the RIMAPI_DLL_PATH env var. |
32 | | -_RIMAPI_DLL_DEFAULT_PATH = Path( |
| 30 | +# Compiled fork layout relative to a RIMAPI checkout root. |
| 31 | +_RIMAPI_DLL_RELATIVE = Path("1.6") / "Assemblies" / "RIMAPI.dll" |
| 32 | + |
| 33 | +# Steam Workshop install we sometimes overlay. Last-resort fallback only — |
| 34 | +# Workshop is not source of truth (Flash can drift the Workshop DLL). |
| 35 | +_RIMAPI_DLL_WORKSHOP_FALLBACK = Path( |
33 | 36 | "C:/Steam/steamapps/workshop/content/294100/3593423732/1.6/Assemblies/RIMAPI.dll", |
34 | 37 | ) |
35 | 38 |
|
@@ -83,36 +86,122 @@ def file_sha256(path: Path | None) -> str | None: |
83 | 86 | return None |
84 | 87 |
|
85 | 88 |
|
| 89 | +def _is_packaged_install(path: Path) -> bool: |
| 90 | + """True when *path* lives in a venv/site-packages install, not a checkout.""" |
| 91 | + return "site-packages" in path.parts or ".venv" in path.parts |
| 92 | + |
| 93 | + |
| 94 | +def _checkout_root_from_source_file(file_path: Path) -> Path | None: |
| 95 | + """RLE checkout root inferred from ``src/rle/tracking/metadata.py``. |
| 96 | +
|
| 97 | + Returns None for packaged installs (site-packages / .venv): ``parents[3]`` |
| 98 | + is not the RLE repo in those layouts. |
| 99 | + """ |
| 100 | + if _is_packaged_install(file_path): |
| 101 | + return None |
| 102 | + try: |
| 103 | + candidate = file_path.resolve().parents[3] |
| 104 | + except IndexError: |
| 105 | + return None |
| 106 | + if (candidate / ".git").exists() or (candidate / "src" / "rle").is_dir(): |
| 107 | + return candidate |
| 108 | + return None |
| 109 | + |
| 110 | + |
| 111 | +def _rle_checkout_root() -> Path | None: |
| 112 | + """Git toplevel of the RLE checkout, if findable. |
| 113 | +
|
| 114 | + Prefers ``git rev-parse --show-toplevel`` from the process cwd (works when |
| 115 | + RLE is imported from site-packages/.venv but launched from the checkout). |
| 116 | + Falls back to ``__file__`` only when that path still looks like a source |
| 117 | + tree — not a packaged install. |
| 118 | + """ |
| 119 | + raw = _git("rev-parse", "--show-toplevel") |
| 120 | + if raw: |
| 121 | + return Path(raw) |
| 122 | + return _checkout_root_from_source_file(Path(__file__)) |
| 123 | + |
| 124 | + |
| 125 | +def _sibling_rimapi_root() -> Path | None: |
| 126 | + """``../RIMAPI`` next to the RLE checkout, or None if the checkout is unknown.""" |
| 127 | + checkout = _rle_checkout_root() |
| 128 | + if checkout is None: |
| 129 | + return None |
| 130 | + return checkout.parent / "RIMAPI" |
| 131 | + |
| 132 | + |
| 133 | +def _first_existing_file(candidates: list[Path]) -> Path | None: |
| 134 | + seen: set[str] = set() |
| 135 | + for candidate in candidates: |
| 136 | + key = os.fspath(candidate) |
| 137 | + if key in seen: |
| 138 | + continue |
| 139 | + seen.add(key) |
| 140 | + if candidate.is_file(): |
| 141 | + return candidate |
| 142 | + return None |
| 143 | + |
| 144 | + |
| 145 | +def _rimapi_dll_candidates() -> list[Path]: |
| 146 | + """Deterministic DLL probe order. First existing file wins. |
| 147 | +
|
| 148 | + 1. ``$RIMAPI_DLL_PATH`` |
| 149 | + 2. ``$RIMAPI_FORK_PATH/1.6/Assemblies/RIMAPI.dll`` |
| 150 | + 3. sibling checkout ``../RIMAPI/1.6/Assemblies/RIMAPI.dll`` |
| 151 | + 4. Workshop path (optional last fallback; not source of truth) |
| 152 | + """ |
| 153 | + candidates: list[Path] = [] |
| 154 | + dll_override = os.environ.get("RIMAPI_DLL_PATH") |
| 155 | + if dll_override: |
| 156 | + candidates.append(Path(dll_override)) |
| 157 | + fork_override = os.environ.get("RIMAPI_FORK_PATH") |
| 158 | + if fork_override: |
| 159 | + candidates.append(Path(fork_override) / _RIMAPI_DLL_RELATIVE) |
| 160 | + sibling = _sibling_rimapi_root() |
| 161 | + if sibling is not None: |
| 162 | + candidates.append(sibling / _RIMAPI_DLL_RELATIVE) |
| 163 | + candidates.append(_RIMAPI_DLL_WORKSHOP_FALLBACK) |
| 164 | + return candidates |
| 165 | + |
| 166 | + |
86 | 167 | def _rimapi_dll_path() -> Path | None: |
87 | | - """Resolve the deployed RIMAPI DLL path (env override → Workshop default).""" |
88 | | - override = os.environ.get("RIMAPI_DLL_PATH") |
| 168 | + """Resolve the RIMAPI DLL, preferring a compiled fork over Workshop.""" |
| 169 | + return _first_existing_file(_rimapi_dll_candidates()) |
| 170 | + |
| 171 | + |
| 172 | +def _rimapi_fork_candidates() -> list[Path]: |
| 173 | + """Fork checkout probe order. First path with a ``.git`` dir wins. |
| 174 | +
|
| 175 | + 1. ``$RIMAPI_FORK_PATH`` |
| 176 | + 2. sibling of the RLE git toplevel (``../RIMAPI``), not only ``__file__`` |
| 177 | + """ |
| 178 | + candidates: list[Path] = [] |
| 179 | + override = os.environ.get("RIMAPI_FORK_PATH") |
89 | 180 | if override: |
90 | | - candidate = Path(override) |
91 | | - return candidate if candidate.is_file() else None |
92 | | - return ( |
93 | | - _RIMAPI_DLL_DEFAULT_PATH if _RIMAPI_DLL_DEFAULT_PATH.is_file() else None |
94 | | - ) |
| 181 | + candidates.append(Path(override)) |
| 182 | + sibling = _sibling_rimapi_root() |
| 183 | + if sibling is not None: |
| 184 | + candidates.append(sibling) |
| 185 | + return candidates |
95 | 186 |
|
96 | 187 |
|
97 | 188 | def _rimapi_fork_commit() -> str: |
98 | 189 | """HEAD short SHA of the local RIMAPI fork checkout, if findable. |
99 | 190 |
|
100 | | - Honors $RIMAPI_FORK_PATH; otherwise checks the conventional sibling repo |
101 | | - location (../RIMAPI relative to this RLE checkout). Empty string when the |
102 | | - fork isn't reachable from the runtime environment. |
| 191 | + Honors ``$RIMAPI_FORK_PATH`` and the sibling of the RLE git toplevel. |
| 192 | + Empty string when the fork isn't reachable from the runtime environment. |
103 | 193 | """ |
104 | | - override = os.environ.get("RIMAPI_FORK_PATH") |
105 | | - candidates = [Path(override)] if override else [] |
106 | | - candidates.append(Path(__file__).resolve().parents[3] / "RIMAPI") |
107 | | - for fork_path in candidates: |
108 | | - if (fork_path / ".git").exists(): |
109 | | - try: |
110 | | - return subprocess.check_output( |
111 | | - ["git", "-C", str(fork_path), "rev-parse", "--short", "HEAD"], |
112 | | - stderr=subprocess.DEVNULL, text=True, |
113 | | - ).strip() |
114 | | - except (subprocess.CalledProcessError, FileNotFoundError): |
115 | | - return "" |
| 194 | + for fork_path in _rimapi_fork_candidates(): |
| 195 | + if not (fork_path / ".git").exists(): |
| 196 | + continue |
| 197 | + try: |
| 198 | + return subprocess.check_output( |
| 199 | + ["git", "-C", str(fork_path), "rev-parse", "--short", "HEAD"], |
| 200 | + stderr=subprocess.DEVNULL, |
| 201 | + text=True, |
| 202 | + ).strip() |
| 203 | + except (subprocess.CalledProcessError, FileNotFoundError): |
| 204 | + return "" |
116 | 205 | return "" |
117 | 206 |
|
118 | 207 |
|
|
0 commit comments