package service import ( "compress/gzip" "errors" "io" "log/slog" "git.gabrielgio.me/cerrado/pkg/config" "git.gabrielgio.me/cerrado/pkg/git" "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing/object" ) type ( Repository struct { Name string Description string LastCommitDate string Ref string } GitService struct { configRepo configurationRepository } configurationRepository interface { List() []*config.GitRepositoryConfiguration GetByName(name string) *config.GitRepositoryConfiguration } ) var ErrRepositoryNotFound = errors.New("Repository not found") // TODO: make it configurable const timeFormat = "2006.01.02 15:04:05" func NewGitService(configRepo configurationRepository) *GitService { return &GitService{ configRepo: configRepo, } } func (g *GitService) ListRepositories() ([]*Repository, error) { rs := g.configRepo.List() repos := make([]*Repository, 0, len(rs)) for _, r := range rs { repo, err := git.OpenRepository(r.Path) if err != nil { return nil, err } obj, err := repo.LastCommit() if err != nil { slog.Error("Error fetching last commit", "repository", r.Path, "error", err) continue } head, err := repo.Head() if err != nil { slog.Error("Error fetching head", "repository", r.Path, "error", err) continue } repos = append(repos, &Repository{ Name: r.Name, Description: r.Description, LastCommitDate: obj.Author.When.Format(timeFormat), Ref: head.Name().Short(), }) } return repos, nil } func (g *GitService) ListCommits(name, ref string, count int) ([]*object.Commit, error) { r := g.configRepo.GetByName(name) if r == nil { return nil, ErrRepositoryNotFound } repo, err := git.OpenRepository(r.Path) if err != nil { return nil, err } err = repo.SetRef(ref) if err != nil { return nil, err } return repo.Commits(count) } func (g *GitService) LastCommit(name, ref string) (*object.Commit, error) { r := g.configRepo.GetByName(name) if r == nil { return nil, ErrRepositoryNotFound } repo, err := git.OpenRepository(r.Path) if err != nil { return nil, err } err = repo.SetRef(ref) if err != nil { return nil, err } return repo.LastCommit() } func (g *GitService) WriteTarGZip(w io.Writer, name, ref string, prefix string) error { r := g.configRepo.GetByName(name) if r == nil { return ErrRepositoryNotFound } repo, err := git.OpenRepository(r.Path) if err != nil { return err } err = repo.SetRef(ref) if err != nil { return err } gw := gzip.NewWriter(w) defer gw.Close() err = repo.WriteTar(gw, prefix) if err != nil { return err } return nil } func (g *GitService) Diff(name, ref string) (string, error) { r := g.configRepo.GetByName(name) if r == nil { return "", ErrRepositoryNotFound } repo, err := git.OpenRepository(r.Path) if err != nil { return "", err } err = repo.SetRef(ref) if err != nil { return "", err } return repo.Diff() } func (g *GitService) GetTree(name, ref, path string) (*object.Tree, error) { r := g.configRepo.GetByName(name) if r == nil { return nil, ErrRepositoryNotFound } repo, err := git.OpenRepository(r.Path) if err != nil { return nil, err } err = repo.SetRef(ref) if err != nil { return nil, err } return repo.Tree(path) } func (g *GitService) IsBinary(name, ref, path string) (bool, error) { r := g.configRepo.GetByName(name) if r == nil { return false, ErrRepositoryNotFound } repo, err := git.OpenRepository(r.Path) if err != nil { return false, err } err = repo.SetRef(ref) if err != nil { return false, err } return repo.IsBinary(path) } func (g *GitService) GetFileContent(name, ref, path string) ([]byte, error) { r := g.configRepo.GetByName(name) if r == nil { return nil, ErrRepositoryNotFound } repo, err := git.OpenRepository(r.Path) if err != nil { return nil, err } err = repo.SetRef(ref) if err != nil { return nil, err } return repo.FileContent(path) } func (g *GitService) GetAbout(name string) ([]byte, error) { r := g.configRepo.GetByName(name) if r == nil { return nil, ErrRepositoryNotFound } repo, err := git.OpenRepository(r.Path) if err != nil { return nil, err } err = repo.SetRef("") if err != nil { return nil, err } file, err := repo.FileContent(r.About) if err != nil { return nil, err } return file, nil } func (g *GitService) ListTags(name string) ([]*git.TagReference, error) { r := g.configRepo.GetByName(name) if r == nil { return nil, ErrRepositoryNotFound } repo, err := git.OpenRepository(r.Path) if err != nil { return nil, err } return repo.Tags() } func (g *GitService) ListBranches(name string) ([]*plumbing.Reference, error) { r := g.configRepo.GetByName(name) if r == nil { return nil, ErrRepositoryNotFound } repo, err := git.OpenRepository(r.Path) if err != nil { return nil, err } return repo.Branches() } func (g *GitService) GetHead(name string) (*plumbing.Reference, error) { r := g.configRepo.GetByName(name) if r == nil { return nil, ErrRepositoryNotFound } repo, err := git.OpenRepository(r.Path) if err != nil { return nil, err } return repo.Head() }