mirror of
https://github.com/rust-lang/cargo.git
synced 2025-09-28 11:20:36 +00:00
Move hardlink_or_copy to a common location so it can be reused.
This commit is contained in:
parent
aca3274f6b
commit
674150e473
@ -19,13 +19,12 @@ use std::env;
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::fs::{self, File};
|
||||
use std::io::Write;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
use failure::Error;
|
||||
use lazycell::LazyCell;
|
||||
use log::debug;
|
||||
use same_file::is_same_file;
|
||||
use serde::Serialize;
|
||||
|
||||
pub use self::build_config::{BuildConfig, CompileMode, MessageFormat};
|
||||
@ -443,12 +442,12 @@ fn link_targets<'a, 'cfg>(
|
||||
}
|
||||
};
|
||||
destinations.push(dst.clone());
|
||||
hardlink_or_copy(src, dst)?;
|
||||
paths::link_or_copy(src, dst)?;
|
||||
if let Some(ref path) = output.export_path {
|
||||
let export_dir = export_dir.as_ref().unwrap();
|
||||
paths::create_dir_all(export_dir)?;
|
||||
|
||||
hardlink_or_copy(src, path)?;
|
||||
paths::link_or_copy(src, path)?;
|
||||
}
|
||||
}
|
||||
|
||||
@ -477,54 +476,6 @@ fn link_targets<'a, 'cfg>(
|
||||
}))
|
||||
}
|
||||
|
||||
/// Hardlink (file) or symlink (dir) src to dst if possible, otherwise copy it.
|
||||
fn hardlink_or_copy(src: &Path, dst: &Path) -> CargoResult<()> {
|
||||
debug!("linking {} to {}", src.display(), dst.display());
|
||||
if is_same_file(src, dst).unwrap_or(false) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// NB: we can't use dst.exists(), as if dst is a broken symlink,
|
||||
// dst.exists() will return false. This is problematic, as we still need to
|
||||
// unlink dst in this case. symlink_metadata(dst).is_ok() will tell us
|
||||
// whether dst exists *without* following symlinks, which is what we want.
|
||||
if fs::symlink_metadata(dst).is_ok() {
|
||||
paths::remove_file(&dst)?;
|
||||
}
|
||||
|
||||
let link_result = if src.is_dir() {
|
||||
#[cfg(target_os = "redox")]
|
||||
use std::os::redox::fs::symlink;
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::fs::symlink;
|
||||
#[cfg(windows)]
|
||||
use std::os::windows::fs::symlink_dir as symlink;
|
||||
|
||||
let dst_dir = dst.parent().unwrap();
|
||||
let src = if src.starts_with(dst_dir) {
|
||||
src.strip_prefix(dst_dir).unwrap()
|
||||
} else {
|
||||
src
|
||||
};
|
||||
symlink(src, dst)
|
||||
} else {
|
||||
fs::hard_link(src, dst)
|
||||
};
|
||||
link_result
|
||||
.or_else(|err| {
|
||||
debug!("link failed {}. falling back to fs::copy", err);
|
||||
fs::copy(src, dst).map(|_| ())
|
||||
})
|
||||
.chain_err(|| {
|
||||
format!(
|
||||
"failed to link or copy `{}` to `{}`",
|
||||
src.display(),
|
||||
dst.display()
|
||||
)
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// For all plugin dependencies, add their -L paths (now calculated and present
|
||||
// in `build_script_outputs`) to the dynamic library load path for the command
|
||||
// to execute.
|
||||
|
@ -340,3 +340,63 @@ fn set_not_readonly(p: &Path) -> io::Result<bool> {
|
||||
fs::set_permissions(p, perms)?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
/// Hardlink (file) or symlink (dir) src to dst if possible, otherwise copy it.
|
||||
///
|
||||
/// If the destination already exists, it is removed before linking.
|
||||
pub fn link_or_copy(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> CargoResult<()> {
|
||||
let src = src.as_ref();
|
||||
let dst = dst.as_ref();
|
||||
_link_or_copy(src, dst)
|
||||
}
|
||||
|
||||
fn _link_or_copy(src: &Path, dst: &Path) -> CargoResult<()> {
|
||||
log::debug!("linking {} to {}", src.display(), dst.display());
|
||||
if same_file::is_same_file(src, dst).unwrap_or(false) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// NB: we can't use dst.exists(), as if dst is a broken symlink,
|
||||
// dst.exists() will return false. This is problematic, as we still need to
|
||||
// unlink dst in this case. symlink_metadata(dst).is_ok() will tell us
|
||||
// whether dst exists *without* following symlinks, which is what we want.
|
||||
if fs::symlink_metadata(dst).is_ok() {
|
||||
remove_file(&dst)?;
|
||||
}
|
||||
|
||||
let link_result = if src.is_dir() {
|
||||
#[cfg(target_os = "redox")]
|
||||
use std::os::redox::fs::symlink;
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::fs::symlink;
|
||||
#[cfg(windows)]
|
||||
// FIXME: This should probably panic or have a copy fallback. Symlinks
|
||||
// are not supported in all windows environments. Currently symlinking
|
||||
// is only used for .dSYM directories on macos, but this shouldn't be
|
||||
// accidentally relied upon.
|
||||
use std::os::windows::fs::symlink_dir as symlink;
|
||||
|
||||
let dst_dir = dst.parent().unwrap();
|
||||
let src = if src.starts_with(dst_dir) {
|
||||
src.strip_prefix(dst_dir).unwrap()
|
||||
} else {
|
||||
src
|
||||
};
|
||||
symlink(src, dst)
|
||||
} else {
|
||||
fs::hard_link(src, dst)
|
||||
};
|
||||
link_result
|
||||
.or_else(|err| {
|
||||
log::debug!("link failed {}. falling back to fs::copy", err);
|
||||
fs::copy(src, dst).map(|_| ())
|
||||
})
|
||||
.chain_err(|| {
|
||||
format!(
|
||||
"failed to link or copy `{}` to `{}`",
|
||||
src.display(),
|
||||
dst.display()
|
||||
)
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user