use anyhow::{Result, bail}; use std::{ fs::File, io::{self, BufRead, prelude::*}, path::{Path, PathBuf}, }; use crate::GIT_DIR; pub mod gitignore; pub mod head; pub mod index; pub mod object; fn read_lines

(filename: P) -> Result>> where P: AsRef, { let file = File::open(filename)?; Ok(io::BufReader::new(file).lines()) } pub fn normalize_path_in_worktree(path: &Path) -> Result { let wt_root = get_worktree_root()?; let canon = path.canonicalize()?; let mut canon_it = canon.components(); for wt_c in wt_root.components() { if let Some(c) = canon_it.next() && wt_c == c { continue; } else { bail!( "'{}' is outside repository at '{}'", path.display(), wt_root.display() ); } } Ok(canon_it.as_path().to_path_buf()) } pub fn get_worktree_root() -> Result { let canon = Path::new(".").canonicalize()?; for ancestor in canon.ancestors() { let potential = ancestor.join(GIT_DIR); if potential.is_dir() { return Ok(ancestor.to_path_buf()); } } bail!("not a git repository (or any parent up to mount point)") } pub fn get_git_root() -> Result { Ok(get_worktree_root()?.join(GIT_DIR)) } pub struct Ref { ref_name: String, commit_hash: String, } impl Ref { pub fn load(name: String) -> Result { let path = get_git_root()?.join(&name); let mut lines = read_lines(path)?; let content = match lines.next() { Some(line) => line?, _ => bail!(""), }; Ok(Ref { ref_name: name, commit_hash: content, }) } pub fn save(&self) -> Result<()> { let path = get_git_root()?.join("refs").join(&self.ref_name); let mut file = File::create(&path)?; file.write_all(self.commit_hash.as_bytes())?; Ok(()) } }