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
128 changes: 94 additions & 34 deletions ceres/src/api_service/import_api_service.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
use std::collections::HashMap;
use std::collections::HashSet;
use std::collections::VecDeque;
use std::path::Component;
use std::path::Path;
use std::path::PathBuf;

use async_trait::async_trait;

use jupiter::context::Context;
use mercury::errors::GitError;
use mercury::hash::SHA1;
use mercury::internal::object::commit::Commit;
use mercury::internal::object::tree::Tree;
use mercury::internal::object::tree::TreeItem;
Expand Down Expand Up @@ -91,6 +93,15 @@ impl ApiHandler for ImportApiService {
.into()
}

async fn get_commit_by_hash(&self, hash: &str) -> Option<Commit> {
let storage = self.context.services.git_db_storage.clone();
let commit = storage
.get_commit_by_hash(self.repo.repo_id, hash)
.await
.unwrap();
commit.map(|x| x.into())
}

async fn get_tree_relate_commit(&self, t_hash: &str) -> Commit {
let storage = self.context.services.git_db_storage.clone();
let tree_info = storage
Expand All @@ -106,36 +117,6 @@ impl ApiHandler for ImportApiService {
.into()
}

async fn add_trees_to_map(
&self,
item_to_commit: &mut HashMap<String, String>,
hashes: Vec<String>,
) {
let storage = self.context.services.git_db_storage.clone();
let trees = storage
.get_trees_by_hashes(self.repo.repo_id, hashes)
.await
.unwrap();
for tree in trees {
item_to_commit.insert(tree.tree_id, tree.commit_id);
}
}

async fn add_blobs_to_map(
&self,
item_to_commit: &mut HashMap<String, String>,
hashes: Vec<String>,
) {
let storage = self.context.services.git_db_storage.clone();
let blobs = storage
.get_blobs_by_hashes(self.repo.repo_id, hashes)
.await
.unwrap();
for blob in blobs {
item_to_commit.insert(blob.blob_id, blob.commit_id);
}
}

async fn get_commits_by_hashes(&self, c_hashes: Vec<String>) -> Result<Vec<Commit>, GitError> {
let storage = self.context.services.git_db_storage.clone();
let commits = storage
Expand All @@ -145,6 +126,29 @@ impl ApiHandler for ImportApiService {
Ok(commits.into_iter().map(|x| x.into()).collect())
}

async fn item_to_commit_map(
&self,
path: PathBuf,
) -> Result<HashMap<TreeItem, Option<Commit>>, GitError> {
let mut cache = GitObjectCache::default();
let root_commit = self.get_root_commit().await;
match self.search_tree_by_path(&path).await? {
Some(tree) => {
let mut result: HashMap<TreeItem, Option<Commit>> = HashMap::new();
for item in tree.tree_items {
let commit = self
.traverse_commit_history(&path, &root_commit, &item, &mut cache)
.await;
result.insert(item, Some(commit));
}
Ok(result)
}
None => Ok(HashMap::new()),
}
}
}

impl ImportApiService {
async fn traverse_commit_history(
&self,
path: &Path,
Expand All @@ -166,20 +170,76 @@ impl ApiHandler for ImportApiService {
.await
.unwrap();
if reachable {
let mut p_ids = vec![];
for p_id in commit.parent_commit_ids.clone() {
if !visited.contains(&p_id) {
p_ids.push(p_id.to_string());
let p_commit = self.get_commit_from_cache(p_id, cache).await.unwrap();
p_stack.push_back(p_commit);
visited.insert(p_id);
}
}
if target_commit.committer.timestamp > commit.committer.timestamp {
target_commit = commit.clone();
}
let parent_commits = self.get_commits_by_hashes(p_ids).await.unwrap();
p_stack.extend(parent_commits);
}
}
target_commit
}

async fn get_tree_from_cache(&self, oid: SHA1, cache: &mut GitObjectCache) -> Tree {
if let Some(tree) = cache.trees.get(&oid) {
return tree.clone();
}
let tree = self.get_tree_by_hash(&oid.to_string()).await;
cache.trees.insert(oid, tree.clone());
tree
}

async fn get_commit_from_cache(
&self,
oid: SHA1,
cache: &mut GitObjectCache,
) -> Result<Commit, GitError> {
if let Some(commit) = cache.commits.get(&oid) {
return Ok(commit.clone());
}
match self.get_commit_by_hash(&oid.to_string()).await {
Some(c) => {
cache.commits.insert(oid, c.clone());
Ok(c)
}
None => Err(GitError::InvalidCommitObject),
}
}

async fn reachable_in_tree(
&self,
root_tree: &Tree,
path: &Path,
target: &TreeItem,
cache: &mut GitObjectCache,
) -> Result<bool, GitError> {
let relative_path = self.strip_relative(path).unwrap();
let mut search_tree = root_tree.clone();
// first find search tree by path
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 {
search_tree = self.get_tree_from_cache(search_res.id, cache).await;
} else {
return Ok(false);
}
}
}
// check item exist under search tree
if search_tree.tree_items.iter().any(|x| x == target) {
return Ok(true);
}
Ok(false)
}
}
Loading
Loading