sley_ref_filter/
contents.rs1use sley_core::{GitError, ObjectFormat, ObjectId, Result};
4use sley_object::{Commit, EncodedObject, ObjectType, Tag};
5use std::borrow::Cow;
6use std::io::Write;
7
8#[derive(Clone)]
9pub struct ForEachRefContents<'a> {
10 pub message: Cow<'a, [u8]>,
11 pub tree: Option<ObjectId>,
12 pub parents: Vec<ObjectId>,
13 pub tag: Option<Cow<'a, [u8]>>,
14 pub tag_object_type: Option<ObjectType>,
15 pub tag_object: Option<ObjectId>,
16 pub author: Option<Cow<'a, [u8]>>,
17 pub committer: Option<Cow<'a, [u8]>>,
18 pub tagger: Option<Cow<'a, [u8]>>,
19 pub creator: Option<Cow<'a, [u8]>>,
20}
21
22impl ForEachRefContents<'_> {
23 pub fn into_owned(self) -> ForEachRefContents<'static> {
24 ForEachRefContents {
25 message: Cow::Owned(self.message.into_owned()),
26 tree: self.tree,
27 parents: self.parents,
28 tag: self.tag.map(|tag| Cow::Owned(tag.into_owned())),
29 tag_object_type: self.tag_object_type,
30 tag_object: self.tag_object,
31 author: self.author.map(|author| Cow::Owned(author.into_owned())),
32 committer: self
33 .committer
34 .map(|committer| Cow::Owned(committer.into_owned())),
35 tagger: self.tagger.map(|tagger| Cow::Owned(tagger.into_owned())),
36 creator: self.creator.map(|creator| Cow::Owned(creator.into_owned())),
37 }
38 }
39}
40
41pub fn for_each_ref_contents<'a>(
42 format: ObjectFormat,
43 object: &'a EncodedObject,
44) -> Result<Option<ForEachRefContents<'a>>> {
45 let contents = match object.object_type {
46 ObjectType::Commit => {
47 let commit = Commit::parse_ref(format, &object.body)?;
48 ForEachRefContents {
49 message: Cow::Borrowed(commit.message),
50 tree: Some(commit.tree),
51 parents: commit.parents,
52 tag: None,
53 tag_object_type: None,
54 tag_object: None,
55 author: Some(Cow::Borrowed(commit.author)),
56 committer: Some(Cow::Borrowed(commit.committer)),
57 tagger: None,
58 creator: Some(Cow::Borrowed(commit.committer)),
59 }
60 }
61 ObjectType::Tag => {
62 let tag = Tag::parse_ref(format, &object.body)?;
63 ForEachRefContents {
64 message: Cow::Borrowed(tag.message),
65 tree: None,
66 parents: Vec::new(),
67 tag: Some(Cow::Borrowed(tag.name)),
68 tag_object_type: Some(tag.object_type),
69 tag_object: Some(tag.object),
70 author: None,
71 committer: None,
72 tagger: tag.tagger.map(Cow::Borrowed),
73 creator: tag.tagger.map(Cow::Borrowed),
74 }
75 }
76 _ => return Ok(None),
77 };
78 Ok(Some(contents))
79}
80
81pub fn for_each_ref_validate_tag_pointer(
82 tag_oid: &ObjectId,
83 contents: &ForEachRefContents<'_>,
84 target_oid: &ObjectId,
85 target: &EncodedObject,
86) -> Result<()> {
87 if contents
88 .tag_object_type
89 .is_some_and(|object_type| object_type != target.object_type)
90 {
91 eprintln!("error: bad tag pointer to {target_oid} in {tag_oid}");
92 return Err(GitError::Exit(128));
93 }
94 Ok(())
95}
96
97pub struct ForEachRefPeeledObject<'a> {
98 pub oid: ObjectId,
99 pub object_type: ObjectType,
100 pub object_body: Cow<'a, [u8]>,
101 pub object_size: usize,
102 pub object_disk_size: Option<u64>,
103 pub tree: Option<ObjectId>,
104 pub parents: Vec<ObjectId>,
105 pub message: Option<Cow<'a, [u8]>>,
106 pub author: Option<Cow<'a, [u8]>>,
107 pub committer: Option<Cow<'a, [u8]>>,
108 pub creator: Option<Cow<'a, [u8]>>,
109}
110
111pub fn write_for_each_ref_contents_lines(
112 stdout: &mut impl Write,
113 message: &[u8],
114 count: usize,
115) -> Result<()> {
116 let mut lines = message.split(|byte| *byte == b'\n').collect::<Vec<_>>();
117 if lines.last().is_some_and(|line| line.is_empty()) {
118 lines.pop();
119 }
120 for (idx, line) in lines.into_iter().take(count).enumerate() {
121 if idx > 0 {
122 stdout.write_all(b"\n ")?;
123 }
124 stdout.write_all(line)?;
125 }
126 Ok(())
127}