mirror of
https://github.com/MrBeanCpp/MIT.git
synced 2026-02-10 05:35:17 +08:00
tree save&load
This commit is contained in:
@@ -17,7 +17,7 @@ pub struct Blob {
|
||||
impl Blob {
|
||||
/// 从源文件新建blob对象,并直接保存到/objects/中
|
||||
pub fn new(file: &Path) -> Blob {
|
||||
let data = fs::read_to_string(file).expect("无法读取文件");
|
||||
let data = fs::read_to_string(file).expect(format!("无法读取文件:{:?}", file).as_str());
|
||||
let hash = calc_hash(&data);
|
||||
let blob = Blob { hash, data };
|
||||
blob.save();
|
||||
|
||||
@@ -21,7 +21,7 @@ pub struct Commit {
|
||||
|
||||
impl Commit {
|
||||
pub fn new(index: &Index, parent: Vec<Hash>, message: String) -> Commit {
|
||||
let tree = Tree::new(index);
|
||||
let mut tree = Tree::new(index);
|
||||
let tree_hash = tree.save();
|
||||
Commit {
|
||||
hash: "".to_string(),
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::store;
|
||||
use crate::{store, utils::util};
|
||||
|
||||
use super::{index::Index, object::Hash};
|
||||
/*Tree
|
||||
@@ -21,14 +23,76 @@ pub struct Tree {
|
||||
pub entries: Vec<TreeEntry>,
|
||||
}
|
||||
|
||||
impl Tree {
|
||||
pub fn new(index: &Index) -> Tree {
|
||||
// XXX wait for index to be implemented
|
||||
Tree {
|
||||
hash: "".to_string(),
|
||||
entries: Vec::new(),
|
||||
/** 将文件列表保存为Tree Object,并返回最上层的Tree */
|
||||
fn store_path_to_tree(path_entries: &Vec<PathBuf>, current_root: PathBuf) -> Tree {
|
||||
let get_blob_entry = |path: &PathBuf| {
|
||||
let file_path = util::get_working_dir().unwrap().join(path);
|
||||
let blob = super::blob::Blob::new(&file_path.clone());
|
||||
let mode = util::get_file_mode(&path);
|
||||
let filename = path.file_name().unwrap().to_str().unwrap().to_string();
|
||||
let entry = TreeEntry {
|
||||
filemode: (String::from("blob"), mode),
|
||||
object_hash: blob.get_hash(),
|
||||
name: filename,
|
||||
};
|
||||
unimplemented!("Tree::new");
|
||||
entry
|
||||
};
|
||||
let mut tree = Tree {
|
||||
hash: "".to_string(),
|
||||
entries: Vec::new(),
|
||||
};
|
||||
let mut processed_path: HashMap<String, bool> = HashMap::new();
|
||||
for path in path_entries.iter() {
|
||||
// 判断是不是直接在根目录下
|
||||
let in_path = path.parent().unwrap() == current_root;
|
||||
// 一定是文件,不会是目录
|
||||
if in_path {
|
||||
let entry = get_blob_entry(path);
|
||||
tree.entries.push(entry);
|
||||
} else {
|
||||
if path.components().count() == 1 {
|
||||
continue;
|
||||
}
|
||||
// 拿到下一级别目录
|
||||
let process_path = path
|
||||
.components()
|
||||
.nth(0)
|
||||
.unwrap()
|
||||
.as_os_str()
|
||||
.to_str()
|
||||
.unwrap();
|
||||
if processed_path
|
||||
.insert(process_path.to_string(), true)
|
||||
.is_some()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
let sub_tree = store_path_to_tree(path_entries, process_path.into());
|
||||
let mode = util::get_file_mode(&util::get_working_dir().unwrap().join(process_path));
|
||||
tree.entries.push(TreeEntry {
|
||||
filemode: (String::from("tree"), mode),
|
||||
object_hash: sub_tree.get_hash(),
|
||||
name: process_path.to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
tree.save();
|
||||
tree
|
||||
}
|
||||
|
||||
impl Tree {
|
||||
pub fn get_hash(&self) -> String {
|
||||
self.hash.clone()
|
||||
}
|
||||
pub fn new(index: &Index) -> Tree {
|
||||
let file_entries: Vec<PathBuf> = index
|
||||
.get_tracked_files()
|
||||
.iter_mut()
|
||||
.map(|file| util::to_root_relative_path(file))
|
||||
.collect();
|
||||
|
||||
store_path_to_tree(&file_entries, "".to_string().into())
|
||||
}
|
||||
|
||||
pub fn load(hash: &String) -> Tree {
|
||||
@@ -39,10 +103,64 @@ impl Tree {
|
||||
tree
|
||||
}
|
||||
|
||||
pub fn save(&self) -> String {
|
||||
pub fn save(&mut self) -> String {
|
||||
let s = store::Store::new();
|
||||
let tree_data = serde_json::to_string_pretty(&self).unwrap();
|
||||
let hash = s.save(&tree_data);
|
||||
self.hash = hash.clone();
|
||||
hash
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::models::blob::Blob;
|
||||
use crate::models::index::FileMetaData;
|
||||
use crate::utils::util;
|
||||
#[test]
|
||||
fn test_new() {
|
||||
util::setup_test_with_clean_mit();
|
||||
let mut index = super::Index::new();
|
||||
for test_file in vec!["b.txt", "mit_src/a.txt"] {
|
||||
let test_file = PathBuf::from(test_file);
|
||||
util::ensure_test_file(&test_file, None);
|
||||
index.add(
|
||||
test_file.clone(),
|
||||
FileMetaData::new(&Blob::new(&test_file), &test_file),
|
||||
);
|
||||
index.add(
|
||||
test_file.clone(),
|
||||
FileMetaData::new(&Blob::new(&test_file), &test_file),
|
||||
);
|
||||
}
|
||||
|
||||
let tree = super::Tree::new(&index);
|
||||
assert!(tree.entries.len() == 2);
|
||||
assert!(tree.hash.len() != 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_load() {
|
||||
util::setup_test_with_clean_mit();
|
||||
let mut index = super::Index::new();
|
||||
let test_files = vec!["b.txt", "mit_src/a.txt"];
|
||||
for test_file in test_files.clone() {
|
||||
let test_file = PathBuf::from(test_file);
|
||||
util::ensure_test_file(&test_file, None);
|
||||
index.add(
|
||||
test_file.clone(),
|
||||
FileMetaData::new(&Blob::new(&test_file), &test_file),
|
||||
);
|
||||
}
|
||||
|
||||
let tree = super::Tree::new(&index);
|
||||
let tree_hash = tree.get_hash();
|
||||
|
||||
let loaded_tree = super::Tree::load(&tree_hash);
|
||||
assert!(loaded_tree.entries.len() == tree.entries.len());
|
||||
assert!(tree.entries[0].name == loaded_tree.entries[0].name);
|
||||
assert!(tree.entries[1].name == loaded_tree.entries[1].name);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user