From 26338bfa294b03ae4d8af8af89c5cbf5d0ea35da Mon Sep 17 00:00:00 2001 From: gitea-actions Date: Sat, 22 Aug 2026 13:13:41 +0200 Subject: [PATCH 1/2] =?UTF-8?q?Adresy=20a=20data=20podle=20syst=C3=A9mu,?= =?UTF-8?q?=20ne=20podle=20Linuxu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Než začneme rozdávat binárky pro macOS a Windows, musí se na nich chovat rozumně to, co dosud počítalo s Linuxem. Adresy rozhraní se hledaly linuxovým ioctl. Na Windows chybí fcntl, na macOS to číslo znamená něco jiného, takže obojí propadlo až na poslední zálohu přes hostname — a ta na macOS vrátí jednu adresu. Tabule by tam nabídla jedinou volbu, přesně to, co jsme minule opravovali. Přibyla mezizáloha přes ifconfig; spouští se jen tam, kde ioctl nic nenašel, takže na Linuxu se neplatí nic. Parsování je zvlášť jako čistá funkce, ať jde otestovat i bez macOS pod rukama. Databáze z binárky mířila do XDG adresáře na všech systémech. Na Windows by to znamenalo C:\Users\...\.local\share\, což tam nikdo nečeká. Teď se volí podle systému: LOCALAPPDATA, Library/Application Support, XDG. Co-Authored-By: Claude Opus 5 --- net.py | 43 +++++++++++++++++++++++++++++++++++++-- storage.py | 16 ++++++++++++--- tests/test_net.py | 47 +++++++++++++++++++++++++++++++++++++++++++ tests/test_storage.py | 17 ++++++++++++++++ 4 files changed, 118 insertions(+), 5 deletions(-) diff --git a/net.py b/net.py index bc001d6..03ec7e5 100644 --- a/net.py +++ b/net.py @@ -11,7 +11,9 @@ adresy a obecný typ rozhraní, ne to, co má kdo zrovna nainstalované. import ipaddress import os +import re import socket +import subprocess from dataclasses import dataclass # Rozsah, ze kterého adresy přiděluje Tailscale (RFC 6598, CGNAT). @@ -123,8 +125,45 @@ def _from_interfaces() -> list[tuple[str, str]]: return found +def parse_ifconfig(text: str) -> list[tuple[str, str]]: + """Rozhraní a jejich IPv4 adresy z výstupu `ifconfig`. + + Oddělená čistá funkce, ať se dá otestovat i bez macOS pod rukama. + """ + found = [] + name = "" + + for line in text.splitlines(): + head = re.match(r"(\S+):", line) + if head: + name = head.group(1) + continue + + addr = re.search(r"\binet (\d+\.\d+\.\d+\.\d+)", line) + if addr: + found.append((name, addr.group(1))) + + return found + + +def _from_ifconfig() -> list[tuple[str, str]]: + """Adresy přes `ifconfig`. Záloha pro macOS, kde ioctl výše nesedí. + + Spouští se jen tam, kde předchozí cesta nic nenašla, takže na Linuxu + se neplatí nic. Trvá jednotky milisekund, cachovat to nemá cenu. + """ + try: + done = subprocess.run(["ifconfig", "-a"], capture_output=True, + text=True, timeout=5, check=True) + except (OSError, subprocess.SubprocessError): + return [] + + return parse_ifconfig(done.stdout) + + def _from_hostname() -> list[tuple[str, str]]: - """Záloha pro systémy, kde předchozí cesta nefunguje.""" + """Poslední záloha. Na Windows vrátí adresy všech rozhraní, jinde + obvykle jen jednu — jména rozhraní se takhle nedozvíme.""" try: infos = socket.getaddrinfo(socket.gethostname(), None, socket.AF_INET) except OSError: @@ -144,7 +183,7 @@ def addresses() -> list[Address]: primary = default_route_address() - found = _from_interfaces() or _from_hostname() + found = _from_interfaces() or _from_ifconfig() or _from_hostname() if primary and primary not in [ip for _name, ip in found]: found.append(("", primary)) diff --git a/storage.py b/storage.py index 35cce6e..80eca90 100644 --- a/storage.py +++ b/storage.py @@ -16,20 +16,30 @@ from pathlib import Path from core import FINAL_SCORE, Game, Turn +def data_home() -> Path: + """Adresář, kam podle zvyklostí systému patří data aplikací.""" + if sys.platform == "win32": + local = os.environ.get("LOCALAPPDATA") + return Path(local) if local else Path.home() / "AppData" / "Local" + if sys.platform == "darwin": + return Path.home() / "Library" / "Application Support" + return Path(os.environ.get("XDG_DATA_HOME") + or Path.home() / ".local" / "share") + + def default_db() -> Path: """Kam se ukládá databáze. Ze zdrojáků do pracovního adresáře — dá se tak mít víc rozehraných sad vedle sebe a je vidět, s čím se pracuje. Z binárky do datového - adresáře podle XDG: binárka se spouští odkudkoli a rozbaluje se do + adresáře podle systému: binárka se spouští odkudkoli a rozbaluje se do dočasného adresáře, takže relativní cesta by databázi rozsypala po disku. """ chosen = os.environ.get("DICE_DB") if chosen: return Path(chosen) if getattr(sys, "frozen", False): - share = os.environ.get("XDG_DATA_HOME") or Path.home() / ".local" / "share" - return Path(share) / "kostky" / "dice.db" + return data_home() / "kostky" / "dice.db" return Path("dice.db") diff --git a/tests/test_net.py b/tests/test_net.py index 8096162..a326839 100644 --- a/tests/test_net.py +++ b/tests/test_net.py @@ -90,3 +90,50 @@ def test_v_systemu_se_neco_najde(): assert all(net.classify(a.ip, a.interface) for a in found) assert len({a.ip for a in found}) == len(found) + + +IFCONFIG_MACOS = """\ +lo0: flags=8049 mtu 16384 +\toptions=1203 +\tinet 127.0.0.1 netmask 0xff000000 +\tinet6 ::1 prefixlen 128 +gif0: flags=8010 mtu 1280 +en0: flags=8863 mtu 1500 +\tether 3c:22:fb:aa:bb:cc +\tinet6 fe80::14b0:6b1a:9e2f:1a4c%en0 prefixlen 64 secured scopeid 0xb +\tinet 192.168.0.42 netmask 0xffffff00 broadcast 192.168.0.255 +\tmedia: autoselect +\tstatus: active +utun4: flags=8051 mtu 1280 +\tinet 100.99.98.97 --> 100.99.98.97 netmask 0xff000000 +""" + + +def test_ifconfig_vytahne_rozhrani_a_adresy(): + """macOS na ioctl z Linuxu neslyší, tak se čte výstup ifconfigu.""" + assert net.parse_ifconfig(IFCONFIG_MACOS) == [ + ("lo0", "127.0.0.1"), + ("en0", "192.168.0.42"), + ("utun4", "100.99.98.97"), + ] + + +def test_ifconfig_si_neplete_inet6_s_inet(): + """`inet6` začíná stejně jako `inet`; IPv6 adresy tudy projít nesmí.""" + assert net.parse_ifconfig("en0: flags=1\n\tinet6 fe80::1 prefixlen 64\n") == [] + + +def test_adresy_z_ifconfigu_projdou_celym_retezem(monkeypatch): + """Bez linuxového ioctl se sáhne po ifconfigu, teprve pak po hostname.""" + monkeypatch.delenv("DICE_HOST", raising=False) + monkeypatch.setattr(net, "_from_interfaces", lambda: []) + monkeypatch.setattr(net, "_from_ifconfig", + lambda: net.parse_ifconfig(IFCONFIG_MACOS)) + monkeypatch.setattr(net, "_from_hostname", lambda: pytest.fail("moc brzy")) + monkeypatch.setattr(net, "default_route_address", lambda: "192.168.0.42") + + found = net.addresses() + + assert [a.ip for a in found] == ["192.168.0.42", "100.99.98.97"] + assert found[0].primary and found[0].interface == "en0" + assert found[1].kind == "tailnet" diff --git a/tests/test_storage.py b/tests/test_storage.py index 603d8df..a07e2c6 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -148,11 +148,28 @@ def test_umisteni_databaze_z_binarky(monkeypatch, tmp_path): """Binárka se rozbaluje do dočasného adresáře, databáze tam nesmí.""" monkeypatch.delenv("DICE_DB", raising=False) monkeypatch.setattr(storage.sys, "frozen", True, raising=False) + monkeypatch.setattr(storage.sys, "platform", "linux") monkeypatch.setenv("XDG_DATA_HOME", str(tmp_path)) assert storage.default_db() == tmp_path / "kostky" / "dice.db" +def test_data_home_podle_systemu(monkeypatch, tmp_path): + """Každý systém má svůj adresář na data; XDG je jen ten linuxový.""" + monkeypatch.setenv("LOCALAPPDATA", str(tmp_path / "AppData" / "Local")) + monkeypatch.setattr(Path, "home", classmethod(lambda cls: tmp_path)) + + monkeypatch.setattr(storage.sys, "platform", "win32") + assert storage.data_home() == tmp_path / "AppData" / "Local" + + monkeypatch.setattr(storage.sys, "platform", "darwin") + assert storage.data_home() == tmp_path / "Library" / "Application Support" + + monkeypatch.setattr(storage.sys, "platform", "linux") + monkeypatch.delenv("XDG_DATA_HOME", raising=False) + assert storage.data_home() == tmp_path / ".local" / "share" + + def test_dice_db_prebije_oboje(monkeypatch, tmp_path): monkeypatch.setattr(storage.sys, "frozen", True, raising=False) monkeypatch.setenv("DICE_DB", str(tmp_path / "jinde.db")) -- 2.47.3 From a7621bb01badaf0cfd3b469dfdabe3e483afbf7d Mon Sep 17 00:00:00 2001 From: gitea-actions Date: Sat, 22 Aug 2026 13:13:57 +0200 Subject: [PATCH 2/2] =?UTF-8?q?Bin=C3=A1rky=20pro=20Windows=20a=20macOS=20?= =?UTF-8?q?p=C5=99es=20GitHub=20Actions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PyInstaller neumí křížovou kompilaci — binárku pro každý systém musí postavit ten systém. Vlastní runner pro Windows a hlavně pro macOS by byl nepoměr, tak si tyhle stroje půjčujeme od GitHub Actions. GitHub je jen půjčená dílna, ne druhý domov projektu: repozitář se tam z Gitey zrcadlí, hotové soubory se posílají zpátky na zdejší release přes Gitea API a stránka s releasy zůstává jedna. Linux se tam schválně nestaví; doma to jde proti glibc 2.17 a je to zároveň pojistka, kdyby GitHub vypadl. build.sh je společný pro všechny tři systémy, liší se jen tím, že Windows dává spustitelné soubory venvu do Scripts/ místo bin/. Ořezání symbolů zůstává jen Linuxu: na macOS by rozbilo podpis, který si PyInstaller sám přidává a bez kterého se binárka na Apple Silicon vůbec nespustí. Zkouška po stavbě je stejná jako u linuxové: nastartovat, stáhnout si stránku i styly a ověřit, že se založila databáze. Nepodepsané binárky si Gatekeeper ani SmartScreen nenechají líbit, tak je v README napsané, co s tím — certifikáty za tisíce ročně by na počitadlo kostek byly nesmysl. Co-Authored-By: Claude Opus 5 --- .github/workflows/binarky.yml | 124 ++++++++++++++++++++++++++++++++++ README.md | 83 ++++++++++++++++++----- build.sh | 31 ++++++--- kostky.spec | 7 +- 4 files changed, 219 insertions(+), 26 deletions(-) create mode 100644 .github/workflows/binarky.yml diff --git a/.github/workflows/binarky.yml b/.github/workflows/binarky.yml new file mode 100644 index 0000000..cfa479e --- /dev/null +++ b/.github/workflows/binarky.yml @@ -0,0 +1,124 @@ +# Binárky pro Windows a macOS. +# +# PyInstaller neumí křížovou kompilaci: binárku pro každý systém musí postavit +# ten systém. Kupovat kvůli tomu Mac nebo krmit Windows VM by bylo přehnané, +# tak si tyhle stroje půjčujeme od GitHub Actions. +# +# GitHub je tu jen půjčená dílna, ne druhý domov projektu: repozitář se sem +# z Gitey zrcadlí a hotové soubory se posílají zpátky na tamní release přes +# Gitea API. Jedna stránka s releasy, ta původní. +# +# Linux se tu schválně nestaví — o ten se stará vlastní runner +# (.gitea/workflows/binarka.yml) a dělá to líp, proti glibc 2.17. +name: binárky + +on: + push: + branches: [main] + tags: ["v*"] + workflow_dispatch: + +env: + GITEA: https://gitea.spacilovi.eu + GITEA_REPO: david-spacil/dice-counter + +jobs: + build: + strategy: + fail-fast: false + matrix: + include: + - os: windows-latest + asset: kostky-windows-x86_64.exe + built: dist/kostky.exe + - os: macos-13 # poslední Intel běhoun + asset: kostky-macos-x86_64 + built: dist/kostky + - os: macos-latest # Apple Silicon + asset: kostky-macos-arm64 + built: dist/kostky + + runs-on: ${{ matrix.os }} + defaults: + run: + shell: bash + + steps: + - uses: actions/checkout@v7 + + - uses: astral-sh/setup-uv@v10 + + - name: Testy + run: uv run --with-requirements requirements.txt --no-project pytest -q + + - name: Binárka + run: ./build.sh + + - name: Zkouška + run: | + # Binárka se musí umět rozbalit, najít šablony a začít poslouchat. + # Adresa se vnucuje, ať zkouška nezávisí na síti běhounu. + export DICE_HOST=127.0.0.1 DICE_PORT=8123 DICE_DB=zkouska/dice.db + "${{ matrix.built }}" & + + for _ in $(seq 30); do + curl -sf -o /dev/null "http://127.0.0.1:8123/" && break + sleep 1 + done + + curl -sf -o /dev/null "http://127.0.0.1:8123/" || { + echo "Server se nerozeběhl." >&2; exit 1; } + curl -sf -o /dev/null "http://127.0.0.1:8123/static/style.css" + curl -sf "http://127.0.0.1:8123/board" | grep -q "127.0.0.1:8123" + test -f zkouska/dice.db + + echo "Binárka jede." + + - name: Na release + if: startsWith(github.ref, 'refs/tags/') + env: + TOKEN: ${{ secrets.GITEA_TOKEN }} + ASSET: ${{ matrix.asset }} + run: | + api="$GITEA/api/v1/repos/$GITEA_REPO" + auth="Authorization: token $TOKEN" + json() { uv run --no-project python -c "$@"; } + + # Release u tagu být může, ale nemusí — dá se založit i ručně a + # sahají na něj čtyři buildy naráz, tak se po neúspěchu ptáme znovu. + for _ in 1 2 3; do + id=$(curl -s -H "$auth" "$api/releases/tags/${GITHUB_REF_NAME}" \ + | json 'import json,sys; print(json.load(sys.stdin).get("id",""))') + [ -n "$id" ] && break + + curl -s -o /dev/null -X POST -H "$auth" -H "Content-Type: application/json" \ + -d "{\"tag_name\":\"${GITHUB_REF_NAME}\",\"name\":\"${GITHUB_REF_NAME}\"}" \ + "$api/releases" + done + [ -n "$id" ] || { echo "Release ${GITHUB_REF_NAME} se nepodařilo najít." >&2; exit 1; } + + # macOS zná jen shasum, Git Bash na Windows jen sha256sum. Formát + # výsledku je stejný, takže se dá ověřit kterýmkoli z nich. + if command -v sha256sum >/dev/null; then + soucet() { sha256sum "$@"; } + else + soucet() { shasum -a 256 "$@"; } + fi + + # Součet se počítá nad jménem, pod kterým se soubor stahuje, aby + # šel ověřit rovnou: shasum -a 256 -c kostky-macos-arm64.sha256 + cp "${{ matrix.built }}" "$ASSET" + soucet "$ASSET" | tee "$ASSET.sha256" + + for file in "$ASSET" "$ASSET.sha256"; do + # Aby se dal build zopakovat, stará příloha stejného jména jde pryč. + curl -s -H "$auth" "$api/releases/$id/assets" \ + | json 'import json,sys; [print(a["id"]) for a in json.load(sys.stdin) if a["name"] == sys.argv[1]]' "$file" \ + | while read -r old; do + curl -sf -X DELETE -H "$auth" "$api/releases/$id/assets/$old" + done + + curl -sf -o /dev/null -X POST -H "$auth" -F "attachment=@$file" \ + "$api/releases/$id/assets?name=$file" + echo "$file pověšen na ${GITHUB_REF_NAME}" + done diff --git a/README.md b/README.md index 9a0b596..7af5121 100644 --- a/README.md +++ b/README.md @@ -8,16 +8,45 @@ ten samý Adam jako z minulého měsíce. Žádné účty, žádná hesla. ## Spuštění -Stáhni binárku z [releases](https://gitea.spacilovi.eu/david-spacil/dice-counter/releases) -a spusť ji: +Stáhni binárku pro svůj systém z +[releases](https://gitea.spacilovi.eu/david-spacil/dice-counter/releases): + +| Systém | Soubor | +|---|---| +| Linux (x86-64) | `kostky-linux-x86_64` | +| macOS (Apple Silicon) | `kostky-macos-arm64` | +| macOS (Intel) | `kostky-macos-x86_64` | +| Windows (x86-64) | `kostky-windows-x86_64.exe` | + +Nic se neinstaluje — Python, Flask i šablony jsou uvnitř. + +Na Linuxu a macOS: ```bash -chmod +x kostky -./kostky +chmod +x kostky-* +./kostky-linux-x86_64 ``` -Nic se neinstaluje — Python, Flask i šablony jsou uvnitř. Zatím jen pro Linux -na x86-64; postavené proti glibc 2.17, takže jede prakticky všude. +Na Windows stačí na `.exe` poklepat. + +Linuxová binárka je postavená proti glibc 2.17, takže jede prakticky všude. + +### Než to poprvé pustíš + +Binárky nejsou podepsané — podpisové certifikáty stojí tisíce ročně a na +počitadlo kostek by to byl nesmysl. Systémy si toho všimnou: + +- **macOS** stažený soubor označí za karanténní a odmítne ho spustit. Buď + značku sundej (`xattr -dr com.apple.quarantine kostky-macos-arm64`), nebo + soubor stáhni rovnou z terminálu přes `curl -LO` — tudy se karanténa + nenastavuje. +- **Windows** ukáže modré okno SmartScreenu. *Další informace* → + *Přesto spustit*. Občas si postěžuje i antivirus; u zabalených Python + programů je to běžný falešný poplach. Při prvním spuštění se ještě zeptá + brána firewall — bez povolení do místní sítě se telefon nepřipojí. + +Kdo tomu nechce věřit, ověří si stažený soubor podle přiloženého součtu +(níž) nebo si ho postaví sám — `./build.sh`, zdrojáky jsou tady celé. Ze zdrojáků to je stejně krátké: @@ -53,7 +82,9 @@ server vypíše při startu. | Spuštěno | Databáze | |---|---| -| binárkou | `~/.local/share/kostky/dice.db` | +| binárkou na Linuxu | `~/.local/share/kostky/dice.db` | +| binárkou na macOS | `~/Library/Application Support/kostky/dice.db` | +| binárkou na Windows | `%LOCALAPPDATA%\kostky\dice.db` | | ze zdrojáků | `dice.db` v pracovním adresáři | Binárka se při každém spuštění rozbaluje do dočasného adresáře a pouští se @@ -101,6 +132,8 @@ při remíze na prvním místě se hraje dál. | `web.py` | Flask aplikace | | `dice.py` | totéž v terminálu, bez ukládání | | `build.sh`, `kostky.spec` | stavba binárky | +| `.gitea/workflows/` | testy a linuxová binárka doma | +| `.github/workflows/` | binárky pro Windows a macOS | Terminálová verze zůstává funkční jako záloha: @@ -135,26 +168,44 @@ Staví se proti samostatnému CPythonu od `uv`, ne proti systémovému. Ten je slinkovaný s glibc 2.17; postavené proti Pythonu z Fedory 44 by to chtělo glibc 2.43 a nešlo by spustit skoro nikde — glibc drží zpětnou kompatibilitu, ne dopřednou. Nic z hostitele se do binárky nedostane, takže kontejner k tomu -potřeba není. Výsledek je v `dist/kostky`. +potřeba není. Výsledek je v `dist/`. + +Stejný `build.sh` staví i na macOS a na Windows (v Git Bash) — jen tam bez +té starosti o glibc. Křížem to nejde: PyInstaller balí do výsledku interpret +a knihovny toho systému, na kterém běží, takže **binárku pro každý systém +musí postavit ten systém.** Terminálová verze součástí binárky není; ta se pouští ze zdrojáků. -Releasy si tohle dělají samy. Otagovaný commit spustí -`.gitea/workflows/binarka.yml`, ta binárku postaví, projede testy, zkusí -ji nastartovat a pověsí ji na release jako `kostky-linux-x86_64`: +### Jak vznikají releasy + +Otagovaný commit spustí stavbu na obou stranách: + +| Kde | Co staví | Workflow | +|---|---|---| +| vlastní runner u Gitey | Linux | `.gitea/workflows/binarka.yml` | +| GitHub Actions | Windows, macOS ×2 | `.github/workflows/binarky.yml` | ```bash git tag v1.0.0 && git push origin v1.0.0 ``` -Vedle binárky se věší i `kostky-linux-x86_64.sha256`, takže se stažený -soubor dá ověřit: +GitHub je tu jen půjčená dílna. Repozitář se tam z Gitey zrcadlí +([mirror](https://github.com/david-spacil/dice-counter)), postavené soubory +se posílají zpátky na zdejší release přes Gitea API a projekt má pořád jednu +stránku s releasy — tuhle. Linux se na GitHubu schválně nestaví; doma to jde +proti staré glibc, a když GitHub vypadne, release má aspoň tu platformu, +na které to reálně poběží. + +Každá stavba nejdřív projede testy a zkusí hotovou binárku nastartovat, než +ji kamkoli pověsí. Vedle každé visí i `.sha256`, takže se stažený soubor dá +ověřit: ```bash -sha256sum -c kostky-linux-x86_64.sha256 +sha256sum -c kostky-linux-x86_64.sha256 # na macOS: shasum -a 256 -c ``` -Stejná stavba běží i nad každým pull requestem, jen se nikam nevěší. +Nad pull requesty se Linux staví taky, jen se nikam nevěší. ## Testy @@ -165,5 +216,5 @@ uv run --with-requirements requirements.txt --no-project pytest Nebo z připraveného prostředí prostě `pytest`. Nad každým pull requestem a nad `main` běží `.gitea/workflows/testy.yml` — -84 testů na Pythonu 3.11, 3.12, 3.13 i 3.14, a k tomu skriptovaná partie +99 testů na Pythonu 3.11, 3.12, 3.13 i 3.14, a k tomu skriptovaná partie v terminálové verzi, na kterou pytest nesahá. diff --git a/build.sh b/build.sh index ea0f553..ee0cf48 100755 --- a/build.sh +++ b/build.sh @@ -1,11 +1,15 @@ #!/usr/bin/env bash -# Postaví jednosouborovou binárku pro Linux do dist/kostky. +# Postaví jednosouborovou binárku do dist/ — pro systém, na kterém běží. # -# Staví se proti samostatnému CPythonu od uv, ne proti systémovému. Ten je -# slinkovaný s glibc 2.17, takže binárka jede i na letitých systémech. -# Postavená proti Pythonu z Fedory 44 by chtěla glibc 2.43 a nešla by -# spustit skoro nikde — glibc drží zpětnou kompatibilitu, ne dopřednou. -# Nic z hostitele se do ní nedostane, takže kontejner k tomu není potřeba. +# PyInstaller neumí křížovou kompilaci: binárku pro každý systém musí postavit +# ten systém. Linux se staví doma na vlastním runneru, Windows a macOS na +# půjčených strojích GitHub Actions (.github/workflows/binarky.yml). +# +# Staví se proti samostatnému CPythonu od uv, ne proti systémovému. Na Linuxu +# je slinkovaný s glibc 2.17, takže binárka jede i na letitých systémech. +# Postavená proti Pythonu z Fedory 44 by chtěla glibc 2.43 a nešla by spustit +# skoro nikde — glibc drží zpětnou kompatibilitu, ne dopřednou. Nic z hostitele +# se do ní nedostane, takže kontejner k tomu není potřeba. set -euo pipefail VERSION=${VERSION:-3.11} @@ -13,10 +17,19 @@ BUILD=${BUILD:-.build} uv python install "$VERSION" uv venv --quiet --managed-python --python "$VERSION" "$BUILD" -uv pip install --quiet --python "$BUILD/bin/python" -r requirements.txt pyinstaller -"$BUILD/bin/pyinstaller" --clean --noconfirm \ +# Windows dává spustitelné soubory venvu do Scripts/, zbytek světa do bin/. +python="$BUILD/bin/python" +pyinstaller="$BUILD/bin/pyinstaller" +if [ -d "$BUILD/Scripts" ]; then + python="$BUILD/Scripts/python.exe" + pyinstaller="$BUILD/Scripts/pyinstaller.exe" +fi + +uv pip install --quiet --python "$python" -r requirements.txt pyinstaller + +"$pyinstaller" --clean --noconfirm \ --distpath dist --workpath "$BUILD/work" kostky.spec echo -ls -lh dist/kostky +ls -lh dist/ diff --git a/kostky.spec b/kostky.spec index 857bd78..68164e8 100644 --- a/kostky.spec +++ b/kostky.spec @@ -5,6 +5,8 @@ Staví se přes `./build.sh`, ne ručně — ta se stará o to, aby výsledek je i na starších systémech, než je ten tvůj. """ +import sys + analysis = Analysis( ["web.py"], pathex=["."], @@ -21,6 +23,9 @@ exe = EXE( analysis.datas, name="kostky", console=True, - strip=True, + # Ořezání symbolů šetří pár megabajtů, ale jen na Linuxu. Na macOS by + # rozbilo podpis, který si PyInstaller sám přidává a bez kterého se + # binárka na Apple Silicon vůbec nespustí; na Windows nedělá nic. + strip=sys.platform == "linux", upx=False, ) -- 2.47.3