Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 128 additions & 16 deletions ceres/src/api_service/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::{
collections::{HashMap, HashSet},
collections::{HashMap, HashSet, VecDeque},
path::{Component, Path, PathBuf},
};

Expand All @@ -14,6 +14,7 @@ use mercury::{
tree::{Tree, TreeItem, TreeItemMode},
},
};
use venus::monorepo::converter;

use crate::model::{
create_file::CreateFileInfo,
Expand Down Expand Up @@ -64,25 +65,32 @@ pub trait ApiHandler: Send + Sync {
let filename = file_path.file_name().unwrap().to_str().unwrap();
let path = file_path.parent().unwrap();
let mut plain_text = String::new();
let (_, tree) = self.search_tree_by_path(path).await?;
if let Some(item) = tree.tree_items.into_iter().find(|x| x.name == filename) {
plain_text = match self.get_raw_blob_by_hash(&item.id.to_plain_str()).await {
Ok(Some(model)) => String::from_utf8(model.data.unwrap()).unwrap(),
_ => String::new(),
};
if let Some(tree) = self.search_tree_by_path(path).await? {
if let Some(item) = tree.tree_items.into_iter().find(|x| x.name == filename) {
plain_text = match self.get_raw_blob_by_hash(&item.id.to_plain_str()).await {
Ok(Some(model)) => String::from_utf8(model.data.unwrap()).unwrap(),
_ => String::new(),
};
}
}
Ok(plain_text)
return Ok(plain_text);
}

async fn get_latest_commit(&self, path: PathBuf) -> Result<LatestCommitInfo, GitError> {
let (_, tree) = self.search_tree_by_path(&path).await.unwrap();
let tree = if let Some(tree) = self.search_tree_by_path(&path).await? {
tree
} else {
return Err(GitError::CustomError(
"can't find target parent tree under latest commit".to_string(),
));
};
let commit = self.get_tree_relate_commit(&tree.id.to_plain_str()).await;
self.convert_commit_to_info(commit)
}

async fn get_tree_info(&self, path: PathBuf) -> Result<Vec<TreeBriefItem>, GitError> {
match self.search_tree_by_path(&path).await {
Ok((_, tree)) => {
match self.search_tree_by_path(&path).await? {
Some(tree) => {
let mut items = Vec::new();
for item in tree.tree_items {
let mut info: TreeBriefItem = item.clone().into();
Expand All @@ -94,13 +102,13 @@ pub trait ApiHandler: Send + Sync {
}
Ok(items)
}
Err(_) => Ok(Vec::new()),
None => Ok(Vec::new()),
}
}

async fn get_tree_commit_info(&self, path: PathBuf) -> Result<Vec<TreeCommitItem>, GitError> {
match self.search_tree_by_path(&path).await {
Ok((_, tree)) => {
match self.search_tree_by_path(&path).await? {
Some(tree) => {
let mut item_to_commit = HashMap::new();

self.add_trees_to_map(
Expand Down Expand Up @@ -153,7 +161,7 @@ pub trait ApiHandler: Send + Sync {
}
Ok(items)
}
Err(_) => Ok(Vec::new()),
None => Ok(Vec::new()),
}
}

Expand Down Expand Up @@ -191,7 +199,7 @@ pub trait ApiHandler: Send + Sync {
///
/// Returns a tuple containing a vector of parent trees to be updated and
/// the target tree if found, or an error of type `GitError`.
async fn search_tree_by_path(&self, path: &Path) -> Result<(Vec<Tree>, Tree), GitError> {
async fn search_tree_for_update(&self, path: &Path) -> Result<(Vec<Tree>, Tree), GitError> {
let relative_path = self.strip_relative(path)?;
let root_tree = self.get_root_tree().await;
let mut search_tree = root_tree.clone();
Expand Down Expand Up @@ -224,6 +232,110 @@ pub trait ApiHandler: Send + Sync {
Ok((update_tree, search_tree))
}

async fn search_tree_by_path(&self, path: &Path) -> Result<Option<Tree>, GitError> {
let relative_path = self.strip_relative(path)?;
let root_tree = self.get_root_tree().await;
let mut search_tree = root_tree.clone();
for component in relative_path.components() {
// root tree already found
if component != Component::RootDir {
let target_name = component.as_os_str().to_str().unwrap();
let search_res = search_tree
.tree_items
.iter()
.find(|x| x.name == target_name);
if let Some(search_res) = search_res {
let res = self.get_tree_by_hash(&search_res.id.to_plain_str()).await;
search_tree = res.clone();
} else {
return Ok(None);
}
}
}
Ok(Some(search_tree))
}

// move to monorepo.
async fn search_and_create_tree(&self, path: &Path) -> Result<Vec<Tree>, GitError> {
let relative_path = self.strip_relative(path)?;
let root_tree = self.get_root_tree().await;
let mut search_tree = root_tree.clone();
let mut update_item_tree = VecDeque::new();
update_item_tree.push_back((root_tree, Component::RootDir));
let mut result = vec![];
let mut stack: VecDeque<_> = VecDeque::new();

for component in relative_path.components() {
// skip rootdir
if component != Component::RootDir {
let target_name = component.as_os_str().to_str().unwrap();
let search_res = search_tree
.tree_items
.iter()
.find(|x| x.name == target_name);
if let Some(search_res) = search_res {
let res = self.get_tree_by_hash(&search_res.id.to_plain_str()).await;
search_tree = res.clone();
update_item_tree.push_back((res, component));
} else {
stack.push_back(component)
}
}
}

let blob = converter::generate_git_keep_with_timestamp();
let new_item = TreeItem {
mode: TreeItemMode::Blob,
id: blob.id,
name: String::from(".gitkeep"),
};
let mut last_tree = Tree::from_tree_items(vec![new_item]).unwrap();
let mut last_tree_name = "";
let mut first_element = true;

while let Some(component) = stack.pop_back() {
if first_element {
first_element = false;
} else {
let new_item = TreeItem {
mode: TreeItemMode::Tree,
id: last_tree.id,
name: last_tree_name.to_owned(),
};
last_tree = Tree::from_tree_items(vec![new_item]).unwrap();
}
result.push(last_tree.clone());
last_tree_name = component.as_os_str().to_str().unwrap();
}

let (new_item_tree, search_name) = update_item_tree.pop_back().unwrap();
let new_item = TreeItem {
mode: TreeItemMode::Tree,
id: last_tree.id,
name: last_tree_name.to_owned(),
};
let mut items = new_item_tree.tree_items.clone();
items.push(new_item);
last_tree = Tree::from_tree_items(items).unwrap();
result.push(last_tree.clone());

let mut replace_hash = last_tree.id;
let mut search_name = search_name.as_os_str().to_str().unwrap();
while let Some((mut tree, component)) = update_item_tree.pop_back() {
let index = tree
.tree_items
.iter()
.position(|x| x.name == search_name)
.unwrap();
tree.tree_items[index].id = replace_hash;
let new_tree = Tree::from_tree_items(tree.tree_items).unwrap();
replace_hash = new_tree.id;
search_name = component.as_os_str().to_str().unwrap();
result.push(new_tree)
}
Ok(result)
}

async fn reachable_in_tree(
&self,
root_tree: &Tree,
Expand Down
24 changes: 14 additions & 10 deletions ceres/src/api_service/mono_api_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ impl ApiHandler for MonoApiService {
let path = PathBuf::from(file_info.path);
let mut save_trees = vec![];

let (update_trees, search_tree) = self.search_tree_by_path(&path).await.unwrap();
let (update_trees, search_tree) = self.search_tree_for_update(&path).await.unwrap();
let mut t_items = search_tree.tree_items;

let new_item = if file_info.is_directory {
Expand Down Expand Up @@ -89,14 +89,18 @@ impl ApiHandler for MonoApiService {
.unwrap();
save_trees.push(p_tree);

for save_t in save_trees {
let mut tree_model: mega_tree::Model = save_t.into();
tree_model.commit_id.clone_from(&commit_id);
let tree_model: mega_tree::ActiveModel = tree_model.into();
batch_save_model(storage.get_connection(), vec![tree_model])
.await
.unwrap();
}
let save_trees = save_trees
.into_iter()
.map(|save_t| {
let mut tree_model: mega_tree::Model = save_t.into();
tree_model.commit_id.clone_from(&commit_id);
let tree_model: mega_tree::ActiveModel = tree_model.into();
tree_model
})
.collect();
batch_save_model(storage.get_connection(), save_trees)
.await
.unwrap();
Ok(())
}

Expand Down Expand Up @@ -297,7 +301,7 @@ impl MonoApiService {
let path = PathBuf::from(mr.path.clone());
// beacuse only parent tree is needed so we skip current directory
let (tree_vec, _) = self
.search_tree_by_path(path.parent().unwrap())
.search_tree_for_update(path.parent().unwrap())
.await
.unwrap();
self.update_parent_tree(path, tree_vec, commit)
Expand Down
66 changes: 52 additions & 14 deletions ceres/src/pack/import_repo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@ use futures::{future::join_all, StreamExt};
use tokio::sync::mpsc;
use tokio_stream::wrappers::ReceiverStream;

use callisto::raw_blob;
use callisto::{mega_tree, raw_blob};
use common::errors::MegaError;
use jupiter::{context::Context, storage::GitStorageProvider};
use jupiter::{
context::Context,
storage::{batch_save_model, GitStorageProvider},
};
use mercury::{
errors::GitError,
internal::{
Expand All @@ -31,7 +34,6 @@ use venus::import_repo::{

use crate::{
api_service::{mono_api_service::MonoApiService, ApiHandler},
model::create_file::CreateFileInfo,
pack::handler::PackHandler,
};

Expand All @@ -55,7 +57,7 @@ impl PackHandler for ImportRepo {
}

async fn handle_receiver(&self, receiver: Receiver<Entry>) -> Result<(), GitError> {
self.create_tree_not_exist().await;
self.create_monorepo_parent().await.unwrap();
let storage = self.context.services.git_db_storage.clone();
let mut entry_list = vec![];
let mut join_tasks = vec![];
Expand Down Expand Up @@ -319,19 +321,55 @@ impl PackHandler for ImportRepo {
}

impl ImportRepo {
async fn create_tree_not_exist(&self) {
// create monorepo parent for preserve import repo
async fn create_monorepo_parent(&self) -> Result<(), GitError> {
let path = PathBuf::from(self.repo.repo_path.clone());
let f_name = path.file_name().unwrap().to_str().unwrap();
let api_service = MonoApiService {
let mono_api_service = MonoApiService {
context: self.context.clone(),
};
let req = CreateFileInfo {
is_directory: true,
name: f_name.to_owned(),
path: path.parent().unwrap().to_str().unwrap().to_owned(),
content: None,
};
let storage = self.context.services.mega_storage.clone();
let save_trees = mono_api_service.search_and_create_tree(&path).await?;

let mut root_ref = storage.get_ref("/").await.unwrap().unwrap();
let new_commit = Commit::from_tree_id(
save_trees[save_trees.len() - 1].id,
vec![SHA1::from_str(&root_ref.ref_commit_hash).unwrap()],
&format!(
"push thrid-part crates {:?} commit",
path.file_name().unwrap()
),
);

let save_trees: Vec<mega_tree::ActiveModel> = save_trees
.into_iter()
.map(|tree| {
let mut model: mega_tree::Model = tree.into();
model.commit_id = new_commit.id.to_plain_str();
model.into()
})
.collect();

batch_save_model(storage.get_connection(), save_trees)
.await
.unwrap();

root_ref.ref_commit_hash = new_commit.id.to_plain_str();
root_ref.ref_tree_hash = new_commit.tree_id.to_plain_str();
storage.update_ref(root_ref).await.unwrap();
storage.save_mega_commits(vec![new_commit]).await.unwrap();
Ok(())
}
}

if (api_service.create_monorepo_file(req).await).is_ok() {}
#[cfg(test)]
mod test {
use std::path::PathBuf;
#[test]
pub fn test_recurse_tree() {
let path = PathBuf::from("/third-part/crates/tokio/tokio-console");
let ancestors: Vec<_> = path.ancestors().collect();
for path in ancestors.into_iter() {
println!("{:?}", path);
}
}
}