diff options
Diffstat (limited to 'src/git_remote_helper.rs')
| -rw-r--r-- | src/git_remote_helper.rs | 78 |
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; | |||
| 21 | use git2::{Remote, Repository}; | 21 | use git2::{Remote, Repository}; |
| 22 | use nostr::nips::nip01::Coordinate; | 22 | use nostr::nips::nip01::Coordinate; |
| 23 | use nostr_sdk::Url; | 23 | use nostr_sdk::Url; |
| 24 | use repo_ref::RepoRef; | ||
| 24 | 25 | ||
| 25 | #[cfg(not(test))] | 26 | #[cfg(not(test))] |
| 26 | use crate::client::Client; | 27 | use 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 | ||
| 141 | fn list(temp_remote: &mut Remote, for_push: bool) -> Result<()> { | 143 | fn 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 | ||
| 153 | fn fetch(temp_remote: &mut Remote, stdin: &Stdin, refstr: &str) -> Result<()> { | 160 | fn 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 | ||
| 161 | fn push( | 173 | fn 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 | ||
| 199 | fn update_remote_refs_pushed(git_repo: &Repository, refspec: &str, url: &str) -> Result<()> { | 217 | fn 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() { |