mirror of
https://github.com/MrBeanCpp/MIT.git
synced 2026-02-03 10:14:13 +08:00
restore: 优化报错 & 编写测试
This commit is contained in:
@@ -21,7 +21,7 @@ Git in Rust. 用 `Rust` 实现的mini `Git`. Called `mit`.
|
||||
|
||||
- 支持 `mit init`, `mit add`, `mit rm`, `mit commit`
|
||||
|
||||
- [x] `init`: 初始化(若仓库已存在,则不执行)
|
||||
- [x] `init`: 初始化(若仓库已存在,则不执行)- `idempotent`
|
||||
- [x] `add`: 将变更添加至暂存区(包括新建、修改、删除),可指定文件或目录
|
||||
- `-A(all)` : 暂存工作区中的所有文件(从根目录开始)变更(新建√ 修改√ 删除√)
|
||||
- `-u(update)`: 仅对暂存区[`index`]中已跟踪的文件进行操作(新建× 修改√ 删除√)
|
||||
@@ -55,7 +55,6 @@ Git in Rust. 用 `Rust` 实现的mini `Git`. Called `mit`.
|
||||
### 名词释义
|
||||
- 暂存区:`index` or `stage`,保存下一次`commit`需要的的文件快照
|
||||
- 工作区:`worktree`,用户直接操作的文件夹
|
||||
- 工作目录:`working directory`,代码仓库的根目录,即`.mit`所在的目录
|
||||
- 仓库:`repository`,包含`.mit`目录的目录
|
||||
- 工作目录:`working directory` or `repository`,代码仓库的根目录,即`.mit`所在的目录
|
||||
- `HEAD`:指向当前`commit`的指针
|
||||
- 已跟踪:`tracked`,指已经在暂存区[`index`]中的文件(即曾经`add`过的文件)
|
||||
@@ -68,9 +68,7 @@ pub fn restore_worktree(filter: Option<&Vec<PathBuf>>, target_blobs: &Vec<(PathB
|
||||
let input_paths = preprocess_filters(filter); //预处理filter 将None转化为workdir
|
||||
let target_blobs = preprocess_blobs(target_blobs); //预处理target_blobs 转化为绝对路径HashMap
|
||||
|
||||
//TODO 输出不存在于target和worktree中文件
|
||||
|
||||
let deleted_files = get_worktree_deleted_files_in_filters(&input_paths, &target_blobs); //统计所有目录中已删除的文件
|
||||
let deleted_files = get_worktree_deleted_files_in_filters(&input_paths, &target_blobs); //统计已删除的文件
|
||||
|
||||
let mut file_paths = util::integrate_paths(&input_paths); //根据用户输入整合存在的文件(绝对路径)
|
||||
file_paths.extend(deleted_files); //已删除的文件
|
||||
@@ -86,9 +84,8 @@ pub fn restore_worktree(filter: Option<&Vec<PathBuf>>, target_blobs: &Vec<(PathB
|
||||
//文件存在于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());
|
||||
// TODO 如果是用户输入的路径,才应该报错,integrate_paths产生的不应该报错
|
||||
//在target_commit和workdir中都不存在(非法路径), 用户输入
|
||||
println!("fatal: pathspec '{}' did not match any files", path.display());
|
||||
}
|
||||
} else {
|
||||
//文件存在,有两种情况:1.修改 2.新文件
|
||||
@@ -116,7 +113,7 @@ pub fn restore_index(filter: Option<&Vec<PathBuf>>, target_blobs: &Vec<(PathBuf,
|
||||
let target_blobs = preprocess_blobs(target_blobs); //预处理target_blobs 转化为绝对路径HashMap
|
||||
|
||||
let mut index = Index::new();
|
||||
let deleted_files_index = get_index_deleted_files_in_filters(&index, &input_paths, &target_blobs); //统计所有目录中已删除的文件
|
||||
let deleted_files_index = get_index_deleted_files_in_filters(&index, &input_paths, &target_blobs); //统计已删除的文件
|
||||
|
||||
//1.获取index中包含于input_path的文件(使用paths进行过滤)
|
||||
let mut file_paths: HashSet<PathBuf> = util::filter_to_fit_paths(&index.get_tracked_files(), &input_paths);
|
||||
@@ -133,8 +130,7 @@ pub fn restore_index(filter: Option<&Vec<PathBuf>>, target_blobs: &Vec<(PathBuf,
|
||||
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产生的不应该报错
|
||||
println!("fatal: pathspec '{}' did not match any files", path.display());
|
||||
}
|
||||
} else {
|
||||
//文件存在于index,有两种情况:1.修改 2.新文件
|
||||
@@ -224,18 +220,46 @@ pub fn restore(paths: Vec<String>, source: Option<String>, worktree: bool, stage
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::fs;
|
||||
//TODO 写测试!
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::{commands, models::index::Index, utils::util};
|
||||
use crate::commands::add::add;
|
||||
use crate::commands::restore::restore;
|
||||
use crate::commands::status;
|
||||
use crate::{models::index::Index, utils::util};
|
||||
|
||||
#[test]
|
||||
fn test_restore_stage() {
|
||||
util::setup_test_with_clean_mit();
|
||||
util::setup_test_with_empty_workdir();
|
||||
let path = PathBuf::from("a.txt");
|
||||
util::ensure_no_file(&path);
|
||||
commands::add::add(vec![], true, false);
|
||||
super::restore(vec![".".to_string()], Some("HEAD".to_string()), false, true);
|
||||
add(vec![], true, false); //add -A
|
||||
restore(vec![".".to_string()], Some("HEAD".to_string()), false, true);
|
||||
let index = Index::new();
|
||||
assert!(index.get_tracked_files().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_restore_worktree() {
|
||||
util::setup_test_with_empty_workdir();
|
||||
let files = vec!["a.txt", "b.txt", "c.txt", "test/in.txt"];
|
||||
util::ensure_test_files(&files);
|
||||
|
||||
add(vec![], true, false);
|
||||
assert_eq!(status::changes_to_be_committed().new.iter().count(), 4);
|
||||
|
||||
restore(vec!["c.txt".to_string()], None, false, true); //restore c.txt --staged
|
||||
assert_eq!(status::changes_to_be_committed().new.iter().count(), 3);
|
||||
assert_eq!(status::changes_to_be_staged().new.iter().count(), 1);
|
||||
|
||||
fs::remove_file("a.txt").unwrap(); //删除a.txt
|
||||
fs::remove_dir_all("test").unwrap(); //删除test文件夹
|
||||
assert_eq!(status::changes_to_be_staged().deleted.iter().count(), 2);
|
||||
|
||||
restore(vec![".".to_string()], None, true, false); //restore . //from index
|
||||
assert_eq!(status::changes_to_be_committed().new.iter().count(), 3);
|
||||
assert_eq!(status::changes_to_be_staged().new.iter().count(), 1);
|
||||
assert_eq!(status::changes_to_be_staged().deleted.iter().count(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ use std::{
|
||||
collections::HashSet,
|
||||
fs, io,
|
||||
io::Write,
|
||||
option,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
@@ -13,29 +12,30 @@ pub const ROOT_DIR: &str = ".mit";
|
||||
pub const TEST_DIR: &str = "mit_test_storage"; // 执行测试的储存库
|
||||
|
||||
/* tools for test */
|
||||
fn find_cargo_dir() -> PathBuf {
|
||||
let cargo_path = std::env::var("CARGO_MANIFEST_DIR");
|
||||
if cargo_path.is_err() {
|
||||
// vscode DEBUG test没有CARGO_MANIFEST_DIR宏,手动尝试查找cargo.toml
|
||||
let mut path = cur_dir();
|
||||
loop {
|
||||
path.push("Cargo.toml");
|
||||
if path.exists() {
|
||||
break;
|
||||
}
|
||||
if !path.pop() {
|
||||
panic!("找不到CARGO_MANIFEST_DIR");
|
||||
}
|
||||
}
|
||||
path.pop();
|
||||
path
|
||||
} else {
|
||||
PathBuf::from(cargo_path.unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_test_dir() {
|
||||
color_backtrace::install(); // colorize backtrace
|
||||
let cargo_path = std::env::var("CARGO_MANIFEST_DIR");
|
||||
let path: PathBuf = {
|
||||
if cargo_path.is_err() {
|
||||
// vscode DEBUG test没有CARGO_MANIFEST_DIR宏,手动尝试查找cargo.toml
|
||||
let mut path = std::env::current_dir().unwrap();
|
||||
loop {
|
||||
path.push("Cargo.toml");
|
||||
if path.exists() {
|
||||
break;
|
||||
}
|
||||
if !path.pop() {
|
||||
panic!("找不到CARGO_MANIFEST_DIR");
|
||||
}
|
||||
}
|
||||
path.pop();
|
||||
path
|
||||
} else {
|
||||
PathBuf::from(cargo_path.unwrap())
|
||||
}
|
||||
};
|
||||
let mut path = PathBuf::from(path);
|
||||
let mut path = find_cargo_dir();
|
||||
path.push(TEST_DIR);
|
||||
if !path.exists() {
|
||||
fs::create_dir(&path).unwrap();
|
||||
@@ -59,7 +59,32 @@ pub fn setup_test_without_mit() {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ensure_test_file(path: &Path, content: option::Option<&str>) {
|
||||
pub fn ensure_test_files<T: AsRef<str>>(paths: &Vec<T>) {
|
||||
for path in paths {
|
||||
ensure_test_file(path.as_ref().as_ref(), None);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ensure_empty_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
|
||||
let entries = fs::read_dir(path.as_ref())?;
|
||||
for entry in entries {
|
||||
let path = entry?.path();
|
||||
if path.is_dir() {
|
||||
fs::remove_dir_all(&path)?; // 如果是目录,则递归删除
|
||||
} else {
|
||||
fs::remove_file(&path)?; // 如果是文件,则直接删除
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn setup_test_with_empty_workdir() {
|
||||
let test_dir = find_cargo_dir().join(TEST_DIR);
|
||||
ensure_empty_dir(&test_dir).unwrap();
|
||||
setup_test_with_clean_mit();
|
||||
}
|
||||
|
||||
pub fn ensure_test_file(path: &Path, content: Option<&str>) {
|
||||
// 以测试目录为根目录,创建文件
|
||||
fs::create_dir_all(path.parent().unwrap()).unwrap(); // ensure父目录
|
||||
let mut file =
|
||||
|
||||
Reference in New Issue
Block a user