diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2023-05-21 11:14:47 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2023-05-21 11:14:47 +0000 |
| commit | 0067804cc00e94ce2b7043e67f9ff50968525479 (patch) | |
| tree | 2accdc6d4e9b73df4f20499238ec24f24a52a1b8 /src/funcs/find_latest_patch.rs | |
| parent | 5c5feaa732363e32e2a980a887fa42b4394b1a5e (diff) | |
v0.0.1-alpha funcs
Diffstat (limited to 'src/funcs/find_latest_patch.rs')
| -rw-r--r-- | src/funcs/find_latest_patch.rs | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/src/funcs/find_latest_patch.rs b/src/funcs/find_latest_patch.rs new file mode 100644 index 0000000..717d6c1 --- /dev/null +++ b/src/funcs/find_latest_patch.rs | |||
| @@ -0,0 +1,137 @@ | |||
| 1 | use std::path::PathBuf; | ||
| 2 | |||
| 3 | use nostr::{ Event }; | ||
| 4 | |||
| 5 | use crate::{ngit_tag::{tag_is_branch, tag_extract_value, tag_is_commit}, branch_refs::BranchRefs, utils::load_event, kind::Kind}; | ||
| 6 | |||
| 7 | /// finds latest patch that needs applying. It might not be the latest created_at date if an earlier patch was 'merged' more recently | ||
| 8 | pub fn find_latest_patch( | ||
| 9 | branch_id: &String, | ||
| 10 | patch_events:&Vec<Event>, | ||
| 11 | merges_into_branch: &Vec<Event>, | ||
| 12 | branch_refs:&BranchRefs, | ||
| 13 | repo_dir_path: &PathBuf, | ||
| 14 | ) -> Option<Event> { | ||
| 15 | |||
| 16 | // ensure only patch events make it into patch_events - we cant rely on relays for this | ||
| 17 | let patch_events:Vec<Event> = patch_events.iter().filter(|p| | ||
| 18 | // kind is patch | ||
| 19 | p.kind == nostr_sdk::Kind::Custom(u64::from(Kind::Patch)) | ||
| 20 | ).map(|p|p.clone()).collect(); | ||
| 21 | |||
| 22 | let directly_authorised_patches: Vec<Event> = patch_events.iter().filter(|p| | ||
| 23 | // kind is patch | ||
| 24 | p.kind == nostr_sdk::Kind::Custom(u64::from(Kind::Patch)) | ||
| 25 | // on branch | ||
| 26 | && p.tags.iter().any( | ||
| 27 | |t|tag_is_branch(t) | ||
| 28 | && tag_extract_value(t) == branch_id.clone() | ||
| 29 | ) | ||
| 30 | // authorized | ||
| 31 | && match &branch_refs.is_authorized(Some(&branch_id), &p.pubkey) { | ||
| 32 | None => { false }, | ||
| 33 | Some(is_authorized) => { is_authorized.clone() } | ||
| 34 | } | ||
| 35 | ).map(|p|p.clone()).collect(); | ||
| 36 | |||
| 37 | let latest_authorized_patch = find_latest_event(&directly_authorised_patches); | ||
| 38 | |||
| 39 | let authorised_merges: Vec<Event> = merges_into_branch.iter().filter(|m| | ||
| 40 | // kind is merge | ||
| 41 | m.kind == nostr_sdk::Kind::Custom(u64::from(Kind::Merge)) | ||
| 42 | // into branch | ||
| 43 | && m.tags.iter().any( | ||
| 44 | |t|tag_is_branch(t) | ||
| 45 | && tag_extract_value(t) == branch_id.clone() | ||
| 46 | ) | ||
| 47 | // merge authorized | ||
| 48 | && match &branch_refs.is_authorized(Some(&branch_id), &m.pubkey) { | ||
| 49 | None => { false }, | ||
| 50 | Some(is_authorized) => { is_authorized.clone() } | ||
| 51 | } | ||
| 52 | ).map(|p|p.clone()).collect(); | ||
| 53 | |||
| 54 | let latest_authorised_merge = find_latest_event(&authorised_merges); | ||
| 55 | |||
| 56 | // find latest patch | ||
| 57 | |||
| 58 | match latest_authorised_merge { | ||
| 59 | // no merge - return patch or None | ||
| 60 | None => latest_authorized_patch, | ||
| 61 | Some(m) => { | ||
| 62 | match latest_authorized_patch { | ||
| 63 | // merge but no patch, return the patch related to the merge | ||
| 64 | None => { | ||
| 65 | Some(get_merge_patch( | ||
| 66 | &m, | ||
| 67 | &patch_events, | ||
| 68 | repo_dir_path, | ||
| 69 | )) | ||
| 70 | }, | ||
| 71 | // a merge and a patch | ||
| 72 | Some(p) => { | ||
| 73 | // return the patch if it is later than merge | ||
| 74 | if m.created_at < p.created_at { | ||
| 75 | Some(p.clone()) | ||
| 76 | } | ||
| 77 | // return the patch related to the merge if the merge is later | ||
| 78 | else { | ||
| 79 | Some(get_merge_patch( | ||
| 80 | &m, | ||
| 81 | &patch_events, | ||
| 82 | repo_dir_path, | ||
| 83 | )) | ||
| 84 | } | ||
| 85 | } | ||
| 86 | } | ||
| 87 | } | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | fn find_latest_event(events:&Vec<Event>) -> Option<Event> { | ||
| 92 | let mut latest = match events.get(0) { | ||
| 93 | None => { return None }, | ||
| 94 | Some(e) => e.clone(), | ||
| 95 | }; | ||
| 96 | for e in events.iter() { | ||
| 97 | if e.created_at > latest.created_at { | ||
| 98 | latest = e.clone(); | ||
| 99 | } | ||
| 100 | } | ||
| 101 | Some(latest) | ||
| 102 | } | ||
| 103 | |||
| 104 | fn get_merge_patch( | ||
| 105 | merge: &Event, | ||
| 106 | patch_events: &Vec<Event>, | ||
| 107 | repo_dir_path: &PathBuf, | ||
| 108 | ) -> Event{ | ||
| 109 | let commit_id = tag_extract_value( | ||
| 110 | merge.tags.iter().find(|tag| tag_is_commit(tag)) | ||
| 111 | .expect("merge event will have a commit tag") | ||
| 112 | ); | ||
| 113 | // search in patch_events vector | ||
| 114 | match patch_events.iter().find(|p| | ||
| 115 | tag_extract_value( | ||
| 116 | p.tags.iter().find(|tag| tag_is_commit(tag)) | ||
| 117 | .expect("patch event will have a commit tag") | ||
| 118 | ) == *commit_id | ||
| 119 | ) { | ||
| 120 | // found merge patch in patch_events | ||
| 121 | Some(patch) => patch.clone(), | ||
| 122 | None => { | ||
| 123 | let patch_path = repo_dir_path.join(format!( | ||
| 124 | ".ngit/patches/{}.json", | ||
| 125 | commit_id | ||
| 126 | )); | ||
| 127 | if patch_path.exists() { | ||
| 128 | // found merge patch in .ngit/patches | ||
| 129 | load_event(patch_path) | ||
| 130 | .expect("patch at path that exists renders as event") | ||
| 131 | } | ||
| 132 | else { | ||
| 133 | panic!("cannot find patch from merge event in event vector or .ngit folder"); | ||
| 134 | } | ||
| 135 | }, | ||
| 136 | } | ||
| 137 | } | ||