main
Raw Download raw file
 1package repo
 2
 3import (
 4	"fmt"
 5	"os"
 6	"path/filepath"
 7	"sort"
 8)
 9
10// Repo represents a bare git repository discovered under the root.
11type Repo struct {
12	FullPath string
13	RelPath  string
14	Name     string
15	Category string
16}
17
18// IsBare reports whether path looks like a bare git repo by checking
19// for a HEAD file.
20func IsBare(path string) (bool, error) {
21	info, err := os.Stat(filepath.Join(path, "HEAD"))
22	if os.IsNotExist(err) {
23		return false, nil
24	}
25	if err != nil {
26		return false, fmt.Errorf("checking HEAD in %s: %w", path, err)
27	}
28	return !info.IsDir(), nil
29}
30
31// Discover walks a two-level directory structure (category/repo) under root
32// and returns all bare git repos found, sorted by RelPath.
33func Discover(root string) ([]Repo, error) {
34	categories, err := os.ReadDir(root)
35	if err != nil {
36		return nil, fmt.Errorf("reading root dir (root=%s): %w", root, err)
37	}
38
39	var repos []Repo
40	for _, cat := range categories {
41		if !cat.IsDir() {
42			continue
43		}
44		catPath := filepath.Join(root, cat.Name())
45		entries, err := os.ReadDir(catPath)
46		if err != nil {
47			return nil, fmt.Errorf("reading category dir (category=%s): %w", cat.Name(), err)
48		}
49		for _, entry := range entries {
50			if !entry.IsDir() {
51				continue
52			}
53			repoPath := filepath.Join(catPath, entry.Name())
54			bare, err := IsBare(repoPath)
55			if err != nil {
56				return nil, err
57			}
58			if !bare {
59				continue
60			}
61			repos = append(repos, Repo{
62				FullPath: repoPath,
63				RelPath:  filepath.Join(cat.Name(), entry.Name()),
64				Name:     entry.Name(),
65				Category: cat.Name(),
66			})
67		}
68	}
69
70	sort.Slice(repos, func(i, j int) bool {
71		return repos[i].RelPath < repos[j].RelPath
72	})
73	return repos, nil
74}