package vcs import ( "context" "io" "tangled.org/core/knotserver/git" ) // gitReadAdapter wraps a git.GitRepo to implement ReadRepo. type gitReadAdapter struct { g *git.GitRepo } func newGitReadAdapter(g *git.GitRepo) *gitReadAdapter { return &gitReadAdapter{g: g} } func (a *gitReadAdapter) VCSType() string { return "git" } func (a *gitReadAdapter) Path() string { return a.g.Path() } func (a *gitReadAdapter) History(offset, limit int) ([]HistoryEntry, error) { commits, err := a.g.Commits(offset, limit) if err != nil { return nil, err } entries := make([]HistoryEntry, 0, len(commits)) for _, c := range commits { parents := make([]string, 0, len(c.ParentHashes)) for _, p := range c.ParentHashes { parents = append(parents, p.String()) } entries = append(entries, HistoryEntry{ Hash: c.Hash.String(), Author: Author{ Name: c.Author.Name, Email: c.Author.Email, When: c.Author.When, }, Committer: Author{ Name: c.Committer.Name, Email: c.Committer.Email, When: c.Committer.When, }, Message: c.Message, Timestamp: c.Committer.When, Parents: parents, }) } return entries, nil } func (a *gitReadAdapter) TotalHistoryEntries() (int, error) { return a.g.TotalCommits() } func (a *gitReadAdapter) HistoryEntry(hash string) (*HistoryEntry, error) { c, err := a.g.Commit(gitHash(hash)) if err != nil { return nil, err } parents := make([]string, 0, len(c.ParentHashes)) for _, p := range c.ParentHashes { parents = append(parents, p.String()) } return &HistoryEntry{ Hash: c.Hash.String(), Author: Author{ Name: c.Author.Name, Email: c.Author.Email, When: c.Author.When, }, Committer: Author{ Name: c.Committer.Name, Email: c.Committer.Email, When: c.Committer.When, }, Message: c.Message, Timestamp: c.Committer.When, Parents: parents, }, nil } func (a *gitReadAdapter) Branches(opts *PaginationOpts) ([]BranchInfo, error) { var gitOpts *git.BranchesOptions if opts != nil { gitOpts = &git.BranchesOptions{ Limit: opts.Limit, Offset: opts.Offset, } } branches, err := a.g.Branches(gitOpts) if err != nil { return nil, err } infos := make([]BranchInfo, 0, len(branches)) for _, b := range branches { info := BranchInfo{ Name: b.Name, Hash: b.Hash, IsDefault: b.IsDefault, } if b.Commit != nil { info.LatestEntry = &HistoryEntry{ Hash: b.Commit.Hash.String(), Author: Author{ Name: b.Commit.Author.Name, Email: b.Commit.Author.Email, When: b.Commit.Author.When, }, Committer: Author{ Name: b.Commit.Committer.Name, Email: b.Commit.Committer.Email, When: b.Commit.Committer.When, }, Message: b.Commit.Message, Timestamp: b.Commit.Committer.When, } } infos = append(infos, info) } return infos, nil } func (a *gitReadAdapter) DefaultBranch() (string, error) { return a.g.FindMainBranch() } func (a *gitReadAdapter) FileTree(ctx context.Context, path string) ([]TreeEntry, error) { files, err := a.g.FileTree(ctx, path) if err != nil { return nil, err } entries := make([]TreeEntry, 0, len(files)) for _, f := range files { entry := TreeEntry{ Name: f.Name, Mode: f.Mode, Size: f.Size, } if f.LastCommit != nil { entry.LastCommit = &LastCommitInfo{ Hash: f.LastCommit.Hash.String(), Message: f.LastCommit.Message, When: f.LastCommit.When, } } entries = append(entries, entry) } return entries, nil } func (a *gitReadAdapter) FileContentN(path string, cap int64) ([]byte, error) { return a.g.FileContentN(path, cap) } func (a *gitReadAdapter) RawContent(path string) ([]byte, error) { return a.g.RawContent(path) } func (a *gitReadAdapter) WriteTar(w io.Writer, prefix string) error { return a.g.WriteTar(w, prefix) } func (a *gitReadAdapter) Tags(opts *PaginationOpts) ([]TagInfo, error) { var gitOpts *git.TagsOptions if opts != nil { gitOpts = &git.TagsOptions{ Limit: opts.Limit, Offset: opts.Offset, } } tags, err := a.g.Tags(gitOpts) if err != nil { return nil, err } infos := make([]TagInfo, 0, len(tags)) for _, t := range tags { info := TagInfo{ Name: t.Name, Hash: t.Hash.String(), Message: t.Message, Target: t.Target.String(), } if t.Tagger.Name != "" { info.Tagger = &Author{ Name: t.Tagger.Name, Email: t.Tagger.Email, When: t.Tagger.When, } } infos = append(infos, info) } return infos, nil } // gitMutableAdapter wraps a git.GitRepo to implement MutableRepo. type gitMutableAdapter struct { *gitReadAdapter } func newGitMutableAdapter(g *git.GitRepo) *gitMutableAdapter { return &gitMutableAdapter{gitReadAdapter: newGitReadAdapter(g)} } func (a *gitMutableAdapter) SetDefaultBranch(name string) error { return a.g.SetDefaultBranch(name) } func (a *gitMutableAdapter) DeleteBranch(name string) error { return a.g.DeleteBranch(name) } // Git returns the underlying *git.GitRepo for git-specific operations // (diff, merge, format-patch, etc.) that don't belong in the VCS interface. func (a *gitReadAdapter) Git() *git.GitRepo { return a.g }