Skip to content

release: 0.4.15 — HEAD-fallback download cache + os.dirs glob fix#265

Merged
Sunrisepeak merged 1 commit into
mainfrom
release/0.4.15
May 5, 2026
Merged

release: 0.4.15 — HEAD-fallback download cache + os.dirs glob fix#265
Sunrisepeak merged 1 commit into
mainfrom
release/0.4.15

Conversation

@Sunrisepeak
Copy link
Copy Markdown
Member

Summary

Two compounding download-cache bugs the user reported as "最近感觉好像有问题".

  1. Download cache silently re-downloaded every install when sha256 is unset. The cache check was fs::exists(destFile) && !task.sha256.empty() — recipes that declare url but no sha256 (about 8% of fixture pkgindex; more in the real index where _linux_url(version) helpers synthesize URLs without a matching hash) re-fetched the entire payload on every xlings install.
  2. os.dirs("…/v*") returned empty on POSIX. The libxpkg shim shelled out as ls -d "<pattern>" 2>/dev/null — the surrounding double quotes made the shell skip glob expansion, so os.dirs("/tmp/x/cuda_v*") looked for a file literally named cuda_v*. Fixed in libxpkg 增加一个exec命令 用于执行命令 或 应用程序 #15 / v0.0.38, brought in via the dep bump below.

Changes

Download cache (xlings)

src/core/xim/downloader.cppm:

  • Path 1 (sha256 known) unchanged behavior on hit; on mismatch we now fs::remove the stale file before falling through, so a future tinyhttps Range/resume mode can't splice old bytes onto new content.
  • Path 2 (NEW, sha256 empty): HEAD-probe → compare local file size to Content-Length, cross-check Last-Modified / ETag against a <destFile>.meta sidecar we write after each download. Match → skip. HEAD failure → trust the existing non-empty file rather than wasting bandwidth (airline-friendly).
  • After a no-sha256 download, persist server-reported Last-Modified / ETag to the sidecar so the next install has something to compare against.

src/libs/tinyhttps.cppm:

  • New RemoteFileMeta { contentLength, lastModified, etag, ok, statusCode, error } + query_remote_meta() returning all three header fields from one HEAD. query_content_length() reduces to a thin wrapper (same semantics, no API break).

tests/unit/test_main.cpp::XimDownloaderTest::MetaSidecarRoundTrip:

  • Round-trip + missing-file + malformed-line tolerance for the sidecar parser.

Dep bump

xmake.lua: mcpplibs-xpkg 0.0.370.0.38.

mcpplibs/mcpplibs-index#8 is already merged with the new sha256 entry.

Behavior comparison

sha256 declared sha256 empty
Before hash-verify, skip if match (correct) re-download every install
After hash-verify, skip if match (unchanged) HEAD probe + sidecar; skip if size + Last-Modified / ETag match

Test plan

  • xmake build xlings_tests clean (mcpplibs-xpkg 0.0.38 resolves)
  • xmake run xlings_tests — 216/220 pass, 4 pre-existing skips
  • New XimDownloaderTest::MetaSidecarRoundTrip exercises the parser/writer
  • Local shell sanity check on the libxpkg os.dirs fix: ls -d /tmp/x/cuda_v* now globs, escaped-space /tmp/x\ space/cuda_v* still resolves
  • CI green (linux + macos + windows)

Related

Two user-visible bug fixes that compound: package recipes that omit
sha256 (~8% of fixture index, more in real index for `_linux_url`-style
helpers) were re-downloading their entire payload on every install; and
on POSIX `os.dirs("…/v*")` silently returned an empty list because the
shim quoted the pattern, suppressing shell glob expansion.

- src/core/xim/downloader.cppm
  - Cache hit path now has two arms. Path 1 (sha256 verified) unchanged
    except it now `fs::remove`s the stale file before falling through —
    defends against a future tinyhttps Range/resume mode reusing partial
    bytes from a different version.
  - Path 2 (NEW): when `task.sha256` is empty, HEAD-probe the URL and
    compare the local file size to `Content-Length`. Cross-check
    `Last-Modified` / `ETag` against a sidecar (`<destFile>.meta`) we
    write after the previous download. Match → skip download. HEAD
    failure (offline, server blocks HEAD, 4xx) → trust an existing
    non-empty file rather than wasting bandwidth.
  - After a successful no-sha256 download, persist server-reported
    Last-Modified / ETag to the sidecar so the next install has
    something to compare against.

- src/libs/tinyhttps.cppm
  - New `RemoteFileMeta { contentLength, lastModified, etag, ok, ... }`
    + `query_remote_meta()` returning all three header fields from one
    HEAD round-trip. `query_content_length()` reduces to a thin wrapper.

- tests/unit/test_main.cpp::XimDownloaderTest::MetaSidecarRoundTrip
  - Locks down the sidecar format (round-trip, missing-file, malformed
    line tolerance).

- xmake.lua / src/core/config.cppm / changelog
  - Bump mcpplibs-xpkg 0.0.37 → 0.0.38 (libxpkg #15 — `os.dirs` glob fix
    as described above).
  - VERSION 0.4.14 → 0.4.15.
@Sunrisepeak Sunrisepeak merged commit 7991ff2 into main May 5, 2026
3 checks passed
@Sunrisepeak Sunrisepeak deleted the release/0.4.15 branch May 5, 2026 00:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant