wolf: fix ES-DE GitLab AppImage download resolving no URL

Two compounding bugs in _wolf_download_emulator_appimage_gitlab() made
the ES-DE AppImage download always fail with "Could not resolve
download URL", confirmed live against the real GitLab API:

1. The asset filter checked url.endswith(".AppImage"), but GitLab's own
   release-asset URL is an opaque .../package_files/<id>/download link
   with no filename in it at all — only the asset's own "name" field
   (e.g. "ES-DE_x64.AppImage") carries the real filename. Filtering on
   the URL suffix matched nothing, even though the latest ES-DE release
   genuinely ships x64/aarch64/SteamDeck AppImage assets.

2. Even with the URL resolved, the download target was built as
   $dir/$(basename "$_url"), which for that same opaque URL evaluates
   to just "download" instead of the real filename — breaking every
   downstream step that looks for a *.AppImage file (the ES-DE.AppImage
   symlink creation, and the "already downloaded" idempotency check on
   a later rerun).

Fixed by filtering on the asset's own "name" field and threading that
name through (tab-separated from the URL) to use as the actual saved
filename. Verified end-to-end against the live GitLab API: resolves to
ES-DE_x64.AppImage and downloads a real, correctly-arched ELF binary.

(Also had to drop an f-string in the same python snippet — pre-3.12
Python disallows a backslash inside an f-string's {} expression, and
separately this whole snippet is wrapped in a bash single-quoted
string, so it can't contain single quotes at all either. Plain string
concatenation avoids both constraints.)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013BWYKEERLA1a7gv86Z4W23
This commit is contained in:
Claude
2026-09-10 03:16:27 +00:00
parent 92e9ee19a7
commit 750c55a4d4
+26 -4
View File
@@ -328,21 +328,43 @@ releases = sorted(releases, key=lambda r: r.get("released_at") or "", reverse=Tr
assets = [] assets = []
for r in releases: for r in releases:
for link in r.get("assets", {}).get("links", []): for link in r.get("assets", {}).get("links", []):
# The GitLab asset URL itself is an opaque .../package_files/<id>/download
# link with no filename/extension in it at all — confirmed live: only
# the link own "name" field carries the real filename
# (e.g. "ES-DE_x64.AppImage"), so filtering on the URL suffix (as
# this used to) matches nothing and silently fails with no
# resolvable download, even though the release genuinely has an
# AppImage asset sitting right there.
name = link.get("name", "")
url = link.get("direct_asset_url") or link.get("url") or "" url = link.get("direct_asset_url") or link.get("url") or ""
if url.endswith(".AppImage"): if name.endswith(".AppImage"):
assets.append({"name": link.get("name", url), "browser_download_url": url}) assets.append({"name": name, "browser_download_url": url})
if assets: if assets:
break break
matching = [a for a in assets if arch_tags and has(a["name"], arch_tags)] matching = [a for a in assets if arch_tags and has(a["name"], arch_tags)]
untagged = [a for a in assets if not has(a["name"], all_arch_tags)] untagged = [a for a in assets if not has(a["name"], all_arch_tags)]
pick = matching or untagged or assets pick = matching or untagged or assets
print(pick[0]["browser_download_url"] if pick else "") # No f-string here on purpose: this whole script is wrapped in a bash
# single-quoted string (see the "python3 -c" call above it), so a single
# quote anywhere in this code — the way an f-string would normally quote
# a dict key — would terminate that bash string early. Plain
# concatenation with double-quoted literals sidesteps that entirely.
print(pick[0]["browser_download_url"] + "\t" + pick[0]["name"] if pick else "")
' 2>/dev/null) ' 2>/dev/null)
if [[ -z "$_url" ]]; then if [[ -z "$_url" ]]; then
log_warning "Could not resolve download URL — get it manually from https://gitlab.com/${_project_path}/-/releases" log_warning "Could not resolve download URL — get it manually from https://gitlab.com/${_project_path}/-/releases"
return 1 return 1
fi fi
local _file="$_dir/$(basename "$_url")" # The URL and the real filename are two different things here — GitLab's
# own asset URL is an opaque .../package_files/<id>/download link with no
# filename in it at all, so basename($_url) would save the file as
# literally "download" instead of e.g. "ES-DE_x64.AppImage". The release
# asset's own "name" field (tab-separated from the URL above) is the only
# place the real filename actually lives.
local _asset_name
_asset_name="${_url#*$'\t'}"
_url="${_url%%$'\t'*}"
local _file="$_dir/$_asset_name"
curl -fL --progress-bar -o "$_file" "$_url" \ curl -fL --progress-bar -o "$_file" "$_url" \
&& chmod +x "$_file" \ && chmod +x "$_file" \
&& chown "$ACTUAL_USER:$ACTUAL_USER" "$_file" \ && chown "$ACTUAL_USER:$ACTUAL_USER" "$_file" \