summaryrefslogtreecommitdiff
path: root/server/common
diff options
context:
space:
mode:
Diffstat (limited to 'server/common')
-rw-r--r--server/common/src/git.rs68
-rw-r--r--server/common/src/tests.rs53
2 files changed, 121 insertions, 0 deletions
diff --git a/server/common/src/git.rs b/server/common/src/git.rs
index c6a44e3..053ff3f 100644
--- a/server/common/src/git.rs
+++ b/server/common/src/git.rs
@@ -64,6 +64,20 @@ pub struct User {
pub username: String,
}
+#[derive(Debug, PartialEq)]
+pub enum ObjectType {
+ BLOB,
+ COMMIT,
+ TREE,
+}
+
+#[derive(Debug, PartialEq)]
+pub struct TreeEntry {
+ pub object_type: ObjectType,
+ pub object_name: String,
+ pub path: String,
+}
+
fn io_err(action: &str, e: std::io::Error) -> Error {
Error::new(format!("{action}: {e}"))
}
@@ -80,6 +94,34 @@ fn parse_user(output: String) -> User {
}
}
+fn parse_tree_entries(output: String) -> Vec<TreeEntry> {
+ let mut ret = Vec::new();
+ for line in output.split_terminator('\0') {
+ let mut parts = line.split_terminator('\t');
+ let mut parts2 = parts.next().unwrap_or("").split_terminator(' ');
+ parts2.next(); // object mode
+ let object_type = match parts2.next() {
+ Some(value) => match value {
+ "blob" => ObjectType::BLOB,
+ "commit" => ObjectType::COMMIT,
+ "tree" => ObjectType::TREE,
+ _ => continue,
+ },
+ None => continue,
+ };
+ if let Some(object_name) = parts2.next() {
+ if let Some(path) = parts.next() {
+ ret.push(TreeEntry {
+ object_type,
+ object_name: object_name.to_string(),
+ path: path.to_string(),
+ });
+ }
+ }
+ }
+ ret
+}
+
impl RepoData {
fn new() -> Self {
Self {
@@ -342,6 +384,21 @@ impl RepoData {
self.run(&mut cmd).await
}
+ async fn ls_tree(
+ &self,
+ repo: &Repository,
+ commit: &str,
+ recursive: bool,
+ ) -> Result<Vec<TreeEntry>, Error> {
+ let mut cmd = self.git_cmd(repo);
+ cmd.arg("ls-tree").arg("-z");
+ if recursive {
+ cmd.arg("-r");
+ }
+ cmd.arg(commit);
+ self.output(&mut cmd).map_ok(parse_tree_entries).await
+ }
+
async fn get_log_format(
&self,
repo: &Repository,
@@ -594,4 +651,15 @@ impl Repository {
data.delete_branch(self, branch.as_str()).await
}
+
+ pub async fn ls_tree(
+ &self,
+ commit: impl Into<String>,
+ recursive: bool,
+ ) -> Result<Vec<TreeEntry>, Error> {
+ let commit = commit.into();
+ let data = self.lock.read().await;
+
+ data.ls_tree(self, commit.as_str(), recursive).await
+ }
}
diff --git a/server/common/src/tests.rs b/server/common/src/tests.rs
index 09e780b..34cc315 100644
--- a/server/common/src/tests.rs
+++ b/server/common/src/tests.rs
@@ -205,6 +205,53 @@ async fn git_get_author_commiter(repo: &git::Repository) {
assert!(repo.get_author("<invalid>").await.is_err());
}
+async fn git_ls_tree(repo: &git::Repository) {
+ let t1 = repo
+ .ls_tree("d7c502b9c6b833060576a0c4da0287933d603011", false)
+ .await
+ .unwrap();
+ assert_eq!(
+ t1,
+ vec![
+ git::TreeEntry {
+ object_type: git::ObjectType::BLOB,
+ object_name: "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391".to_string(),
+ path: "empty".to_string(),
+ },
+ git::TreeEntry {
+ object_type: git::ObjectType::BLOB,
+ object_name: "d393216eb885c4b4ec91b691dd59a88c846d881d".to_string(),
+ path: "phrase".to_string(),
+ },
+ ]
+ );
+
+ let t2 = repo
+ .ls_tree("2cecdec660a30bf3964cee645d9cee03640ef8dc", false)
+ .await
+ .unwrap();
+ assert_eq!(
+ t2,
+ vec![
+ git::TreeEntry {
+ object_type: git::ObjectType::BLOB,
+ object_name: "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391".to_string(),
+ path: "empty".to_string(),
+ },
+ git::TreeEntry {
+ object_type: git::ObjectType::BLOB,
+ object_name: "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391".to_string(),
+ path: "foo".to_string(),
+ },
+ git::TreeEntry {
+ object_type: git::ObjectType::BLOB,
+ object_name: "d393216eb885c4b4ec91b691dd59a88c846d881d".to_string(),
+ path: "phrase".to_string(),
+ },
+ ]
+ );
+}
+
async fn git_fetch(bare: bool) -> git::Repository {
let path = testdir!().join("repo");
let remote_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("src/testdata/bare");
@@ -289,6 +336,12 @@ async fn test_git_bare_delete_branch() {
}
#[tokio::test]
+async fn test_git_ls_tree() {
+ let repo = BARE.get_or_init(|| git_setup(true)).await;
+ git_ls_tree(repo).await;
+}
+
+#[tokio::test]
async fn test_grit_parse_base() {
let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("src/testdata/grit/base.grd");
let grit = grit::parse_grit(path).await.unwrap();