use std::{fmt::Write, path::Path};
use ignore::WalkBuilder;
use snafu::ResultExt;
use crate::{Result, error};
pub(crate) fn format_hex_lower(bytes: impl AsRef<[u8]>) -> String {
let bytes = bytes.as_ref();
let mut s = String::with_capacity(bytes.len() * 2);
for b in bytes {
let _ = write!(s, "{b:02x}");
}
s
}
pub(crate) fn copy_source_tree(src: &Path, dst: &Path) -> Result<()> {
let walker = WalkBuilder::new(src)
.hidden(false) .git_ignore(true) .git_exclude(true) .build();
for result in walker {
let entry = result
.map_err(|e| Box::new(e) as _)
.with_context(|_| error::CopySourceTreeSnafu {
src: src.to_path_buf(),
dst: dst.to_path_buf(),
})?;
let src_path = entry.path();
if src_path == src {
continue; }
let rel_path = src_path
.strip_prefix(src)
.expect("BUG: strip_prefix cannot fail: src_path was produced by walking src");
let dst_path = dst.join(rel_path);
let file_type = entry
.file_type()
.expect("BUG: file_type returns None only for stdin, impossible when walking a directory");
if file_type.is_dir() {
std::fs::create_dir_all(&dst_path)
.map_err(|e| Box::new(e) as _)
.with_context(|_| error::CopySourceTreeSnafu {
src: src.to_path_buf(),
dst: dst.to_path_buf(),
})?;
} else if file_type.is_file() {
if let Some(parent) = dst_path.parent() {
std::fs::create_dir_all(parent)
.map_err(|e| Box::new(e) as _)
.with_context(|_| error::CopySourceTreeSnafu {
src: src.to_path_buf(),
dst: dst.to_path_buf(),
})?;
}
std::fs::copy(src_path, &dst_path)
.map_err(|e| Box::new(e) as _)
.with_context(|_| error::CopySourceTreeSnafu {
src: src.to_path_buf(),
dst: dst.to_path_buf(),
})?;
}
}
Ok(())
}