@@ -3,7 +3,7 @@ use std::env;
3
3
use std:: ffi:: { CStr , CString , OsStr } ;
4
4
use std:: iter:: IntoIterator ;
5
5
use std:: mem;
6
- use std:: path:: Path ;
6
+ use std:: path:: { Path , PathBuf } ;
7
7
use std:: ptr;
8
8
use std:: str;
9
9
@@ -259,6 +259,33 @@ impl Repository {
259
259
Repository :: open ( util:: bytes2path ( & * buf) )
260
260
}
261
261
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
+
262
289
/// Creates a new repository in the specified folder.
263
290
///
264
291
/// This by default will create any necessary directories to create the
@@ -3428,6 +3455,34 @@ mod tests {
3428
3455
) ;
3429
3456
}
3430
3457
3458
+ #[ test]
3459
+ fn smoke_discover_path ( ) {
3460
+ let td = TempDir :: new ( ) . unwrap ( ) ;
3461
+ let subdir = td. path ( ) . join ( "subdi" ) ;
3462
+ fs:: create_dir ( & subdir) . unwrap ( ) ;
3463
+ Repository :: init_bare ( td. path ( ) ) . unwrap ( ) ;
3464
+ let path = Repository :: discover_path ( & subdir, & [ ] as & [ & OsStr ] ) . unwrap ( ) ;
3465
+ assert_eq ! (
3466
+ crate :: test:: realpath( & path) . unwrap( ) ,
3467
+ crate :: test:: realpath( & td. path( ) . join( "" ) ) . unwrap( )
3468
+ ) ;
3469
+ }
3470
+
3471
+ #[ test]
3472
+ fn smoke_discover_path_ceiling_dir ( ) {
3473
+ let td = TempDir :: new ( ) . unwrap ( ) ;
3474
+ let subdir = td. path ( ) . join ( "subdi" ) ;
3475
+ fs:: create_dir ( & subdir) . unwrap ( ) ;
3476
+ let ceilingdir = subdir. join ( "ceiling" ) ;
3477
+ fs:: create_dir ( & ceilingdir) . unwrap ( ) ;
3478
+ let testdir = ceilingdir. join ( "testdi" ) ;
3479
+ fs:: create_dir ( & testdir) . unwrap ( ) ;
3480
+ Repository :: init_bare ( td. path ( ) ) . unwrap ( ) ;
3481
+ let path = Repository :: discover_path ( & testdir, & [ ceilingdir. as_os_str ( ) ] ) ;
3482
+
3483
+ assert ! ( path. is_err( ) ) ;
3484
+ }
3485
+
3431
3486
#[ test]
3432
3487
fn smoke_open_ext ( ) {
3433
3488
let td = TempDir :: new ( ) . unwrap ( ) ;
0 commit comments