
https://github.com/zed-industries/zed/issues/30972 brought up another case where our context is not enough to track the actual source of the issue: we get a general top-level error without inner error. The reason for this was `.ok_or_else(|| anyhow!("failed to read HEAD SHA"))?; ` on the top level. The PR finally reworks the way we use anyhow to reduce such issues (or at least make it simpler to bubble them up later in a fix). On top of that, uses a few more anyhow methods for better readability. * `.ok_or_else(|| anyhow!("..."))`, `map_err` and other similar error conversion/option reporting cases are replaced with `context` and `with_context` calls * in addition to that, various `anyhow!("failed to do ...")` are stripped with `.context("Doing ...")` messages instead to remove the parasitic `failed to` text * `anyhow::ensure!` is used instead of `if ... { return Err(...); }` calls * `anyhow::bail!` is used instead of `return Err(anyhow!(...));` Release Notes: - N/A
111 lines
3.5 KiB
Rust
111 lines
3.5 KiB
Rust
use crate::{Oid, status::StatusCode};
|
||
use anyhow::{Context as _, Result};
|
||
use collections::HashMap;
|
||
use std::path::Path;
|
||
|
||
pub async fn get_messages(working_directory: &Path, shas: &[Oid]) -> Result<HashMap<Oid, String>> {
|
||
if shas.is_empty() {
|
||
return Ok(HashMap::default());
|
||
}
|
||
|
||
const MARKER: &str = "<MARKER>";
|
||
|
||
let output = util::command::new_smol_command("git")
|
||
.current_dir(working_directory)
|
||
.arg("show")
|
||
.arg("-s")
|
||
.arg(format!("--format=%B{}", MARKER))
|
||
.args(shas.iter().map(ToString::to_string))
|
||
.output()
|
||
.await
|
||
.context("starting git blame process")?;
|
||
|
||
anyhow::ensure!(
|
||
output.status.success(),
|
||
"'git show' failed with error {:?}",
|
||
output.status
|
||
);
|
||
|
||
Ok(shas
|
||
.iter()
|
||
.cloned()
|
||
.zip(
|
||
String::from_utf8_lossy(&output.stdout)
|
||
.trim()
|
||
.split_terminator(MARKER)
|
||
.map(|str| str.trim().replace("<", "<").replace(">", ">")),
|
||
)
|
||
.collect::<HashMap<Oid, String>>())
|
||
}
|
||
|
||
/// Parse the output of `git diff --name-status -z`
|
||
pub fn parse_git_diff_name_status(content: &str) -> impl Iterator<Item = (&Path, StatusCode)> {
|
||
let mut parts = content.split('\0');
|
||
std::iter::from_fn(move || {
|
||
loop {
|
||
let status_str = parts.next()?;
|
||
let path = parts.next()?;
|
||
let status = match status_str {
|
||
"M" => StatusCode::Modified,
|
||
"A" => StatusCode::Added,
|
||
"D" => StatusCode::Deleted,
|
||
_ => continue,
|
||
};
|
||
return Some((Path::new(path), status));
|
||
}
|
||
})
|
||
}
|
||
|
||
#[cfg(test)]
|
||
mod tests {
|
||
use super::*;
|
||
|
||
#[test]
|
||
fn test_parse_git_diff_name_status() {
|
||
let input = concat!(
|
||
"M |