diff --git a/Cargo.lock b/Cargo.lock index 51d931612..ffd22635b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4507,6 +4507,7 @@ dependencies = [ "fs-err", "futures", "indicatif", + "install-wheel-rs", "itertools 0.12.1", "mimalloc", "owo-colors", @@ -4547,6 +4548,7 @@ dependencies = [ "anyhow", "distribution-types", "futures", + "install-wheel-rs", "itertools 0.12.1", "pep508_rs", "rustc-hash", diff --git a/crates/uv-dev/Cargo.toml b/crates/uv-dev/Cargo.toml index 7f9d323c7..727e89e9f 100644 --- a/crates/uv-dev/Cargo.toml +++ b/crates/uv-dev/Cargo.toml @@ -18,6 +18,7 @@ workspace = true [dependencies] distribution-filename = { workspace = true } distribution-types = { workspace = true } +install-wheel-rs = { workspace = true } pep440_rs = { workspace = true } pep508_rs = { workspace = true } uv-build = { workspace = true } diff --git a/crates/uv-dev/src/build.rs b/crates/uv-dev/src/build.rs index ae6095086..730a09b8b 100644 --- a/crates/uv-dev/src/build.rs +++ b/crates/uv-dev/src/build.rs @@ -73,6 +73,7 @@ pub(crate) async fn build(args: BuildArgs) -> Result { setup_py, &config_settings, BuildIsolation::Isolated, + install_wheel_rs::linker::LinkMode::default(), &NoBuild::None, &NoBinary::None, ); diff --git a/crates/uv-dev/src/resolve_cli.rs b/crates/uv-dev/src/resolve_cli.rs index b4aa0d992..52c171843 100644 --- a/crates/uv-dev/src/resolve_cli.rs +++ b/crates/uv-dev/src/resolve_cli.rs @@ -91,6 +91,7 @@ pub(crate) async fn resolve_cli(args: ResolveCliArgs) -> Result<()> { SetupPyStrategy::default(), &config_settings, BuildIsolation::Isolated, + install_wheel_rs::linker::LinkMode::default(), &no_build, &NoBinary::None, ); diff --git a/crates/uv-dev/src/resolve_many.rs b/crates/uv-dev/src/resolve_many.rs index 761fcbed6..eee4b8613 100644 --- a/crates/uv-dev/src/resolve_many.rs +++ b/crates/uv-dev/src/resolve_many.rs @@ -115,6 +115,7 @@ pub(crate) async fn resolve_many(args: ResolveManyArgs) -> Result<()> { setup_py, &config_settings, BuildIsolation::Isolated, + install_wheel_rs::linker::LinkMode::default(), &no_build, &NoBinary::None, ); diff --git a/crates/uv-dispatch/Cargo.toml b/crates/uv-dispatch/Cargo.toml index 7cd8476d4..afbb53741 100644 --- a/crates/uv-dispatch/Cargo.toml +++ b/crates/uv-dispatch/Cargo.toml @@ -15,15 +15,16 @@ workspace = true [dependencies] distribution-types = { workspace = true } +install-wheel-rs = { workspace = true } pep508_rs = { workspace = true } uv-build = { workspace = true } uv-cache = { workspace = true } uv-client = { workspace = true } +uv-configuration = { workspace = true } uv-installer = { workspace = true } uv-interpreter = { workspace = true } uv-resolver = { workspace = true } uv-types = { workspace = true } -uv-configuration = { workspace = true } anyhow = { workspace = true } futures = { workspace = true } diff --git a/crates/uv-dispatch/src/lib.rs b/crates/uv-dispatch/src/lib.rs index b204b9a1f..b5858ce7e 100644 --- a/crates/uv-dispatch/src/lib.rs +++ b/crates/uv-dispatch/src/lib.rs @@ -35,6 +35,7 @@ pub struct BuildDispatch<'a> { in_flight: &'a InFlight, setup_py: SetupPyStrategy, build_isolation: BuildIsolation<'a>, + link_mode: install_wheel_rs::linker::LinkMode, no_build: &'a NoBuild, no_binary: &'a NoBinary, config_settings: &'a ConfigSettings, @@ -56,6 +57,7 @@ impl<'a> BuildDispatch<'a> { setup_py: SetupPyStrategy, config_settings: &'a ConfigSettings, build_isolation: BuildIsolation<'a>, + link_mode: install_wheel_rs::linker::LinkMode, no_build: &'a NoBuild, no_binary: &'a NoBinary, ) -> Self { @@ -70,6 +72,7 @@ impl<'a> BuildDispatch<'a> { setup_py, config_settings, build_isolation, + link_mode, no_build, no_binary, source_build_context: SourceBuildContext::default(), @@ -262,6 +265,7 @@ impl<'a> BuildContext for BuildDispatch<'a> { wheels.iter().map(ToString::to_string).join(", ") ); Installer::new(venv) + .with_link_mode(self.link_mode) .install(&wheels) .context("Failed to install build dependencies")?; } diff --git a/crates/uv/src/cli.rs b/crates/uv/src/cli.rs index 7e6045edd..cfdb719d3 100644 --- a/crates/uv/src/cli.rs +++ b/crates/uv/src/cli.rs @@ -323,6 +323,15 @@ pub(crate) struct PipCompileArgs { #[clap(long)] pub(crate) refresh_package: Vec, + /// The method to use when installing packages from the global cache. + /// + /// This option is only used when creating build environments for source distributions. + /// + /// Defaults to `clone` (also known as Copy-on-Write) on macOS, and `hardlink` on Linux and + /// Windows. + #[clap(long, value_enum, default_value_t = install_wheel_rs::linker::LinkMode::default())] + pub(crate) link_mode: install_wheel_rs::linker::LinkMode, + /// The URL of the Python package index (by default: ). /// /// The index given by this flag is given lower priority than all other @@ -1239,6 +1248,15 @@ pub(crate) struct VenvArgs { #[clap(long)] pub(crate) system_site_packages: bool, + /// The method to use when installing packages from the global cache. + /// + /// This option is only used for installing seed packages. + /// + /// Defaults to `clone` (also known as Copy-on-Write) on macOS, and `hardlink` on Linux and + /// Windows. + #[clap(long, value_enum, default_value_t = install_wheel_rs::linker::LinkMode::default())] + pub(crate) link_mode: install_wheel_rs::linker::LinkMode, + /// The URL of the Python package index (by default: ). /// /// The index given by this flag is given lower priority than all other diff --git a/crates/uv/src/commands/pip_compile.rs b/crates/uv/src/commands/pip_compile.rs index 72020f972..2f5b82bb0 100644 --- a/crates/uv/src/commands/pip_compile.rs +++ b/crates/uv/src/commands/pip_compile.rs @@ -15,6 +15,7 @@ use tempfile::tempdir_in; use tracing::debug; use distribution_types::{IndexLocations, LocalEditable, LocalEditables, Verbatim}; +use install_wheel_rs::linker::LinkMode; use platform_tags::Tags; use requirements_txt::EditableRequirement; use uv_auth::{KeyringProvider, GLOBAL_AUTH_STORE}; @@ -80,6 +81,7 @@ pub(crate) async fn pip_compile( annotation_style: AnnotationStyle, native_tls: bool, quiet: bool, + link_mode: LinkMode, cache: Cache, printer: Printer, ) -> Result { @@ -262,6 +264,7 @@ pub(crate) async fn pip_compile( setup_py, &config_settings, build_isolation, + link_mode, &no_build, &NoBinary::None, ) diff --git a/crates/uv/src/commands/pip_install.rs b/crates/uv/src/commands/pip_install.rs index 63ff8af1e..4e30b7c42 100644 --- a/crates/uv/src/commands/pip_install.rs +++ b/crates/uv/src/commands/pip_install.rs @@ -255,6 +255,7 @@ pub(crate) async fn pip_install( setup_py, config_settings, build_isolation, + link_mode, &no_build, &no_binary, ) @@ -382,6 +383,7 @@ pub(crate) async fn pip_install( setup_py, config_settings, build_isolation, + link_mode, &no_build, &no_binary, ) diff --git a/crates/uv/src/commands/pip_sync.rs b/crates/uv/src/commands/pip_sync.rs index 218ad29c3..04635672d 100644 --- a/crates/uv/src/commands/pip_sync.rs +++ b/crates/uv/src/commands/pip_sync.rs @@ -205,6 +205,7 @@ pub(crate) async fn pip_sync( setup_py, config_settings, build_isolation, + link_mode, &no_build, &no_binary, ); diff --git a/crates/uv/src/commands/venv.rs b/crates/uv/src/commands/venv.rs index 6f44fecbe..72674689b 100644 --- a/crates/uv/src/commands/venv.rs +++ b/crates/uv/src/commands/venv.rs @@ -12,6 +12,7 @@ use owo_colors::OwoColorize; use thiserror::Error; use distribution_types::{DistributionMetadata, IndexLocations, Name, ResolvedDist}; +use install_wheel_rs::linker::LinkMode; use pep508_rs::Requirement; use uv_auth::{KeyringProvider, GLOBAL_AUTH_STORE}; use uv_cache::Cache; @@ -32,6 +33,7 @@ use crate::shell::Shell; pub(crate) async fn venv( path: &Path, python_request: Option<&str>, + link_mode: LinkMode, index_locations: &IndexLocations, index_strategy: IndexStrategy, keyring_provider: KeyringProvider, @@ -47,6 +49,7 @@ pub(crate) async fn venv( match venv_impl( path, python_request, + link_mode, index_locations, index_strategy, keyring_provider, @@ -93,6 +96,7 @@ enum VenvError { async fn venv_impl( path: &Path, python_request: Option<&str>, + link_mode: LinkMode, index_locations: &IndexLocations, index_strategy: IndexStrategy, keyring_provider: KeyringProvider, @@ -197,6 +201,7 @@ async fn venv_impl( SetupPyStrategy::default(), &config_settings, BuildIsolation::Isolated, + link_mode, &NoBuild::All, &NoBinary::None, ) diff --git a/crates/uv/src/main.rs b/crates/uv/src/main.rs index f34fa774c..e18928c45 100644 --- a/crates/uv/src/main.rs +++ b/crates/uv/src/main.rs @@ -245,6 +245,7 @@ async fn run() -> Result { args.annotation_style, cli.native_tls, cli.quiet, + args.link_mode, cache, printer, ) @@ -514,6 +515,7 @@ async fn run() -> Result { commands::venv( &args.name, args.python.as_deref(), + args.link_mode, &index_locations, args.index_strategy, args.keyring_provider,