Skip to content

Commit b09d3de

Browse files
committed
fix(vendor): early Windows 10 versions cannot move dirs
Not sure if it is really needed, though Cargo had better follow what platform support says. > The behavior on Windows is the same on Windows 10 1607 and higher > if `FileRenameInfoEx` is supported by the filesystem; otherwise, > `from` can be anything, but `to` must *not* be a directory. https://doc.rust-lang.org/1.86.0/src/std/fs.rs.html#2430-2435
1 parent d64e8c4 commit b09d3de

File tree

1 file changed

+23
-10
lines changed

1 file changed

+23
-10
lines changed

src/cargo/ops/vendor.rs

+23-10
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use crate::core::SourceId;
33
use crate::core::{GitReference, Package, Workspace};
44
use crate::ops;
55
use crate::sources::path::PathSource;
6-
use crate::sources::PathEntry;
76
use crate::sources::RegistrySource;
87
use crate::sources::SourceConfigMap;
98
use crate::sources::CRATES_IO_REGISTRY;
@@ -255,17 +254,19 @@ fn sync(
255254
_ => unreachable!("not registry source: {sid}"),
256255
};
257256

258-
let mut compute_file_cksums = |root| {
259-
let walkdir = WalkDir::new(root)
257+
let walkdir = |root| {
258+
WalkDir::new(root)
260259
.into_iter()
261260
// It is safe to skip errors,
262261
// since we'll hit them during copying/reading later anyway.
263262
.filter_map(|e| e.ok())
264263
// There should be no symlink in tarballs on crates.io,
265264
// but might be wrong for local registries.
266265
// Hence here be conservative and include symlinks.
267-
.filter(|e| e.file_type().is_file() || e.file_type().is_symlink());
268-
for e in walkdir {
266+
.filter(|e| e.file_type().is_file() || e.file_type().is_symlink())
267+
};
268+
let mut compute_file_cksums = |root| {
269+
for e in walkdir(root) {
269270
let path = e.path();
270271
let relative = path.strip_prefix(&dst).unwrap();
271272
let cksum = Sha256::new()
@@ -289,11 +290,24 @@ fn sync(
289290
.tempdir_in(vendor_dir)?;
290291
let unpacked_src =
291292
registry.unpack_package_in(id, staging_dir.path(), &vendor_this)?;
292-
fs::rename(&unpacked_src, &dst)?;
293-
compute_file_cksums(&dst)?;
293+
if let Err(e) = fs::rename(&unpacked_src, &dst) {
294+
// This fallback is mainly for Windows 10 versions earlier than 1607.
295+
// The destination of `fs::rename` can't be a diretory in older versions.
296+
// Can be removed once the minimal supported Windows version gets bumped.
297+
tracing::warn!("failed to `mv {unpacked_src:?} {dst:?}`: {e}");
298+
let paths: Vec<_> = walkdir(&unpacked_src).map(|e| e.into_path()).collect();
299+
cp_sources(pkg, src, &paths, &dst, &mut file_cksums, &mut tmp_buf, gctx)
300+
.with_context(|| format!("failed to copy vendored sources for {id}"))?;
301+
} else {
302+
compute_file_cksums(&dst)?;
303+
}
294304
}
295305
} else {
296-
let paths = PathSource::new(src, sid, gctx).list_files(pkg)?;
306+
let paths = PathSource::new(src, sid, gctx)
307+
.list_files(pkg)?
308+
.into_iter()
309+
.map(|p| p.into_path_buf())
310+
.collect::<Vec<_>>();
297311
cp_sources(pkg, src, &paths, &dst, &mut file_cksums, &mut tmp_buf, gctx)
298312
.with_context(|| format!("failed to copy vendored sources for {id}"))?;
299313
}
@@ -387,14 +401,13 @@ fn sync(
387401
fn cp_sources(
388402
pkg: &Package,
389403
src: &Path,
390-
paths: &[PathEntry],
404+
paths: &[PathBuf],
391405
dst: &Path,
392406
cksums: &mut BTreeMap<String, String>,
393407
tmp_buf: &mut [u8],
394408
gctx: &GlobalContext,
395409
) -> CargoResult<()> {
396410
for p in paths {
397-
let p = p.as_ref();
398411
let relative = p.strip_prefix(&src).unwrap();
399412

400413
if !vendor_this(relative) {

0 commit comments

Comments
 (0)