1use uv_configuration::{
2 BuildIsolation, BuildOptions, ExcludeNewer, ForkStrategy, HashCheckingMode, IndexStrategy,
3 KeyringProviderType, NoBinary, NoBuild, NoSources, Prerelease, PrereleaseMode,
4 PrereleasePackage, Reinstall, ResolutionMode, Upgrade,
5};
6use uv_distribution_types::{
7 ConfigSettings, DependencyMetadata, ExtraBuildVariables, IndexLocations, PackageConfigSettings,
8};
9use uv_install_wheel::LinkMode;
10use uv_pep440::Version;
11use uv_preview::PreviewFeature;
12use uv_torch::{AmdGpuArchitecture, TorchMode};
13use uv_warnings::warn_user_once;
14use uv_workspace::pyproject::ExtraBuildDependencies;
15
16use crate::{ResolverInstallerOptions, ResolverOptions};
17
18#[derive(Debug, Clone, Copy)]
20pub enum LockedFlag {
21 Locked,
22 Check,
23}
24
25impl LockedFlag {
26 pub fn name(self) -> &'static str {
28 match self {
29 Self::Locked => "locked",
30 Self::Check => "check",
31 }
32 }
33}
34
35impl std::fmt::Display for LockedFlag {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 write!(f, "--{}", self.name())
38 }
39}
40
41#[derive(Debug, Clone, Copy)]
43pub enum LockedSource {
44 Cli(LockedFlag),
46 Env,
48}
49
50impl std::fmt::Display for LockedSource {
51 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52 match self {
53 Self::Cli(flag) => flag.fmt(f),
54 Self::Env => write!(f, "UV_LOCKED=1"),
55 }
56 }
57}
58
59#[derive(Debug, Clone, Copy)]
61pub enum LockCheck {
62 Enabled(LockedSource),
64 Disabled,
66}
67
68#[derive(Debug, Clone, Copy)]
70pub enum FrozenFlag {
71 Frozen,
72 CheckExists,
73}
74
75impl FrozenFlag {
76 pub fn name(self) -> &'static str {
78 match self {
79 Self::Frozen => "frozen",
80 Self::CheckExists => "check-exists",
81 }
82 }
83}
84
85impl std::fmt::Display for FrozenFlag {
86 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87 write!(f, "--{}", self.name())
88 }
89}
90
91#[derive(Debug, Clone, Copy)]
93pub enum FrozenSource {
94 Cli(FrozenFlag),
96 Env,
98}
99
100impl std::fmt::Display for FrozenSource {
101 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
102 match self {
103 Self::Cli(flag) => flag.fmt(f),
104 Self::Env => write!(f, "UV_FROZEN=1"),
105 }
106 }
107}
108
109#[derive(Debug, Clone, Default)]
111pub enum PythonListKinds {
112 #[default]
114 Default,
115 Downloads,
117 Installed,
119}
120
121#[derive(Debug, Clone)]
125pub struct InstallerSettingsRef<'a> {
126 pub index_locations: &'a IndexLocations,
127 pub index_strategy: IndexStrategy,
128 pub keyring_provider: KeyringProviderType,
129 pub dependency_metadata: &'a DependencyMetadata,
130 pub config_setting: &'a ConfigSettings,
131 pub config_settings_package: &'a PackageConfigSettings,
132 pub build_hash_checking: HashCheckingMode,
133 pub build_isolation: &'a BuildIsolation,
134 pub extra_build_dependencies: &'a ExtraBuildDependencies,
135 pub extra_build_variables: &'a ExtraBuildVariables,
136 pub exclude_newer: &'a ExcludeNewer,
137 pub link_mode: LinkMode,
138 pub compile_bytecode: bool,
139 pub reinstall: &'a Reinstall,
140 pub build_options: &'a BuildOptions,
141 pub sources: NoSources,
142}
143
144#[derive(Debug, Clone, Default)]
148pub struct ResolverSettings {
149 pub build_options: BuildOptions,
150 pub config_setting: ConfigSettings,
151 pub config_settings_package: PackageConfigSettings,
152 pub dependency_metadata: DependencyMetadata,
153 pub exclude_newer: ExcludeNewer,
154 pub fork_strategy: ForkStrategy,
155 pub index_locations: IndexLocations,
156 pub index_strategy: IndexStrategy,
157 pub keyring_provider: KeyringProviderType,
158 pub link_mode: LinkMode,
159 pub build_hash_checking: HashCheckingMode,
160 pub build_isolation: BuildIsolation,
161 pub extra_build_dependencies: ExtraBuildDependencies,
162 pub extra_build_variables: ExtraBuildVariables,
163 pub prerelease: Prerelease,
164 pub resolution: ResolutionMode,
165 pub sources: NoSources,
166 pub torch_backend: Option<TorchMode>,
167 pub cuda_driver_version: Option<Version>,
168 pub amd_gpu_architecture: Option<AmdGpuArchitecture>,
169 pub upgrade: Upgrade,
170}
171
172#[expect(deprecated)]
174fn warn_if_deprecated_prerelease_mode(prerelease: PrereleaseMode) -> PrereleaseMode {
175 if matches!(prerelease, PrereleaseMode::IfNecessaryOrExplicit) {
176 warn_user_once!(
177 "The `if-necessary-or-explicit` pre-release mode is deprecated and will be removed in a future release. Use `if-necessary` instead."
178 );
179 PrereleaseMode::IfNecessary
180 } else {
181 prerelease
182 }
183}
184
185pub fn resolve_prerelease(global: PrereleaseMode, mut package: PrereleasePackage) -> Prerelease {
187 for mode in package.values_mut() {
188 *mode = warn_if_deprecated_prerelease_mode(*mode);
189 }
190
191 Prerelease {
192 global: warn_if_deprecated_prerelease_mode(global),
193 package,
194 }
195}
196
197impl From<ResolverOptions> for ResolverSettings {
198 fn from(value: ResolverOptions) -> Self {
199 Self {
200 index_locations: value.indexes.into(),
201 resolution: value.resolution.unwrap_or_default(),
202 prerelease: resolve_prerelease(
203 value.prerelease.unwrap_or_default(),
204 value.prerelease_package.unwrap_or_default(),
205 ),
206 fork_strategy: value.fork_strategy.unwrap_or_default(),
207 dependency_metadata: DependencyMetadata::from_entries(
208 value.dependency_metadata.into_iter().flatten(),
209 ),
210 index_strategy: value.index_strategy.unwrap_or_default(),
211 keyring_provider: value.keyring_provider.unwrap_or_default(),
212 config_setting: value.config_settings.unwrap_or_default(),
213 config_settings_package: value.config_settings_package.unwrap_or_default(),
214 build_isolation: value.build_isolation.unwrap_or_default(),
215 build_hash_checking: resolve_build_hash_checking(value.require_build_hashes),
216 extra_build_dependencies: value.extra_build_dependencies.unwrap_or_default(),
217 extra_build_variables: value.extra_build_variables.unwrap_or_default(),
218 exclude_newer: ExcludeNewer::from_args(
219 value.exclude_newer,
220 value
221 .exclude_newer_package
222 .unwrap_or_default()
223 .into_iter()
224 .map(Into::into)
225 .collect(),
226 ),
227 link_mode: value.link_mode.unwrap_or_default(),
228 torch_backend: value.torch_backend,
229 cuda_driver_version: None,
230 amd_gpu_architecture: None,
231 sources: NoSources::from_args(
232 value.no_sources,
233 value.no_sources_package.unwrap_or_default(),
234 ),
235 upgrade: value.upgrade.unwrap_or_default(),
236 build_options: BuildOptions::new(
237 NoBinary::from_args(value.no_binary, value.no_binary_package.unwrap_or_default()),
238 NoBuild::from_args(value.no_build, value.no_build_package.unwrap_or_default()),
239 ),
240 }
241 }
242}
243
244#[derive(Debug, Clone, Default)]
250pub struct ResolverInstallerSettings {
251 pub resolver: ResolverSettings,
252 pub compile_bytecode: bool,
253 pub reinstall: Reinstall,
254}
255
256impl From<ResolverInstallerOptions> for ResolverInstallerSettings {
257 fn from(value: ResolverInstallerOptions) -> Self {
258 let index_locations = value.indexes.into();
259 Self {
260 resolver: ResolverSettings {
261 build_options: BuildOptions::new(
262 NoBinary::from_args(
263 value.no_binary,
264 value.no_binary_package.unwrap_or_default(),
265 ),
266 NoBuild::from_args(value.no_build, value.no_build_package.unwrap_or_default()),
267 ),
268 config_setting: value.config_settings.unwrap_or_default(),
269 config_settings_package: value.config_settings_package.unwrap_or_default(),
270 dependency_metadata: DependencyMetadata::from_entries(
271 value.dependency_metadata.into_iter().flatten(),
272 ),
273 exclude_newer: ExcludeNewer::from_args(
274 value.exclude_newer,
275 value
276 .exclude_newer_package
277 .unwrap_or_default()
278 .into_iter()
279 .map(Into::into)
280 .collect(),
281 ),
282 fork_strategy: value.fork_strategy.unwrap_or_default(),
283 index_locations,
284 index_strategy: value.index_strategy.unwrap_or_default(),
285 keyring_provider: value.keyring_provider.unwrap_or_default(),
286 link_mode: value.link_mode.unwrap_or_default(),
287 build_isolation: value.build_isolation.unwrap_or_default(),
288 build_hash_checking: resolve_build_hash_checking(value.require_build_hashes),
289 extra_build_dependencies: value.extra_build_dependencies.unwrap_or_default(),
290 extra_build_variables: value.extra_build_variables.unwrap_or_default(),
291 prerelease: resolve_prerelease(
292 value.prerelease.unwrap_or_default(),
293 value.prerelease_package.unwrap_or_default(),
294 ),
295 resolution: value.resolution.unwrap_or_default(),
296 sources: NoSources::from_args(
297 value.no_sources,
298 value.no_sources_package.unwrap_or_default(),
299 ),
300 torch_backend: value.torch_backend,
301 cuda_driver_version: None,
302 amd_gpu_architecture: None,
303 upgrade: value.upgrade.unwrap_or_default(),
304 },
305 compile_bytecode: value.compile_bytecode.unwrap_or_default(),
306 reinstall: value.reinstall.unwrap_or_default(),
307 }
308 }
309}
310
311impl<'a> From<&'a ResolverInstallerSettings> for InstallerSettingsRef<'a> {
312 fn from(settings: &'a ResolverInstallerSettings) -> Self {
313 Self {
314 index_locations: &settings.resolver.index_locations,
315 index_strategy: settings.resolver.index_strategy,
316 keyring_provider: settings.resolver.keyring_provider,
317 dependency_metadata: &settings.resolver.dependency_metadata,
318 config_setting: &settings.resolver.config_setting,
319 config_settings_package: &settings.resolver.config_settings_package,
320 build_isolation: &settings.resolver.build_isolation,
321 build_hash_checking: settings.resolver.build_hash_checking,
322 extra_build_dependencies: &settings.resolver.extra_build_dependencies,
323 extra_build_variables: &settings.resolver.extra_build_variables,
324 exclude_newer: &settings.resolver.exclude_newer,
325 link_mode: settings.resolver.link_mode,
326 compile_bytecode: settings.compile_bytecode,
327 reinstall: &settings.reinstall,
328 build_options: &settings.resolver.build_options,
329 sources: settings.resolver.sources.clone(),
330 }
331 }
332}
333
334pub fn resolve_build_hash_checking(require_build_hashes: Option<bool>) -> HashCheckingMode {
336 if !require_build_hashes.unwrap_or_default() {
337 return HashCheckingMode::Verify;
338 }
339 if !uv_preview::is_enabled(PreviewFeature::BuildDependencyHashes) {
340 warn_user_once!(
341 "The `--require-build-hashes` option is experimental and may change without warning. Pass `--preview-features {}` to disable this warning.",
342 PreviewFeature::BuildDependencyHashes
343 );
344 }
345 HashCheckingMode::Require
346}