Skip to main content

uv_distribution/
download.rs

1use std::path::Path;
2
3use uv_cache_info::CacheInfo;
4use uv_distribution_filename::WheelFilename;
5use uv_distribution_types::{BuildInfo, BuiltDist, CachedDist, Dist, Hashed};
6use uv_metadata::{find_flat_dist_info, read_flat_wheel_metadata, read_wheel_variant};
7use uv_preview::PreviewFeature;
8use uv_pypi_types::{HashDigest, HashDigests, ResolutionMetadata};
9
10use crate::Error;
11
12/// Allow variant wheels from an index when the wheel variants preview is enabled.
13pub fn check_supported_wheel_variant(dist: &BuiltDist) -> Result<(), Error> {
14    let filename = dist.wheel_filename();
15    if filename.variant().is_some()
16        && (dist.index().is_none() || !uv_preview::is_enabled(PreviewFeature::WheelVariants))
17    {
18        return Err(Error::UnsupportedWheelVariant(Box::new(filename.clone())));
19    }
20    Ok(())
21}
22
23/// Whether an extracted wheel's variant properties are supported by the target system.
24pub(crate) fn variant_compatible(filename: &WheelFilename, archive: &Path) -> Result<bool, Error> {
25    let Some(label) = filename.variant() else {
26        return Ok(true);
27    };
28    if !uv_preview::is_enabled(PreviewFeature::WheelVariants) {
29        return Ok(false);
30    }
31
32    let dist_info = find_flat_dist_info(filename, archive)
33        .map_err(|err| Error::WheelMetadata(archive.to_path_buf(), Box::new(err)))?;
34    let path = archive.join(format!("{dist_info}.dist-info/variant.json"));
35    let metadata = read_wheel_variant(&path, label)
36        .map_err(|err| Error::WheelMetadata(path, Box::new(err)))?;
37    Ok(metadata
38        .score_variant(label, &metadata.static_supported_properties())
39        .is_some())
40}
41
42/// A locally available wheel.
43#[derive(Debug, Clone)]
44pub struct LocalWheel {
45    /// The remote distribution from which this wheel was downloaded.
46    pub(crate) dist: Dist,
47    /// The parsed filename.
48    pub(crate) filename: WheelFilename,
49    /// The canonicalized path in the cache directory to which the wheel was downloaded.
50    /// Typically, a directory within the archive bucket.
51    pub(crate) archive: Box<Path>,
52    /// The cache info of the wheel.
53    pub(crate) cache: CacheInfo,
54    /// The build info, if available.
55    pub(crate) build: Option<BuildInfo>,
56    /// The computed hashes of the wheel.
57    pub(crate) hashes: HashDigests,
58}
59
60impl LocalWheel {
61    /// Return the [`Dist`] from which this wheel was downloaded.
62    fn remote(&self) -> &Dist {
63        &self.dist
64    }
65
66    /// Read the [`ResolutionMetadata`] from a wheel.
67    pub(crate) fn metadata(&self) -> Result<ResolutionMetadata, Error> {
68        read_flat_wheel_metadata(&self.filename, &self.archive)
69            .map_err(|err| Error::WheelMetadata(self.archive.to_path_buf(), Box::new(err)))
70    }
71}
72
73impl Hashed for LocalWheel {
74    fn hashes(&self) -> &[HashDigest] {
75        self.hashes.as_slice()
76    }
77}
78
79/// Convert a [`LocalWheel`] into a [`CachedDist`].
80impl From<LocalWheel> for CachedDist {
81    fn from(wheel: LocalWheel) -> Self {
82        Self::from_remote(
83            wheel.dist,
84            wheel.filename,
85            wheel.hashes,
86            wheel.cache,
87            wheel.build,
88            wheel.archive,
89        )
90    }
91}
92
93impl std::fmt::Display for LocalWheel {
94    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95        write!(f, "{}", self.remote())
96    }
97}