Skip to main content

parley/git/
root.rs

1use anyhow::{Context, Result};
2use git2::Repository;
3use std::path::{Path, PathBuf};
4use tokio::task::spawn_blocking;
5
6/// # Errors
7///
8/// Returns an error when git repository discovery fails, the repository is bare, or the blocking
9/// discovery task cannot be joined.
10pub async fn discover_workdir(start_dir: impl AsRef<Path>) -> Result<PathBuf> {
11    let start_dir = start_dir.as_ref().to_path_buf();
12    spawn_blocking(move || {
13        let repo = Repository::discover(&start_dir).context("failed to discover git repository")?;
14        let workdir = repo
15            .workdir()
16            .context("parley requires a non-bare git repository")?;
17        Ok::<_, anyhow::Error>(workdir.to_path_buf())
18    })
19    .await
20    .context("failed to join git repository discovery task")?
21}
22
23#[cfg(test)]
24mod tests {
25    use super::discover_workdir;
26    use anyhow::Result;
27    use git2::Repository;
28    use tempfile::tempdir;
29    use tokio::fs as tokio_fs;
30
31    #[tokio::test]
32    async fn discover_workdir_should_return_repo_root_from_subdirectory() -> Result<()> {
33        let tempdir = tempdir()?;
34        Repository::init(tempdir.path())?;
35        let nested_dir = tempdir.path().join("src").join("nested");
36        tokio_fs::create_dir_all(&nested_dir).await?;
37
38        let workdir = discover_workdir(&nested_dir).await?;
39        let expected = tokio_fs::canonicalize(tempdir.path()).await?;
40
41        assert_eq!(workdir, expected);
42        Ok(())
43    }
44}