summaryrefslogtreecommitdiffstats
path: root/vendor/gix-path/src
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gix-path/src')
-rw-r--r--vendor/gix-path/src/convert.rs10
-rw-r--r--vendor/gix-path/src/env/git.rs89
-rw-r--r--vendor/gix-path/src/env/mod.rs117
-rw-r--r--vendor/gix-path/src/lib.rs3
4 files changed, 219 insertions, 0 deletions
diff --git a/vendor/gix-path/src/convert.rs b/vendor/gix-path/src/convert.rs
index 6a949529f..d8bf70353 100644
--- a/vendor/gix-path/src/convert.rs
+++ b/vendor/gix-path/src/convert.rs
@@ -82,6 +82,16 @@ pub fn into_bstr<'a>(path: impl Into<Cow<'a, Path>>) -> Cow<'a, BStr> {
try_into_bstr(path).expect("prefix path doesn't contain ill-formed UTF-8")
}
+/// Join `path` to `base` such that they are separated with a `/`, i.e. `base/path`.
+pub fn join_bstr_unix_pathsep<'a, 'b>(base: impl Into<Cow<'a, BStr>>, path: impl Into<&'b BStr>) -> Cow<'a, BStr> {
+ let mut base = base.into();
+ if !base.is_empty() && base.last() != Some(&b'/') {
+ base.to_mut().push(b'/');
+ }
+ base.to_mut().extend_from_slice(path.into());
+ base
+}
+
/// Given `input` bytes, produce a `Path` from them ignoring encoding entirely if on unix.
///
/// On windows, the input is required to be valid UTF-8, which is guaranteed if we wrote it before. There are some potential
diff --git a/vendor/gix-path/src/env/git.rs b/vendor/gix-path/src/env/git.rs
new file mode 100644
index 000000000..2e5d867bb
--- /dev/null
+++ b/vendor/gix-path/src/env/git.rs
@@ -0,0 +1,89 @@
+use std::{
+ path::Path,
+ process::{Command, Stdio},
+};
+
+use bstr::{BStr, BString, ByteSlice};
+
+/// Returns the file that contains git configuration coming with the installation of the `git` file in the current `PATH`, or `None`
+/// if no `git` executable was found or there were other errors during execution.
+pub(crate) fn install_config_path() -> Option<&'static BStr> {
+ static PATH: once_cell::sync::Lazy<Option<BString>> = once_cell::sync::Lazy::new(|| {
+ // Shortcut: in Msys shells this variable is set which allows to deduce the installation directory
+ // so we can save the `git` invocation.
+ #[cfg(windows)]
+ if let Some(mut exec_path) = std::env::var_os("EXEPATH").map(std::path::PathBuf::from) {
+ exec_path.push("etc");
+ exec_path.push("gitconfig");
+ return crate::os_string_into_bstring(exec_path.into()).ok();
+ }
+ let mut cmd = Command::new(if cfg!(windows) { "git.exe" } else { "git" });
+ cmd.args(["config", "-l", "--show-origin"])
+ .stdin(Stdio::null())
+ .stderr(Stdio::null());
+ first_file_from_config_with_origin(cmd.output().ok()?.stdout.as_slice().into()).map(ToOwned::to_owned)
+ });
+ PATH.as_ref().map(|b| b.as_ref())
+}
+
+fn first_file_from_config_with_origin(source: &BStr) -> Option<&BStr> {
+ let file = source.strip_prefix(b"file:")?;
+ let end_pos = file.find_byte(b'\t')?;
+ file[..end_pos].trim_with(|c| c == '"').as_bstr().into()
+}
+
+/// Given `config_path` as obtained from `install_config_path()`, return the path of the git installation base.
+pub(crate) fn config_to_base_path(config_path: &Path) -> &Path {
+ config_path
+ .parent()
+ .expect("config file paths always have a file name to pop")
+}
+
+#[cfg(test)]
+mod tests {
+ use std::path::Path;
+
+ #[test]
+ fn config_to_base_path() {
+ for (input, expected) in [
+ (
+ "/Applications/Xcode.app/Contents/Developer/usr/share/git-core/gitconfig",
+ "/Applications/Xcode.app/Contents/Developer/usr/share/git-core",
+ ),
+ ("C:/git-sdk-64/etc/gitconfig", "C:/git-sdk-64/etc"),
+ ("C:\\ProgramData/Git/config", "C:\\ProgramData/Git"),
+ ("C:/Program Files/Git/etc/gitconfig", "C:/Program Files/Git/etc"),
+ ] {
+ assert_eq!(super::config_to_base_path(Path::new(input)), Path::new(expected));
+ }
+ }
+ #[test]
+ fn first_file_from_config_with_origin() {
+ let macos = "file:/Applications/Xcode.app/Contents/Developer/usr/share/git-core/gitconfig credential.helper=osxkeychain\nfile:/Users/byron/.gitconfig push.default=simple\n";
+ let win_msys =
+ "file:C:/git-sdk-64/etc/gitconfig core.symlinks=false\r\nfile:C:/git-sdk-64/etc/gitconfig core.autocrlf=true";
+ let win_cmd = "file:C:/Program Files/Git/etc/gitconfig diff.astextplain.textconv=astextplain\r\nfile:C:/Program Files/Git/etc/gitconfig filter.lfs.clean=gix-lfs clean -- %f\r\n";
+ let win_msys_old = "file:\"C:\\ProgramData/Git/config\" diff.astextplain.textconv=astextplain\r\nfile:\"C:\\ProgramData/Git/config\" filter.lfs.clean=git-lfs clean -- %f\r\n";
+ let linux = "file:/home/parallels/.gitconfig core.excludesfile=~/.gitignore\n";
+ let bogus = "something unexpected";
+ let empty = "";
+
+ for (source, expected) in [
+ (
+ macos,
+ Some("/Applications/Xcode.app/Contents/Developer/usr/share/git-core/gitconfig"),
+ ),
+ (win_msys, Some("C:/git-sdk-64/etc/gitconfig")),
+ (win_msys_old, Some("C:\\ProgramData/Git/config")),
+ (win_cmd, Some("C:/Program Files/Git/etc/gitconfig")),
+ (linux, Some("/home/parallels/.gitconfig")),
+ (bogus, None),
+ (empty, None),
+ ] {
+ assert_eq!(
+ super::first_file_from_config_with_origin(source.into()),
+ expected.map(Into::into)
+ );
+ }
+ }
+}
diff --git a/vendor/gix-path/src/env/mod.rs b/vendor/gix-path/src/env/mod.rs
new file mode 100644
index 000000000..170222c7a
--- /dev/null
+++ b/vendor/gix-path/src/env/mod.rs
@@ -0,0 +1,117 @@
+use std::{
+ ffi::OsString,
+ path::{Path, PathBuf},
+};
+
+use bstr::{BString, ByteSlice};
+
+mod git;
+
+/// Return the location at which installation specific git configuration file can be found, or `None`
+/// if the binary could not be executed or its results could not be parsed.
+///
+/// ### Performance
+///
+/// This invokes the git binary which is slow on windows.
+pub fn installation_config() -> Option<&'static Path> {
+ git::install_config_path().and_then(|p| crate::try_from_byte_slice(p).ok())
+}
+
+/// Return the location at which git installation specific configuration files are located, or `None` if the binary
+/// could not be executed or its results could not be parsed.
+///
+/// ### Performance
+///
+/// This invokes the git binary which is slow on windows.
+pub fn installation_config_prefix() -> Option<&'static Path> {
+ installation_config().map(git::config_to_base_path)
+}
+
+/// Returns the fully qualified path in the *xdg-home* directory (or equivalent in the home dir) to `file`,
+/// accessing `env_var(<name>)` to learn where these bases are.
+///
+/// Note that the `HOME` directory should ultimately come from [`home_dir()`] as it handles windows correctly.
+/// The same can be achieved by using [`var()`] as `env_var`.
+pub fn xdg_config(file: &str, env_var: &mut dyn FnMut(&str) -> Option<OsString>) -> Option<PathBuf> {
+ env_var("XDG_CONFIG_HOME")
+ .map(|home| {
+ let mut p = PathBuf::from(home);
+ p.push("git");
+ p.push(file);
+ p
+ })
+ .or_else(|| {
+ env_var("HOME").map(|home| {
+ let mut p = PathBuf::from(home);
+ p.push(".config");
+ p.push("git");
+ p.push(file);
+ p
+ })
+ })
+}
+
+/// Returns the platform dependent system prefix or `None` if it cannot be found (right now only on windows).
+///
+/// ### Performance
+///
+/// On windows, the slowest part is the launch of the `git.exe` executable in the PATH, which only happens when launched
+/// from outside of the `msys2` shell.
+///
+/// ### When `None` is returned
+///
+/// This happens only windows if the git binary can't be found at all for obtaining its executable path, or if the git binary
+/// wasn't built with a well-known directory structure or environment.
+pub fn system_prefix() -> Option<&'static Path> {
+ if cfg!(windows) {
+ static PREFIX: once_cell::sync::Lazy<Option<PathBuf>> = once_cell::sync::Lazy::new(|| {
+ if let Some(root) = std::env::var_os("EXEPATH").map(PathBuf::from) {
+ for candidate in ["mingw64", "mingw32"] {
+ let candidate = root.join(candidate);
+ if candidate.is_dir() {
+ return Some(candidate);
+ }
+ }
+ }
+
+ let path = std::process::Command::new("git.exe")
+ .arg("--exec-path")
+ .stderr(std::process::Stdio::null())
+ .output()
+ .ok()?
+ .stdout;
+ let path = BString::new(path)
+ .trim_with(|b| b.is_ascii_whitespace())
+ .to_path()
+ .ok()?
+ .to_owned();
+
+ let one_past_prefix = path.components().enumerate().find_map(|(idx, c)| {
+ matches!(c,std::path::Component::Normal(name) if name.to_str() == Some("libexec")).then_some(idx)
+ })?;
+ Some(path.components().take(one_past_prefix.checked_sub(1)?).collect())
+ });
+ PREFIX.as_deref()
+ } else {
+ Path::new("/").into()
+ }
+}
+
+/// Returns `$HOME` or `None` if it cannot be found.
+#[cfg(target_family = "wasm")]
+pub fn home_dir() -> Option<PathBuf> {
+ std::env::var("HOME").map(PathBuf::from).ok()
+}
+
+#[cfg(not(target_family = "wasm"))]
+pub use home::home_dir;
+
+/// Returns the contents of an environment variable of `name` with some special handling
+/// for certain environment variables (like `HOME`) for platform compatibility.
+pub fn var(name: &str) -> Option<OsString> {
+ if name == "HOME" {
+ home_dir().map(PathBuf::into_os_string)
+ } else {
+ std::env::var_os(name)
+ }
+}
diff --git a/vendor/gix-path/src/lib.rs b/vendor/gix-path/src/lib.rs
index 70a9bc53f..6895aca46 100644
--- a/vendor/gix-path/src/lib.rs
+++ b/vendor/gix-path/src/lib.rs
@@ -66,3 +66,6 @@ mod spec;
///
pub mod realpath;
pub use realpath::function::{realpath, realpath_opts};
+
+/// Information about the environment in terms of locations of resources.
+pub mod env;