use serde::{Deserialize, Serialize}; use crate::service::GitService; use crate::service::cache::{self, IMMUTABLE_TTL}; use crate::share::errors::{GitError, map_baby}; #[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)] pub struct PatchDto { pub content: String, pub size: i64, } #[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)] pub struct ParsedPatchDto { pub files: Vec, pub additions: i64, pub deletions: i64, } #[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)] pub struct AppliedPatchDto { pub applied: bool, pub conflicts: Vec, } impl GitService { pub async fn patch_generate( &self, space_name: String, repo_name: String, base: String, head: String, ) -> Result { let ctx = self.context(space_name, repo_name).await?; let baby = self.baby(&ctx); let left = baby.rev_parse(&base).await.map_err(map_baby)?; let right = baby.rev_parse(&head).await.map_err(map_baby)?; let key = format!("repo.{}.patch_generate.{}.{}", ctx.model.id, left, right); cache::cached_fetch(&ctx.cache, &key, IMMUTABLE_TTL, || async { let body = baby .raw_diff( &crate::rpcgit::diff::types::DiffRequest { left, right }, None, ) .await .map_err(map_baby)?; let size = body.len() as i64; Ok(PatchDto { content: body, size, }) }) .await } pub async fn patch_parse(&self, content: String) -> Result { let mut files: Vec = Vec::new(); let mut additions = 0i64; let mut deletions = 0i64; for line in content.lines() { if let Some(rest) = line.strip_prefix("+++ b/") { if rest != "/dev/null" { files.push(rest.to_string()); } } else if let Some(rest) = line.strip_prefix("--- a/") { if rest == "/dev/null" && !files.iter().any(|f| f == "unknown") { files.push("unknown".to_string()); } } else if line.starts_with("+") && !line.starts_with("+++") { additions += 1; } else if line.starts_with("-") && !line.starts_with("---") { deletions += 1; } } files.sort(); files.dedup(); Ok(ParsedPatchDto { files, additions, deletions, }) } pub async fn patch_apply( &self, _space_name: String, _repo_name: String, _patch: String, _base: String, ) -> Result { Err(GitError::Unimplemented( "applying patches requires a KenShell PatchService", )) } }