From 2ae60aecb606d4aa1b0f8171b4cb6a58144a693b Mon Sep 17 00:00:00 2001 From: Sandu Turcan Date: Fri, 21 Jun 2024 18:44:43 -0400 Subject: [PATCH] lock with overrides from tool.uv (#4108) --- crates/uv/src/commands/project/add.rs | 3 ++ crates/uv/src/commands/project/lock.rs | 9 +++- crates/uv/src/commands/project/remove.rs | 3 ++ crates/uv/src/commands/project/run.rs | 3 ++ crates/uv/src/main.rs | 4 ++ crates/uv/src/settings.rs | 55 ++++++++++++------------ crates/uv/tests/lock.rs | 50 +++++++++++++++++++++ 7 files changed, 99 insertions(+), 28 deletions(-) diff --git a/crates/uv/src/commands/project/add.rs b/crates/uv/src/commands/project/add.rs index 857b15fcbb417..32385272c37a0 100644 --- a/crates/uv/src/commands/project/add.rs +++ b/crates/uv/src/commands/project/add.rs @@ -1,4 +1,5 @@ use anyhow::Result; +use pypi_types::Requirement; use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder}; use uv_dispatch::BuildDispatch; use uv_distribution::pyproject::{Source, SourceError}; @@ -25,6 +26,7 @@ use crate::settings::ResolverInstallerSettings; #[allow(clippy::too_many_arguments, clippy::fn_params_excessive_bools)] pub(crate) async fn add( requirements: Vec, + overrides: Vec, workspace: bool, dev: bool, editable: Option, @@ -197,6 +199,7 @@ pub(crate) async fn add( &settings.prerelease, &settings.config_setting, settings.exclude_newer.as_ref(), + overrides, &settings.link_mode, &settings.build_options, preview, diff --git a/crates/uv/src/commands/project/lock.rs b/crates/uv/src/commands/project/lock.rs index 2ba87992285d3..908e38002a9ca 100644 --- a/crates/uv/src/commands/project/lock.rs +++ b/crates/uv/src/commands/project/lock.rs @@ -4,6 +4,7 @@ use anstream::eprint; use distribution_types::{IndexLocations, UnresolvedRequirementSpecification}; use install_wheel_rs::linker::LinkMode; +use pypi_types::Requirement; use uv_cache::Cache; use uv_client::{Connectivity, FlatIndexClient, RegistryClientBuilder}; use uv_configuration::{ @@ -32,6 +33,7 @@ use crate::settings::ResolverSettings; pub(crate) async fn lock( python: Option, settings: ResolverSettings, + overrides: Vec, preview: PreviewMode, toolchain_preference: ToolchainPreference, connectivity: Connectivity, @@ -71,6 +73,7 @@ pub(crate) async fn lock( &settings.prerelease, &settings.config_setting, settings.exclude_newer.as_ref(), + overrides, &settings.link_mode, &settings.build_options, preview, @@ -108,6 +111,7 @@ pub(super) async fn do_lock( prerelease: &PreReleaseMode, config_setting: &ConfigSettings, exclude_newer: Option<&ExcludeNewer>, + overrides: Vec, link_mode: &LinkMode, build_options: &BuildOptions, preview: PreviewMode, @@ -124,7 +128,10 @@ pub(super) async fn do_lock( .map(UnresolvedRequirementSpecification::from) .collect(); let constraints = vec![]; - let overrides = vec![]; + let overrides = overrides + .into_iter() + .map(UnresolvedRequirementSpecification::from) + .collect(); let dev = vec![DEV_DEPENDENCIES.clone()]; let source_trees = vec![]; diff --git a/crates/uv/src/commands/project/remove.rs b/crates/uv/src/commands/project/remove.rs index f63d7d198b564..48021e0adacf3 100644 --- a/crates/uv/src/commands/project/remove.rs +++ b/crates/uv/src/commands/project/remove.rs @@ -1,6 +1,7 @@ use anyhow::Result; use pep508_rs::PackageName; +use pypi_types::Requirement; use uv_cache::Cache; use uv_client::Connectivity; use uv_configuration::{Concurrency, ExtrasSpecification, PreviewMode}; @@ -18,6 +19,7 @@ use crate::settings::{InstallerSettings, ResolverSettings}; #[allow(clippy::too_many_arguments)] pub(crate) async fn remove( requirements: Vec, + overrides: Vec, dev: bool, python: Option, toolchain_preference: ToolchainPreference, @@ -109,6 +111,7 @@ pub(crate) async fn remove( &settings.prerelease, &settings.config_setting, settings.exclude_newer.as_ref(), + overrides, &settings.link_mode, &settings.build_options, preview, diff --git a/crates/uv/src/commands/project/run.rs b/crates/uv/src/commands/project/run.rs index 36b887db55271..dc633207fe0ef 100644 --- a/crates/uv/src/commands/project/run.rs +++ b/crates/uv/src/commands/project/run.rs @@ -3,6 +3,7 @@ use std::path::PathBuf; use anyhow::{Context, Result}; use itertools::Itertools; +use pypi_types::Requirement; use tokio::process::Command; use tracing::debug; @@ -30,6 +31,7 @@ pub(crate) async fn run( dev: bool, command: ExternalCommand, requirements: Vec, + overrides: Vec, python: Option, package: Option, settings: ResolverInstallerSettings, @@ -86,6 +88,7 @@ pub(crate) async fn run( &settings.prerelease, &settings.config_setting, settings.exclude_newer.as_ref(), + overrides, &settings.link_mode, &settings.build_options, preview, diff --git a/crates/uv/src/main.rs b/crates/uv/src/main.rs index 069405b64b026..72bddb4b954bf 100644 --- a/crates/uv/src/main.rs +++ b/crates/uv/src/main.rs @@ -648,6 +648,7 @@ async fn run() -> Result { args.dev, args.command, requirements, + args.overrides_from_workspace, args.python, args.package, args.settings, @@ -697,6 +698,7 @@ async fn run() -> Result { commands::lock( args.python, args.settings, + args.overrides_from_workspace, globals.preview, globals.toolchain_preference, globals.connectivity, @@ -717,6 +719,7 @@ async fn run() -> Result { commands::add( args.requirements, + args.overrides_from_workspace, args.workspace, args.dev, args.editable, @@ -746,6 +749,7 @@ async fn run() -> Result { commands::remove( args.requirements, + args.overrides_from_workspace, args.dev, args.python, globals.toolchain_preference, diff --git a/crates/uv/src/settings.rs b/crates/uv/src/settings.rs index 6605e552ee7a2..40fbedde4d3ae 100644 --- a/crates/uv/src/settings.rs +++ b/crates/uv/src/settings.rs @@ -152,6 +152,7 @@ pub(crate) struct RunSettings { pub(crate) package: Option, pub(crate) refresh: Refresh, pub(crate) settings: ResolverInstallerSettings, + pub(crate) overrides_from_workspace: Vec, } impl RunSettings { @@ -184,6 +185,7 @@ impl RunSettings { python, package, refresh: Refresh::from(refresh), + overrides_from_workspace: overrides_from_workspace(&filesystem), settings: ResolverInstallerSettings::combine( resolver_installer_options(installer, build), filesystem, @@ -366,6 +368,7 @@ pub(crate) struct LockSettings { pub(crate) python: Option, pub(crate) refresh: Refresh, pub(crate) settings: ResolverSettings, + pub(crate) overrides_from_workspace: Vec, } impl LockSettings { @@ -382,6 +385,7 @@ impl LockSettings { Self { python, refresh: Refresh::from(refresh), + overrides_from_workspace: overrides_from_workspace(&filesystem), settings: ResolverSettings::combine(resolver_options(resolver, build), filesystem), } } @@ -392,6 +396,7 @@ impl LockSettings { #[derive(Debug, Clone)] pub(crate) struct AddSettings { pub(crate) requirements: Vec, + pub(crate) overrides_from_workspace: Vec, pub(crate) dev: bool, pub(crate) workspace: bool, pub(crate) editable: Option, @@ -439,6 +444,7 @@ impl AddSettings { branch, python, refresh: Refresh::from(refresh), + overrides_from_workspace: overrides_from_workspace(&filesystem), settings: ResolverInstallerSettings::combine( resolver_installer_options(installer, build), filesystem, @@ -454,12 +460,13 @@ pub(crate) struct RemoveSettings { pub(crate) requirements: Vec, pub(crate) dev: bool, pub(crate) python: Option, + pub(crate) overrides_from_workspace: Vec, } impl RemoveSettings { /// Resolve the [`RemoveSettings`] from the CLI and filesystem configuration. #[allow(clippy::needless_pass_by_value)] - pub(crate) fn resolve(args: RemoveArgs, _filesystem: Option) -> Self { + pub(crate) fn resolve(args: RemoveArgs, filesystem: Option) -> Self { let RemoveArgs { dev, requirements, @@ -470,6 +477,7 @@ impl RemoveSettings { requirements, dev, python, + overrides_from_workspace: overrides_from_workspace(&filesystem), } } } @@ -536,19 +544,7 @@ impl PipCompileSettings { compat_args: _, } = args; - let overrides_from_workspace = if let Some(configuration) = &filesystem { - configuration - .override_dependencies - .clone() - .unwrap_or_default() - .into_iter() - .map(|requirement| { - Requirement::from(requirement.with_origin(RequirementOrigin::Workspace)) - }) - .collect() - } else { - Vec::new() - }; + let overrides_from_workspace = overrides_from_workspace(&filesystem); Self { src_file, @@ -733,19 +729,7 @@ impl PipInstallSettings { compat_args: _, } = args; - let overrides_from_workspace = if let Some(configuration) = &filesystem { - configuration - .override_dependencies - .clone() - .unwrap_or_default() - .into_iter() - .map(|requirement| { - Requirement::from(requirement.with_origin(RequirementOrigin::Workspace)) - }) - .collect() - } else { - Vec::new() - }; + let overrides_from_workspace = overrides_from_workspace(&filesystem); Self { package, @@ -2050,3 +2034,20 @@ fn resolver_installer_options( no_binary_package: Some(no_binary_package), } } + +/// Used by multiple commands to extract dependency overrides +fn overrides_from_workspace(filesystem: &Option) -> Vec { + if let Some(configuration) = &filesystem { + configuration + .override_dependencies + .clone() + .unwrap_or_default() + .into_iter() + .map(|requirement| { + Requirement::from(requirement.with_origin(RequirementOrigin::Workspace)) + }) + .collect() + } else { + Vec::new() + } +} \ No newline at end of file diff --git a/crates/uv/tests/lock.rs b/crates/uv/tests/lock.rs index 9abc58879eb53..5507f718da563 100644 --- a/crates/uv/tests/lock.rs +++ b/crates/uv/tests/lock.rs @@ -583,6 +583,56 @@ fn lock_project_extra() -> Result<()> { Ok(()) } +#[test] +fn lock_project_with_overrides() -> Result<()> { + let context = TestContext::new("3.12"); + + let pyproject_toml = context.temp_dir.child("pyproject.toml"); + pyproject_toml.write_str( + r#" + [project] + name = "project" + version = "0.1.0" + requires-python = ">=3.12" + dependencies = ["flask==3.0.0"] + + [tool.uv] + override-dependencies = ["werkzeug==2.3.8"] + "#, + )?; + + uv_snapshot!(context.filters(), context.lock(), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + warning: `uv lock` is experimental and may change without warning. + Resolved 9 packages in [TIME] + "###); + + // Install the base dependencies from the lockfile. + uv_snapshot!(context.filters(), context.sync(), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + warning: `uv sync` is experimental and may change without warning. + Prepared 8 packages in [TIME] + Installed 8 packages in [TIME] + + blinker==1.7.0 + + click==8.1.7 + + flask==3.0.0 + + itsdangerous==2.1.2 + + jinja2==3.1.3 + + markupsafe==2.1.5 + + project==0.1.0 (from file://[TEMP_DIR]/) + + werkzeug==2.3.8 + "###); + + Ok(()) +} /// Lock a project with a dependency that has an extra. #[test] fn lock_dependency_extra() -> Result<()> {