diff --git a/src/commands/add.rs b/src/commands/add.rs index b12fd21..d15de31 100644 --- a/src/commands/add.rs +++ b/src/commands/add.rs @@ -5,7 +5,7 @@ use colored::Colorize; use crate::commands::status; use crate::models::index::FileMetaData; use crate::models::*; -use crate::utils::util; +use crate::utils::{util, PathExt}; /// add是对index的操作,不会对工作区产生影响 /// @see git add .,git add -A,git add -u,git add * 的区别与联系 @@ -41,7 +41,7 @@ pub fn add(raw_paths: Vec, all: bool, mut update: bool) { fn add_a_file(file: &Path, index: &mut Index) { let workdir = util::get_working_dir().unwrap(); - if !util::is_sub_path(file, &workdir) { + if !file.is_sub_to(&workdir) { //文件不在工作区内 println!("fatal: '{}' is outside workdir at '{}'", file.display(), workdir.display()); return; @@ -52,7 +52,7 @@ fn add_a_file(file: &Path, index: &mut Index) { return; } - let rel_path = util::to_cur_relative_path(file); + let rel_path = file.to_relative(); if !file.exists() { //文件被删除 index.remove(file); diff --git a/src/commands/restore.rs b/src/commands/restore.rs index d96b064..f777cf6 100644 --- a/src/commands/restore.rs +++ b/src/commands/restore.rs @@ -6,7 +6,7 @@ use std::{ use crate::{ models::*, - utils::{util, Store}, + utils::{util, PathExt, Store}, }; /// 统计[工作区]中相对于target_blobs已删除的文件(根据filters进行过滤) @@ -18,7 +18,7 @@ fn get_worktree_deleted_files_in_filters( .iter() .filter(|(path, _)| { assert!(path.is_absolute()); // - !path.exists() && util::include_in_paths(path, filters) + !path.exists() && path.include_in(filters) }) .map(|(path, _)| path.clone()) .collect() //HashSet自动去重 @@ -34,7 +34,7 @@ fn get_index_deleted_files_in_filters( .iter() .filter(|(path, _)| { assert!(path.is_absolute()); - !index.contains(path) && util::include_in_paths(path, filters) + !index.contains(path) && path.include_in(filters) }) .map(|(path, _)| path.clone()) .collect() //HashSet自动去重 @@ -53,7 +53,7 @@ fn preprocess_filters(filters: Option<&Vec>) -> Vec { fn preprocess_blobs(blobs: &Vec<(PathBuf, Hash)>) -> HashMap { blobs // 转为绝对路径 //TODO tree改变路径表示方式后,这里需要修改 .iter() - .map(|(path, hash)| (util::to_workdir_absolute_path(path), hash.clone())) + .map(|(path, hash)| (path.to_absolute_workdir(), hash.clone())) .collect() //to HashMap } diff --git a/src/commands/status.rs b/src/commands/status.rs index 9dc844d..f3d705d 100644 --- a/src/commands/status.rs +++ b/src/commands/status.rs @@ -1,3 +1,4 @@ +use crate::utils::PathExt; use crate::{ models::{head, Commit, Index}, utils::util, @@ -45,7 +46,7 @@ impl Changes { [&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)); + **paths = util::map(&**paths, |p| p.to_absolute_workdir()); }); change } @@ -53,11 +54,10 @@ impl Changes { /// 转换为相对路径(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)); + **paths = util::map(&**paths, |p| p.to_relative()); }); change } @@ -73,7 +73,7 @@ pub fn changes_to_be_committed() -> Changes { let tracked_files = index .get_tracked_files() .iter() - .map(|f| util::to_workdir_relative_path(f)) + .map(|f| f.to_relative_workdir()) .collect::>(); if head_hash == "" { // 初始提交 @@ -89,7 +89,7 @@ pub fn changes_to_be_committed() -> Changes { for (tree_file, blob_hash) in tree_files.iter() { let index_file = index_files.iter().find(|&f| f == tree_file); if let Some(index_file) = index_file { - let index_path = util::to_workdir_absolute_path(index_file); + let index_path = index_file.to_absolute_workdir(); if !index.verify_hash(&index_path, blob_hash) { change.modified.push(tree_file.clone()); } @@ -112,11 +112,11 @@ pub fn changes_to_be_staged() -> Changes { let index = Index::get_instance(); for file in index.get_tracked_files() { if !file.exists() { - change.deleted.push(util::to_workdir_relative_path(&file)); + change.deleted.push(file.to_relative_workdir()); } else if index.is_modified(&file) { // 若文件元数据被修改,才需要比较暂存区与文件的hash来判别内容修改 if !index.verify_hash(&file, &util::calc_file_hash(&file)) { - change.modified.push(util::to_workdir_relative_path(&file)); + change.modified.push(file.to_relative_workdir()); } } } @@ -124,7 +124,7 @@ pub fn changes_to_be_staged() -> Changes { for file in files { if !index.tracked(&file) { //文件未被跟踪 - change.new.push(util::to_workdir_relative_path(&file)); + change.new.push(file.to_relative_workdir()); } } change diff --git a/src/models/index.rs b/src/models/index.rs index 5a17d8c..bd99525 100644 --- a/src/models/index.rs +++ b/src/models/index.rs @@ -1,3 +1,4 @@ +use crate::utils::PathExt; use crate::{models::*, utils::util}; use once_cell::unsync::Lazy; use serde::{Deserialize, Serialize}; @@ -76,7 +77,7 @@ impl Index { /// 预处理路径,统一形式为绝对路径 fn preprocess(path: &Path) -> PathBuf { - util::get_absolute_path(&path) + path.to_absolute() } // 添加文件 @@ -173,7 +174,7 @@ impl Index { .entries .iter() .map(|(path, value)| { - let relative_path = util::get_relative_path(path, &self.working_dir); + let relative_path = util::get_relative_path_to_dir(path, &self.working_dir); (relative_path, value.clone()) }) .collect(); diff --git a/src/models/tree.rs b/src/models/tree.rs index 539b118..b509614 100644 --- a/src/models/tree.rs +++ b/src/models/tree.rs @@ -2,7 +2,7 @@ use std::{collections::HashSet, path::PathBuf}; use serde::{Deserialize, Serialize}; -use crate::utils::{util, Store}; +use crate::utils::{util, PathExt, Store}; use super::{Hash, Index}; /*Tree @@ -41,7 +41,7 @@ fn store_path_to_tree(index: &Index, current_root: PathBuf) -> Tree { let path_entries: Vec = index .get_tracked_files() .iter() - .map(|file| util::to_workdir_relative_path(file)) + .map(|file| file.to_relative_workdir()) .filter(|path| path.starts_with(¤t_root)) .collect(); for path in path_entries.iter() { diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 91ff23b..f8b0e34 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,4 +1,6 @@ pub mod store; pub use store::Store; +pub mod path_ext; +pub use path_ext::PathExt; pub mod test; pub mod util; diff --git a/src/utils/path_ext.rs b/src/utils/path_ext.rs new file mode 100644 index 0000000..a4242bb --- /dev/null +++ b/src/utils/path_ext.rs @@ -0,0 +1,56 @@ +use crate::utils::util; +use std::path::{Path, PathBuf}; + +/** +Path的扩展 基于util 为了解耦,不要再util中使用PathExt + */ +pub trait PathExt { + fn to_absolute(&self) -> PathBuf; + fn to_absolute_workdir(&self) -> PathBuf; + fn to_relative(&self) -> PathBuf; + fn to_relative_workdir(&self) -> PathBuf; + fn is_sub_to(&self, parent: &PathBuf) -> bool; + fn include_in(&self, paths: U) -> bool + where + T: AsRef, + U: IntoIterator; +} +/* +在 Rust 中,当你调用一个方法时,Rust 会尝试自动解引用和自动引用(auto-deref and auto-ref)来匹配方法签名。 +如果有一个为 Path 实现的方法,你可以在 PathBuf、&PathBuf、&&PathBuf 等上调用这个方法,Rust 会自动进行必要的解引用。 + */ +impl PathExt for Path { + /// 转换为绝对路径 + fn to_absolute(&self) -> PathBuf { + util::get_absolute_path(&self) + } + + /// 转换为绝对路径(from workdir相对路径) + fn to_absolute_workdir(&self) -> PathBuf { + util::to_workdir_absolute_path(&self) + } + + /// 转换为相对路径(to cur_dir) + fn to_relative(&self) -> PathBuf { + util::get_relative_path(&self) + } + + /// 转换为相对路径(to workdir) + fn to_relative_workdir(&self) -> PathBuf { + util::to_workdir_relative_path(&self) + } + + /// 从字符串角度判断path是否是parent的子路径(不检测存在性) + fn is_sub_to(&self, parent: &PathBuf) -> bool { + util::is_sub_path(&self, parent) + } + + /// 判断是否在paths中(包括子目录),不检查存在 + fn include_in(&self, paths: U) -> bool + where + T: AsRef, + U: IntoIterator, + { + util::include_in_paths(&self, paths) + } +} diff --git a/src/utils/util.rs b/src/utils/util.rs index 71d24cc..e5dc13b 100644 --- a/src/utils/util.rs +++ b/src/utils/util.rs @@ -95,7 +95,7 @@ pub fn is_sub_path(path: &Path, parent: &Path) -> bool { is_parent_dir(path, parent) } -/// 判断文件是否在paths中(包括子目录),不检查存在性 +/// 判断是否在paths中(包括子目录),不检查存在性 pub fn include_in_paths(path: &Path, paths: U) -> bool where T: AsRef, @@ -252,7 +252,7 @@ pub fn list_workdir_files() -> Vec { } /// 获取相对于dir的 规范化 相对路径(不包含../ ./) -pub fn get_relative_path(path: &Path, dir: &Path) -> PathBuf { +pub fn get_relative_path_to_dir(path: &Path, dir: &Path) -> PathBuf { // 先统一为绝对路径 let abs_path = if path.is_relative() { get_absolute_path(path) @@ -287,12 +287,12 @@ pub fn get_common_dir(p1: &Path, p2: &Path) -> PathBuf { /// 获取相较于工作区(Working Dir)的相对路径 pub fn to_workdir_relative_path(path: &Path) -> PathBuf { - get_relative_path(path, &get_working_dir().unwrap()) + get_relative_path_to_dir(path, &get_working_dir().unwrap()) } /// 获取相较于当前目录的 规范化 相对路径(不包含../ ./) -pub fn to_cur_relative_path(path: &Path) -> PathBuf { - get_relative_path(path, &cur_dir()) +pub fn get_relative_path(path: &Path) -> PathBuf { + get_relative_path_to_dir(path, &cur_dir()) } /// 获取相较于工作区(Working Dir)的绝对路径 @@ -336,7 +336,7 @@ pub fn get_file_mode(path: &Path) -> String { /// 获取绝对路径(相对于目录current_dir) 不论是否存在 pub fn get_absolute_path(path: &Path) -> PathBuf { - get_absolute_path_to_dir(path, &std::env::current_dir().unwrap()) + get_absolute_path_to_dir(path, &cur_dir()) } /// 获取绝对路径(相对于目录dir) 不论是否存在 @@ -467,7 +467,7 @@ mod tests { fn test_get_relative_path() { test::setup_with_clean_mit(); let path = Path::new("../../src\\main.rs"); - let rel_path = get_relative_path(&path, &cur_dir()); + let rel_path = get_relative_path_to_dir(&path, &cur_dir()); println!("{:?}", rel_path); assert_eq!(rel_path, path); diff --git a/tests/test.rs b/tests/test.rs index e69de29..8b13789 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -0,0 +1 @@ +