Skip to content

Commit

Permalink
Add support for hash-object -w
Browse files Browse the repository at this point in the history
  • Loading branch information
robinlinden committed Sep 2, 2024
1 parent 037fed4 commit 5151563
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 5 deletions.
37 changes: 34 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::{fs, io};
use std::{
fs,
io::{self, Write},
};

use anyhow::Result;
use object::Object;
Expand All @@ -22,12 +25,35 @@ pub fn init_repo(repo: &Repo, branch_name: &str) -> Result<()> {
Ok(())
}

pub fn hash_object(object: &mut dyn io::Read, stdout: &mut dyn io::Write) -> Result<()> {
pub enum HashObjectMode<'a> {
HashOnly,
Write(&'a Repo),
}

pub fn hash_object(
mode: HashObjectMode,
object: &mut dyn io::Read,
stdout: &mut dyn io::Write,
) -> Result<()> {
let mut data = Vec::new();
object.read_to_end(&mut data)?;
let blob = object::Blob::new(data);
let hash = blob.hash();

if let HashObjectMode::Write(repo) = mode {
let dir = &repo.git_dir().join("objects").join(&hash[0..2]);
let file_path = dir.join(&hash[2..]);
let mut data = Vec::new();
let mut writer = flate2::write::ZlibEncoder::new(&mut data, flate2::Compression::default());
writer.write_all(b"blob ")?;
writer.write_all(blob.content.len().to_string().as_bytes())?;
writer.write_all(b"\0")?;
writer.write_all(&blob.content)?;
drop(writer);
fs::create_dir_all(dir)?;
fs::write(file_path, data)?;
}

writeln!(stdout, "{hash}")?;
Ok(())
}
Expand Down Expand Up @@ -116,7 +142,12 @@ mod tests {
let mut stdout = Vec::new();

// From https://git-scm.com/book/sv/v2/Git-Internals-Git-Objects
hash_object(&mut "test content\n".as_bytes(), &mut stdout).unwrap();
hash_object(
HashObjectMode::HashOnly,
&mut "test content\n".as_bytes(),
&mut stdout,
)
.unwrap();
assert_eq!(stdout, b"d670460b4b4aece5915caf5c68d12f560a9fe3e4\n");
}
}
18 changes: 16 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ struct InitArgs {

#[derive(Args)]
struct HashObjectArgs {
/// Write the object into the object database.
#[arg(short)]
write: bool,

/// Read the object from stdin instead of from a file.
#[arg(long)]
stdin: bool,
Expand All @@ -65,15 +69,25 @@ fn main() -> Result<()> {
good_git::init_repo(&Repo::new(&init_args.path), &init_args.branch)?;
}
Commands::HashObject(hash_object_args) => {
let repo = Repo::from_dir(Path::new("."));
let mode = if hash_object_args.write {
good_git::HashObjectMode::Write(
repo.as_ref()
.ok_or_else(|| anyhow!("Could not find a valid git repository"))?,
)
} else {
good_git::HashObjectMode::HashOnly
};

if hash_object_args.stdin {
hash_object(&mut io::stdin(), &mut io::stdout())?;
hash_object(mode, &mut io::stdin(), &mut io::stdout())?;
} else {
let f = hash_object_args
.file
.clone()
.expect("<file> is required when --stdin isn't set");
let f = fs::File::open(f)?;
hash_object(&mut io::BufReader::new(f), &mut io::stdout())?;
hash_object(mode, &mut io::BufReader::new(f), &mut io::stdout())?;
}
}
Commands::CatFile(cat_file_args) => {
Expand Down

0 comments on commit 5151563

Please sign in to comment.