@@ -10,13 +10,99 @@ pub fn bare(git_dir_candidate: impl AsRef<Path>) -> bool {
10
10
!( git_dir. join ( "index" ) . exists ( ) || ( git_dir. file_name ( ) == Some ( OsStr :: new ( DOT_GIT_DIR ) ) ) )
11
11
}
12
12
13
+ /// Parse `<git_dir_candidate>/config` quickly to evaluate the value of the `bare` line, or return `true` if the file doesn't exist
14
+ /// similar to what`guess_repository_type` seems to be doing.
15
+ /// Return `None` if the `bare` line can't be found or the value of `bare` can't be determined.
16
+ fn bare_by_config ( git_dir_candidate : impl AsRef < Path > ) -> std:: io:: Result < Option < bool > > {
17
+ match std:: fs:: read ( git_dir_candidate. as_ref ( ) . join ( "config" ) ) {
18
+ Ok ( buf) => Ok ( config:: parse_bare ( & buf) ) ,
19
+ Err ( err) if err. kind ( ) == std:: io:: ErrorKind :: NotFound => Ok ( Some ( true ) ) ,
20
+ Err ( err) => Err ( err) ,
21
+ }
22
+ }
23
+
24
+ // Copied and adapted from `gix-config-value::boolean`.
25
+ mod config {
26
+ use bstr:: { BStr , ByteSlice } ;
27
+
28
+ pub ( crate ) fn parse_bare ( buf : & [ u8 ] ) -> Option < bool > {
29
+ buf. lines ( ) . find_map ( |line| {
30
+ let line = line. trim ( ) . strip_prefix ( b"bare" ) ?;
31
+ match line. first ( ) {
32
+ None => Some ( true ) ,
33
+ Some ( c) if * c == b'=' => parse_bool ( line. get ( 1 ..) ?. trim_start ( ) . as_bstr ( ) ) ,
34
+ Some ( c) if c. is_ascii_whitespace ( ) => match line. split_once_str ( b"=" ) {
35
+ Some ( ( _left, right) ) => parse_bool ( right. trim_start ( ) . as_bstr ( ) ) ,
36
+ None => Some ( true ) ,
37
+ } ,
38
+ Some ( _other_char_) => None ,
39
+ }
40
+ } )
41
+ }
42
+
43
+ fn parse_bool ( value : & BStr ) -> Option < bool > {
44
+ Some ( if parse_true ( value) {
45
+ true
46
+ } else if parse_false ( value) {
47
+ false
48
+ } else {
49
+ use std:: str:: FromStr ;
50
+ if let Some ( integer) = value. to_str ( ) . ok ( ) . and_then ( |s| i64:: from_str ( s) . ok ( ) ) {
51
+ integer != 0
52
+ } else {
53
+ return None ;
54
+ }
55
+ } )
56
+ }
57
+
58
+ fn parse_true ( value : & BStr ) -> bool {
59
+ value. eq_ignore_ascii_case ( b"yes" ) || value. eq_ignore_ascii_case ( b"on" ) || value. eq_ignore_ascii_case ( b"true" )
60
+ }
61
+
62
+ fn parse_false ( value : & BStr ) -> bool {
63
+ value. eq_ignore_ascii_case ( b"no" )
64
+ || value. eq_ignore_ascii_case ( b"off" )
65
+ || value. eq_ignore_ascii_case ( b"false" )
66
+ || value. is_empty ( )
67
+ }
68
+
69
+ #[ cfg( test) ]
70
+ mod tests {
71
+ use super :: * ;
72
+
73
+ #[ test]
74
+ fn various ( ) {
75
+ for ( input, expected) in [
76
+ ( "bare=true" , Some ( true ) ) ,
77
+ ( "bare=1" , Some ( true ) ) ,
78
+ ( "bare =1" , Some ( true ) ) ,
79
+ ( "bare= yes" , Some ( true ) ) ,
80
+ ( "bare=false" , Some ( false ) ) ,
81
+ ( "bare=0" , Some ( false ) ) ,
82
+ ( "bare=blah" , None ) ,
83
+ ( "bare=" , Some ( false ) ) ,
84
+ ( "bare= \n " , Some ( false ) ) ,
85
+ ( "bare = true \n " , Some ( true ) ) ,
86
+ ( "\t bare = false \n " , Some ( false ) ) ,
87
+ ( "\n \t bare=true" , Some ( true ) ) ,
88
+ ( "\n \t bare=true\n \t foo" , Some ( true ) ) ,
89
+ ( "\n \t bare " , Some ( true ) ) ,
90
+ ( "\n \t bare" , Some ( true ) ) ,
91
+ ( "not found\n really" , None ) ,
92
+ ] {
93
+ assert_eq ! ( parse_bare( input. as_bytes( ) ) , expected, "{input:?}" ) ;
94
+ }
95
+ }
96
+ }
97
+ }
98
+
13
99
/// Returns true if `git_dir` is located within a `.git/modules` directory, indicating it's a submodule clone.
14
100
pub fn submodule_git_dir ( git_dir : impl AsRef < Path > ) -> bool {
15
101
let git_dir = git_dir. as_ref ( ) ;
16
102
17
103
let mut last_comp = None ;
18
104
git_dir. file_name ( ) != Some ( OsStr :: new ( DOT_GIT_DIR ) )
19
- && git_dir. components ( ) . rev ( ) . any ( |c| {
105
+ && git_dir. components ( ) . rev ( ) . skip ( 1 ) . any ( |c| {
20
106
if c. as_os_str ( ) == OsStr :: new ( DOT_GIT_DIR ) {
21
107
true
22
108
} else {
@@ -154,8 +240,17 @@ pub(crate) fn git_with_metadata(
154
240
crate :: repository:: Kind :: Bare
155
241
} else if submodule_git_dir ( conformed_git_dir. as_ref ( ) ) {
156
242
crate :: repository:: Kind :: SubmoduleGitDir
157
- } else {
243
+ } else if conformed_git_dir. file_name ( ) == Some ( OsStr :: new ( DOT_GIT_DIR ) )
244
+ || !bare_by_config ( conformed_git_dir. as_ref ( ) )
245
+ . map_err ( |err| crate :: is_git:: Error :: Metadata {
246
+ source : err,
247
+ path : conformed_git_dir. join ( "config" ) ,
248
+ } ) ?
249
+ . ok_or ( crate :: is_git:: Error :: Inconclusive ) ?
250
+ {
158
251
crate :: repository:: Kind :: WorkTree { linked_git_dir : None }
252
+ } else {
253
+ crate :: repository:: Kind :: Bare
159
254
}
160
255
}
161
256
} )
0 commit comments