Register GetSetting as an operation
parent: tbd commit: 6a85805
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 | RepositoryBranchFilter, 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 | |
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 | pg_pool: PgPool, |
154 | repository_folder: String, |
155 | instance: Instance, |
156 | 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 | // We make sure there's no end slash |
171 | repository_folder: repository_folder.trim_end_matches .to_string, |
172 | instance, |
173 | stack, |
174 | |
175 | |
176 | |
177 | pub async |
178 | &self, |
179 | user: &User, |
180 | repository_name: &str, |
181 | |
182 | // TODO: Patch for use with new GetValue system |
183 | if let Ok = query_as! |
184 | r#"SELECT owner_user, name, description, visibility as "visibility: _", default_branch FROM repositories WHERE owner_user = $1 AND name = $2"#, |
185 | user.to_string, repository_name |
186 | .fetch_one |
187 | .await |
188 | Ok |
189 | else |
190 | Err |
191 | owner_user: user.to_string, |
192 | name: repository_name.to_string, |
193 | |
194 | |
195 | |
196 | |
197 | pub async |
198 | &self, |
199 | user: &User, |
200 | repository_name: &str, |
201 | |
202 | if let Err = remove_dir_all |
203 | "{}/{}/{}/{}" |
204 | self.repository_folder, user.instance, user.username, repository_name |
205 | ) |
206 | let err = CouldNotDeleteFromDisk; |
207 | error! |
208 | "Couldn't delete repository from disk, this is bad! {:?}", |
209 | err |
210 | ; |
211 | |
212 | return Err; |
213 | |
214 | |
215 | // Delete the repository from the database |
216 | self.delete_from_database .await |
217 | |
218 | |
219 | /// Deletes the repository from the database |
220 | pub async |
221 | &self, |
222 | user: &User, |
223 | repository_name: &str, |
224 | |
225 | match query! |
226 | "DELETE FROM repositories WHERE owner_user = $1 AND name = $2", |
227 | user.to_string, |
228 | repository_name |
229 | |
230 | .execute |
231 | .await |
232 | |
233 | Ok => Ok, |
234 | Err => Err, |
235 | |
236 | |
237 | |
238 | pub async |
239 | &self, |
240 | owner: &User, |
241 | name: &str, |
242 | requester: & , |
243 | |
244 | let repository = match self |
245 | .find_by_owner_user_name |
246 | // &request.owner.instance.url, |
247 | owner, name, |
248 | |
249 | .await |
250 | |
251 | Ok => repository, |
252 | Err => return Err, |
253 | ; |
254 | |
255 | if let Some = requester |
256 | if !repository |
257 | .can_user_view_repository |
258 | &self.instance, |
259 | &Some, |
260 | self.stack.get .unwrap, |
261 | |
262 | .await |
263 | |
264 | return Err |
265 | owner_user: repository.owner_user.to_string, |
266 | name: repository.name.clone, |
267 | ; |
268 | |
269 | else if matches! |
270 | // Unauthenticated users can never view private repositories |
271 | |
272 | return Err |
273 | owner_user: repository.owner_user.to_string, |
274 | name: repository.name.clone, |
275 | ; |
276 | |
277 | |
278 | match repository.open_git2_repository |
279 | Ok => Ok, |
280 | Err => Err, |
281 | |
282 | |
283 | |
284 | // TODO: Find where this fits |
285 | // TODO: Cache this and general repository tree and invalidate select files on push |
286 | // TODO: Find better and faster technique for this |
287 | |
288 | path: &str, |
289 | git: & Repository, |
290 | start_commit: & Commit, |
291 | |
292 | trace!; |
293 | |
294 | let mut revwalk = git.revwalk?; |
295 | revwalk.set_sorting?; |
296 | revwalk.push?; |
297 | |
298 | for oid in revwalk |
299 | let oid = oid?; |
300 | let commit = git.find_commit?; |
301 | |
302 | // Merge commits have 2 or more parents |
303 | // Commits with 0 parents are handled different because we can't diff against them |
304 | if commit.parent_count == 0 |
305 | return Ok; |
306 | else if commit.parent_count == 1 |
307 | let tree = commit.tree?; |
308 | let last_tree = commit.parent?.tree?; |
309 | |
310 | // Get the diff between the current tree and the last one |
311 | let diff = git.diff_tree_to_tree?; |
312 | |
313 | for dd in diff.deltas |
314 | // Get the path of the current file we're diffing against |
315 | let current_path = dd.new_file .path .unwrap; |
316 | |
317 | // Path or directory |
318 | if current_path.eq || current_path.starts_with |
319 | return Ok; |
320 | |
321 | |
322 | |
323 | |
324 | |
325 | Err? |
326 | |
327 | |
328 | /// Gets the total amount of commits using revwalk |
329 | |
330 | git: & Repository, |
331 | start_commit: & Commit, |
332 | |
333 | // TODO: There must be a better way |
334 | let mut revwalk = git.revwalk?; |
335 | revwalk.set_sorting?; |
336 | revwalk.push?; |
337 | |
338 | Ok |
339 | |
340 | |
341 | /// Attempts to get the oid in this order: |
342 | /// 1. Full refname (refname_to_id) |
343 | /// 2. Short branch name (find_branch) |
344 | /// 3. Other (revparse_single) |
345 | |
346 | git: & Repository, |
347 | rev: , |
348 | |
349 | // If the rev is None try and get the repository head |
350 | let Some = rev else |
351 | if let Ok = git.head |
352 | // TODO: Fix for symbolic references |
353 | // TODO: unsafe unwrap? |
354 | return Ok; |
355 | else |
356 | // Nothing in database, render empty tree. |
357 | return Err; |
358 | |
359 | ; |
360 | |
361 | // TODO: This is far from ideal or speedy and would love for a better way to check this in the same order, but I can't find proper methods to do any of this. |
362 | |
363 | // Try getting it as a refname (refs/heads/name) |
364 | if let Ok = git.refname_to_id |
365 | Ok |
366 | // Try finding it as a short branch name |
367 | else if let Ok = git.find_branch |
368 | // SHOULD be safe to unwrap |
369 | Ok |
370 | // As last resort, try revparsing (will catch short oid and tags) |
371 | else if let Ok = git.revparse_single |
372 | Ok |
373 | else |
374 | Err |
375 | |
376 | |
377 | |
378 | /// Gets the last commit in a rev |
379 | |
380 | let oid = Self get_oid_from_reference?; |
381 | |
382 | // Walk through the repository commit graph starting at our rev |
383 | let mut revwalk = git.revwalk?; |
384 | revwalk.set_sorting?; |
385 | revwalk.push?; |
386 | |
387 | if let Some = revwalk.next |
388 | if let Ok = git |
389 | .find_commit |
390 | .map_err |
391 | |
392 | return Ok; |
393 | |
394 | |
395 | |
396 | Err |
397 | |
398 | |
399 | |
400 | |
401 | |
402 | async |
403 | &mut self, |
404 | requester: & , |
405 | repository: &Repository, |
406 | |
407 | if let Ok = self |
408 | .find_by_owner_user_name |
409 | .await |
410 | |
411 | Ok |
412 | .can_user_view_repository |
413 | .await |
414 | else |
415 | Ok |
416 | |
417 | |
418 | |
419 | async |
420 | &mut self, |
421 | _user: &AuthenticatedUser, |
422 | request: &RepositoryCreateRequest, |
423 | |
424 | // Check if repository already exists in the database |
425 | if let Ok = self |
426 | .find_by_owner_user_name |
427 | .await |
428 | |
429 | let err = RepositoryAlreadyExists |
430 | owner_user: repository.owner_user.to_string, |
431 | name: repository.name, |
432 | ; |
433 | error!; |
434 | |
435 | return Err; |
436 | |
437 | |
438 | // Insert the repository into the database |
439 | let _ = match query_as! |
440 | r#"INSERT INTO repositories VALUES ($1, $2, $3, $4, $5) RETURNING owner_user, name, description, visibility as "visibility: _", default_branch"#, |
441 | request.owner.to_string, request.name, request.description, request.visibility as _, "master" |
442 | .fetch_one |
443 | .await |
444 | Ok => repository, |
445 | Err => |
446 | let err = FailedInsertingIntoDatabase; |
447 | error!; |
448 | |
449 | return Err; |
450 | |
451 | ; |
452 | |
453 | // Create bare (server side) repository on disk |
454 | match init_bare |
455 | "{}/{}/{}/{}" |
456 | self.repository_folder, request.owner.instance, request.owner.username, request.name |
457 | ) |
458 | Ok => |
459 | debug! |
460 | "Created new repository with the name {}/{}/{}", |
461 | request.owner.instance, request.owner.username, request.name |
462 | ; |
463 | |
464 | let stack = self.stack.get .unwrap; |
465 | |
466 | let repository = Repository |
467 | owner: request.owner.clone, |
468 | name: request.name.clone, |
469 | instance: request.instance.as_ref .unwrap_or .clone, |
470 | ; |
471 | |
472 | stack |
473 | .write_setting |
474 | &repository, |
475 | Description, |
476 | |
477 | .await |
478 | .unwrap; |
479 | |
480 | stack |
481 | .write_setting |
482 | .await |
483 | .unwrap; |
484 | |
485 | stack |
486 | .write_setting |
487 | .await |
488 | .unwrap; |
489 | |
490 | Ok |
491 | |
492 | Err => |
493 | let err = FailedCreatingRepository; |
494 | error!; |
495 | |
496 | // Delete repository from database |
497 | self.delete_from_database |
498 | .await?; |
499 | |
500 | // ??? |
501 | Err |
502 | |
503 | |
504 | |
505 | |
506 | /// If the OID can't be found because there's no repository head, this will return an empty `Vec`. |
507 | async |
508 | &mut self, |
509 | requester: & , |
510 | repository: &Repository, |
511 | request: &RepositoryFileInspectRequest, |
512 | |
513 | let git = self |
514 | .open_repository_and_check_permissions |
515 | .await?; |
516 | |
517 | // Try and find the tree_id/branch |
518 | let tree_id = match Self get_oid_from_reference |
519 | Ok => oid, |
520 | Err => return Ok, |
521 | Err => return Err, |
522 | ; |
523 | |
524 | // Get the commit from the oid |
525 | let commit = match git.find_commit |
526 | Ok => commit, |
527 | // If the commit isn't found, it's generally safe to assume the tree is empty. |
528 | Err => return Ok, |
529 | ; |
530 | |
531 | // this is stupid |
532 | let rev = request.rev.clone .unwrap_or_else; |
533 | let mut current_path = rev.clone; |
534 | |
535 | // Get the commit tree |
536 | let git_tree = if let Some = &request.path |
537 | // Add it to our full path string |
538 | current_path.push_str; |
539 | // Get the specified path, return an error if it wasn't found. |
540 | let entry = match commit |
541 | .tree |
542 | .unwrap |
543 | .get_path |
544 | .map_err |
545 | |
546 | Ok => entry, |
547 | Err => return Err, |
548 | ; |
549 | // Turn the entry into a git tree |
550 | entry.to_object .unwrap .as_tree .unwrap .clone |
551 | else |
552 | commit.tree .unwrap |
553 | ; |
554 | |
555 | // Iterate over the git tree and collect it into our own tree types |
556 | let mut tree = git_tree |
557 | .iter |
558 | .map |
559 | let object_type = match entry.kind .unwrap |
560 | => Tree, | Tree
561 | => Blob, | Blob
562 | _ => unreachable!, |
563 | ; |
564 | let mut tree_entry = new |
565 | entry.id .to_string .as_str, |
566 | entry.name .unwrap, |
567 | object_type, |
568 | entry.filemode, |
569 | ; |
570 | |
571 | if request.extra_metadata |
572 | // Get the file size if It's a blob |
573 | let object = entry.to_object .unwrap; |
574 | if let Some = object.as_blob |
575 | tree_entry.size = Some; |
576 | |
577 | |
578 | // Get the path to the folder the file is in by removing the rev from current_path |
579 | let mut path = current_path.replace; |
580 | if path.starts_with |
581 | path.remove; |
582 | |
583 | |
584 | // Format it as the path + file name |
585 | let full_path = if path.is_empty |
586 | entry.name .unwrap .to_string |
587 | else |
588 | format! |
589 | ; |
590 | |
591 | // Get the last commit made to the entry |
592 | if let Ok = |
593 | get_last_commit_of_file |
594 | |
595 | tree_entry.last_commit = Some; |
596 | |
597 | |
598 | |
599 | tree_entry |
600 | |
601 | .; |
602 | |
603 | // Sort the tree alphabetically and with tree first |
604 | tree.sort_unstable_by_key; |
605 | tree.sort_unstable_by_key |
606 | Reverse |
607 | ; |
608 | |
609 | Ok |
610 | |
611 | |
612 | async |
613 | &mut self, |
614 | requester: & , |
615 | repository: &Repository, |
616 | request: &RepositoryFileFromIdRequest, |
617 | |
618 | let git = self |
619 | .open_repository_and_check_permissions |
620 | .await?; |
621 | |
622 | // Parse the passed object id |
623 | let oid = match from_str |
624 | Ok => oid, |
625 | Err => |
626 | return Err |
627 | |
628 | ; |
629 | |
630 | // Find the file and turn it into our own struct |
631 | let file = match git.find_blob |
632 | Ok => RepositoryFile |
633 | id: blob.id .to_string, |
634 | content: blob.content .to_vec, |
635 | binary: blob.is_binary, |
636 | size: blob.size, |
637 | , |
638 | Err => return Err, |
639 | ; |
640 | |
641 | Ok |
642 | |
643 | |
644 | async |
645 | &mut self, |
646 | requester: & , |
647 | repository: &Repository, |
648 | request: &RepositoryFileFromPathRequest, |
649 | |
650 | let git = self |
651 | .open_repository_and_check_permissions |
652 | .await?; |
653 | |
654 | let tree_id = Self get_oid_from_reference?; |
655 | |
656 | // unwrap might be dangerous? |
657 | // Get the commit from the oid |
658 | let commit = git.find_commit .unwrap; |
659 | |
660 | // this is stupid |
661 | let mut current_path = request.rev.clone .unwrap_or_else; |
662 | |
663 | // Add it to our full path string |
664 | current_path.push_str; |
665 | // Get the specified path, return an error if it wasn't found. |
666 | let entry = match commit |
667 | .tree |
668 | .unwrap |
669 | .get_path |
670 | .map_err |
671 | |
672 | Ok => entry, |
673 | Err => return Err, |
674 | ; |
675 | |
676 | // Find the file and turn it into our own struct |
677 | let file = match git.find_blob |
678 | Ok => RepositoryFile |
679 | id: blob.id .to_string, |
680 | content: blob.content .to_vec, |
681 | binary: blob.is_binary, |
682 | size: blob.size, |
683 | , |
684 | Err => |
685 | return Err |
686 | |
687 | ; |
688 | |
689 | Ok |
690 | |
691 | |
692 | async |
693 | &mut self, |
694 | requester: & , |
695 | repository: &Repository, |
696 | request: &RepositoryCommitFromIdRequest, |
697 | |
698 | let git = self |
699 | .open_repository_and_check_permissions |
700 | .await?; |
701 | |
702 | // Parse the passed object ids |
703 | let oid = from_str |
704 | .map_err?; |
705 | |
706 | // Get the commit from the oid |
707 | let commit = git |
708 | .find_commit |
709 | .map_err?; |
710 | |
711 | Ok |
712 | |
713 | |
714 | async |
715 | &mut self, |
716 | requester: & , |
717 | repository: &Repository, |
718 | request: &RepositoryLastCommitOfFileRequest, |
719 | |
720 | let git = self |
721 | .open_repository_and_check_permissions |
722 | .await?; |
723 | |
724 | // Parse the passed object ids |
725 | let oid = from_str |
726 | .map_err?; |
727 | |
728 | // Get the commit from the oid |
729 | let commit = git |
730 | .find_commit |
731 | .map_err?; |
732 | |
733 | // Find the last commit of the file |
734 | let commit = get_last_commit_of_file?; |
735 | |
736 | Ok |
737 | |
738 | |
739 | /// Returns zero for all statistics if an OID wasn't found |
740 | async |
741 | &mut self, |
742 | requester: & , |
743 | repository: &Repository, |
744 | request: &RepositoryStatisticsRequest, |
745 | |
746 | let git = self |
747 | .open_repository_and_check_permissions |
748 | .await?; |
749 | |
750 | let tree_id = match Self get_oid_from_reference |
751 | Ok => oid, |
752 | Err => return Ok, |
753 | ; |
754 | |
755 | // Count the amount of branches and tags |
756 | let mut branches = 0; |
757 | let mut tags = 0; |
758 | if let Ok = git.references |
759 | for reference in references.flatten |
760 | if reference.is_branch |
761 | branches += 1; |
762 | else if reference.is_tag |
763 | tags += 1; |
764 | |
765 | |
766 | |
767 | |
768 | // Attempt to get the commit from the oid |
769 | let commits = if let Ok = git.find_commit |
770 | // Get the total commit count if we found the tree oid commit |
771 | ? | get_total_commit_count
772 | else |
773 | 0 |
774 | ; |
775 | |
776 | Ok |
777 | commits, |
778 | branches, |
779 | tags, |
780 | |
781 | |
782 | |
783 | /// .0: List of branches filtering by passed requirements. |
784 | /// .1: Total amount of branches after being filtered |
785 | async |
786 | &mut self, |
787 | requester: & , |
788 | repository: &Repository, |
789 | request: &RepositoryBranchesRequest, |
790 | |
791 | let git = self |
792 | .open_repository_and_check_permissions |
793 | .await?; |
794 | |
795 | // Could be done better with the RepositoryBranchFilter::None check done beforehand. |
796 | let mut filtered_branches = git |
797 | .branches? |
798 | .filter_map |
799 | let branch = branch.ok?.0; |
800 | |
801 | let Some = branch.name .ok .flatten else |
802 | return None; |
803 | ; |
804 | |
805 | // TODO: Non UTF-8? |
806 | let Some = |
807 | ok | get_last_commit_in_rev .
808 | else |
809 | return None; |
810 | ; |
811 | |
812 | // TODO: Implement stale with configurable age |
813 | let stale = false; |
814 | |
815 | // Filter based on if the branch is stale or not |
816 | if request.filter != None |
817 | |
818 | if stale && request.filter == Active |
819 | return None; |
820 | else if !stale && request.filter == Stale |
821 | return None; |
822 | |
823 | |
824 | |
825 | Some |
826 | |
827 | .; |
828 | |
829 | // Get the total amount of filtered branches |
830 | let branch_count = filtered_branches.len; |
831 | |
832 | if let Some = &request.search |
833 | // TODO: Caching |
834 | // Search by sorting using a simple fuzzy search algorithm |
835 | filtered_branches.sort_by |
836 | damerau_levenshtein |
837 | .cmp |
838 | ; |
839 | else |
840 | // Sort the branches by commit date |
841 | filtered_branches.sort_by; |
842 | |
843 | |
844 | // Go to the requested position |
845 | let mut filtered_branches = filtered_branches.iter .skip; |
846 | |
847 | let head = git.head?; |
848 | let mut branches = vec!; |
849 | |
850 | // Iterate through the filtered branches using the passed range |
851 | for _ in request.range.0..request.range.1 |
852 | let Some = filtered_branches.next else |
853 | break; |
854 | ; |
855 | |
856 | // Get how many commits are ahead of and behind of the head |
857 | let ahead_behind_head = if head.target .is_some && branch.get .target .is_some |
858 | git.graph_ahead_behind |
859 | .ok |
860 | else |
861 | None |
862 | ; |
863 | |
864 | branches.push |
865 | name: name.to_string, |
866 | stale: *stale, |
867 | last_commit: Some, |
868 | ahead_behind_head, |
869 | |
870 | |
871 | |
872 | Ok |
873 | |
874 | |
875 | async |
876 | &mut self, |
877 | requester: & , |
878 | repository: &Repository, |
879 | request: &RepositoryDiffRequest, |
880 | |
881 | let git = self |
882 | .open_repository_and_check_permissions |
883 | .await?; |
884 | |
885 | // Parse the passed object ids |
886 | let oid_old = from_str |
887 | .map_err?; |
888 | let oid_new = from_str |
889 | .map_err?; |
890 | |
891 | // Get the ids associates commits |
892 | let commit_old = git |
893 | .find_commit |
894 | .map_err?; |
895 | let commit_new = git |
896 | .find_commit |
897 | .map_err?; |
898 | |
899 | // Get the commit trees |
900 | let tree_old = commit_old |
901 | .tree |
902 | .map_err?; |
903 | let tree_new = commit_new |
904 | .tree |
905 | .map_err?; |
906 | |
907 | // Diff the two trees against each other |
908 | let diff = git |
909 | .diff_tree_to_tree |
910 | .map_err |
911 | FailedDiffing |
912 | ?; |
913 | |
914 | // Should be safe to unwrap? |
915 | let stats = diff.stats .unwrap; |
916 | let mut files: = vec!; |
917 | |
918 | diff.deltas .enumerate .for_each |
919 | // Parse the old file info from the delta |
920 | let old_file_info = match delta.old_file .exists |
921 | true => Some |
922 | id: delta.old_file .id .to_string, |
923 | path: delta |
924 | .old_file |
925 | .path |
926 | .unwrap |
927 | .to_str |
928 | .unwrap |
929 | .to_string, |
930 | size: delta.old_file .size, |
931 | binary: delta.old_file .is_binary, |
932 | , |
933 | false => None, |
934 | ; |
935 | // Parse the new file info from the delta |
936 | let new_file_info = match delta.new_file .exists |
937 | true => Some |
938 | id: delta.new_file .id .to_string, |
939 | path: delta |
940 | .new_file |
941 | .path |
942 | .unwrap |
943 | .to_str |
944 | .unwrap |
945 | .to_string, |
946 | size: delta.new_file .size, |
947 | binary: delta.new_file .is_binary, |
948 | , |
949 | false => None, |
950 | ; |
951 | |
952 | let mut chunks: = vec!; |
953 | if let Some = from_diff .ok .flatten |
954 | for chunk_num in 0..patch.num_hunks |
955 | if let Ok = patch.hunk |
956 | let mut lines: = vec!; |
957 | |
958 | for line_num in 0..chunk_num_lines |
959 | if let Ok = patch.line_in_hunk |
960 | if let Ok = String from_utf8 |
961 | lines.push |
962 | change_type: line.origin_value .into, |
963 | content: line_utf8, |
964 | old_line_num: line.old_lineno, |
965 | new_line_num: line.new_lineno, |
966 | ; |
967 | |
968 | |
969 | continue; |
970 | |
971 | |
972 | |
973 | chunks.push |
974 | header: String from_utf8 .ok, |
975 | old_start: chunk.old_start, |
976 | old_lines: chunk.old_lines, |
977 | new_start: chunk.new_start, |
978 | new_lines: chunk.new_lines, |
979 | lines, |
980 | ; |
981 | |
982 | |
983 | ; |
984 | |
985 | let file = RepositoryDiffFile |
986 | status: from, |
987 | old_file_info, |
988 | new_file_info, |
989 | chunks, |
990 | ; |
991 | |
992 | files.push; |
993 | ; |
994 | |
995 | Ok |
996 | new_commit: from, |
997 | files_changed: stats.files_changed, |
998 | insertions: stats.insertions, |
999 | deletions: stats.deletions, |
1000 | files, |
1001 | |
1002 | |
1003 | |
1004 | async |
1005 | &mut self, |
1006 | requester: & , |
1007 | repository: &Repository, |
1008 | request: &RepositoryDiffPatchRequest, |
1009 | |
1010 | let git = self |
1011 | .open_repository_and_check_permissions |
1012 | .await?; |
1013 | |
1014 | // Parse the passed object ids |
1015 | let oid_old = from_str |
1016 | .map_err?; |
1017 | let oid_new = from_str |
1018 | .map_err?; |
1019 | |
1020 | // Get the ids associates commits |
1021 | let commit_old = git |
1022 | .find_commit |
1023 | .map_err?; |
1024 | let commit_new = git |
1025 | .find_commit |
1026 | .map_err?; |
1027 | |
1028 | // Get the commit trees |
1029 | let tree_old = commit_old |
1030 | .tree |
1031 | .map_err?; |
1032 | let tree_new = commit_new |
1033 | .tree |
1034 | .map_err?; |
1035 | |
1036 | // Diff the two trees against each other |
1037 | let diff = git |
1038 | .diff_tree_to_tree |
1039 | .map_err |
1040 | FailedDiffing |
1041 | ?; |
1042 | |
1043 | // Print the entire patch |
1044 | let mut patch = String new; |
1045 | |
1046 | diff.print |
1047 | match line.origin |
1048 | '+' | '-' | ' ' => patch.push, |
1049 | _ => |
1050 | |
1051 | patch.push_str; |
1052 | true |
1053 | |
1054 | .unwrap; |
1055 | |
1056 | Ok |
1057 | |
1058 | |
1059 | async |
1060 | &mut self, |
1061 | requester: & , |
1062 | repository: &Repository, |
1063 | request: &RepositoryCommitBeforeRequest, |
1064 | |
1065 | let git = self |
1066 | .open_repository_and_check_permissions |
1067 | .await?; |
1068 | |
1069 | // Parse the passed object id |
1070 | let oid = match from_str |
1071 | Ok => oid, |
1072 | Err => |
1073 | return Err |
1074 | |
1075 | ; |
1076 | |
1077 | // Find the commit using the parsed oid |
1078 | let commit = match git.find_commit |
1079 | Ok => commit, |
1080 | Err => return Err, |
1081 | ; |
1082 | |
1083 | // Get the first parent it has |
1084 | let parent = commit.parent; |
1085 | if let Ok = parent |
1086 | return Ok; |
1087 | else |
1088 | // TODO: See if can be done better |
1089 | // Walk through the repository commit graph starting at our current commit |
1090 | let mut revwalk = git.revwalk?; |
1091 | revwalk.set_sorting?; |
1092 | revwalk.push?; |
1093 | |
1094 | if let Some = revwalk.next |
1095 | // Find the commit using the parsed oid |
1096 | if let Ok = git.find_commit |
1097 | return Ok; |
1098 | |
1099 | |
1100 | |
1101 | Err |
1102 | |
1103 | |
1104 | |
1105 | |
1106 | |
1107 | |
1108 | &mut self, |
1109 | _requester: & , |
1110 | _request: &RepositoryIssuesCountRequest, |
1111 | |
1112 | todo! |
1113 | |
1114 | |
1115 | |
1116 | &mut self, |
1117 | _requester: & , |
1118 | _request: &RepositoryIssueLabelsRequest, |
1119 | |
1120 | todo! |
1121 | |
1122 | |
1123 | |
1124 | &mut self, |
1125 | _requester: & , |
1126 | _request: &RepositoryIssuesRequest, |
1127 | |
1128 | todo! |
1129 | |
1130 | |
1131 | |
1132 | |
1133 | |
1134 | |
1135 | pub repository: String, |
1136 | pub name: String, |
1137 | pub value: String, |
1138 | |
1139 |