feat: adding commit, show commands
This commit is contained in:
parent
49ed740014
commit
62af81b28f
106
src/commit.rs
Normal file
106
src/commit.rs
Normal file
@ -0,0 +1,106 @@
|
||||
use std::fs::{read_to_string, File};
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use hex::FromHex;
|
||||
|
||||
use crate::{kind::Kind, repository::Repository};
|
||||
|
||||
impl Repository {
|
||||
pub fn read_head(&self) -> Result<String> {
|
||||
let head_path = self.path.join(".git").join("HEAD");
|
||||
read_to_string(head_path).context("reading head")
|
||||
}
|
||||
|
||||
pub fn current_branch(&self) -> Result<String> {
|
||||
let head = self.read_head()?;
|
||||
Ok(head
|
||||
.trim_start_matches("ref: refs/heads/")
|
||||
.trim_end()
|
||||
.to_string())
|
||||
}
|
||||
|
||||
pub fn current_commit(&self) -> Result<[u8; 20]> {
|
||||
let current_branch = self.current_branch()?;
|
||||
let branch_path = self
|
||||
.path
|
||||
.join(".git")
|
||||
.join("refs")
|
||||
.join("heads")
|
||||
.join(¤t_branch);
|
||||
|
||||
let r = read_to_string(branch_path).context("could not read current branch")?;
|
||||
let r = r.trim();
|
||||
|
||||
Ok(<[u8; 20]>::from_hex(r)?)
|
||||
}
|
||||
|
||||
pub fn has_current_commit(&self) -> bool {
|
||||
self.current_commit().is_ok()
|
||||
}
|
||||
|
||||
pub fn set_current_commit(&self, hash: &[u8; 20]) -> Result<()> {
|
||||
let current_branch = self
|
||||
.current_branch()
|
||||
.context("could not find current branch")?;
|
||||
|
||||
let branch_path = self.path.join(".git").join("refs").join("heads");
|
||||
|
||||
if !branch_path.exists() {
|
||||
std::fs::create_dir_all(&branch_path)?;
|
||||
}
|
||||
|
||||
let branch_path = branch_path.join(¤t_branch);
|
||||
|
||||
// file does not exist
|
||||
if !branch_path.exists() {
|
||||
File::create(&branch_path)?;
|
||||
}
|
||||
|
||||
std::fs::write(branch_path, hex::encode(hash))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn commit(&self, message: &str) -> Result<[u8; 20]> {
|
||||
let has_current_commit = self.has_current_commit();
|
||||
let mut out: Vec<u8> = Vec::new();
|
||||
|
||||
let tree_hash = self
|
||||
.write_tree(&self.path)
|
||||
.context("could not write_tree")?;
|
||||
out.extend_from_slice(b"tree ");
|
||||
out.extend_from_slice(hex::encode(tree_hash).as_bytes());
|
||||
out.push(b'\n');
|
||||
|
||||
if has_current_commit {
|
||||
let current_commit_id = self.current_commit()?;
|
||||
out.extend_from_slice(b"parent ");
|
||||
out.extend_from_slice(hex::encode(current_commit_id).as_bytes());
|
||||
out.push(b'\n');
|
||||
}
|
||||
|
||||
out.push(b'\n');
|
||||
out.extend_from_slice(message.as_bytes());
|
||||
out.push(b'\n');
|
||||
|
||||
let hash = self.write_object(Kind::Commit, &out).context("Write")?;
|
||||
|
||||
// update current branch's commit id
|
||||
self.set_current_commit(&hash)?;
|
||||
|
||||
Ok(hash)
|
||||
}
|
||||
|
||||
pub fn show(&self, hash: Option<String>) -> Result<()> {
|
||||
let mut commit = if let Some(hash) = hash {
|
||||
self.read_object(&hash)?
|
||||
} else {
|
||||
let current_commit = self.current_commit()?;
|
||||
self.read_object(&hex::encode(current_commit))?
|
||||
};
|
||||
|
||||
println!("{}", commit.string()?);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
25
src/main.rs
25
src/main.rs
@ -5,6 +5,7 @@ use std::path::PathBuf;
|
||||
use clap::Parser;
|
||||
use clap::Subcommand;
|
||||
|
||||
mod commit;
|
||||
mod error;
|
||||
mod kind;
|
||||
mod object;
|
||||
@ -43,6 +44,18 @@ enum Command {
|
||||
/// The path to write
|
||||
path: PathBuf,
|
||||
},
|
||||
/// Commit current changes
|
||||
Commit {
|
||||
/// The commit message
|
||||
message: String,
|
||||
},
|
||||
/// Get the current branch
|
||||
Branch,
|
||||
/// Get the latest commit
|
||||
Show {
|
||||
/// The commit to show
|
||||
hash: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Error> {
|
||||
@ -67,6 +80,18 @@ fn main() -> Result<(), Error> {
|
||||
Ok(hash) => println!("{}", hex::encode(hash)),
|
||||
Err(e) => eprintln!("Failed to write tree: {}", e),
|
||||
},
|
||||
Command::Commit { message } => match repo.commit(&message) {
|
||||
Ok(hash) => println!("{}", hex::encode(hash)),
|
||||
Err(e) => eprintln!("Failed to commit: {}", e),
|
||||
},
|
||||
Command::Branch => match repo.current_branch() {
|
||||
Ok(branch) => println!("{}", branch),
|
||||
Err(e) => eprintln!("Failed to get branch: {}", e),
|
||||
},
|
||||
Command::Show { hash } => match repo.show(hash) {
|
||||
Ok(_) => (),
|
||||
Err(e) => eprintln!("Failed to show: {}", e),
|
||||
},
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -77,7 +77,7 @@ impl Repository {
|
||||
|
||||
let content = std::fs::read(file)?;
|
||||
|
||||
Ok(self.write_object(Kind::Blob(false), &content)?)
|
||||
self.write_object(Kind::Blob(false), &content)
|
||||
}
|
||||
|
||||
pub fn write_object(&self, kind: Kind, content: &[u8]) -> Result<[u8; 20]> {
|
||||
@ -102,7 +102,7 @@ impl Repository {
|
||||
let mut zlib_out = ZlibEncoder::new(file_out_fd, Compression::default());
|
||||
write!(zlib_out, "{} {}\0", kind.string(), content.len())
|
||||
.context("could not write header")?;
|
||||
zlib_out.write(content)?;
|
||||
zlib_out.write_all(content)?;
|
||||
zlib_out
|
||||
.finish()
|
||||
.context("could not compress or write file")?;
|
||||
|
@ -2,7 +2,7 @@ use anyhow::Result;
|
||||
use std::{
|
||||
env,
|
||||
fs::{create_dir, read_to_string},
|
||||
path::PathBuf,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
pub struct Repository {
|
||||
@ -42,8 +42,8 @@ impl Repository {
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
pub fn init_repository(&mut self, path: &PathBuf) -> Result<PathBuf> {
|
||||
self.path = path.clone();
|
||||
pub fn init_repository(&mut self, path: &Path) -> Result<PathBuf> {
|
||||
self.path = path.to_path_buf();
|
||||
let git_dir = self.path.join(".git");
|
||||
|
||||
create_dir(&git_dir)?;
|
||||
|
Loading…
x
Reference in New Issue
Block a user