package repository
import (
"errors"
"os"
"path/filepath"
"sort"
"sync"
"github.com/go-git/go-git/v5"
)
type Info struct {
Name string
Path string
}
type Store struct {
root string
repos map[string]Info
mu sync.Mutex
cache map[string]*Repository
}
func Discover(root string) (*Store, error) {
entries, err := os.ReadDir(root)
if err != nil {
return nil, err
}
repos := make(map[string]Info)
for _, entry := range entries {
if !entry.IsDir() {
continue
}
name := entry.Name()
path := filepath.Join(root, name)
if _, err := git.PlainOpen(path); err != nil {
if errors.Is(err, git.ErrRepositoryNotExists) {
continue
}
return nil, err
}
repos[name] = Info{Name: name, Path: path}
}
return &Store{
root: root,
repos: repos,
cache: make(map[string]*Repository),
}, nil
}
func (s *Store) Root() string {
return s.root
}
func (s *Store) List() []Info {
items := make([]Info, 0, len(s.repos))
for _, repo := range s.repos {
items = append(items, repo)
}
sort.Slice(items, func(i, j int) bool {
return items[i].Name < items[j].Name
})
return items
}
func (s *Store) Open(name string) (*Repository, error) {
info, ok := s.repos[name]
if !ok {
return nil, os.ErrNotExist
}
s.mu.Lock()
defer s.mu.Unlock()
if repo, ok := s.cache[name]; ok {
return repo, nil
}
repo, err := Open(info.Name, info.Path)
if err != nil {
return nil, err
}
s.cache[name] = repo
return repo, nil
}