mirror of
https://github.com/MrBeanCpp/MIT.git
synced 2026-04-26 03:42:17 +08:00
初步编写add逻辑;新增终端颜色库
This commit is contained in:
@@ -10,3 +10,6 @@ sha1 = "0.10.6"
|
|||||||
hex = "0.4.3"
|
hex = "0.4.3"
|
||||||
clap = { version = "4.4.11", features = ["derive"] }
|
clap = { version = "4.4.11", features = ["derive"] }
|
||||||
chrono = "0.4.31"
|
chrono = "0.4.31"
|
||||||
|
serde = { version = "1.0.193", features = ["derive"] }
|
||||||
|
serde_json = "1.0.108"
|
||||||
|
colored = "2.1.0"
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
|
use mit::commands::add::add;
|
||||||
use mit::commands::init::init;
|
use mit::commands::init::init;
|
||||||
|
|
||||||
/// Rust实现的简易版本的Git,用于学习Rust语言
|
/// Rust实现的简易版本的Git,用于学习Rust语言
|
||||||
@@ -52,11 +53,7 @@ pub fn handle_command() {
|
|||||||
let _ = init();
|
let _ = init();
|
||||||
}
|
}
|
||||||
Command::Add { files , all, update} => {
|
Command::Add { files , all, update} => {
|
||||||
if files.contains(&".".to_string()) || all {
|
add(files, all, update);
|
||||||
println!("add all files");
|
|
||||||
} else {
|
|
||||||
println!("add: {:?}, all:{:?}", files, all);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Command::Rm { files, cached } => {
|
Command::Rm { files, cached } => {
|
||||||
println!("rm: {:?}, cached= {}", files, cached);
|
println!("rm: {:?}, cached= {}", files, cached);
|
||||||
|
|||||||
45
src/commands/add.rs
Normal file
45
src/commands/add.rs
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
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};
|
||||||
|
|
||||||
|
pub fn add(files: Vec<String>, all: bool, mut update: bool) {
|
||||||
|
check_repo_exist();
|
||||||
|
let index = Index::new();
|
||||||
|
let mut dot = files.contains(&".".to_string());
|
||||||
|
|
||||||
|
let mut files: Vec<PathBuf> = files.into_iter().map(PathBuf::from).collect();
|
||||||
|
|
||||||
|
if dot || all || update{
|
||||||
|
if all { // all 优先级最高
|
||||||
|
dot = false;
|
||||||
|
update = false;
|
||||||
|
} else if update {
|
||||||
|
dot = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = if all || update {
|
||||||
|
println!("{}", "--all || --update 运行于工作区目录".bright_green());
|
||||||
|
get_working_dir().unwrap()
|
||||||
|
} else {
|
||||||
|
println!("{}", "'.'代表了当前目录".bright_green());
|
||||||
|
env::current_dir().unwrap()
|
||||||
|
};
|
||||||
|
println!("Working on [{}]\n", path.to_str().unwrap().bright_blue());
|
||||||
|
files = list_files(&*path).unwrap();
|
||||||
|
if update {
|
||||||
|
files.retain(|file|{
|
||||||
|
index.contains(file)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for file in files {
|
||||||
|
add_a_file(file.as_path(), &index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_a_file(file: &Path, index: &Index) {
|
||||||
|
println!("add a file: {:?}", file);
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
use std::{env, fs, io};
|
use std::{env, fs, io};
|
||||||
|
use crate::utils::util::ROOT_DIR;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
初始化mit仓库 创建.mit/objects .mit/refs/heads .mit/HEAD
|
初始化mit仓库 创建.mit/objects .mit/refs/heads .mit/HEAD
|
||||||
@@ -7,7 +8,7 @@ use std::{env, fs, io};
|
|||||||
*/
|
*/
|
||||||
pub fn init() -> io::Result<()> {
|
pub fn init() -> io::Result<()> {
|
||||||
let dir = env::current_dir()?;
|
let dir = env::current_dir()?;
|
||||||
let mit_dir = dir.join(".mit");
|
let mit_dir = dir.join(ROOT_DIR);
|
||||||
if mit_dir.exists() {
|
if mit_dir.exists() {
|
||||||
println!("!Already a mit repo - [{}]", dir.display());
|
println!("!Already a mit repo - [{}]", dir.display());
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
pub mod init;
|
pub mod init;
|
||||||
|
pub mod add;
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::PathBuf;
|
use std::fs;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use crate::models::object::Hash;
|
use crate::models::object::Hash;
|
||||||
|
|
||||||
// 文件元数据结构
|
// 文件元数据结构
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
struct FileMetaData {
|
pub struct FileMetaData {
|
||||||
hash: Hash, // SHA-1 哈希值
|
hash: Hash, // SHA-1 哈希值
|
||||||
size: u64, // 文件大小
|
size: u64, // 文件大小
|
||||||
created_time: SystemTime, // 创建时间
|
created_time: SystemTime, // 创建时间
|
||||||
@@ -14,11 +16,56 @@ struct FileMetaData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 索引数据结构
|
// 索引数据结构
|
||||||
#[derive(Debug, Default)]
|
#[derive(Serialize, Deserialize, Debug, Default)]
|
||||||
struct Index {
|
pub struct Index {
|
||||||
entries: HashMap<PathBuf, FileMetaData>,
|
entries: HashMap<PathBuf, FileMetaData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Index {
|
||||||
|
// 创建索引
|
||||||
|
pub(crate) fn new() -> Index {
|
||||||
|
let mut index = Index {
|
||||||
|
entries: HashMap::new(),
|
||||||
|
};
|
||||||
|
index.load();
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加文件
|
||||||
|
fn add(&mut self, path: PathBuf, data: FileMetaData) {
|
||||||
|
self.entries.insert(path, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除文件
|
||||||
|
fn remove(&mut self, path: PathBuf) {
|
||||||
|
self.entries.remove(&path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取文件元数据
|
||||||
|
fn get(&self, path: PathBuf) -> Option<&FileMetaData> {
|
||||||
|
self.entries.get(&path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取所有文件元数据
|
||||||
|
fn get_all(&self) -> &HashMap<PathBuf, FileMetaData> {
|
||||||
|
&self.entries
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn contains(&self, path: &Path) -> bool {
|
||||||
|
self.entries.contains_key(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load(&mut self) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 二进制序列化
|
||||||
|
fn save(&self) {
|
||||||
|
let ser = serde_json::to_string(&self).unwrap();
|
||||||
|
println!("{}", ser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
|
use std::{fs, io};
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
use sha1::{Digest, Sha1};
|
use sha1::{Digest, Sha1};
|
||||||
|
|
||||||
|
pub const ROOT_DIR: &str = ".mit";
|
||||||
|
|
||||||
pub fn calc_hash(data: &String) -> String {
|
pub fn calc_hash(data: &String) -> String {
|
||||||
let mut hasher = Sha1::new();
|
let mut hasher = Sha1::new();
|
||||||
hasher.update(data);
|
hasher.update(data);
|
||||||
@@ -16,6 +20,12 @@ pub fn storage_exist() -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn check_repo_exist() {
|
||||||
|
if !storage_exist() {
|
||||||
|
panic!("不是合法的mit仓库");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_storage_path() -> Result<String, std::io::Error> {
|
pub fn get_storage_path() -> Result<String, std::io::Error> {
|
||||||
/*递归获取储存库 */
|
/*递归获取储存库 */
|
||||||
let mut current_dir = std::env::current_dir()?;
|
let mut current_dir = std::env::current_dir()?;
|
||||||
@@ -34,11 +44,43 @@ pub fn get_storage_path() -> Result<String, std::io::Error> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 获取项目工作区目录, 也就是.mit的父目录
|
||||||
|
pub fn get_working_dir() -> Option<PathBuf> {
|
||||||
|
if let Some(path) = PathBuf::from(get_storage_path().unwrap()).parent() {
|
||||||
|
Some(path.to_path_buf())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn format_time(time: &std::time::SystemTime) -> String {
|
pub fn format_time(time: &std::time::SystemTime) -> String {
|
||||||
let datetime: chrono::DateTime<chrono::Utc> = time.clone().into();
|
let datetime: chrono::DateTime<chrono::Utc> = time.clone().into();
|
||||||
datetime.format("%Y-%m-%d %H:%M:%S.%3f").to_string()
|
datetime.format("%Y-%m-%d %H:%M:%S.%3f").to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 递归遍历给定目录及其子目录,列出所有文件,除了.mit
|
||||||
|
pub fn list_files(path: &Path) -> io::Result<Vec<PathBuf>> {
|
||||||
|
let mut files = Vec::new();
|
||||||
|
|
||||||
|
if path.is_dir() {
|
||||||
|
if path.file_name().unwrap_or_default() == ROOT_DIR { // 跳过 .mit 目录
|
||||||
|
return Ok(files);
|
||||||
|
}
|
||||||
|
for entry in fs::read_dir(path)? {
|
||||||
|
let entry = entry?;
|
||||||
|
let path = entry.path();
|
||||||
|
if path.is_dir() {
|
||||||
|
// 递归遍历子目录
|
||||||
|
files.extend(list_files(&path)?);
|
||||||
|
} else {
|
||||||
|
// 将文件的路径添加到列表中
|
||||||
|
files.push(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(files)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -61,4 +103,17 @@ mod tests {
|
|||||||
let formatted_time = format_time(&time);
|
let formatted_time = format_time(&time);
|
||||||
println!("{}", formatted_time);
|
println!("{}", formatted_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_list_files() {
|
||||||
|
let files = list_files(Path::new("F:\\Git-Test\\list-test"));
|
||||||
|
match files {
|
||||||
|
Ok(files) => {
|
||||||
|
for file in files {
|
||||||
|
println!("{}", file.display());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => println!("{}", err),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user