1use std::path::Path;
2
3use either::Either;
4use rustc_hash::FxHashMap;
5
6use uv_cache::Refresh;
7use uv_cache_info::Timestamp;
8use uv_distribution_types::Requirement;
9use uv_normalize::PackageName;
10
11#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)]
13#[serde(rename_all = "kebab-case", deny_unknown_fields)]
14pub enum Reinstall {
15 #[default]
17 None,
18
19 All,
21
22 Packages(Vec<PackageName>, Vec<Box<Path>>),
24}
25
26impl Reinstall {
27 pub fn from_args(reinstall: Option<bool>, reinstall_package: Vec<PackageName>) -> Option<Self> {
29 match reinstall {
30 Some(true) => Some(Self::All),
31 Some(false) => Some(Self::None),
32 None if reinstall_package.is_empty() => None,
33 None => Some(Self::Packages(reinstall_package, Vec::new())),
34 }
35 }
36
37 pub fn is_none(&self) -> bool {
39 matches!(self, Self::None)
40 }
41
42 pub fn is_all(&self) -> bool {
44 matches!(self, Self::All)
45 }
46
47 pub fn contains_package(&self, package_name: &PackageName) -> bool {
49 match self {
50 Self::None => false,
51 Self::All => true,
52 Self::Packages(packages, ..) => packages.contains(package_name),
53 }
54 }
55
56 pub fn contains_path(&self, path: &Path) -> bool {
58 match self {
59 Self::None => false,
60 Self::All => true,
61 Self::Packages(.., paths) => paths
62 .iter()
63 .any(|target| same_file::is_same_file(path, target).unwrap_or(false)),
64 }
65 }
66
67 #[must_use]
69 pub fn combine(self, other: Self) -> Self {
70 match self {
71 Self::All | Self::None => self,
73 Self::Packages(self_packages, self_paths) => match other {
74 Self::All => other,
76 Self::None => Self::Packages(self_packages, self_paths),
78 Self::Packages(other_packages, other_paths) => {
80 let mut combined_packages = self_packages;
81 combined_packages.extend(other_packages);
82 let mut combined_paths = self_paths;
83 combined_paths.extend(other_paths);
84 Self::Packages(combined_packages, combined_paths)
85 }
86 },
87 }
88 }
89
90 #[must_use]
92 pub fn with_path(self, path: Box<Path>) -> Self {
93 match self {
94 Self::None => Self::Packages(vec![], vec![path]),
95 Self::All => Self::All,
96 Self::Packages(packages, mut paths) => {
97 paths.push(path);
98 Self::Packages(packages, paths)
99 }
100 }
101 }
102
103 #[must_use]
105 pub fn with_package(self, package_name: PackageName) -> Self {
106 match self {
107 Self::None => Self::Packages(vec![package_name], vec![]),
108 Self::All => Self::All,
109 Self::Packages(mut packages, paths) => {
110 packages.push(package_name);
111 Self::Packages(packages, paths)
112 }
113 }
114 }
115
116 pub fn package(package_name: PackageName) -> Self {
118 Self::Packages(vec![package_name], vec![])
119 }
120}
121
122impl From<Reinstall> for Refresh {
124 fn from(value: Reinstall) -> Self {
125 match value {
126 Reinstall::None => Self::None(Timestamp::now()),
127 Reinstall::All => Self::All(Timestamp::now()),
128 Reinstall::Packages(packages, paths) => {
129 Self::Packages(packages, paths, Timestamp::now())
130 }
131 }
132 }
133}
134
135#[derive(Debug, Default, Clone)]
137pub enum Upgrade {
138 #[default]
140 None,
141
142 All,
144
145 Packages(FxHashMap<PackageName, Vec<Requirement>>),
147}
148
149impl Upgrade {
150 pub fn from_args(upgrade: Option<bool>, upgrade_package: Vec<Requirement>) -> Option<Self> {
152 match upgrade {
153 Some(true) => Some(Self::All),
154 Some(false) => Some(Self::None),
157 None if upgrade_package.is_empty() => None,
158 None => Some(Self::Packages(upgrade_package.into_iter().fold(
159 FxHashMap::default(),
160 |mut map, requirement| {
161 map.entry(requirement.name.clone())
162 .or_default()
163 .push(requirement);
164 map
165 },
166 ))),
167 }
168 }
169
170 pub fn package(package_name: PackageName) -> Self {
172 Self::Packages({
173 let mut map = FxHashMap::default();
174 map.insert(package_name, vec![]);
175 map
176 })
177 }
178
179 pub fn is_none(&self) -> bool {
181 matches!(self, Self::None)
182 }
183
184 pub fn is_all(&self) -> bool {
186 matches!(self, Self::All)
187 }
188
189 pub fn contains(&self, package_name: &PackageName) -> bool {
191 match self {
192 Self::None => false,
193 Self::All => true,
194 Self::Packages(packages) => packages.contains_key(package_name),
195 }
196 }
197
198 pub fn constraints(&self) -> impl Iterator<Item = &Requirement> {
202 if let Self::Packages(packages) = self {
203 Either::Right(
204 packages
205 .values()
206 .flat_map(|requirements| requirements.iter()),
207 )
208 } else {
209 Either::Left(std::iter::empty())
210 }
211 }
212
213 #[must_use]
215 pub fn combine(self, other: Self) -> Self {
216 match self {
217 Self::All | Self::None => self,
219 Self::Packages(self_packages) => match other {
220 Self::All => other,
222 Self::None => Self::Packages(self_packages),
224 Self::Packages(other_packages) => {
226 let mut combined = self_packages;
227 for (package, requirements) in other_packages {
228 combined.entry(package).or_default().extend(requirements);
229 }
230 Self::Packages(combined)
231 }
232 },
233 }
234 }
235}
236
237impl From<Upgrade> for Refresh {
239 fn from(value: Upgrade) -> Self {
240 match value {
241 Upgrade::None => Self::None(Timestamp::now()),
242 Upgrade::All => Self::All(Timestamp::now()),
243 Upgrade::Packages(packages) => Self::Packages(
244 packages.into_keys().collect::<Vec<_>>(),
245 Vec::new(),
246 Timestamp::now(),
247 ),
248 }
249 }
250}
251
252#[derive(Debug, Default, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
254#[serde(rename_all = "kebab-case", deny_unknown_fields)]
255#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
256pub enum BuildIsolation {
257 #[default]
259 Isolate,
260
261 Shared,
263
264 SharedPackage(Vec<PackageName>),
266}
267
268impl BuildIsolation {
269 pub fn from_args(
271 no_build_isolation: Option<bool>,
272 no_build_isolation_package: Vec<PackageName>,
273 ) -> Option<Self> {
274 match no_build_isolation {
275 Some(true) => Some(Self::Shared),
276 Some(false) => Some(Self::Isolate),
277 None if no_build_isolation_package.is_empty() => None,
278 None => Some(Self::SharedPackage(no_build_isolation_package)),
279 }
280 }
281
282 #[must_use]
284 pub fn combine(self, other: Self) -> Self {
285 match self {
286 Self::Isolate | Self::Shared => self,
288 Self::SharedPackage(self_packages) => match other {
289 Self::Shared => other,
291 Self::Isolate => Self::SharedPackage(self_packages),
293 Self::SharedPackage(other_packages) => {
295 let mut combined = self_packages;
296 combined.extend(other_packages);
297 Self::SharedPackage(combined)
298 }
299 },
300 }
301 }
302}