Always show lock updates in uv lock (#5413)

## Summary

Closes https://github.com/astral-sh/uv/issues/5412.
This commit is contained in:
Charlie Marsh 2024-07-24 11:54:18 -04:00 committed by GitHub
parent 3d36b71ab1
commit 22db997240
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 56 additions and 41 deletions

View file

@ -244,7 +244,7 @@ pub(crate) async fn add(
project::sync::do_sync(
&VirtualProject::Project(project),
&venv,
&lock,
&lock.lock,
&extras,
dev,
Modifications::Sufficient,

View file

@ -32,6 +32,15 @@ use crate::commands::{pip, ExitStatus};
use crate::printer::Printer;
use crate::settings::{ResolverSettings, ResolverSettingsRef};
/// The result of running a lock operation.
#[derive(Debug, Clone)]
pub(crate) struct LockResult {
/// The previous lock, if any.
pub(crate) previous: Option<Lock>,
/// The updated lock.
pub(crate) lock: Lock,
}
/// Resolve the project requirements into a lockfile.
pub(crate) async fn lock(
locked: bool,
@ -86,7 +95,12 @@ pub(crate) async fn lock(
)
.await
{
Ok(_) => Ok(ExitStatus::Success),
Ok(lock) => {
if let Some(previous) = lock.previous.as_ref() {
report_upgrades(previous, &lock.lock, printer)?;
}
Ok(ExitStatus::Success)
}
Err(ProjectError::Operation(pip::operations::Error::Resolve(
uv_resolver::ResolveError::NoSolution(err),
))) => {
@ -112,12 +126,16 @@ pub(super) async fn do_safe_lock(
native_tls: bool,
cache: &Cache,
printer: Printer,
) -> Result<Lock, ProjectError> {
) -> Result<LockResult, ProjectError> {
if frozen {
// Read the existing lockfile, but don't attempt to lock the project.
read(workspace)
let existing = read(workspace)
.await?
.ok_or_else(|| ProjectError::MissingLockfile)
.ok_or_else(|| ProjectError::MissingLockfile)?;
Ok(LockResult {
previous: None,
lock: existing,
})
} else if locked {
// Read the existing lockfile.
let existing = read(workspace)
@ -145,7 +163,10 @@ pub(super) async fn do_safe_lock(
return Err(ProjectError::LockMismatch);
}
Ok(lock)
Ok(LockResult {
previous: Some(existing),
lock,
})
} else {
// Read the existing lockfile.
let existing = read(workspace).await?;
@ -166,16 +187,19 @@ pub(super) async fn do_safe_lock(
)
.await?;
if !existing.is_some_and(|existing| existing == lock) {
if !existing.as_ref().is_some_and(|existing| *existing == lock) {
commit(&lock, workspace).await?;
}
Ok(lock)
Ok(LockResult {
previous: existing,
lock,
})
}
}
/// Lock the project requirements into a lockfile.
pub(super) async fn do_lock(
async fn do_lock(
workspace: &Workspace,
interpreter: &Interpreter,
existing_lock: Option<&Lock>,
@ -506,16 +530,7 @@ pub(super) async fn do_lock(
// Notify the user of any resolution diagnostics.
pip::operations::diagnose_resolution(resolution.diagnostics(), printer)?;
let new_lock = Lock::from_resolution_graph(&resolution)?;
// Notify the user of any dependency updates
if !upgrade.is_none() {
if let Some(existing_lock) = existing_lock {
report_upgrades(existing_lock, &new_lock, printer)?;
}
}
Ok(new_lock)
Ok(Lock::from_resolution_graph(&resolution)?)
}
/// Write the lockfile to disk.

View file

@ -131,7 +131,7 @@ pub(crate) async fn remove(
project::sync::do_sync(
&VirtualProject::Project(project),
&venv,
&lock,
&lock.lock,
&extras,
dev,
Modifications::Exact,

View file

@ -238,7 +238,7 @@ pub(crate) async fn run(
project::sync::do_sync(
&project,
&venv,
&lock,
&lock.lock,
&extras,
dev,
Modifications::Sufficient,

View file

@ -95,7 +95,7 @@ pub(crate) async fn sync(
do_sync(
&project,
&venv,
&lock,
&lock.lock,
&extras,
dev,
modifications,

View file

@ -83,7 +83,7 @@ pub(crate) async fn tree(
// Read packages from the lockfile.
let mut packages: IndexMap<_, Vec<_>> = IndexMap::new();
for dist in lock.into_distributions() {
for dist in lock.lock.into_distributions() {
let name = dist.name().clone();
let metadata = dist.to_metadata(workspace.install_path())?;
packages.entry(name).or_default().push(metadata);

View file

@ -3569,23 +3569,23 @@ fn lock_new_extras() -> Result<()> {
"#,
)?;
deterministic! { context =>
uv_snapshot!(context.filters(), context.lock().arg("--preview"), @r###"
uv_snapshot!(context.filters(), context.lock().arg("--preview"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 7 packages in [TIME]
Added pysocks v1.7.1
"###);
let lock = fs_err::read_to_string(context.temp_dir.join("uv.lock")).unwrap();
let lock = fs_err::read_to_string(context.temp_dir.join("uv.lock")).unwrap();
insta::with_settings!({
filters => context.filters(),
}, {
assert_snapshot!(
lock, @r###"
insta::with_settings!({
filters => context.filters(),
}, {
assert_snapshot!(
lock, @r###"
version = 1
requires-python = ">=3.12"
exclude-newer = "2024-03-25 00:00:00 UTC"
@ -3678,9 +3678,8 @@ fn lock_new_extras() -> Result<()> {
{ url = "https://files.pythonhosted.org/packages/a2/73/a68704750a7679d0b6d3ad7aa8d4da8e14e151ae82e6fee774e6e0d05ec8/urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d", size = 121067 },
]
"###
);
});
}
);
});
Ok(())
}
@ -3863,14 +3862,15 @@ fn lock_resolution_mode() -> Result<()> {
// Locking with `lowest-direct` should ignore the existing lockfile.
uv_snapshot!(context.filters(), context.lock().arg("--resolution").arg("lowest-direct"), @r###"
success: true
exit_code: 0
----- stdout -----
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: `uv lock` is experimental and may change without warning
Ignoring existing lockfile due to change in resolution mode: `highest` vs. `lowest-direct`
Resolved 4 packages in [TIME]
----- stderr -----
warning: `uv lock` is experimental and may change without warning
Ignoring existing lockfile due to change in resolution mode: `highest` vs. `lowest-direct`
Resolved 4 packages in [TIME]
Updated anyio v4.3.0 -> v3.0.0
"###);
let lock = fs_err::read_to_string(context.temp_dir.join("uv.lock")).unwrap();