use std::path::PathBuf;
use anyhow::{Context as _, Result};
use crate::cancel::Cancel;
use crate::cli::Cli;
use crate::config::{Global, Repo};
#[allow(clippy::struct_excessive_bools)]
pub struct Context {
repo_hint: Option<PathBuf>,
config_override: Option<PathBuf>,
pub json: bool,
pub no_color: bool,
pub yes: bool,
pub quiet: bool,
pub cancel: Cancel,
}
impl Context {
#[must_use]
pub fn from_cli(cli: &Cli, cancel: Cancel) -> Self {
let no_color = cli.no_color || std::env::var_os("NO_COLOR").is_some();
Self {
repo_hint: cli.repo.clone(),
config_override: cli.config.clone(),
json: cli.json,
no_color,
yes: cli.yes,
quiet: cli.quiet,
cancel,
}
}
pub fn repo(&self) -> Result<PathBuf> {
let start = match &self.repo_hint {
Some(p) => p.clone(),
None => std::env::current_dir().context("read current dir")?,
};
for ancestor in start.ancestors() {
if ancestor.join(".git").exists() {
return Ok(ancestor.to_path_buf());
}
if ancestor.join("HEAD").is_file()
&& ancestor.join("objects").is_dir()
&& ancestor.join("refs").is_dir()
{
return Ok(ancestor.to_path_buf());
}
}
anyhow::bail!(
"not a git repository at {}; try: cd into a repo or pass --repo <path>",
start.display()
)
}
pub fn global(&self) -> Result<Global> {
Global::load(self.config_override.as_deref())
}
pub fn repo_config(&self) -> Result<Option<Repo>> {
let repo = self.repo()?;
Repo::discover(&repo)
}
#[must_use]
pub fn repo_config_optional(&self) -> Option<Repo> {
self.repo()
.ok()
.and_then(|r| Repo::discover(&r).ok().flatten())
}
}