Add ahead_behind comparison, filter and range to branches request.
parent: tbd commit: 3aca035
1 | use Error; |
2 | use async_trait; |
3 | |
4 | use BranchType; |
5 | use ; |
6 | |
7 | use |
8 | AccessList, Commit, DefaultBranch, Description, IssueLabel, Repository, RepositoryBranch, |
9 | RepositoryBranchesRequest, RepositoryChunkLine, RepositoryCommitBeforeRequest, |
10 | RepositoryCommitFromIdRequest, RepositoryDiff, RepositoryDiffFile, RepositoryDiffFileChunk, |
11 | RepositoryDiffFileInfo, RepositoryDiffFileStatus, RepositoryDiffPatchRequest, |
12 | RepositoryDiffRequest, RepositoryFile, RepositoryFileFromIdRequest, |
13 | RepositoryFileFromPathRequest, RepositoryFileInspectRequest, RepositoryIssue, |
14 | RepositoryIssueLabelsRequest, RepositoryIssuesCountRequest, RepositoryIssuesRequest, |
15 | RepositoryLastCommitOfFileRequest, RepositoryObjectType, RepositoryStatistics, |
16 | RepositoryStatisticsRequest, RepositoryTreeEntry, RepositoryVisibility, Visibility, RepositoryBranchFilter, |
17 | ; |
18 | |
19 | use User; |
20 | |
21 | use ; |
22 | |
23 | use PgPool; |
24 | use Deref; |
25 | use |
26 | , |
27 | , | Arc
28 | ; |
29 | use Error; |
30 | use OnceCell; |
31 | |
32 | use ; |
33 | |
34 | // TODO: Handle this |
35 | //region database structures |
36 | |
37 | /// Repository in the database |
38 | |
39 | |
40 | #[sqlx(try_from = "String")] |
41 | pub owner_user: User, |
42 | pub name: String, |
43 | pub description: , |
44 | pub visibility: RepositoryVisibility, |
45 | pub default_branch: String, |
46 | |
47 | |
48 | |
49 | // Separate function because "Private" will be expanded later |
50 | /// Checks if the user is allowed to view this repository |
51 | pub async |
52 | &self, |
53 | our_instance: &Instance, |
54 | user: & , |
55 | stack: &GiteratedStack, |
56 | |
57 | if matches! |
58 | return true; |
59 | |
60 | |
61 | // User must exist for any further checks to pass |
62 | let user = match user |
63 | Some => user, |
64 | None => return false, |
65 | ; |
66 | |
67 | if *user.deref == self.owner_user |
68 | // owner can always view |
69 | return true; |
70 | |
71 | |
72 | if matches! |
73 | // Check if the user can view\ |
74 | let access_list = stack |
75 | . |
76 | owner: self.owner_user.clone, |
77 | name: self.name.clone, |
78 | instance: our_instance.clone, |
79 | |
80 | .await |
81 | .unwrap; |
82 | |
83 | access_list |
84 | .0 |
85 | .iter |
86 | .any |
87 | else |
88 | false |
89 | |
90 | |
91 | |
92 | // This is in it's own function because I assume I'll have to add logic to this later |
93 | |
94 | &self, |
95 | repository_directory: &str, |
96 | |
97 | match open |
98 | "{}/{}/{}/{}" |
99 | repository_directory, self.owner_user.instance, self.owner_user.username, self.name |
100 | ) |
101 | Ok => Ok, |
102 | Err => |
103 | let err = FailedOpeningFromDisk; |
104 | error!; |
105 | |
106 | Err |
107 | |
108 | |
109 | |
110 | |
111 | |
112 | //endregion |
113 | |
114 | |
115 | |
116 | |
117 | FailedCreatingRepository, |
118 | |
119 | FailedInsertingIntoDatabase, |
120 | |
121 | RepositoryNotFound , |
122 | |
123 | RepositoryAlreadyExists , |
124 | |
125 | CouldNotDeleteFromDisk, |
126 | |
127 | FailedDeletingFromDatabase, |
128 | |
129 | FailedOpeningFromDisk, |
130 | |
131 | RefNotFound, |
132 | |
133 | HeadNotFound, |
134 | |
135 | PathNotFound, |
136 | |
137 | LastCommitNotFound, |
138 | |
139 | InvalidObjectId, |
140 | |
141 | BlobNotFound, |
142 | |
143 | TreeNotFound, |
144 | |
145 | CommitNotFound, |
146 | |
147 | CommitParentNotFound, |
148 | |
149 | FailedDiffing, |
150 | |
151 | |
152 | |
153 | pub pg_pool: PgPool, |
154 | pub repository_folder: String, |
155 | pub instance: Instance, |
156 | pub stack: , |
157 | |
158 | |
159 | |
160 | |
161 | pg_pool: &PgPool, |
162 | repository_folder: &str, |
163 | instance: impl , |
164 | stack: , |
165 | |
166 | let instance = instance.to_owned; |
167 | |
168 | Self |
169 | pg_pool: pg_pool.clone, |
170 | repository_folder: repository_folder.to_string, |
171 | instance, |
172 | stack, |
173 | |
174 | |
175 | |
176 | pub async |
177 | &self, |
178 | user: &User, |
179 | repository_name: &str, |
180 | |
181 | if let Ok = query_as! |
182 | r#"SELECT owner_user, name, description, visibility as "visibility: _", default_branch FROM repositories WHERE owner_user = $1 AND name = $2"#, |
183 | user.to_string, repository_name |
184 | .fetch_one |
185 | .await |
186 | Ok |
187 | else |
188 | Err |
189 | owner_user: user.to_string, |
190 | name: repository_name.to_string, |
191 | |
192 | |
193 | |
194 | |
195 | pub async |
196 | &self, |
197 | user: &User, |
198 | repository_name: &str, |
199 | |
200 | if let Err = remove_dir_all |
201 | "{}/{}/{}/{}" |
202 | self.repository_folder, user.instance, user.username, repository_name |
203 | ) |
204 | let err = CouldNotDeleteFromDisk; |
205 | error! |
206 | "Couldn't delete repository from disk, this is bad! {:?}", |
207 | err |
208 | ; |
209 | |
210 | return Err; |
211 | |
212 | |
213 | // Delete the repository from the database |
214 | match query! |
215 | "DELETE FROM repositories WHERE owner_user = $1 AND name = $2", |
216 | user.to_string, |
217 | repository_name |
218 | |
219 | .execute |
220 | .await |
221 | |
222 | Ok => Ok, |
223 | Err => Err, |
224 | |
225 | |
226 | |
227 | pub async |
228 | &self, |
229 | owner: &User, |
230 | name: &str, |
231 | requester: & , |
232 | |
233 | let repository = match self |
234 | .find_by_owner_user_name |
235 | // &request.owner.instance.url, |
236 | owner, name, |
237 | |
238 | .await |
239 | |
240 | Ok => repository, |
241 | Err => return Err, |
242 | ; |
243 | |
244 | if let Some = requester |
245 | if !repository |
246 | .can_user_view_repository |
247 | &self.instance, |
248 | &Some, |
249 | self.stack.get .unwrap, |
250 | |
251 | .await |
252 | |
253 | return Err |
254 | owner_user: repository.owner_user.to_string, |
255 | name: repository.name.clone, |
256 | ; |
257 | |
258 | else if matches! |
259 | // Unauthenticated users can never view private repositories |
260 | |
261 | return Err |
262 | owner_user: repository.owner_user.to_string, |
263 | name: repository.name.clone, |
264 | ; |
265 | |
266 | |
267 | match repository.open_git2_repository |
268 | Ok => Ok, |
269 | Err => Err, |
270 | |
271 | |
272 | |
273 | // TODO: Find where this fits |
274 | // TODO: Cache this and general repository tree and invalidate select files on push |
275 | // TODO: Find better and faster technique for this |
276 | |
277 | path: &str, |
278 | git: & Repository, |
279 | start_commit: & Commit, |
280 | |
281 | trace!; |
282 | |
283 | let mut revwalk = git.revwalk?; |
284 | revwalk.set_sorting?; |
285 | revwalk.push?; |
286 | |
287 | for oid in revwalk |
288 | let oid = oid?; |
289 | let commit = git.find_commit?; |
290 | |
291 | // Merge commits have 2 or more parents |
292 | // Commits with 0 parents are handled different because we can't diff against them |
293 | if commit.parent_count == 0 |
294 | return Ok; |
295 | else if commit.parent_count == 1 |
296 | let tree = commit.tree?; |
297 | let last_tree = commit.parent?.tree?; |
298 | |
299 | // Get the diff between the current tree and the last one |
300 | let diff = git.diff_tree_to_tree?; |
301 | |
302 | for dd in diff.deltas |
303 | // Get the path of the current file we're diffing against |
304 | let current_path = dd.new_file .path .unwrap; |
305 | |
306 | // Path or directory |
307 | if current_path.eq || current_path.starts_with |
308 | return Ok; |
309 | |
310 | |
311 | |
312 | |
313 | |
314 | Err? |
315 | |
316 | |
317 | /// Gets the total amount of commits using revwalk |
318 | |
319 | git: & Repository, |
320 | start_commit: & Commit, |
321 | |
322 | // TODO: There must be a better way |
323 | let mut revwalk = git.revwalk?; |
324 | revwalk.set_sorting?; |
325 | revwalk.push?; |
326 | |
327 | Ok |
328 | |
329 | |
330 | |
331 | git: & Repository, |
332 | rev: , |
333 | |
334 | // Try and parse the input as a reference and get the object ID |
335 | let mut tree_id = match rev |
336 | None => |
337 | if let Ok = git.head |
338 | // TODO: Fix for symbolic references |
339 | head.target |
340 | else |
341 | // Nothing in database, render empty tree. |
342 | return Err; |
343 | |
344 | |
345 | Some => |
346 | // Find the reference, otherwise return GitBackendError |
347 | git.refname_to_id .ok |
348 | |
349 | ; |
350 | |
351 | // If the reference wasn't found, try parsing it as a commit ID |
352 | if tree_id.is_none |
353 | if let Ok = from_str |
354 | tree_id = Some |
355 | |
356 | |
357 | |
358 | // If the commit ID wasn't found, try parsing it as a branch and otherwise return error |
359 | if tree_id.is_none |
360 | match git.find_branch |
361 | Ok => tree_id = branch.get .target, |
362 | Err => |
363 | return Err |
364 | Box new .into, |
365 | |
366 | |
367 | |
368 | |
369 | |
370 | // Should be safe? |
371 | Ok |
372 | |
373 | |
374 | /// Gets the last commit in a rev |
375 | |
376 | let oid = Self get_oid_from_reference?; |
377 | |
378 | // Walk through the repository commit graph starting at our rev |
379 | let mut revwalk = git.revwalk?; |
380 | revwalk.set_sorting?; |
381 | revwalk.push?; |
382 | |
383 | if let Some = revwalk.next |
384 | if let Ok = git |
385 | .find_commit |
386 | .map_err |
387 | |
388 | return Ok; |
389 | |
390 | |
391 | |
392 | Err |
393 | |
394 | |
395 | |
396 | |
397 | |
398 | async |
399 | &mut self, |
400 | requester: & , |
401 | repository: &Repository, |
402 | |
403 | if let Ok = self |
404 | .find_by_owner_user_name |
405 | .await |
406 | |
407 | Ok |
408 | .can_user_view_repository |
409 | .await |
410 | else |
411 | Ok |
412 | |
413 | |
414 | |
415 | async |
416 | &mut self, |
417 | _user: &AuthenticatedUser, |
418 | request: &RepositoryCreateRequest, |
419 | |
420 | // Check if repository already exists in the database |
421 | if let Ok = self |
422 | .find_by_owner_user_name |
423 | .await |
424 | |
425 | let err = RepositoryAlreadyExists |
426 | owner_user: repository.owner_user.to_string, |
427 | name: repository.name, |
428 | ; |
429 | error!; |
430 | |
431 | return Err; |
432 | |
433 | |
434 | // Insert the repository into the database |
435 | let _ = match query_as! |
436 | r#"INSERT INTO repositories VALUES ($1, $2, $3, $4, $5) RETURNING owner_user, name, description, visibility as "visibility: _", default_branch"#, |
437 | request.owner.to_string, request.name, request.description, request.visibility as _, "master" |
438 | .fetch_one |
439 | .await |
440 | Ok => repository, |
441 | Err => |
442 | let err = FailedInsertingIntoDatabase; |
443 | error!; |
444 | |
445 | return Err; |
446 | |
447 | ; |
448 | |
449 | // Create bare (server side) repository on disk |
450 | match init_bare |
451 | "{}/{}/{}/{}" |
452 | self.repository_folder, request.owner.instance, request.owner.username, request.name |
453 | ) |
454 | Ok => |
455 | debug! |
456 | "Created new repository with the name {}/{}/{}", |
457 | request.owner.instance, request.owner.username, request.name |
458 | ; |
459 | |
460 | let stack = self.stack.get .unwrap; |
461 | |
462 | let repository = Repository |
463 | owner: request.owner.clone, |
464 | name: request.name.clone, |
465 | instance: request.instance.as_ref .unwrap_or .clone, |
466 | ; |
467 | |
468 | stack |
469 | .write_setting |
470 | &repository, |
471 | Description, |
472 | |
473 | .await |
474 | .unwrap; |
475 | |
476 | stack |
477 | .write_setting |
478 | .await |
479 | .unwrap; |
480 | |
481 | stack |
482 | .write_setting |
483 | .await |
484 | .unwrap; |
485 | |
486 | Ok |
487 | |
488 | Err => |
489 | let err = FailedCreatingRepository; |
490 | error!; |
491 | |
492 | // Delete repository from database |
493 | self.delete_by_owner_user_name |
494 | .await?; |
495 | |
496 | // ??? |
497 | Err |
498 | |
499 | |
500 | |
501 | |
502 | async |
503 | &mut self, |
504 | requester: & , |
505 | repository: &Repository, |
506 | request: &RepositoryFileInspectRequest, |
507 | |
508 | let git = self |
509 | .open_repository_and_check_permissions |
510 | .await?; |
511 | |
512 | // Try and find the tree_id/branch |
513 | let tree_id = Self get_oid_from_reference?; |
514 | |
515 | // Get the commit from the oid |
516 | let commit = match git.find_commit |
517 | Ok => commit, |
518 | // If the commit isn't found, it's generally safe to assume the tree is empty. |
519 | Err => return Ok, |
520 | ; |
521 | |
522 | // this is stupid |
523 | let rev = request.rev.clone .unwrap_or_else; |
524 | let mut current_path = rev.clone; |
525 | |
526 | // Get the commit tree |
527 | let git_tree = if let Some = &request.path |
528 | // Add it to our full path string |
529 | current_path.push_str; |
530 | // Get the specified path, return an error if it wasn't found. |
531 | let entry = match commit |
532 | .tree |
533 | .unwrap |
534 | .get_path |
535 | .map_err |
536 | |
537 | Ok => entry, |
538 | Err => return Err, |
539 | ; |
540 | // Turn the entry into a git tree |
541 | entry.to_object .unwrap .as_tree .unwrap .clone |
542 | else |
543 | commit.tree .unwrap |
544 | ; |
545 | |
546 | // Iterate over the git tree and collect it into our own tree types |
547 | let mut tree = git_tree |
548 | .iter |
549 | .map |
550 | let object_type = match entry.kind .unwrap |
551 | => Tree, | Tree
552 | => Blob, | Blob
553 | _ => unreachable!, |
554 | ; |
555 | let mut tree_entry = new |
556 | entry.id .to_string .as_str, |
557 | entry.name .unwrap, |
558 | object_type, |
559 | entry.filemode, |
560 | ; |
561 | |
562 | if request.extra_metadata |
563 | // Get the file size if It's a blob |
564 | let object = entry.to_object .unwrap; |
565 | if let Some = object.as_blob |
566 | tree_entry.size = Some; |
567 | |
568 | |
569 | // Get the path to the folder the file is in by removing the rev from current_path |
570 | let mut path = current_path.replace; |
571 | if path.starts_with |
572 | path.remove; |
573 | |
574 | |
575 | // Format it as the path + file name |
576 | let full_path = if path.is_empty |
577 | entry.name .unwrap .to_string |
578 | else |
579 | format! |
580 | ; |
581 | |
582 | // Get the last commit made to the entry |
583 | if let Ok = |
584 | get_last_commit_of_file |
585 | |
586 | tree_entry.last_commit = Some; |
587 | |
588 | |
589 | |
590 | tree_entry |
591 | |
592 | .; |
593 | |
594 | // Sort the tree alphabetically and with tree first |
595 | tree.sort_unstable_by_key; |
596 | tree.sort_unstable_by_key |
597 | Reverse |
598 | ; |
599 | |
600 | Ok |
601 | |
602 | |
603 | async |
604 | &mut self, |
605 | requester: & , |
606 | repository: &Repository, |
607 | request: &RepositoryFileFromIdRequest, |
608 | |
609 | let git = self |
610 | .open_repository_and_check_permissions |
611 | .await?; |
612 | |
613 | // Parse the passed object id |
614 | let oid = match from_str |
615 | Ok => oid, |
616 | Err => |
617 | return Err |
618 | |
619 | ; |
620 | |
621 | // Find the file and turn it into our own struct |
622 | let file = match git.find_blob |
623 | Ok => RepositoryFile |
624 | id: blob.id .to_string, |
625 | content: blob.content .to_vec, |
626 | binary: blob.is_binary, |
627 | size: blob.size, |
628 | , |
629 | Err => return Err, |
630 | ; |
631 | |
632 | Ok |
633 | |
634 | |
635 | async |
636 | &mut self, |
637 | requester: & , |
638 | repository: &Repository, |
639 | request: &RepositoryFileFromPathRequest, |
640 | |
641 | let git = self |
642 | .open_repository_and_check_permissions |
643 | .await?; |
644 | |
645 | let tree_id = Self get_oid_from_reference?; |
646 | |
647 | // unwrap might be dangerous? |
648 | // Get the commit from the oid |
649 | let commit = git.find_commit .unwrap; |
650 | |
651 | // this is stupid |
652 | let mut current_path = request.rev.clone .unwrap_or_else; |
653 | |
654 | // Add it to our full path string |
655 | current_path.push_str; |
656 | // Get the specified path, return an error if it wasn't found. |
657 | let entry = match commit |
658 | .tree |
659 | .unwrap |
660 | .get_path |
661 | .map_err |
662 | |
663 | Ok => entry, |
664 | Err => return Err, |
665 | ; |
666 | |
667 | // Find the file and turn it into our own struct |
668 | let file = match git.find_blob |
669 | Ok => RepositoryFile |
670 | id: blob.id .to_string, |
671 | content: blob.content .to_vec, |
672 | binary: blob.is_binary, |
673 | size: blob.size, |
674 | , |
675 | Err => |
676 | return Err |
677 | |
678 | ; |
679 | |
680 | Ok |
681 | |
682 | |
683 | async |
684 | &mut self, |
685 | requester: & , |
686 | repository: &Repository, |
687 | request: &RepositoryCommitFromIdRequest, |
688 | |
689 | let git = self |
690 | .open_repository_and_check_permissions |
691 | .await?; |
692 | |
693 | // Parse the passed object ids |
694 | let oid = from_str |
695 | .map_err?; |
696 | |
697 | // Get the commit from the oid |
698 | let commit = git |
699 | .find_commit |
700 | .map_err?; |
701 | |
702 | Ok |
703 | |
704 | |
705 | async |
706 | &mut self, |
707 | requester: & , |
708 | repository: &Repository, |
709 | request: &RepositoryLastCommitOfFileRequest, |
710 | |
711 | let git = self |
712 | .open_repository_and_check_permissions |
713 | .await?; |
714 | |
715 | // Parse the passed object ids |
716 | let oid = from_str |
717 | .map_err?; |
718 | |
719 | // Get the commit from the oid |
720 | let commit = git |
721 | .find_commit |
722 | .map_err?; |
723 | |
724 | // Find the last commit of the file |
725 | let commit = get_last_commit_of_file?; |
726 | |
727 | Ok |
728 | |
729 | |
730 | async |
731 | &mut self, |
732 | requester: & , |
733 | repository: &Repository, |
734 | request: &RepositoryStatisticsRequest, |
735 | |
736 | let git = self |
737 | .open_repository_and_check_permissions |
738 | .await?; |
739 | |
740 | let tree_id = Self get_oid_from_reference?; |
741 | |
742 | // Count the amount of branches and tags |
743 | let mut branches = 0; |
744 | let mut tags = 0; |
745 | if let Ok = git.references |
746 | for reference in references.flatten |
747 | if reference.is_branch |
748 | branches += 1; |
749 | else if reference.is_tag |
750 | tags += 1; |
751 | |
752 | |
753 | |
754 | |
755 | // Attempt to get the commit from the oid |
756 | let commits = if let Ok = git.find_commit |
757 | // Get the total commit count if we found the tree oid commit |
758 | ? | get_total_commit_count
759 | else |
760 | 0 |
761 | ; |
762 | |
763 | Ok |
764 | commits, |
765 | branches, |
766 | tags, |
767 | |
768 | |
769 | |
770 | async |
771 | &mut self, |
772 | requester: & , |
773 | repository: &Repository, |
774 | request: &RepositoryBranchesRequest, |
775 | |
776 | let git = self |
777 | .open_repository_and_check_permissions |
778 | .await?; |
779 | |
780 | // Could be done better with the RepositoryBranchFilter::None check done beforehand. |
781 | let mut filtered_branches = git.branches?.filter_map |
782 | let branch = branch.ok?.0; |
783 | |
784 | let Some = branch.name .ok .flatten else |
785 | return None; |
786 | ; |
787 | |
788 | // TODO: Non UTF-8? |
789 | let Some = get_last_commit_in_rev .ok else |
790 | return None; |
791 | ; |
792 | |
793 | // TODO: Implement stale with configurable age |
794 | let stale = false; |
795 | |
796 | // Filter based on if the branch is stale or not |
797 | if request.filter != None |
798 | |
799 | if stale && request.filter == Active |
800 | return None; |
801 | else if !stale && request.filter == Stale |
802 | return None; |
803 | |
804 | |
805 | |
806 | Some |
807 | ; | .
808 | |
809 | // Sort the branches by commit date |
810 | filtered_branches.sort_by; |
811 | // Go to the requested position |
812 | let mut filtered_branches = filtered_branches.iter .skip; |
813 | |
814 | let head = git.head?; |
815 | let mut branches = vec!; |
816 | |
817 | // Iterate through the filtered branches using the passed range |
818 | for _ in request.range.0..request.range.1 |
819 | let Some = filtered_branches.next else |
820 | break; |
821 | ; |
822 | |
823 | // Get how many commits are ahead of and behind of the head |
824 | let ahead_behind_head = if head.target .is_some && branch.get .target .is_some |
825 | git.graph_ahead_behind .ok |
826 | else |
827 | None |
828 | ; |
829 | |
830 | branches.push |
831 | |
832 | |
833 | Ok |
834 | |
835 | |
836 | async |
837 | &mut self, |
838 | requester: & , |
839 | repository: &Repository, |
840 | request: &RepositoryDiffRequest, |
841 | |
842 | let git = self |
843 | .open_repository_and_check_permissions |
844 | .await?; |
845 | |
846 | // Parse the passed object ids |
847 | let oid_old = from_str |
848 | .map_err?; |
849 | let oid_new = from_str |
850 | .map_err?; |
851 | |
852 | // Get the ids associates commits |
853 | let commit_old = git |
854 | .find_commit |
855 | .map_err?; |
856 | let commit_new = git |
857 | .find_commit |
858 | .map_err?; |
859 | |
860 | // Get the commit trees |
861 | let tree_old = commit_old |
862 | .tree |
863 | .map_err?; |
864 | let tree_new = commit_new |
865 | .tree |
866 | .map_err?; |
867 | |
868 | // Diff the two trees against each other |
869 | let diff = git |
870 | .diff_tree_to_tree |
871 | .map_err |
872 | FailedDiffing |
873 | ?; |
874 | |
875 | // Should be safe to unwrap? |
876 | let stats = diff.stats .unwrap; |
877 | let mut files: = vec!; |
878 | |
879 | diff.deltas .enumerate .for_each |
880 | // Parse the old file info from the delta |
881 | let old_file_info = match delta.old_file .exists |
882 | true => Some |
883 | id: delta.old_file .id .to_string, |
884 | path: delta |
885 | .old_file |
886 | .path |
887 | .unwrap |
888 | .to_str |
889 | .unwrap |
890 | .to_string, |
891 | size: delta.old_file .size, |
892 | binary: delta.old_file .is_binary, |
893 | , |
894 | false => None, |
895 | ; |
896 | // Parse the new file info from the delta |
897 | let new_file_info = match delta.new_file .exists |
898 | true => Some |
899 | id: delta.new_file .id .to_string, |
900 | path: delta |
901 | .new_file |
902 | .path |
903 | .unwrap |
904 | .to_str |
905 | .unwrap |
906 | .to_string, |
907 | size: delta.new_file .size, |
908 | binary: delta.new_file .is_binary, |
909 | , |
910 | false => None, |
911 | ; |
912 | |
913 | let mut chunks: = vec!; |
914 | if let Some = from_diff .ok .flatten |
915 | for chunk_num in 0..patch.num_hunks |
916 | if let Ok = patch.hunk |
917 | let mut lines: = vec!; |
918 | |
919 | for line_num in 0..chunk_num_lines |
920 | if let Ok = patch.line_in_hunk |
921 | if let Ok = String from_utf8 |
922 | lines.push |
923 | change_type: line.origin_value .into, |
924 | content: line_utf8, |
925 | old_line_num: line.old_lineno, |
926 | new_line_num: line.new_lineno, |
927 | ; |
928 | |
929 | |
930 | continue; |
931 | |
932 | |
933 | |
934 | chunks.push |
935 | header: String from_utf8 .ok, |
936 | old_start: chunk.old_start, |
937 | old_lines: chunk.old_lines, |
938 | new_start: chunk.new_start, |
939 | new_lines: chunk.new_lines, |
940 | lines, |
941 | ; |
942 | |
943 | |
944 | ; |
945 | |
946 | let file = RepositoryDiffFile |
947 | status: from, |
948 | old_file_info, |
949 | new_file_info, |
950 | chunks, |
951 | ; |
952 | |
953 | files.push; |
954 | ; |
955 | |
956 | Ok |
957 | new_commit: from, |
958 | files_changed: stats.files_changed, |
959 | insertions: stats.insertions, |
960 | deletions: stats.deletions, |
961 | files, |
962 | |
963 | |
964 | |
965 | async |
966 | &mut self, |
967 | requester: & , |
968 | repository: &Repository, |
969 | request: &RepositoryDiffPatchRequest, |
970 | |
971 | let git = self |
972 | .open_repository_and_check_permissions |
973 | .await?; |
974 | |
975 | // Parse the passed object ids |
976 | let oid_old = from_str |
977 | .map_err?; |
978 | let oid_new = from_str |
979 | .map_err?; |
980 | |
981 | // Get the ids associates commits |
982 | let commit_old = git |
983 | .find_commit |
984 | .map_err?; |
985 | let commit_new = git |
986 | .find_commit |
987 | .map_err?; |
988 | |
989 | // Get the commit trees |
990 | let tree_old = commit_old |
991 | .tree |
992 | .map_err?; |
993 | let tree_new = commit_new |
994 | .tree |
995 | .map_err?; |
996 | |
997 | // Diff the two trees against each other |
998 | let diff = git |
999 | .diff_tree_to_tree |
1000 | .map_err |
1001 | FailedDiffing |
1002 | ?; |
1003 | |
1004 | // Print the entire patch |
1005 | let mut patch = String new; |
1006 | |
1007 | diff.print |
1008 | match line.origin |
1009 | '+' | '-' | ' ' => patch.push, |
1010 | _ => |
1011 | |
1012 | patch.push_str; |
1013 | true |
1014 | |
1015 | .unwrap; |
1016 | |
1017 | Ok |
1018 | |
1019 | |
1020 | async |
1021 | &mut self, |
1022 | requester: & , |
1023 | repository: &Repository, |
1024 | request: &RepositoryCommitBeforeRequest, |
1025 | |
1026 | let git = self |
1027 | .open_repository_and_check_permissions |
1028 | .await?; |
1029 | |
1030 | // Parse the passed object id |
1031 | let oid = match from_str |
1032 | Ok => oid, |
1033 | Err => |
1034 | return Err |
1035 | |
1036 | ; |
1037 | |
1038 | // Find the commit using the parsed oid |
1039 | let commit = match git.find_commit |
1040 | Ok => commit, |
1041 | Err => return Err, |
1042 | ; |
1043 | |
1044 | // Get the first parent it has |
1045 | let parent = commit.parent; |
1046 | if let Ok = parent |
1047 | return Ok; |
1048 | else |
1049 | // TODO: See if can be done better |
1050 | // Walk through the repository commit graph starting at our current commit |
1051 | let mut revwalk = git.revwalk?; |
1052 | revwalk.set_sorting?; |
1053 | revwalk.push?; |
1054 | |
1055 | if let Some = revwalk.next |
1056 | // Find the commit using the parsed oid |
1057 | if let Ok = git.find_commit |
1058 | return Ok; |
1059 | |
1060 | |
1061 | |
1062 | Err |
1063 | |
1064 | |
1065 | |
1066 | |
1067 | |
1068 | |
1069 | &mut self, |
1070 | _requester: & , |
1071 | _request: &RepositoryIssuesCountRequest, |
1072 | |
1073 | todo! |
1074 | |
1075 | |
1076 | |
1077 | &mut self, |
1078 | _requester: & , |
1079 | _request: &RepositoryIssueLabelsRequest, |
1080 | |
1081 | todo! |
1082 | |
1083 | |
1084 | |
1085 | &mut self, |
1086 | _requester: & , |
1087 | _request: &RepositoryIssuesRequest, |
1088 | |
1089 | todo! |
1090 | |
1091 | |
1092 | |
1093 | |
1094 | |
1095 | |
1096 | pub repository: String, |
1097 | pub name: String, |
1098 | pub value: String, |
1099 | |
1100 |