upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/git/mod.rs
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2025-11-21 13:37:57 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2025-11-21 13:37:57 +0000
commit9a8c551adfada379704d594a6ff3862f13857b8e (patch)
treea902c6b313ab40a8914a34380ee194524dd67604 /src/git/mod.rs
parent12756fa66e3ec7f9dd24c66598085772829a8063 (diff)
add git http handling
Diffstat (limited to 'src/git/mod.rs')
-rw-r--r--src/git/mod.rs127
1 files changed, 127 insertions, 0 deletions
diff --git a/src/git/mod.rs b/src/git/mod.rs
new file mode 100644
index 0000000..bd3b9e8
--- /dev/null
+++ b/src/git/mod.rs
@@ -0,0 +1,127 @@
1//! Git Smart HTTP Backend
2//!
3//! This module implements Git Smart HTTP protocol support for ngit-grasp.
4//! It provides handlers for clone, fetch, and push operations over HTTP.
5//!
6//! # Architecture
7//!
8//! - `protocol` - Git pkt-line format parsing and utilities
9//! - `subprocess` - Git process spawning and management
10//! - `handlers` - HTTP request handlers for Git operations
11//!
12//! # URL Patterns
13//!
14//! The following URL patterns are supported:
15//! - `GET /<npub>/<identifier>.git/info/refs?service=git-upload-pack` - Clone/fetch advertisement
16//! - `GET /<npub>/<identifier>.git/info/refs?service=git-receive-pack` - Push advertisement
17//! - `POST /<npub>/<identifier>.git/git-upload-pack` - Clone/fetch operation
18//! - `POST /<npub>/<identifier>.git/git-receive-pack` - Push operation
19
20pub mod handlers;
21pub mod protocol;
22pub mod subprocess;
23
24use std::path::PathBuf;
25
26/// Parse a Git repository path from URL components
27///
28/// Converts /<npub>/<identifier>.git/* to a filesystem path
29///
30/// # Arguments
31/// * `git_data_path` - Base directory for Git repositories
32/// * `npub` - The npub (Nostr public key in bech32 format)
33/// * `identifier` - The repository identifier
34///
35/// # Returns
36/// Path to the bare Git repository
37pub fn resolve_repo_path(git_data_path: &str, npub: &str, identifier: &str) -> PathBuf {
38 // Remove .git suffix if present
39 let identifier = identifier.strip_suffix(".git").unwrap_or(identifier);
40
41 PathBuf::from(git_data_path)
42 .join(npub)
43 .join(format!("{}.git", identifier))
44}
45
46/// Extract npub and identifier from a Git URL path
47///
48/// Parses paths like `/<npub>/<identifier>.git/info/refs`
49///
50/// Returns (npub, identifier, subpath) where subpath is the part after .git/
51pub fn parse_git_url(path: &str) -> Option<(&str, &str, &str)> {
52 // Remove leading slash
53 let path = path.strip_prefix('/').unwrap_or(path);
54
55 // Split into components
56 let parts: Vec<&str> = path.splitn(3, '/').collect();
57
58 if parts.len() < 3 {
59 return None;
60 }
61
62 let npub = parts[0];
63 let repo_part = parts[1];
64 let subpath = parts[2];
65
66 // Extract identifier (remove .git suffix if present for the middle part)
67 let identifier = if repo_part.ends_with(".git") {
68 &repo_part[..repo_part.len() - 4]
69 } else {
70 repo_part
71 };
72
73 Some((npub, identifier, subpath))
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79
80 #[test]
81 fn test_resolve_repo_path() {
82 let path = resolve_repo_path(
83 "/data/git",
84 "npub1abc123",
85 "my-repo"
86 );
87 assert_eq!(
88 path,
89 PathBuf::from("/data/git/npub1abc123/my-repo.git")
90 );
91 }
92
93 #[test]
94 fn test_resolve_repo_path_with_git_suffix() {
95 let path = resolve_repo_path(
96 "/data/git",
97 "npub1abc123",
98 "my-repo.git"
99 );
100 assert_eq!(
101 path,
102 PathBuf::from("/data/git/npub1abc123/my-repo.git")
103 );
104 }
105
106 #[test]
107 fn test_parse_git_url_info_refs() {
108 let (npub, id, subpath) = parse_git_url("/npub1abc/repo.git/info/refs").unwrap();
109 assert_eq!(npub, "npub1abc");
110 assert_eq!(id, "repo");
111 assert_eq!(subpath, "info/refs");
112 }
113
114 #[test]
115 fn test_parse_git_url_upload_pack() {
116 let (npub, id, subpath) = parse_git_url("/npub1abc/repo.git/git-upload-pack").unwrap();
117 assert_eq!(npub, "npub1abc");
118 assert_eq!(id, "repo");
119 assert_eq!(subpath, "git-upload-pack");
120 }
121
122 #[test]
123 fn test_parse_git_url_invalid() {
124 assert!(parse_git_url("/npub1abc").is_none());
125 assert!(parse_git_url("/npub1abc/repo").is_none());
126 }
127} \ No newline at end of file