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