1- use std:: ffi:: OsString ;
1+ use std:: ffi:: { OsStr , OsString } ;
22use std:: path:: { Path , PathBuf } ;
33
44use bstr:: { BString , ByteSlice } ;
@@ -28,21 +28,25 @@ pub fn installation_config_prefix() -> Option<&'static Path> {
2828 installation_config ( ) . map ( git:: config_to_base_path)
2929}
3030
31- /// Return the shell that Git would prefer as login shell , the shell to execute Git commands from.
31+ /// Return the shell that Git would use , the shell to execute commands from.
3232///
33- /// On Windows, this is the `bash.exe` bundled with it, and on Unix it's the shell specified by `SHELL`,
34- /// or `None` if it is truly unspecified.
35- pub fn login_shell ( ) -> Option < & ' static Path > {
36- static PATH : Lazy < Option < PathBuf > > = Lazy :: new ( || {
33+ /// On Windows, this is the full path to `sh.exe` bundled with Git, and on
34+ /// Unix it's `/bin/sh` as posix compatible shell.
35+ /// If the bundled shell on Windows cannot be found, `sh` is returned as the name of a shell
36+ /// as it could possibly be found in `PATH`.
37+ /// Note that the returned path might not be a path on disk.
38+ pub fn shell ( ) -> & ' static OsStr {
39+ static PATH : Lazy < OsString > = Lazy :: new ( || {
3740 if cfg ! ( windows) {
38- installation_config_prefix ( )
39- . and_then ( |p| p. parent ( ) )
40- . map ( |p| p. join ( "usr" ) . join ( "bin" ) . join ( "bash.exe" ) )
41+ core_dir ( )
42+ . and_then ( |p| p. ancestors ( ) . nth ( 3 ) ) // Skip something like mingw64/libexec/git-core.
43+ . map ( |p| p. join ( "usr" ) . join ( "bin" ) . join ( "sh.exe" ) )
44+ . map_or_else ( || OsString :: from ( "sh" ) , Into :: into)
4145 } else {
42- std :: env :: var_os ( "SHELL" ) . map ( PathBuf :: from )
46+ "/bin/sh" . into ( )
4347 }
4448 } ) ;
45- PATH . as_deref ( )
49+ PATH . as_ref ( )
4650}
4751
4852/// Return the name of the Git executable to invoke it.
@@ -102,6 +106,36 @@ pub fn xdg_config(file: &str, env_var: &mut dyn FnMut(&str) -> Option<OsString>)
102106 } )
103107}
104108
109+ static GIT_CORE_DIR : Lazy < Option < PathBuf > > = Lazy :: new ( || {
110+ let mut cmd = std:: process:: Command :: new ( exe_invocation ( ) ) ;
111+
112+ #[ cfg( windows) ]
113+ {
114+ use std:: os:: windows:: process:: CommandExt ;
115+ const CREATE_NO_WINDOW : u32 = 0x08000000 ;
116+ cmd. creation_flags ( CREATE_NO_WINDOW ) ;
117+ }
118+ let output = cmd. arg ( "--exec-path" ) . output ( ) . ok ( ) ?;
119+
120+ if !output. status . success ( ) {
121+ return None ;
122+ }
123+
124+ BString :: new ( output. stdout )
125+ . strip_suffix ( b"\n " ) ?
126+ . to_path ( )
127+ . ok ( ) ?
128+ . to_owned ( )
129+ . into ( )
130+ } ) ;
131+
132+ /// Return the directory obtained by calling `git --exec-path`.
133+ ///
134+ /// Returns `None` if Git could not be found or if it returned an error.
135+ pub fn core_dir ( ) -> Option < & ' static Path > {
136+ GIT_CORE_DIR . as_deref ( )
137+ }
138+
105139/// Returns the platform dependent system prefix or `None` if it cannot be found (right now only on windows).
106140///
107141/// ### Performance
@@ -125,22 +159,7 @@ pub fn system_prefix() -> Option<&'static Path> {
125159 }
126160 }
127161
128- let mut cmd = std:: process:: Command :: new ( exe_invocation ( ) ) ;
129- #[ cfg( windows) ]
130- {
131- use std:: os:: windows:: process:: CommandExt ;
132- const CREATE_NO_WINDOW : u32 = 0x08000000 ;
133- cmd. creation_flags ( CREATE_NO_WINDOW ) ;
134- }
135- cmd. arg ( "--exec-path" ) . stderr ( std:: process:: Stdio :: null ( ) ) ;
136- gix_trace:: debug!( cmd = ?cmd, "invoking git to get system prefix/exec path" ) ;
137- let path = cmd. output ( ) . ok ( ) ?. stdout ;
138- let path = BString :: new ( path)
139- . trim_with ( |b| b. is_ascii_whitespace ( ) )
140- . to_path ( )
141- . ok ( ) ?
142- . to_owned ( ) ;
143-
162+ let path = GIT_CORE_DIR . as_deref ( ) ?;
144163 let one_past_prefix = path. components ( ) . enumerate ( ) . find_map ( |( idx, c) | {
145164 matches ! ( c, std:: path:: Component :: Normal ( name) if name. to_str( ) == Some ( "libexec" ) ) . then_some ( idx)
146165 } ) ?;
0 commit comments