mirror of
https://github.com/MrBeanCpp/MIT.git
synced 2026-07-05 02:36:04 +08:00
修改Blob逻辑,主要变更为 Blob 与 objects文件解构。store作为与objects文件交互的唯一依赖。具体为:
1. Blob使用Content新建而不是path 2. workdir的读写能力由util::read|write workfile提供 3. 判断文件是否更改不直接计算hash,经由新建一个不保存的Blob进行。现在Hash算法只由Store决定。
This commit is contained in:
@@ -2,11 +2,7 @@ use base64::Engine;
|
||||
use flate2::{read::GzDecoder, write::GzEncoder, Compression};
|
||||
use std::io::{Read, Write};
|
||||
|
||||
use crate::{
|
||||
models::Hash,
|
||||
utils::{store, util},
|
||||
};
|
||||
use std::{fs, path::Path};
|
||||
use crate::{models::Hash, utils::store};
|
||||
|
||||
/**Blob<br>
|
||||
git中最基本的对象,他储存一份文件的内容,并使用hash作为标识符。
|
||||
@@ -19,31 +15,46 @@ pub struct Blob {
|
||||
|
||||
impl Blob {
|
||||
/// 从源文件新建blob对象,并直接保存到/objects/中
|
||||
pub fn new(file: &Path) -> Blob {
|
||||
let data = fs::read_to_string(file).expect(format!("无法读取文件:{:?}", file).as_str());
|
||||
pub fn new(data: String) -> Blob {
|
||||
let mut blob = Blob { hash: "".to_string(), data };
|
||||
blob.save();
|
||||
blob
|
||||
}
|
||||
|
||||
pub fn load(hash: &String) -> Blob {
|
||||
/// 从源文件新建blob对象,但不保存到/objects/中
|
||||
pub fn dry_new(data: String) -> Blob {
|
||||
let mut blob = Blob { hash: "".to_string(), data };
|
||||
let s = store::Store::new();
|
||||
let encoded = s.load(hash);
|
||||
let hash: String = s.dry_save(&Blob::encode(blob.data.clone()));
|
||||
blob.hash = hash;
|
||||
blob
|
||||
}
|
||||
|
||||
fn encode(data: String) -> String {
|
||||
let mut cmopress_encoder = GzEncoder::new(Vec::new(), Compression::default());
|
||||
cmopress_encoder.write_all(data.as_bytes()).unwrap();
|
||||
let compressed_data = cmopress_encoder.finish().unwrap();
|
||||
base64::engine::general_purpose::STANDARD_NO_PAD.encode(&compressed_data)
|
||||
}
|
||||
fn decode(encoded: String) -> String {
|
||||
let compressed_data = base64::engine::general_purpose::STANDARD_NO_PAD.decode(&encoded).unwrap();
|
||||
let mut decompress_decoder = GzDecoder::new(&compressed_data[..]);
|
||||
let mut data = String::new();
|
||||
decompress_decoder.read_to_string(&mut data).unwrap();
|
||||
data
|
||||
}
|
||||
|
||||
pub fn load(hash: &String) -> Blob {
|
||||
let s = store::Store::new();
|
||||
let encoded_data = s.load(hash);
|
||||
let data = Blob::decode(encoded_data);
|
||||
Blob { hash: hash.clone(), data }
|
||||
}
|
||||
|
||||
/// 写入文件
|
||||
pub fn save(&mut self) -> Hash {
|
||||
let s = store::Store::new();
|
||||
let mut cmopress_encoder = GzEncoder::new(Vec::new(), Compression::default());
|
||||
cmopress_encoder.write_all(self.data.as_bytes()).unwrap();
|
||||
let compressed_data = cmopress_encoder.finish().unwrap();
|
||||
let encoded_data = base64::engine::general_purpose::STANDARD_NO_PAD.encode(&compressed_data);
|
||||
let hash: String = s.save(&encoded_data);
|
||||
let hash: String = s.save(&Blob::encode(self.data.clone()));
|
||||
self.hash = hash;
|
||||
self.hash.clone()
|
||||
}
|
||||
@@ -51,20 +62,21 @@ impl Blob {
|
||||
pub fn get_hash(&self) -> String {
|
||||
self.hash.clone()
|
||||
}
|
||||
|
||||
pub fn get_content(&self) -> String {
|
||||
self.data.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::utils::test_util;
|
||||
|
||||
#[test]
|
||||
fn test_save_and_load() {
|
||||
test_util::setup_test_with_clean_mit();
|
||||
let test_data = "hello world";
|
||||
test_util::ensure_test_file(&PathBuf::from("a.txt"), Some(test_data));
|
||||
let blob = super::Blob::new(&PathBuf::from("a.txt"));
|
||||
let blob = super::Blob::new(test_data.into());
|
||||
|
||||
let blob2 = super::Blob::load(&blob.hash);
|
||||
assert_eq!(blob2.get_hash(), blob.get_hash());
|
||||
|
||||
@@ -233,12 +233,12 @@ mod tests {
|
||||
test_util::setup_test_with_clean_mit();
|
||||
let index = Index::get_instance();
|
||||
let path = PathBuf::from("../mit_test_storage/.mit/HEAD"); //测试../相对路径的处理
|
||||
index.add(path.clone(), FileMetaData::new(&Blob::new(&path), &path));
|
||||
index.add(path.clone(), FileMetaData::new(&Blob::new(util::read_workfile(&path)), &path));
|
||||
|
||||
let 中文路径 = "中文路径.txt";
|
||||
test_util::ensure_test_file(Path::new(中文路径), None);
|
||||
let path = PathBuf::from(中文路径);
|
||||
index.add(path.clone(), FileMetaData::new(&Blob::new(&path), &path));
|
||||
index.add(path.clone(), FileMetaData::new(&Blob::new(util::read_workfile(&path)), &path));
|
||||
index.save();
|
||||
println!("{:?}", index.entries);
|
||||
}
|
||||
@@ -248,7 +248,7 @@ mod tests {
|
||||
test_util::setup_test_with_empty_workdir();
|
||||
let index = Index::get_instance();
|
||||
let path = PathBuf::from(".mit/HEAD");
|
||||
index.add(path.clone(), FileMetaData::new(&Blob::new(&path), &path));
|
||||
index.add(path.clone(), FileMetaData::new(&Blob::new(util::read_workfile(&path)), &path));
|
||||
assert!(Index::new().is_empty()); //未保存前,新读取的index应该是空的
|
||||
index.save();
|
||||
assert!(!Index::new().is_empty()); //保存后,新读取的index不是空的
|
||||
|
||||
@@ -137,7 +137,7 @@ mod test {
|
||||
|
||||
use crate::{
|
||||
models::*,
|
||||
utils::test_util,
|
||||
utils::{test_util, util},
|
||||
};
|
||||
|
||||
#[test]
|
||||
@@ -147,8 +147,7 @@ mod test {
|
||||
for test_file in vec!["b.txt", "mit_src/a.txt", "test/test.txt"] {
|
||||
let test_file = PathBuf::from(test_file);
|
||||
test_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));
|
||||
index.add(test_file.clone(), FileMetaData::new(&Blob::new(util::read_workfile(&test_file)), &test_file));
|
||||
}
|
||||
|
||||
let tree = Tree::new(&index);
|
||||
@@ -164,7 +163,7 @@ mod test {
|
||||
for test_file in test_files.clone() {
|
||||
let test_file = PathBuf::from(test_file);
|
||||
test_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(util::read_workfile(&test_file)), &test_file));
|
||||
}
|
||||
|
||||
let tree = Tree::new(&index);
|
||||
@@ -185,9 +184,9 @@ mod test {
|
||||
for test_file in test_files.clone() {
|
||||
let test_file = PathBuf::from(test_file);
|
||||
test_util::ensure_test_file(&test_file, None);
|
||||
let blob = Blob::new(&test_file);
|
||||
let blob = Blob::new(util::read_workfile(&test_file));
|
||||
test_blobs.push(blob.clone());
|
||||
index.add(test_file.clone(), FileMetaData::new(&Blob::new(&test_file), &test_file));
|
||||
index.add(test_file.clone(), FileMetaData::new(&Blob::new(util::read_workfile(&test_file)), &test_file));
|
||||
}
|
||||
|
||||
let tree = Tree::new(&index);
|
||||
|
||||
Reference in New Issue
Block a user