diff --git a/giterated-daemon/src/backend/git.rs b/giterated-daemon/src/backend/git.rs index eba4a42..345cdda 100644 --- a/giterated-daemon/src/backend/git.rs +++ b/giterated-daemon/src/backend/git.rs @@ -148,6 +148,8 @@ pub enum GitBackendError { FailedOpeningFromDisk(git2::Error), #[error("Couldn't find ref with name `{0}`")] RefNotFound(String), + #[error("Couldn't find repository head")] + HeadNotFound, #[error("Couldn't find path in repository `{0}`")] PathNotFound(String), #[error("Couldn't find commit for path `{0}`")] @@ -344,6 +346,74 @@ impl GitBackend { Ok(revwalk.count()) } + + pub fn get_oid_from_reference( + git: &git2::Repository, + rev: Option<&str>, + ) -> anyhow::Result { + // Try and parse the input as a reference and get the object ID + let mut tree_id = match rev { + None => { + if let Ok(head) = git.head() { + // TODO: Fix for symbolic references + head.target() + } else { + // Nothing in database, render empty tree. + return Err(GitBackendError::HeadNotFound.into()); + } + } + Some(rev_name) => { + // Find the reference, otherwise return GitBackendError + git.refname_to_id(rev_name).ok() + } + }; + + // If the reference wasn't found, try parsing it as a commit ID + if tree_id.is_none() { + if let Ok(oid) = git2::Oid::from_str(rev.as_ref().unwrap()) { + tree_id = Some(oid) + } + } + + // If the commit ID wasn't found, try parsing it as a branch and otherwise return error + if tree_id.is_none() { + match git.find_branch(rev.as_ref().unwrap(), BranchType::Local) { + Ok(branch) => tree_id = branch.get().target(), + Err(_) => { + return Err(Box::new(GitBackendError::RefNotFound( + rev.unwrap().to_string(), + )) + .into()) + } + } + } + + // Should be safe? + Ok(tree_id.unwrap()) + } + + /// Gets the last commit in a rev + pub fn get_last_commit_in_rev( + git: &git2::Repository, + rev: &str, + ) -> anyhow::Result { + let oid = Self::get_oid_from_reference(git, Some(rev))?; + + // Walk through the repository commit graph starting at our rev + let mut revwalk = git.revwalk()?; + revwalk.set_sorting(git2::Sort::TIME)?; + revwalk.push(oid)?; + + if let Some(commit_oid) = revwalk.next() { + if let Ok(commit_oid) = commit_oid { + if let Ok(commit) = git.find_commit(commit_oid).map_err(|_| GitBackendError::CommitNotFound(commit_oid.to_string())) { + return Ok(Commit::from(commit)); + } + } + } + + Err(GitBackendError::RefNotFound(oid.to_string()).into()) + } } #[async_trait] @@ -524,46 +594,11 @@ impl RepositoryBackend for GitBackend { .open_repository_and_check_permissions(&repository.owner, &repository.name, requester) .await?; - // Try and parse the input as a reference and get the object ID - let mut tree_id = match &request.rev { - None => { - if let Ok(head) = git.head() { - // TODO: Fix for symbolic references - head.target() - } else { - // Nothing in database, render empty tree. - return Ok(vec![]); - } - } - Some(rev_name) => { - // Find the reference, otherwise return GitBackendError - git.refname_to_id(rev_name).ok() - } - }; - - // If the reference wasn't found, try parsing it as a commit ID - if tree_id.is_none() { - if let Ok(oid) = git2::Oid::from_str(request.rev.as_ref().unwrap()) { - tree_id = Some(oid) - } - } - - // If the commit ID wasn't found, try parsing it as a branch and otherwise return error - if tree_id.is_none() { - match git.find_branch(request.rev.as_ref().unwrap(), BranchType::Local) { - Ok(branch) => tree_id = branch.get().target(), - Err(_) => { - return Err(Box::new(GitBackendError::RefNotFound( - request.rev.clone().unwrap(), - )) - .into()) - } - } - } + let tree_id = Self::get_oid_from_reference(&git, request.rev.as_ref().map(|s| s.as_str()))?; // unwrap might be dangerous? // Get the commit from the oid - let commit = git.find_commit(tree_id.unwrap()).unwrap(); + let commit = git.find_commit(tree_id).unwrap(); // this is stupid let mut current_path = request.rev.clone().unwrap_or_else(|| "master".to_string()); @@ -681,50 +716,11 @@ impl RepositoryBackend for GitBackend { .open_repository_and_check_permissions(&repository.owner, &repository.name, requester) .await?; - // TODO: Remove duplicate code with repository_file_inspect, most of it is duplicate. - // Try and parse the input as a reference and get the object ID - let mut tree_id = match &request.rev { - None => { - if let Ok(head) = git.head() { - // TODO: Fix for symbolic references - head.target() - } else { - // Nothing in database, render empty tree. - return Err(Box::new(GitBackendError::RefNotFound( - request.rev.clone().unwrap(), - )) - .into()); - } - } - Some(rev_name) => { - // Find the reference, otherwise return GitBackendError - git.refname_to_id(rev_name).ok() - } - }; - - // If the reference wasn't found, try parsing it as a commit ID - if tree_id.is_none() { - if let Ok(oid) = git2::Oid::from_str(request.rev.as_ref().unwrap()) { - tree_id = Some(oid) - } - } - - // If the commit ID wasn't found, try parsing it as a branch and otherwise return error - if tree_id.is_none() { - match git.find_branch(request.rev.as_ref().unwrap(), BranchType::Local) { - Ok(branch) => tree_id = branch.get().target(), - Err(_) => { - return Err(Box::new(GitBackendError::RefNotFound( - request.rev.clone().unwrap(), - )) - .into()) - } - } - } + let tree_id = Self::get_oid_from_reference(&git, request.rev.as_ref().map(|s| s.as_str()))?; // unwrap might be dangerous? // Get the commit from the oid - let commit = git.find_commit(tree_id.unwrap()).unwrap(); + let commit = git.find_commit(tree_id).unwrap(); // this is stupid let mut current_path = request.rev.clone().unwrap_or_else(|| "master".to_string()); @@ -811,50 +807,11 @@ impl RepositoryBackend for GitBackend { .open_repository_and_check_permissions(&repository.owner, &repository.name, requester) .await?; - // TODO: Remove duplicate code with repository_file_inspect, most of it is duplicate. - // Try and parse the input as a reference and get the object ID - let mut tree_id = match &request.rev { - None => { - if let Ok(head) = git.head() { - // TODO: Fix for symbolic references - head.target() - } else { - // Nothing in database, render empty tree. - return Err(Box::new(GitBackendError::RefNotFound( - request.rev.clone().unwrap(), - )) - .into()); - } - } - Some(rev_name) => { - // Find the reference, otherwise return GitBackendError - git.refname_to_id(rev_name).ok() - } - }; - - // If the reference wasn't found, try parsing it as a commit ID - if tree_id.is_none() { - if let Ok(oid) = git2::Oid::from_str(request.rev.as_ref().unwrap()) { - tree_id = Some(oid) - } - } - - // If the commit ID wasn't found, try parsing it as a branch and otherwise return error - if tree_id.is_none() { - match git.find_branch(request.rev.as_ref().unwrap(), BranchType::Local) { - Ok(branch) => tree_id = branch.get().target(), - Err(_) => { - return Err(Box::new(GitBackendError::RefNotFound( - request.rev.clone().unwrap(), - )) - .into()) - } - } - } + let tree_id = Self::get_oid_from_reference(&git, request.rev.as_ref().map(|s| s.as_str()))?; // unwrap might be dangerous? // Get the commit from the oid - let commit = git.find_commit(tree_id.unwrap()).unwrap(); + let commit = git.find_commit(tree_id).unwrap(); // Count the amount of branches and tags let mut branches = 0; @@ -888,7 +845,6 @@ impl RepositoryBackend for GitBackend { let mut branches = vec![]; - // TODO: Add details like stale and such for branch in git.branches(None)? { let branch = branch?; @@ -896,7 +852,13 @@ impl RepositoryBackend for GitBackend { continue; }; - branches.push(RepositoryBranch { name: name.to_string() }) + // TODO: Non UTF-8? + let commit = GitBackend::get_last_commit_in_rev(&git, branch.0.get().name().unwrap()).ok(); + + // TODO: Implement stale with configurable age + let mut stale = false; + + branches.push(RepositoryBranch {name:name.to_string(), stale, last_commit: commit }) } Ok(branches) diff --git a/giterated-models/src/repository/mod.rs b/giterated-models/src/repository/mod.rs index 7d87dca..a998b0f 100644 --- a/giterated-models/src/repository/mod.rs +++ b/giterated-models/src/repository/mod.rs @@ -155,6 +155,10 @@ pub struct RepositoryStatistics { pub struct RepositoryBranch { /// Full reference name pub name: String, + /// Whether the repository is stale or not + pub stale: bool, + /// The last commit made to the branch + pub last_commit: Option, } #[derive(Clone, Debug, Serialize, Deserialize)]