use std::io;
use std::path::Path;
use std::{thread::sleep, time::Duration};
use remove_dir_all::remove_dir_all;
pub fn remove_history(project_dir: &Path) -> io::Result<()> {
let git_dir = project_dir.join(".git");
if !git_dir.is_dir() {
return Ok(());
}
let mut attempt = 0_u8;
loop {
attempt += 1;
match remove_dir_all(&git_dir) {
Ok(()) => return Ok(()),
Err(e) => {
if attempt >= 5 {
return Err(e);
}
if e.to_string().contains(
"The process cannot access the file because it is being used by another process.",
) {
let wait_for = Duration::from_secs(2_u64.pow(u32::from(attempt - 1)));
log::warn!(
"`.git` cleanup failed with a Windows process-lock error. \
Retry in {wait_for:?}"
);
sleep(wait_for);
} else {
return Err(e);
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
use tempfile::TempDir;
#[test]
fn removes_dot_git_when_present() {
let dir = TempDir::new().unwrap();
let git_dir = dir.path().join(".git");
fs::create_dir_all(&git_dir).unwrap();
fs::write(git_dir.join("HEAD"), "ref: refs/heads/main\n").unwrap();
remove_history(dir.path()).unwrap();
assert!(!git_dir.exists());
}
#[test]
fn is_noop_when_no_dot_git() {
let dir = TempDir::new().unwrap();
remove_history(dir.path()).unwrap();
}
#[test]
fn is_noop_when_dot_git_is_a_file_not_a_dir() {
let dir = TempDir::new().unwrap();
fs::write(dir.path().join(".git"), "gitdir: ../.git/modules/x").unwrap();
remove_history(dir.path()).unwrap();
assert!(dir.path().join(".git").exists());
}
}