Skip to content

Commit 5ac8cff

Browse files
committed
fix: Skip EXEPATH optimization if it finds no best path
The `EXEPATH` optimization for `gix_path::env::system_prefix()` on Windows previously tried https://www.msys2.org/docs/environments prefixes used by Git for Windows, returning a successful result on the first subdirectory found. However, if `EXEPATH` points to a directory that contains more than one such subdirectory, then the subdirectory returned would not necessarily be the correct one. Getting more than one subdirectory is unlikely. It is expected that at most one of `clangarm64`, `mingw64`, and `mingw32` will be present. However, there are at least three ways it could happen: - `EXEPATH` has the intended meaning as the root of a Git for Windows installation, but the directory it refers to contains multiple directories left over from a previous installation. A corresponding scenario applies to `ALTERNATIVE_LOCATIONS`, but it is resolved by checking all the directories in a reasonable order. Here, we are not checking the contents of the directories, so no matter what order we look for them in, picking one when there are others risks picking the wrong one. - `EXEPATH` has the intended meaning as the root of a Git for Windows installation, but it is a custom installation produced from local build or custom distribution rather than an official build, and it contains multiple such directories because it carries binaries built against more than one of the targets (even if only one of them has `git` itself). A corresponding scenario is fairly unlikely for `ALTERNATIVE_LOCATIONS`, because a custom MSYS2 tree, even if created using the Git for Windows SDK, would probably not be installed in one of the common Git for Windows installation locations, without considering the effects of doing so. In contrast, `EXEPATH` will often be set in a Git Bash environment even in a highly customized Git for Windows tree. - `EXEPATH` has a different meaning from what is intended. For example, the user might set it to the root of an ordinary MSYS2 installation. (Note that it is also likely to have various other meanings even more different from these, but those won't likely cause the `EXEPATH` optimization to be used when it shouldn't, because most possible meanings of `EXEPATH` won't involve a subdirectory of any of the names we look for. Instead of using the first existing subdirectory we fine, this checks for all of them and requires that exactly one exist. If more than one exist, then that is now treated the same as if none exist, falling back to the `git --exec-path`-based strategy, which is sometimes slower but more robust.
1 parent 2d2c11b commit 5ac8cff

File tree

1 file changed

+10
-6
lines changed

1 file changed

+10
-6
lines changed

gix-path/src/env/mod.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -155,13 +155,17 @@ where
155155
F: Fn(&str) -> Option<OsString>,
156156
{
157157
let root = PathBuf::from(var_os_func("EXEPATH")?);
158-
for candidate in ["clangarm64", "mingw64", "mingw32"] {
159-
let candidate = root.join(candidate);
160-
if candidate.is_dir() {
161-
return Some(candidate);
162-
}
158+
159+
let mut candidates = ["clangarm64", "mingw64", "mingw32"]
160+
.iter()
161+
.map(|component| root.join(component))
162+
.filter(|candidate| candidate.is_dir());
163+
164+
let path = candidates.next()?;
165+
match candidates.next() {
166+
Some(_) => None, // Multiple plausible candidates, so don't use the `EXEPATH` optimization.
167+
None => Some(path),
163168
}
164-
None
165169
}
166170

167171
/// Returns the platform dependent system prefix or `None` if it cannot be found (right now only on Windows).

0 commit comments

Comments
 (0)