commit.rs
1 use std::path::Path; 2 use std::str; 3 4 use base64::{prelude::BASE64_STANDARD, Engine}; 5 use radicle_surf as surf; 6 use serde_json::{json, Value}; 7 8 pub(crate) struct Commit<'a>(&'a surf::Commit); 9 10 impl<'a> Commit<'a> { 11 pub fn new(commit: &'a surf::Commit) -> Self { 12 Self(commit) 13 } 14 15 pub fn as_json(&self) -> Value { 16 json!({ 17 "id": self.0.id, 18 "author": { 19 "name": self.0.author.name, 20 "email": self.0.author.email 21 }, 22 "summary": self.0.summary, 23 "description": self.0.description(), 24 "parents": self.0.parents, 25 "committer": { 26 "name": self.0.committer.name, 27 "email": self.0.committer.email, 28 "time": self.0.committer.time.seconds() 29 } 30 }) 31 } 32 } 33 34 pub(crate) struct Blob<'a, T: AsRef<[u8]>>(&'a surf::blob::Blob<T>); 35 36 impl<'a, T: AsRef<[u8]>> Blob<'a, T> { 37 pub fn new(blob: &'a surf::blob::Blob<T>) -> Self { 38 Self(blob) 39 } 40 41 pub fn as_json(&self, path: &str) -> Value { 42 let content = match str::from_utf8(self.0.content()) { 43 Ok(s) => s.to_owned(), 44 Err(_) => BASE64_STANDARD.encode(self.0.content()), 45 }; 46 47 json!({ 48 "binary": self.0.is_binary(), 49 "name": name_in_path(path), 50 "content": content, 51 "path": path, 52 "lastCommit": Commit(self.0.commit()).as_json() 53 }) 54 } 55 } 56 57 pub(crate) struct Tree<'a>(&'a surf::tree::Tree); 58 59 impl<'a> Tree<'a> { 60 pub fn new(tree: &'a surf::tree::Tree) -> Self { 61 Self(tree) 62 } 63 64 pub fn as_json(&self, path: &str) -> Value { 65 let prefix = Path::new(path); 66 let entries = self 67 .0 68 .entries() 69 .iter() 70 .map(|entry| { 71 json!({ 72 "path": prefix.join(entry.name()), 73 "oid": entry.object_id(), 74 "name": entry.name(), 75 "kind": match entry.entry() { 76 surf::tree::EntryKind::Tree(_) => "tree", 77 surf::tree::EntryKind::Blob(_) => "blob", 78 surf::tree::EntryKind::Submodule { .. } => "submodule" 79 }, 80 }) 81 }) 82 .collect::<Vec<_>>(); 83 84 json!({ 85 "entries": &entries, 86 "lastCommit": Commit::new(self.0.commit()).as_json(), 87 "name": name_in_path(path), 88 "path": path, 89 }) 90 } 91 } 92 93 /// Returns the name part of a path string. 94 fn name_in_path(path: &str) -> &str { 95 match path.rsplit('/').next() { 96 Some(name) => name, 97 None => path, 98 } 99 }