From 2b54f5c51ff9a26d4077037631ed39d62ed2b3fb Mon Sep 17 00:00:00 2001 From: Joel Klinghed Date: Thu, 12 Jun 2025 09:11:18 +0200 Subject: Initial support for translation reviews --- server/common/src/git.rs | 61 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 3 deletions(-) (limited to 'server/common/src/git.rs') diff --git a/server/common/src/git.rs b/server/common/src/git.rs index 8fe7863..e396d8a 100644 --- a/server/common/src/git.rs +++ b/server/common/src/git.rs @@ -4,6 +4,7 @@ use futures::future::TryFutureExt; use pathdiff::diff_paths; use std::collections::HashMap; use std::fmt; +use std::io::{self, Cursor, Read}; use std::path::{Path, PathBuf}; use std::process::Stdio; use tokio::fs; @@ -78,6 +79,24 @@ pub struct TreeEntry { pub path: String, } +pub struct GitFile { + cursor: Cursor>, +} + +impl GitFile { + pub fn new(data: Vec) -> Self { + GitFile { + cursor: Cursor::new(data), + } + } +} + +impl Read for GitFile { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.cursor.read(buf) + } +} + fn io_err(action: &str, e: std::io::Error) -> Error { Error::new(format!("{action}: {e}")) } @@ -161,6 +180,8 @@ impl RepoData { cmd.arg("--porcelain"); // This option disables this automatic tag following. cmd.arg("--no-tags"); + // Write out refs even if they didn't change + cmd.arg("--verbose"); cmd.arg("origin"); // <+ force update>: cmd.arg(format!("+{branch}:{branch}")); @@ -430,6 +451,23 @@ impl RepoData { self.output(&mut cmd).map_ok(parse_tree_entries).await } + async fn cat_file( + &self, + repo: &Repository, + object_type: ObjectType, + object_name: &str, + ) -> Result { + let mut cmd = self.git_cmd(repo); + cmd.arg("cat-file") + .arg(match object_type { + ObjectType::BLOB => "blob", + ObjectType::COMMIT => "commit", + ObjectType::TREE => "tree", + }) + .arg(object_name); + self.raw_output(&mut cmd).map_ok(GitFile::new).await + } + async fn get_log_format( &self, repo: &Repository, @@ -516,6 +554,14 @@ impl RepoData { } async fn output(&self, cmd: &mut Command) -> Result { + match self.raw_output(cmd).await { + Ok(bytes) => String::from_utf8(bytes) + .map_err(|e| Error::new(format!("git command had invalid output: {e}"))), + Err(e) => Err(e), + } + } + + async fn raw_output(&self, cmd: &mut Command) -> Result, Error> { cmd.stdin(Stdio::null()) .stdout(Stdio::piped()) .stderr(Stdio::piped()); @@ -530,9 +576,7 @@ impl RepoData { .await?; if output.status.success() { - let output_utf8 = String::from_utf8(output.stdout) - .map_err(|e| Error::new(format!("git command had invalid output: {e}")))?; - Ok(output_utf8) + Ok(output.stdout) } else { Err(Error::new(format!( "git command failed with exitcode: {}\n{:?}\n{}", @@ -693,4 +737,15 @@ impl Repository { data.ls_tree(self, commit.as_str(), recursive).await } + + pub async fn cat_file( + &self, + object_type: ObjectType, + object_name: impl Into, + ) -> Result { + let object_name = object_name.into(); + let data = self.lock.read().await; + + data.cat_file(self, object_type, object_name.as_str()).await + } } -- cgit v1.2.3-70-g09d2