1
+ use std:: path:: PathBuf ;
1
2
use std:: {
2
3
path:: Path ,
3
4
process:: { Command , Stdio } ,
4
5
} ;
5
6
6
7
use bstr:: { BStr , BString , ByteSlice } ;
7
8
9
+ /// Other places to find Git in.
10
+ #[ cfg( windows) ]
11
+ static ALTERNATIVE_LOCATIONS : & [ & str ] = & [ "C:/Program Files/Git/mingw64/bin" ] ;
12
+ #[ cfg( not( windows) ) ]
13
+ static ALTERNATIVE_LOCATIONS : & [ & str ] = & [ ] ;
14
+
15
+ #[ cfg( windows) ]
16
+ pub ( super ) static EXE_NAME : & str = "git.exe" ;
17
+ #[ cfg( not( windows) ) ]
18
+ pub ( super ) static EXE_NAME : & str = "git" ;
19
+
20
+ /// The path to the Git executable as located in the `PATH` or in other locations that it's known to be installed to.
21
+ /// It's `None` if environment variables couldn't be read or if no executable could be found.
22
+ pub ( super ) static EXECUTABLE_PATH : once_cell:: sync:: Lazy < Option < PathBuf > > = once_cell:: sync:: Lazy :: new ( || {
23
+ std:: env:: split_paths ( & std:: env:: var_os ( "PATH" ) ?)
24
+ . chain ( ALTERNATIVE_LOCATIONS . into_iter ( ) . map ( Into :: into) )
25
+ . find_map ( |prefix| {
26
+ let full_path = prefix. join ( EXE_NAME ) ;
27
+ full_path. is_file ( ) . then_some ( full_path)
28
+ } )
29
+ } ) ;
30
+
31
+ /// Invoke the git executable in PATH to obtain the origin configuration, which is cached and returned.
32
+ pub ( super ) static EXE_INFO : once_cell:: sync:: Lazy < Option < BString > > = once_cell:: sync:: Lazy :: new ( || {
33
+ let git_cmd = |executable : PathBuf | {
34
+ let mut cmd = Command :: new ( executable) ;
35
+ cmd. args ( [ "config" , "-l" , "--show-origin" ] )
36
+ . stdin ( Stdio :: null ( ) )
37
+ . stderr ( Stdio :: null ( ) ) ;
38
+ cmd
39
+ } ;
40
+ let mut cmd = git_cmd ( EXE_NAME . into ( ) ) ;
41
+ gix_trace:: debug!( cmd = ?cmd, "invoking git for installation config path" ) ;
42
+ let cmd_output = match cmd. output ( ) {
43
+ Ok ( out) => out. stdout ,
44
+ #[ cfg( windows) ]
45
+ Err ( err) if err. kind ( ) == std:: io:: ErrorKind :: NotFound => {
46
+ let executable = ALTERNATIVE_LOCATIONS . into_iter ( ) . find_map ( |prefix| {
47
+ let candidate = Path :: new ( prefix) . join ( EXE_NAME ) ;
48
+ candidate. is_file ( ) . then_some ( candidate)
49
+ } ) ?;
50
+ gix_trace:: debug!( cmd = ?cmd, "invoking git for installation config path in alternate location" ) ;
51
+ git_cmd ( executable) . output ( ) . ok ( ) ?. stdout
52
+ }
53
+ Err ( _) => return None ,
54
+ } ;
55
+
56
+ first_file_from_config_with_origin ( cmd_output. as_slice ( ) . into ( ) ) . map ( ToOwned :: to_owned)
57
+ } ) ;
58
+
8
59
/// Returns the file that contains git configuration coming with the installation of the `git` file in the current `PATH`, or `None`
9
60
/// if no `git` executable was found or there were other errors during execution.
10
- pub ( crate ) fn install_config_path ( ) -> Option < & ' static BStr > {
61
+ pub ( super ) fn install_config_path ( ) -> Option < & ' static BStr > {
11
62
let _span = gix_trace:: detail!( "gix_path::git::install_config_path()" ) ;
12
63
static PATH : once_cell:: sync:: Lazy < Option < BString > > = once_cell:: sync:: Lazy :: new ( || {
13
- // Shortcut: in Msys shells this variable is set which allows to deduce the installation directory
64
+ // Shortcut: in Msys shells this variable is set which allows to deduce the installation directory,
14
65
// so we can save the `git` invocation.
15
66
#[ cfg( windows) ]
16
67
if let Some ( mut exec_path) = std:: env:: var_os ( "EXEPATH" ) . map ( std:: path:: PathBuf :: from) {
17
68
exec_path. push ( "etc" ) ;
18
69
exec_path. push ( "gitconfig" ) ;
19
70
return crate :: os_string_into_bstring ( exec_path. into ( ) ) . ok ( ) ;
20
71
}
21
- let mut cmd = Command :: new ( if cfg ! ( windows) { "git.exe" } else { "git" } ) ;
22
- cmd. args ( [ "config" , "-l" , "--show-origin" ] )
23
- . stdin ( Stdio :: null ( ) )
24
- . stderr ( Stdio :: null ( ) ) ;
25
- gix_trace:: debug!( cmd = ?cmd, "invoking git for installation config path" ) ;
26
- first_file_from_config_with_origin ( cmd. output ( ) . ok ( ) ?. stdout . as_slice ( ) . into ( ) ) . map ( ToOwned :: to_owned)
72
+ first_file_from_config_with_origin ( ( * EXE_INFO ) . as_ref ( ) ?. as_bstr ( ) ) . map ( ToOwned :: to_owned)
27
73
} ) ;
28
74
PATH . as_ref ( ) . map ( AsRef :: as_ref)
29
75
}
@@ -35,7 +81,7 @@ fn first_file_from_config_with_origin(source: &BStr) -> Option<&BStr> {
35
81
}
36
82
37
83
/// Given `config_path` as obtained from `install_config_path()`, return the path of the git installation base.
38
- pub ( crate ) fn config_to_base_path ( config_path : & Path ) -> & Path {
84
+ pub ( super ) fn config_to_base_path ( config_path : & Path ) -> & Path {
39
85
config_path
40
86
. parent ( )
41
87
. expect ( "config file paths always have a file name to pop" )
0 commit comments