feat: enhance compatibility table with file name handling and UI updates

This commit is contained in:
Patryk Gensch
2026-06-19 00:07:18 +02:00
parent 2c785dc87c
commit 429aafb6ce
4 changed files with 39 additions and 5 deletions

View File

@@ -219,7 +219,9 @@ która gra wiezie którą bibliotekę. Haczyk: ta sama nazwa może wystąpić w
nie być tym samym silnikiem. Dlatego w obrębie jednej nazwy klastrujemy **warianty po powierzchni nie być tym samym silnikiem. Dlatego w obrębie jednej nazwy klastrujemy **warianty po powierzchni
silnika** (te same zbiory tożsamości co `diff`/`similarity` — kompilator-agnostyczne), a każdy silnika** (te same zbiory tożsamości co `diff`/`similarity` — kompilator-agnostyczne), a każdy
wariant inny niż referencyjny (`A`) dostaje **gwiazdkę** `*` z deltą *czym* się różni. Byte-różnice wariant inny niż referencyjny (`A`) dostaje **gwiazdkę** `*` z deltą *czym* się różni. Byte-różnice
z rekompilacji nie generują gwiazdki — liczy się API skryptowe. z rekompilacji nie generują gwiazdki — liczy się API skryptowe. Prefiks `<sha8>_` doklejany do
nazwy pliku przy składowaniu (np. `333ab0c4_PIKLIB8.dll`) jest **obcinany przed grupowaniem**, więc
wszystkie kopie `PIKLIB8.dll` lądują w jednym wierszu (pełna nazwa pliku zostaje w polu `file` JSON-a).
```bash ```bash
# z plików snapshot (bez DB/serwera); Label= ustawia kolumnę-grę # z plików snapshot (bez DB/serwera); Label= ustawia kolumnę-grę
@@ -236,7 +238,7 @@ curl -OJ "http://127.0.0.1:8000/compat?format=md" # → compat.md
curl -OJ "http://127.0.0.1:8000/compat?format=json" # → compat.json (grupy + warianty + diffy) curl -OJ "http://127.0.0.1:8000/compat?format=json" # → compat.json (grupy + warianty + diffy)
``` ```
W UI: przycisk **kompat** w panelu *Gry / wersje*. Markdown to macierz `biblioteka × gra` W UI: przyciski **md** / **⬇ json** w panelu *Gry / wersje*. Markdown to macierz `biblioteka × gra`
(`✓` = obecna; `A`/`B*`/… gdy nazwa ma kilka wariantów powierzchni) plus sekcja *Warianty* z (`✓` = obecna; `A`/`B*`/… gdy nazwa ma kilka wariantów powierzchni) plus sekcja *Warianty* z
przypisem: dla każdego rozbieżnego wariantu overlap % i `types/methods/events/fields +N/-N/~N` przypisem: dla każdego rozbieżnego wariantu overlap % i `types/methods/events/fields +N/-N/~N`
względem referencyjnego. względem referencyjnego.

View File

@@ -17,8 +17,10 @@
<div class="panel-title"> <div class="panel-title">
Gry / wersje Gry / wersje
<span class="panel-actions"> <span class="panel-actions">
<a id="dl-compat" class="mini-btn" href="/compat?format=md" download="compat.md" <a id="dl-compat-md" class="mini-btn" href="/compat?format=md" download="compat.md"
title="Pobierz tablicę kompatybilności (Markdown) — grupowaną po nazwie biblioteki">kompat</a> title="Tablica kompatybilności Markdown (grupowana po nazwie biblioteki)">md</a>
<a id="dl-compat-json" class="mini-btn" href="/compat?format=json" download="compat.json"
title="Tablica kompatybilności — JSON (grupy + warianty + diffy)">⬇ json</a>
<button id="upload-toggle" class="mini-btn" title="Wgraj grę (ISO / ZIP / DLL)">+ wgraj</button> <button id="upload-toggle" class="mini-btn" title="Wgraj grę (ISO / ZIP / DLL)">+ wgraj</button>
</span> </span>
</div> </div>

View File

@@ -17,6 +17,7 @@ from __future__ import annotations
import hashlib import hashlib
import json import json
import re
from collections import Counter from collections import Counter
from dataclasses import dataclass from dataclasses import dataclass
from datetime import datetime, timezone from datetime import datetime, timezone
@@ -77,8 +78,19 @@ def _vs_reference(reference: Snapshot, variant: Snapshot) -> dict[str, Any]:
# --- table builder ----------------------------------------------------------------------------- # --- table builder -----------------------------------------------------------------------------
# Stored binaries are prefixed with the first 8 hex of their sha256 to keep filenames unique on
# disk (e.g. ``333ab0c4_PIKLIB8.dll``). That prefix is per-file, so it must be stripped before
# grouping — otherwise every copy of PIKLIB8.dll lands in its own row and nothing ever clusters.
_HASH_PREFIX = re.compile(r"^[0-9a-fA-F]{8}_")
def library_name(raw: str) -> str:
"""The display/grouping name: the stored binary name with any ``<sha8>_`` prefix removed."""
return _HASH_PREFIX.sub("", raw)
def _library_name(snap: Snapshot) -> str: def _library_name(snap: Snapshot) -> str:
return snap.binary.get("name") or "?" return library_name(snap.binary.get("name") or "?")
def _variant_id(index: int) -> str: def _variant_id(index: int) -> str:
@@ -115,6 +127,7 @@ def _build_library(name: str, entries: list[Entry]) -> dict[str, Any]:
members = [ members = [
{ {
"game": e.game, "game": e.game,
"file": e.snapshot.binary.get("name"), # stored name, incl. the <sha8>_ prefix
"engine": e.snapshot.binary.get("engine"), "engine": e.snapshot.binary.get("engine"),
"compiler": e.snapshot.binary.get("compiler"), "compiler": e.snapshot.binary.get("compiler"),
"sha256": e.snapshot.binary.get("sha256"), "sha256": e.snapshot.binary.get("sha256"),

View File

@@ -77,6 +77,23 @@ def test_divergent_surface_raises_asterisk():
assert lib["cells"]["Game C"]["diverges"] is True assert lib["cells"]["Game C"]["diverges"] is True
def test_hash_prefix_is_stripped_for_grouping():
# stored names carry a per-file <sha8>_ prefix; copies must still group under one library row
t = compatibility_table([
Entry("Game A", _snap("333ab0c4_PIKLIB8.dll", ["SHOW", "HIDE"])),
Entry("Game B", _snap("8dc0165d_PIKLIB8.dll", ["SHOW", "HIDE"])),
Entry("Game C", _snap("bba62d83_PIKLIB8.dll", ["SHOW", "HIDE", "PAUSE"])),
])
assert len(t["libraries"]) == 1
lib = t["libraries"][0]
assert lib["name"] == "PIKLIB8.dll" # prefix gone from the display name
assert lib["variant_count"] == 2 # A,B identical → reference; C diverges → asterisk
assert lib["cells"]["Game C"]["diverges"] is True
# the original stored filename is preserved per member for correlation
files = {m["file"] for v in lib["variants"] for m in v["members"]}
assert "333ab0c4_PIKLIB8.dll" in files
def test_grouping_is_case_insensitive_keeps_common_spelling(): def test_grouping_is_case_insensitive_keeps_common_spelling():
t = compatibility_table([ t = compatibility_table([
Entry("Game A", _snap("Piklib8.dll", ["SHOW"])), Entry("Game A", _snap("Piklib8.dll", ["SHOW"])),