From 750c55a4d4ef8d4e386c4add518f93d41d09f528 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 10 Sep 2026 03:16:27 +0000 Subject: [PATCH] wolf: fix ES-DE GitLab AppImage download resolving no URL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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//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 Claude-Session: https://claude.ai/code/session_013BWYKEERLA1a7gv86Z4W23 --- services/wolf.sh | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/services/wolf.sh b/services/wolf.sh index a1558ad..19d48d2 100644 --- a/services/wolf.sh +++ b/services/wolf.sh @@ -328,21 +328,43 @@ releases = sorted(releases, key=lambda r: r.get("released_at") or "", reverse=Tr assets = [] for r in releases: for link in r.get("assets", {}).get("links", []): + # The GitLab asset URL itself is an opaque .../package_files//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 "" - if url.endswith(".AppImage"): - assets.append({"name": link.get("name", url), "browser_download_url": url}) + if name.endswith(".AppImage"): + assets.append({"name": name, "browser_download_url": url}) if assets: break 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)] 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) if [[ -z "$_url" ]]; then log_warning "Could not resolve download URL — get it manually from https://gitlab.com/${_project_path}/-/releases" return 1 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//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" \ && chmod +x "$_file" \ && chown "$ACTUAL_USER:$ACTUAL_USER" "$_file" \