use crate::objects::blob::{compress_zlib, compute_sha1, hash_to_hex};
use std::io::Result;
pub fn create_commit(
tree_hash: &str,
parent_hash: Option<&str>,
author: &str,
committer: &str,
message: &str,
) -> Result<String> {
if tree_hash.len() != 40 {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!(
"Invalid tree hash length: expected 40 characters, got {}",
tree_hash.len()
),
));
}
if let Some(parent) = parent_hash {
if parent.len() != 40 {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!(
"Invalid parent hash length: expected 40 characters, got {}",
parent.len()
),
));
}
}
if author.is_empty() {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"Author cannot be empty",
));
}
if committer.is_empty() {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"Committer cannot be empty",
));
}
if message.is_empty() {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"Commit message cannot be empty",
));
}
let mut content = String::new();
content.push_str(&format!(
"tree {}
",
tree_hash
));
if let Some(parent) = parent_hash {
content.push_str(&format!(
"parent {}
",
parent
));
}
content.push_str(&format!(
"author {}
",
author
));
content.push_str(&format!(
"committer {}
",
committer
));
content.push_str(&format!(
"\n{}
",
message
));
let header = format!("commit {}\0", content.len());
let data = [header.as_bytes(), content.as_bytes()].concat();
let hash = compute_sha1(&data);
let compressed_data = compress_zlib(&data)?;
let hash_str = hash_to_hex(&hash);
let dir_path = format!(".xit/objects/{}", &hash_str[0..2]);
std::fs::create_dir_all(&dir_path)?;
let path = format!("{}/{}", dir_path, &hash_str[2..]);
std::fs::write(path, compressed_data)?;
Ok(hash_str)
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
#[test]
fn test_create_commit() {
let tree_hash = "1234567890123456789012345678901234567890";
let parent_hash = "0987654321098765432109876543210987654321";
let author = "Author Name <author@example.com>";
let committer = "Committer Name <committer@example.com>";
let message = "Test commit";
let hash = create_commit(tree_hash, Some(parent_hash), author, committer, message).unwrap();
let dir_path = format!(".xit/objects/{}", &hash[0..2]);
fs::remove_dir_all(dir_path).unwrap();
}
}