Sebastian Thielmake fmt5d2b5d03 years agoHistory
89 lines · 3.9 KB · Rust
RawDownload
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)            );        }    }}