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