// Copyright (C) 2024 Umorpha Systems // SPDX-License-Identifier: AGPL-3.0-or-later package gitcache import ( "fmt" "regexp" "strings" ) func NormalizeURL(url string) string { // > Clients MUST strip a trailing `/`, if present, from the // > user supplied `$GIT_URL` string // -- gitprotocol-http(5) url = strings.TrimRight(url, "/") return url } func ValidateURL(url string) bool { return NormalizeURL(url) != "" } func URL2NS(url string) string { url = NormalizeURL(url) var id strings.Builder id.Grow(len(url)) for i := 0; i < len(url); i++ { b := url[i] switch { case b == '!', // our own escape // see: git-check-ref-format(1) b <= ' ', b == '\x7F', // never: ASCII control characters b == '~', b == '^', b == ':', // never: gitrevision meaning b == '?', b == '*', b == '[', // never: refspec pattern b == '\\', // never: backslash b == '.', b == '@', b == '/': // sometimes: special rules fmt.Fprintf(&id, "!%02x", b) default: id.WriteByte(b) } } return id.String() } var reEsc = regexp.MustCompile("![0-9a-f]{2}") func hex2int(h byte) byte { switch { case '0' <= h && h <= '9': return h - '0' case 'a' <= h && h <= 'f': return h - 'a' + 0xa default: panic("should not happen") } } func NS2URL(id string) string { return reEsc.ReplaceAllStringFunc(id, func(esc string) string { b := hex2int(esc[1])<<4 | hex2int(esc[2]) return string([]byte{b}) }) }