Skip to main content

uv_distribution_filename/
lib.rs

1use std::fmt::{Display, Formatter};
2use std::str::FromStr;
3
4use uv_normalize::PackageName;
5use uv_pep440::Version;
6
7pub use build_tag::{BuildTag, BuildTagError};
8pub use egg::{EggInfoFilename, EggInfoFilenameError};
9pub use expanded_tags::{ExpandedTagError, ExpandedTags};
10pub use extension::{DistExtension, ExtensionError, SourceDistExtension};
11pub use source_dist::{SourceDistFilename, SourceDistFilenameError};
12pub use wheel::{WheelFilename, WheelFilenameError};
13
14mod build_tag;
15mod egg;
16mod expanded_tags;
17mod extension;
18mod source_dist;
19mod splitter;
20mod wheel;
21mod wheel_tag;
22
23#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
24pub enum DistFilename {
25    SourceDistFilename(SourceDistFilename),
26    WheelFilename(WheelFilename),
27}
28
29impl DistFilename {
30    /// Parse a filename as wheel or source dist name.
31    pub fn try_from_filename(filename: &str, package_name: &PackageName) -> Option<Self> {
32        match DistExtension::from_path(filename) {
33            Ok(DistExtension::Wheel) => {
34                if let Ok(filename) = WheelFilename::from_str(filename) {
35                    return Some(Self::WheelFilename(filename));
36                }
37            }
38            Ok(DistExtension::Source(extension)) => {
39                if let Ok(filename) = SourceDistFilename::parse(filename, extension, package_name) {
40                    return Some(Self::SourceDistFilename(filename));
41                }
42            }
43            Err(_) => {}
44        }
45        None
46    }
47
48    /// Like [`DistFilename::try_from_normalized_filename`], but without knowing the package name.
49    ///
50    /// Source dist filenames can be ambiguous, e.g. `a-1-1.tar.gz`. Without knowing the package name, we assume that
51    /// source dist filename version doesn't contain minus (the version is normalized).
52    pub fn try_from_normalized_filename(filename: &str) -> Option<Self> {
53        if let Ok(filename) = WheelFilename::from_str(filename) {
54            Some(Self::WheelFilename(filename))
55        } else if let Ok(filename) = SourceDistFilename::parsed_normalized_filename(filename) {
56            Some(Self::SourceDistFilename(filename))
57        } else {
58            None
59        }
60    }
61
62    pub fn name(&self) -> &PackageName {
63        match self {
64            Self::SourceDistFilename(filename) => &filename.name,
65            Self::WheelFilename(filename) => &filename.name,
66        }
67    }
68
69    pub fn version(&self) -> &Version {
70        match self {
71            Self::SourceDistFilename(filename) => &filename.version,
72            Self::WheelFilename(filename) => &filename.version,
73        }
74    }
75
76    pub fn into_version(self) -> Version {
77        match self {
78            Self::SourceDistFilename(filename) => filename.version,
79            Self::WheelFilename(filename) => filename.version,
80        }
81    }
82
83    /// Whether the file is a `bdist_wheel` or an `sdist`.
84    pub fn filetype(&self) -> &'static str {
85        match self {
86            Self::SourceDistFilename(_) => "sdist",
87            Self::WheelFilename(_) => "bdist_wheel",
88        }
89    }
90}
91
92impl Display for DistFilename {
93    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
94        match self {
95            Self::SourceDistFilename(filename) => Display::fmt(filename, f),
96            Self::WheelFilename(filename) => Display::fmt(filename, f),
97        }
98    }
99}
100
101#[cfg(test)]
102mod tests {
103    use crate::WheelFilename;
104
105    #[test]
106    fn wheel_filename_size() {
107        assert_eq!(size_of::<WheelFilename>(), 48);
108    }
109}