From 19c1578320ef98d76c3e758316d8774ac51a47fe Mon Sep 17 00:00:00 2001 From: edef Date: Tue, 10 May 2022 01:32:17 +0000 Subject: ripple/fossil: permit importing trees from git repos Change-Id: I8329f14bddaaa2d141e82c087821e4602bd1259a --- ripple/fossil/Cargo.toml | 1 + ripple/fossil/src/lib.rs | 57 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) (limited to 'ripple/fossil') diff --git a/ripple/fossil/Cargo.toml b/ripple/fossil/Cargo.toml index 2ff2288..663919f 100644 --- a/ripple/fossil/Cargo.toml +++ b/ripple/fossil/Cargo.toml @@ -15,6 +15,7 @@ bytes = "1.0.1" clap = { version = "3.1.15", features = ["derive"] } env_logger = "0.9.0" fuser = "0.11.0" +git2 = "0.14.3" lazy_static = "1.4.0" libc = "0.2.112" log = "0.4.14" 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) -> DirectoryRef { let d = self.add_directory_inner(path.as_ref()); self.flush(); -- cgit 1.4.1