1use std::borrow::Cow;
2use std::path::Path;
3
4use uv_distribution_filename::SourceDistExtension;
5use uv_git_types::GitUrl;
6use uv_pep440::{Version, VersionSpecifiers};
7use uv_pep508::VerbatimUrl;
8
9use uv_normalize::PackageName;
10use uv_redacted::DisplaySafeUrl;
11
12use crate::{DirectorySourceDist, GitSourceDist, Name, PathSourceDist, SourceDist};
13
14#[derive(Debug, Clone)]
21pub enum BuildableSource<'a> {
22 Dist(&'a SourceDist),
23 Url(SourceUrl<'a>),
24}
25
26impl BuildableSource<'_> {
27 pub fn name(&self) -> Option<&PackageName> {
29 match self {
30 Self::Dist(dist) => Some(dist.name()),
31 Self::Url(_) => None,
32 }
33 }
34
35 pub fn source_tree(&self) -> Option<&Path> {
37 match self {
38 Self::Dist(dist) => dist.source_tree(),
39 Self::Url(url) => url.source_tree(),
40 }
41 }
42
43 pub fn version(&self) -> Option<&Version> {
45 match self {
46 Self::Dist(SourceDist::Registry(dist)) => Some(&dist.version),
47 Self::Dist(SourceDist::Path(dist)) => dist.version.as_ref(),
48 Self::Dist(_) => None,
49 Self::Url(_) => None,
50 }
51 }
52
53 pub fn as_dist(&self) -> Option<&SourceDist> {
55 match self {
56 Self::Dist(dist) => Some(dist),
57 Self::Url(_) => None,
58 }
59 }
60
61 pub fn is_editable(&self) -> bool {
63 match self {
64 Self::Dist(dist) => dist.is_editable(),
65 Self::Url(url) => url.is_editable(),
66 }
67 }
68
69 pub fn is_source_tree(&self) -> bool {
71 match self {
72 Self::Dist(dist) => matches!(dist, SourceDist::Directory(_)),
73 Self::Url(url) => matches!(url, SourceUrl::Directory(_)),
74 }
75 }
76
77 pub fn requires_python(&self) -> Option<&VersionSpecifiers> {
79 let Self::Dist(SourceDist::Registry(dist)) = self else {
80 return None;
81 };
82 dist.file.requires_python.as_ref()
83 }
84}
85
86impl std::fmt::Display for BuildableSource<'_> {
87 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88 match self {
89 Self::Dist(dist) => write!(f, "{dist}"),
90 Self::Url(url) => write!(f, "{url}"),
91 }
92 }
93}
94
95#[derive(Debug, Clone)]
97pub enum SourceUrl<'a> {
98 Direct(DirectSourceUrl<'a>),
99 Git(GitSourceUrl<'a>),
100 Path(PathSourceUrl<'a>),
101 Directory(DirectorySourceUrl<'a>),
102}
103
104impl SourceUrl<'_> {
105 pub fn url(&self) -> &DisplaySafeUrl {
107 match self {
108 Self::Direct(dist) => dist.url,
109 Self::Git(dist) => dist.url,
110 Self::Path(dist) => dist.url,
111 Self::Directory(dist) => dist.url,
112 }
113 }
114
115 pub fn source_tree(&self) -> Option<&Path> {
117 match self {
118 Self::Directory(dist) => Some(&dist.install_path),
119 _ => None,
120 }
121 }
122
123 pub fn is_editable(&self) -> bool {
125 matches!(
126 self,
127 Self::Directory(DirectorySourceUrl {
128 editable: Some(true),
129 ..
130 })
131 )
132 }
133
134 pub fn is_local(&self) -> bool {
136 matches!(self, Self::Path(_) | Self::Directory(_))
137 }
138}
139
140impl std::fmt::Display for SourceUrl<'_> {
141 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
142 match self {
143 Self::Direct(url) => write!(f, "{url}"),
144 Self::Git(url) => write!(f, "{url}"),
145 Self::Path(url) => write!(f, "{url}"),
146 Self::Directory(url) => write!(f, "{url}"),
147 }
148 }
149}
150
151#[derive(Debug, Clone)]
152pub struct DirectSourceUrl<'a> {
153 pub url: &'a DisplaySafeUrl,
154 pub subdirectory: Option<&'a Path>,
155 pub ext: SourceDistExtension,
156}
157
158impl std::fmt::Display for DirectSourceUrl<'_> {
159 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
160 write!(f, "{url}", url = self.url)
161 }
162}
163
164#[derive(Debug, Clone)]
165pub struct GitSourceUrl<'a> {
166 pub url: &'a VerbatimUrl,
168 pub git: &'a GitUrl,
169 pub subdirectory: Option<&'a Path>,
171}
172
173impl std::fmt::Display for GitSourceUrl<'_> {
174 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
175 write!(f, "{url}", url = self.url)
176 }
177}
178
179impl<'a> From<&'a GitSourceDist> for GitSourceUrl<'a> {
180 fn from(dist: &'a GitSourceDist) -> Self {
181 Self {
182 url: &dist.url,
183 git: &dist.git,
184 subdirectory: dist.subdirectory.as_deref(),
185 }
186 }
187}
188
189#[derive(Debug, Clone)]
190pub struct PathSourceUrl<'a> {
191 pub url: &'a DisplaySafeUrl,
192 pub path: Cow<'a, Path>,
193 pub ext: SourceDistExtension,
194}
195
196impl std::fmt::Display for PathSourceUrl<'_> {
197 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
198 write!(f, "{url}", url = self.url)
199 }
200}
201
202impl<'a> From<&'a PathSourceDist> for PathSourceUrl<'a> {
203 fn from(dist: &'a PathSourceDist) -> Self {
204 Self {
205 url: &dist.url,
206 path: Cow::Borrowed(&dist.install_path),
207 ext: dist.ext,
208 }
209 }
210}
211
212#[derive(Debug, Clone)]
213pub struct DirectorySourceUrl<'a> {
214 pub url: &'a DisplaySafeUrl,
215 pub install_path: Cow<'a, Path>,
216 pub editable: Option<bool>,
217}
218
219impl std::fmt::Display for DirectorySourceUrl<'_> {
220 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
221 write!(f, "{url}", url = self.url)
222 }
223}
224
225impl<'a> From<&'a DirectorySourceDist> for DirectorySourceUrl<'a> {
226 fn from(dist: &'a DirectorySourceDist) -> Self {
227 Self {
228 url: &dist.url,
229 install_path: Cow::Borrowed(&dist.install_path),
230 editable: dist.editable,
231 }
232 }
233}