Skip to main content

fluidattacks_core_git/
ops.rs

1use std::path::Path;
2
3use crate::cli;
4
5/// Runs `git reset --hard`, removes symlinks, and returns whether it succeeded.
6pub async fn reset_repo(repo_path: &Path) -> bool {
7    if let Err(error) = cli::set_safe_directory().await {
8        tracing::error!(repo_path = %repo_path.display(), error = %error, "failed to add the safe directory");
9    }
10    if !repo_path.join(".git").exists() {
11        tracing::error!(repo_path = %repo_path.display(), "not the root of a repository");
12        return false;
13    }
14    if let Err(error) = cli::reset_hard(repo_path).await {
15        tracing::error!(repo_path = %repo_path.display(), error = %error, "failed to reset the repository");
16        return false;
17    }
18    let root = repo_path.to_path_buf();
19    if let Err(error) = tokio::task::spawn_blocking(move || super::fs::remove_symlinks(&root)).await
20    {
21        tracing::error!(repo_path = %repo_path.display(), error = %error, "failed to remove the symlinks");
22        return false;
23    }
24    true
25}
26
27#[cfg(test)]
28mod tests {
29    use super::reset_repo;
30    use std::path::Path;
31
32    fn git(repo: &Path, args: &[&str]) {
33        let status = std::process::Command::new("git")
34            .arg("-C")
35            .arg(repo)
36            .args(args)
37            .status()
38            .unwrap();
39        assert!(status.success());
40    }
41
42    #[tokio::test]
43    async fn only_the_root_of_the_repository_gets_reset() {
44        let dir = tempfile::tempdir().unwrap();
45        std::env::set_var("GIT_CONFIG_GLOBAL", dir.path().join("gitconfig"));
46
47        let repo = dir.path().join("repo");
48        std::fs::create_dir_all(repo.join("sub/deep")).unwrap();
49        git(&repo, &["init", "-q"]);
50        std::fs::write(repo.join("f.txt"), b"committed").unwrap();
51        git(&repo, &["add", "-A"]);
52        git(
53            &repo,
54            &[
55                "-c",
56                "user.email=dev@fluidattacks.com",
57                "-c",
58                "user.name=dev",
59                "commit",
60                "-q",
61                "-m",
62                "files",
63            ],
64        );
65        std::fs::write(repo.join("f.txt"), b"dirty").unwrap();
66
67        let deep = repo.join("sub/deep");
68        assert!(!reset_repo(&deep).await);
69        assert_eq!(
70            std::fs::read_to_string(repo.join("f.txt")).unwrap(),
71            "dirty"
72        );
73
74        assert!(reset_repo(&repo).await);
75        assert_eq!(
76            std::fs::read_to_string(repo.join("f.txt")).unwrap(),
77            "committed"
78        );
79    }
80}