diff --git a/crates/uv-cli/src/lib.rs b/crates/uv-cli/src/lib.rs index 4e4d67694..f643e1e8d 100644 --- a/crates/uv-cli/src/lib.rs +++ b/crates/uv-cli/src/lib.rs @@ -3719,20 +3719,34 @@ pub struct LockArgs { /// missing or needs to be updated, uv will exit with an error. /// /// Equivalent to `--locked`. - #[arg(long, alias = "locked", env = EnvVars::UV_LOCKED, value_parser = clap::builder::BoolishValueParser::new(), conflicts_with_all = ["check_exists", "upgrade"])] + #[arg(long, env = EnvVars::UV_LOCKED, value_parser = clap::builder::BoolishValueParser::new(), conflicts_with_all = ["check_exists", "upgrade", "locked"])] pub check: bool, + /// Check if the lockfile is up-to-date. + /// + /// Asserts that the `uv.lock` would remain unchanged after a resolution. If the lockfile is + /// missing or needs to be updated, uv will exit with an error. + /// + /// Equivalent to `--check`. + #[arg(long, env = EnvVars::UV_LOCKED, value_parser = clap::builder::BoolishValueParser::new(), conflicts_with_all = ["check_exists", "upgrade", "check"], hide = true)] + pub locked: bool, + /// Assert that a `uv.lock` exists without checking if it is up-to-date. /// /// Equivalent to `--frozen`. - #[arg(long, alias = "frozen", env = EnvVars::UV_FROZEN, value_parser = clap::builder::BoolishValueParser::new(), conflicts_with = "check")] + #[arg(long, alias = "frozen", env = EnvVars::UV_FROZEN, value_parser = clap::builder::BoolishValueParser::new(), conflicts_with_all = ["check", "locked"])] pub check_exists: bool, /// Perform a dry run, without writing the lockfile. /// /// In dry-run mode, uv will resolve the project's dependencies and report on the resulting /// changes, but will not write the lockfile to disk. - #[arg(long, conflicts_with = "check_exists", conflicts_with = "check")] + #[arg( + long, + conflicts_with = "check_exists", + conflicts_with = "check", + conflicts_with = "locked" + )] pub dry_run: bool, /// Lock the specified Python script, rather than the current project. diff --git a/crates/uv/src/commands/project/add.rs b/crates/uv/src/commands/project/add.rs index c449416e4..cc06ce97b 100644 --- a/crates/uv/src/commands/project/add.rs +++ b/crates/uv/src/commands/project/add.rs @@ -59,13 +59,13 @@ use crate::commands::project::{ use crate::commands::reporters::{PythonDownloadReporter, ResolverReporter}; use crate::commands::{ExitStatus, ScriptPath, diagnostics, project}; use crate::printer::Printer; -use crate::settings::ResolverInstallerSettings; +use crate::settings::{LockCheck, ResolverInstallerSettings}; /// Add one or more packages to the project requirements. #[allow(clippy::fn_params_excessive_bools)] pub(crate) async fn add( project_dir: &Path, - locked: bool, + lock_check: LockCheck, frozen: bool, active: Option, no_sync: bool, @@ -177,9 +177,9 @@ pub(crate) async fn add( "`--package` is a no-op for Python scripts with inline metadata, which always run in isolation" ); } - if locked { + if let LockCheck::Enabled(lock_check) = lock_check { warn_user_once!( - "`--locked` is a no-op for Python scripts with inline metadata, which always run in isolation" + "`{lock_check}` is a no-op for Python scripts with inline metadata, which always run in isolation" ); } if frozen { @@ -728,7 +728,7 @@ pub(crate) async fn add( &edits, lock_state, sync_state, - locked, + lock_check, no_install_project, no_install_workspace, no_install_local, @@ -959,7 +959,7 @@ async fn lock_and_sync( edits: &[DependencyEdit], lock_state: UniversalState, sync_state: PlatformState, - locked: bool, + lock_check: LockCheck, no_install_project: bool, no_install_workspace: bool, no_install_local: bool, @@ -977,8 +977,8 @@ async fn lock_and_sync( preview: Preview, ) -> Result<(), ProjectError> { let mut lock = project::lock::LockOperation::new( - if locked { - LockMode::Locked(target.interpreter()) + if let LockCheck::Enabled(lock_check) = lock_check { + LockMode::Locked(target.interpreter(), lock_check) } else { LockMode::Write(target.interpreter()) }, @@ -1099,8 +1099,8 @@ async fn lock_and_sync( // If the file was modified, we have to lock again, though the only expected change is // the addition of the minimum version specifiers. lock = project::lock::LockOperation::new( - if locked { - LockMode::Locked(target.interpreter()) + if let LockCheck::Enabled(lock_check) = lock_check { + LockMode::Locked(target.interpreter(), lock_check) } else { LockMode::Write(target.interpreter()) }, diff --git a/crates/uv/src/commands/project/export.rs b/crates/uv/src/commands/project/export.rs index 600374218..29472475b 100644 --- a/crates/uv/src/commands/project/export.rs +++ b/crates/uv/src/commands/project/export.rs @@ -30,7 +30,7 @@ use crate::commands::project::{ }; use crate::commands::{ExitStatus, OutputWriter, diagnostics}; use crate::printer::Printer; -use crate::settings::ResolverSettings; +use crate::settings::{LockCheck, ResolverSettings}; #[derive(Debug, Clone)] #[allow(clippy::large_enum_variant)] @@ -65,7 +65,7 @@ pub(crate) async fn export( extras: ExtrasSpecification, groups: DependencyGroups, editable: Option, - locked: bool, + lock_check: LockCheck, frozen: bool, include_annotations: bool, include_header: bool, @@ -172,8 +172,8 @@ pub(crate) async fn export( // Determine the lock mode. let mode = if frozen { LockMode::Frozen - } else if locked { - LockMode::Locked(interpreter.as_ref().unwrap()) + } else if let LockCheck::Enabled(lock_check) = lock_check { + LockMode::Locked(interpreter.as_ref().unwrap(), lock_check) } else if matches!(target, ExportTarget::Script(_)) && !LockTarget::from(&target).lock_path().is_file() { diff --git a/crates/uv/src/commands/project/lock.rs b/crates/uv/src/commands/project/lock.rs index 9eff538a2..5363a365a 100644 --- a/crates/uv/src/commands/project/lock.rs +++ b/crates/uv/src/commands/project/lock.rs @@ -49,7 +49,7 @@ use crate::commands::project::{ use crate::commands::reporters::{PythonDownloadReporter, ResolverReporter}; use crate::commands::{ExitStatus, ScriptPath, diagnostics, pip}; use crate::printer::Printer; -use crate::settings::ResolverSettings; +use crate::settings::{LockCheck, LockCheckSource, ResolverSettings}; /// The result of running a lock operation. #[derive(Debug, Clone)] @@ -81,7 +81,7 @@ impl LockResult { #[allow(clippy::fn_params_excessive_bools)] pub(crate) async fn lock( project_dir: &Path, - locked: bool, + lock_check: LockCheck, frozen: bool, dry_run: DryRun, refresh: Refresh, @@ -177,8 +177,8 @@ pub(crate) async fn lock( .into_interpreter(), }; - if locked { - LockMode::Locked(&interpreter) + if let LockCheck::Enabled(lock_check) = lock_check { + LockMode::Locked(&interpreter, lock_check) } else if dry_run.enabled() { LockMode::DryRun(&interpreter) } else { @@ -257,7 +257,7 @@ pub(super) enum LockMode<'env> { /// Perform a resolution, but don't write the lockfile to disk. DryRun(&'env Interpreter), /// Error if the lockfile is not up-to-date with the project requirements. - Locked(&'env Interpreter), + Locked(&'env Interpreter, LockCheckSource), /// Use the existing lockfile without performing a resolution. Frozen, } @@ -336,7 +336,7 @@ impl<'env> LockOperation<'env> { .ok_or_else(|| ProjectError::MissingLockfile)?; Ok(LockResult::Unchanged(existing)) } - LockMode::Locked(interpreter) => { + LockMode::Locked(interpreter, lock_source) => { // Read the existing lockfile. let existing = target .read() @@ -367,6 +367,7 @@ impl<'env> LockOperation<'env> { return Err(ProjectError::LockMismatch( prev.map(Box::new), Box::new(cur), + lock_source, )); } diff --git a/crates/uv/src/commands/project/mod.rs b/crates/uv/src/commands/project/mod.rs index 1dee92370..785874c6e 100644 --- a/crates/uv/src/commands/project/mod.rs +++ b/crates/uv/src/commands/project/mod.rs @@ -57,7 +57,9 @@ use crate::commands::project::install_target::InstallTarget; use crate::commands::reporters::{PythonDownloadReporter, ResolverReporter}; use crate::commands::{capitalize, conjunction, pip}; use crate::printer::Printer; -use crate::settings::{InstallerSettingsRef, ResolverInstallerSettings, ResolverSettings}; +use crate::settings::{ + InstallerSettingsRef, LockCheckSource, ResolverInstallerSettings, ResolverSettings, +}; pub(crate) mod add; pub(crate) mod environment; @@ -76,9 +78,9 @@ pub(crate) mod version; #[derive(thiserror::Error, Debug)] pub(crate) enum ProjectError { #[error( - "The lockfile at `uv.lock` needs to be updated, but `--locked` was provided. To update the lockfile, run `uv lock`." + "The lockfile at `uv.lock` needs to be updated, but `{2}` was provided. To update the lockfile, run `uv lock`." )] - LockMismatch(Option>, Box), + LockMismatch(Option>, Box, LockCheckSource), #[error( "Unable to find lockfile at `uv.lock`. To create a lockfile, run `uv lock` or `uv sync`." diff --git a/crates/uv/src/commands/project/remove.rs b/crates/uv/src/commands/project/remove.rs index 03a3f04fc..c67a231d9 100644 --- a/crates/uv/src/commands/project/remove.rs +++ b/crates/uv/src/commands/project/remove.rs @@ -36,13 +36,13 @@ use crate::commands::project::{ }; use crate::commands::{ExitStatus, diagnostics, project}; use crate::printer::Printer; -use crate::settings::ResolverInstallerSettings; +use crate::settings::{LockCheck, ResolverInstallerSettings}; /// Remove one or more packages from the project requirements. #[allow(clippy::fn_params_excessive_bools)] pub(crate) async fn remove( project_dir: &Path, - locked: bool, + lock_check: LockCheck, frozen: bool, active: Option, no_sync: bool, @@ -70,9 +70,9 @@ pub(crate) async fn remove( "`--package` is a no-op for Python scripts with inline metadata, which always run in isolation" ); } - if locked { + if let LockCheck::Enabled(lock_check) = lock_check { warn_user_once!( - "`--locked` is a no-op for Python scripts with inline metadata, which always run in isolation" + "`{lock_check}` is a no-op for Python scripts with inline metadata, which always run in isolation", ); } if frozen { @@ -291,8 +291,8 @@ pub(crate) async fn remove( .ok(); // Determine the lock mode. - let mode = if locked { - LockMode::Locked(target.interpreter()) + let mode = if let LockCheck::Enabled(lock_check) = lock_check { + LockMode::Locked(target.interpreter(), lock_check) } else { LockMode::Write(target.interpreter()) }; diff --git a/crates/uv/src/commands/project/run.rs b/crates/uv/src/commands/project/run.rs index fa3227c45..2e0f2e7e1 100644 --- a/crates/uv/src/commands/project/run.rs +++ b/crates/uv/src/commands/project/run.rs @@ -73,7 +73,7 @@ use crate::commands::project::{ use crate::commands::reporters::PythonDownloadReporter; use crate::commands::{ExitStatus, diagnostics, project}; use crate::printer::Printer; -use crate::settings::{ResolverInstallerSettings, ResolverSettings}; +use crate::settings::{LockCheck, ResolverInstallerSettings, ResolverSettings}; /// Run a command. #[allow(clippy::fn_params_excessive_bools)] @@ -83,7 +83,7 @@ pub(crate) async fn run( command: Option, requirements: Vec, show_resolution: bool, - locked: bool, + lock_check: LockCheck, frozen: bool, active: Option, no_sync: bool, @@ -264,8 +264,8 @@ hint: If you are running a script with `{}` in the shebang, you may need to incl // Determine the lock mode. let mode = if frozen { LockMode::Frozen - } else if locked { - LockMode::Locked(environment.interpreter()) + } else if let LockCheck::Enabled(lock_check) = lock_check { + LockMode::Locked(environment.interpreter(), lock_check) } else { LockMode::Write(environment.interpreter()) }; @@ -356,9 +356,9 @@ hint: If you are running a script with `{}` in the shebang, you may need to incl Some(environment.into_interpreter()) } else { // If no lockfile is found, warn against `--locked` and `--frozen`. - if locked { + if let LockCheck::Enabled(lock_check) = lock_check { warn_user!( - "No lockfile found for Python script (ignoring `--locked`); run `{}` to generate a lockfile", + "No lockfile found for Python script (ignoring `{lock_check}`); run `{}` to generate a lockfile", "uv lock --script".green(), ); } @@ -588,8 +588,8 @@ hint: If you are running a script with `{}` in the shebang, you may need to incl for flag in groups.history().as_flags_pretty() { warn_user!("`{flag}` has no effect when used alongside `--no-project`"); } - if locked { - warn_user!("`--locked` has no effect when used alongside `--no-project`"); + if let LockCheck::Enabled(lock_check) = lock_check { + warn_user!("`{lock_check}` has no effect when used alongside `--no-project`"); } if frozen { warn_user!("`--frozen` has no effect when used alongside `--no-project`"); @@ -605,8 +605,8 @@ hint: If you are running a script with `{}` in the shebang, you may need to incl for flag in groups.history().as_flags_pretty() { warn_user!("`{flag}` has no effect when used outside of a project"); } - if locked { - warn_user!("`--locked` has no effect when used outside of a project"); + if let LockCheck::Enabled(lock_check) = lock_check { + warn_user!("`{lock_check}` has no effect when used outside of a project",); } if no_sync { warn_user!("`--no-sync` has no effect when used outside of a project"); @@ -740,8 +740,8 @@ hint: If you are running a script with `{}` in the shebang, you may need to incl // Determine the lock mode. let mode = if frozen { LockMode::Frozen - } else if locked { - LockMode::Locked(venv.interpreter()) + } else if let LockCheck::Enabled(lock_check) = lock_check { + LockMode::Locked(venv.interpreter(), lock_check) } else if isolated { LockMode::DryRun(venv.interpreter()) } else { diff --git a/crates/uv/src/commands/project/sync.rs b/crates/uv/src/commands/project/sync.rs index 27b3c70e6..1225f3757 100644 --- a/crates/uv/src/commands/project/sync.rs +++ b/crates/uv/src/commands/project/sync.rs @@ -50,13 +50,15 @@ use crate::commands::project::{ }; use crate::commands::{ExitStatus, diagnostics}; use crate::printer::Printer; -use crate::settings::{InstallerSettingsRef, ResolverInstallerSettings, ResolverSettings}; +use crate::settings::{ + InstallerSettingsRef, LockCheck, LockCheckSource, ResolverInstallerSettings, ResolverSettings, +}; /// Sync the project environment. #[allow(clippy::fn_params_excessive_bools)] pub(crate) async fn sync( project_dir: &Path, - locked: bool, + lock_check: LockCheck, frozen: bool, dry_run: DryRun, active: Option, @@ -217,9 +219,9 @@ pub(crate) async fn sync( )); } - if locked { + if let LockCheck::Enabled(lock_check) = lock_check { return Err(anyhow::anyhow!( - "`uv sync --locked` requires a script lockfile; run `{}` to lock the script", + "`uv sync {lock_check}` requires a script lockfile; run `{}` to lock the script", format!("uv lock --script {}", script.path.user_display()).green(), )); } @@ -304,8 +306,8 @@ pub(crate) async fn sync( // Determine the lock mode. let mode = if frozen { LockMode::Frozen - } else if locked { - LockMode::Locked(environment.interpreter()) + } else if let LockCheck::Enabled(lock_check) = lock_check { + LockMode::Locked(environment.interpreter(), lock_check) } else if dry_run.enabled() { LockMode::DryRun(environment.interpreter()) } else { @@ -338,16 +340,18 @@ pub(crate) async fn sync( .report(err) .map_or(Ok(ExitStatus::Failure), |err| Err(err.into())); } - Err(ProjectError::LockMismatch(prev, cur)) => { + Err(ProjectError::LockMismatch(prev, cur, lock_source)) => { if dry_run.enabled() { // The lockfile is mismatched, but we're in dry-run mode. We should proceed with the // sync operation, but exit with a non-zero status. - Outcome::LockMismatch(prev, cur) + Outcome::LockMismatch(prev, cur, lock_source) } else { writeln!( printer.stderr(), "{}", - ProjectError::LockMismatch(prev, cur).to_string().bold() + ProjectError::LockMismatch(prev, cur, lock_source) + .to_string() + .bold() )?; return Ok(ExitStatus::Failure); } @@ -415,11 +419,13 @@ pub(crate) async fn sync( match outcome { Outcome::Success(..) => Ok(ExitStatus::Success), - Outcome::LockMismatch(prev, cur) => { + Outcome::LockMismatch(prev, cur, lock_source) => { writeln!( printer.stderr(), "{}", - ProjectError::LockMismatch(prev, cur).to_string().bold() + ProjectError::LockMismatch(prev, cur, lock_source) + .to_string() + .bold() )?; Ok(ExitStatus::Failure) } @@ -433,7 +439,7 @@ enum Outcome { /// The `lock` operation was successful. Success(LockResult), /// The `lock` operation successfully resolved, but failed due to a mismatch (e.g., with `--locked`). - LockMismatch(Option>, Box), + LockMismatch(Option>, Box, LockCheckSource), } impl Outcome { @@ -444,7 +450,7 @@ impl Outcome { LockResult::Changed(_, lock) => lock, LockResult::Unchanged(lock) => lock, }, - Self::LockMismatch(_prev, cur) => cur, + Self::LockMismatch(_prev, cur, _lock_source) => cur, } } } @@ -1272,7 +1278,7 @@ impl From<(&LockTarget<'_>, &LockMode<'_>, &Outcome)> for LockReport { LockResult::Unchanged(..) => match mode { // When `--frozen` is used, we don't check the lockfile LockMode::Frozen => LockAction::Use, - LockMode::DryRun(_) | LockMode::Locked(_) | LockMode::Write(_) => { + LockMode::DryRun(_) | LockMode::Locked(_, _) | LockMode::Write(_) => { LockAction::Check } }, diff --git a/crates/uv/src/commands/project/tree.rs b/crates/uv/src/commands/project/tree.rs index 667415fc0..49d2a25d1 100644 --- a/crates/uv/src/commands/project/tree.rs +++ b/crates/uv/src/commands/project/tree.rs @@ -29,6 +29,7 @@ use crate::commands::project::{ use crate::commands::reporters::LatestVersionReporter; use crate::commands::{ExitStatus, diagnostics}; use crate::printer::Printer; +use crate::settings::LockCheck; use crate::settings::ResolverSettings; /// Run a command. @@ -36,7 +37,7 @@ use crate::settings::ResolverSettings; pub(crate) async fn tree( project_dir: &Path, groups: DependencyGroups, - locked: bool, + lock_check: LockCheck, frozen: bool, universal: bool, depth: u8, @@ -125,8 +126,8 @@ pub(crate) async fn tree( // Determine the lock mode. let mode = if frozen { LockMode::Frozen - } else if locked { - LockMode::Locked(interpreter.as_ref().unwrap()) + } else if let LockCheck::Enabled(lock_check) = lock_check { + LockMode::Locked(interpreter.as_ref().unwrap(), lock_check) } else if matches!(target, LockTarget::Script(_)) && !target.lock_path().is_file() { // If we're locking a script, avoid creating a lockfile if it doesn't already exist. LockMode::DryRun(interpreter.as_ref().unwrap()) diff --git a/crates/uv/src/commands/project/version.rs b/crates/uv/src/commands/project/version.rs index 09a6810b7..e19011092 100644 --- a/crates/uv/src/commands/project/version.rs +++ b/crates/uv/src/commands/project/version.rs @@ -38,7 +38,7 @@ use crate::commands::project::{ }; use crate::commands::{ExitStatus, diagnostics, project}; use crate::printer::Printer; -use crate::settings::ResolverInstallerSettings; +use crate::settings::{LockCheck, ResolverInstallerSettings}; /// Display version information for uv itself (`uv self version`) pub(crate) fn self_version( @@ -63,7 +63,7 @@ pub(crate) async fn project_version( package: Option, explicit_project: bool, dry_run: bool, - locked: bool, + lock_check: LockCheck, frozen: bool, active: Option, no_sync: bool, @@ -297,7 +297,7 @@ pub(crate) async fn project_version( Box::pin(lock_and_sync( project, project_dir, - locked, + lock_check, frozen, active, no_sync, @@ -502,7 +502,7 @@ async fn print_frozen_version( async fn lock_and_sync( project: VirtualProject, project_dir: &Path, - locked: bool, + lock_check: LockCheck, frozen: bool, active: Option, no_sync: bool, @@ -579,8 +579,8 @@ async fn lock_and_sync( }; // Determine the lock mode. - let mode = if locked { - LockMode::Locked(target.interpreter()) + let mode = if let LockCheck::Enabled(lock_check) = lock_check { + LockMode::Locked(target.interpreter(), lock_check) } else { LockMode::Write(target.interpreter()) }; diff --git a/crates/uv/src/lib.rs b/crates/uv/src/lib.rs index 350ea1505..35b1569d2 100644 --- a/crates/uv/src/lib.rs +++ b/crates/uv/src/lib.rs @@ -1844,7 +1844,7 @@ async fn run_project( command, requirements, args.show_resolution || globals.verbose > 0, - args.locked, + args.lock_check, args.frozen, args.active, args.no_sync, @@ -1895,7 +1895,7 @@ async fn run_project( Box::pin(commands::sync( project_dir, - args.locked, + args.lock_check, args.frozen, args.dry_run, args.active, @@ -1951,7 +1951,7 @@ async fn run_project( Box::pin(commands::lock( project_dir, - args.locked, + args.lock_check, args.frozen, args.dry_run, args.refresh, @@ -2056,7 +2056,7 @@ async fn run_project( Box::pin(commands::add( project_dir, - args.locked, + args.lock_check, args.frozen, args.active, args.no_sync, @@ -2114,7 +2114,7 @@ async fn run_project( Box::pin(commands::remove( project_dir, - args.locked, + args.lock_check, args.frozen, args.active, args.no_sync, @@ -2158,7 +2158,7 @@ async fn run_project( args.package, explicit_project, args.dry_run, - args.locked, + args.lock_check, args.frozen, args.active, args.no_sync, @@ -2195,7 +2195,7 @@ async fn run_project( Box::pin(commands::tree( project_dir, args.groups, - args.locked, + args.lock_check, args.frozen, args.universal, args.depth, @@ -2249,7 +2249,7 @@ async fn run_project( args.extras, args.groups, args.editable, - args.locked, + args.lock_check, args.frozen, args.include_annotations, args.include_header, diff --git a/crates/uv/src/settings.rs b/crates/uv/src/settings.rs index 4e2da8b5c..25d11cab7 100644 --- a/crates/uv/src/settings.rs +++ b/crates/uv/src/settings.rs @@ -347,10 +347,37 @@ impl InitSettings { } } +/// The source of a lock check operation. +#[derive(Debug, Clone, Copy)] +pub(crate) enum LockCheckSource { + /// The user invoked `uv --locked` + Locked, + /// The user invoked `uv --check` + Check, +} + +impl std::fmt::Display for LockCheckSource { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Locked => write!(f, "--locked"), + Self::Check => write!(f, "--check"), + } + } +} + +// Has lock check been enabled? +#[derive(Debug, Clone, Copy)] +pub(crate) enum LockCheck { + /// Lockfile check is enabled. + Enabled(LockCheckSource), + /// Lockfile check is disabled. + Disabled, +} + /// The resolved settings to use for a `run` invocation. #[derive(Debug, Clone)] pub(crate) struct RunSettings { - pub(crate) locked: bool, + pub(crate) lock_check: LockCheck, pub(crate) frozen: bool, pub(crate) extras: ExtrasSpecification, pub(crate) groups: DependencyGroups, @@ -439,7 +466,11 @@ impl RunSettings { .unwrap_or_default(); Self { - locked, + lock_check: if locked { + LockCheck::Enabled(LockCheckSource::Locked) + } else { + LockCheck::Disabled + }, frozen, extras: ExtrasSpecification::from_args( extra.unwrap_or_default(), @@ -1263,7 +1294,7 @@ impl PythonPinSettings { #[allow(clippy::struct_excessive_bools, dead_code)] #[derive(Debug, Clone)] pub(crate) struct SyncSettings { - pub(crate) locked: bool, + pub(crate) lock_check: LockCheck, pub(crate) frozen: bool, pub(crate) dry_run: DryRun, pub(crate) script: Option, @@ -1345,10 +1376,15 @@ impl SyncSettings { } else { DryRun::from_args(dry_run) }; + let lock_check = if locked { + LockCheck::Enabled(LockCheckSource::Locked) + } else { + LockCheck::Disabled + }; Self { output_format, - locked, + lock_check, frozen, dry_run, script, @@ -1401,7 +1437,7 @@ impl SyncSettings { #[allow(clippy::struct_excessive_bools, dead_code)] #[derive(Debug, Clone)] pub(crate) struct LockSettings { - pub(crate) locked: bool, + pub(crate) lock_check: LockCheck, pub(crate) frozen: bool, pub(crate) dry_run: DryRun, pub(crate) script: Option, @@ -1421,6 +1457,7 @@ impl LockSettings { ) -> Self { let LockArgs { check, + locked, check_exists, dry_run, script, @@ -1435,8 +1472,16 @@ impl LockSettings { .map(|fs| fs.install_mirrors.clone()) .unwrap_or_default(); + let lock_check = if check { + LockCheck::Enabled(LockCheckSource::Check) + } else if locked { + LockCheck::Enabled(LockCheckSource::Locked) + } else { + LockCheck::Disabled + }; + Self { - locked: check, + lock_check, frozen: check_exists, dry_run: DryRun::from_args(dry_run), script, @@ -1454,7 +1499,7 @@ impl LockSettings { #[allow(clippy::struct_excessive_bools, dead_code)] #[derive(Debug, Clone)] pub(crate) struct AddSettings { - pub(crate) locked: bool, + pub(crate) lock_check: LockCheck, pub(crate) frozen: bool, pub(crate) active: Option, pub(crate) no_sync: bool, @@ -1603,7 +1648,11 @@ impl AddSettings { let bounds = bounds.or(filesystem.as_ref().and_then(|fs| fs.add.add_bounds)); Self { - locked, + lock_check: if locked { + LockCheck::Enabled(LockCheckSource::Locked) + } else { + LockCheck::Disabled + }, frozen, active: flag(active, no_active, "active"), no_sync, @@ -1646,7 +1695,7 @@ impl AddSettings { #[allow(clippy::struct_excessive_bools, dead_code)] #[derive(Debug, Clone)] pub(crate) struct RemoveSettings { - pub(crate) locked: bool, + pub(crate) lock_check: LockCheck, pub(crate) frozen: bool, pub(crate) active: Option, pub(crate) no_sync: bool, @@ -1707,7 +1756,11 @@ impl RemoveSettings { .collect(); Self { - locked, + lock_check: if locked { + LockCheck::Enabled(LockCheckSource::Locked) + } else { + LockCheck::Disabled + }, frozen, active: flag(active, no_active, "active"), no_sync, @@ -1737,7 +1790,7 @@ pub(crate) struct VersionSettings { pub(crate) short: bool, pub(crate) output_format: VersionFormat, pub(crate) dry_run: bool, - pub(crate) locked: bool, + pub(crate) lock_check: LockCheck, pub(crate) frozen: bool, pub(crate) active: Option, pub(crate) no_sync: bool, @@ -1785,7 +1838,11 @@ impl VersionSettings { short, output_format, dry_run, - locked, + lock_check: if locked { + LockCheck::Enabled(LockCheckSource::Locked) + } else { + LockCheck::Disabled + }, frozen, active: flag(active, no_active, "active"), no_sync, @@ -1807,7 +1864,7 @@ impl VersionSettings { #[derive(Debug, Clone)] pub(crate) struct TreeSettings { pub(crate) groups: DependencyGroups, - pub(crate) locked: bool, + pub(crate) lock_check: LockCheck, pub(crate) frozen: bool, pub(crate) universal: bool, pub(crate) depth: u8, @@ -1870,7 +1927,11 @@ impl TreeSettings { only_group, all_groups, ), - locked, + lock_check: if locked { + LockCheck::Enabled(LockCheckSource::Locked) + } else { + LockCheck::Disabled + }, frozen, universal, depth: tree.depth, @@ -1906,7 +1967,7 @@ pub(crate) struct ExportSettings { pub(crate) hashes: bool, pub(crate) install_options: InstallOptions, pub(crate) output_file: Option, - pub(crate) locked: bool, + pub(crate) lock_check: LockCheck, pub(crate) frozen: bool, pub(crate) include_annotations: bool, pub(crate) include_header: bool, @@ -2001,7 +2062,11 @@ impl ExportSettings { no_emit_package, ), output_file, - locked, + lock_check: if locked { + LockCheck::Enabled(LockCheckSource::Locked) + } else { + LockCheck::Disabled + }, frozen, include_annotations: flag(annotate, no_annotate, "annotate").unwrap_or(true), include_header: flag(header, no_header, "header").unwrap_or(true), diff --git a/crates/uv/tests/it/lock.rs b/crates/uv/tests/it/lock.rs index c7b5c6093..b9d54bd44 100644 --- a/crates/uv/tests/it/lock.rs +++ b/crates/uv/tests/it/lock.rs @@ -13193,7 +13193,7 @@ fn check_outdated_lock() -> Result<()> { ----- stderr ----- Resolved 2 packages in [TIME] - The lockfile at `uv.lock` needs to be updated, but `--locked` was provided. To update the lockfile, run `uv lock`. + The lockfile at `uv.lock` needs to be updated, but `--check` was provided. To update the lockfile, run `uv lock`. "); Ok(()) } diff --git a/crates/uv/tests/it/show_settings.rs b/crates/uv/tests/it/show_settings.rs index e82135f0d..9ee19e5c4 100644 --- a/crates/uv/tests/it/show_settings.rs +++ b/crates/uv/tests/it/show_settings.rs @@ -7780,7 +7780,7 @@ fn preview_features() { short: false, output_format: Text, dry_run: false, - locked: false, + lock_check: Disabled, frozen: false, active: None, no_sync: false, @@ -7894,7 +7894,7 @@ fn preview_features() { short: false, output_format: Text, dry_run: false, - locked: false, + lock_check: Disabled, frozen: false, active: None, no_sync: false, @@ -8008,7 +8008,7 @@ fn preview_features() { short: false, output_format: Text, dry_run: false, - locked: false, + lock_check: Disabled, frozen: false, active: None, no_sync: false, @@ -8122,7 +8122,7 @@ fn preview_features() { short: false, output_format: Text, dry_run: false, - locked: false, + lock_check: Disabled, frozen: false, active: None, no_sync: false, @@ -8236,7 +8236,7 @@ fn preview_features() { short: false, output_format: Text, dry_run: false, - locked: false, + lock_check: Disabled, frozen: false, active: None, no_sync: false, @@ -8352,7 +8352,7 @@ fn preview_features() { short: false, output_format: Text, dry_run: false, - locked: false, + lock_check: Disabled, frozen: false, active: None, no_sync: false, @@ -9596,7 +9596,7 @@ fn upgrade_project_cli_config_interaction() -> anyhow::Result<()> { ), } LockSettings { - locked: false, + lock_check: Disabled, frozen: false, dry_run: Disabled, script: None, @@ -9715,7 +9715,7 @@ fn upgrade_project_cli_config_interaction() -> anyhow::Result<()> { ), } LockSettings { - locked: false, + lock_check: Disabled, frozen: false, dry_run: Disabled, script: None, @@ -9857,7 +9857,7 @@ fn upgrade_project_cli_config_interaction() -> anyhow::Result<()> { ), } LockSettings { - locked: false, + lock_check: Disabled, frozen: false, dry_run: Disabled, script: None, @@ -9974,7 +9974,7 @@ fn upgrade_project_cli_config_interaction() -> anyhow::Result<()> { ), } LockSettings { - locked: false, + lock_check: Disabled, frozen: false, dry_run: Disabled, script: None, @@ -10081,7 +10081,7 @@ fn upgrade_project_cli_config_interaction() -> anyhow::Result<()> { ), } LockSettings { - locked: false, + lock_check: Disabled, frozen: false, dry_run: Disabled, script: None, @@ -10189,7 +10189,7 @@ fn upgrade_project_cli_config_interaction() -> anyhow::Result<()> { ), } LockSettings { - locked: false, + lock_check: Disabled, frozen: false, dry_run: Disabled, script: None, diff --git a/docs/reference/cli.md b/docs/reference/cli.md index 20b3b74d1..6c083ddc7 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -1634,7 +1634,7 @@ uv lock [OPTIONS]

May also be set with the UV_INSECURE_HOST environment variable.

--cache-dir cache-dir

Path to the cache directory.

Defaults to $XDG_CACHE_HOME/uv or $HOME/.cache/uv on macOS and Linux, and %LOCALAPPDATA%\uv\cache on Windows.

To view the location of the cache directory, run uv cache dir.

-

May also be set with the UV_CACHE_DIR environment variable.

--check, --locked

Check if the lockfile is up-to-date.

+

May also be set with the UV_CACHE_DIR environment variable.

--check

Check if the lockfile is up-to-date.

Asserts that the uv.lock would remain unchanged after a resolution. If the lockfile is missing or needs to be updated, uv will exit with an error.

Equivalent to --locked.

May also be set with the UV_LOCKED environment variable.

--check-exists, --frozen

Assert that a uv.lock exists without checking if it is up-to-date.