upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/lib/repo_ref.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/repo_ref.rs')
-rw-r--r--src/lib/repo_ref.rs103
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
9use anyhow::{Context, Result, bail}; 9use anyhow::{Context, Result, bail};
10use console::Style; 10use console::Style;
11use nostr::{FromBech32, PublicKey, Tag, TagStandard, ToBech32, nips::nip01::Coordinate}; 11use nostr::{
12 FromBech32, PublicKey, Tag, TagStandard, ToBech32,
13 nips::{nip01::Coordinate, nip19::Nip19Coordinate},
14};
12use nostr_sdk::{Kind, NostrSigner, RelayUrl, Timestamp}; 15use nostr_sdk::{Kind, NostrSigner, RelayUrl, Timestamp};
13use serde::{Deserialize, Serialize}; 16use 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
275pub async fn try_and_get_repo_coordinates_when_remote_unknown( 286pub 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
319async fn get_nostr_git_remote_selection_labels( 330async 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
337fn get_repo_coordinates_from_git_config(git_repo: &Repo) -> Result<Coordinate> { 348fn 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
346async fn get_repo_coordinates_from_nostr_remotes( 357async 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
362async fn get_repo_coordinates_from_maintainers_yaml(git_repo: &Repo) -> Result<Coordinate> { 373async 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 );