diff --git a/ceres/src/api_service/mono_api_service.rs b/ceres/src/api_service/mono_api_service.rs index 16a511cc..2b1af7ff 100644 --- a/ceres/src/api_service/mono_api_service.rs +++ b/ceres/src/api_service/mono_api_service.rs @@ -19,7 +19,6 @@ use venus::monorepo::converter; use crate::api_service::ApiHandler; use crate::model::create_file::CreateFileInfo; use crate::model::mr::{MRDetail, MrInfoItem}; -use crate::model::tree::MRFileTree; #[derive(Clone)] pub struct MonoApiService { @@ -217,16 +216,57 @@ impl MonoApiService { Ok(None) } - pub async fn mr_tree_files(&self, mr_id: i64) -> Result { + pub async fn mr_tree_files(&self, mr_id: i64) -> Result, MegaError> { let storage = self.context.services.mega_storage.clone(); let model = storage.get_mr(mr_id).await.unwrap(); if let Some(model) = model { - let start_tree = storage.get_commit_by_hash(&model.to_hash).await.unwrap().unwrap().tree; - let mut stack = VecDeque::new(); - stack.push_back(start_tree); - // while let Some(_) = stack.pop_front() { + let to_tree_id = storage + .get_commit_by_hash(&model.to_hash) + .await + .unwrap() + .unwrap() + .tree; + + let from_tree_id = storage + .get_commit_by_hash(&model.from_hash) + .await + .unwrap() + .unwrap() + .tree; + + let mut tree_comparation = TreeComparation { + left_tree: VecDeque::new(), + result_file: vec![], + }; + tree_comparation.left_tree.push_back(( + SHA1::from_str(&to_tree_id).unwrap(), + Some(SHA1::from_str(&from_tree_id).unwrap()), + PathBuf::from(model.path), + )); + while let Some((new_tree, base_tree, mut current_path)) = + tree_comparation.left_tree.pop_front() + { + let new_tree: Tree = storage + .get_tree_by_hash(&new_tree.to_plain_str()) + .await + .unwrap() + .unwrap() + .into(); - // } + let base_tree = if let Some(base_tree) = base_tree { + let base_tree: Tree = storage + .get_tree_by_hash(&base_tree.to_plain_str()) + .await + .unwrap() + .unwrap() + .into(); + Some(base_tree) + } else { + None + }; + tree_comparation.compare(new_tree, base_tree, &mut current_path); + } + return Ok(tree_comparation.result_file); } Err(MegaError::with_message("Can not find related MR by id")) } @@ -337,9 +377,91 @@ impl MonoApiService { } } +pub struct TreeComparation { + pub left_tree: VecDeque<(SHA1, Option, PathBuf)>, + pub result_file: Vec, +} + +impl TreeComparation { + // fn compare(&mut self, new: Tree, base: Option) { + // let new_set: HashSet<_> = new.tree_items.into_iter().collect(); + // let base_set = if let Some(tree) = base { + // tree.tree_items.into_iter().collect() + // } else { + // HashSet::new() + // }; + // let diff: Vec<_> = new_set.symmetric_difference(&base_set).cloned().collect(); + // for item in diff { + // if item.mode == TreeItemMode::Tree { + // let t_id = item.id.to_plain_str(); + // if !self.left_tree.contains(&t_id) { + // self.left_tree.push_back(t_id); + // } + // } else { + // self.result_file.push(item.name) + // } + // } + // } + + pub fn compare(&mut self, new: Tree, base: Option, current_path: &mut PathBuf) { + let mut map_name_to_item = HashMap::new(); + let mut map_id_to_item = HashMap::new(); + + if let Some(tree) = base { + for item in tree.tree_items { + map_name_to_item.insert(item.name.clone(), item.clone()); + map_id_to_item.insert(item.id, item.clone()); + } + } + + for item in new.tree_items { + match ( + map_name_to_item.get(&item.name), + map_id_to_item.get(&item.id), + ) { + (Some(base_item), _) if base_item.id != item.id => { + self.process_diff(item, Some(base_item.id), current_path); + } + (_, Some(base_item)) if base_item.name != item.name => { + self.process_diff(item, None, current_path); + } + (None, None) => { + self.process_diff(item, None, current_path); + } + _ => {} + } + } + } + + fn process_diff(&mut self, item: TreeItem, base_id: Option, current_path: &mut PathBuf) { + if item.mode == TreeItemMode::Tree { + if !self + .left_tree + .contains(&(item.id, base_id, current_path.to_path_buf())) + { + current_path.push(item.name); + self.left_tree + .push_back((item.id, base_id, current_path.to_path_buf())); + current_path.pop(); + } + } else { + current_path.push(item.name); + self.result_file.push(current_path.to_path_buf()); + current_path.pop(); + } + } +} + #[cfg(test)] mod test { - use std::path::PathBuf; + use std::{collections::VecDeque, path::PathBuf}; + + use mercury::{ + hash::SHA1, + internal::object::tree::{Tree, TreeItem, TreeItemMode}, + }; + + use crate::api_service::mono_api_service::TreeComparation; #[test] pub fn test() { @@ -351,4 +473,66 @@ mod test { println!("name: {}, path: {:?}", name, full_path); } } + + #[test] + fn test_compare_tree() { + let base = Tree::from_tree_items(vec![ + TreeItem { + mode: TreeItemMode::Tree, + id: SHA1::new(&"src".as_bytes().to_vec()), + name: "src".to_string(), + }, + TreeItem { + mode: TreeItemMode::Tree, + id: SHA1::new(&"mega".as_bytes().to_vec()), + name: "mega".to_string(), + }, + TreeItem { + mode: TreeItemMode::Blob, + id: SHA1::new(&"delete.txt".as_bytes().to_vec()), + name: "delete.txt".to_string(), + }, + TreeItem { + mode: TreeItemMode::Blob, + id: SHA1::new(&"README.md".as_bytes().to_vec()), + name: "README.md".to_string(), + }, + ]) + .unwrap(); + + let new = Tree::from_tree_items(vec![ + TreeItem { + mode: TreeItemMode::Tree, + id: SHA1::new(&"src".as_bytes().to_vec()), + name: "src_new".to_string(), + }, + TreeItem { + mode: TreeItemMode::Tree, + id: SHA1::new(&"mega222".as_bytes().to_vec()), + name: "mega".to_string(), + }, + TreeItem { + mode: TreeItemMode::Blob, + id: SHA1::new(&"Cargo.toml".as_bytes().to_vec()), + name: "Cargo.toml".to_string(), + }, + TreeItem { + mode: TreeItemMode::Blob, + id: SHA1::new(&"README.md".as_bytes().to_vec()), + name: "README.md".to_string(), + }, + ]) + .unwrap(); + + let mut tree_comparation = TreeComparation { + left_tree: VecDeque::new(), + result_file: vec![], + }; + // let mut current_path = Path::new("/"); + tree_comparation.compare(new, Some(base), &mut PathBuf::from("/")); + println!( + "files: {:?} left Tree: {:?}", + tree_comparation.result_file, tree_comparation.left_tree + ); + } } diff --git a/gateway/src/api/mr_router.rs b/gateway/src/api/mr_router.rs index e4fe2448..65feab74 100644 --- a/gateway/src/api/mr_router.rs +++ b/gateway/src/api/mr_router.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::{collections::HashMap, path::PathBuf}; use axum::{ extract::{Path, Query, State}, @@ -10,7 +10,6 @@ use axum::{ use crate::api::ApiServiceState; use ceres::model::{ mr::{MRDetail, MrInfoItem}, - tree::MRFileTree, CommonResult, }; @@ -62,7 +61,7 @@ async fn mr_detail( async fn get_mr_files( Path(mr_id): Path, state: State, -) -> Result>, (StatusCode, String)> { +) -> Result>>, (StatusCode, String)> { let res = state.monorepo().mr_tree_files(mr_id).await; let res = match res { Ok(data) => CommonResult::success(Some(data)), diff --git a/moon/src/components/Bottombar.tsx b/moon/src/components/Bottombar.tsx index 0b5dd4fe..f2935ed0 100644 --- a/moon/src/components/Bottombar.tsx +++ b/moon/src/components/Bottombar.tsx @@ -62,7 +62,7 @@ const navigation = [ }, ] -export default function Bottombar() { +export default function BottomBar() { const currentYear = new Date().getFullYear(); return (