1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
use git2::{Email, EmailCreateOptions};
use indicatif::ProgressBar;
use nostr::{Keys, Event};
use crate::{repos::repo::Repo, utils::{create_client, load_event, save_event}, ngit_tag::{tag_is_commit, tag_extract_value}, patch::initialize_patch, repo_config::RepoConfig};
pub fn create_and_broadcast_patches_from_oid(
oids_ancestors_first: Vec<git2::Oid>,
git_repo: &git2::Repository,
repo_dir_path: &std::path::PathBuf,
repo: &Repo,
branch_id: &String,
keys: &Keys,
) {
let mut patches: Vec<Event> = vec![];
for oid in oids_ancestors_first {
patches.push(
create_and_save_patch_from_oid(
&oid,
&patches,
&git_repo,
&repo_dir_path.join(".ngit"),
&repo,
&branch_id,
&keys,
)
);
}
// update branch update timestamp
match patches.last() {
Some(p) => {
let mut repo_config = RepoConfig::open(&repo_dir_path);
repo_config.set_last_patch_update_time(
branch_id.clone(),
p.created_at.clone(),
);
}
None => (),
};
// broadcast patches
let spinner = ProgressBar::new_spinner();
spinner.set_message(format!("Broadcasting... if this takes 20s+, there was a problem broadcasting to one or more relays even if it says 'Pushed {} patches!'.",patches.len()));
let client = create_client(&keys, repo.relays.clone())
.expect("create_client to return client for create_and_broadcast_patches");
for e in &patches {
match client.send_event(e.clone()) {
Ok(_) => (),
// TODO: this isn't working - if a relay is specified with a type it will wait 30ish secs and then return successful
Err(e) => { println!("error broadcasting patch event: {}",e); },
}
// TODO: better error handling here / reporting. potentially warn if taking a while and report on troublesome relays
}
spinner.finish_with_message(format!("Pushed {} commits!.",patches.len()));
}
pub fn create_and_save_patch_from_oid(
oid: &git2::Oid,
patches: &Vec<Event>,
git_repo: &git2::Repository,
ngit_path: &std::path::PathBuf,
repo: &Repo,
branch_id: &String,
keys: &Keys,
) -> Event {
let commit_id = format!("{}",oid);
let commit = git_repo.find_commit(*oid)
.expect("revwalk returns oid that matches a comit in the repository");
let message = match commit.message() {
None => "",
Some(m) => m
}.to_string();
let email = Email::from_commit(
&commit,
&mut EmailCreateOptions::default(),
).expect("renders a commit as an email diff");
let parent_commit_id: Option<String> = match &commit.parent_id(0) {
Ok(parent_oid) => Some(format!("{}",parent_oid)),
Err(_) => None,
};
let parent_patch_id = match &parent_commit_id {
None => None,
Some(id) => Some({
// search for parent in current batch of patches
match patches.iter().find(|p|
p.tags.iter().find(|t|tag_is_commit(t) && id.clone() == tag_extract_value(&t)).is_some()
) {
Some(p) => p.id.to_string(),
None => {
let parent_patch_path = ngit_path.join(format!("patches/{}.json",id));
if parent_patch_path.exists() {
load_event(parent_patch_path)
.expect("patch in json file that exists produces valid event")
.id.to_string()
} else {
panic!("cannot find parent patch. ngit may have ordered ancestors without patches incorrectly");
}
},
}
}),
};
let event = initialize_patch(
&keys,
&repo.id.to_string(),
&branch_id,
&email.as_slice(),
&message,
&vec![commit_id.to_string()],
parent_patch_id,
parent_commit_id,
);
// save patch
save_event(ngit_path.join(
// TODO: consider what happens if a commit gets published twice, which one would get priority? The one from a maintiner?
format!("patches/{}.json",commit_id),
), &event)
.expect("save_event to store event in /patches");
event
}
|