fix(git_branch): more robust handling of .git (#3290)

This commit is contained in:
arcnmx 2021-12-03 12:15:31 -08:00 committed by GitHub
parent 1109fd6997
commit e3a88a6ec1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 37 additions and 41 deletions

View File

@ -274,7 +274,8 @@ impl<'a> Context<'a> {
}?;
Ok(Repo {
branch: get_current_branch(&repository),
root: repository.workdir().map(Path::to_path_buf),
workdir: repository.workdir().map(Path::to_path_buf),
path: Path::to_path_buf(repository.path()),
state: repository.state(),
remote: get_remote_repository_info(&repository),
})
@ -433,7 +434,10 @@ pub struct Repo {
/// If `current_dir` is a git repository or is contained within one,
/// this is the path to the root of that repo.
pub root: Option<PathBuf>,
pub workdir: Option<PathBuf>,
/// The path of the repository's `.git` directory.
pub path: PathBuf,
/// State
pub state: RepositoryState,
@ -442,6 +446,13 @@ pub struct Repo {
pub remote: Option<Remote>,
}
impl Repo {
/// Opens the associated git repository.
pub fn open(&self) -> Result<Repository, git2::Error> {
Repository::open(&self.path)
}
}
/// Remote repository
pub struct Remote {
pub branch: Option<String>,

View File

@ -53,7 +53,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
// Otherwise use the logical path, automatically contracting
let repo = context.get_repo().ok();
let dir_string = if config.truncate_to_repo {
repo.and_then(|r| r.root.as_ref())
repo.and_then(|r| r.workdir.as_ref())
.filter(|&root| root != &home_dir)
.and_then(|root| contract_repo_path(display_dir, root))
} else {
@ -99,7 +99,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
String::from("")
};
let path_vec = match &repo.and_then(|r| r.root.as_ref()) {
let path_vec = match &repo.and_then(|r| r.workdir.as_ref()) {
Some(repo_root) if config.repo_root_style.is_some() => {
let contracted_path = contract_repo_path(display_dir, repo_root)?;
let repo_path_vec: Vec<&str> = contracted_path.split('/').collect();

View File

@ -54,7 +54,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
.map(|variable| match variable {
"version" => {
let version = if enable_heuristic {
let repo_root = context.get_repo().ok().and_then(|r| r.root.as_deref());
let repo_root = context.get_repo().ok().and_then(|r| r.workdir.as_deref());
estimate_dotnet_version(
context,
&dotnet_files,

View File

@ -1,7 +1,6 @@
use unicode_segmentation::UnicodeSegmentation;
use super::{Context, Module, RootModuleConfig};
use git2::Repository;
use crate::configs::git_branch::GitBranchConfig;
use crate::formatter::StringFormatter;
@ -27,13 +26,13 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
let repo = context.get_repo().ok()?;
if let Some(repo_root) = repo.root.as_ref() {
let git_repo = Repository::open(repo_root).ok()?;
let is_detached = git_repo.head_detached().ok()?;
if config.only_attached && is_detached {
if config.only_attached {
if let Ok(git_repo) = repo.open() {
if git_repo.head_detached().ok()? {
return None;
}
}
}
let branch_name = repo.branch.as_ref()?;
let mut graphemes: Vec<&str> = branch_name.graphemes(true).collect();

View File

@ -1,6 +1,5 @@
use super::{Context, Module, RootModuleConfig};
use crate::formatter::string_formatter::StringFormatterError;
use git2::Repository;
use git2::Time;
use crate::configs::git_commit::GitCommitConfig;
@ -14,8 +13,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
let config: GitCommitConfig = GitCommitConfig::try_load(module.config);
let repo = context.get_repo().ok()?;
let repo_root = repo.root.as_ref()?;
let git_repo = Repository::open(repo_root).ok()?;
let git_repo = repo.open().ok()?;
let is_detached = git_repo.head_detached().ok()?;
if config.only_detached && !is_detached {

View File

@ -21,13 +21,15 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
};
let repo = context.get_repo().ok()?;
let repo_root = repo.root.as_ref()?;
let repo_root = repo.workdir.as_ref()?;
let diff = context
.exec_cmd(
"git",
&[
OsStr::new("-C"),
OsStr::new("--git-dir"),
repo.path.as_os_str(),
OsStr::new("--work-tree"),
repo_root.as_os_str(),
OsStr::new("--no-optional-locks"),
OsStr::new("diff"),

View File

@ -1,8 +1,9 @@
use git2::RepositoryState;
use std::path::{Path, PathBuf};
use std::path::PathBuf;
use super::{Context, Module, RootModuleConfig};
use crate::configs::git_state::GitStateConfig;
use crate::context::Repo;
use crate::formatter::StringFormatter;
/// Creates a module with the state of the git repository at the current directory
@ -14,10 +15,8 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
let config: GitStateConfig = GitStateConfig::try_load(module.config);
let repo = context.get_repo().ok()?;
let repo_root = repo.root.as_ref()?;
let repo_state = repo.state;
let state_description = get_state_description(repo_state, repo_root, &config)?;
let state_description = get_state_description(repo, &config)?;
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
formatter
@ -52,11 +51,10 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
///
/// During a git operation it will show: REBASING, BISECTING, MERGING, etc.
fn get_state_description<'a>(
state: RepositoryState,
root: &'a Path,
repo: &'a Repo,
config: &GitStateConfig<'a>,
) -> Option<StateDescription<'a>> {
match state {
match repo.state {
RepositoryState::Clean => None,
RepositoryState::Merge => Some(StateDescription {
label: config.merge,
@ -98,13 +96,13 @@ fn get_state_description<'a>(
current: None,
total: None,
}),
RepositoryState::Rebase => Some(describe_rebase(root, config.rebase)),
RepositoryState::RebaseInteractive => Some(describe_rebase(root, config.rebase)),
RepositoryState::RebaseMerge => Some(describe_rebase(root, config.rebase)),
RepositoryState::Rebase => Some(describe_rebase(repo, config.rebase)),
RepositoryState::RebaseInteractive => Some(describe_rebase(repo, config.rebase)),
RepositoryState::RebaseMerge => Some(describe_rebase(repo, config.rebase)),
}
}
fn describe_rebase<'a>(root: &'a Path, rebase_config: &'a str) -> StateDescription<'a> {
fn describe_rebase<'a>(repo: &'a Repo, rebase_config: &'a str) -> StateDescription<'a> {
/*
* Sadly, libgit2 seems to have some issues with reading the state of
* interactive rebases. So, instead, we'll poke a few of the .git files
@ -113,25 +111,13 @@ fn describe_rebase<'a>(root: &'a Path, rebase_config: &'a str) -> StateDescripti
* The following is based heavily on: https://github.com/magicmonty/bash-git-prompt
*/
let dot_git = root.join(".git");
let dot_git = if let Ok(conf) = std::fs::read_to_string(&dot_git) {
let gitdir_re = regex::Regex::new(r"(?m)^gitdir: (.*)$").unwrap();
if let Some(caps) = gitdir_re.captures(&conf) {
root.join(caps.get(1).unwrap().as_str())
} else {
dot_git
}
} else {
dot_git
};
let has_path = |relative_path: &str| {
let path = dot_git.join(PathBuf::from(relative_path));
let path = repo.path.join(PathBuf::from(relative_path));
path.exists()
};
let file_to_usize = |relative_path: &str| {
let path = dot_git.join(PathBuf::from(relative_path));
let path = repo.path.join(PathBuf::from(relative_path));
let contents = crate::utils::read_file(path).ok()?;
let quantity = contents.trim().parse::<usize>().ok()?;
Some(quantity)