From d6351282bc7abdd310402fae063d093184e99758 Mon Sep 17 00:00:00 2001 From: Johan Norberg Date: Wed, 12 Mar 2025 19:47:10 +0100 Subject: [PATCH 1/2] Show better message if an expected file is not found --- src/object.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/object.rs b/src/object.rs index 56ac8e8..8e49c66 100644 --- a/src/object.rs +++ b/src/object.rs @@ -197,6 +197,9 @@ impl Object { } pub fn from_file(path: &std::path::Path) -> Result { + if !path.exists() { + return Err(anyhow!("Expected file: {:?} does not exist", path)); + } let data = std::fs::read(path).context("Could not read from file")?; let mut z = ZlibDecoder::new(&data[..]); let mut s: Vec = vec![]; @@ -286,6 +289,8 @@ pub fn hash(s: &[u8]) -> String { #[cfg(test)] mod tests { + use tempfile::tempdir; + use crate::object::File; use super::Blob; @@ -411,6 +416,28 @@ parent"; assert_eq!(err, "Incorrect header length"); } + #[test] + fn test_from_file_nonexisting_file() { + let result = Object::from_file(std::path::Path::new("/nonexisting/file")); + assert!(result.is_err()); + assert_eq!( + result.unwrap_err().to_string(), + "Expected file: \"/nonexisting/file\" does not exist" + ); + } + + #[test] + fn test_from_file_with_invalid_data() { + let dir = tempdir().unwrap(); + let file_path = dir.path().join("invalid_object"); + + std::fs::write(&file_path, "not a valid git object").unwrap(); + + let result = Object::from_file(&file_path); + assert!(result.is_err()); + assert_eq!(result.unwrap_err().to_string(), "corrupt deflate stream"); + } + #[test] fn test_blob_hash_is_correct() { // From https://git-scm.com/book/sv/v2/Git-Internals-Git-Objects From 1d0be180b221d2358c5961dbb43a35b06fd82579 Mon Sep 17 00:00:00 2001 From: Johan Norberg Date: Wed, 12 Mar 2025 19:47:59 +0100 Subject: [PATCH 2/2] Handle HEAD as rev * This means things like "cat-file HEAD" and "log HEAD" works. --- src/lib.rs | 8 +++----- src/object.rs | 4 ++++ tests/git_test.rs | 18 +++--------------- 3 files changed, 10 insertions(+), 20 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 68d1280..214e55c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -107,11 +107,9 @@ pub fn log(repo: &Repo, object_rev: &str, stdout: &mut dyn io::Write) -> Result< Object::Commit(commit) => { let commiter = commit.committer; let first_line = commit.message.lines().next().unwrap_or(""); - writeln!( - stdout, - "{hash} - {first_line} - \"{commiter}\"", - hash = &this_rev[0..6] - )?; + // TODO: resolve all refs to their full hash. + // Now this_rev could be for example a branch name. + writeln!(stdout, "{this_rev:.6} - {first_line} - \"{commiter}\"",)?; if commit.parent.is_empty() { return Ok(()); } else { diff --git a/src/object.rs b/src/object.rs index 8e49c66..7b519a0 100644 --- a/src/object.rs +++ b/src/object.rs @@ -227,6 +227,10 @@ impl Object { pub fn from_rev(repo: &Repo, rev: &str) -> Result { let mut candidates: Vec = vec![]; + if rev == "HEAD" { + return Object::from_hash(repo, &refs::find_ref("HEAD", repo)?); + } + // Check if this is a hash if rev.len() >= 4 { let (short_hash, long_hash) = rev.split_at(2); diff --git a/tests/git_test.rs b/tests/git_test.rs index b9769e9..6825199 100644 --- a/tests/git_test.rs +++ b/tests/git_test.rs @@ -168,25 +168,12 @@ mod tests { use super::*; use rstest::rstest; - #[rstest] - fn test_cat_file(test_repo: tempfile::TempDir) { - let repo = Repo::new(test_repo.path()); - let mut stdout = Vec::new(); - - good_git::cat_file( - &repo, - "d670460b4b4aece5915caf5c68d12f560a9fe3e4", - &mut stdout, - ) - .unwrap(); - assert_eq!(stdout, b"test content\n\n"); - } - #[rstest] #[case("d670", b"test content\n\n".to_vec())] #[case("d67046", b"test content\n\n".to_vec())] + #[case("d670460b4b4aece5915caf5c68d12f560a9fe3e4", b"test content\n\n".to_vec())] #[case("1234567890", b"more content\nfrom a good client\n".to_vec())] - fn test_cat_file_short_hash( + fn test_cat_file( test_repo: tempfile::TempDir, #[case] input: String, #[case] expected: Vec, @@ -246,6 +233,7 @@ from a good client #[rstest] #[case("aaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbb")] #[case("main")] // Points to the same commit + #[case("HEAD")] fn test_cat_file_commit(test_repo: tempfile::TempDir, #[case] reference: String) { let repo = Repo::new(test_repo.path()); let mut stdout = Vec::new();