mirror of
https://github.com/astral-sh/uv.git
synced 2025-10-01 06:21:13 +00:00
Always show lock updates in uv lock
(#5413)
## Summary Closes https://github.com/astral-sh/uv/issues/5412.
This commit is contained in:
parent
3d36b71ab1
commit
22db997240
7 changed files with 56 additions and 41 deletions
|
@ -244,7 +244,7 @@ pub(crate) async fn add(
|
||||||
project::sync::do_sync(
|
project::sync::do_sync(
|
||||||
&VirtualProject::Project(project),
|
&VirtualProject::Project(project),
|
||||||
&venv,
|
&venv,
|
||||||
&lock,
|
&lock.lock,
|
||||||
&extras,
|
&extras,
|
||||||
dev,
|
dev,
|
||||||
Modifications::Sufficient,
|
Modifications::Sufficient,
|
||||||
|
|
|
@ -32,6 +32,15 @@ use crate::commands::{pip, ExitStatus};
|
||||||
use crate::printer::Printer;
|
use crate::printer::Printer;
|
||||||
use crate::settings::{ResolverSettings, ResolverSettingsRef};
|
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.
|
/// Resolve the project requirements into a lockfile.
|
||||||
pub(crate) async fn lock(
|
pub(crate) async fn lock(
|
||||||
locked: bool,
|
locked: bool,
|
||||||
|
@ -86,7 +95,12 @@ pub(crate) async fn lock(
|
||||||
)
|
)
|
||||||
.await
|
.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(
|
Err(ProjectError::Operation(pip::operations::Error::Resolve(
|
||||||
uv_resolver::ResolveError::NoSolution(err),
|
uv_resolver::ResolveError::NoSolution(err),
|
||||||
))) => {
|
))) => {
|
||||||
|
@ -112,12 +126,16 @@ pub(super) async fn do_safe_lock(
|
||||||
native_tls: bool,
|
native_tls: bool,
|
||||||
cache: &Cache,
|
cache: &Cache,
|
||||||
printer: Printer,
|
printer: Printer,
|
||||||
) -> Result<Lock, ProjectError> {
|
) -> Result<LockResult, ProjectError> {
|
||||||
if frozen {
|
if frozen {
|
||||||
// Read the existing lockfile, but don't attempt to lock the project.
|
// Read the existing lockfile, but don't attempt to lock the project.
|
||||||
read(workspace)
|
let existing = read(workspace)
|
||||||
.await?
|
.await?
|
||||||
.ok_or_else(|| ProjectError::MissingLockfile)
|
.ok_or_else(|| ProjectError::MissingLockfile)?;
|
||||||
|
Ok(LockResult {
|
||||||
|
previous: None,
|
||||||
|
lock: existing,
|
||||||
|
})
|
||||||
} else if locked {
|
} else if locked {
|
||||||
// Read the existing lockfile.
|
// Read the existing lockfile.
|
||||||
let existing = read(workspace)
|
let existing = read(workspace)
|
||||||
|
@ -145,7 +163,10 @@ pub(super) async fn do_safe_lock(
|
||||||
return Err(ProjectError::LockMismatch);
|
return Err(ProjectError::LockMismatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(lock)
|
Ok(LockResult {
|
||||||
|
previous: Some(existing),
|
||||||
|
lock,
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
// Read the existing lockfile.
|
// Read the existing lockfile.
|
||||||
let existing = read(workspace).await?;
|
let existing = read(workspace).await?;
|
||||||
|
@ -166,16 +187,19 @@ pub(super) async fn do_safe_lock(
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if !existing.is_some_and(|existing| existing == lock) {
|
if !existing.as_ref().is_some_and(|existing| *existing == lock) {
|
||||||
commit(&lock, workspace).await?;
|
commit(&lock, workspace).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(lock)
|
Ok(LockResult {
|
||||||
|
previous: existing,
|
||||||
|
lock,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lock the project requirements into a lockfile.
|
/// Lock the project requirements into a lockfile.
|
||||||
pub(super) async fn do_lock(
|
async fn do_lock(
|
||||||
workspace: &Workspace,
|
workspace: &Workspace,
|
||||||
interpreter: &Interpreter,
|
interpreter: &Interpreter,
|
||||||
existing_lock: Option<&Lock>,
|
existing_lock: Option<&Lock>,
|
||||||
|
@ -506,16 +530,7 @@ pub(super) async fn do_lock(
|
||||||
// Notify the user of any resolution diagnostics.
|
// Notify the user of any resolution diagnostics.
|
||||||
pip::operations::diagnose_resolution(resolution.diagnostics(), printer)?;
|
pip::operations::diagnose_resolution(resolution.diagnostics(), printer)?;
|
||||||
|
|
||||||
let new_lock = Lock::from_resolution_graph(&resolution)?;
|
Ok(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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write the lockfile to disk.
|
/// Write the lockfile to disk.
|
||||||
|
|
|
@ -131,7 +131,7 @@ pub(crate) async fn remove(
|
||||||
project::sync::do_sync(
|
project::sync::do_sync(
|
||||||
&VirtualProject::Project(project),
|
&VirtualProject::Project(project),
|
||||||
&venv,
|
&venv,
|
||||||
&lock,
|
&lock.lock,
|
||||||
&extras,
|
&extras,
|
||||||
dev,
|
dev,
|
||||||
Modifications::Exact,
|
Modifications::Exact,
|
||||||
|
|
|
@ -238,7 +238,7 @@ pub(crate) async fn run(
|
||||||
project::sync::do_sync(
|
project::sync::do_sync(
|
||||||
&project,
|
&project,
|
||||||
&venv,
|
&venv,
|
||||||
&lock,
|
&lock.lock,
|
||||||
&extras,
|
&extras,
|
||||||
dev,
|
dev,
|
||||||
Modifications::Sufficient,
|
Modifications::Sufficient,
|
||||||
|
|
|
@ -95,7 +95,7 @@ pub(crate) async fn sync(
|
||||||
do_sync(
|
do_sync(
|
||||||
&project,
|
&project,
|
||||||
&venv,
|
&venv,
|
||||||
&lock,
|
&lock.lock,
|
||||||
&extras,
|
&extras,
|
||||||
dev,
|
dev,
|
||||||
modifications,
|
modifications,
|
||||||
|
|
|
@ -83,7 +83,7 @@ pub(crate) async fn tree(
|
||||||
|
|
||||||
// Read packages from the lockfile.
|
// Read packages from the lockfile.
|
||||||
let mut packages: IndexMap<_, Vec<_>> = IndexMap::new();
|
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 name = dist.name().clone();
|
||||||
let metadata = dist.to_metadata(workspace.install_path())?;
|
let metadata = dist.to_metadata(workspace.install_path())?;
|
||||||
packages.entry(name).or_default().push(metadata);
|
packages.entry(name).or_default().push(metadata);
|
||||||
|
|
|
@ -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
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
Resolved 7 packages in [TIME]
|
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!({
|
insta::with_settings!({
|
||||||
filters => context.filters(),
|
filters => context.filters(),
|
||||||
}, {
|
}, {
|
||||||
assert_snapshot!(
|
assert_snapshot!(
|
||||||
lock, @r###"
|
lock, @r###"
|
||||||
version = 1
|
version = 1
|
||||||
requires-python = ">=3.12"
|
requires-python = ">=3.12"
|
||||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
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 },
|
{ url = "https://files.pythonhosted.org/packages/a2/73/a68704750a7679d0b6d3ad7aa8d4da8e14e151ae82e6fee774e6e0d05ec8/urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d", size = 121067 },
|
||||||
]
|
]
|
||||||
"###
|
"###
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -3863,14 +3862,15 @@ fn lock_resolution_mode() -> Result<()> {
|
||||||
|
|
||||||
// Locking with `lowest-direct` should ignore the existing lockfile.
|
// Locking with `lowest-direct` should ignore the existing lockfile.
|
||||||
uv_snapshot!(context.filters(), context.lock().arg("--resolution").arg("lowest-direct"), @r###"
|
uv_snapshot!(context.filters(), context.lock().arg("--resolution").arg("lowest-direct"), @r###"
|
||||||
success: true
|
success: true
|
||||||
exit_code: 0
|
exit_code: 0
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
warning: `uv lock` is experimental and may change without warning
|
warning: `uv lock` is experimental and may change without warning
|
||||||
Ignoring existing lockfile due to change in resolution mode: `highest` vs. `lowest-direct`
|
Ignoring existing lockfile due to change in resolution mode: `highest` vs. `lowest-direct`
|
||||||
Resolved 4 packages in [TIME]
|
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();
|
let lock = fs_err::read_to_string(context.temp_dir.join("uv.lock")).unwrap();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue