1
- use std:: ffi:: OsString ;
1
+ use std:: ffi:: { OsStr , OsString } ;
2
2
use std:: path:: { Path , PathBuf } ;
3
3
4
4
use bstr:: { BString , ByteSlice } ;
@@ -28,21 +28,25 @@ pub fn installation_config_prefix() -> Option<&'static Path> {
28
28
installation_config ( ) . map ( git:: config_to_base_path)
29
29
}
30
30
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.
32
32
///
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 ( || {
37
40
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)
41
45
} else {
42
- std :: env :: var_os ( "SHELL" ) . map ( PathBuf :: from )
46
+ "/bin/sh" . into ( )
43
47
}
44
48
} ) ;
45
- PATH . as_deref ( )
49
+ PATH . as_ref ( )
46
50
}
47
51
48
52
/// 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>)
102
106
} )
103
107
}
104
108
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
+
105
139
/// Returns the platform dependent system prefix or `None` if it cannot be found (right now only on windows).
106
140
///
107
141
/// ### Performance
@@ -125,22 +159,7 @@ pub fn system_prefix() -> Option<&'static Path> {
125
159
}
126
160
}
127
161
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 ( ) ?;
144
163
let one_past_prefix = path. components ( ) . enumerate ( ) . find_map ( |( idx, c) | {
145
164
matches ! ( c, std:: path:: Component :: Normal ( name) if name. to_str( ) == Some ( "libexec" ) ) . then_some ( idx)
146
165
} ) ?;
0 commit comments