diff --git a/src/repo.rs b/src/repo.rs index 3aeac2f1f5..21d621832a 100644 --- a/src/repo.rs +++ b/src/repo.rs @@ -3,7 +3,7 @@ use std::env; use std::ffi::{CStr, CString, OsStr}; use std::iter::IntoIterator; use std::mem; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::ptr; use std::str; @@ -259,6 +259,33 @@ impl Repository { Repository::open(util::bytes2path(&*buf)) } + /// Attempt to find the path to a git repo for a given path + /// + /// This starts at `path` and looks up the filesystem hierarchy + /// until it finds a repository, stopping if it finds a member of ceiling_dirs + pub fn discover_path, I, O>(path: P, ceiling_dirs: I) -> Result + where + O: AsRef, + I: IntoIterator, + { + crate::init(); + let buf = Buf::new(); + // Normal file path OK (does not need Windows conversion). + let path = path.as_ref().into_c_string()?; + let ceiling_dirs_os = env::join_paths(ceiling_dirs)?; + let ceiling_dirs = ceiling_dirs_os.into_c_string()?; + unsafe { + try_call!(raw::git_repository_discover( + buf.raw(), + path, + 1, + ceiling_dirs + )); + } + + Ok(util::bytes2path(&*buf).to_path_buf()) + } + /// Creates a new repository in the specified folder. /// /// This by default will create any necessary directories to create the @@ -3412,6 +3439,34 @@ mod tests { ); } + #[test] + fn smoke_discover_path() { + let td = TempDir::new().unwrap(); + let subdir = td.path().join("subdi"); + fs::create_dir(&subdir).unwrap(); + Repository::init_bare(td.path()).unwrap(); + let path = Repository::discover_path(&subdir, &[] as &[&OsStr]).unwrap(); + assert_eq!( + crate::test::realpath(&path).unwrap(), + crate::test::realpath(&td.path().join("")).unwrap() + ); + } + + #[test] + fn smoke_discover_path_ceiling_dir() { + let td = TempDir::new().unwrap(); + let subdir = td.path().join("subdi"); + fs::create_dir(&subdir).unwrap(); + let ceilingdir = subdir.join("ceiling"); + fs::create_dir(&ceilingdir).unwrap(); + let testdir = ceilingdir.join("testdi"); + fs::create_dir(&testdir).unwrap(); + Repository::init_bare(td.path()).unwrap(); + let path = Repository::discover_path(&testdir, &[ceilingdir.as_os_str()]); + + assert!(path.is_err()); + } + #[test] fn smoke_open_ext() { let td = TempDir::new().unwrap();