From 9e2da88d95af43cf29e8a6767d9f5483ce7571ec Mon Sep 17 00:00:00 2001 From: Thomas O'Donnell Date: Mon, 5 Jul 2021 23:19:09 +0200 Subject: fix(git_status): Fix when the worktree != root dir (#2831) Have updated the git_status module to work if the worktree has been changed to a different directory than the repository root directory. --- src/modules/git_status.rs | 61 +++++++++++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/src/modules/git_status.rs b/src/modules/git_status.rs index b8dd655ad..0c921c09c 100644 --- a/src/modules/git_status.rs +++ b/src/modules/git_status.rs @@ -4,10 +4,8 @@ use regex::Regex; use super::{Context, Module, RootModuleConfig}; use crate::configs::git_status::GitStatusConfig; -use crate::context::Repo; use crate::formatter::StringFormatter; use crate::segment::Segment; -use std::path::Path; use std::sync::Arc; const ALL_STATUS_FORMAT: &str = "$conflicted$stashed$deleted$renamed$modified$staged$untracked"; @@ -27,8 +25,7 @@ const ALL_STATUS_FORMAT: &str = "$conflicted$stashed$deleted$renamed$modified$st /// - `»` — A renamed file has been added to the staging area /// - `✘` — A file's deletion has been added to the staging area pub fn module<'a>(context: &'a Context) -> Option> { - let repo = context.get_repo().ok()?; - let info = Arc::new(GitStatusInfo::load(context, repo)); + let info = Arc::new(GitStatusInfo::load(context)); let mut module = context.new_module("git_status"); let config: GitStatusConfig = GitStatusConfig::try_load(module.config); @@ -110,16 +107,14 @@ pub fn module<'a>(context: &'a Context) -> Option> { struct GitStatusInfo<'a> { context: &'a Context<'a>, - repo: &'a Repo, repo_status: OnceCell>, stashed_count: OnceCell>, } impl<'a> GitStatusInfo<'a> { - pub fn load(context: &'a Context, repo: &'a Repo) -> Self { + pub fn load(context: &'a Context) -> Self { Self { context, - repo, repo_status: OnceCell::new(), stashed_count: OnceCell::new(), } @@ -130,31 +125,25 @@ impl<'a> GitStatusInfo<'a> { } pub fn get_repo_status(&self) -> &Option { - self.repo_status.get_or_init(|| { - let repo_root = self.repo.root.as_ref()?; - - match get_repo_status(self.context, repo_root) { + self.repo_status + .get_or_init(|| match get_repo_status(self.context) { Some(repo_status) => Some(repo_status), None => { log::debug!("get_repo_status: git status execution failed"); None } - } - }) + }) } pub fn get_stashed(&self) -> &Option { - self.stashed_count.get_or_init(|| { - let repo_root = self.repo.root.as_ref()?; - - match get_stashed_count(self.context, repo_root) { + self.stashed_count + .get_or_init(|| match get_stashed_count(self.context) { Some(stashed_count) => Some(stashed_count), None => { log::debug!("get_stashed_count: git stash execution failed"); None } - } - }) + }) } pub fn get_conflicted(&self) -> Option { @@ -183,7 +172,7 @@ impl<'a> GitStatusInfo<'a> { } /// Gets the number of files in various git states (staged, modified, deleted, etc...) -fn get_repo_status(context: &Context, repo_root: &Path) -> Option { +fn get_repo_status(context: &Context) -> Option { log::debug!("New repo status created"); let mut repo_status = RepoStatus::default(); @@ -191,7 +180,7 @@ fn get_repo_status(context: &Context, repo_root: &Path) -> Option { "git", &[ "-C", - &repo_root.to_string_lossy(), + &context.current_dir.to_string_lossy(), "--no-optional-locks", "status", "--porcelain=2", @@ -211,12 +200,12 @@ fn get_repo_status(context: &Context, repo_root: &Path) -> Option { Some(repo_status) } -fn get_stashed_count(context: &Context, repo_root: &Path) -> Option { +fn get_stashed_count(context: &Context) -> Option { let stash_output = context.exec_cmd( "git", &[ "-C", - &repo_root.to_string_lossy(), + &context.current_dir.to_string_lossy(), "--no-optional-locks", "stash", "list", @@ -757,6 +746,32 @@ mod tests { repo_dir.close() } + #[test] + fn worktree_in_different_dir() -> io::Result<()> { + let worktree_dir = tempfile::tempdir()?; + let repo_dir = fixture_repo(FixtureProvider::Git)?; + + Command::new("git") + .args(&[ + "config", + "core.worktree", + &worktree_dir.path().to_string_lossy(), + ]) + .current_dir(repo_dir.path()) + .output()?; + + File::create(worktree_dir.path().join("test_file"))?.sync_all()?; + + let actual = ModuleRenderer::new("git_status") + .path(&repo_dir.path()) + .collect(); + let expected = format_output("✘?"); + + assert_eq!(expected, actual); + worktree_dir.close()?; + repo_dir.close() + } + // Whenever a file is manually renamed, git itself ('git status') does not treat such file as renamed, // but as untracked instead. The following test checks if manually deleted and manually renamed // files are tracked by git_status module in the same way 'git status' does. -- cgit v1.2.3