Skip to content

Commit 0af58ff

Browse files
update ci
1 parent 1aa5a73 commit 0af58ff

1 file changed

Lines changed: 126 additions & 23 deletions

File tree

.github/workflows/release-binaries.yml

Lines changed: 126 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,13 @@ jobs:
2828
print(f"tag=v{v}")
2929
PY
3030
31-
- uses: softprops/action-gh-release@v2
31+
- name: Create GitHub release
32+
uses: softprops/action-gh-release@v2
3233
with:
3334
tag_name: ${{ steps.meta.outputs.tag }}
3435
name: ${{ steps.meta.outputs.tag }}
36+
draft: false
37+
prerelease: false
3538

3639
build:
3740
needs: metadata
@@ -42,43 +45,121 @@ jobs:
4245
include:
4346
- os: ubuntu-latest
4447
platform: linux-x86_64
45-
exe: bangen
48+
extra_build_flags: --clang
49+
4650
- os: macos-latest
4751
platform: macos-universal2
48-
exe: bangen
52+
extra_build_flags: --clang --macos-target-arch=universal
53+
4954
- os: windows-latest
5055
platform: windows-x86_64
51-
exe: bangen.exe
56+
extra_build_flags: ""
5257

5358
steps:
5459
- uses: actions/checkout@v4
5560

5661
- uses: actions/setup-python@v5
5762
with:
5863
python-version: "3.11"
59-
cache: "pip"
64+
# No cache: pip — we cache the entire installed env in Layer 1,
65+
# which is strictly better (zero pip activity on a cache hit).
66+
67+
# ── Layer 1: installed Python environment ────────────────────────────
68+
# Caches the full Python + site-packages directory. On a hit, pip is
69+
# never invoked at all. Keyed on pyproject.toml only — bangen itself
70+
# is installed with -e (editable) so source changes are always live
71+
# without busting this cache.
72+
- name: Cache pip environment
73+
id: pip-cache
74+
uses: actions/cache@v4
75+
with:
76+
path: ${{ env.pythonLocation }}
77+
key: pip-env-${{ runner.os }}-py3.11-${{ hashFiles('pyproject.toml') }}
78+
# Intentionally no restore-keys: a partial env restore causes subtle
79+
# import errors that are harder to debug than a clean install.
6080

61-
# 🔥 Cache Nuitka + compiler artifacts
62-
- name: Cache Nuitka + compiler
81+
- name: Install dependencies
82+
if: steps.pip-cache.outputs.cache-hit != 'true'
83+
run: |
84+
python -m pip install --upgrade pip
85+
pip install -e . nuitka
86+
87+
# ── Layer 2: sccache (C compiler output cache) ───────────────────────
88+
# Nuitka translates Python → C, then compiles the C with clang/MSVC.
89+
# sccache caches the compiled C object files keyed on content hash,
90+
# so unchanged modules are never recompiled.
91+
#
92+
# Linux / macOS: we shim the clang binary so every compiler call Nuitka
93+
# makes goes through sccache transparently. The shim must land before
94+
# /usr/bin in PATH — /usr/local/bin satisfies this on both runners.
95+
#
96+
# Windows: Nuitka calls cl.exe (MSVC) through its own Scons backend in
97+
# a way that cannot be intercepted with a shim. Layer 3 carries Windows.
98+
- uses: mozilla-actions/sccache-action@v0.0.5
99+
100+
- name: Configure sccache
101+
shell: bash
102+
run: |
103+
echo "SCCACHE_GHA_ENABLED=true" >> "$GITHUB_ENV"
104+
echo "SCCACHE_CACHE_SIZE=2G" >> "$GITHUB_ENV"
105+
106+
if [ "${{ runner.os }}" = "Linux" ]; then
107+
REAL_CLANG="$(which clang)"
108+
REAL_CLANGXX="$(which clang++)"
109+
printf '#!/bin/sh\nexec sccache %s "$@"\n' "$REAL_CLANG" | sudo tee /usr/local/bin/clang > /dev/null
110+
printf '#!/bin/sh\nexec sccache %s "$@"\n' "$REAL_CLANGXX" | sudo tee /usr/local/bin/clang++ > /dev/null
111+
sudo chmod +x /usr/local/bin/clang /usr/local/bin/clang++
112+
113+
elif [ "${{ runner.os }}" = "macOS" ]; then
114+
REAL_CLANG="$(xcrun -f clang)"
115+
REAL_CLANGXX="$(xcrun -f clang++)"
116+
printf '#!/bin/sh\nexec sccache %s "$@"\n' "$REAL_CLANG" | sudo tee /usr/local/bin/clang > /dev/null
117+
printf '#!/bin/sh\nexec sccache %s "$@"\n' "$REAL_CLANGXX" | sudo tee /usr/local/bin/clang++ > /dev/null
118+
sudo chmod +x /usr/local/bin/clang /usr/local/bin/clang++
119+
fi
120+
121+
# ── Layer 3: Nuitka bytecode + download cache ─────────────────────────
122+
# Caches two things inside Nuitka's cache dir:
123+
# • Python→C translation results (expensive, source-sensitive)
124+
# • Onefile bootstrap downloads (AppImage on Linux, etc. — one-time)
125+
#
126+
# Three-tier restore-key cascade:
127+
# 1. Exact hit — source + deps unchanged, fully warm
128+
# 2. Deps hit — only deps unchanged; translation cache partially warm
129+
# 3. OS hit — bootstrap downloads reused; compilation starts cold
130+
- name: Set Nuitka cache dir
131+
shell: bash
132+
run: |
133+
if [ "${{ runner.os }}" = "Windows" ]; then
134+
echo "NUITKA_CACHE_DIR=${LOCALAPPDATA}/Nuitka" >> "$GITHUB_ENV"
135+
else
136+
echo "NUITKA_CACHE_DIR=${HOME}/.cache/Nuitka" >> "$GITHUB_ENV"
137+
fi
138+
139+
- name: Cache Nuitka artifacts
63140
uses: actions/cache@v4
64141
with:
65142
path: |
66143
~/.cache/Nuitka
67-
~/.ccache
68144
~/AppData/Local/Nuitka
69-
~/AppData/Local/ccache
70-
key: nuitka-${{ runner.os }}-3.11-${{ hashFiles('pyproject.toml', 'bangen/**/*.py') }}
145+
key: >-
146+
nuitka-${{ runner.os }}-py3.11-
147+
${{ hashFiles('pyproject.toml') }}-
148+
${{ hashFiles('bangen/**/*.py', '_entry.py') }}
71149
restore-keys: |
72-
nuitka-${{ runner.os }}-3.11-
150+
nuitka-${{ runner.os }}-py3.11-${{ hashFiles('pyproject.toml') }}-
151+
nuitka-${{ runner.os }}-py3.11-
73152
74-
- name: Install dependencies
75-
run: |
76-
python -m pip install --upgrade pip
77-
pip install . "nuitka[onefile]"
153+
# ─────────────────────────────────────────────────────────────────────
78154

