From 162dcd49b444360e88244a4fa989e66135684714 Mon Sep 17 00:00:00 2001 From: Yuya Nishihara Date: Tue, 31 Oct 2023 09:50:10 +0900 Subject: [PATCH] cli: rewrite base GitIgnoreFile lookup to use gitoxide instead of libgit2 Since gix::Repository::config_snapshot() borrows the repo instance, it has to be allocated in caller's stack. That's why GitBackend::git_config() is removed. --- Cargo.lock | 1 + cli/Cargo.toml | 1 + cli/src/cli_util.rs | 41 ++++++++++++++++++++--------------------- lib/src/git_backend.rs | 11 ++++------- 4 files changed, 26 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0f2a33646..42afa5a84 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1616,6 +1616,7 @@ dependencies = [ "esl01-renderdag", "futures 0.3.29", "git2", + "gix", "hex", "indexmap", "insta", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 44ed2c750..0c998f2d4 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -41,6 +41,7 @@ dirs = { workspace = true } esl01-renderdag = { workspace = true } futures = { workspace = true } git2 = { workspace = true } +gix = { workspace = true } hex = { workspace = true } indexmap = { workspace = true } itertools = { workspace = true } diff --git a/cli/src/cli_util.rs b/cli/src/cli_util.rs index d0f077226..1c3dcf985 100644 --- a/cli/src/cli_util.rs +++ b/cli/src/cli_util.rs @@ -17,7 +17,6 @@ use std::env::{self, ArgsOs, VarError}; use std::ffi::{OsStr, OsString}; use std::fmt::Debug; use std::io::Write as _; -use std::iter; use std::ops::Deref; use std::path::{Path, PathBuf}; use std::process::ExitCode; @@ -25,6 +24,7 @@ use std::rc::Rc; use std::str::FromStr; use std::sync::Arc; use std::time::SystemTime; +use std::{iter, str}; use clap::builder::{NonEmptyStringValueParser, TypedValueParser, ValueParserFactory}; use clap::{Arg, ArgAction, ArgMatches, Command, FromArgMatches}; @@ -926,16 +926,18 @@ impl WorkspaceCommandHelper { } } - pub fn git_config(&self) -> Result { - if let Some(git_backend) = self.git_backend() { - git_backend.git_config() - } else { - git2::Config::open_default() - } - } - #[instrument(skip_all)] pub fn base_ignores(&self) -> Arc { + fn get_excludes_file_path(config: &gix::config::File) -> Option { + // TODO: maybe use path_by_key() and interpolate(), which can process non-utf-8 + // path on Unix. + if let Some(value) = config.string_by_key("core.excludesFile") { + str::from_utf8(&value).ok().map(expand_git_path) + } else { + xdg_config_home().ok().map(|x| x.join("git").join("ignore")) + } + } + fn xdg_config_home() -> Result { if let Ok(x) = std::env::var("XDG_CONFIG_HOME") { if !x.is_empty() { @@ -946,20 +948,17 @@ impl WorkspaceCommandHelper { } let mut git_ignores = GitIgnoreFile::empty(); - if let Ok(excludes_file_path) = self - .git_config() - .and_then(|git_config| { - git_config - .get_string("core.excludesFile") - .map(expand_git_path) - }) - .or_else(|_| xdg_config_home().map(|x| x.join("git").join("ignore"))) - { - git_ignores = git_ignores.chain_with_file("", excludes_file_path); - } if let Some(git_backend) = self.git_backend() { + let git_repo = git_backend.git_repo(); + if let Some(excludes_file_path) = get_excludes_file_path(&git_repo.config_snapshot()) { + git_ignores = git_ignores.chain_with_file("", excludes_file_path); + } git_ignores = git_ignores .chain_with_file("", git_backend.git_repo_path().join("info").join("exclude")); + } else if let Ok(git_config) = gix::config::File::from_globals() { + if let Some(excludes_file_path) = get_excludes_file_path(&git_config) { + git_ignores = git_ignores.chain_with_file("", excludes_file_path); + } } git_ignores } @@ -1853,7 +1852,7 @@ export or their "parent" branches."#, } /// Expands "~/" to "$HOME/" as Git seems to do for e.g. core.excludesFile. -fn expand_git_path(path_str: String) -> PathBuf { +fn expand_git_path(path_str: &str) -> PathBuf { if let Some(remainder) = path_str.strip_prefix("~/") { if let Ok(home_dir_str) = std::env::var("HOME") { return PathBuf::from(home_dir_str).join(remainder); diff --git a/lib/src/git_backend.rs b/lib/src/git_backend.rs index bdf9fda65..d8d4288d8 100644 --- a/lib/src/git_backend.rs +++ b/lib/src/git_backend.rs @@ -206,19 +206,16 @@ impl GitBackend { self.repo.lock().unwrap() } - // TODO: add public API to obtain new gix::Repository from base_repo + /// Returns new thread-local instance to access to the underlying Git repo. + pub fn git_repo(&self) -> gix::Repository { + self.base_repo.to_thread_local() + } /// Creates new owned git repository instance. pub fn open_git_repo(&self) -> Result { git2::Repository::open(self.git_repo_path()) } - /// Git configuration for this repository. - pub fn git_config(&self) -> Result { - // TODO: switch to gix config type - self.open_git_repo().and_then(|repo| repo.config()) - } - /// Path to the `.git` directory or the repository itself if it's bare. pub fn git_repo_path(&self) -> &Path { self.base_repo.path()