Skip to content

Commit 6787eb3

Browse files
committed
Add RepositoryPool and companion code
Signed-off-by: Javi Fontan <[email protected]>
1 parent ca31cf6 commit 6787eb3

File tree

1 file changed

+199
-0
lines changed

1 file changed

+199
-0
lines changed

repositories.go

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
package gitquery
2+
3+
import (
4+
"io"
5+
6+
"gopkg.in/src-d/go-git.v4"
7+
"gopkg.in/src-d/go-mysql-server.v0/sql"
8+
)
9+
10+
// Repository struct holds an initialized repository and its ID
11+
type Repository struct {
12+
ID string
13+
Repo *git.Repository
14+
}
15+
16+
// NewRepository creates and initializes a new Repository structure
17+
func NewRepository(id string, repo *git.Repository) Repository {
18+
return Repository{
19+
ID: id,
20+
Repo: repo,
21+
}
22+
}
23+
24+
// RepositoryPool holds a pool of initialized git repositories and
25+
// functionality to open and iterate them.
26+
type RepositoryPool struct {
27+
repositories []Repository
28+
}
29+
30+
// NewRepositoryPool initializes a new RepositoryPool
31+
func NewRepositoryPool() RepositoryPool {
32+
return RepositoryPool{}
33+
}
34+
35+
// Add inserts a new repository in the pool
36+
func (p *RepositoryPool) Add(id string, repo *git.Repository) {
37+
repository := NewRepository(id, repo)
38+
p.repositories = append(p.repositories, repository)
39+
}
40+
41+
// AddGit opens a new git repository and adds it to the pool. It
42+
// also sets its path as ID.
43+
func (p *RepositoryPool) AddGit(path string) (string, error) {
44+
repo, err := git.PlainOpen(path)
45+
if err != nil {
46+
return "", err
47+
}
48+
49+
p.Add(path, repo)
50+
51+
return path, nil
52+
}
53+
54+
// GetPos retrieves a repository at a given position. It returns false
55+
// as second return value if the position is out of bounds.
56+
func (p *RepositoryPool) GetPos(pos int) (*Repository, bool) {
57+
if pos >= len(p.repositories) {
58+
return nil, false
59+
}
60+
61+
return &p.repositories[pos], true
62+
}
63+
64+
// RepoIter creates a new Repository iterator
65+
func (p *RepositoryPool) RepoIter() (*RepositoryIter, error) {
66+
iter := &RepositoryIter{
67+
pos: 0,
68+
pool: p,
69+
}
70+
71+
return iter, nil
72+
}
73+
74+
// RepositoryIter iterates over all repositories in the pool
75+
type RepositoryIter struct {
76+
pos int
77+
pool *RepositoryPool
78+
}
79+
80+
// Next retrieves the next Repository. It returns io.EOF as error
81+
// when there are no more Repositories to retrieve.
82+
func (i *RepositoryIter) Next() (*Repository, error) {
83+
r, ok := i.pool.GetPos(i.pos)
84+
if !ok {
85+
return nil, io.EOF
86+
}
87+
88+
i.pos++
89+
90+
return r, nil
91+
}
92+
93+
// Close finished iterator. It's no-op.
94+
func (i *RepositoryIter) Close() error {
95+
return nil
96+
}
97+
98+
type funcInitRepository func(Repository, interface{}) error
99+
type funcNextRow func(interface{}) (sql.Row, error)
100+
type funcClose func(interface{}) error
101+
102+
// RowRepoIter is used as the base to iterate over all the repositories
103+
// in the pool. It needs three functions that execute specific code per
104+
// implemented iterator.
105+
type RowRepoIter struct {
106+
repositoryIter *RepositoryIter
107+
repository *Repository
108+
data interface{}
109+
110+
funcInitRepository funcInitRepository
111+
funcNextRow funcNextRow
112+
funcClose funcClose
113+
}
114+
115+
// NewRowRepoIter initializes a new repository iterator.
116+
//
117+
// * pool: is a RepositoryPool we want to iterate
118+
// * data: this pointer will be passed to the provided functions and is useful
119+
// to save state like initialized iterators or other needed variables
120+
// * init: called when a new repository is about to be iterated, initialize
121+
// its iterator there
122+
// * next: called for each row
123+
// * close: called when a repository finished iterating
124+
func NewRowRepoIter(pool *RepositoryPool, data interface{},
125+
init funcInitRepository, next funcNextRow,
126+
close funcClose) (RowRepoIter, error) {
127+
128+
rIter, err := pool.RepoIter()
129+
if err != nil {
130+
return RowRepoIter{}, err
131+
}
132+
133+
repo := RowRepoIter{
134+
repositoryIter: rIter,
135+
funcInitRepository: init,
136+
funcNextRow: next,
137+
funcClose: close,
138+
data: data,
139+
}
140+
141+
err = repo.nextRepository()
142+
if err != nil {
143+
return RowRepoIter{}, err
144+
}
145+
146+
return repo, nil
147+
}
148+
149+
// nextRepository is called to initialize the next repository. It is called
150+
// when the iterator is created and when the previous repository finished
151+
// iterating.
152+
func (i *RowRepoIter) nextRepository() error {
153+
repo, err := i.repositoryIter.Next()
154+
if err != nil {
155+
return err
156+
}
157+
158+
i.repository = repo
159+
err = i.funcInitRepository(*repo, i.data)
160+
if err != nil {
161+
return err
162+
}
163+
164+
return nil
165+
}
166+
167+
// Next gets the next row
168+
func (i *RowRepoIter) Next() (sql.Row, error) {
169+
for {
170+
row, err := i.funcNextRow(i.data)
171+
172+
switch err {
173+
case nil:
174+
return row, nil
175+
176+
case io.EOF:
177+
i.Close()
178+
179+
err := i.nextRepository()
180+
if err != nil {
181+
return nil, err
182+
}
183+
184+
default:
185+
return nil, err
186+
}
187+
}
188+
189+
return nil, nil
190+
}
191+
192+
// Close called to close the iterator
193+
func (i *RowRepoIter) Close() error {
194+
if i.funcClose != nil {
195+
return i.funcClose(i.data)
196+
}
197+
198+
return nil
199+
}

0 commit comments

Comments
 (0)