indexer/scraper/forgejo_readme.go
2026-09-28 15:36:42 +02:00

70 lines
1.9 KiB
Go

package scraper
import (
"sort"
"strings"
"github.com/go-enry/go-license-detector/v4/licensedb/filer"
)
// readmeCandidates are the filenames looked for, in priority order, when
// retrieving a repository's README.
var readmeCandidates = []string{"README.md", "README.rst", "README.txt", "README"}
// readmeFor returns the content of the repository's README on the given ref
// (default branch), picking from root (the pre-fetched root file listing) the
// first candidate found (case-insensitively). An empty string is returned when
// no README can be found; the repo is still kept in results either way.
func (s *ForgejoScraper) readmeFor(owner, name, ref string, root []filer.File) string {
// Collect root file names, lowercased for case-insensitive matching, while
// keeping the real name for the GetFile call.
type rootFile struct {
real string
low string
}
files := make([]rootFile, 0, len(root))
for _, e := range root {
if e.IsDir {
continue
}
files = append(files, rootFile{real: e.Name, low: strings.ToLower(e.Name)})
}
// Candidate priority wins; ties broken by alphabetical real name for
// deterministic picks when a repo has e.g. both README and README.md.
sort.SliceStable(files, func(i, j int) bool {
pi, pj := readmePriority(files[i].low), readmePriority(files[j].low)
if pi != pj {
return pi < pj // lower = higher priority
}
return files[i].real < files[j].real
})
var chosen string
for i := range files {
if readmePriority(files[i].low) >= 0 {
chosen = files[i].real
break
}
}
if chosen == "" {
return ""
}
data, _, err := s.Client.GetFile(owner, name, ref, chosen)
if err != nil {
return ""
}
return string(data)
}
// readmePriority returns the index of a lowercased filename in
// readmeCandidates, or -1 if it is not a readme candidate.
func readmePriority(low string) int {
for i, c := range readmeCandidates {
if low == strings.ToLower(c) {
return i
}
}
return -1
}