use std::io;
use std::path::{Path, PathBuf};
pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
fn copy_dir_all_inner(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
let dst = dst.as_ref();
if !dst.is_dir() {
std::fs::create_dir_all(&dst)?;
}
for entry in std::fs::read_dir(src)? {
let entry = entry?;
let ty = entry.file_type()?;
if ty.is_dir() {
copy_dir_all_inner(entry.path(), dst.join(entry.file_name()))?;
} else if ty.is_symlink() {
let target_path = std::fs::read_link(entry.path())?;
let new_symlink_path = dst.join(entry.file_name());
#[cfg(windows)]
{
use std::os::windows::fs::FileTypeExt;
if ty.is_symlink_dir() {
std::os::windows::fs::symlink_dir(&target_path, new_symlink_path)?;
} else {
std::os::windows::fs::symlink_file(&target_path, new_symlink_path)?;
}
}
#[cfg(unix)]
{
std::os::unix::fs::symlink(target_path, new_symlink_path)?;
}
#[cfg(not(any(windows, unix)))]
{
unimplemented!("unsupported target");
}
} else {
std::fs::copy(entry.path(), dst.join(entry.file_name()))?;
}
}
Ok(())
}
if let Err(e) = copy_dir_all_inner(&src, &dst) {
panic!(
"failed to copy `{}` to `{}`: {:?}",
src.as_ref().display(),
dst.as_ref().display(),
e
);
}
}
pub fn read_dir_entries<P: AsRef<Path>, F: FnMut(&Path)>(dir: P, mut callback: F) {
for entry in read_dir(dir) {
callback(&entry.unwrap().path());
}
}
#[track_caller]
pub fn remove_file<P: AsRef<Path>>(path: P) {
if let Err(e) = std::fs::remove_file(path.as_ref()) {
panic!("failed to remove file at `{}`: {e}", path.as_ref().display());
}
}
#[track_caller]
pub fn remove_dir<P: AsRef<Path>>(path: P) {
if let Err(e) = std::fs::remove_dir(path.as_ref()) {
panic!("failed to remove directory at `{}`: {e}", path.as_ref().display());
}
}
#[track_caller]
pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) {
std::fs::copy(from.as_ref(), to.as_ref()).expect(&format!(
"the file \"{}\" could not be copied over to \"{}\"",
from.as_ref().display(),
to.as_ref().display(),
));
}
#[track_caller]
pub fn create_file<P: AsRef<Path>>(path: P) {
std::fs::File::create(path.as_ref())
.expect(&format!("the file in path \"{}\" could not be created", path.as_ref().display()));
}
#[track_caller]
pub fn read<P: AsRef<Path>>(path: P) -> Vec<u8> {
std::fs::read(path.as_ref())
.expect(&format!("the file in path \"{}\" could not be read", path.as_ref().display()))
}
#[track_caller]
pub fn read_to_string<P: AsRef<Path>>(path: P) -> String {
std::fs::read_to_string(path.as_ref()).expect(&format!(
"the file in path \"{}\" could not be read into a String",
path.as_ref().display()
))
}
#[track_caller]
pub fn read_dir<P: AsRef<Path>>(path: P) -> std::fs::ReadDir {
std::fs::read_dir(path.as_ref())
.expect(&format!("the directory in path \"{}\" could not be read", path.as_ref().display()))
}
#[track_caller]
pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) {
std::fs::write(path.as_ref(), contents.as_ref()).expect(&format!(
"the file in path \"{}\" could not be written to",
path.as_ref().display()
));
}
#[track_caller]
pub fn remove_dir_all<P: AsRef<Path>>(path: P) {
std::fs::remove_dir_all(path.as_ref()).expect(&format!(
"the directory in path \"{}\" could not be removed alongside all its contents",
path.as_ref().display(),
));
}
#[track_caller]
pub fn create_dir<P: AsRef<Path>>(path: P) {
std::fs::create_dir(path.as_ref()).expect(&format!(
"the directory in path \"{}\" could not be created",
path.as_ref().display()
));
}
#[track_caller]
pub fn create_dir_all<P: AsRef<Path>>(path: P) {
std::fs::create_dir_all(path.as_ref()).expect(&format!(
"the directory (and all its parents) in path \"{}\" could not be created",
path.as_ref().display()
));
}
#[track_caller]
pub fn metadata<P: AsRef<Path>>(path: P) -> std::fs::Metadata {
match std::fs::metadata(path.as_ref()) {
Ok(m) => m,
Err(e) => panic!("failed to read file metadata at `{}`: {e}", path.as_ref().display()),
}
}
#[track_caller]
pub fn symlink_metadata<P: AsRef<Path>>(path: P) -> std::fs::Metadata {
match std::fs::symlink_metadata(path.as_ref()) {
Ok(m) => m,
Err(e) => {
panic!("failed to read file metadata (shallow) at `{}`: {e}", path.as_ref().display())
}
}
}
#[track_caller]
pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) {
std::fs::rename(from.as_ref(), to.as_ref()).expect(&format!(
"the file \"{}\" could not be moved over to \"{}\"",
from.as_ref().display(),
to.as_ref().display(),
));
}
#[track_caller]
pub fn set_permissions<P: AsRef<Path>>(path: P, perm: std::fs::Permissions) {
std::fs::set_permissions(path.as_ref(), perm).expect(&format!(
"the file's permissions in path \"{}\" could not be changed",
path.as_ref().display()
));
}
#[track_caller]
pub fn shallow_find_dir_entries<P: AsRef<Path>>(dir: P) -> Vec<PathBuf> {
let paths = read_dir(dir);
let mut output = Vec::new();
for path in paths {
output.push(path.unwrap().path());
}
output
}
pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) {
#[cfg(unix)]
{
if let Err(e) = std::os::unix::fs::symlink(original.as_ref(), link.as_ref()) {
panic!(
"failed to create symlink: original=`{}`, link=`{}`: {e}",
original.as_ref().display(),
link.as_ref().display()
);
}
}
#[cfg(windows)]
{
if let Err(e) = std::os::windows::fs::symlink_dir(original.as_ref(), link.as_ref()) {
panic!(
"failed to create symlink-to-directory: original=`{}`, link=`{}`: {e}",
original.as_ref().display(),
link.as_ref().display()
);
}
}
#[cfg(not(any(windows, unix)))]
{
unimplemented!("target family not currently supported")
}
}
pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) {
#[cfg(unix)]
{
if let Err(e) = std::os::unix::fs::symlink(original.as_ref(), link.as_ref()) {
panic!(
"failed to create symlink: original=`{}`, link=`{}`: {e}",
original.as_ref().display(),
link.as_ref().display()
);
}
}
#[cfg(windows)]
{
if let Err(e) = std::os::windows::fs::symlink_file(original.as_ref(), link.as_ref()) {
panic!(
"failed to create symlink-to-file: original=`{}`, link=`{}`: {e}",
original.as_ref().display(),
link.as_ref().display()
);
}
}
#[cfg(not(any(windows, unix)))]
{
unimplemented!("target family not currently supported")
}
}