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 std::io::Write;
use anyhow::{Context, Result, bail};
use ngit::client::get_all_proposal_patch_pr_pr_update_events_from_cache;
use ngit::git_events::get_pr_tip_event_or_most_recent_patch_with_ancestors;
use nostr::nips::nip19::Nip19;
use nostr_sdk::{EventId, FromBech32};
use crate::client::{Client, Connect, get_repo_ref_from_cache};
use crate::git::{Repo, RepoActions};
use crate::repo_ref::get_repo_coordinates_when_remote_unknown;
pub async fn launch(id: &str, stdout: bool) -> Result<()> {
let event_id = parse_event_id(id)?;
let git_repo = Repo::discover().context("failed to find a git repository")?;
let git_repo_path = git_repo.get_path()?;
let client = Client::new(ngit::client::Params::with_git_config_relay_defaults(&Some(
&git_repo,
)));
let repo_coordinates = get_repo_coordinates_when_remote_unknown(&git_repo, &client).await?;
crate::client::fetching_with_report(git_repo_path, &client, &repo_coordinates).await?;
let repo_ref = get_repo_ref_from_cache(Some(git_repo_path), &repo_coordinates).await?;
let proposals_and_revisions: Vec<nostr::Event> =
ngit::client::get_proposals_and_revisions_from_cache(
git_repo_path,
repo_ref.coordinates(),
)
.await?;
let proposal = proposals_and_revisions
.iter()
.find(|e| e.id == event_id)
.context(format!(
"proposal with id {} not found in cache",
event_id.to_hex()
))?;
let commits_events: Vec<nostr::Event> = get_all_proposal_patch_pr_pr_update_events_from_cache(
git_repo_path,
&repo_ref,
&proposal.id,
)
.await?;
let patches = get_pr_tip_event_or_most_recent_patch_with_ancestors(commits_events.clone())
.context("failed to find any PR or patch events on this proposal")?;
if patches
.iter()
.any(|e| [ngit::git_events::KIND_PULL_REQUEST, ngit::git_events::KIND_PULL_REQUEST_UPDATE].contains(&e.kind))
{
bail!(
"this proposal uses PR format (not patches). Use `ngit checkout {}` instead.",
event_id.to_hex()
);
}
if stdout {
output_patches_to_stdout(patches);
} else {
launch_git_am_with_patches(patches)?;
}
Ok(())
}
fn parse_event_id(id: &str) -> Result<EventId> {
if let Ok(nip19) = Nip19::from_bech32(id) {
match nip19 {
Nip19::Event(e) => return Ok(e.event_id),
Nip19::EventId(event_id) => return Ok(event_id),
_ => {}
}
}
if let Ok(event_id) = EventId::from_hex(id) {
return Ok(event_id);
}
bail!("invalid event-id or nevent: {id}")
}
fn output_patches_to_stdout(mut patches: Vec<nostr::Event>) {
patches.reverse();
for patch in patches {
print!("{}\n\n", patch.content);
}
}
fn launch_git_am_with_patches(mut patches: Vec<nostr::Event>) -> Result<()> {
println!("applying to current branch with `git am`");
patches.reverse();
let mut am = std::process::Command::new("git")
.arg("am")
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::inherit())
.stderr(std::process::Stdio::inherit())
.spawn()
.context("failed to spawn git am")?;
let stdin = am
.stdin
.as_mut()
.context("git am process failed to take stdin")?;
for patch in patches {
stdin
.write(format!("{}\n\n", patch.content).as_bytes())
.context("failed to write patch content into git am stdin buffer")?;
}
stdin.flush()?;
let output = am
.wait_with_output()
.context("failed to read git am stdout")?;
print!("{:?}", output.stdout);
Ok(())
}
|