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::{
13 DirectorySourceDist, GitDirectorySourceDist, GitPathSourceDist, Name, PathSourceDist,
14 SourceDist,
15};
16
17#[derive(Debug, Clone)]
24pub enum BuildableSource<'a> {
25 Dist(&'a SourceDist),
26 Url(SourceUrl<'a>),
27}
28
29impl BuildableSource<'_> {
30 pub fn name(&self) -> Option<&PackageName> {
32 match self {
33 Self::Dist(dist) => Some(dist.name()),
34 Self::Url(_) => None,
35 }
36 }
37
38 pub fn source_tree(&self) -> Option<&Path> {
40 match self {
41 Self::Dist(dist) => dist.source_tree(),
42 Self::Url(url) => url.source_tree(),
43 }
44 }
45
46 pub fn version(&self) -> Option<&Version> {
48 match self {
49 Self::Dist(SourceDist::Registry(dist)) => Some(&dist.version),
50 Self::Dist(SourceDist::Path(dist)) => dist.version.as_ref(),
51 Self::Dist(_) => None,
52 Self::Url(_) => None,
53 }
54 }
55
56 pub fn as_dist(&self) -> Option<&SourceDist> {
58 match self {
59 Self::Dist(dist) => Some(dist),
60 Self::Url(_) => None,
61 }
62 }
63
64 pub fn is_editable(&self) -> bool {
66 match self {
67 Self::Dist(dist) => dist.is_editable(),
68 Self::Url(url) => url.is_editable(),
69 }
70 }
71
72 pub fn is_source_tree(&self) -> bool {
74 match self {
75 Self::Dist(dist) => matches!(dist, SourceDist::Directory(_)),
76 Self::Url(url) => matches!(url, SourceUrl::Directory(_)),
77 }
78 }
79
80 pub fn requires_python(&self) -> Option<&VersionSpecifiers> {
82 let Self::Dist(SourceDist::Registry(dist)) = self else {
83 return None;
84 };
85 dist.file.requires_python.as_ref()
86 }
87}
88
89impl std::fmt::Display for BuildableSource<'_> {
90 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91 match self {
92 Self::Dist(dist) => write!(f, "{dist}"),
93 Self::Url(url) => write!(f, "{url}"),
94 }
95 }
96}
97
98#[derive(Debug, Clone)]
100pub enum SourceUrl<'a> {
101 Direct(DirectSourceUrl<'a>),
102 GitDirectory(GitDirectorySourceUrl<'a>),
103 GitPath(GitPathSourceUrl<'a>),
104 Path(PathSourceUrl<'a>),
105 Directory(DirectorySourceUrl<'a>),
106}
107
108impl SourceUrl<'_> {
109 pub fn url(&self) -> &DisplaySafeUrl {
111 match self {
112 Self::Direct(dist) => dist.url,
113 Self::GitDirectory(dist) => dist.url,
114 Self::GitPath(dist) => dist.url,
115 Self::Path(dist) => dist.url,
116 Self::Directory(dist) => dist.url,
117 }
118 }
119
120 pub fn source_tree(&self) -> Option<&Path> {
122 match self {
123 Self::Directory(dist) => Some(dist.install_path),
124 _ => None,
125 }
126 }
127
128 pub fn is_editable(&self) -> bool {
130 matches!(
131 self,
132 Self::Directory(DirectorySourceUrl {
133 editable: Some(true),
134 ..
135 })
136 )
137 }
138
139 pub fn is_local(&self) -> bool {
141 matches!(self, Self::Path(_) | Self::Directory(_))
142 }
143}
144
145impl std::fmt::Display for SourceUrl<'_> {
146 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
147 match self {
148 Self::Direct(url) => write!(f, "{url}"),
149 Self::GitDirectory(url) => write!(f, "{url}"),
150 Self::GitPath(url) => write!(f, "{url}"),
151 Self::Path(url) => write!(f, "{url}"),
152 Self::Directory(url) => write!(f, "{url}"),
153 }
154 }
155}
156
157#[derive(Debug, Clone)]
158pub struct DirectSourceUrl<'a> {
159 pub url: &'a DisplaySafeUrl,
160 pub subdirectory: Option<&'a Path>,
161 pub ext: SourceDistExtension,
162}
163
164impl std::fmt::Display for DirectSourceUrl<'_> {
165 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
166 write!(f, "{url}", url = self.url)
167 }
168}
169
170#[derive(Debug, Clone)]
171pub struct GitPathSourceUrl<'a> {
172 pub url: &'a VerbatimUrl,
174 pub git: &'a GitUrl,
175 pub path: Cow<'a, Path>,
176 pub ext: SourceDistExtension,
177}
178
179impl std::fmt::Display for GitPathSourceUrl<'_> {
180 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
181 write!(f, "{url}", url = self.url)
182 }
183}
184
185impl<'a> From<&'a GitPathSourceDist> for GitPathSourceUrl<'a> {
186 fn from(dist: &'a GitPathSourceDist) -> Self {
187 Self {
188 url: &dist.url,
189 git: &dist.git,
190 path: Cow::Borrowed(&dist.install_path),
191 ext: dist.ext,
192 }
193 }
194}
195
196#[derive(Debug, Clone)]
197pub struct GitDirectorySourceUrl<'a> {
198 pub url: &'a VerbatimUrl,
200 pub git: &'a GitUrl,
201 pub subdirectory: Option<&'a Path>,
203}
204
205impl std::fmt::Display for GitDirectorySourceUrl<'_> {
206 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
207 write!(f, "{url}", url = self.url)
208 }
209}
210
211impl<'a> From<&'a GitDirectorySourceDist> for GitDirectorySourceUrl<'a> {
212 fn from(dist: &'a GitDirectorySourceDist) -> Self {
213 Self {
214 url: &dist.url,
215 git: &dist.git,
216 subdirectory: dist.subdirectory.as_deref(),
217 }
218 }
219}
220
221#[derive(Debug, Clone)]
222pub struct PathSourceUrl<'a> {
223 pub url: &'a DisplaySafeUrl,
224 pub path: Cow<'a, Path>,
225 pub ext: SourceDistExtension,
226}
227
228impl std::fmt::Display for PathSourceUrl<'_> {
229 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
230 write!(f, "{url}", url = self.url)
231 }
232}
233
234impl<'a> From<&'a PathSourceDist> for PathSourceUrl<'a> {
235 fn from(dist: &'a PathSourceDist) -> Self {
236 Self {
237 url: &dist.url,
238 path: Cow::Borrowed(&dist.install_path),
239 ext: dist.ext,
240 }
241 }
242}
243
244#[derive(Debug, Clone)]
245pub struct DirectorySourceUrl<'a> {
246 pub url: &'a DisplaySafeUrl,
247 pub install_path: &'a Path,
248 pub editable: Option<bool>,
249}
250
251impl std::fmt::Display for DirectorySourceUrl<'_> {
252 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
253 write!(f, "{url}", url = self.url)
254 }
255}
256
257impl<'a> From<&'a DirectorySourceDist> for DirectorySourceUrl<'a> {
258 fn from(dist: &'a DirectorySourceDist) -> Self {
259 Self {
260 url: &dist.url,
261 install_path: &dist.install_path,
262 editable: dist.editable,
263 }
264 }
265}