Skip to content

Commit 2efd5b5

Browse files
committed
Generalize the gix_path::env::auxiliary helpers
They are now in a form where they take the name of the command to be found and look for it in a way that would find many of the binaries shipped with and reasonable to use with Git for Windows. However, as noted in comments, further refinement as well as new tests would be called for if using it for purposes other than to find `sh`. For now it remains private with `gix_path::env` and is only used to find `sh`, as an implementation detail of `gix_path::shell()`.
1 parent 2abbb1a commit 2efd5b5

File tree

2 files changed

+34
-20
lines changed

2 files changed

+34
-20
lines changed

gix-path/src/env/auxiliary.rs

+33-19
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ use once_cell::sync::Lazy;
2424
/// more prefixes or matching a broad pattern of platform-like strings might be too broad. So only
2525
/// prefixes that have been used in MSYS2 are considered.
2626
///
27-
/// Second, we don't recognize `usr` itself here, even though is a plausible prefix. In MSYS2, it
28-
/// is the prefix for MSYS2 non-native programs, i.e. those that use `msys-2.0.dll`. But unlike the
29-
/// `<platform>` names we recognize, `usr` also has an effectively unbounded range of plausible
27+
/// Second, we don't recognize `usr` itself here, even though it is a plausible prefix. In MSYS2,
28+
/// it is the prefix for MSYS2 non-native programs, i.e. those that use `msys-2.0.dll`. But unlike
29+
/// the `<platform>` names we recognize, `usr` also has an effectively unbounded range of plausible
3030
/// meanings on non-Unix systems (for example, what should we take `Z:\usr` to mean?), which might
3131
/// occasionally relate to subdirectories with contents controlled by different *user accounts*.
3232
///
@@ -60,30 +60,44 @@ fn git_for_windows_root() -> Option<&'static Path> {
6060
GIT_ROOT.as_deref()
6161
}
6262

63-
/// Shell path fragments to concatenate to the root of a Git for Windows or MSYS2 installation.
64-
///
65-
/// When appended to the root of a Git for Windows installation, these are locations where `sh.exe`
66-
/// can usually be found. The leading `/` allow these to be used (only) with `raw_join()`.
63+
/// `bin` directory paths to try relative to the root of a Git for Windows or MSYS2 installation.
6764
///
6865
/// These are ordered so that a shim is preferred over a non-shim when they are tried in order.
69-
const RAW_SH_EXE_PATH_SUFFIXES: &[&str] = &["/bin/sh.exe", "/usr/bin/sh.exe"];
70-
71-
/// Concatenate a path by appending a raw suffix, which must contain its own leading separator.
72-
fn raw_join(path: &Path, raw_suffix: &str) -> OsString {
73-
let mut raw_path = OsString::from(path);
74-
raw_path.push(raw_suffix);
75-
raw_path
76-
}
66+
const BIN_DIR_FRAGMENTS: &[&str] = &["bin", "usr/bin"];
7767

78-
/// Obtain a path to a `sh.exe` on Windows associated with Git, if one can be found.
68+
/// Obtain a path to an executable command on Windows associated with Git, if one can be found.
7969
///
8070
/// The resulting path uses only `/` separators so long as the path obtained from `git --exec-path`
8171
/// does, which is the case unless it is overridden by setting `GIT_EXEC_PATH` to an unusual value.
82-
pub(super) fn find_sh_on_windows() -> Option<OsString> {
72+
///
73+
/// This is currently only used (and only exercised in tests) for finding `sh.exe`. It may be used
74+
/// to find other executables in the future, but may require adjustment. (In particular, depending
75+
/// on the desired semantics, it should possibly also check inside a `cmd` directory, possibly also
76+
/// check inside `super::core_dir()` itself, and could safely check the latter location even if its
77+
/// value is not suitable to use in inferring any other paths.)
78+
fn find_git_associated_windows_executable(stem: &str) -> Option<OsString> {
8379
let git_root = git_for_windows_root()?;
8480

85-
RAW_SH_EXE_PATH_SUFFIXES
81+
BIN_DIR_FRAGMENTS
8682
.iter()
87-
.map(|raw_suffix| raw_join(git_root, raw_suffix))
83+
.map(|bin_dir_fragment| {
84+
// Perform explicit raw concatenation with `/` to avoid introducing any `\` separators.
85+
let mut raw_path = OsString::from(git_root);
86+
raw_path.push("/");
87+
raw_path.push(bin_dir_fragment);
88+
raw_path.push("/");
89+
raw_path.push(stem);
90+
raw_path.push(".exe");
91+
raw_path
92+
})
8893
.find(|raw_path| Path::new(raw_path).is_file())
8994
}
95+
96+
/// Like `find_associated_windows_executable`, but if not found, fall back to a simple filename.
97+
pub(super) fn find_git_associated_windows_executable_with_fallback(stem: &str) -> OsString {
98+
find_git_associated_windows_executable(stem).unwrap_or_else(|| {
99+
let mut raw_path = OsString::from(stem);
100+
raw_path.push(".exe");
101+
raw_path
102+
})
103+
}

gix-path/src/env/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ pub fn installation_config_prefix() -> Option<&'static Path> {
4040
pub fn shell() -> &'static OsStr {
4141
static PATH: Lazy<OsString> = Lazy::new(|| {
4242
if cfg!(windows) {
43-
auxiliary::find_sh_on_windows().unwrap_or_else(|| "sh.exe".into())
43+
auxiliary::find_git_associated_windows_executable_with_fallback("sh")
4444
} else {
4545
"/bin/sh".into()
4646
}

0 commit comments

Comments
 (0)