748 lines
34 KiB
RPMSpec
748 lines
34 KiB
RPMSpec
%bcond check 1
|
||
# Should we run tests that require specific Python interpreter versions
|
||
# (major.minor, not major.minor.patch)? This adds a few dozen tests, but adds
|
||
# BuildRequires on more Python interpreters (which aren’t available in EPEL).
|
||
%bcond other_python_versions %{undefined epel}
|
||
|
||
Name: uv
|
||
Version: 0.12.3
|
||
# The uv package has a permanent exception to the Updates Policy in Fedora, so
|
||
# it can be updated in stable releases across SemVer boundaries (subject to
|
||
# good judgement and actual compatibility of any reverse dependencies). See
|
||
# https://docs.fedoraproject.org/en-US/fesco/Updates_Policy/#_other_packages,
|
||
# https://pagure.io/fesco/issue/3262. It also has a corresponding exception in
|
||
# EPEL, but only in leading branches and only until version 1.0; see
|
||
# https://pagure.io/epel/issue/317.
|
||
Release: %autorelease
|
||
Summary: An extremely fast Python package installer and resolver, written in Rust
|
||
|
||
# The license of the uv project is (MIT OR Apache-2.0), except:
|
||
#
|
||
# Apache-2.0:
|
||
# - crates/uv-python/src/libc.rs contains code derived from
|
||
# crate(glibc_version)
|
||
# - crates/uv-requirements-txt/src/shquote.rs contains code derived from
|
||
# crate(r-shquote); the original code was (Apache-2.0 OR
|
||
# LGPL-2.1-or-later), but the vendored copy cites only the Apache-2.0
|
||
# option.
|
||
# - crates/uv-build-frontend/src/pipreqs/mappings is a data file taken from
|
||
# https://pypi.org/project/pipreqs, https://github.com/bndr/pipreqs
|
||
#
|
||
# Apache-2.0 OR BSD-2-Clause:
|
||
# - crates/uv-pep440/ is vendored and forked from crate(pep440_rs)
|
||
# - crates/uv-pep508/ is vendored and forked from crate(pep508_rs)
|
||
# - crates/uv-python/packaging/ is vendored and forked from
|
||
# python3dist(packaging)
|
||
#
|
||
# (Apache-2.0 OR MIT) AND BSD-3-Clause:
|
||
# - The function wheel_metadata_from_remote_zip in
|
||
# crates/uv-client/src/remote_metadata.rs is vendored and forked from the
|
||
# function lazy_read_wheel_metadata in src/index/lazy_metadata.rs in
|
||
# crate(rattler_installs_packages) and is BSD-3-Clause AND (Apache-2.0 OR
|
||
# MIT): the original routine is BSD-3-Clause, and subsequent modifications
|
||
# are explicitly (Apache-2.0 OR MIT).
|
||
#
|
||
# MIT
|
||
# - crates/uv-virtualenv/src/activator/ is vendored and forked from
|
||
# python3dist(virtualenv)
|
||
# - crates/uv-netrc/ is vendored from crate(rust-netrc)
|
||
#
|
||
# Additionally, the following are bundled/forked but happen to be under the
|
||
# same (Apache-2.0 OR MIT) terms as uv itself:
|
||
# - crates/uv-extract/src/vendor/cloneable_seekable_reader.rs is vendored and
|
||
# forked from crate(ripunzip)
|
||
#
|
||
# The following are present in the source but believed not to contribute to the
|
||
# licenses of the binary RPMs. Note that test/ecosystem/ contains only
|
||
# pyproject.toml files used for testing, not complete bundled projects.
|
||
#
|
||
# Apache-2.0:
|
||
# - test/ecosystem/airflow/
|
||
# - test/ecosystem/home-assistant-core/
|
||
# - test/ecosystem/transformers/
|
||
# - test/ecosystem/warehouse/
|
||
# Apache-2.0 OR MIT:
|
||
# - test/ecosystem/packse/
|
||
# BSD-2-Clause-Patent:
|
||
# - test/ecosystem/github-wikidata-bot/
|
||
# BSD-3-Clause:
|
||
# - test/ecosystem/jupyterlab/
|
||
# - test/ecosystem/pandas/
|
||
# - test/ecosystem/saleor/
|
||
# MIT:
|
||
# - crates/uv-python/fetch-download-metadata.py is derived from
|
||
# https://github.com/mitsuhiko/rye/tree/f9822267a7f00332d15be8551f89a212e7bc9017
|
||
# which was MIT.
|
||
# - test/ecosystem/black/
|
||
# - test/ecosystem/poetry/
|
||
# - test/ecosystem/semantic-kernel/
|
||
#
|
||
# Rust crates compiled into the executable contribute additional license terms.
|
||
# To obtain the following list of licenses, build the package and note the
|
||
# output of %%{cargo_license_summary}.
|
||
#
|
||
# (Apache-2.0 OR MIT) AND BSD-3-Clause
|
||
# (MIT OR Apache-2.0) AND Apache-2.0 AND CC0-1.0
|
||
# (MIT OR Apache-2.0) AND Unicode-3.0
|
||
# (MIT OR Apache-2.0) AND Unicode-DFS-2016
|
||
# 0BSD
|
||
# 0BSD OR MIT OR Apache-2.0
|
||
# Apache-2.0
|
||
# Apache-2.0 AND ISC AND (MIT OR Apache-2.0)
|
||
# Apache-2.0 OR BSD-2-Clause
|
||
# Apache-2.0 OR BSL-1.0
|
||
# Apache-2.0 OR ISC OR MIT
|
||
# Apache-2.0 OR MIT
|
||
# Apache-2.0 OR MIT OR Zlib
|
||
# Apache-2.0 WITH LLVM-exception
|
||
# Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT
|
||
# BSD-2-Clause OR Apache-2.0 OR MIT
|
||
# BSD-3-Clause
|
||
# CDLA-Permissive-2.0
|
||
# ISC
|
||
# LGPL-3.0-or-later OR MPL-2.0
|
||
# MIT
|
||
# MIT AND (MIT OR Apache-2.0)
|
||
# MIT OR Apache-2.0
|
||
# MIT OR LGPL-3.0-or-later
|
||
# MIT OR Zlib OR Apache-2.0
|
||
# MIT-0
|
||
# MIT-0 OR Apache-2.0
|
||
# MPL-2.0
|
||
# Unicode-3.0
|
||
# Unlicense OR MIT
|
||
# Zlib
|
||
License: %{shrink:
|
||
0BSD AND
|
||
(0BSD OR Apache-2.0 OR MIT) AND
|
||
Apache-2.0 AND
|
||
(Apache-2.0 OR BSD-2-Clause) AND
|
||
(Apache-2.0 OR BSD-2-Clause OR MIT) AND
|
||
(Apache-2.0 OR BSL-1.0) AND
|
||
(Apache-2.0 OR ISC OR MIT) AND
|
||
(Apache-2.0 OR MIT) AND
|
||
(Apache-2.0 OR MIT OR Zlib) AND
|
||
(Apache-2.0 OR MIT-0) AND
|
||
(Apache-2.0 WITH LLVM-exception) AND
|
||
(Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT) AND
|
||
BSD-3-Clause AND
|
||
CC0-1.0 AND
|
||
CDLA-Permissive-2.0 AND
|
||
ISC AND
|
||
(LGPL-3.0-or-later OR MIT) AND
|
||
(LGPL-3.0-or-later OR MPL-2.0) AND
|
||
MIT AND
|
||
MIT-0 AND
|
||
(MIT OR Unlicense) AND
|
||
MPL-2.0 AND
|
||
Unicode-3.0 AND
|
||
Unicode-DFS-2016 AND
|
||
Zlib
|
||
}
|
||
# LICENSE.dependencies contains a full license breakdown
|
||
URL: https://github.com/astral-sh/uv
|
||
Source0: %{url}/archive/%{version}/uv-%{version}.tar.gz
|
||
# Default system-wide configuration file
|
||
# https://docs.astral.sh/uv/configuration/files
|
||
Source1: uv.toml
|
||
|
||
# Downstream-only: Always find the system-wide uv executable
|
||
# See discussion in
|
||
# Should uv.find_uv_bin() be able to find /usr/bin/uv?
|
||
# https://github.com/astral-sh/uv/issues/4451
|
||
Patch: 0001-Downstream-patch-always-find-the-system-wide-uv-exec.patch
|
||
# Downstream-only: revert source-code changes from “Upgrade BLAKE2 to unify
|
||
# hashing digest versions”, https://github.com/astral-sh/uv/pull/20834. We do
|
||
# not wish to upgrade rust-blake2 to a pre-release.
|
||
Patch: uv-0.12.1-revert-blake2-beta.patch
|
||
# Add license texts for new contents of test/ecosystem/ from PR#20068
|
||
# https://github.com/astral-sh/uv/pull/20174
|
||
Patch: %{url}/pull/20174.patch
|
||
|
||
BuildSystem: pyproject
|
||
BuildOption(install): --assert-license uv
|
||
|
||
# https://fedoraproject.org/wiki/Changes/EncourageI686LeafRemoval
|
||
ExcludeArch: %{ix86}
|
||
|
||
# On some releases and architectures, Koji builders sometimes or always run out
|
||
# of memory in the final linking step. This cannot be fixed by adding
|
||
# "-C link-args=-Wl,--no-keep-memory" to the RUSTFLAGS (as that seems to have
|
||
# no significant effect on memory requirements), nor can it be fixed by
|
||
# reducing parallelism (although we do need this as well), since nothing else
|
||
# is happening at that point in the build. See:
|
||
# https://doc.rust-lang.org/rustc/codegen-options/index.html#debuginfo
|
||
%global rustflags_debuginfo 1
|
||
|
||
# As a separate limitation, memory exhaustion (OOM) can occur during parallel
|
||
# portions of the build.
|
||
# - Because very many workspace crates can be built in parallel, builders with
|
||
# a very large number of CPUs may OOM. Typical workspace crates peak out at
|
||
# roughly 2–4 GB per rustc process.
|
||
# - The uv crate needs much more memory to compile and link, at least 8 GB, and
|
||
# when building the tests we may be building bin and lib versions at the same
|
||
# time, along with the it (integration test) crate, which is also rather
|
||
# large. This is a problem for “low memory” builders (<20 GB or so).
|
||
# Unfortunately, this means that we need to scale the memory per task based on
|
||
# the memory requirements of the top-level uv crate in order to avoid OOM on
|
||
# all kinds of builders.
|
||
%global _smp_tasksize_proc 10240
|
||
|
||
# Compilation may fail on builders with very many cores (e.g. 192 cores) due to
|
||
# “too many open files.” Try to keep the files/core ratio from getting too low.
|
||
%global _smp_ncpus_max 48
|
||
|
||
BuildRequires: cargo-rpm-macros
|
||
BuildRequires: rust2rpm-helper
|
||
BuildRequires: tomcli
|
||
%if %{with check} && %{with other_python_versions}
|
||
# See trove classifiers in pyproject.toml for supported Pythons.
|
||
BuildRequires: /usr/bin/python3.9
|
||
BuildRequires: /usr/bin/python3.10
|
||
BuildRequires: /usr/bin/python3.11
|
||
BuildRequires: /usr/bin/python3.12
|
||
BuildRequires: /usr/bin/python3.13
|
||
BuildRequires: /usr/bin/python3.13t
|
||
BuildRequires: /usr/bin/python3.14
|
||
BuildRequires: /usr/bin/python3.14t
|
||
%endif
|
||
|
||
# In https://github.com/astral-sh/uv/issues/5588#issuecomment-2257823242,
|
||
# upstream writes “These have diverged significantly and the upstream versions
|
||
# are only passively maintained, uv requires these custom versions and can't
|
||
# use a system copy.”
|
||
#
|
||
# crates/uv-pep440/
|
||
# Version number from crates/uv-pep440/CHANGELOG.md; it was also in
|
||
# crates/uv-pep440/Cargo.toml until uv 0.9.11, when internal crates started
|
||
# being versioned and published on crates.io.
|
||
Provides: bundled(crate(pep440_rs)) = 0.7.0
|
||
# crates/uv-pep508/
|
||
# Version number from crates/uv-pep508/Changelog.md; it was also in
|
||
# crates/uv-pep508/Cargo.toml until uv 0.9.11, when internal crates started
|
||
# being versioned and published on crates.io, but the version in Cargo.toml was
|
||
# 0.6.0. The source reflects upstream changes in 0.7.0.
|
||
Provides: bundled(crate(pep508_rs)) = 0.7.0
|
||
# crates/uv-virtualenv/
|
||
# As a whole, this crate is derived from https://github.com/konstin/gourgeist
|
||
# 0.0.4, which was published as https://crates.io/crates/gourgeist. It looks
|
||
# like the project was subsumed into `uv`, and the link to `uv` at
|
||
# https://konstin.github.io/gourgeist/ (“See
|
||
# https://github.com/astral-sh/uv/tree/main/crates/uv-virtualenv for the up to
|
||
# date version”) supports this. We therefore consider this not to be a real
|
||
# case of bundling, since the source in uv is now the canonical one, and we do
|
||
# not add:
|
||
# Provides: bundled(crate(gourgeist)) = 0.0.4
|
||
|
||
# crates/uv-extract/src/vendor/cloneable_seekable_reader.rs
|
||
# Version number is an educated guess based on comparison of file contents,
|
||
# cross-checked with timing: the file was first introduced to uv as
|
||
# crates/puffin-installer/src/vendor/cloneable_seekable_reader.rs in
|
||
# https://github.com/astral-sh/uv/commit/2a846e76b7725633776fd08e04ce8b827bb0580f
|
||
# on 2023-10-08, and 0.4.0 was the current release of ripunzip at that time.
|
||
Provides: bundled(crate(ripunzip)) = 0.4.0
|
||
# wheel_metadata_from_remote_zip only, in
|
||
# crates/uv-client/src/remote_metadata.rs
|
||
# Version number is, at the time of this writing, the only release of
|
||
# https://github.com/prefix-dev/rip containing the corresponding function
|
||
# lazy_read_wheel_metadata in
|
||
# (crates/rattler_installs_packages/)src/index/lazy_metadata.rs.
|
||
Provides: bundled(crate(rattler_installs_packages)) = 0.9.0
|
||
|
||
# crates/uv-python/src/libc.rs
|
||
# This is at least partially derived (with changes) from the glibc_version
|
||
# crate, https://github.com/delta-incubator/glibc-version-rs. The last commit
|
||
# that we can match up with the file in uv is
|
||
# 5e1002dc7a3c39c0d72631cc488bef2fc5fea0fb, although it would be equally
|
||
# correct to reference any of several slightly later commits.
|
||
Provides: bundled(crate(glibc_version)) = 0.1.2^20221117git5e1002d
|
||
|
||
# crates/uv-requirements-txt/src/shquote.rs
|
||
# The unquote implementation is vendored from the r-shquote crate because it is
|
||
# unmaintained upstream, https://github.com/astral-sh/uv/issues/11780.
|
||
Provides: bundled(crate(r-shquote)) = 0.1.1
|
||
|
||
# crates/uv-keyring
|
||
# From crates/uv-keyring/README.md, “This is vendored from [keyring-rs
|
||
# crate](https://github.com/open-source-cooperative/keyring-rs)
|
||
# commit 9635a2f53a19eb7f188cdc4e38982dcb19caee00.” The commit message of the
|
||
# referenced upstream commit indicates it corresponds to 4.0.0-rc2.
|
||
#
|
||
# The text of https://github.com/astral-sh/uv/pull/14725 explains the differing
|
||
# design goals and tradeoffs that lead uv to fork keyring-rs rather than using
|
||
# the upstream https://crates.io/crates/keyring crate or trying to get the
|
||
# necessary changes merged upstream. Based on this explanation, there does not
|
||
# appear to be any prospect of unbundling.
|
||
Provides: bundled(crate(keyring)) = 4.0.0~rc2
|
||
|
||
# crates/uv-netrc
|
||
# From crates/uv-netrc/README.md, “This crate vendors the rust-netrc parser for
|
||
# use by uv. The source was vendored from gribouille/netrc, as published in
|
||
# rust-netrc 0.1.2[…]”
|
||
#
|
||
# Upstream justifies the bundling in
|
||
# https://github.com/astral-sh/uv/pull/19409: they want unreleased bug fixes,
|
||
# including those pertaining to https://github.com/astral-sh/uv/issues/16083,
|
||
# and to avoid a dependency on thiserror v1. In response to the mandatory
|
||
# query, they report they are open to de-vendoring if a new rust-netrc release
|
||
# with the desired changes appears.
|
||
Provides: bundled(crate(rust-netrc)) = 0.1.2
|
||
|
||
# The contents of crates/uv-virtualenv/src/activator/ are a bundled and
|
||
# slightly forked copy of a subset of https://pypi.org/project/virtualenv; see
|
||
# https://github.com/pypa/virtualenv/tree/main/src/virtualenv/activation.
|
||
#
|
||
# The same justification for not attempting to unbundle downstream applies as
|
||
# for the bundling from python3dist(packaging), below; additionally, some of
|
||
# the scripts have been forked. See also:
|
||
# https://github.com/astral-sh/uv/issues/5588#issuecomment-2257474140
|
||
#
|
||
# The scripts were last updated from virtualenv upstream in
|
||
# https://github.com/astral-sh/uv/pull/15272 on 2025-09-05. The PR was opened
|
||
# on 2025-08-14 and last revised on 2025-08-30; the latest virtualenv release
|
||
# throughout that time interval was 20.34.0.
|
||
Provides: bundled(python3dist(virtualenv)) = 20.34
|
||
|
||
# The contents of crates/uv-python/python/packaging/ are a bundled copy of a
|
||
# subset of https://pypi.org/project/packaging.
|
||
#
|
||
# This was added in
|
||
# https://github.com/astral-sh/uv/commit/7964bfbb2bed50a5c7b0650a7b6799a66503a33a,
|
||
# the commit message of which helps explain the rationale. In part:
|
||
#
|
||
# The architecture of uv does not necessarily match that of the python
|
||
# interpreter. In cross compiling/testing scenarios the operating system can
|
||
# also mismatch. To solve this, we move arch and os detection to python,
|
||
# vendoring the relevant pypa/packaging code, preventing mismatches between
|
||
# what the python interpreter was compiled for and what uv was compiled for.
|
||
#
|
||
# We cannot use the system package directly because these Python sources are
|
||
# compiled into the uv executable, and the binary package does not even depend
|
||
# on the system Python interpreter. Patching uv to read the sources from the
|
||
# system package at runtime would be much too extreme for a downstream change.
|
||
# Copying sources from the system package into the build tree is feasible, but
|
||
# – especially considering that the sources are not necessarily executed with
|
||
# the system Python interpreter – the risks of deviating from upstream’s tested
|
||
# sources would seem to greatly outweigh any possible benefits of such
|
||
# “build-time unbundling.” We therefore consider this instance of bundling
|
||
# technically necessary. See also:
|
||
# https://github.com/astral-sh/uv/issues/5588#issuecomment-2257474140
|
||
#
|
||
# README.md has the bundled commit hash, __init__.py has the version number,
|
||
# and https://github.com/pypa/packaging/tree/${commit} is the source of the
|
||
# snapshot date.
|
||
Provides: bundled(python3dist(packaging)) = 24.1~dev0^20240310gitcc938f9
|
||
|
||
# The contents of crates/uv-build-frontend/src/pipreqs/mapping are copied from
|
||
# https://pypi.org/project/pipreqs. Since this is just a data file, since uv
|
||
# does not take Python dependencies, and since pipreqs is not currently
|
||
# actively maintained anyway, there is no reasonable prospect of unbundling.
|
||
# The version number is just that of the latest pipreqs release at the time the
|
||
# data file was vendored.
|
||
Provides: bundled(python3dist(pipreqs)) = 0.5.0
|
||
|
||
%global common_description %{expand:
|
||
An extremely fast Python package and project manager, written in Rust.
|
||
|
||
Highlights:
|
||
|
||
• A single tool to replace pip, pip-tools, pipx, poetry, pyenv, twine,
|
||
virtualenv, and more.
|
||
• 10-100x faster than pip.
|
||
• Provides comprehensive project management, with a universal lockfile.
|
||
• Runs scripts, with support for inline dependency metadata.
|
||
• Installs and manages Python versions.
|
||
• Runs and installs tools published as Python packages.
|
||
• Includes a pip-compatible interface for a performance boost with a familiar
|
||
CLI.
|
||
• Supports Cargo-style workspaces for scalable projects.
|
||
• Disk-space efficient, with a global cache for dependency deduplication.}
|
||
|
||
%description %{common_description}
|
||
|
||
|
||
%package -n python3-uv
|
||
Summary: Importable Python module for uv
|
||
|
||
BuildArch: noarch
|
||
|
||
Requires: uv = %{version}-%{release}
|
||
|
||
%description -n python3-uv %{common_description}
|
||
|
||
This package provides an importable Python module for uv.
|
||
|
||
|
||
%prep -a
|
||
# Collect license files of vendored dependencies
|
||
install -D --preserve-timestamps --mode=0644 \
|
||
--target=LICENSE.bundled/packaging \
|
||
crates/uv-python/python/packaging/LICENSE.*
|
||
install -D --preserve-timestamps --mode=0644 \
|
||
--target=LICENSE.bundled/pep440_rs crates/uv-pep440/License-*
|
||
install -D --preserve-timestamps --mode=0644 \
|
||
--target=LICENSE.bundled/pep508_rs crates/uv-pep508/License-*
|
||
install -D --preserve-timestamps --mode=0644 \
|
||
--target=LICENSE.bundled/pipreqs \
|
||
crates/uv-build-frontend/src/pipreqs/LICENSE
|
||
install -D --preserve-timestamps --mode=0644 \
|
||
--target=LICENSE.bundled/ripunzip crates/uv-extract/src/vendor/LICENSE
|
||
install -D --preserve-timestamps --mode=0644 \
|
||
--target=LICENSE.bundled/rust-netrc crates/uv-netrc/LICENSE
|
||
# The original license text from rattler_installs_packages is present in a
|
||
# comment, but we want it in a separate file so we can ensure it is present in
|
||
# the binary RPM.
|
||
install --directory LICENSE.bundled/rattler_installs_packages
|
||
awk '$2 == "BSD" { out=1 }; $2 == "```" { out=0 }; out' \
|
||
crates/uv-client/src/remote_metadata.rs |
|
||
sed --regexp-extended 's@^///( |$)@@' |
|
||
tee LICENSE.bundled/rattler_installs_packages/LICENSE
|
||
# Similarly for virtualenv. All files in
|
||
# crates/uv-virtualenv/src/activator/activate/ have the same license text.
|
||
install --directory LICENSE.bundled/virtualenv
|
||
awk '$1 == "#" { out=1 }; $1 != "#" { out=0; exit }; out' \
|
||
crates/uv-virtualenv/src/activator/activate |
|
||
sed --regexp-extended 's@^#( |$)@@' |
|
||
tee LICENSE.bundled/virtualenv/LICENSE
|
||
|
||
# Patch out foreign (e.g. Windows-only) dependencies. Follow symbolic links so
|
||
# that we also patch the bundled crates we just finished setting up.
|
||
find -L . -type f -name Cargo.toml -print \
|
||
-execdir rust2rpm-helper strip-foreign -o '{}' '{}' ';'
|
||
|
||
# The uv-trampoline crate (a fork of posy trampolines, from
|
||
# https://github.com/njsmith/posy) uses a set of trampoline Windows executables
|
||
# for launching Python scripts. These precompiled executables are funished by
|
||
# the uv-trampoline-builder crate. We must remove them to prove they are not
|
||
# used in the build. Since they are used only on Windows, nothing is lost by
|
||
# doing so.
|
||
rm --verbose crates/uv-trampoline-builder/trampolines/*.exe
|
||
# Per Cargo.toml, uv-trampoline is excluded from the workspace and not compiled
|
||
# because it still requires a nightly compiler. For now, we remove it entirely
|
||
# to show that we do not need to document bundling from posy. Note that we
|
||
# *cannot* cleanly remove uv-trampoline-builder, only the precompiled
|
||
# trampolines themselves.
|
||
rm --recursive --verbose crates/uv-trampoline
|
||
|
||
# Remove the dependency on embed-manifest, which applies only when (cross-?)
|
||
# compiling for Windows.
|
||
tomcli set Cargo.toml del workspace.dependencies.embed-manifest
|
||
# We may have to do something more sophisticated if this build script ever
|
||
# starts to do anything other than just embedding a manifest on Windows.
|
||
rm --verbose crates/uv/build.rs
|
||
tomcli set crates/uv/Cargo.toml del build-dependencies.embed-manifest
|
||
# The embed-manifest depenency is also used in uv-trampoline, which we removed.
|
||
|
||
# Do not strip the compiled executable; we need useful debuginfo. Upstream set
|
||
# this intentionally, so this change makes sense to keep downstream-only.
|
||
tomcli set pyproject.toml false tool.maturin.strip
|
||
tomcli set Cargo.toml false profile.release.strip
|
||
|
||
# Exclude the bench crate from the workspace. We don’t need to build and run
|
||
# benchmarks, and it brings in unwanted additional dev dependencies.
|
||
tomcli set Cargo.toml append workspace.exclude crates/uv-bench
|
||
# The uv-dev crate provides “development utilities for uv,” which should not be
|
||
# needed here. It also brings extra dependencies that we would prefer to avoid.
|
||
tomcli set Cargo.toml append workspace.exclude crates/uv-dev
|
||
|
||
# Disable several default features that control which tests are compiled and
|
||
# executed, and which are not usable in offline builds:
|
||
#
|
||
# - test-crates-io: Introduces a testing dependency on crates.io.
|
||
# - test-git: Introduces a testing dependency on Git. This sounds innocuous –
|
||
# we have git! – but in fact, it controls tests of git dependencies, which
|
||
# implies accessing remote repositories, e.g. on GitHub.
|
||
# - test-git-lfs: as for git, but also require Git Large File Storage; again,
|
||
# this implies accessing remote repositories
|
||
# - test-pypi: Introduces a testing dependency on PyPI.
|
||
# - test-python-managed: Introduces a testing dependency on managed Python
|
||
# installations. (These are pre-compiled Pythons downloaded from the
|
||
# Internet.)
|
||
# - test-r2: Introduces a testing dependency on R2.
|
||
#
|
||
# These are OK:
|
||
# - test-python: Introduces a testing dependency on a local Python installation.
|
||
# - test-slow: Include "slow" test cases.
|
||
# - test-ecosystem: Includes test cases that require ecosystem packages
|
||
#
|
||
# Note that the python-patch feature, which ”introduces a dependency on a local
|
||
# Python installation with specific patch versions,” is already not among the
|
||
# default features.
|
||
tomcli set crates/uv/Cargo.toml lists delitem features.test-defaults \
|
||
'test-(crates-io|git(-lfs)?|pypi|python-managed|r2)'
|
||
# - -test-osv: Introduces a testing dependency on osv.dev.
|
||
tomcli set crates/uv-audit/Cargo.toml lists delitem features.default \
|
||
'test-(osv)'
|
||
|
||
%if %{without other_python_versions}
|
||
# Many of these tests require specific Python versions (major.minor, not
|
||
# major.minor.patch, unless the python-patch feature is enabled). Manually
|
||
# selecting the tests in these modules that would succeed with just the system
|
||
# Python would be far too tedious.
|
||
omit_modules() {
|
||
set -o nounset
|
||
set -o errexit
|
||
main_module="${1}"
|
||
commented_modules=''
|
||
comment='Downstream-only: skip, needs specific Python interpreter versions'
|
||
shift
|
||
while [ "${#}" != 0 ]
|
||
do
|
||
commented_modules="${commented_modules-}${commented_modules+|}${1}"
|
||
shift
|
||
done
|
||
sed --regexp-extended --in-place \
|
||
"s@mod (${commented_modules});@// ${comment}\n#[cfg(any())]\n&@" \
|
||
"${main_module}"
|
||
}
|
||
# -p uv --test build
|
||
omit_modules crates/uv/tests/build/main.rs build_backend
|
||
# -p uv --test it:
|
||
omit_modules crates/uv/tests/it/main.rs \
|
||
auth branching_urls network upgrade version
|
||
# -p uv --test python:
|
||
omit_modules crates/uv/tests/python/main.rs \
|
||
'python_(dir|find|install|list|pin)' venv
|
||
# -p uv --test workspace:
|
||
omit_modules crates/uv/tests/workspace/main.rs \
|
||
workspace 'workspace_(dir|list|metadata)'
|
||
# -p uv --test pip:
|
||
omit_modules crates/uv/tests/pip/main.rs \
|
||
'pip_(debug|list|show|tree|uninstall)'
|
||
%endif
|
||
|
||
# For unclear reasons, maturin checks for the presence of optional crate
|
||
# dependencies that correspond to features we have not enabled. We need to
|
||
# patch out those that are not packaged, an unfortunate but straightforward
|
||
# hack. See further commentary in %%generate_buildrequires.
|
||
tomcli set crates/uv/Cargo.toml del dependencies.axoupdater
|
||
tomcli set crates/uv/Cargo.toml del features.self-update
|
||
tomcli set crates/uv/Cargo.toml del features.tracing-durations-export
|
||
tomcli set crates/uv/Cargo.toml del dependencies.tracing-durations-export
|
||
|
||
# We retain the following example even when there are currently no dependencies
|
||
# that need to be adjusted.
|
||
#
|
||
# # foocrate
|
||
# # wanted: 0.2.0
|
||
# # currently packaged: 0.1.2
|
||
# # https://bugzilla.redhat.com/show_bug.cgi?id=1234567
|
||
# tomcli set Cargo.toml str workspace.dependencies.foocrate.version 0.1.2
|
||
|
||
# tikv-jemallocator
|
||
# wanted: 0.6.0
|
||
# currently packaged: 0.7.0
|
||
# https://github.com/astral-sh/uv/pull/19735
|
||
# We use sed instead of tomcli because the target.cfg(…) expression is a
|
||
# *mess*, and we don’t want to have to write it out here.
|
||
sed --regexp-extended --in-place \
|
||
's/^(tikv-jemallocator\b.*version = ")0\.6\.0"/\1>=0.6.0, <0.8.0"/' \
|
||
crates/uv-performance-memory-allocator/Cargo.toml
|
||
|
||
# blake2
|
||
# wanted: 0.11.0-rc.6
|
||
# currently packaged: 0.10.6
|
||
# https://github.com/astral-sh/uv/pull/19735
|
||
# Downstream-only: revert “Upgrade BLAKE2 to unify hashing digest versions”,
|
||
# https://github.com/astral-sh/uv/pull/20834. We do not wish to upgrade
|
||
# rust-blake2 to a pre-release. There is an anccompanying source-code patch.
|
||
tomcli set Cargo.toml str workspace.dependencies.blake2.version 0.10.6
|
||
|
||
%cargo_prep
|
||
|
||
|
||
%generate_buildrequires -p
|
||
# For unclear reasons, maturin checks for all crate dependencies when it is
|
||
# invoked as part of %%pyproject_buildrequires – including those corresponding
|
||
# to optional features.
|
||
#
|
||
# Furthermore, if we do not supply -a to %%cargo_generate_buildrequires, then
|
||
# maturin will fail looking for crates like pyo3 (and will still look for
|
||
# optional crate dependencies).
|
||
#
|
||
# Since maturin always checks for dev-dependencies, we need -t so that they are
|
||
# generated even when the “check” bcond is disabled.
|
||
%cargo_generate_buildrequires -a -t
|
||
|
||
|
||
%build -a
|
||
%{cargo_license_summary}
|
||
%{cargo_license} > LICENSE.dependencies
|
||
|
||
|
||
%install -a
|
||
if [ '%{python3_sitearch}' != '%{python3_sitelib}' ]
|
||
then
|
||
# Maturin is really designed to build compiled Python extensions, but (when
|
||
# the uv executable is not bundled in the Python package) the uv Python
|
||
# library is actually pure-Python, and the python3-uv subpackage can be
|
||
# noarch. We can’t tell maturin to install to the appropriate site-packages
|
||
# directory, but we can fix the installation path manually.
|
||
install --directory %{buildroot}%{python3_sitelib}
|
||
mv %{buildroot}%{python3_sitearch}/uv* %{buildroot}%{python3_sitelib}
|
||
sed --regexp-extended --in-place \
|
||
's@%{python3_sitearch}@%{python3_sitelib}@' %{pyproject_files}
|
||
fi
|
||
|
||
# generate and install shell completions
|
||
for cmd in uv uvx
|
||
do
|
||
target/rpm/${cmd} --generate-shell-completion bash > ${cmd}.bash
|
||
target/rpm/${cmd} --generate-shell-completion fish > ${cmd}.fish
|
||
target/rpm/${cmd} --generate-shell-completion zsh > _${cmd}
|
||
|
||
install -Dpm 0644 ${cmd}.bash -t %{buildroot}/%{bash_completions_dir}
|
||
install -Dpm 0644 ${cmd}.fish -t %{buildroot}/%{fish_completions_dir}
|
||
install -Dpm 0644 _${cmd} -t %{buildroot}/%{zsh_completions_dir}
|
||
done
|
||
|
||
# Install a default system-wide configuration file
|
||
install -D --preserve-timestamps --mode=0644 \
|
||
--target='%{buildroot}%{_sysconfdir}/uv' '%{SOURCE1}'
|
||
|
||
|
||
%check -a
|
||
%if %{with check}
|
||
# These tests rely on debug assertions, and fail when tests are compiled in
|
||
# release mode:
|
||
#
|
||
# cargo test -p uv-auth --lib:
|
||
skip="${skip-} --skip keyring::tests::fetch_url_no_host"
|
||
skip="${skip-} --skip keyring::tests::fetch_url_with_empty_username"
|
||
skip="${skip-} --skip keyring::tests::fetch_url_with_no_username"
|
||
skip="${skip-} --skip keyring::tests::fetch_url_with_password"
|
||
|
||
%if %{without other_python_versions}
|
||
# These tests require specific Python interpreter versions, which upstream
|
||
# normally downloads, precompiled, into the build area.
|
||
skip="${skip-} --skip version::self_version"
|
||
skip="${skip-} --skip version::self_version_json"
|
||
skip="${skip-} --skip version::self_version_short"
|
||
%endif
|
||
|
||
%ifnarch %{x86_64} %{arm64}
|
||
# On other architectures, the list of available downloads differs, e.g. pypy
|
||
# and graalpy downloads may be missing.
|
||
skip="${skip-} --skip python_list::python_list_downloads"
|
||
# Similarly, version numbers may not match exactly.
|
||
skip="${skip-} --skip python_list::python_list_with_mirrors"
|
||
%endif
|
||
%ifarch %{power64}
|
||
# The error message lacks the expected hint:
|
||
# hint: A managed Python download is available for PyPy, but Python downloads
|
||
# are set to 'never'
|
||
# This might be worth reporting upstream, but is not a serious issue.
|
||
skip="${skip-} --skip python_pin::python_pin_resolve"
|
||
%endif
|
||
%ifarch riscv64
|
||
# These expect managed interpreters of the form
|
||
# cpython-3.##-linux-riscv64gc-any, but crates/uv-python/download-metadata.json
|
||
# only has them for cpython-3.##-linux-riscv64-gnu. It’s not weird to find
|
||
# holes in the managed interpreter support matrix for less common
|
||
# architectures.
|
||
skip="${skip-} --skip python_find::python_find"
|
||
skip="${skip-} --skip python_list::python_list"
|
||
skip="${skip-} --skip python_pin::python_pin_resolve"
|
||
%endif
|
||
|
||
# It’s not clear what causes the trivial discrepancy, but we find that this
|
||
# fails when building in qemu-user-static emulated chroots.
|
||
# 4 │- Caused by: Failed to query Python interpreter at `[TEMP_DIR]/bar`
|
||
# 5 │- Caused by: [PERMISSION DENIED]
|
||
# 4 │+ Caused by: Querying Python at `[TEMP_DIR]/bar` failed with
|
||
# exit status exit status: 127
|
||
skip="${skip-} --skip python_find::python_find_path"
|
||
|
||
# Test registry_client::tests::test_redirect_to_server_with_credentials is
|
||
# flaky
|
||
# https://github.com/astral-sh/uv/issues/16447
|
||
skip="${skip-} --skip registry_client::tests::test_redirect_to_server_with_credentials"
|
||
|
||
# This requires specific Python interpreter versions (so it would be grouped
|
||
# with the conditionalized integration tests above), but it also requires
|
||
# network access to PyPI, so it must be skipped either way until it can be
|
||
# appropriately conditionalized upstream; see
|
||
# https://github.com/astral-sh/uv/pull/13699#issuecomment-2916115588.
|
||
skip="${skip-} --skip remote_metadata::remote_metadata_with_and_without_cache"
|
||
|
||
# Upstream is trying to ensure platform-independent byte-for-byte deterministic
|
||
# wheels. This isn’t quite working out. It would be nice to understand this,
|
||
# but this kind of reproducibility can be brittle, and there are many possible
|
||
# innocuous reasons behind it.
|
||
# ---- tests::built_by_uv_building stdout ----
|
||
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Snapshot Summary ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
# Snapshot: built_by_uv_building-4
|
||
# Source: crates/uv-build-backend/src/lib.rs:652
|
||
# ────────────────────────────────────────────────────────────────────────────────
|
||
# Expression: format!("{:x}", sha2::Sha256::digest(fs_err::read(&wheel_path).unwrap()))
|
||
# ────────────────────────────────────────────────────────────────────────────────
|
||
# -old snapshot
|
||
# +new results
|
||
# ────────────┬───────────────────────────────────────────────────────────────────
|
||
# 1 │-319afb04e87caf894b1362b508ec745253c6d241423ea59021694d2015e821da
|
||
# 1 │+007327b23085c5debf31fb44df7a2294b5882aefdba960bdd68fab665db12c5a
|
||
# ────────────┴───────────────────────────────────────────────────────────────────
|
||
skip="${skip-} --skip tests::built_by_uv_building"
|
||
|
||
# The list of HTTP status codes contains 103, but the expected list from the
|
||
# snapshot doesn’t. This seems like a trivial discrepancy, probably due to a
|
||
# dependency version differing from Cargo.lock.
|
||
skip="${skip-} --skip base_client::tests::retried_status_codes"
|
||
|
||
# Harmless and trivial discrepancies in error messages:
|
||
# 8 │- Caused by: error decoding response body for url (http://[LOCALHOST]/tqdm/)
|
||
# 8 │+ Caused by: error decoding response body
|
||
skip="${skip-} --skip network::retry_read_timeout_index"
|
||
# 9 │- Caused by: error decoding response body for url (http://[LOCALHOST]/)
|
||
# 9 │+ Caused by: error decoding response body
|
||
skip="${skip-} --skip network::retry_read_timeout_python_downloads_json"
|
||
|
||
# These fail flakily: most frequently on ppc64le, but this seems to be just a
|
||
# matter of luck, since we suspect a race condition. We have also seen failures
|
||
# on aarch64. This is probably a race involving the SSL_CERT_FILE environment
|
||
# variable, which process-isolated testing in “cargo nextest” (used by
|
||
# upstream) should avoid. That suggests there is nothing to report upstream.
|
||
# When this fails, the error looks something like:
|
||
# Error: failed to build HTTP client
|
||
# Caused by:
|
||
# 0: certificate in `/tmp/uv/tests/certs/.tmpFF0lkk/ca.pem` (from
|
||
# `SSL_CERT_FILE`) could not be used as a trust anchor on certificate
|
||
# `CN=uv-test-ca, O=Astral Software Inc.`
|
||
# 1: ExtensionValueInvalid
|
||
skip="${skip-} --skip user_agent_version::test_user_agent_has_linehaul"
|
||
skip="${skip-} --skip user_agent_version::test_user_agent_has_subcommand"
|
||
skip="${skip-} --skip user_agent_version::test_user_agent_has_version"
|
||
# Similarly, with an error like:
|
||
# Client::new(): reqwest::Error {
|
||
# kind: Builder,
|
||
# source: General("No CA certificates were loaded from the system")
|
||
# }
|
||
# There are probably more of these.
|
||
skip="${skip-} --skip retry::tests::retried_status_codes"
|
||
|
||
%cargo_test -- -- --exact ${skip-}
|
||
%endif
|
||
|
||
|
||
%files
|
||
%license LICENSE-APACHE LICENSE-MIT LICENSE.dependencies LICENSE.bundled/
|
||
%doc CHANGELOG.md
|
||
%doc README.md
|
||
|
||
%{_bindir}/uv
|
||
# Equivalent to “uv tool run”:
|
||
%{_bindir}/uvx
|
||
|
||
%{bash_completions_dir}/{uv,uvx}.bash
|
||
%{fish_completions_dir}/{uv,uvx}.fish
|
||
%{zsh_completions_dir}/_{uv,uvx}
|
||
|
||
%dir %{_sysconfdir}/uv
|
||
%config(noreplace) %{_sysconfdir}/uv/uv.toml
|
||
|
||
|
||
%files -n python3-uv -f %{pyproject_files}
|
||
|
||
|
||
%changelog
|
||
%autochangelog
|