diff --git a/src/commands/add.rs b/src/commands/add.rs index edba0d1..256238d 100644 --- a/src/commands/add.rs +++ b/src/commands/add.rs @@ -1,9 +1,10 @@ use std::env; use std::path::{Path, PathBuf}; use colored::Colorize; +use sha1::Digest; use crate::models::blob::Blob; use crate::models::index::{FileMetaData, Index}; -use crate::utils::util::{check_repo_exist, get_file_mode, get_relative_path, get_working_dir, list_files}; +use crate::utils::util::{check_repo_exist, get_relative_path, get_working_dir, list_files}; pub fn add(files: Vec, all: bool, mut update: bool) { check_repo_exist(); @@ -41,23 +42,21 @@ pub fn add(files: Vec, all: bool, mut update: bool) { for file in &files { add_a_file(file, &mut index); } + + index.save(); } fn add_a_file(file: &Path, index: &mut Index) { println!("add a file: {}", get_relative_path(file, get_working_dir().unwrap()).display()); if !file.exists() { //文件被删除 index.remove(file); - } else if !index.contains(file) { //文件未被跟踪 + } else { let blob = Blob::new(file); - let meta = file.metadata().unwrap(); - index.add(file.to_path_buf(), FileMetaData{ - hash: blob.get_hash(), - size: meta.len(), - created_time: meta.created().unwrap(), - modified_time: meta.modified().unwrap(), - mode: get_file_mode(file) - }); - } else { //文件已被跟踪,可能被修改 - + let file_data = FileMetaData::new(&blob, file); + if !index.contains(file) { //文件未被跟踪 + index.add(file.to_path_buf(), file_data); + } else { //文件已被跟踪,可能被修改 + index.update(file.to_path_buf(), file_data); + } } } \ No newline at end of file diff --git a/src/models/blob.rs b/src/models/blob.rs index c3fc7fc..4f23967 100644 --- a/src/models/blob.rs +++ b/src/models/blob.rs @@ -15,10 +15,13 @@ pub struct Blob { } impl Blob { + /// 从源文件新建blob对象,并直接保存到/objects/中 pub fn new(file: &Path) -> Blob { let data = fs::read_to_string(file).unwrap(); let hash = calc_hash(&data); - Blob { hash, data } + let blob = Blob { hash, data }; + blob.save(); + blob } pub fn load(hash: &String) -> Blob { @@ -32,7 +35,10 @@ impl Blob { pub fn save(&self) { let s = Store::new(); - s.save(&self.data); + if !s.contains(&self.hash) { + let hash = s.save(&self.data); + assert_eq!(hash, self.hash); + } } pub fn get_hash(&self) -> String { diff --git a/src/models/index.rs b/src/models/index.rs index 916d62a..57ccd4f 100644 --- a/src/models/index.rs +++ b/src/models/index.rs @@ -3,8 +3,9 @@ use std::fs; use std::path::{Path, PathBuf}; use std::time::SystemTime; use serde::{Deserialize, Serialize}; +use crate::models::blob::Blob; use crate::models::object::Hash; -use crate::utils::util::get_working_dir; +use crate::utils::util::{get_file_mode, get_working_dir}; // 文件元数据结构 #[derive(Serialize, Deserialize, Debug, Clone)] @@ -16,6 +17,19 @@ pub struct FileMetaData { pub mode: String, // 文件模式 } +impl FileMetaData { + pub fn new(blob: &Blob, file: &Path) -> FileMetaData { + let meta = file.metadata().unwrap(); + FileMetaData { + hash: blob.get_hash(), + size: meta.len(), + created_time: meta.created().unwrap(), + modified_time: meta.modified().unwrap(), + mode: get_file_mode(file) + } + } +} + // 索引数据结构 #[derive(Serialize, Deserialize, Debug, Default)] pub struct Index { @@ -69,12 +83,16 @@ impl Index { files } + pub fn update(&mut self, path: PathBuf, data: FileMetaData) { + self.entries.insert(path, data); + } + fn load(&mut self) { } /// 二进制序列化 - fn save(&self) { //要先转化为相对路径 + pub fn save(&self) { //要先转化为相对路径 let ser = serde_json::to_string(&self).unwrap(); println!("{}", ser); } @@ -97,8 +115,9 @@ mod tests { #[test] fn test_save(){ + util::setup_test_with_mit(); let mut index = Index::new(); - let metadata = fs::metadata(".gitignore").unwrap(); + let metadata = fs::metadata("../.gitignore").unwrap(); let file_meta_data = FileMetaData { hash: "123".to_string(), size: metadata.len(), diff --git a/src/store.rs b/src/store.rs index a0c4e66..8e3702f 100644 --- a/src/store.rs +++ b/src/store.rs @@ -24,6 +24,14 @@ impl Store { Err(_) => panic!("储存库疑似损坏,无法读取文件"), } } + + pub fn contains(&self, hash: &String) -> bool { + let mut path = self.store_path.clone(); + path.push("objects"); + path.push(hash); + path.exists() + } + pub fn save(&self, content: &String) -> String { /* 保存文件内容 */ println!("store_path: {:?}", self.store_path); @@ -41,7 +49,6 @@ impl Store { } #[cfg(test)] mod tests { - use super::*; #[test]