hugin/cli/internal/repo/repo.go
2026-10-27 08:33:21 +01:00

58 lines
1.7 KiB
Go

// 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+"/", "/"):]
}