fix: introduce ExtractHeredocError that implements PartialEq (#958)

This commit is contained in:
Michael Bolin
2025-05-16 09:42:27 -07:00
committed by GitHub
parent 84e01f4b62
commit 3d9f4fcd8a
2 changed files with 24 additions and 32 deletions

View File

@@ -4,9 +4,9 @@ mod seek_sequence;
use std::collections::HashMap; use std::collections::HashMap;
use std::path::Path; use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use std::str::Utf8Error;
use anyhow::Context; use anyhow::Context;
use anyhow::Error;
use anyhow::Result; use anyhow::Result;
pub use parser::Hunk; pub use parser::Hunk;
pub use parser::ParseError; pub use parser::ParseError;
@@ -15,6 +15,7 @@ use parser::UpdateFileChunk;
pub use parser::parse_patch; pub use parser::parse_patch;
use similar::TextDiff; use similar::TextDiff;
use thiserror::Error; use thiserror::Error;
use tree_sitter::LanguageError;
use tree_sitter::Parser; use tree_sitter::Parser;
use tree_sitter_bash::LANGUAGE as BASH; use tree_sitter_bash::LANGUAGE as BASH;
@@ -52,10 +53,10 @@ impl PartialEq for IoError {
} }
} }
#[derive(Debug)] #[derive(Debug, PartialEq)]
pub enum MaybeApplyPatch { pub enum MaybeApplyPatch {
Body(Vec<Hunk>), Body(Vec<Hunk>),
ShellParseError(Error), ShellParseError(ExtractHeredocError),
PatchParseError(ParseError), PatchParseError(ParseError),
NotApplyPatch, NotApplyPatch,
} }
@@ -97,14 +98,14 @@ pub enum ApplyPatchFileChange {
}, },
} }
#[derive(Debug)] #[derive(Debug, PartialEq)]
pub enum MaybeApplyPatchVerified { pub enum MaybeApplyPatchVerified {
/// `argv` corresponded to an `apply_patch` invocation, and these are the /// `argv` corresponded to an `apply_patch` invocation, and these are the
/// resulting proposed file changes. /// resulting proposed file changes.
Body(ApplyPatchAction), Body(ApplyPatchAction),
/// `argv` could not be parsed to determine whether it corresponds to an /// `argv` could not be parsed to determine whether it corresponds to an
/// `apply_patch` invocation. /// `apply_patch` invocation.
ShellParseError(Error), ShellParseError(ExtractHeredocError),
/// `argv` corresponded to an `apply_patch` invocation, but it could not /// `argv` corresponded to an `apply_patch` invocation, but it could not
/// be fulfilled due to the specified error. /// be fulfilled due to the specified error.
CorrectnessError(ApplyPatchError), CorrectnessError(ApplyPatchError),
@@ -112,26 +113,6 @@ pub enum MaybeApplyPatchVerified {
NotApplyPatch, NotApplyPatch,
} }
impl PartialEq for MaybeApplyPatchVerified {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(MaybeApplyPatchVerified::Body(a), MaybeApplyPatchVerified::Body(b)) => a == b,
(
MaybeApplyPatchVerified::ShellParseError(a),
MaybeApplyPatchVerified::ShellParseError(b),
) => a.to_string() == b.to_string(),
(
MaybeApplyPatchVerified::CorrectnessError(a),
MaybeApplyPatchVerified::CorrectnessError(b),
) => a == b,
(MaybeApplyPatchVerified::NotApplyPatch, MaybeApplyPatchVerified::NotApplyPatch) => {
true
}
_ => false,
}
}
}
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
/// ApplyPatchAction is the result of parsing an `apply_patch` command. By /// ApplyPatchAction is the result of parsing an `apply_patch` command. By
/// construction, all paths should be absolute paths. /// construction, all paths should be absolute paths.
@@ -225,19 +206,21 @@ pub fn maybe_parse_apply_patch_verified(argv: &[String], cwd: &Path) -> MaybeApp
/// * `Ok(String)` - The heredoc body if the extraction is successful. /// * `Ok(String)` - The heredoc body if the extraction is successful.
/// * `Err(anyhow::Error)` - An error if the extraction fails. /// * `Err(anyhow::Error)` - An error if the extraction fails.
/// ///
fn extract_heredoc_body_from_apply_patch_command(src: &str) -> anyhow::Result<String> { fn extract_heredoc_body_from_apply_patch_command(
src: &str,
) -> std::result::Result<String, ExtractHeredocError> {
if !src.trim_start().starts_with("apply_patch") { if !src.trim_start().starts_with("apply_patch") {
anyhow::bail!("expected command to start with 'apply_patch'"); return Err(ExtractHeredocError::CommandDidNotStartWithApplyPatch);
} }
let lang = BASH.into(); let lang = BASH.into();
let mut parser = Parser::new(); let mut parser = Parser::new();
parser parser
.set_language(&lang) .set_language(&lang)
.context("failed to load bash grammar")?; .map_err(ExtractHeredocError::FailedToLoadBashGrammar)?;
let tree = parser let tree = parser
.parse(src, None) .parse(src, None)
.ok_or_else(|| anyhow::anyhow!("failed to parse patch into AST"))?; .ok_or(ExtractHeredocError::FailedToParsePatchIntoAst)?;
let bytes = src.as_bytes(); let bytes = src.as_bytes();
let mut c = tree.root_node().walk(); let mut c = tree.root_node().walk();
@@ -247,7 +230,7 @@ fn extract_heredoc_body_from_apply_patch_command(src: &str) -> anyhow::Result<St
if node.kind() == "heredoc_body" { if node.kind() == "heredoc_body" {
let text = node let text = node
.utf8_text(bytes) .utf8_text(bytes)
.context("failed to interpret heredoc body as UTF-8")?; .map_err(ExtractHeredocError::HeredocNotUtf8)?;
return Ok(text.trim_end_matches('\n').to_owned()); return Ok(text.trim_end_matches('\n').to_owned());
} }
@@ -256,12 +239,21 @@ fn extract_heredoc_body_from_apply_patch_command(src: &str) -> anyhow::Result<St
} }
while !c.goto_next_sibling() { while !c.goto_next_sibling() {
if !c.goto_parent() { if !c.goto_parent() {
anyhow::bail!("expected to find heredoc_body in patch candidate"); return Err(ExtractHeredocError::FailedToFindHeredocBody);
} }
} }
} }
} }
#[derive(Debug, PartialEq)]
pub enum ExtractHeredocError {
CommandDidNotStartWithApplyPatch,
FailedToLoadBashGrammar(LanguageError),
HeredocNotUtf8(Utf8Error),
FailedToParsePatchIntoAst,
FailedToFindHeredocBody,
}
/// Applies the patch and prints the result to stdout/stderr. /// Applies the patch and prints the result to stdout/stderr.
pub fn apply_patch( pub fn apply_patch(
patch: &str, patch: &str,

View File

@@ -1080,7 +1080,7 @@ async fn handle_function_call(
}; };
} }
MaybeApplyPatchVerified::ShellParseError(error) => { MaybeApplyPatchVerified::ShellParseError(error) => {
trace!("Failed to parse shell command, {error}"); trace!("Failed to parse shell command, {error:?}");
} }
MaybeApplyPatchVerified::NotApplyPatch => (), MaybeApplyPatchVerified::NotApplyPatch => (),
} }