A container registry that uses the AT Protocol for manifest storage and S3 for blob storage.
at codeberg-source 116 lines 3.4 kB view raw
1package readme 2 3import ( 4 "fmt" 5 "net/url" 6 "strings" 7) 8 9// Platform represents a supported Git hosting platform 10type Platform string 11 12const ( 13 PlatformGitHub Platform = "github" 14 PlatformGitLab Platform = "gitlab" 15 PlatformTangled Platform = "tangled" 16 PlatformCodeberg Platform = "codeberg" 17) 18 19// ParseSourceURL extracts platform, user, and repo from a source repository URL. 20// Returns ok=false if the URL is not a recognized pattern. 21func ParseSourceURL(sourceURL string) (platform Platform, user, repo string, ok bool) { 22 if sourceURL == "" { 23 return "", "", "", false 24 } 25 26 parsed, err := url.Parse(sourceURL) 27 if err != nil { 28 return "", "", "", false 29 } 30 31 // Normalize: remove trailing slash and .git suffix 32 path := strings.TrimSuffix(parsed.Path, "/") 33 path = strings.TrimSuffix(path, ".git") 34 path = strings.TrimPrefix(path, "/") 35 36 if path == "" { 37 return "", "", "", false 38 } 39 40 host := strings.ToLower(parsed.Host) 41 42 switch host { 43 case "github.com": 44 // GitHub: github.com/{user}/{repo} 45 parts := strings.SplitN(path, "/", 3) 46 if len(parts) < 2 || parts[0] == "" || parts[1] == "" { 47 return "", "", "", false 48 } 49 return PlatformGitHub, parts[0], parts[1], true 50 51 case "gitlab.com": 52 // GitLab: gitlab.com/{user}/{repo} or gitlab.com/{group}/{subgroup}/{repo} 53 // For nested groups, user = everything except last part, repo = last part 54 lastSlash := strings.LastIndex(path, "/") 55 if lastSlash == -1 || lastSlash == 0 { 56 return "", "", "", false 57 } 58 user = path[:lastSlash] 59 repo = path[lastSlash+1:] 60 if user == "" || repo == "" { 61 return "", "", "", false 62 } 63 return PlatformGitLab, user, repo, true 64 65 case "tangled.org", "tangled.sh": 66 // Tangled: tangled.org/{user}/{repo} or tangled.sh/@{user}/{repo} (legacy) 67 // Strip leading @ from user if present 68 path = strings.TrimPrefix(path, "@") 69 parts := strings.SplitN(path, "/", 3) 70 if len(parts) < 2 || parts[0] == "" || parts[1] == "" { 71 return "", "", "", false 72 } 73 return PlatformTangled, parts[0], parts[1], true 74 75 case "codeberg.org": 76 // Codeberg: codeberg.org/{user}/{repo} 77 parts := strings.SplitN(path, "/", 3) 78 if len(parts) < 2 || parts[0] == "" || parts[1] == "" { 79 return "", "", "", false 80 } 81 return PlatformCodeberg, parts[0], parts[1], true 82 83 default: 84 return "", "", "", false 85 } 86} 87 88// DeriveReadmeURL converts a source repository URL to a raw README URL. 89// Returns empty string if platform is not supported. 90func DeriveReadmeURL(sourceURL, branch string) string { 91 platform, user, repo, ok := ParseSourceURL(sourceURL) 92 if !ok { 93 return "" 94 } 95 96 switch platform { 97 case PlatformGitHub: 98 // https://raw.githubusercontent.com/{user}/{repo}/refs/heads/{branch}/README.md 99 return fmt.Sprintf("https://raw.githubusercontent.com/%s/%s/refs/heads/%s/README.md", user, repo, branch) 100 101 case PlatformGitLab: 102 // https://gitlab.com/{user}/{repo}/-/raw/{branch}/README.md 103 return fmt.Sprintf("https://gitlab.com/%s/%s/-/raw/%s/README.md", user, repo, branch) 104 105 case PlatformTangled: 106 // https://tangled.org/{user}/{repo}/raw/{branch}/README.md 107 return fmt.Sprintf("https://tangled.org/%s/%s/raw/%s/README.md", user, repo, branch) 108 109 case PlatformCodeberg: 110 // https://codeberg.org/{user}/{repo}/raw/branch/{branch}/README.md 111 return fmt.Sprintf("https://codeberg.org/%s/%s/raw/branch/%s/README.md", user, repo, branch) 112 113 default: 114 return "" 115 } 116}