diff options
| -rw-r--r-- | src/git_remote_helper.rs | 72 |
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; | |||
| 18 | use client::Connect; | 18 | use client::Connect; |
| 19 | use client::{fetching_with_report, get_repo_ref_from_cache}; | 19 | use client::{fetching_with_report, get_repo_ref_from_cache}; |
| 20 | use git::RepoActions; | 20 | use git::RepoActions; |
| 21 | use git2::{Remote, Repository}; | ||
| 21 | use nostr::nips::nip01::Coordinate; | 22 | use nostr::nips::nip01::Coordinate; |
| 22 | use nostr_sdk::Url; | 23 | use 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 | |||
| 162 | fn 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 | |||
| 209 | fn 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 | } | ||