Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,13 @@ jobs:
# Write pending snapshots to a separate directory for artifact upload
INSTA_UPDATE: new
INSTA_PENDING_DIR: ${{ github.workspace }}/pending-snapshots
# Dev Drive is ReFS which supports copy-on-write
# Note: trailing backslash is required — `D:` alone is a relative
# path on Windows (current directory on that drive), not the root.
UV_INTERNAL__TEST_COW_FS: "${{ env.DEV_DRIVE }}\\"
# C: is NTFS which does not support copy-on-write
UV_INTERNAL__TEST_NOCOW_FS: "C:\\"
UV_INTERNAL__TEST_ALT_FS: "C:\\"
shell: bash
run: |
cargo nextest run \
Expand Down
2 changes: 1 addition & 1 deletion crates/uv-fs/src/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use walkdir::WalkDir;
///
/// Defaults to [`Clone`](LinkMode::Clone) on macOS and Linux (which support copy-on-write on
/// APFS and btrfs/xfs/bcachefs respectively), and [`Hardlink`](LinkMode::Hardlink) on other
/// platforms.
/// platforms. On Windows, clone can be enabled via the `reflink-windows` preview flag.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
Expand Down
4 changes: 4 additions & 0 deletions crates/uv-preview/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ pub enum PreviewFeature {
PublishRequireNormalized = 1 << 25,
Audit = 1 << 26,
ProjectDirectoryMustExist = 1 << 27,
ReflinkWindows = 1 << 28,
}

impl PreviewFeature {
Expand Down Expand Up @@ -228,6 +229,7 @@ impl PreviewFeature {
Self::PublishRequireNormalized => "publish-require-normalized",
Self::Audit => "audit",
Self::ProjectDirectoryMustExist => "project-directory-must-exist",
Self::ReflinkWindows => "reflink-windows",
}
}
}
Expand Down Expand Up @@ -275,6 +277,7 @@ impl FromStr for PreviewFeature {
"publish-require-normalized" => Self::PublishRequireNormalized,
"audit" => Self::Audit,
"project-directory-must-exist" => Self::ProjectDirectoryMustExist,
"reflink-windows" => Self::ReflinkWindows,
_ => return Err(PreviewFeatureParseError),
})
}
Expand Down Expand Up @@ -524,6 +527,7 @@ mod tests {
PreviewFeature::ProjectDirectoryMustExist.as_str(),
"project-directory-must-exist"
);
assert_eq!(PreviewFeature::ReflinkWindows.as_str(), "reflink-windows");
}

#[test]
Expand Down
2 changes: 1 addition & 1 deletion crates/uv/src/commands/project/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ pub(crate) async fn add(
build_isolation,
&extra_build_requires,
&extra_build_variables,
settings.resolver.link_mode,
crate::effective_link_mode(settings.resolver.link_mode, preview),
&settings.resolver.build_options,
&build_hasher,
settings.resolver.exclude_newer.clone(),
Expand Down
1 change: 1 addition & 0 deletions crates/uv/src/commands/project/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2237,6 +2237,7 @@ pub(crate) async fn sync_environment(
build_options,
sources,
} = settings;
let link_mode = crate::effective_link_mode(link_mode, preview);

let client_builder = client_builder.clone().keyring(keyring_provider);

Expand Down
1 change: 1 addition & 0 deletions crates/uv/src/commands/project/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,7 @@ pub(super) async fn do_sync(
build_options,
sources,
} = settings;
let link_mode = crate::effective_link_mode(link_mode, preview);

// Lower the extra build dependencies with source resolution.
let extra_build_requires = match &target {
Expand Down
25 changes: 21 additions & 4 deletions crates/uv/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ use uv_client::BaseClientBuilder;
use uv_configuration::min_stack_size;
use uv_flags::EnvironmentFlags;
use uv_fs::{CWD, Simplified};
use uv_install_wheel::LinkMode;
#[cfg(feature = "self-update")]
use uv_pep440::release_specifiers_to_ranges;
use uv_pep508::VersionOrUrl;
Expand Down Expand Up @@ -69,6 +70,22 @@ pub(crate) mod settings;
#[cfg(windows)]
mod windows_exception;

/// Returns the effective [`LinkMode`], applying the `reflink-windows` preview override.
///
/// On Windows, the default link mode is [`LinkMode::Hardlink`]. When the `reflink-windows`
/// preview feature is enabled, this overrides the default to [`LinkMode::Clone`] so that
/// copy-on-write is attempted on ReFS/Dev Drive volumes.
pub(crate) fn effective_link_mode(link_mode: LinkMode, preview: uv_preview::Preview) -> LinkMode {
if cfg!(target_os = "windows")
&& link_mode == LinkMode::Hardlink
&& preview.is_enabled(PreviewFeature::ReflinkWindows)
{
LinkMode::Clone
} else {
link_mode
}
}

#[instrument(skip_all)]
async fn run(mut cli: Cli) -> Result<ExitStatus> {
// Enable flag to pick up warnings generated by workspace loading.
Expand Down Expand Up @@ -737,7 +754,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
args.settings.exclude_newer,
args.settings.sources,
args.settings.annotation_style,
args.settings.link_mode,
effective_link_mode(args.settings.link_mode, globals.preview),
args.settings.python,
args.settings.system,
globals.python_preference,
Expand Down Expand Up @@ -798,7 +815,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
&args.settings.extras,
&groups,
args.settings.reinstall,
args.settings.link_mode,
effective_link_mode(args.settings.link_mode, globals.preview),
args.settings.compile_bytecode,
args.settings.hash_checking,
args.settings.index_locations,
Expand Down Expand Up @@ -963,7 +980,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
args.settings.keyring_provider,
&client_builder.subcommand(vec!["pip".to_owned(), "install".to_owned()]),
args.settings.reinstall,
args.settings.link_mode,
effective_link_mode(args.settings.link_mode, globals.preview),
args.settings.compile_bytecode,
args.settings.hash_checking,
globals.installer_metadata,
Expand Down Expand Up @@ -1301,7 +1318,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
args.settings.install_mirrors,
globals.python_preference,
globals.python_downloads,
args.settings.link_mode,
effective_link_mode(args.settings.link_mode, globals.preview),
&args.settings.index_locations,
args.settings.index_strategy,
args.settings.dependency_metadata,
Expand Down
Loading