79-
# Ensure Nuitka uses cache path
80-
- name: Set Nuitka cache dir
81-
run: echo "NUITKA_CACHE_DIR=$HOME/.cache/Nuitka" >> $GITHUB_ENV
155+
- name: Generate entry script
156+
shell: bash
157+
run: |
158+
cat > _entry.py << 'EOF'
159+
from bangen.app import main
160+
if __name__ == "__main__":
161+
main()
162+
EOF
82163
83164
- name: Build (Nuitka onefile optimized)
84165
shell: bash
@@ -89,14 +170,34 @@ jobs:
89170
--output-dir=build \
90171
--output-filename=bangen \
91172
--follow-imports \
173+
\
174+
--include-package=bangen \
175+
\
176+
--include-package=rich \
177+
--include-package-data=rich \
178+
\
179+
--include-package=pyfiglet \
180+
--include-package-data=pyfiglet \
181+
\
182+
--include-package=PIL \
183+
\
184+
--include-package=typer \
185+
--include-package=click \
186+
\
187+
--nofollow-import-to=tkinter \
188+
--nofollow-import-to=unittest \
189+
--nofollow-import-to=test \
190+
--nofollow-import-to=distutils \
191+
--nofollow-import-to=setuptools \
192+
--nofollow-import-to=pkg_resources \
193+
\
92194
--lto=yes \
93-
--jobs=2 \
94195
--python-flag=no_asserts \
95196
--python-flag=no_docstrings \
96197
--python-flag=isolated \
97198
--onefile-tempdir-spec="{CACHE_DIR}/bangen/${{ needs.metadata.outputs.version }}" \
98-
--clang \
99-
bangen/__main__.py
199+
${{ matrix.extra_build_flags }} \
200+
_entry.py
100201
101202
- name: Prepare release asset
102203
shell: bash
@@ -105,13 +206,15 @@ jobs:
105206
106207
if [ "${{ runner.os }}" = "Windows" ]; then
107208
BIN="build/bangen.exe"
209+
EXT=".exe"
108210
else
109211
BIN="build/bangen"
212+
EXT=""
110213
chmod +x "$BIN"
111214
fi
112215
113216
cp "$BIN" \
114-
"release-assets/bangen-${{ needs.metadata.outputs.tag }}-${{ matrix.platform }}"
217+
"release-assets/bangen-${{ needs.metadata.outputs.tag }}-${{ matrix.platform }}${EXT}"
115218
116219
- name: Upload artifact
117220
uses: actions/upload-artifact@v4
@@ -123,4 +226,4 @@ jobs:
123226
uses: softprops/action-gh-release@v2
124227
with:
125228
tag_name: ${{ needs.metadata.outputs.tag }}
126-
files: release-assets/*
229+
files: release-assets/*

0 commit comments

Comments
 (0)