summary refs log tree commit diff
path: root/ripple/fossil/src
diff options
context:
space:
mode:
authoredef <edef@unfathomable.blue>2022-05-10 01:32:17 +0000
committeredef <edef@unfathomable.blue>2022-05-10 01:32:17 +0000
commit19c1578320ef98d76c3e758316d8774ac51a47fe (patch)
treef1d3b5296ce5e44d5474ba0248b22fb5585b3d65 /ripple/fossil/src
parent96d28a91c4b71e6b78f8b9061866f91b2684b19b (diff)
downloadunf-legacy-19c1578320ef98d76c3e758316d8774ac51a47fe.tar.zst
ripple/fossil: permit importing trees from git repos
Change-Id: I8329f14bddaaa2d141e82c087821e4602bd1259a
Diffstat (limited to 'ripple/fossil/src')
-rw-r--r--ripple/fossil/src/lib.rs57
1 files changed, 57 insertions, 0 deletions
diff --git a/ripple/fossil/src/lib.rs b/ripple/fossil/src/lib.rs
index 007a771..b3a1c3d 100644
--- a/ripple/fossil/src/lib.rs
+++ b/ripple/fossil/src/lib.rs
@@ -14,6 +14,7 @@ use {
 		io::{self, Read, Write},
 		os::unix::{fs::PermissionsExt, prelude::FileExt},
 		path::Path,
+		str,
 	},
 };
 
@@ -74,6 +75,62 @@ impl Store {
 		self.meta.flush().unwrap();
 	}
 
+	pub fn add_git_tree(&self, repo: &git2::Repository, tree: git2::Oid) -> DirectoryRef {
+		let tree = repo.find_tree(tree).unwrap();
+		let d = self.add_git_tree_inner(repo, &tree);
+		self.flush();
+		d
+	}
+
+	fn add_git_tree_inner(&self, repo: &git2::Repository, tree: &git2::Tree) -> DirectoryRef {
+		let mut d = Directory::new();
+		let mut size: u32 = 0;
+
+		for entry in tree {
+			let name = entry.name().expect("invalid UTF-8");
+			let object = entry.to_object(repo).unwrap();
+			let kind = entry.kind().unwrap();
+			let mode = entry.filemode();
+
+			let child = match kind {
+				git2::ObjectType::Tree => {
+					let tree = object.as_tree().unwrap();
+					Node::Directory(self.add_git_tree_inner(repo, tree))
+				}
+				git2::ObjectType::Blob if mode == 0o120000 => {
+					let target = object.as_blob().unwrap().content();
+					let target = str::from_utf8(target).unwrap();
+					Node::Link {
+						target: target.to_owned(),
+					}
+				}
+				git2::ObjectType::Blob => {
+					let executable = match mode {
+						0o100644 => true,
+						0o100755 => false,
+						_ => panic!("unexpected mode: {:o} for file {:?}", mode, name),
+					};
+
+					let data = object.as_blob().unwrap().content();
+					Node::File(FileRef {
+						ident: self.write_blob(data),
+						size: data.len() as u32,
+						executable,
+					})
+				}
+				kind => panic!("unexpected object kind: {:?}", kind),
+			};
+
+			size = size.checked_add(child.size()).expect("overflow");
+			d.children.insert(name.to_owned(), child);
+		}
+
+		let blob = d.into_pb().encode_to_vec();
+		let ident = self.write_blob(&blob);
+
+		DirectoryRef { ident, size }
+	}
+
 	pub fn add_directory(&self, path: impl AsRef<Path>) -> DirectoryRef {
 		let d = self.add_directory_inner(path.as_ref());
 		self.flush();