From 07dfd24d32c905495e24948417fa974aee0d145e Mon Sep 17 00:00:00 2001 From: mrbeanc Date: Sun, 24 Dec 2023 11:46:07 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20status=E5=91=BD=E4=BB=A4=E5=AF=B9?= =?UTF-8?q?=E5=BD=93=E5=89=8D=E7=9B=AE=E5=BD=95=E8=BF=9B=E8=A1=8C=E8=BF=87?= =?UTF-8?q?=E6=BB=A4=20&=20=E6=94=B9=E8=BF=9Butil=E6=B3=9B=E5=9E=8B?= =?UTF-8?q?=E6=A8=A1=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/commands/restore.rs | 2 +- src/commands/status.rs | 62 +++++++++++++++++++++++++++++++++++------ src/models/tree.rs | 5 +--- src/utils/util.rs | 38 ++++++++++++++++++++----- 4 files changed, 87 insertions(+), 20 deletions(-) diff --git a/src/commands/restore.rs b/src/commands/restore.rs index 656c721..688f88b 100644 --- a/src/commands/restore.rs +++ b/src/commands/restore.rs @@ -119,7 +119,7 @@ pub fn restore_index(filter: Option<&Vec>, 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 = util::filter_to_fit_paths(&index.get_tracked_files(), &input_paths); // 2.补充index中已删除的文件(相较于target_blobs) file_paths.extend(deleted_files_index); //已删除的文件 diff --git a/src/commands/status.rs b/src/commands/status.rs index 5a1e3d3..88f901e 100644 --- a/src/commands/status.rs +++ b/src/commands/status.rs @@ -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, pub modified: Vec, @@ -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) -> 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) -> 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")); diff --git a/src/models/tree.rs b/src/models/tree.rs index 56d6ae1..c1b8f81 100644 --- a/src/models/tree.rs +++ b/src/models/tree.rs @@ -1,7 +1,4 @@ -use std::{ - collections::{HashMap, HashSet}, - path::PathBuf, -}; +use std::{collections::HashSet, path::PathBuf}; use serde::{Deserialize, Serialize}; diff --git a/src/utils/util.rs b/src/utils/util.rs index 8e2a8ed..d46cf4c 100644 --- a/src/utils/util.rs +++ b/src/utils/util.rs @@ -174,17 +174,38 @@ where } /// 过滤列表中的元素,对.iter().filter().cloned().collect()的简化 -pub fn filter(items: &Vec, pred: F) -> Vec +pub fn filter<'a, I, O, T, F>(items: I, pred: F) -> O where - T: Clone, + T: Clone + 'a, + I: IntoIterator, + O: FromIterator, F: Fn(&T) -> bool, { - items.iter().filter(|item| pred(item)).cloned().collect() + //items可以是一个引用 + items.into_iter().filter(|item| pred(item)).cloned().collect::() +} + +/// 对列表中的元素应用func,对.iter().map().collect()的简化 +pub fn map<'a, I, O, T, F>(items: I, func: F) -> O +where + T: Clone + 'a, + I: IntoIterator, + O: FromIterator, + F: Fn(&T) -> T, +{ + //items可以是一个引用 + items.into_iter().map(|item| func(item)).collect::() } /// 过滤列表中的元素,使其在paths中(包括子目录),不检查存在性 -pub fn filter_to_fit_paths(items: &Vec, paths: &Vec) -> HashSet { - filter(items, |item| include_in_paths(item, paths)).into_iter().collect() +pub fn filter_to_fit_paths(items: &Vec, paths: &Vec) -> O +where + T: AsRef + Clone, + O: FromIterator + IntoIterator, +{ + filter::<_, O, _, _>(items, |item| include_in_paths(item.as_ref(), paths)) + .into_iter() + .collect::() } /// 检查文件是否在工作区内, 若不存在则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() //应该是绝对路径吧 } /// 列出工作区所有文件(包括子文件夹)