-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcacher.go
129 lines (106 loc) · 3.17 KB
/
cacher.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
123
124
125
126
127
128
129
package git
import (
"path/filepath"
"strings"
"sync"
"github.com/go-git/go-billy/v5/osfs"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing/cache"
"github.com/go-git/go-git/v5/storage"
"github.com/go-git/go-git/v5/storage/filesystem"
"github.com/go-git/go-git/v5/storage/memory"
)
// Cacher is an interface to cache git repositories.
type Cacher interface {
// Get repository via the repo name.
Get(string) (*git.Repository, bool)
// Set save repository with the repo name key.
Set(string, *git.Repository)
// NewStorer returns a new storage.Storer with repo name like github.com/org/repo.
NewStorer(string) storage.Storer
}
// MemCache implements the Cacher interface storing repositories in memory.
type MemCache struct {
repos map[string]*git.Repository
mutex sync.RWMutex
}
// NewMemcache returns a new MemCache.
func NewMemcache() MemCache {
return MemCache{
repos: make(map[string]*git.Repository),
mutex: sync.RWMutex{},
}
}
func (s MemCache) Get(repo string) (*git.Repository, bool) {
s.mutex.RLock()
defer s.mutex.RUnlock()
r, ok := s.repos[repo]
return r, ok
}
func (s MemCache) Set(repo string, v *git.Repository) {
s.mutex.Lock()
defer s.mutex.Unlock()
s.repos[repo] = v
}
func (s MemCache) NewStorer(repo string) storage.Storer {
return memory.NewStorage()
}
// FsCache implements the Cacher interface storing repositories in filesystem.
type FsCache struct {
dir string
}
// NewFscache returns a new FsCache.
func NewFscache(dir string) FsCache {
return FsCache{dir: dir}
}
func (s FsCache) Get(repo string) (*git.Repository, bool) {
st := s.NewStorer(repo)
r, err := git.Open(st, nil)
if err != nil {
return nil, false
}
return r, true
}
func (s FsCache) Set(repo string, v *git.Repository) {
if _, is := v.Storer.(*filesystem.Storage); !is {
panic("it is not a filesystem storage")
}
}
func (s FsCache) NewStorer(repo string) storage.Storer {
return filesystem.NewStorage(osfs.New(s.repoDir(repo)), cache.NewObjectLRUDefault())
}
func (s FsCache) repoDir(repo string) string {
return filepath.Join(s.dir, cleanForSubPath(repo))
}
// PlainFsCache implements the Cacher interface storing repositories in filesystem
// without extra storage.Storer files.
type PlainFsCache struct {
dir string
}
// NewPlainFscache returns a new PlainFsCache.
func NewPlainFscache(dir string) PlainFsCache {
return PlainFsCache{dir: dir}
}
func (s PlainFsCache) Get(repo string) (*git.Repository, bool) {
r, err := git.PlainOpen(s.RepoDir(repo))
if err != nil {
return nil, false
}
return r, true
}
func (s PlainFsCache) Set(repo string, v *git.Repository) {
if _, is := v.Storer.(*filesystem.Storage); !is {
panic("it is not a filesystem storage")
}
}
func (s PlainFsCache) NewStorer(repo string) storage.Storer {
panic("storage.Storer not supported by PlainFsCache")
}
func (s PlainFsCache) RepoDir(repo string) string {
return filepath.Join(s.dir, cleanForSubPath(repo))
}
// cleanForSubPath will return a string that is suitable to be used as subpath in the cache directory
// for Windows caching a local repo we need to remove the colon in the drive letter
func cleanForSubPath(repo string) string {
return strings.ReplaceAll(repo, ":", "")
}