57 lines
1.5 KiB
Rust
57 lines
1.5 KiB
Rust
use anyhow::{Context, Result};
|
|
use sha1::{Digest, Sha1};
|
|
use std::os::unix::fs::MetadataExt;
|
|
use std::path::PathBuf;
|
|
|
|
use crate::kind::Kind;
|
|
use crate::object::{hash_file, TreeObject};
|
|
|
|
pub fn write_tree(_repo_path: &PathBuf, path: &PathBuf) -> Result<[u8; 20]> {
|
|
let mut entries = Vec::new();
|
|
|
|
let files = std::fs::read_dir(path)?;
|
|
for file in files {
|
|
let file = file?;
|
|
let file_type = file.file_type()?;
|
|
let file_name = file.file_name();
|
|
let file_path = file.path();
|
|
|
|
let hash: [u8; 20];
|
|
let kind;
|
|
|
|
if file_type.is_dir() {
|
|
hash = write_tree(_repo_path, &file_path).context("could not write_tree of subtree")?;
|
|
kind = Kind::Tree;
|
|
} else {
|
|
hash = hash_file(&file_path)?;
|
|
kind = Kind::Blob(file_path.metadata()?.mode() & 0o111 != 0);
|
|
}
|
|
|
|
entries.push(TreeObject {
|
|
mode: kind.to_mode().to_string(),
|
|
kind,
|
|
name: file_name.into_string().unwrap(),
|
|
hash,
|
|
})
|
|
}
|
|
|
|
entries.sort_by(|a, b| a.name.cmp(&b.name));
|
|
|
|
let mut out: Vec<u8> = Vec::new();
|
|
for entry in &entries {
|
|
out.extend_from_slice(entry.mode.as_bytes());
|
|
out.push(b' ');
|
|
out.extend_from_slice(entry.name.as_bytes());
|
|
out.push(0);
|
|
out.extend_from_slice(&entry.hash);
|
|
}
|
|
|
|
let header = format!("tree {}\0", out.len());
|
|
|
|
let mut hasher = Sha1::new();
|
|
hasher.update(header);
|
|
hasher.update(out);
|
|
|
|
Ok(hasher.finalize().into())
|
|
}
|