fix: status命令对当前目录进行过滤 & 改进util泛型模板

This commit is contained in:
mrbeanc
2023-12-24 11:46:07 +08:00
parent 3272b793da
commit 07dfd24d32
4 changed files with 87 additions and 20 deletions

View File

@@ -119,7 +119,7 @@ pub fn restore_index(filter: Option<&Vec<PathBuf>>, target_blobs: &Vec<(PathBuf,
let deleted_files_index = get_index_deleted_files_in_filters(&index, &input_paths, &target_blobs); //统计所有目录中已删除的文件
//1.获取index中包含于input_path的文件使用paths进行过滤
let mut file_paths = util::filter_to_fit_paths(&index.get_tracked_files(), &input_paths);
let mut file_paths: HashSet<PathBuf> = util::filter_to_fit_paths(&index.get_tracked_files(), &input_paths);
// 2.补充index中已删除的文件相较于target_blobs
file_paths.extend(deleted_files_index); //已删除的文件

View File

@@ -5,12 +5,13 @@ use crate::{
utils::{util, util::check_repo_exist},
};
use colored::Colorize;
use std::env;
use std::path::PathBuf;
/** 获取需要commit的更改(staged)
注:相对路径
注:相对路径(to workdir)
*/
#[derive(Debug, Default)]
#[derive(Debug, Default, Clone)]
pub struct Changes {
pub new: Vec<PathBuf>,
pub modified: Vec<PathBuf>,
@@ -21,8 +22,53 @@ impl Changes {
pub fn is_empty(&self) -> bool {
self.new.is_empty() && self.modified.is_empty() && self.deleted.is_empty()
}
/// 使用paths过滤返回绝对路径
pub fn filter_abs(&self, paths: &Vec<PathBuf>) -> Changes {
let mut change = Changes::default();
let abs_self = self.to_absolute(); //先要转换为绝对路径
change.new = util::filter_to_fit_paths(&abs_self.new, paths);
change.modified = util::filter_to_fit_paths(&abs_self.modified, paths);
change.deleted = util::filter_to_fit_paths(&abs_self.deleted, paths);
change
}
/// 使用paths过滤返回相对路径(to cur_dir)
pub fn filter_relative(&self, paths: &Vec<PathBuf>) -> Changes {
self.filter_abs(paths).to_relative()
}
/// 转换为绝对路径from workdir相对路径
pub fn to_absolute(&self) -> Changes {
let mut change = self.clone();
// change.new = util::map(&self.new, |p| util::to_workdir_absolute_path(p));
// change.modified = util::map(&self.modified, |p| util::to_workdir_absolute_path(p));
// change.deleted = util::map(&self.deleted, |p| util::to_workdir_absolute_path(p));
//离谱子
[&mut change.new, &mut change.modified, &mut change.deleted]
.iter_mut()
.for_each(|paths| {
**paths = util::map(&**paths, |p| util::to_workdir_absolute_path(p));
});
change
}
/// 转换为相对路径to cur_dir注意要先转换为绝对路径
fn to_relative(&self) -> Changes {
let mut change = self.clone();
let cur_dir = util::cur_dir();
[&mut change.new, &mut change.modified, &mut change.deleted]
.iter_mut()
.for_each(|paths| {
**paths = util::map(&**paths, |p| util::get_relative_path(p, &cur_dir));
});
change
}
}
/** 比较暂存区与HEAD(最后一次Commit::Tree)的差异
注:相对路径(to workdir)
*/
pub fn changes_to_be_committed() -> Changes {
let mut change = Changes::default();
let index = Index::new();
@@ -63,11 +109,11 @@ pub fn changes_to_be_committed() -> Changes {
change
}
/// 比较工作区与暂存区的差异,返回相对路径(to workdir),不筛选
pub fn changes_to_be_staged() -> Changes {
let mut change = Changes::default();
let index = Index::new();
for file in index.get_tracked_files() {
//TODO 考虑当前目录
if !file.exists() {
change.deleted.push(util::to_workdir_relative_path(&file));
} else if index.is_modified(&file) {
@@ -77,14 +123,13 @@ pub fn changes_to_be_staged() -> Changes {
}
}
}
let files = util::list_workdir_files(); //TODO 考虑当前目录
let files = util::list_workdir_files(); // all the files
for file in files {
if !index.tracked(&file) {
//文件未被跟踪
change.new.push(util::to_workdir_relative_path(&file));
}
}
change
}
@@ -104,8 +149,9 @@ pub fn status() {
}
}
let staged = changes_to_be_committed();
let unstaged = changes_to_be_staged();
// 对当前目录进行过滤 & 转换为相对路径
let staged = changes_to_be_committed().filter_relative(&vec![util::cur_dir()]);
let unstaged = changes_to_be_staged().filter_relative(&vec![util::cur_dir()]);
if staged.is_empty() && unstaged.is_empty() {
println!("nothing to commit, working tree clean");
return;
@@ -172,7 +218,7 @@ mod tests {
assert_eq!(change.modified.len(), 0);
assert_eq!(change.deleted.len(), 0);
println!("{:?}", change);
println!("{:?}", change.to_absolute());
commit::commit("test commit".to_string(), true);
util::ensure_test_file(Path::new(test_file), Some("new content"));

View File

@@ -1,7 +1,4 @@
use std::{
collections::{HashMap, HashSet},
path::PathBuf,
};
use std::{collections::HashSet, path::PathBuf};
use serde::{Deserialize, Serialize};

View File

@@ -174,17 +174,38 @@ where
}
/// 过滤列表中的元素,对.iter().filter().cloned().collect()的简化
pub fn filter<T, F>(items: &Vec<T>, pred: F) -> Vec<T>
pub fn filter<'a, I, O, T, F>(items: I, pred: F) -> O
where
T: Clone,
T: Clone + 'a,
I: IntoIterator<Item = &'a T>,
O: FromIterator<T>,
F: Fn(&T) -> bool,
{
items.iter().filter(|item| pred(item)).cloned().collect()
//items可以是一个引用
items.into_iter().filter(|item| pred(item)).cloned().collect::<O>()
}
/// 对列表中的元素应用func对.iter().map().collect()的简化
pub fn map<'a, I, O, T, F>(items: I, func: F) -> O
where
T: Clone + 'a,
I: IntoIterator<Item = &'a T>,
O: FromIterator<T>,
F: Fn(&T) -> T,
{
//items可以是一个引用
items.into_iter().map(|item| func(item)).collect::<O>()
}
/// 过滤列表中的元素使其在paths中包括子目录不检查存在性
pub fn filter_to_fit_paths(items: &Vec<PathBuf>, paths: &Vec<PathBuf>) -> HashSet<PathBuf> {
filter(items, |item| include_in_paths(item, paths)).into_iter().collect()
pub fn filter_to_fit_paths<T, O>(items: &Vec<T>, paths: &Vec<T>) -> O
where
T: AsRef<Path> + Clone,
O: FromIterator<T> + IntoIterator<Item = T>,
{
filter::<_, O, _, _>(items, |item| include_in_paths(item.as_ref(), paths))
.into_iter()
.collect::<O>()
}
/// 检查文件是否在工作区内, 若不存在则false
@@ -295,8 +316,11 @@ pub fn is_empty_dir(dir: &Path) -> bool {
}
pub fn is_cur_dir(dir: &Path) -> bool {
let cur_dir = std::env::current_dir().unwrap(); //应该是绝对路径吧
get_absolute_path(dir) == cur_dir
get_absolute_path(dir) == cur_dir()
}
pub fn cur_dir() -> PathBuf {
std::env::current_dir().unwrap() //应该是绝对路径吧
}
/// 列出工作区所有文件(包括子文件夹)