Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 43 additions & 37 deletions crates/uv/src/commands/project/lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -947,16 +947,16 @@ async fn do_lock(

#[derive(Debug)]
enum ValidatedLock {
/// An existing lockfile was provided, and it satisfies the workspace requirements.
Satisfies(Lock),
/// An existing lockfile was provided, but its contents should be ignored.
Unusable(Lock),
/// An existing lockfile was provided, and the locked versions and forks should be preferred if
/// possible, even though the lockfile does not satisfy the workspace requirements.
Preferable(Lock),
/// An existing lockfile was provided, and the locked versions should be preferred if possible,
/// though the forks should be ignored.
Versions(Lock),
/// An existing lockfile was provided, and the locked versions and forks should be preferred if
/// possible, even though the lockfile does not satisfy the workspace requirements.
Preferable(Lock),
/// An existing lockfile was provided, and it satisfies the workspace requirements.
Satisfies(Lock),
}

impl ValidatedLock {
Expand Down Expand Up @@ -987,7 +987,10 @@ impl ValidatedLock {
database: &DistributionDatabase<'_, Context>,
printer: Printer,
) -> Result<Self, ProjectError> {
// Start with the most severe condition: a fundamental option changed between resolutions.
// Perform checks in a deliberate order, such that the most extreme conditions are tested
// first (i.e., every check that returns `Self::Unusable`, followed by every check that
// returns `Self::Versions`, followed by every check that returns `Self::Preferable`, and
// finally `Self::Satisfies`).
if lock.resolution_mode() != options.resolution_mode {
let _ = writeln!(
printer.stderr(),
Expand All @@ -997,15 +1000,6 @@ impl ValidatedLock {
);
return Ok(Self::Unusable(lock));
}
if lock.prerelease_mode() != options.prerelease_mode {
let _ = writeln!(
printer.stderr(),
"Resolving despite existing lockfile due to change in pre-release mode: `{}` vs. `{}`",
lock.prerelease_mode().cyan(),
options.prerelease_mode.cyan()
);
return Ok(Self::Preferable(lock));
}
if lock.fork_strategy() != options.fork_strategy {
let _ = writeln!(
printer.stderr(),
Expand Down Expand Up @@ -1100,28 +1094,6 @@ impl ValidatedLock {
return Ok(Self::Versions(lock));
}

if let Upgrade::Packages(_) = upgrade {
// If the user specified `--upgrade-package`, then at best we can prefer some of
// the existing versions.
debug!("Resolving despite existing lockfile due to `--upgrade-package`");
return Ok(Self::Preferable(lock));
}

// If the Requires-Python bound has changed, we have to perform a clean resolution, since
// the set of `resolution-markers` may no longer cover the entire supported Python range.
if lock.requires_python().range() != requires_python.range() {
debug!(
"Resolving despite existing lockfile due to change in Python requirement: `{}` vs. `{}`",
lock.requires_python(),
requires_python,
);
return if lock.fork_markers().is_empty() {
Ok(Self::Preferable(lock))
} else {
Ok(Self::Versions(lock))
};
}

// If the set of supported environments has changed, we have to perform a clean resolution.
let expected = lock.simplified_supported_environments();
let actual = environments
Expand Down Expand Up @@ -1166,6 +1138,40 @@ impl ValidatedLock {
return Ok(Self::Versions(lock));
}

// If the Requires-Python bound has changed, we have to perform a clean resolution, since
// the set of `resolution-markers` may no longer cover the entire supported Python range.
if lock.requires_python().range() != requires_python.range() {
debug!(
"Resolving despite existing lockfile due to change in Python requirement: `{}` vs. `{}`",
lock.requires_python(),
requires_python,
);
return if lock.fork_markers().is_empty() {
Ok(Self::Preferable(lock))
} else {
Ok(Self::Versions(lock))
};
}

// If the pre-release mode has changed, we have to re-resolve, but can retain the existing
// versions and forks.
if lock.prerelease_mode() != options.prerelease_mode {
let _ = writeln!(
printer.stderr(),
"Resolving despite existing lockfile due to change in pre-release mode: `{}` vs. `{}`",
lock.prerelease_mode().cyan(),
options.prerelease_mode.cyan()
);
return Ok(Self::Preferable(lock));
}

// If the user specified `--upgrade-package`, then at best we can prefer some of
// the existing versions.
if let Upgrade::Packages(_) = upgrade {
debug!("Resolving despite existing lockfile due to `--upgrade-package`");
return Ok(Self::Preferable(lock));
}

// If the user specified `--refresh`, then we have to re-resolve.
if matches!(refresh, Some(Refresh::All(..) | Refresh::Packages(..))) {
debug!("Resolving despite existing lockfile due to `--refresh`");
Expand Down
Loading