use crate::error::{Error, Result};
use crate::gen::fs;
use crate::paths;
use std::path::Path;
pub(crate) fn write(path: impl AsRef<Path>, content: &[u8]) -> Result<()> {
let path = path.as_ref();
let mut create_dir_error = None;
if path.exists() {
if let Ok(existing) = fs::read(path) {
if existing == content {
return Ok(());
}
}
best_effort_remove(path);
} else {
let parent = path.parent().unwrap();
create_dir_error = fs::create_dir_all(parent).err();
}
match fs::write(path, content) {
Ok(()) => Ok(()),
Err(err) => Err(Error::Fs(create_dir_error.unwrap_or(err))),
}
}
pub(crate) fn symlink_file(original: impl AsRef<Path>, link: impl AsRef<Path>) -> Result<()> {
let original = original.as_ref();
let link = link.as_ref();
let mut create_dir_error = None;
if link.exists() {
best_effort_remove(link);
} else {
let parent = link.parent().unwrap();
create_dir_error = fs::create_dir_all(parent).err();
}
match paths::symlink_or_copy(original, link) {
Ok(()) => Ok(()),
Err(err) => Err(Error::Fs(create_dir_error.unwrap_or(err))),
}
}
pub(crate) fn symlink_dir(original: impl AsRef<Path>, link: impl AsRef<Path>) -> Result<()> {
let original = original.as_ref();
let link = link.as_ref();
let mut create_dir_error = None;
if link.exists() {
best_effort_remove(link);
} else {
let parent = link.parent().unwrap();
create_dir_error = fs::create_dir_all(parent).err();
}
match fs::symlink_dir(original, link) {
Ok(()) => Ok(()),
Err(err) => Err(Error::Fs(create_dir_error.unwrap_or(err))),
}
}
fn best_effort_remove(path: &Path) {
use std::fs;
let file_type = match if cfg!(windows) {
fs::metadata(path)
} else {
fs::symlink_metadata(path)
} {
Ok(metadata) => metadata.file_type(),
Err(_) => return,
};
if file_type.is_dir() {
let _ = fs::remove_dir_all(path);
} else {
let _ = fs::remove_file(path);
}
}