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