diff options
Diffstat (limited to 'src/lib/repo_ref.rs')
| -rw-r--r-- | src/lib/repo_ref.rs | 103 |
1 files changed, 58 insertions, 45 deletions
diff --git a/src/lib/repo_ref.rs b/src/lib/repo_ref.rs index 38f6774..b21a911 100644 --- a/src/lib/repo_ref.rs +++ b/src/lib/repo_ref.rs | |||
| @@ -8,7 +8,10 @@ use std::{ | |||
| 8 | 8 | ||
| 9 | use anyhow::{Context, Result, bail}; | 9 | use anyhow::{Context, Result, bail}; |
| 10 | use console::Style; | 10 | use console::Style; |
| 11 | use nostr::{FromBech32, PublicKey, Tag, TagStandard, ToBech32, nips::nip01::Coordinate}; | 11 | use nostr::{ |
| 12 | FromBech32, PublicKey, Tag, TagStandard, ToBech32, | ||
| 13 | nips::{nip01::Coordinate, nip19::Nip19Coordinate}, | ||
| 14 | }; | ||
| 12 | use nostr_sdk::{Kind, NostrSigner, RelayUrl, Timestamp}; | 15 | use nostr_sdk::{Kind, NostrSigner, RelayUrl, Timestamp}; |
| 13 | use serde::{Deserialize, Serialize}; | 16 | use serde::{Deserialize, Serialize}; |
| 14 | 17 | ||
| @@ -37,7 +40,7 @@ pub struct RepoRef { | |||
| 37 | pub relays: Vec<RelayUrl>, | 40 | pub relays: Vec<RelayUrl>, |
| 38 | pub maintainers: Vec<PublicKey>, | 41 | pub maintainers: Vec<PublicKey>, |
| 39 | pub trusted_maintainer: PublicKey, | 42 | pub trusted_maintainer: PublicKey, |
| 40 | pub events: HashMap<Coordinate, nostr::Event>, | 43 | pub events: HashMap<Nip19Coordinate, nostr::Event>, |
| 41 | pub nostr_git_url: Option<NostrUrlDecoded>, | 44 | pub nostr_git_url: Option<NostrUrlDecoded>, |
| 42 | } | 45 | } |
| 43 | 46 | ||
| @@ -119,10 +122,12 @@ impl TryFrom<(nostr::Event, Option<PublicKey>)> for RepoRef { | |||
| 119 | } | 122 | } |
| 120 | r.events = HashMap::new(); | 123 | r.events = HashMap::new(); |
| 121 | r.events.insert( | 124 | r.events.insert( |
| 122 | Coordinate { | 125 | Nip19Coordinate { |
| 123 | kind: event.kind, | 126 | coordinate: Coordinate { |
| 124 | identifier: event.tags.identifier().unwrap().to_string(), | 127 | kind: event.kind, |
| 125 | public_key: event.pubkey, | 128 | identifier: event.tags.identifier().unwrap().to_string(), |
| 129 | public_key: event.pubkey, | ||
| 130 | }, | ||
| 126 | relays: vec![], | 131 | relays: vec![], |
| 127 | }, | 132 | }, |
| 128 | event, | 133 | event, |
| @@ -195,20 +200,24 @@ impl RepoRef { | |||
| 195 | .context("failed to create repository reference event") | 200 | .context("failed to create repository reference event") |
| 196 | } | 201 | } |
| 197 | /// coordinates without relay hints | 202 | /// coordinates without relay hints |
| 198 | pub fn coordinates(&self) -> HashSet<Coordinate> { | 203 | pub fn coordinates(&self) -> HashSet<Nip19Coordinate> { |
| 199 | let mut res = HashSet::new(); | 204 | let mut res = HashSet::new(); |
| 200 | res.insert(Coordinate { | 205 | res.insert(Nip19Coordinate { |
| 201 | kind: Kind::GitRepoAnnouncement, | 206 | coordinate: Coordinate { |
| 202 | public_key: self.trusted_maintainer, | 207 | kind: Kind::GitRepoAnnouncement, |
| 203 | identifier: self.identifier.clone(), | 208 | public_key: self.trusted_maintainer, |
| 209 | identifier: self.identifier.clone(), | ||
| 210 | }, | ||
| 204 | relays: vec![], | 211 | relays: vec![], |
| 205 | }); | 212 | }); |
| 206 | 213 | ||
| 207 | for m in &self.maintainers { | 214 | for m in &self.maintainers { |
| 208 | res.insert(Coordinate { | 215 | res.insert(Nip19Coordinate { |
| 209 | kind: Kind::GitRepoAnnouncement, | 216 | coordinate: Coordinate { |
| 210 | public_key: *m, | 217 | kind: Kind::GitRepoAnnouncement, |
| 211 | identifier: self.identifier.clone(), | 218 | public_key: *m, |
| 219 | identifier: self.identifier.clone(), | ||
| 220 | }, | ||
| 212 | relays: vec![], | 221 | relays: vec![], |
| 213 | }); | 222 | }); |
| 214 | } | 223 | } |
| @@ -216,11 +225,13 @@ impl RepoRef { | |||
| 216 | } | 225 | } |
| 217 | 226 | ||
| 218 | /// coordinates without relay hints | 227 | /// coordinates without relay hints |
| 219 | pub fn coordinate_with_hint(&self) -> Coordinate { | 228 | pub fn coordinate_with_hint(&self) -> Nip19Coordinate { |
| 220 | Coordinate { | 229 | Nip19Coordinate { |
| 221 | kind: Kind::GitRepoAnnouncement, | 230 | coordinate: Coordinate { |
| 222 | public_key: self.trusted_maintainer, | 231 | kind: Kind::GitRepoAnnouncement, |
| 223 | identifier: self.identifier.clone(), | 232 | public_key: self.trusted_maintainer, |
| 233 | identifier: self.identifier.clone(), | ||
| 234 | }, | ||
| 224 | relays: if let Some(relay) = self.relays.first() { | 235 | relays: if let Some(relay) = self.relays.first() { |
| 225 | vec![relay.clone()] | 236 | vec![relay.clone()] |
| 226 | } else { | 237 | } else { |
| @@ -230,11 +241,11 @@ impl RepoRef { | |||
| 230 | } | 241 | } |
| 231 | 242 | ||
| 232 | /// coordinates without relay hints | 243 | /// coordinates without relay hints |
| 233 | pub fn coordinates_with_timestamps(&self) -> Vec<(Coordinate, Option<Timestamp>)> { | 244 | pub fn coordinates_with_timestamps(&self) -> Vec<(Nip19Coordinate, Option<Timestamp>)> { |
| 234 | self.coordinates() | 245 | self.coordinates() |
| 235 | .iter() | 246 | .iter() |
| 236 | .map(|c| (c.clone(), self.events.get(c).map(|e| e.created_at))) | 247 | .map(|c| (c.clone(), self.events.get(c).map(|e| e.created_at))) |
| 237 | .collect::<Vec<(Coordinate, Option<Timestamp>)>>() | 248 | .collect::<Vec<(Nip19Coordinate, Option<Timestamp>)>>() |
| 238 | } | 249 | } |
| 239 | 250 | ||
| 240 | pub fn set_nostr_git_url(&mut self, nostr_git_url: NostrUrlDecoded) { | 251 | pub fn set_nostr_git_url(&mut self, nostr_git_url: NostrUrlDecoded) { |
| @@ -264,7 +275,7 @@ pub async fn get_repo_coordinates_when_remote_unknown( | |||
| 264 | git_repo: &Repo, | 275 | git_repo: &Repo, |
| 265 | #[cfg(test)] client: &crate::client::MockConnect, | 276 | #[cfg(test)] client: &crate::client::MockConnect, |
| 266 | #[cfg(not(test))] client: &Client, | 277 | #[cfg(not(test))] client: &Client, |
| 267 | ) -> Result<Coordinate> { | 278 | ) -> Result<Nip19Coordinate> { |
| 268 | if let Ok(c) = try_and_get_repo_coordinates_when_remote_unknown(git_repo).await { | 279 | if let Ok(c) = try_and_get_repo_coordinates_when_remote_unknown(git_repo).await { |
| 269 | Ok(c) | 280 | Ok(c) |
| 270 | } else { | 281 | } else { |
| @@ -274,7 +285,7 @@ pub async fn get_repo_coordinates_when_remote_unknown( | |||
| 274 | 285 | ||
| 275 | pub async fn try_and_get_repo_coordinates_when_remote_unknown( | 286 | pub async fn try_and_get_repo_coordinates_when_remote_unknown( |
| 276 | git_repo: &Repo, | 287 | git_repo: &Repo, |
| 277 | ) -> Result<Coordinate> { | 288 | ) -> Result<Nip19Coordinate> { |
| 278 | let remote_coordinates = get_repo_coordinates_from_nostr_remotes(git_repo).await?; | 289 | let remote_coordinates = get_repo_coordinates_from_nostr_remotes(git_repo).await?; |
| 279 | if remote_coordinates.is_empty() { | 290 | if remote_coordinates.is_empty() { |
| 280 | if let Ok(c) = get_repo_coordinates_from_git_config(git_repo) { | 291 | if let Ok(c) = get_repo_coordinates_from_git_config(git_repo) { |
| @@ -318,7 +329,7 @@ pub async fn try_and_get_repo_coordinates_when_remote_unknown( | |||
| 318 | 329 | ||
| 319 | async fn get_nostr_git_remote_selection_labels( | 330 | async fn get_nostr_git_remote_selection_labels( |
| 320 | git_repo: &Repo, | 331 | git_repo: &Repo, |
| 321 | remote_coordinates: &HashMap<String, Coordinate>, | 332 | remote_coordinates: &HashMap<String, Nip19Coordinate>, |
| 322 | ) -> Result<Vec<String>> { | 333 | ) -> Result<Vec<String>> { |
| 323 | let mut res = vec![]; | 334 | let mut res = vec![]; |
| 324 | for (remote, c) in remote_coordinates { | 335 | for (remote, c) in remote_coordinates { |
| @@ -334,9 +345,9 @@ async fn get_nostr_git_remote_selection_labels( | |||
| 334 | Ok(res) | 345 | Ok(res) |
| 335 | } | 346 | } |
| 336 | 347 | ||
| 337 | fn get_repo_coordinates_from_git_config(git_repo: &Repo) -> Result<Coordinate> { | 348 | fn get_repo_coordinates_from_git_config(git_repo: &Repo) -> Result<Nip19Coordinate> { |
| 338 | Coordinate::parse( | 349 | Nip19Coordinate::from_bech32( |
| 339 | git_repo | 350 | &git_repo |
| 340 | .get_git_config_item("nostr.repo", Some(false))? | 351 | .get_git_config_item("nostr.repo", Some(false))? |
| 341 | .context("git config item \"nostr.repo\" is not set in local repository")?, | 352 | .context("git config item \"nostr.repo\" is not set in local repository")?, |
| 342 | ) | 353 | ) |
| @@ -345,7 +356,7 @@ fn get_repo_coordinates_from_git_config(git_repo: &Repo) -> Result<Coordinate> { | |||
| 345 | 356 | ||
| 346 | async fn get_repo_coordinates_from_nostr_remotes( | 357 | async fn get_repo_coordinates_from_nostr_remotes( |
| 347 | git_repo: &Repo, | 358 | git_repo: &Repo, |
| 348 | ) -> Result<HashMap<String, Coordinate>> { | 359 | ) -> Result<HashMap<String, Nip19Coordinate>> { |
| 349 | let mut repo_coordinates = HashMap::new(); | 360 | let mut repo_coordinates = HashMap::new(); |
| 350 | for remote_name in git_repo.git_repo.remotes()?.iter().flatten() { | 361 | for remote_name in git_repo.git_repo.remotes()?.iter().flatten() { |
| 351 | if let Some(remote_url) = git_repo.git_repo.find_remote(remote_name)?.url() { | 362 | if let Some(remote_url) = git_repo.git_repo.find_remote(remote_name)?.url() { |
| @@ -359,21 +370,23 @@ async fn get_repo_coordinates_from_nostr_remotes( | |||
| 359 | Ok(repo_coordinates) | 370 | Ok(repo_coordinates) |
| 360 | } | 371 | } |
| 361 | 372 | ||
| 362 | async fn get_repo_coordinates_from_maintainers_yaml(git_repo: &Repo) -> Result<Coordinate> { | 373 | async fn get_repo_coordinates_from_maintainers_yaml(git_repo: &Repo) -> Result<Nip19Coordinate> { |
| 363 | let repo_config = get_repo_config_from_yaml(git_repo)?; | 374 | let repo_config = get_repo_config_from_yaml(git_repo)?; |
| 364 | 375 | ||
| 365 | Ok(Coordinate { | 376 | Ok(Nip19Coordinate { |
| 366 | identifier: repo_config | 377 | coordinate: Coordinate { |
| 367 | .identifier | 378 | identifier: repo_config |
| 368 | .context("maintainers.yaml doesnt list the identifier")?, | 379 | .identifier |
| 369 | kind: Kind::GitRepoAnnouncement, | 380 | .context("maintainers.yaml doesnt list the identifier")?, |
| 370 | public_key: PublicKey::from_bech32( | 381 | kind: Kind::GitRepoAnnouncement, |
| 371 | repo_config | 382 | public_key: PublicKey::from_bech32( |
| 372 | .maintainers | 383 | repo_config |
| 373 | .first() | 384 | .maintainers |
| 374 | .context("maintainers.yaml doesnt list any maintainers")?, | 385 | .first() |
| 375 | ) | 386 | .context("maintainers.yaml doesnt list any maintainers")?, |
| 376 | .context("maintainers.yaml doesn't list the first maintainer using a valid npub")?, | 387 | ) |
| 388 | .context("maintainers.yaml doesn't list the first maintainer using a valid npub")?, | ||
| 389 | }, | ||
| 377 | relays: repo_config | 390 | relays: repo_config |
| 378 | .relays | 391 | .relays |
| 379 | .iter() | 392 | .iter() |
| @@ -386,7 +399,7 @@ async fn get_repo_coordinate_from_user_prompt( | |||
| 386 | git_repo: &Repo, | 399 | git_repo: &Repo, |
| 387 | #[cfg(test)] client: &crate::client::MockConnect, | 400 | #[cfg(test)] client: &crate::client::MockConnect, |
| 388 | #[cfg(not(test))] client: &Client, | 401 | #[cfg(not(test))] client: &Client, |
| 389 | ) -> Result<Coordinate> { | 402 | ) -> Result<Nip19Coordinate> { |
| 390 | // TODO: present list of events filter by root_commit | 403 | // TODO: present list of events filter by root_commit |
| 391 | // TODO: fallback to search based on identifier | 404 | // TODO: fallback to search based on identifier |
| 392 | let dim = Style::new().color256(247); | 405 | let dim = Style::new().color256(247); |
| @@ -401,7 +414,7 @@ async fn get_repo_coordinate_from_user_prompt( | |||
| 401 | loop { | 414 | loop { |
| 402 | let input = Interactor::default() | 415 | let input = Interactor::default() |
| 403 | .input(PromptInputParms::default().with_prompt("nostr repository"))?; | 416 | .input(PromptInputParms::default().with_prompt("nostr repository"))?; |
| 404 | let coordinate = if let Ok(c) = Coordinate::parse(&input) { | 417 | let coordinate = if let Ok(c) = Nip19Coordinate::from_bech32(&input) { |
| 405 | c | 418 | c |
| 406 | } else if let Ok(nostr_url) = | 419 | } else if let Ok(nostr_url) = |
| 407 | NostrUrlDecoded::parse_and_resolve(&input, &Some(git_repo)).await | 420 | NostrUrlDecoded::parse_and_resolve(&input, &Some(git_repo)).await |
| @@ -491,7 +504,7 @@ pub fn extract_pks(pk_strings: Vec<String>) -> Result<Vec<PublicKey>> { | |||
| 491 | let mut pks: Vec<PublicKey> = vec![]; | 504 | let mut pks: Vec<PublicKey> = vec![]; |
| 492 | for s in pk_strings { | 505 | for s in pk_strings { |
| 493 | pks.push( | 506 | pks.push( |
| 494 | nostr_sdk::prelude::PublicKey::from_bech32(s.clone()).context(format!( | 507 | nostr_sdk::prelude::PublicKey::from_bech32(&s).context(format!( |
| 495 | "failed to convert {s} into a valid nostr public key" | 508 | "failed to convert {s} into a valid nostr public key" |
| 496 | ))?, | 509 | ))?, |
| 497 | ); | 510 | ); |