mirror of
https://github.com/MrBeanCpp/MIT.git
synced 2026-02-06 11:54:12 +08:00
基本实现restore命令
This commit is contained in:
@@ -24,6 +24,7 @@ pub fn add(files: Vec<String>, all: bool, mut update: bool) {
|
||||
let mut files: Vec<PathBuf> = files.into_iter().map(PathBuf::from).collect();
|
||||
|
||||
if dot || all || update {
|
||||
//TODO files中可能包含文件夹,需要统计文件夹中被删除的文件
|
||||
if all {
|
||||
// all 优先级最高
|
||||
dot = false;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::{fs, path::PathBuf};
|
||||
|
||||
use crate::utils::util::{get_absolute_path, list_files};
|
||||
use crate::models::index::FileMetaData;
|
||||
use crate::{
|
||||
head,
|
||||
models::{commit::Commit, index::Index, object::Hash},
|
||||
@@ -9,25 +9,14 @@ use crate::{
|
||||
utils::{util, util::get_working_dir},
|
||||
};
|
||||
|
||||
/** 根据filter restore workdir */
|
||||
pub fn restore_worktree(filter: Option<&Vec<PathBuf>>, target_blobs: &Vec<(PathBuf, Hash)>) {
|
||||
let paths: Vec<PathBuf> = if let Some(filter) = filter {
|
||||
filter.clone()
|
||||
} else {
|
||||
vec![get_working_dir().unwrap()] //None == all(workdir), '.' == cur_dir
|
||||
};
|
||||
|
||||
let target_blobs = target_blobs // 转为绝对路径 //TODO tree改变路径表示方式后,这里需要修改
|
||||
.iter()
|
||||
.map(|(path, hash)| (util::to_workdir_absolute_path(path), hash.clone()))
|
||||
.collect::<HashMap<PathBuf, Hash>>();
|
||||
|
||||
let dirs: Vec<PathBuf> = paths.iter().filter(|path| path.is_dir()).cloned().collect();
|
||||
let del_files = target_blobs //统计所有目录中(包括None & '.'),删除的文件
|
||||
/// 统计[工作区]中的dirs文件夹中,相对于target_blobs已删除的文件
|
||||
fn get_worktree_deleted_files_in_dirs(dirs: &Vec<PathBuf>, target_blobs: &HashMap<PathBuf, Hash>) -> HashSet<PathBuf> {
|
||||
target_blobs //统计所有目录中(包括None & '.'),删除的文件
|
||||
.iter()
|
||||
.filter(|(path, _)| {
|
||||
assert!(path.is_absolute()); //
|
||||
if !path.exists() {
|
||||
for dir in &dirs {
|
||||
for dir in dirs {
|
||||
if util::is_parent_dir(path, dir) {
|
||||
//需要包含在指定dir内
|
||||
return true;
|
||||
@@ -37,23 +26,76 @@ pub fn restore_worktree(filter: Option<&Vec<PathBuf>>, target_blobs: &Vec<(PathB
|
||||
false
|
||||
})
|
||||
.map(|(path, _)| path.clone())
|
||||
.collect::<HashSet<PathBuf>>(); //HashSet自动去重
|
||||
let mut paths = util::integrate_paths(&paths); //存在的文件路径
|
||||
paths.extend(del_files); //不存在的文件路径
|
||||
.collect() //HashSet自动去重
|
||||
}
|
||||
|
||||
/// 统计[暂存区index]中相对于target_blobs已删除的文件,且包含在指定dirs内
|
||||
fn get_index_deleted_files_in_dirs(
|
||||
index: &Index,
|
||||
dirs: &Vec<PathBuf>,
|
||||
target_blobs: &HashMap<PathBuf, Hash>,
|
||||
) -> HashSet<PathBuf> {
|
||||
target_blobs //统计index中相对target已删除的文件,且包含在指定dir内
|
||||
.iter()
|
||||
.filter(|(path, _)| {
|
||||
assert!(path.is_absolute()); //
|
||||
if !index.contains(path) {
|
||||
//index中不存在
|
||||
for dir in dirs {
|
||||
if util::is_parent_dir(path, dir) {
|
||||
//需要包含在指定dir内
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
})
|
||||
.map(|(path, _)| path.clone())
|
||||
.collect() //HashSet自动去重
|
||||
}
|
||||
|
||||
/// 将None转化为workdir
|
||||
fn preprocess_filters(filters: Option<&Vec<PathBuf>>) -> Vec<PathBuf> {
|
||||
if let Some(filter) = filters {
|
||||
filter.clone()
|
||||
} else {
|
||||
vec![get_working_dir().unwrap()] //None == all(workdir), '.' == cur_dir
|
||||
}
|
||||
}
|
||||
|
||||
/// 转化为绝对路径(to workdir)的HashMap
|
||||
fn preprocess_blobs(blobs: &Vec<(PathBuf, Hash)>) -> HashMap<PathBuf, Hash> {
|
||||
blobs // 转为绝对路径 //TODO tree改变路径表示方式后,这里需要修改
|
||||
.iter()
|
||||
.map(|(path, hash)| (util::to_workdir_absolute_path(path), hash.clone()))
|
||||
.collect() //to HashMap
|
||||
}
|
||||
|
||||
/** 根据filter restore workdir */
|
||||
pub fn restore_worktree(filter: Option<&Vec<PathBuf>>, target_blobs: &Vec<(PathBuf, Hash)>) {
|
||||
let paths = preprocess_filters(filter); //预处理filter 将None转化为workdir
|
||||
let target_blobs = preprocess_blobs(target_blobs); //预处理target_blobs 转化为绝对路径HashMap
|
||||
|
||||
let dirs = util::filter_dirs(&paths); //统计所有目录
|
||||
let deleted_files = get_worktree_deleted_files_in_dirs(&dirs, &target_blobs); //统计所有目录中已删除的文件
|
||||
|
||||
let mut file_paths = util::integrate_paths(&paths); //整合存在的文件(绝对路径)
|
||||
file_paths.extend(deleted_files); //已删除的文件
|
||||
|
||||
let index = Index::new();
|
||||
let store = Store::new();
|
||||
|
||||
for path in &paths {
|
||||
for path in &file_paths {
|
||||
assert!(path.is_absolute() && !path.is_dir()); // 绝对路径且不是目录
|
||||
if !path.exists() {
|
||||
//文件不存在于workdir
|
||||
if target_blobs.contains_key(path) {
|
||||
//文件存在于target_commit
|
||||
//文件存在于target_commit (deleted),需要恢复
|
||||
store.restore_to_file(&target_blobs[path], &path);
|
||||
} else {
|
||||
//在target_commit和workdir中都不存在(非法路径)
|
||||
println!("fatal: pathspec '{}' did not match any files", path.display());
|
||||
// println!("fatal: pathspec '{}' did not match any files", path.display());
|
||||
// TODO 如果是用户输入的路径,才应该报错,integrate_paths产生的不应该报错
|
||||
}
|
||||
} else {
|
||||
//文件存在,有两种情况:1.修改 2.新文件
|
||||
@@ -73,10 +115,44 @@ pub fn restore_worktree(filter: Option<&Vec<PathBuf>>, target_blobs: &Vec<(PathB
|
||||
}
|
||||
}
|
||||
}
|
||||
/** 根据filte restore staged */
|
||||
/** 根据filter restore staged */
|
||||
pub fn restore_index(filter: Option<&Vec<PathBuf>>, target_blobs: &Vec<(PathBuf, Hash)>) {
|
||||
// TODO 让@mrbeanc来写吧
|
||||
unimplemented!("TODO");
|
||||
let input_paths = preprocess_filters(filter); //预处理filter 将None转化为workdir
|
||||
let target_blobs = preprocess_blobs(target_blobs); //预处理target_blobs 转化为绝对路径HashMap
|
||||
|
||||
let mut index = Index::new();
|
||||
|
||||
let dirs = util::filter_dirs(&input_paths); //统计所有目录
|
||||
let deleted_files_index = get_index_deleted_files_in_dirs(&index, &dirs, &target_blobs); //统计所有目录中已删除的文件
|
||||
|
||||
let mut file_paths = util::integrate_paths(&input_paths); //整合存在的文件(绝对路径)
|
||||
file_paths.extend(deleted_files_index); //已删除的文件
|
||||
|
||||
for path in &file_paths {
|
||||
assert!(path.is_absolute() && !path.is_dir()); // 绝对路径且不是目录
|
||||
if !index.contains(path) {
|
||||
//文件不存在于index
|
||||
if target_blobs.contains_key(path) {
|
||||
//文件存在于target_commit (deleted),需要恢复
|
||||
index.add(path.clone(), FileMetaData { hash: target_blobs[path].clone(), ..Default::default() });
|
||||
} else {
|
||||
//在target_commit和index中都不存在(非法路径)
|
||||
// println!("fatal: pathspec '{}' did not match any files", path.display());
|
||||
// TODO 如果是用户输入的路径,才应该报错,integrate_paths产生的不应该报错
|
||||
}
|
||||
} else {
|
||||
//文件存在于index,有两种情况:1.修改 2.新文件
|
||||
if target_blobs.contains_key(path) {
|
||||
if !index.verify_hash(path, &target_blobs[path]) {
|
||||
//文件已修改(modified)
|
||||
index.update(path.clone(), FileMetaData { hash: target_blobs[path].clone(), ..Default::default() });
|
||||
}
|
||||
} else {
|
||||
//新文件 需要从index中删除
|
||||
index.remove(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
对于工作区中的新文件,若已跟踪,则删除;若未跟踪,则保留<br>
|
||||
|
||||
@@ -20,6 +20,18 @@ pub struct FileMetaData {
|
||||
pub mode: String, // 文件模式
|
||||
}
|
||||
|
||||
impl Default for FileMetaData {
|
||||
fn default() -> Self {
|
||||
FileMetaData {
|
||||
hash: Default::default(),
|
||||
size: Default::default(),
|
||||
created_time: SystemTime::now(), // 或者使用 UNIX_EPOCH
|
||||
modified_time: SystemTime::now(), // 或者使用 UNIX_EPOCH
|
||||
mode: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FileMetaData {
|
||||
pub fn new(blob: &Blob, file: &Path) -> FileMetaData {
|
||||
let meta = file.metadata().unwrap();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use sha1::{Digest, Sha1};
|
||||
use std::collections::HashSet;
|
||||
use std::{
|
||||
fs, io,
|
||||
io::Write,
|
||||
@@ -148,6 +149,7 @@ pub fn is_inside_dir(file: &Path, dir: &Path) -> bool {
|
||||
|
||||
/// 检测dir是否是file的父目录 (不论文件是否存在)
|
||||
pub fn is_parent_dir(file: &Path, dir: &Path) -> bool {
|
||||
assert!(dir.is_dir());
|
||||
let file = get_absolute_path(file);
|
||||
let dir = get_absolute_path(dir);
|
||||
file.starts_with(dir)
|
||||
@@ -168,6 +170,11 @@ pub fn format_time(time: &std::time::SystemTime) -> String {
|
||||
datetime.format("%Y-%m-%d %H:%M:%S.%3f").to_string()
|
||||
}
|
||||
|
||||
/// 过滤出路径数组中的目录
|
||||
pub fn filter_dirs(paths: &Vec<PathBuf>) -> Vec<PathBuf> {
|
||||
paths.iter().filter(|path| path.is_dir()).cloned().collect()
|
||||
}
|
||||
|
||||
/// 将路径中的分隔符统一为当前系统的分隔符
|
||||
fn unify_path_separator(path: &Path) -> PathBuf {
|
||||
#[cfg(windows)]
|
||||
@@ -315,9 +322,9 @@ pub fn get_absolute_path(path: &Path) -> PathBuf {
|
||||
abs_path
|
||||
}
|
||||
}
|
||||
/// 整理输入的路径数组(相对、绝对、文件、目录),返回一个绝对路径的文件数组
|
||||
pub fn integrate_paths(paths: &Vec<PathBuf>) -> Vec<PathBuf> {
|
||||
let mut abs_paths = Vec::new();
|
||||
/// 整理输入的路径数组(相对、绝对、文件、目录),返回一个绝对路径的文件数组(只包含exist)
|
||||
pub fn integrate_paths(paths: &Vec<PathBuf>) -> HashSet<PathBuf> {
|
||||
let mut abs_paths = HashSet::new();
|
||||
for path in paths {
|
||||
let path = get_absolute_path(&path); // 统一转换为绝对路径
|
||||
if path.is_dir() {
|
||||
@@ -325,11 +332,9 @@ pub fn integrate_paths(paths: &Vec<PathBuf>) -> Vec<PathBuf> {
|
||||
let files = list_files(&path).unwrap();
|
||||
abs_paths.extend(files);
|
||||
} else {
|
||||
abs_paths.push(path);
|
||||
abs_paths.insert(path);
|
||||
}
|
||||
}
|
||||
abs_paths.sort();
|
||||
abs_paths.dedup(); // 去重
|
||||
abs_paths
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user