为Blob增加压缩支持,IO优化放置到Store中

This commit is contained in:
HouXiaoxuan
2023-12-28 22:02:02 +08:00
parent cdc289b3bb
commit b3aea1d0d1
4 changed files with 51 additions and 69 deletions

View File

@@ -1,3 +1,7 @@
use base64::Engine;
use flate2::{read::GzDecoder, write::GzEncoder, Compression};
use std::io::{Read, Write};
use crate::{
models::Hash,
utils::{store, util},
@@ -17,28 +21,53 @@ impl Blob {
/// 从源文件新建blob对象并直接保存到/objects/中
pub fn new(file: &Path) -> Blob {
let data = fs::read_to_string(file).expect(format!("无法读取文件:{:?}", file).as_str());
let hash = util::calc_hash(&data);
let blob = Blob { hash, data };
let mut blob = Blob { hash: "".to_string(), data };
blob.save();
blob
}
pub fn load(hash: &String) -> Blob {
let s = store::Store::new();
let data = s.load(hash);
let encoded = s.load(hash);
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();
Blob { hash: hash.clone(), data }
}
/// 写入文件;优化:文件已存在时不做操作
pub fn save(&self) {
/// 写入文件
pub fn save(&mut self) -> Hash {
let s = store::Store::new();
if !s.contains(&self.hash) {
let hash = s.save(&self.data);
assert_eq!(hash, self.hash);
}
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);
self.hash = hash;
self.hash.clone()
}
pub fn get_hash(&self) -> String {
self.hash.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 blob2 = super::Blob::load(&blob.hash);
assert_eq!(blob2.get_hash(), blob.get_hash());
assert_eq!(blob2.data, test_data);
}
}

View File

@@ -99,7 +99,7 @@ impl Tree {
tree
}
pub fn save(&mut self) -> String {
pub fn save(&mut self) -> Hash {
let s = store::Store::new();
let tree_data = serde_json::to_string_pretty(&self).unwrap();
let hash = s.save(&tree_data);
@@ -107,28 +107,6 @@ impl Tree {
hash
}
/**递归获取Tree对应的所有文件 */
pub fn get_recursive_file_entries(&self) -> Vec<PathBuf> {
let mut files = Vec::new();
for entry in self.entries.iter() {
if entry.filemode.0 == "blob" {
files.push(PathBuf::from(entry.name.clone()));
} else {
let sub_tree = Tree::load(&entry.object_hash);
let sub_files = sub_tree.get_recursive_file_entries();
files.append(
sub_files
.iter()
.map(|file| PathBuf::from(entry.name.clone()).join(file))
.collect::<Vec<PathBuf>>()
.as_mut(),
);
}
}
files
}
///注:相对路径(to workdir)
pub fn get_recursive_blobs(&self) -> Vec<(PathBuf, Hash)> {
//TODO 返回HashMap
@@ -159,7 +137,7 @@ mod test {
use crate::{
models::*,
utils::{util, test_util},
utils::test_util,
};
#[test]
@@ -198,34 +176,6 @@ mod test {
assert!(tree.entries[1].name == loaded_tree.entries[1].name);
}
#[test]
fn test_get_recursive_file_entries() {
test_util::setup_test_with_clean_mit();
let index = Index::get_instance();
let mut test_files = vec![PathBuf::from("b.txt"), PathBuf::from("mit_src/a.txt")];
for test_file in test_files.clone() {
test_util::ensure_test_file(&test_file, None);
index.add(test_file.clone(), FileMetaData::new(&Blob::new(&test_file), &test_file));
}
let tree = Tree::new(&index);
let tree_hash = tree.get_hash();
let loaded_tree = Tree::load(&tree_hash);
let mut files = loaded_tree.get_recursive_file_entries();
files.sort();
test_files.sort();
assert_eq!(files.len(), test_files.len());
assert_eq!(
util::to_workdir_absolute_path(&files[0]).to_str().unwrap(), //TODO 罪大恶极的路径问题
util::get_absolute_path(&test_files[0]).to_str().unwrap()
);
assert_eq!(
util::to_workdir_absolute_path(&files[1]).to_str().unwrap(),
util::get_absolute_path(&test_files[1]).to_str().unwrap()
);
}
#[test]
fn test_get_recursive_blobs() {
test_util::setup_test_with_clean_mit();