git@cosmocr.at/gitweb.git @ HEAD · summary refs log
HEAD / internal / gitrepo / locate.go /
internal/gitrepo/locate.go · 1.8 KiB · raw
view: SourceMarkdown ☑ force

package gitrepo

import ( "errors" "strings"

"gitweb/internal/store"

)

// Locate finds whether the upspin path "" points into a bare git // repository. It scans path prefixes from the user root downward and returns // the shallowest prefix that is a bare repo (repos do not nest), along with the // remaining path after it. // // - user: validated upspin user, e.g. "u@d.com" // - clean: the cleaned remainder, always beginning with "/", e.g. "/proj.git/log/main" // // On a match it returns repoPath="u@d.com/proj.git", rest="log/main", found=true. // found=false means no repo lies on this path and the caller should fall back to // plain namespace browsing. A store error other than not-found is returned. func Locate(st store.Store, user, clean string) (repoPath, rest string, found bool, err error) { trimmed := strings.Trim(clean, "/") var segs []string if trimmed != "" { segs = strings.Split(trimmed, "/") }

// Candidates shallow -> deep: user, user/seg1, user/seg1/seg2, ...
prefix := user
for i := 0; ; i++ {
	ok, err := isRepo(st, prefix)
	if err != nil {
		return "", "", false, err
	}
	if ok {
		return prefix, strings.Join(segs[i:], "/"), true, nil
	}
	if i >= len(segs) {
		break
	}
	prefix = prefix + "/" + segs[i]
}
return "", "", false, nil

}

// isRepo reports whether prefix is a bare git repository: it must contain a // HEAD file and an objects directory. Not-found on either means "not a repo". func isRepo(st store.Store, prefix string) (bool, error) { headIsDir, err := st.Stat(prefix + "/HEAD") if err != nil { if errors.Is(err, store.ErrNotFound) { return false, nil } return false, err } if headIsDir { return false, nil } objIsDir, err := st.Stat(prefix + "/objects") if err != nil { if errors.Is(err, store.ErrNotFound) { return false, nil } return false, err } return objIsDir, nil }