Skip to content

Commit 1480f81

Browse files
committed
Prefer locked versions of packages in build environments
1 parent 5686771 commit 1480f81

File tree

14 files changed

+396
-18
lines changed

14 files changed

+396
-18
lines changed

crates/uv-bench/benches/uv.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,8 @@ mod resolver {
9999
use uv_pypi_types::{Conflicts, ResolverMarkerEnvironment};
100100
use uv_python::Interpreter;
101101
use uv_resolver::{
102-
FlatIndex, InMemoryIndex, Manifest, OptionsBuilder, PythonRequirement, Resolver,
103-
ResolverEnvironment, ResolverOutput,
102+
FlatIndex, InMemoryIndex, Manifest, OptionsBuilder, Preferences, PythonRequirement,
103+
Resolver, ResolverEnvironment, ResolverOutput,
104104
};
105105
use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy};
106106
use uv_workspace::WorkspaceCache;
@@ -195,6 +195,7 @@ mod resolver {
195195
workspace_cache,
196196
concurrency,
197197
Preview::default(),
198+
Preferences::default(),
198199
);
199200

200201
let markers = if universal {

crates/uv-dispatch/src/lib.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use uv_installer::{Installer, Plan, Planner, Preparer, SitePackages};
3232
use uv_pypi_types::Conflicts;
3333
use uv_python::{Interpreter, PythonEnvironment};
3434
use uv_resolver::{
35-
ExcludeNewer, FlatIndex, Flexibility, InMemoryIndex, Manifest, OptionsBuilder,
35+
ExcludeNewer, FlatIndex, Flexibility, InMemoryIndex, Manifest, OptionsBuilder, Preferences,
3636
PythonRequirement, Resolver, ResolverEnvironment,
3737
};
3838
use uv_types::{
@@ -100,6 +100,7 @@ pub struct BuildDispatch<'a> {
100100
workspace_cache: WorkspaceCache,
101101
concurrency: Concurrency,
102102
preview: Preview,
103+
preferences: Preferences,
103104
}
104105

105106
impl<'a> BuildDispatch<'a> {
@@ -124,6 +125,7 @@ impl<'a> BuildDispatch<'a> {
124125
workspace_cache: WorkspaceCache,
125126
concurrency: Concurrency,
126127
preview: Preview,
128+
preferences: Preferences,
127129
) -> Self {
128130
Self {
129131
client,
@@ -148,6 +150,7 @@ impl<'a> BuildDispatch<'a> {
148150
workspace_cache,
149151
concurrency,
150152
preview,
153+
preferences,
151154
}
152155
}
153156

@@ -229,7 +232,9 @@ impl BuildContext for BuildDispatch<'_> {
229232
let tags = self.interpreter.tags()?;
230233

231234
let resolver = Resolver::new(
232-
Manifest::simple(requirements.to_vec()).with_constraints(self.constraints.clone()),
235+
Manifest::simple(requirements.to_vec())
236+
.with_constraints(self.constraints.clone())
237+
.with_preferences(self.preferences.clone()),
233238
OptionsBuilder::new()
234239
.exclude_newer(self.exclude_newer)
235240
.index_strategy(self.index_strategy)

crates/uv-resolver/src/manifest.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@ impl Manifest {
9292
self
9393
}
9494

95+
#[must_use]
96+
pub fn with_preferences(mut self, preferences: Preferences) -> Self {
97+
self.preferences = preferences;
98+
self
99+
}
100+
95101
/// Return an iterator over all requirements, constraints, and overrides, in priority order,
96102
/// such that requirements come first, followed by constraints, followed by overrides.
97103
///

crates/uv/src/commands/build_frontend.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use uv_python::{
3535
VersionRequest,
3636
};
3737
use uv_requirements::RequirementsSource;
38-
use uv_resolver::{ExcludeNewer, FlatIndex};
38+
use uv_resolver::{ExcludeNewer, FlatIndex, Preferences};
3939
use uv_settings::PythonInstallMirrors;
4040
use uv_types::{AnyErrorBuild, BuildContext, BuildIsolation, BuildStack, HashStrategy};
4141
use uv_workspace::{DiscoveryOptions, Workspace, WorkspaceCache, WorkspaceError};
@@ -581,6 +581,7 @@ async fn build_package(
581581
workspace_cache,
582582
concurrency,
583583
preview,
584+
Preferences::default(),
584585
);
585586

586587
prepare_output_directory(&output_dir).await?;

crates/uv/src/commands/pip/compile.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ use uv_requirements::{
3939
};
4040
use uv_resolver::{
4141
AnnotationStyle, DependencyMode, DisplayResolutionGraph, ExcludeNewer, FlatIndex, ForkStrategy,
42-
InMemoryIndex, OptionsBuilder, PrereleaseMode, PylockToml, PythonRequirement, ResolutionMode,
43-
ResolverEnvironment,
42+
InMemoryIndex, OptionsBuilder, Preferences, PrereleaseMode, PylockToml, PythonRequirement,
43+
ResolutionMode, ResolverEnvironment,
4444
};
4545
use uv_torch::{TorchMode, TorchStrategy};
4646
use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy};
@@ -490,6 +490,7 @@ pub(crate) async fn pip_compile(
490490
WorkspaceCache::default(),
491491
concurrency,
492492
preview,
493+
Preferences::default(),
493494
);
494495

495496
let options = OptionsBuilder::new()

crates/uv/src/commands/pip/install.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ use uv_python::{
3131
};
3232
use uv_requirements::{GroupsSpecification, RequirementsSource, RequirementsSpecification};
3333
use uv_resolver::{
34-
DependencyMode, ExcludeNewer, FlatIndex, OptionsBuilder, PrereleaseMode, PylockToml,
35-
PythonRequirement, ResolutionMode, ResolverEnvironment,
34+
DependencyMode, ExcludeNewer, FlatIndex, OptionsBuilder, Preferences, PrereleaseMode,
35+
PylockToml, PythonRequirement, ResolutionMode, ResolverEnvironment,
3636
};
3737
use uv_torch::{TorchMode, TorchStrategy};
3838
use uv_types::{BuildIsolation, HashStrategy};
@@ -434,6 +434,7 @@ pub(crate) async fn pip_install(
434434
WorkspaceCache::default(),
435435
concurrency,
436436
preview,
437+
Preferences::default(),
437438
);
438439

439440
let (resolution, hasher) = if let Some(pylock) = pylock {

crates/uv/src/commands/pip/sync.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ use uv_python::{
2727
};
2828
use uv_requirements::{GroupsSpecification, RequirementsSource, RequirementsSpecification};
2929
use uv_resolver::{
30-
DependencyMode, ExcludeNewer, FlatIndex, OptionsBuilder, PrereleaseMode, PylockToml,
31-
PythonRequirement, ResolutionMode, ResolverEnvironment,
30+
DependencyMode, ExcludeNewer, FlatIndex, OptionsBuilder, Preferences, PrereleaseMode,
31+
PylockToml, PythonRequirement, ResolutionMode, ResolverEnvironment,
3232
};
3333
use uv_torch::{TorchMode, TorchStrategy};
3434
use uv_types::{BuildIsolation, HashStrategy};
@@ -369,6 +369,7 @@ pub(crate) async fn pip_sync(
369369
WorkspaceCache::default(),
370370
concurrency,
371371
preview,
372+
Preferences::default(),
372373
);
373374

374375
// Determine the set of installed packages.

crates/uv/src/commands/project/add.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::collections::BTreeMap;
22
use std::collections::hash_map::Entry;
33
use std::fmt::Write;
44
use std::io;
5-
use std::path::Path;
5+
use std::path::{Path, PathBuf};
66
use std::str::FromStr;
77
use std::sync::Arc;
88

@@ -36,7 +36,7 @@ use uv_pypi_types::{ParsedUrl, VerbatimParsedUrl};
3636
use uv_python::{Interpreter, PythonDownloads, PythonEnvironment, PythonPreference, PythonRequest};
3737
use uv_redacted::DisplaySafeUrl;
3838
use uv_requirements::{NamedRequirementsResolver, RequirementsSource, RequirementsSpecification};
39-
use uv_resolver::FlatIndex;
39+
use uv_resolver::{FlatIndex, Preference, Preferences, ResolverEnvironment};
4040
use uv_scripts::{Pep723ItemRef, Pep723Metadata, Pep723Script};
4141
use uv_settings::PythonInstallMirrors;
4242
use uv_types::{BuildIsolation, HashStrategy};
@@ -427,6 +427,33 @@ pub(crate) async fn add(
427427
FlatIndex::from_entries(entries, None, &hasher, &settings.resolver.build_options)
428428
};
429429

430+
// Load preferences from the existing lockfile if available.
431+
let preferences = if let Ok(Some(lock)) = LockTarget::from(&target).read().await {
432+
Preferences::from_iter(
433+
lock.packages()
434+
.iter()
435+
.filter_map(|package| {
436+
Preference::from_lock(
437+
package,
438+
match &target {
439+
AddTarget::Script(_, _) => Path::new(".")
440+
.canonicalize()
441+
.unwrap_or_else(|_| PathBuf::from(".")),
442+
AddTarget::Project(project, _) => {
443+
project.workspace().install_path().clone()
444+
}
445+
}
446+
.as_path(),
447+
)
448+
.transpose()
449+
})
450+
.collect::<Result<Vec<_>, _>>()?,
451+
&ResolverEnvironment::specific(target.interpreter().markers().clone().into()),
452+
)
453+
} else {
454+
Preferences::default()
455+
};
456+
430457
// Create a build dispatch.
431458
let build_dispatch = BuildDispatch::new(
432459
&client,
@@ -450,6 +477,7 @@ pub(crate) async fn add(
450477
WorkspaceCache::default(),
451478
concurrency,
452479
preview,
480+
preferences,
453481
);
454482

455483
requirements.extend(

crates/uv/src/commands/project/lock.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use uv_python::{Interpreter, PythonDownloads, PythonEnvironment, PythonPreferenc
2929
use uv_requirements::ExtrasResolver;
3030
use uv_requirements::upgrade::{LockedRequirements, read_lock_requirements};
3131
use uv_resolver::{
32-
FlatIndex, InMemoryIndex, Lock, Options, OptionsBuilder, PythonRequirement,
32+
FlatIndex, InMemoryIndex, Lock, Options, OptionsBuilder, Preferences, PythonRequirement,
3333
ResolverEnvironment, ResolverManifest, SatisfiesResult, UniversalMarker,
3434
};
3535
use uv_scripts::{Pep723ItemRef, Pep723Script};
@@ -663,6 +663,25 @@ async fn do_lock(
663663
FlatIndex::from_entries(entries, None, &hasher, build_options)
664664
};
665665

666+
// We extract preferences before validation because validation may need to build source
667+
// distributions to get their metadata.
668+
let preferences = existing_lock
669+
.as_ref()
670+
.map(|existing_lock| -> Result<Preferences, ProjectError> {
671+
let locked = read_lock_requirements(existing_lock, target.install_path(), upgrade)?;
672+
// Populate the Git resolver.
673+
for ResolvedRepositoryReference { reference, sha } in &locked.git {
674+
debug!("Inserting Git reference into resolver: `{reference:?}` at `{sha}`");
675+
state.git().insert(reference.clone(), *sha);
676+
}
677+
Ok(Preferences::from_iter(
678+
locked.preferences,
679+
&ResolverEnvironment::universal(vec![]),
680+
))
681+
})
682+
.transpose()?
683+
.unwrap_or_default();
684+
666685
// Create a build dispatch.
667686
let build_dispatch = BuildDispatch::new(
668687
&client,
@@ -685,6 +704,7 @@ async fn do_lock(
685704
workspace_cache.clone(),
686705
concurrency,
687706
preview,
707+
preferences,
688708
);
689709

690710
let database = DistributionDatabase::new(&client, &build_dispatch, concurrency.downloads);

crates/uv/src/commands/project/mod.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ use uv_python::{
3636
use uv_requirements::upgrade::{LockedRequirements, read_lock_requirements};
3737
use uv_requirements::{NamedRequirementsResolver, RequirementsSpecification};
3838
use uv_resolver::{
39-
FlatIndex, Lock, OptionsBuilder, Preference, PythonRequirement, ResolverEnvironment,
40-
ResolverOutput,
39+
FlatIndex, Lock, OptionsBuilder, Preference, Preferences, PythonRequirement,
40+
ResolverEnvironment, ResolverOutput,
4141
};
4242
use uv_scripts::Pep723ItemRef;
4343
use uv_settings::PythonInstallMirrors;
@@ -1761,6 +1761,7 @@ pub(crate) async fn resolve_names(
17611761
workspace_cache.clone(),
17621762
concurrency,
17631763
preview,
1764+
Preferences::default(),
17641765
);
17651766

17661767
// Resolve the unnamed requirements.
@@ -1969,6 +1970,7 @@ pub(crate) async fn resolve_environment(
19691970
workspace_cache,
19701971
concurrency,
19711972
preview,
1973+
Preferences::default(),
19721974
);
19731975

19741976
// Resolve the requirements.
@@ -2107,6 +2109,7 @@ pub(crate) async fn sync_environment(
21072109
workspace_cache,
21082110
concurrency,
21092111
preview,
2112+
Preferences::default(),
21102113
);
21112114

21122115
// Sync the environment.
@@ -2331,6 +2334,7 @@ pub(crate) async fn update_environment(
23312334
workspace_cache,
23322335
concurrency,
23332336
preview,
2337+
Preferences::default(),
23342338
);
23352339

23362340
// Resolve the requirements.

0 commit comments

Comments
 (0)