1use anyhow::{Context, Result};
2use git2::Repository;
3use std::path::{Path, PathBuf};
4use tokio::task::spawn_blocking;
5
6pub 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}