forked from owenthereal/ccat
-
Notifications
You must be signed in to change notification settings - Fork 0
/
repo_stores.go
122 lines (108 loc) · 3.15 KB
/
repo_stores.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package store
import (
"fmt"
"reflect"
)
// scopeRepos returns a list of repos that are matched by the
// filters. If potentially all repos could match, or if enough repos
// could potentially match that it would probably be cheaper to
// iterate through all of them, then a nil slice is returned. If none
// match, an empty slice is returned.
//
// TODO(sqs): return an error if the filters are mutually exclusive?
func scopeRepos(filters []interface{}) ([]string, error) {
repos := map[string]struct{}{}
everHadAny := false // whether unitIDs ever contained any repos
for _, f := range filters {
switch f := f.(type) {
case ByReposFilter:
if len(repos) == 0 && !everHadAny {
everHadAny = true
for _, r := range f.ByRepos() {
repos[r] = struct{}{}
}
} else {
// Intersect.
newRepos := make(map[string]struct{}, (len(repos)+len(f.ByRepos()))/2)
for _, r := range f.ByRepos() {
if _, present := repos[r]; present {
newRepos[r] = struct{}{}
}
}
repos = newRepos
}
}
}
if len(repos) == 0 && !everHadAny {
// No unit scoping filters were present, so scope includes
// potentially all repos.
return nil, nil
}
repos2 := make([]string, 0, len(repos))
for repo := range repos {
repos2 = append(repos2, repo)
}
return repos2, nil
}
// A repoStoreOpener opens the RepoStore for the specified repo.
type repoStoreOpener interface {
openRepoStore(repo string) RepoStore
openAllRepoStores() (map[string]RepoStore, error)
}
// openRepoStores is a helper func that calls o.openRepoStore for each
// repo returned by scopeRepoStores(filters...).
func openRepoStores(o repoStoreOpener, filters interface{}) (map[string]RepoStore, error) {
repos, err := scopeRepos(storeFilters(filters))
if err != nil {
return nil, err
}
if repos == nil {
return o.openAllRepoStores()
}
rss := make(map[string]RepoStore, len(repos))
for _, repo := range repos {
rss[repo] = o.openRepoStore(repo)
}
return rss, nil
}
// filtersForRepo modifies the filters list to remove filters or
// conditions inside filters that are guaranteed to be true or
// unnecessary when using the filters on a call to a specific repo
// store.
func filtersForRepo(repo string, filters interface{}) interface{} {
// Copy filters so that it can be used concurrently.
sf := storeFilters(filters)
repoFilters := make([]interface{}, len(sf))
copy(repoFilters, sf)
d := 0 // deleted (-) and added (+) indexes in repoFilters vs. sf
for i, f := range sf {
switch f := f.(type) {
case byRepoCommitIDsFilter:
found := false
for _, v := range f.ByRepoCommitIDs() {
if v.Repo == repo {
repoFilters[i+d] = ByCommitIDs(v.CommitID)
found = true
break
}
}
if !found {
panic(fmt.Sprintf("in ByRepoCommitIDsFilter, no version.Repo == %q", repo))
}
case byReposFilter:
found := false
for _, r := range f.ByRepos() {
if r == repo {
repoFilters = append(repoFilters[:i+d], repoFilters[i+d+1:]...)
found = true
d--
break
}
}
if !found {
panic(fmt.Sprintf("in ByReposFilter, no version.Repo == %q", repo))
}
}
}
return toTypedFilterSlice(reflect.TypeOf(filters), repoFilters)
}