mirror of
https://github.com/MrBeanCpp/MIT.git
synced 2026-02-12 14:45:42 +08:00
临时提交:add & index & blob
This commit is contained in:
1
git-rs
1
git-rs
Submodule git-rs deleted from 5f3bb36574
@@ -1,12 +1,13 @@
|
||||
use std::env;
|
||||
use std::path::{Path, PathBuf};
|
||||
use colored::Colorize;
|
||||
use crate::models::index::Index;
|
||||
use crate::utils::util::{check_repo_exist, get_working_dir, list_files};
|
||||
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};
|
||||
|
||||
pub fn add(files: Vec<String>, all: bool, mut update: bool) {
|
||||
check_repo_exist();
|
||||
let index = Index::new();
|
||||
let mut index = Index::new();
|
||||
let mut dot = files.contains(&".".to_string());
|
||||
|
||||
let mut files: Vec<PathBuf> = files.into_iter().map(PathBuf::from).collect();
|
||||
@@ -33,13 +34,30 @@ pub fn add(files: Vec<String>, all: bool, mut update: bool) {
|
||||
index.contains(file)
|
||||
});
|
||||
}
|
||||
|
||||
files.extend(index.get_deleted_files()); //包含已删除的文件
|
||||
}
|
||||
|
||||
for file in files {
|
||||
add_a_file(file.as_path(), &index);
|
||||
for file in &files {
|
||||
add_a_file(file, &mut index);
|
||||
}
|
||||
}
|
||||
|
||||
fn add_a_file(file: &Path, index: &Index) {
|
||||
println!("add a file: {:?}", file);
|
||||
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) { //文件未被跟踪
|
||||
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 { //文件已被跟踪,可能被修改
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,25 @@
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use crate::models::object::Hash;
|
||||
/*Blob
|
||||
* Blob是git中最基本的对象,他储存一份文件的内容,并使用hash作为标识符。
|
||||
use crate::utils::util::calc_hash;
|
||||
|
||||
/**
|
||||
Blob
|
||||
Blob是git中最基本的对象,他储存一份文件的内容,并使用hash作为标识符。
|
||||
*/
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Blob {
|
||||
hash: Hash,
|
||||
data: String,
|
||||
}
|
||||
|
||||
impl Blob {
|
||||
pub fn new(file: &Path) -> Blob {
|
||||
let data = fs::read_to_string(file).unwrap();
|
||||
let hash = calc_hash(&data);
|
||||
Blob { hash, data }
|
||||
}
|
||||
pub fn get_hash(&self) -> String {
|
||||
self.hash.clone()
|
||||
}
|
||||
}
|
||||
@@ -4,21 +4,23 @@ use std::path::{Path, PathBuf};
|
||||
use std::time::SystemTime;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use crate::models::object::Hash;
|
||||
use crate::utils::util::get_working_dir;
|
||||
|
||||
// 文件元数据结构
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct FileMetaData {
|
||||
hash: Hash, // SHA-1 哈希值
|
||||
size: u64, // 文件大小
|
||||
created_time: SystemTime, // 创建时间
|
||||
modified_time: SystemTime, // 修改时间
|
||||
mode: String, // 文件模式
|
||||
pub hash: Hash, // SHA-1 哈希值
|
||||
pub size: u64, // 文件大小
|
||||
pub created_time: SystemTime, // 创建时间
|
||||
pub modified_time: SystemTime, // 修改时间
|
||||
pub mode: String, // 文件模式
|
||||
}
|
||||
|
||||
// 索引数据结构
|
||||
#[derive(Serialize, Deserialize, Debug, Default)]
|
||||
pub struct Index {
|
||||
entries: HashMap<PathBuf, FileMetaData>,
|
||||
working_dir: PathBuf,
|
||||
}
|
||||
|
||||
impl Index {
|
||||
@@ -26,19 +28,20 @@ impl Index {
|
||||
pub(crate) fn new() -> Index {
|
||||
let mut index = Index {
|
||||
entries: HashMap::new(),
|
||||
working_dir: get_working_dir().unwrap()
|
||||
};
|
||||
index.load();
|
||||
return index;
|
||||
}
|
||||
|
||||
// 添加文件
|
||||
fn add(&mut self, path: PathBuf, data: FileMetaData) {
|
||||
pub fn add(&mut self, path: PathBuf, data: FileMetaData) {
|
||||
self.entries.insert(path, data);
|
||||
}
|
||||
|
||||
// 删除文件
|
||||
fn remove(&mut self, path: PathBuf) {
|
||||
self.entries.remove(&path);
|
||||
pub fn remove(&mut self, path: &Path) {
|
||||
self.entries.remove(path);
|
||||
}
|
||||
|
||||
// 获取文件元数据
|
||||
@@ -55,12 +58,23 @@ impl Index {
|
||||
self.entries.contains_key(path)
|
||||
}
|
||||
|
||||
/// 获取所有已删除的文件
|
||||
pub fn get_deleted_files(&self) -> Vec<PathBuf> {
|
||||
let mut files = Vec::new();
|
||||
self.entries.keys().for_each(|file| {
|
||||
if !file.exists() {
|
||||
files.push(file.clone());
|
||||
}
|
||||
});
|
||||
files
|
||||
}
|
||||
|
||||
fn load(&mut self) {
|
||||
|
||||
}
|
||||
|
||||
/// 二进制序列化
|
||||
fn save(&self) {
|
||||
fn save(&self) { //要先转化为相对路径
|
||||
let ser = serde_json::to_string(&self).unwrap();
|
||||
println!("{}", ser);
|
||||
}
|
||||
|
||||
@@ -26,18 +26,18 @@ pub fn check_repo_exist() {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_storage_path() -> Result<PathBuf, std::io::Error> {
|
||||
pub fn get_storage_path() -> Result<PathBuf, io::Error> {
|
||||
/*递归获取储存库 */
|
||||
let mut current_dir = std::env::current_dir()?;
|
||||
loop {
|
||||
let mut git_path = current_dir.clone();
|
||||
git_path.push(ROOT_DIR);
|
||||
if git_path.exists() {
|
||||
return Ok(git_path);
|
||||
return Ok(git_path);
|
||||
}
|
||||
if !current_dir.pop() {
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::NotFound,
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::NotFound,
|
||||
"Not a git repository",
|
||||
));
|
||||
}
|
||||
@@ -46,7 +46,7 @@ pub fn get_storage_path() -> Result<PathBuf, std::io::Error> {
|
||||
|
||||
/// 获取项目工作区目录, 也就是.mit的父目录
|
||||
pub fn get_working_dir() -> Option<PathBuf> {
|
||||
if let Some(path) = PathBuf::from(get_storage_path().unwrap()).parent() {
|
||||
if let Some(path) = get_storage_path().unwrap().parent() {
|
||||
Some(path.to_path_buf())
|
||||
} else {
|
||||
None
|
||||
@@ -81,6 +81,38 @@ pub fn list_files(path: &Path) -> io::Result<Vec<PathBuf>> {
|
||||
Ok(files)
|
||||
}
|
||||
|
||||
pub fn get_relative_path(path: &Path, dir: PathBuf) -> PathBuf {
|
||||
let relative_path = path.strip_prefix(dir).unwrap();
|
||||
relative_path.to_path_buf()
|
||||
}
|
||||
|
||||
fn is_executable(path: &str) -> bool {
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
fs::metadata(path)
|
||||
.map(|metadata| metadata.permissions().mode() & 0o111 != 0)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let path = Path::new(path);
|
||||
match path.extension().and_then(|s| s.to_str()) {
|
||||
Some(ext) => ext.eq_ignore_ascii_case("exe") || ext.eq_ignore_ascii_case("bat"),
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_file_mode(path: &Path) -> String {
|
||||
if is_executable(path.to_str().unwrap()) {
|
||||
"100755".to_string()
|
||||
} else {
|
||||
"100644".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
Reference in New Issue
Block a user