Skip to content

Commit 27e6504

Browse files
committed
Divide helpers more logically, expand doc comments
This also uses `once_cell::sync::Lazy` for the inferred Git for Windows installation directory based on `git --exec-path` output, though it is only used in one function that is itself only used by a caller that itself caches, so it too is so far effectively just a refactoring.
1 parent 3b07dc6 commit 27e6504

File tree

1 file changed

+40
-17
lines changed

1 file changed

+40
-17
lines changed

gix-path/src/env/auxiliary.rs

+40-17
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use std::ffi::OsString;
2-
use std::path::Path;
2+
use std::path::{Path, PathBuf};
3+
4+
use once_cell::sync::Lazy;
35

46
/// `usr`-like directory component names that MSYS2 may provide, other than for `/usr` itself.
57
///
@@ -25,20 +27,48 @@ use std::path::Path;
2527
/// Second, we don't recognize `usr` itself here, even though is a plausible prefix. In MSYS2, it
2628
/// is the prefix for MSYS2 non-native programs, i.e. those that use `msys-2.0.dll`. But unlike the
2729
/// `<platform>` names we recognize, `usr` also has an effectively unbounded range of plausible
28-
/// meanings on non-Unix systems, which may occasionally relate to subdirectories whose contents
29-
/// are controlled by different user accounts.
30+
/// meanings on non-Unix systems (for example, what should we take `Z:\usr` to mean?), which might
31+
/// occasionally relate to subdirectories with contents controlled by different *user accounts*.
3032
///
3133
/// If we start with a `libexec/git-core` directory that we already use and trust, and it is in a
3234
/// directory with a name like `mingw64`, we infer that this `mingw64` directory has the expected
33-
/// meaning and that its `usr` sibling, if present, is acceptable to treat as though it is a
34-
/// first-level directory inside an MSYS2-like tree. So we are willing to traverse down to
35-
/// `usr/sh.exe` and attempt to use it. But if the `libexec/git-core` we use and trust is inside a
35+
/// meaning and accordingly infer that its `usr` sibling, if present, is acceptable to treat as
36+
/// though it is a first-level directory inside an MSYS2-like tree. So we are willing to traverse
37+
/// down to `usr/sh.exe` and try to use it. But if the `libexec/git-core` we use and trust is in a
3638
/// directory named `usr`, that `usr` directory may still not have the meaning we expect of `usr`.
3739
///
38-
/// The conditions for a privilege escalation attack or other serious malfunction seem unlikely. If
39-
/// research indicates the risk is low enough, `usr` may be added. But for now it is omitted.
40+
/// Conditions for a privilege escalation attack or other serious malfunction seem far-fetched. If
41+
/// further research finds the risk is low enough, `usr` may be added. But for now it is omitted.
4042
const MSYS_USR_VARIANTS: &[&str] = &["mingw64", "mingw32", "clangarm64", "clang64", "clang32", "ucrt64"];
4143

44+
/// Find a Git for Windows installation directory based on `git --exec-path` output.
45+
///
46+
/// Currently this is used only for finding the path to an `sh.exe` associated with Git. This is
47+
/// separate from `installation_config()` and `installation_config_prefix()` in `gix_path::env`,
48+
/// which guess where `etc/gitconfig` is based on `EXEPATH` or the location of the highest-scope
49+
/// config file.
50+
///
51+
/// The techniques might be combined or unified in some way in the future. The techniques those
52+
/// functions currently use shouldn't be used to find `sh.exe`, because `EXEPATH` can take on other
53+
/// values in some environments, and the highest scope config file may be unavailable or in another
54+
/// location if `GIT_CONFIG_SYSTEM` or `GIT_CONFIG_NOSYSTEM` are set or if there are no variables
55+
/// of system scope. Then paths found relative to it could be different. In contrast, the technique
56+
/// used here may be usable for those functions, though may need to cover more directory layouts.
57+
fn git_for_windows_root() -> Option<&'static Path> {
58+
static GIT_ROOT: Lazy<Option<PathBuf>> = Lazy::new(|| {
59+
super::core_dir()
60+
.filter(|core| core.is_absolute() && core.ends_with("libexec/git-core"))
61+
.and_then(|core| core.ancestors().nth(2))
62+
.filter(|prefix| {
63+
// Only use `libexec/git-core` from inside something `usr`-like, such as `mingw64`.
64+
MSYS_USR_VARIANTS.iter().any(|name| prefix.ends_with(name))
65+
})
66+
.and_then(|prefix| prefix.parent())
67+
.map(Into::into)
68+
});
69+
GIT_ROOT.as_deref()
70+
}
71+
4272
/// Shell path fragments to concatenate to the root of a Git for Windows or MSYS2 installation.
4373
///
4474
/// These look like absolute Unix-style paths, but the leading `/` separators are present because
@@ -56,16 +86,9 @@ fn raw_join(path: &Path, raw_suffix: &str) -> OsString {
5686
raw_path
5787
}
5888

59-
///
89+
/// Obtain a path to a `sh.exe` on Windows associated with Git, if one can be found.
6090
pub(super) fn find_sh_on_windows() -> Option<OsString> {
61-
super::core_dir()
62-
.filter(|core| core.is_absolute() && core.ends_with("libexec/git-core"))
63-
.and_then(|core| core.ancestors().nth(2))
64-
.filter(|prefix| {
65-
// Only use `libexec/git-core` from inside something `usr`-like, such as `mingw64`.
66-
MSYS_USR_VARIANTS.iter().any(|name| prefix.ends_with(name))
67-
})
68-
.and_then(|prefix| prefix.parent())
91+
git_for_windows_root()
6992
.into_iter()
7093
.flat_map(|git_root| {
7194
// Enumerate locations where `sh.exe` usually is. To avoid breaking scripts that assume the

0 commit comments

Comments
 (0)