实现:status命令

TODO:add 不存在的文件报错
This commit is contained in:
mrbeanc
2023-12-22 00:09:53 +08:00
parent f9e7ef493a
commit 5f1d115658
6 changed files with 128 additions and 20 deletions

View File

@@ -10,7 +10,6 @@ use crate::utils::util::{
ROOT_DIR,
};
// TODO: fatal: ../moj/app.py: '../moj/app.py' is outside repository at 'Git-Rust'
pub fn add(files: Vec<String>, all: bool, mut update: bool) {
check_repo_exist();
let mut index = Index::new();
@@ -53,7 +52,8 @@ pub fn add(files: Vec<String>, all: bool, mut update: bool) {
}
fn add_a_file(file: &Path, index: &mut Index) {
if !is_inside_workdir(file) {
//TODO 文件不存在会报错
if !is_inside_workdir(file) && file.exists() {
//文件不在工作区内
println!("fatal: '{}' is outside repository at '{}'", file.display(), get_working_dir().unwrap().display());
return;

View File

@@ -1,13 +1,14 @@
use crate::head::Head;
use crate::models::commit::Commit;
use crate::models::index::Index;
use crate::utils::util::check_repo_exist;
use crate::{head, utils::util};
use colored::Colorize;
use std::path::PathBuf;
use crate::utils::util::to_workdir_absolute_path;
use crate::{
head,
models::{commit, index},
utils::util,
};
/** 获取需要commit的更改(staged) */
/** 获取需要commit的更改(staged)
注:相对路径
*/
#[derive(Debug, Default)]
pub struct Changes {
pub new: Vec<PathBuf>,
@@ -15,9 +16,15 @@ pub struct Changes {
pub deleted: Vec<PathBuf>,
}
impl Changes {
pub fn is_empty(&self) -> bool {
self.new.is_empty() && self.modified.is_empty() && self.deleted.is_empty()
}
}
pub fn changes_to_be_committed() -> Changes {
let mut change = Changes::default();
let index = index::Index::new();
let index = Index::new();
let head_hash = head::current_head_commit();
let tracked_files = index
.get_tracked_files()
@@ -30,7 +37,7 @@ pub fn changes_to_be_committed() -> Changes {
return change;
}
let commit = commit::Commit::load(&head_hash);
let commit = Commit::load(&head_hash);
let tree = commit.get_tree();
let tree_files = tree.get_recursive_blobs(); //相对路径
let index_files: Vec<PathBuf> = tracked_files;
@@ -38,7 +45,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 = to_workdir_absolute_path(index_file);
let index_path = util::to_workdir_absolute_path(index_file);
if !index.verify_hash(&index_path, blob_hash) {
change.modified.push(tree_file.clone());
}
@@ -55,8 +62,29 @@ pub fn changes_to_be_committed() -> Changes {
change
}
pub fn changes_to_be_staged() {
unimplemented!()
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) {
// 若文件元数据被修改才需要比较暂存区与文件的hash来判别内容修改
if !index.verify_hash(&file, &util::calc_file_hash(&file)) {
change.modified.push(util::to_workdir_relative_path(&file));
}
}
}
let files = util::list_workdir_files(); //TODO 考虑当前目录
for file in files {
if !index.tracked(&file) {
//文件未被跟踪
change.new.push(util::to_workdir_relative_path(&file));
}
}
change
}
/** 分为两个部分
@@ -64,7 +92,60 @@ pub fn changes_to_be_staged() {
2. staged to be committed: 暂存区与HEAD(最后一次Commit::Tree)比较,即上次的暂存区
*/
pub fn status() {
unimplemented!()
check_repo_exist();
//TODO: 输出文件与当前所在目录有关 输出时过滤
match head::current_head() {
Head::Detached(commit) => {
println!("HEAD detached at {}", commit[0..7].to_string());
}
Head::Branch(branch) => {
println!("On branch {}", branch);
}
}
let staged = changes_to_be_committed();
let unstaged = changes_to_be_staged();
if staged.is_empty() && unstaged.is_empty() {
println!("nothing to commit, working tree clean");
return;
}
if !staged.is_empty() {
println!("Changes to be committed:");
staged.deleted.iter().for_each(|f| {
let str = format!("\tdeleted: {}", f.display());
println!("{}", str.bright_green());
});
staged.modified.iter().for_each(|f| {
let str = format!("\tmodified: {}", f.display());
println!("{}", str.bright_green());
});
staged.new.iter().for_each(|f| {
let str = format!("\tnew file: {}", f.display());
println!("{}", str.bright_green());
});
}
if !unstaged.deleted.is_empty() || !unstaged.modified.is_empty() {
println!("Changes not staged for commit:");
println!(" use \"mit add <file>...\" to update what will be committed");
unstaged.deleted.iter().for_each(|f| {
let str = format!("\tdeleted: {}", f.display());
println!("{}", str.bright_red());
});
unstaged.modified.iter().for_each(|f| {
let str = format!("\tmodified: {}", f.display());
println!("{}", str.bright_red());
});
}
if !unstaged.new.is_empty() {
println!("Untracked files:");
println!(" use \"mit add <file>...\" to include in what will be committed");
unstaged.new.iter().for_each(|f| {
let str = format!("\t{}", f.display());
println!("{}", str.bright_red());
});
}
}
#[cfg(test)]