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 fn source_tree(&self) -> Option<&Path> {
122 match self {
123 Self::Directory(dist) => Some(dist.install_path),
124 _ => None,
125 }
126 }
127
128 fn is_editable(&self) -> bool {
130 matches!(
131 self,
132 Self::Directory(DirectorySourceUrl {
133 editable: Some(true),
134 ..
135 })
136 )
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::GitDirectory(url) => write!(f, "{url}"),
145 Self::GitPath(url) => write!(f, "{url}"),
146 Self::Path(url) => write!(f, "{url}"),
147 Self::Directory(url) => write!(f, "{url}"),
148 }
149 }
150}
151
152#[derive(Debug, Clone)]
153pub struct DirectSourceUrl<'a> {
154 pub url: &'a DisplaySafeUrl,
155 pub subdirectory: Option<&'a Path>,
156 pub ext: SourceDistExtension,
157}
158
159impl std::fmt::Display for DirectSourceUrl<'_> {
160 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
161 write!(f, "{url}", url = self.url)
162 }
163}
164
165#[derive(Debug, Clone)]
166pub struct GitPathSourceUrl<'a> {
167 pub url: &'a VerbatimUrl,
169 pub git: &'a GitUrl,
170 pub path: Cow<'a, Path>,
171 pub ext: SourceDistExtension,
172}
173
174impl std::fmt::Display for GitPathSourceUrl<'_> {
175 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
176 write!(f, "{url}", url = self.url)
177 }
178}
179
180impl<'a> From<&'a GitPathSourceDist> for GitPathSourceUrl<'a> {
181 fn from(dist: &'a GitPathSourceDist) -> Self {
182 Self {
183 url: &dist.url,
184 git: &dist.git,
185 path: Cow::Borrowed(&dist.install_path),
186 ext: dist.ext,
187 }
188 }
189}
190
191#[derive(Debug, Clone)]
192pub struct GitDirectorySourceUrl<'a> {
193 pub url: &'a VerbatimUrl,
195 pub git: &'a GitUrl,
196 pub subdirectory: Option<&'a Path>,
198}
199
200impl std::fmt::Display for GitDirectorySourceUrl<'_> {
201 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
202 write!(f, "{url}", url = self.url)
203 }
204}
205
206impl<'a> From<&'a GitDirectorySourceDist> for GitDirectorySourceUrl<'a> {
207 fn from(dist: &'a GitDirectorySourceDist) -> Self {
208 Self {
209 url: &dist.url,
210 git: &dist.git,
211 subdirectory: dist.subdirectory.as_deref(),
212 }
213 }
214}
215
216#[derive(Debug, Clone)]
217pub struct PathSourceUrl<'a> {
218 pub url: &'a DisplaySafeUrl,
219 pub path: Cow<'a, Path>,
220 pub ext: SourceDistExtension,
221}
222
223impl std::fmt::Display for PathSourceUrl<'_> {
224 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
225 write!(f, "{url}", url = self.url)
226 }
227}
228
229impl<'a> From<&'a PathSourceDist> for PathSourceUrl<'a> {
230 fn from(dist: &'a PathSourceDist) -> Self {
231 Self {
232 url: &dist.url,
233 path: Cow::Borrowed(&dist.install_path),
234 ext: dist.ext,
235 }
236 }
237}
238
239#[derive(Debug, Clone)]
240pub struct DirectorySourceUrl<'a> {
241 pub url: &'a DisplaySafeUrl,
242 pub install_path: &'a Path,
243 pub editable: Option<bool>,
244}
245
246impl std::fmt::Display for DirectorySourceUrl<'_> {
247 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
248 write!(f, "{url}", url = self.url)
249 }
250}
251
252impl<'a> From<&'a DirectorySourceDist> for DirectorySourceUrl<'a> {
253 fn from(dist: &'a DirectorySourceDist) -> Self {
254 Self {
255 url: &dist.url,
256 install_path: &dist.install_path,
257 editable: dist.editable,
258 }
259 }
260}