upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/git_remote_helper.rs78
1 files changed, 50 insertions, 28 deletions
diff --git a/src/git_remote_helper.rs b/src/git_remote_helper.rs
index 506fd5e..44f7fb5 100644
--- a/src/git_remote_helper.rs
+++ b/src/git_remote_helper.rs
@@ -21,6 +21,7 @@ use git::RepoActions;
21use git2::{Remote, Repository}; 21use git2::{Remote, Repository};
22use nostr::nips::nip01::Coordinate; 22use nostr::nips::nip01::Coordinate;
23use nostr_sdk::Url; 23use nostr_sdk::Url;
24use repo_ref::RepoRef;
24 25
25#[cfg(not(test))] 26#[cfg(not(test))]
26use crate::client::Client; 27use crate::client::Client;
@@ -43,7 +44,7 @@ async fn main() -> Result<()> {
43 let args = env::args(); 44 let args = env::args();
44 let args = args.skip(1).take(2).collect::<Vec<_>>(); 45 let args = args.skip(1).take(2).collect::<Vec<_>>();
45 46
46 let ([_, url] | [url]) = args.as_slice() else { 47 let ([_, nostr_remote_url] | [nostr_remote_url]) = args.as_slice() else {
47 bail!("invalid arguments - no url"); 48 bail!("invalid arguments - no url");
48 }; 49 };
49 if env::args().nth(1).as_deref() == Some("--version") { 50 if env::args().nth(1).as_deref() == Some("--version") {
@@ -60,7 +61,8 @@ async fn main() -> Result<()> {
60 #[cfg(test)] 61 #[cfg(test)]
61 let client = <MockConnect as std::default::Default>::default(); 62 let client = <MockConnect as std::default::Default>::default();
62 63
63 let repo_coordinates = nostr_git_url_to_repo_coordinates(url).context("invalid nostr url")?; 64 let repo_coordinates =
65 nostr_git_url_to_repo_coordinates(nostr_remote_url).context("invalid nostr url")?;
64 66
65 fetching_with_report(git_repo_path, &client, &repo_coordinates).await?; 67 fetching_with_report(git_repo_path, &client, &repo_coordinates).await?;
66 68
@@ -69,12 +71,6 @@ async fn main() -> Result<()> {
69 let stdin = io::stdin(); 71 let stdin = io::stdin();
70 let mut line = String::new(); 72 let mut line = String::new();
71 73
72 let temp_remote_url = repo_ref
73 .git_server
74 .first()
75 .context("no git server listed in nostr repository announcement")?;
76
77 let mut temp_remote = git_repo.git_repo.remote_anonymous(temp_remote_url)?;
78 loop { 74 loop {
79 let tokens = read_line(&stdin, &mut line)?; 75 let tokens = read_line(&stdin, &mut line)?;
80 76
@@ -92,16 +88,22 @@ async fn main() -> Result<()> {
92 println!("unsupported"); 88 println!("unsupported");
93 } 89 }
94 ["fetch", _oid, refstr] => { 90 ["fetch", _oid, refstr] => {
95 fetch(&mut temp_remote, &stdin, refstr)?; 91 fetch(&git_repo.git_repo, &repo_ref, &stdin, refstr)?;
96 } 92 }
97 ["push", refspec] => { 93 ["push", refspec] => {
98 push(&git_repo.git_repo, url, &mut temp_remote, &stdin, refspec)?; 94 push(
95 &git_repo.git_repo,
96 &repo_ref,
97 nostr_remote_url,
98 &stdin,
99 refspec,
100 )?;
99 } 101 }
100 ["list"] => { 102 ["list"] => {
101 list(&mut temp_remote, false)?; 103 list(&git_repo.git_repo, &repo_ref, false)?;
102 } 104 }
103 ["list", "for-push"] => { 105 ["list", "for-push"] => {
104 list(&mut temp_remote, true)?; 106 list(&git_repo.git_repo, &repo_ref, true)?;
105 } 107 }
106 [] => { 108 [] => {
107 return Ok(()); 109 return Ok(());
@@ -138,34 +140,50 @@ fn nostr_git_url_to_repo_coordinates(url: &str) -> Result<HashSet<Coordinate>> {
138 Ok(repo_coordinattes) 140 Ok(repo_coordinattes)
139} 141}
140 142
141fn list(temp_remote: &mut Remote, for_push: bool) -> Result<()> { 143fn list(git_repo: &Repository, repo_ref: &RepoRef, for_push: bool) -> Result<()> {
142 temp_remote.connect(git2::Direction::Fetch)?; 144 let git_server_remote_url = repo_ref
143 for head in temp_remote.list()? { 145 .git_server
146 .first()
147 .context("no git server listed in nostr repository announcement")?;
148 let mut git_server_remote = git_repo.remote_anonymous(git_server_remote_url)?;
149 git_server_remote.connect(git2::Direction::Fetch)?;
150 for head in git_server_remote.list()? {
144 if !for_push || head.name() != "HEAD" { 151 if !for_push || head.name() != "HEAD" {
145 println!("{} {}", head.oid(), head.name()); 152 println!("{} {}", head.oid(), head.name());
146 } 153 }
147 } 154 }
148 temp_remote.disconnect()?; 155 git_server_remote.disconnect()?;
149 println!(); 156 println!();
150 Ok(()) 157 Ok(())
151} 158}
152 159
153fn fetch(temp_remote: &mut Remote, stdin: &Stdin, refstr: &str) -> Result<()> { 160fn fetch(git_repo: &Repository, repo_ref: &RepoRef, stdin: &Stdin, refstr: &str) -> Result<()> {
154 temp_remote.connect(git2::Direction::Fetch)?; 161 let git_server_remote_url = repo_ref
155 temp_remote.download(&get_refstrs_from_fetch_batch(stdin, refstr)?, None)?; 162 .git_server
156 temp_remote.disconnect()?; 163 .first()
164 .context("no git server listed in nostr repository announcement")?;
165 let mut git_server_remote = git_repo.remote_anonymous(git_server_remote_url)?;
166 git_server_remote.connect(git2::Direction::Fetch)?;
167 git_server_remote.download(&get_refstrs_from_fetch_batch(stdin, refstr)?, None)?;
168 git_server_remote.disconnect()?;
157 println!(); 169 println!();
158 Ok(()) 170 Ok(())
159} 171}
160 172
161fn push( 173fn push(
162 git_repo: &Repository, 174 git_repo: &Repository,
163 nostr_url: &str, 175 repo_ref: &RepoRef,
164 temp_remote: &mut Remote, 176 nostr_remote_url: &str,
165 stdin: &Stdin, 177 stdin: &Stdin,
166 initial_refspec: &str, 178 initial_refspec: &str,
167) -> Result<()> { 179) -> Result<()> {
180 // if no state events - create from first git server listed
168 let refspecs = get_refspecs_from_push_batch(stdin, initial_refspec)?; 181 let refspecs = get_refspecs_from_push_batch(stdin, initial_refspec)?;
182 let git_server_url = repo_ref
183 .git_server
184 .first()
185 .context("no git server listed in nostr repository announcement")?;
186 let mut git_server_remote = git_repo.remote_anonymous(git_server_url)?;
169 let auth = GitAuthenticator::default(); 187 let auth = GitAuthenticator::default();
170 let git_config = git_repo.config()?; 188 let git_config = git_repo.config()?;
171 let mut push_options = git2::PushOptions::new(); 189 let mut push_options = git2::PushOptions::new();
@@ -179,7 +197,7 @@ fn push(
179 .iter() 197 .iter()
180 .find(|r| r.contains(format!(":{name}").as_str())) 198 .find(|r| r.contains(format!(":{name}").as_str()))
181 { 199 {
182 if let Err(e) = update_remote_refs_pushed(git_repo, refspec, nostr_url) 200 if let Err(e) = update_remote_refs_pushed(git_repo, refspec, nostr_remote_url)
183 .context("could not update remote_ref locally") 201 .context("could not update remote_ref locally")
184 { 202 {
185 return Err(git2::Error::from_str(e.to_string().as_str())); 203 return Err(git2::Error::from_str(e.to_string().as_str()));
@@ -190,13 +208,17 @@ fn push(
190 Ok(()) 208 Ok(())
191 }); 209 });
192 push_options.remote_callbacks(remote_callbacks); 210 push_options.remote_callbacks(remote_callbacks);
193 temp_remote.push(&refspecs, Some(&mut push_options))?; 211 git_server_remote.push(&refspecs, Some(&mut push_options))?;
194 temp_remote.disconnect()?; 212 git_server_remote.disconnect()?;
195 println!(); 213 println!();
196 Ok(()) 214 Ok(())
197} 215}
198 216
199fn update_remote_refs_pushed(git_repo: &Repository, refspec: &str, url: &str) -> Result<()> { 217fn update_remote_refs_pushed(
218 git_repo: &Repository,
219 refspec: &str,
220 nostr_remote_url: &str,
221) -> Result<()> {
200 if !refspec.contains(':') { 222 if !refspec.contains(':') {
201 bail!( 223 bail!(
202 "refspec should contain a colon (:) but consists of: {}", 224 "refspec should contain a colon (:) but consists of: {}",
@@ -207,11 +229,11 @@ fn update_remote_refs_pushed(git_repo: &Repository, refspec: &str, url: &str) ->
207 let from = parts.first().unwrap(); 229 let from = parts.first().unwrap();
208 let to = parts.get(1).unwrap(); 230 let to = parts.get(1).unwrap();
209 231
210 let remote = get_remote_by_url(git_repo, url)?; 232 let nostr_remote = get_remote_by_url(git_repo, nostr_remote_url)?;
211 233
212 let target_ref_name = format!( 234 let target_ref_name = format!(
213 "refs/remotes/{}/{}", 235 "refs/remotes/{}/{}",
214 remote.name().context("remote should have a name")?, 236 nostr_remote.name().context("remote should have a name")?,
215 to.replace("refs/heads/", ""), // TODO only replace if it begins with this 237 to.replace("refs/heads/", ""), // TODO only replace if it begins with this
216 ); 238 );
217 if from.is_empty() { 239 if from.is_empty() {