use anyhow::Result;
use ignore::gitignore::GitignoreBuilder;
use std::fs;
use std::path::Path;
use walkdir::WalkDir;
pub fn remove_symlinks(dir: &Path) -> Result<()> {
for entry in WalkDir::new(dir) {
let entry = entry?;
let metadata = entry.path().symlink_metadata()?;
if metadata.file_type().is_symlink() {
fs::remove_file(entry.path())?;
}
}
Ok(())
}
pub fn delete_gitignored_files(repo_path: &Path, patterns: &[String]) -> Result<()> {
let mut builder = GitignoreBuilder::new(repo_path);
for pattern in patterns {
builder.add_line(None, pattern)?;
}
let gitignore = builder.build()?;
for entry in WalkDir::new(repo_path) {
let entry = entry?;
let path = entry.path();
let rel = match path.strip_prefix(repo_path) {
Ok(r) => r,
Err(_) => continue,
};
let rel_str = rel.to_string_lossy();
if rel_str == ".git" || rel_str.starts_with(".git/") || rel_str.starts_with(".git\\") {
continue;
}
if rel_str.is_empty() {
continue;
}
if !entry.file_type().is_dir() && gitignore.matched(rel, false).is_ignore() {
let _ = fs::remove_file(path);
}
}
remove_empty_dirs(repo_path)?;
Ok(())
}
pub fn copy_dir_all(src: &Path, dst: &Path) -> Result<()> {
fs::create_dir_all(dst)?;
for entry in fs::read_dir(src)? {
let entry = entry?;
let ty = entry.file_type()?;
let dst_path = dst.join(entry.file_name());
if ty.is_dir() {
copy_dir_all(&entry.path(), &dst_path)?;
} else {
fs::copy(entry.path(), &dst_path)?;
}
}
Ok(())
}
fn remove_empty_dirs(root: &Path) -> Result<()> {
let mut dirs: Vec<_> = Vec::new();
for entry in WalkDir::new(root) {
let entry = entry?;
let path = entry.path();
let rel = match path.strip_prefix(root) {
Ok(r) => r,
Err(_) => continue,
};
let rel_str = rel.to_string_lossy();
if rel_str == ".git" || rel_str.starts_with(".git/") || rel_str.starts_with(".git\\") {
continue;
}
if entry.file_type().is_dir() && path != root {
dirs.push(path.to_path_buf());
}
}
dirs.sort();
dirs.reverse();
for dir in dirs {
if let Ok(entries) = fs::read_dir(&dir) {
if entries.count() == 0 {
let _ = fs::remove_dir(&dir);
}
}
}
Ok(())
}