upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/git.rs
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2024-09-03 15:30:37 +0100
committerDanConwayDev <DanConwayDev@protonmail.com>2024-09-03 15:30:37 +0100
commita825311f2c55661aaab3a163bda9109295c96044 (patch)
treeaf56db8858187a540ae90c38998a5222c8cc1f01 /src/git.rs
parenta0fdc17426afa0e55a2a3b733983bab763226e5a (diff)
feat(remote): enhance nostr url format
add protocol and user parameters so that users can overide the protcol in the clone url and use specific protocols for fetch and push. see: nostr:nevent1qvzqqqqqqypzpgqgmmc409hm4xsdd74sf68a2uyf9pwel4g9mfdg8l5244t6x4jdqyxhwumn8ghj7mn0wvhxcmmvqqsp6a5ck6grd9lq0nu25dcfzggxde67erut76w0ucal5rcfq4y5gzc7gmpzm the override feature hasn't been implemented yet but this is an enabler. also added a new format so that macos (zsh) users don't have to use quotes: nostr://<optional-protocol>/npub123/<optional-relay>/identifer
Diffstat (limited to 'src/git.rs')
-rw-r--r--src/git.rs145
1 files changed, 109 insertions, 36 deletions
diff --git a/src/git.rs b/src/git.rs
index 42ff587..5919667 100644
--- a/src/git.rs
+++ b/src/git.rs
@@ -835,55 +835,128 @@ fn extract_sig_from_patch_tags<'a>(
835 .context("failed to create git signature") 835 .context("failed to create git signature")
836} 836}
837 837
838pub fn nostr_git_url_to_repo_coordinates(url: &str) -> Result<HashSet<Coordinate>> { 838#[derive(Debug, PartialEq)]
839 let mut repo_coordinattes = HashSet::new(); 839pub enum ServerProtocol {
840 let url = Url::parse(url)?; 840 Ssh,
841 Https,
842 Http,
843 Git,
844}
841 845
842 if url.scheme().ne("nostr") { 846#[derive(Debug, PartialEq)]
843 bail!("nostr git url must start with nostr://") 847pub struct NostrUrlDecoded {
844 } 848 pub coordinates: HashSet<Coordinate>,
849 pub protocol: Option<ServerProtocol>,
850 pub user: Option<String>,
851}
845 852
846 if let Ok(coordinate) = Coordinate::parse(url.domain().context("no naddr")?) { 853static INCORRECT_NOSTR_URL_FORMAT_ERROR: &str = "incorrect nostr git url format. try nostr://naddr123 or nostr://npub123/my-repo or nostr://ssh/npub123/relay.damus.io/my-repo";
847 if coordinate.kind.eq(&nostr_sdk::Kind::GitRepoAnnouncement) { 854
848 repo_coordinattes.insert(coordinate); 855impl NostrUrlDecoded {
849 return Ok(repo_coordinattes); 856 pub fn from_str(url: &str) -> Result<Self> {
857 let mut coordinates = HashSet::new();
858 let mut protocol = None;
859 let mut user = None;
860 let mut relays = vec![];
861
862 if !url.starts_with("nostr://") {
863 bail!("nostr git url must start with nostr://");
864 }
865 // process get url parameters if present
866 for (name, value) in Url::parse(url)?.query_pairs() {
867 if name.contains("relay") {
868 let mut decoded = urlencoding::decode(&value)
869 .context("could not parse relays in nostr git url")?
870 .to_string();
871 if !decoded.starts_with("ws://") && !decoded.starts_with("wss://") {
872 decoded = format!("wss://{decoded}");
873 }
874 let url =
875 Url::parse(&decoded).context("could not parse relays in nostr git url")?;
876 relays.push(url.to_string());
877 } else if name == "protocol" {
878 protocol = match value.as_ref() {
879 "ssh" => Some(ServerProtocol::Ssh),
880 "https" => Some(ServerProtocol::Https),
881 "http" => Some(ServerProtocol::Http),
882 "git" => Some(ServerProtocol::Git),
883 _ => None,
884 };
885 } else if name == "user" {
886 user = Some(value.to_string());
887 }
850 } 888 }
851 bail!("naddr doesnt point to a git repository announcement");
852 }
853 889
854 if let Some(domain) = url.domain() { 890 let mut parts: Vec<&str> = url[8..]
855 if let Ok(public_key) = PublicKey::parse(domain) { 891 .split('?')
856 if url.path().len() < 2 { 892 .next()
857 bail!( 893 .unwrap_or("")
858 "nostr git url should include the repo identifier eg nostr://npub123/the-repo-identifer" 894 .split('/')
859 ); 895 .collect();
896
897 // extract optional protocol
898 if protocol.is_none() {
899 let part = parts.first().context(INCORRECT_NOSTR_URL_FORMAT_ERROR)?;
900 let protocol_str = if let Some(at_index) = part.find('@') {
901 user = Some(part[..at_index].to_string());
902 &part[at_index + 1..]
903 } else {
904 part
905 };
906 protocol = match protocol_str {
907 "ssh" => Some(ServerProtocol::Ssh),
908 "https" => Some(ServerProtocol::Https),
909 "http" => Some(ServerProtocol::Http),
910 "git" => Some(ServerProtocol::Git),
911 _ => protocol,
912 };
913 if protocol.is_some() {
914 parts.remove(0);
860 } 915 }
861 let mut relays = vec![]; 916 }
862 for (name, value) in url.query_pairs() { 917 // extract naddr npub/<optional-relays>/identifer
863 if name.contains("relay") { 918 let part = parts.first().context(INCORRECT_NOSTR_URL_FORMAT_ERROR)?;
864 let mut decoded = urlencoding::decode(&value) 919 // naddr used
865 .context("could not parse relays in nostr git url")? 920 if let Ok(coordinate) = Coordinate::parse(part) {
866 .to_string(); 921 if coordinate.kind.eq(&nostr_sdk::Kind::GitRepoAnnouncement) {
867 if !decoded.starts_with("ws://") && !decoded.starts_with("wss://") { 922 coordinates.insert(coordinate);
868 decoded = format!("wss://{decoded}"); 923 } else {
869 } 924 bail!("naddr doesnt point to a git repository announcement");
870 let url = 925 }
871 Url::parse(&decoded).context("could not parse relays in nostr git url")?; 926 // npub/<optional-relays>/identifer used
872 relays.push(url.to_string()); 927 } else if let Ok(public_key) = PublicKey::parse(part) {
928 parts.remove(0);
929 let identifier = parts
930 .pop()
931 .context("nostr url must have an identifier eg. nostr://npub123/repo-identifier")?
932 .to_string();
933 for relay in parts {
934 let mut decoded = urlencoding::decode(relay)
935 .context("could not parse relays in nostr git url")?
936 .to_string();
937 if !decoded.starts_with("ws://") && !decoded.starts_with("wss://") {
938 decoded = format!("wss://{decoded}");
873 } 939 }
940 let url =
941 Url::parse(&decoded).context("could not parse relays in nostr git url")?;
942 relays.push(url.to_string());
874 } 943 }
875 repo_coordinattes.insert(Coordinate { 944 coordinates.insert(Coordinate {
876 identifier: url.path()[1..].to_string(), 945 identifier,
877 public_key, 946 public_key,
878 kind: nostr_sdk::Kind::GitRepoAnnouncement, 947 kind: nostr_sdk::Kind::GitRepoAnnouncement,
879 relays, 948 relays,
880 }); 949 });
881 return Ok(repo_coordinattes); 950 } else {
951 bail!(INCORRECT_NOSTR_URL_FORMAT_ERROR);
882 } 952 }
953
954 Ok(Self {
955 coordinates,
956 protocol,
957 user,
958 })
883 } 959 }
884 bail!(
885 "nostr git url must be in format nostr://naddr123 or nostr://npub123/identifer?relay=wss://relay-example.com&relay1=wss://relay-example.org"
886 );
887} 960}
888 961
889/** produce error when using local repo or custom protocols */ 962/** produce error when using local repo or custom protocols */