From d8b8f44b2365e562d6db861e13fc2ccb2483b0e1 Mon Sep 17 00:00:00 2001 From: Carl Csaposs Date: Fri, 6 Feb 2026 16:50:58 +0100 Subject: [PATCH] fix(plugins/uv): Avoid modifying already relocatable venv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The uv plugin from craft-parts already uses `uv venv --relocatable` to create an activate script that has a portable path instead of an absolute path https://github.com/canonical/craft-parts/blob/71291d50ec95aed813215e89463866dd09aaaa5e/craft_parts/plugins/uv_plugin.py#L108 Currently, charmcraft is overriding the relocatable path set by uv with its own relocatable path (since it's expecting `activate` to contain a hardcoded path, like it does with `venv`—instead of a relocatable path) This currently doesn't cause any issues, but could break in the future if the format of the activate script created by `uv venv` changes (since charmcraft is using `sed` to update the script) Use the relocatable option provided by uv's public API instead of patching a private implementation detail --- charmcraft/parts/plugins/_uv.py | 5 ++++- charmcraft/utils/parts.py | 20 +++++++++++++------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/charmcraft/parts/plugins/_uv.py b/charmcraft/parts/plugins/_uv.py index b2bcfe318..e3fa3cd35 100644 --- a/charmcraft/parts/plugins/_uv.py +++ b/charmcraft/parts/plugins/_uv.py @@ -61,6 +61,9 @@ def get_build_commands(self) -> list[str]: return [ *super().get_build_commands(), *utils.get_venv_cleanup_commands( - self._get_venv_directory(), keep_bins=False + self._get_venv_directory(), + keep_bins=False, + # craft-parts already uses `uv venv --relocatable` + make_relocatable=False, ), ] diff --git a/charmcraft/utils/parts.py b/charmcraft/utils/parts.py index 9ed7d9ce7..d105cad88 100644 --- a/charmcraft/utils/parts.py +++ b/charmcraft/utils/parts.py @@ -56,11 +56,14 @@ def get_charm_copy_commands( return commands -def get_venv_cleanup_commands(venv_path: pathlib.Path, *, keep_bins: bool) -> list[str]: +def get_venv_cleanup_commands( + venv_path: pathlib.Path, *, keep_bins: bool, make_relocatable: bool = True +) -> list[str]: """Get a script do Charmcraft-specific venv cleanup. :param venv_path: The path to the venv. :param keep_bins: Whether to keep the bin directory of the venv. + :param make_relocatable: Whether to make the activate script portable :returns: A shell script to do this, as a string. """ venv_bin = venv_path / "bin" @@ -74,12 +77,15 @@ def get_venv_cleanup_commands(venv_path: pathlib.Path, *, keep_bins: bool) -> li f"rm -rf {venv_bin}/!(activate)", "shopt -u extglob", ] - update_activate = [ - # Replace hard-coded path in `activate` with portable path - # "\&" is escape for sed - 'sed -i \'s#^VIRTUAL_ENV=.*$#VIRTUAL_ENV="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )/.." \\&> /dev/null \\&\\& pwd )"#\' ' - + str(venv_bin / "activate"), - ] + if make_relocatable: + update_activate = [ + # Replace hard-coded path in `activate` with portable path + # "\&" is escape for sed + 'sed -i \'s#^VIRTUAL_ENV=.*$#VIRTUAL_ENV="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )/.." \\&> /dev/null \\&\\& pwd )"#\' ' + + str(venv_bin / "activate"), + ] + else: + update_activate = [] delete_lib64 = textwrap.dedent(f""" if [ -L '{venv_lib64}' ]; then rm -f '{venv_lib64}'