summaryrefslogtreecommitdiff
path: root/server/common/src/git.rs
diff options
context:
space:
mode:
Diffstat (limited to 'server/common/src/git.rs')
-rw-r--r--server/common/src/git.rs61
1 files changed, 58 insertions, 3 deletions
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<Vec<u8>>,
+}
+
+impl GitFile {
+ pub fn new(data: Vec<u8>) -> Self {
+ GitFile {
+ cursor: Cursor::new(data),
+ }
+ }
+}
+
+impl Read for GitFile {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ 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><remote branch>:<local branch>
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<GitFile, Error> {
+ 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<String, Error> {
+ 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<Vec<u8>, 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<String>,
+ ) -> Result<GitFile, Error> {
+ let object_name = object_name.into();
+ let data = self.lock.read().await;
+
+ data.cat_file(self, object_type, object_name.as_str()).await
+ }
}