JavaScript is disabled, refresh for a better experience. ambee/giterated

ambee/giterated

Git repository hosting, collaboration, and discovery for the Fediverse.

Move towards having GitBackend split into files

Emilia - ⁨1⁩ year ago

parent: tbd commit: ⁨e55da0e

⁨giterated-daemon/src/backend/git/tags.rs⁩ - ⁨5058⁩ bytes
Raw
1 use anyhow::Error;
2 use giterated_models::{
3 object::Object,
4 repository::{Commit, CommitSignature, Repository, RepositoryTag, RepositoryTagsRequest},
5 };
6 use giterated_stack::{AuthenticatedUser, GiteratedStack, OperationState, StackOperationState};
7
8 use super::GitBackend;
9
10 impl GitBackend {
11 /// .0: List of tags in passed range
12 /// .1: Total amount of tags
13 pub async fn handle_repository_get_tags(
14 &mut self,
15 requester: &Option<AuthenticatedUser>,
16 repository_object: &mut Object<'_, StackOperationState, Repository, GiteratedStack>,
17 OperationState(_operation_state): OperationState<StackOperationState>,
18 request: &RepositoryTagsRequest,
19 ) -> Result<(Vec<RepositoryTag>, usize), Error> {
20 let repository = repository_object.object();
21 let git = self
22 .open_repository_and_check_permissions(&repository.owner, &repository.name, requester)
23 .await?;
24
25 let mut tags = vec![];
26
27 // Iterate over each tag
28 let _ = git.tag_foreach(|id, name| {
29 // Get the name in utf8
30 let name = String::from_utf8_lossy(name).replacen("refs/tags/", "", 1);
31
32 // Find the tag so we can get the messages attached if any
33 if let Ok(tag) = git.find_tag(id) {
34 // Get the tag message and split it into a summary and body
35 let (summary, body) = if let Some(message) = tag.message() {
36 // Iterate over the lines
37 let mut lines = message
38 .lines()
39 .map(|line| {
40 // Trim the whitespace for every line
41 let mut whitespace_removed = String::with_capacity(line.len());
42
43 line.split_whitespace().for_each(|word| {
44 if !whitespace_removed.is_empty() {
45 whitespace_removed.push(' ');
46 }
47
48 whitespace_removed.push_str(word);
49 });
50
51 whitespace_removed
52 })
53 .collect::<Vec<String>>();
54
55 let summary = Some(lines.remove(0));
56 let body = if lines.is_empty() {
57 None
58 } else {
59 Some(lines.join("\n"))
60 };
61
62 (summary, body)
63 } else {
64 (None, None)
65 };
66
67 // Get the commit the tag is (possibly) pointing to
68 let commit = tag
69 .peel()
70 .map(|obj| obj.into_commit().ok())
71 .ok()
72 .flatten()
73 .map(|c| Commit::from(c));
74 // Get the author of the tag
75 let author: Option<CommitSignature> = tag.tagger().map(|s| s.into());
76 // Get the time the tag or pointed commit was created
77 let time = if let Some(ref author) = author {
78 Some(author.time)
79 } else {
80 // Get possible commit time if the tag has no author time
81 commit.as_ref().map(|c| c.time.clone())
82 };
83
84 tags.push(RepositoryTag {
85 id: id.to_string(),
86 name: name.to_string(),
87 summary,
88 body,
89 author,
90 time,
91 commit,
92 });
93 } else {
94 // Lightweight commit, we try and find the commit it's pointing to
95 let commit = git.find_commit(id).ok().map(|c| Commit::from(c));
96
97 tags.push(RepositoryTag {
98 id: id.to_string(),
99 name: name.to_string(),
100 summary: None,
101 body: None,
102 author: None,
103 time: commit.as_ref().map(|c| c.time.clone()),
104 commit,
105 });
106 };
107
108 true
109 });
110
111 // Get the total amount of tags
112 let tag_count = tags.len();
113
114 if let Some(search) = &request.search {
115 // TODO: Caching
116 // Search by sorting using a simple fuzzy search algorithm
117 tags.sort_by(|n1, n2| {
118 strsim::damerau_levenshtein(search, &n1.name)
119 .cmp(&strsim::damerau_levenshtein(search, &n2.name))
120 });
121 } else {
122 // Sort the tags using their creation or pointer date
123 tags.sort_by(|t1, t2| t2.time.cmp(&t1.time));
124 }
125
126 // Get the requested range of tags
127 let tags = tags
128 .into_iter()
129 .skip(request.range.0)
130 .take(request.range.1.saturating_sub(request.range.0))
131 .collect::<Vec<RepositoryTag>>();
132
133 Ok((tags, tag_count))
134 }
135 }
136