@@ -9,6 +9,8 @@ use crate::Source;
9
9
/// The category of a [`Source`], in order of ascending precedence.
10
10
#[ derive( Clone , Copy , Debug , Eq , PartialEq , Hash , Ord , PartialOrd ) ]
11
11
pub enum Kind {
12
+ /// A special configuration file that ships with the git installation, and is thus tied to the used git binary.
13
+ GitInstallation ,
12
14
/// A source shared for the entire system.
13
15
System ,
14
16
/// Application specific configuration unique for each user of the `System`.
@@ -23,7 +25,8 @@ impl Kind {
23
25
/// Return a list of sources associated with this `Kind` of source, in order of ascending precedence.
24
26
pub fn sources ( self ) -> & ' static [ Source ] {
25
27
let src = match self {
26
- Kind :: System => & [ Source :: System ] as & [ _ ] ,
28
+ Kind :: GitInstallation => & [ Source :: GitInstallation ] as & [ _ ] ,
29
+ Kind :: System => & [ Source :: System ] ,
27
30
Kind :: Global => & [ Source :: Git , Source :: User ] ,
28
31
Kind :: Repository => & [ Source :: Local , Source :: Worktree ] ,
29
32
Kind :: Override => & [ Source :: Env , Source :: Cli , Source :: Api ] ,
@@ -41,6 +44,7 @@ impl Source {
41
44
pub const fn kind ( self ) -> Kind {
42
45
use Source :: * ;
43
46
match self {
47
+ GitInstallation => Kind :: GitInstallation ,
44
48
System => Kind :: System ,
45
49
Git | User => Kind :: Global ,
46
50
Local | Worktree => Kind :: Repository ,
@@ -61,6 +65,7 @@ impl Source {
61
65
pub fn storage_location ( self , env_var : & mut dyn FnMut ( & str ) -> Option < OsString > ) -> Option < Cow < ' static , Path > > {
62
66
use Source :: * ;
63
67
match self {
68
+ GitInstallation => git:: install_config_path ( ) . map ( git_path:: from_bstr) ,
64
69
System => env_var ( "GIT_CONFIG_NO_SYSTEM" )
65
70
. is_none ( )
66
71
. then ( || PathBuf :: from ( env_var ( "GIT_CONFIG_SYSTEM" ) . unwrap_or_else ( || "/etc/gitconfig" . into ( ) ) ) . into ( ) ) ,
@@ -99,3 +104,59 @@ impl Source {
99
104
}
100
105
}
101
106
}
107
+
108
+ /// Environment information involving the `git` program itself.
109
+ mod git {
110
+ use bstr:: { BStr , BString , ByteSlice } ;
111
+ use std:: process:: { Command , Stdio } ;
112
+
113
+ /// Returns the file that contains git configuration coming with the installation of the `git` file in the current `PATH`, or `None`
114
+ /// if no `git` executable was found or there were other errors during execution.
115
+ pub fn install_config_path ( ) -> Option < & ' static BStr > {
116
+ static PATH : once_cell:: sync:: Lazy < Option < BString > > = once_cell:: sync:: Lazy :: new ( || {
117
+ let mut cmd = Command :: new ( if cfg ! ( windows) { "git.exe" } else { "git" } ) ;
118
+ cmd. args ( [ "config" , "-l" , "--show-origin" ] )
119
+ . stdin ( Stdio :: null ( ) )
120
+ . stderr ( Stdio :: null ( ) ) ;
121
+ first_file_from_config_with_origin ( cmd. output ( ) . ok ( ) ?. stdout . as_slice ( ) . into ( ) ) . map ( ToOwned :: to_owned)
122
+ } ) ;
123
+ PATH . as_ref ( ) . map ( |b| b. as_ref ( ) )
124
+ }
125
+
126
+ fn first_file_from_config_with_origin ( source : & BStr ) -> Option < & BStr > {
127
+ let file = source. strip_prefix ( b"file:" ) ?;
128
+ let end_pos = file. find_byte ( b'\t' ) ?;
129
+ file[ ..end_pos] . as_bstr ( ) . into ( )
130
+ }
131
+
132
+ #[ cfg( test) ]
133
+ mod tests {
134
+ #[ test]
135
+ fn first_file_from_config_with_origin ( ) {
136
+ let macos = "file:/Applications/Xcode.app/Contents/Developer/usr/share/git-core/gitconfig credential.helper=osxkeychain\n file:/Users/byron/.gitconfig push.default=simple\n " ;
137
+ let win_msys =
138
+ "file:C:/git-sdk-64/etc/gitconfig core.symlinks=false\r \n file:C:/git-sdk-64/etc/gitconfig core.autocrlf=true" ;
139
+ let win_cmd = "file:C:/Program Files/Git/etc/gitconfig diff.astextplain.textconv=astextplain\r \n file:C:/Program Files/Git/etc/gitconfig filter.lfs.clean=git-lfs clean -- %f\r \n " ;
140
+ let linux = "file:/home/parallels/.gitconfig core.excludesfile=~/.gitignore\n " ;
141
+ let bogus = "something unexpected" ;
142
+ let empty = "" ;
143
+
144
+ for ( source, expected) in [
145
+ (
146
+ macos,
147
+ Some ( "/Applications/Xcode.app/Contents/Developer/usr/share/git-core/gitconfig" ) ,
148
+ ) ,
149
+ ( win_msys, Some ( "C:/git-sdk-64/etc/gitconfig" ) ) ,
150
+ ( win_cmd, Some ( "C:/Program Files/Git/etc/gitconfig" ) ) ,
151
+ ( linux, Some ( "/home/parallels/.gitconfig" ) ) ,
152
+ ( bogus, None ) ,
153
+ ( empty, None ) ,
154
+ ] {
155
+ assert_eq ! (
156
+ super :: first_file_from_config_with_origin( source. into( ) ) ,
157
+ expected. map( Into :: into)
158
+ ) ;
159
+ }
160
+ }
161
+ }
162
+ }
0 commit comments