From 650a1b5cf25e086197cc55a68525a411e1c28031 Mon Sep 17 00:00:00 2001 From: Eliah Kagan Date: Sat, 24 Aug 2024 05:52:07 -0400 Subject: [PATCH] fix: Parse installation config path more robustly This adds the `-z`/`--null` and `--name-only` options in the `git` invocation that tries to obtain the configuration file path associated with the `git` installation itself. The benefits are: - Parsing is more reliable for paths containing unusual characters, because `-z`/`--null` causes all paths to be output literally. Previously, `"` characters were trimmed from the ends, but this would not always extract a correct path, because when a path contains characters that cause `git` to enclose it in double quotes, those characters are usually represented in a symbolic form, usually with `\` escapes. In some scenarios, such as usually on Windows when the escaped character is itself a `\` and not in the leading position, the mangled path would be usable, but more often it would not. - The volume of output is less, because `--name-only` casues values not to be included in the output. - The combination of `-z`/`--null` and `--name-only` makes the output format simpler, and the parsing logic is accordingly simpler. `git` has supported the `-z`/`--null` and `--name-only` options even before support for `--show-origin` was added in Git 2.8.0, so this change should have no effect on Git version compatibility. --- gix-path/src/env/git/mod.rs | 6 +++--- gix-path/src/env/git/tests.rs | 13 ++++++++----- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/gix-path/src/env/git/mod.rs b/gix-path/src/env/git/mod.rs index c28aceae44e..d8947a96ff8 100644 --- a/gix-path/src/env/git/mod.rs +++ b/gix-path/src/env/git/mod.rs @@ -90,7 +90,7 @@ pub(super) static EXE_INFO: Lazy> = Lazy::new(|| { cmd.creation_flags(CREATE_NO_WINDOW); } // git 2.8.0 and higher support --show-origin. - cmd.args(["config", "-l", "--show-origin"]) + cmd.args(["config", "-lz", "--show-origin", "--name-only"]) .current_dir(env::temp_dir()) .stdin(Stdio::null()) .stderr(Stdio::null()); @@ -138,8 +138,8 @@ pub(super) fn install_config_path() -> Option<&'static BStr> { 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() + let end_pos = file.find_byte(b'\0')?; + file[..end_pos].as_bstr().into() } /// Given `config_path` as obtained from `install_config_path()`, return the path of the git installation base. diff --git a/gix-path/src/env/git/tests.rs b/gix-path/src/env/git/tests.rs index 033b6f0b983..86b2b7b28f1 100644 --- a/gix-path/src/env/git/tests.rs +++ b/gix-path/src/env/git/tests.rs @@ -17,12 +17,15 @@ fn config_to_base_path() { #[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 macos = + "file:/Applications/Xcode.app/Contents/Developer/usr/share/git-core/gitconfig\0credential.helper\0file:/Users/byron/.gitconfig\0push.default\0"; 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"; + "file:C:/git-sdk-64/etc/gitconfig\0core.symlinks\0file:C:/git-sdk-64/etc/gitconfig\0core.autocrlf\0"; + let win_cmd = + "file:C:/Program Files/Git/etc/gitconfig\0diff.astextplain.textconv\0file:C:/Program Files/Git/etc/gitconfig\0filter.lfs.clean\0"; + let win_msys_old = + "file:C:\\ProgramData/Git/config\0diff.astextplain.textconv\0file:C:\\ProgramData/Git/config\0filter.lfs.clean\0"; + let linux = "file:/home/parallels/.gitconfig\0core.excludesfile\0"; let bogus = "something unexpected"; let empty = "";