uv cache prune --ci 是什么?CI 中如何缩小 uv 缓存体积
【免费下载链接】uvAn extremely fast Python package and project manager, written in Rust.项目地址: https://gitcode.com/GitHub_Trending/uv/uv
如果你在 GitHub Actions 或 GitLab CI 中开启了 uv 缓存以加速依赖安装,很快就会遇到一个反向问题:缓存里存了大量预构建 wheel,体积不断膨胀,下次恢复缓存时上传/下载时间越来越长。uv 针对这个场景提供了uv cache prune --ci命令:它删除缓存中所有预构建的 wheel 和解压后的源码分发包,但保留从源码构建出来的 wheel。官方建议在每次 CI 任务结束时运行它,以换取最大的缓存效率。
这篇文章基于 uv 官方文档(缓存概念、GitHub Actions 集成指南、GitLab CI/CD 集成指南)说明这个命令的作用原理,并给出在 CI 中缩小 uv 缓存体积的具体配置步骤。
uv cache prune --ci 做了什么
理解这个命令前,先看 uv 缓存的内容构成。uv 为了高性能安装,默认会缓存两类 wheel:
- 从源码构建(build from source)的 wheel;
- 直接从注册表下载的预构建 wheel。
在 CI 环境中,持久化预构建 wheel 往往并不划算——每次运行重新从注册表下载通常比传输一个臃肿的缓存更快。相反,缓存源码构建出的 wheel 是值得的,因为构建过程本身开销很大,尤其是扩展模块。
uv cache prune --ci就是按这个策略裁剪缓存:删掉预构建 wheel 和解压后的源码分发包,保留源码构建的 wheel。两点需要留意:
- 性能收益取决于安装的包:官方文档明确说明,该命令对性能的影响依赖于具体安装的包,不存在“一定更快”的保证。
- 它与
uv cache prune是两回事:不带--ci的uv cache prune删除所有_未使用_的缓存条目和所有集中式项目环境(centralized project environments,这些环境会在需要时重建),适合定期清理本地缓存;--ci模式则是专门针对“在 CI 中持久化缓存”这一目标设计的裁剪方式。
前提条件
- CI 环境中已安装 uv(GitHub Actions 使用
astral-sh/setup-uv动作;GitLab 可使用 Astral 提供的 Docker 镜像)。 - 你正在把 uv 缓存持久化到 CI 的跨任务缓存中——这正是需要缩小的对象。缓存目录的确定顺序是:
--no-cache时的临时目录 →--cache-dir/UV_CACHE_DIR/tool.uv.cache-dir配置 → 系统默认目录(Unix 上如$XDG_CACHE_HOME/uv或$HOME/.cache/uv,Windows 上为%LOCALAPPDATA%\uv\cache)。在 CI 中通常用UV_CACHE_DIR显式固定位置。
在 GitHub Actions 中配置
下面是一条完整可执行的主路径:固定缓存目录 → 恢复缓存 → 安装依赖 → 任务结束前裁剪缓存 → 上传。
在 job 级别设置UV_CACHE_DIR,把缓存位置固定为常量路径;缓存键基于uv.lock的哈希:
jobs: install_job: env: # Configure a constant location for the uv cache UV_CACHE_DIR: /tmp/.uv-cache steps: # ... setup up Python and uv ... - name: Restore uv cache uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: /tmp/.uv-cache key: uv-${{ runner.os }}-${{ hashFiles('uv.lock') }} restore-keys: | uv-${{ runner.os }}-${{ hashFiles('uv.lock') }} uv-${{ runner.os }} # ... install packages, run tests, etc ... - name: Minimize uv cache run: uv cache prune --ci几个要点:
uv cache prune --ci的位置:放在依赖安装和测试执行_之后_、缓存被保存回 CI 之前。这样裁剪下来的才是最终会被上传的缓存。- 缓存键:项目使用 uv 项目接口(有
uv.lock)时,用hashFiles('uv.lock')作为键。如果使用uv pip接口,官方建议改用requirements.txt作为缓存键文件,而不是uv.lock。 - 替代方案:如果不想手动管理缓存,
astral-sh/setup-uv自带缓存支持,加一个enable-cache: true即可:
- name: Enable caching uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 with: enable-cache: true在 GitLab CI/CD 中配置
GitLab 的对应做法是把uv cache prune --ci放进after_script,让它在该 job 的所有步骤之后、缓存持久化之前执行:
uv-install: variables: UV_CACHE_DIR: .uv-cache cache: - key: files: - uv.lock paths: - $UV_CACHE_DIR script: # Your `uv` commands after_script: - uv cache prune --ci官方文档同样建议在 job 末尾运行该命令来减小缓存体积;如果使用uv pip接口,缓存键文件应改用requirements.txt或pyproject.toml而不是uv.lock。
验证缓存目录与体积
裁剪效果没有固定的数值预期,但可以用以下官方给出的手段核对:
- 用
uv cache dir确认当前生效的缓存目录路径,检查它是否与 CI 中配置的UV_CACHE_DIR一致——这是排查“缓存没有变小”的第一步。 - 默认情况下,缓存清理类命令会估算回收的磁盘空间;如果需要更精确、能考虑硬链接和写时复制克隆的估算值,可以启用
cache-physical-space预览特性:
$ uv cache clean --preview-features cache-physical-space这个预览特性目前支持 macOS 和 Linux,其他平台仍报告较粗略的估算。注意上例是对uv cache clean的演示命令;对prune的裁剪量判断同样适用这套估算机制。
两个已知的边界情况
自托管 runner:在长时间存活的自托管 runner 上,默认缓存目录会无限增长,此时在不同 job 之间共享缓存可能不是最优选择。官方给出的替代方案是把缓存移进 GitHub workspace(UV_CACHE_DIR: ${{ github.workspace }}/.cache/uv),并在 job 结束时用 Post Job Hook 清理,例如在 runner 上设置ACTIONS_RUNNER_HOOK_JOB_STARTED指向一个只包含uv cache clean的清理脚本。注意这是整目录清理,而非prune --ci的选择性裁剪,二者定位不同。
并发锁定:uv 会阻止在其他 uv 命令运行时修改缓存。uv cache命令默认等待其他 uv 进程结束最多 5 分钟以避免死锁,该超时可以由UV_LOCK_TIMEOUT调整;如果确定没有其他 uv 进程在读写缓存,可以使用--force忽略锁。
参考资料
- uv 缓存文档:Caching in continuous integration
- 在 GitHub Actions 中使用 uv
- 在 GitLab CI/CD 中使用 uv
- 存储目录说明
【免费下载链接】uvAn extremely fast Python package and project manager, written in Rust.项目地址: https://gitcode.com/GitHub_Trending/uv/uv
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考