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 @@
+