@@ -3,7 +3,7 @@ use std::env;
33use std:: ffi:: { CStr , CString , OsStr } ;
44use std:: iter:: IntoIterator ;
55use std:: mem;
6- use std:: path:: Path ;
6+ use std:: path:: { Path , PathBuf } ;
77use std:: ptr;
88use std:: str;
99
@@ -259,6 +259,33 @@ impl Repository {
259259 Repository :: open ( util:: bytes2path ( & * buf) )
260260 }
261261
262+ /// Attempt to find the path to a git repo for a given path
263+ ///
264+ /// This starts at `path` and looks up the filesystem hierarchy
265+ /// until it finds a repository, stopping if it finds a member of ceiling_dirs
266+ pub fn discover_path < P : AsRef < Path > , I , O > ( path : P , ceiling_dirs : I ) -> Result < PathBuf , Error >
267+ where
268+ O : AsRef < OsStr > ,
269+ I : IntoIterator < Item = O > ,
270+ {
271+ crate :: init ( ) ;
272+ let buf = Buf :: new ( ) ;
273+ // Normal file path OK (does not need Windows conversion).
274+ let path = path. as_ref ( ) . into_c_string ( ) ?;
275+ let ceiling_dirs_os = env:: join_paths ( ceiling_dirs) ?;
276+ let ceiling_dirs = ceiling_dirs_os. into_c_string ( ) ?;
277+ unsafe {
278+ try_call ! ( raw:: git_repository_discover(
279+ buf. raw( ) ,
280+ path,
281+ 1 ,
282+ ceiling_dirs
283+ ) ) ;
284+ }
285+
286+ Ok ( util:: bytes2path ( & * buf) . to_path_buf ( ) )
287+ }
288+
262289 /// Creates a new repository in the specified folder.
263290 ///
264291 /// This by default will create any necessary directories to create the
@@ -3412,6 +3439,34 @@ mod tests {
34123439 ) ;
34133440 }
34143441
3442+ #[ test]
3443+ fn smoke_discover_path ( ) {
3444+ let td = TempDir :: new ( ) . unwrap ( ) ;
3445+ let subdir = td. path ( ) . join ( "subdi" ) ;
3446+ fs:: create_dir ( & subdir) . unwrap ( ) ;
3447+ Repository :: init_bare ( td. path ( ) ) . unwrap ( ) ;
3448+ let path = Repository :: discover_path ( & subdir, & [ ] as & [ & OsStr ] ) . unwrap ( ) ;
3449+ assert_eq ! (
3450+ crate :: test:: realpath( & path) . unwrap( ) ,
3451+ crate :: test:: realpath( & td. path( ) . join( "" ) ) . unwrap( )
3452+ ) ;
3453+ }
3454+
3455+ #[ test]
3456+ fn smoke_discover_path_ceiling_dir ( ) {
3457+ let td = TempDir :: new ( ) . unwrap ( ) ;
3458+ let subdir = td. path ( ) . join ( "subdi" ) ;
3459+ fs:: create_dir ( & subdir) . unwrap ( ) ;
3460+ let ceilingdir = subdir. join ( "ceiling" ) ;
3461+ fs:: create_dir ( & ceilingdir) . unwrap ( ) ;
3462+ let testdir = ceilingdir. join ( "testdi" ) ;
3463+ fs:: create_dir ( & testdir) . unwrap ( ) ;
3464+ Repository :: init_bare ( td. path ( ) ) . unwrap ( ) ;
3465+ let path = Repository :: discover_path ( & testdir, & [ ceilingdir. as_os_str ( ) ] ) ;
3466+
3467+ assert ! ( path. is_err( ) ) ;
3468+ }
3469+
34153470 #[ test]
34163471 fn smoke_open_ext ( ) {
34173472 let td = TempDir :: new ( ) . unwrap ( ) ;
0 commit comments