From 1bf59e0af9b268607c6805c66d538e722d2e134c Mon Sep 17 00:00:00 2001 From: Ed Morley <501702+edmorley@users.noreply.github.com> Date: Tue, 3 Mar 2026 16:47:17 +0000 Subject: [PATCH] Explicitly configure uv to use hard links Since in newer versions of uv (specifically uv 0.10.5+, which we haven't yet updated to) the default link mode has changed from `hardlink` to `clone` (aka reflink), and reflinks are slower in some environments (such as Heroku's build system). See: https://github.com/astral-sh/uv/issues/18259 Even if the uv default ends up being changed back to hard links again, it seems worth us explicitly requesting that link mode, given that we know it's the best mode for our use-case. GUS-W-21429394. --- CHANGELOG.md | 1 + src/layers/uv.rs | 12 ++++++++++-- tests/uv_test.rs | 1 + 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1b8277..612aa27 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Updated pip from 25.3 to 26.0.1. ([#508](https://github.com/heroku/buildpacks-python/pull/508)) +- Explicitly configured uv to use hard links to maintain the behaviour of previous versions. ([#519](https://github.com/heroku/buildpacks-python/pull/519)) ## [5.1.0] - 2026-02-26 diff --git a/src/layers/uv.rs b/src/layers/uv.rs index 1501721..2212bf3 100644 --- a/src/layers/uv.rs +++ b/src/layers/uv.rs @@ -39,9 +39,9 @@ pub(crate) fn install_uv( }, )?; - // Prevent uv from downloading/using its own Python installation: - // https://docs.astral.sh/uv/concepts/python-versions/#disabling-automatic-python-downloads let mut layer_env = LayerEnv::new() + // Prevent uv from downloading/using its own Python installation: + // https://docs.astral.sh/uv/concepts/python-versions/#disabling-automatic-python-downloads .chainable_insert( Scope::Build, ModificationBehavior::Override, @@ -53,6 +53,14 @@ pub(crate) fn install_uv( ModificationBehavior::Override, "UV_PYTHON_DOWNLOADS", "never", + ) + // Force uv to use hardlinks rather than the new default of reflinks, since the latter are + // significantly slower in some environments: https://github.com/astral-sh/uv/issues/18259 + .chainable_insert( + Scope::Build, + ModificationBehavior::Override, + "UV_LINK_MODE", + "hardlink", ); match layer.state { diff --git a/tests/uv_test.rs b/tests/uv_test.rs index b874d63..34dbc50 100644 --- a/tests/uv_test.rs +++ b/tests/uv_test.rs @@ -50,6 +50,7 @@ fn uv_basic_install_and_cache_reuse() { PYTHONUNBUFFERED=1 SOURCE_DATE_EPOCH=315532801 UV_CACHE_DIR=/layers/heroku_python/uv-cache + UV_LINK_MODE=hardlink UV_NO_MANAGED_PYTHON=1 UV_PROJECT_ENVIRONMENT=/layers/heroku_python/venv UV_PYTHON_DOWNLOADS=never