// Package repo liefert die Repo-Kennung für die Nutzungsmeldung (→ KONZEPT.md 11.5). package repo import ( "context" "os" "os/exec" "path/filepath" "regexp" "strings" "time" ) // Id ist die vereinheitlichte Git-Remote-URL von origin, z. B. // git.intern/shop/api. Ohne Remote: der Pfad relativ zum Benutzerordner. func Id(repo string) string { ctx, abort := context.WithTimeout(context.Background(), 5*time.Second) defer abort() from, err := exec.CommandContext(ctx, "git", "-C", repo, "remote", "get-url", "origin").Output() if err == nil { if k := Unify(strings.TrimSpace(string(from))); k != "" { return k } } abs, _ := filepath.Abs(repo) if home, err := os.UserHomeDir(); err == nil { if rel, err := filepath.Rel(home, abs); err == nil && !strings.HasPrefix(rel, "..") { return "~/" + filepath.ToSlash(rel) } } return filepath.ToSlash(abs) } var scpForm = regexp.MustCompile(`^[^@/:]+@([^:/]+):(.+)$`) // git@host:pfad // Unify entfernt Schema, Zugangsdaten, Port bei SSH und .git: // https://user:pw@git.intern/shop/api.git und git@git.intern:shop/api.git // werden beide zu git.intern/shop/api. func Unify(url string) string { if t := scpForm.FindStringSubmatch(url); t != nil { url = t[1] + "/" + t[2] } else { if i := strings.Index(url, "://"); i >= 0 { schema := url[:i] url = url[i+3:] if j := strings.Index(url, "@"); j >= 0 && j < strings.Index(url+"/", "/") { url = url[j+1:] } if schema == "ssh" { if host, rest, ok := strings.Cut(url, "/"); ok { url = strings.Split(host, ":")[0] + "/" + rest } } } } url = strings.TrimSuffix(strings.TrimSuffix(url, "/"), ".git") return strings.ToLower(url[:strings.Index(url+"/", "/")]) + url[strings.Index(url+"/", "/"):] }