upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/git_remote_helper.rs72
1 files changed, 72 insertions, 0 deletions
diff --git a/src/git_remote_helper.rs b/src/git_remote_helper.rs
index 2899fec..e6991d6 100644
--- a/src/git_remote_helper.rs
+++ b/src/git_remote_helper.rs
@@ -18,6 +18,7 @@ use auth_git2::GitAuthenticator;
18use client::Connect; 18use client::Connect;
19use client::{fetching_with_report, get_repo_ref_from_cache}; 19use client::{fetching_with_report, get_repo_ref_from_cache};
20use git::RepoActions; 20use git::RepoActions;
21use git2::{Remote, Repository};
21use nostr::nips::nip01::Coordinate; 22use nostr::nips::nip01::Coordinate;
22use nostr_sdk::Url; 23use nostr_sdk::Url;
23 24
@@ -98,8 +99,10 @@ async fn main() -> Result<()> {
98 println!(); 99 println!();
99 } 100 }
100 ["push", refspec] => { 101 ["push", refspec] => {
102 // Why are new branches being pushed without -u?
101 let auth = GitAuthenticator::default(); 103 let auth = GitAuthenticator::default();
102 auth.push(&git_repo.git_repo, &mut temp_remote, &[refspec])?; 104 auth.push(&git_repo.git_repo, &mut temp_remote, &[refspec])?;
105 update_remote_refs_from_push_refspecs(&git_repo.git_repo, refspec, url)?;
103 temp_remote.disconnect()?; 106 temp_remote.disconnect()?;
104 println!(); 107 println!();
105 } 108 }
@@ -155,3 +158,72 @@ fn nostr_git_url_to_repo_coordinates(url: &str) -> Result<HashSet<Coordinate>> {
155 } 158 }
156 Ok(repo_coordinattes) 159 Ok(repo_coordinattes)
157} 160}
161
162fn update_remote_refs_from_push_refspecs(
163 git_repo: &Repository,
164 refspec: &str,
165 url: &str,
166) -> Result<()> {
167 if !refspec.contains(':') {
168 bail!(
169 "refspec should contain a colon (:) but consists of: {}",
170 refspec
171 );
172 }
173 let parts = refspec.split(':').collect::<Vec<&str>>();
174 let from = parts.first().unwrap();
175 let to = parts.get(1).unwrap();
176
177 let remote = get_remote_by_url(git_repo, url)?;
178
179 let target_ref_name = format!(
180 "refs/remotes/{}/{}",
181 remote.name().context("remote should have a name")?,
182 to.replace("refs/heads/", ""), // TODO only replace if it begins with this
183 );
184 if from.is_empty() {
185 if let Ok(mut remote_ref) = git_repo.find_reference(&target_ref_name) {
186 remote_ref.delete()?;
187 }
188 } else {
189 let local_ref = git_repo
190 .find_reference(from)
191 .context(format!("from ref in refspec should exist: {from}"))?;
192 let commit = local_ref
193 .peel_to_commit()
194 .context(format!("from ref in refspec should peel to commit: {from}"))?;
195 if let Ok(mut remote_ref) = git_repo.find_reference(&target_ref_name) {
196 remote_ref.set_target(commit.id(), "updated by nostr remote helper")?;
197 } else {
198 git_repo.reference(
199 &target_ref_name,
200 commit.id(),
201 false,
202 "created by nostr remote helper",
203 )?;
204 }
205 }
206 Ok(())
207}
208
209fn get_remote_by_url<'a>(git_repo: &'a Repository, url: &'a str) -> Result<Remote<'a>> {
210 let remotes = git_repo.remotes()?;
211 let remote_name = remotes
212 .iter()
213 .find(|r| {
214 if let Some(name) = r {
215 if let Some(remote_url) = git_repo.find_remote(name).unwrap().url() {
216 url == remote_url
217 } else {
218 false
219 }
220 } else {
221 false
222 }
223 })
224 .context("could not find remote with matching url")?
225 .context("remote with matching url must be named")?;
226 git_repo
227 .find_remote(remote_name)
228 .context("we should have just located this remote")
229}