repo_cache_common.go

  1package cache
  2
  3import (
  4	"sync"
  5
  6	"github.com/go-git/go-billy/v5"
  7	"github.com/pkg/errors"
  8
  9	"github.com/MichaelMure/git-bug/entities/identity"
 10	"github.com/MichaelMure/git-bug/entity"
 11	"github.com/MichaelMure/git-bug/repository"
 12)
 13
 14func (c *RepoCache) Name() string {
 15	return c.name
 16}
 17
 18// LocalConfig give access to the repository scoped configuration
 19func (c *RepoCache) LocalConfig() repository.Config {
 20	return c.repo.LocalConfig()
 21}
 22
 23// GlobalConfig give access to the global scoped configuration
 24func (c *RepoCache) GlobalConfig() repository.Config {
 25	return c.repo.GlobalConfig()
 26}
 27
 28// AnyConfig give access to a merged local/global configuration
 29func (c *RepoCache) AnyConfig() repository.ConfigRead {
 30	return c.repo.AnyConfig()
 31}
 32
 33// Keyring give access to a user-wide storage for secrets
 34func (c *RepoCache) Keyring() repository.Keyring {
 35	return c.repo.Keyring()
 36}
 37
 38// GetUserName returns the name the user has used to configure git
 39func (c *RepoCache) GetUserName() (string, error) {
 40	return c.repo.GetUserName()
 41}
 42
 43// GetUserEmail returns the email address that the user has used to configure git.
 44func (c *RepoCache) GetUserEmail() (string, error) {
 45	return c.repo.GetUserEmail()
 46}
 47
 48// GetCoreEditor returns the name of the editor that the user has used to configure git.
 49func (c *RepoCache) GetCoreEditor() (string, error) {
 50	return c.repo.GetCoreEditor()
 51}
 52
 53// GetRemotes returns the configured remotes repositories.
 54func (c *RepoCache) GetRemotes() (map[string]string, error) {
 55	return c.repo.GetRemotes()
 56}
 57
 58// LocalStorage return a billy.Filesystem giving access to $RepoPath/.git/git-bug
 59func (c *RepoCache) LocalStorage() billy.Filesystem {
 60	return c.repo.LocalStorage()
 61}
 62
 63// ReadData will attempt to read arbitrary data from the given hash
 64func (c *RepoCache) ReadData(hash repository.Hash) ([]byte, error) {
 65	return c.repo.ReadData(hash)
 66}
 67
 68// StoreData will store arbitrary data and return the corresponding hash
 69func (c *RepoCache) StoreData(data []byte) (repository.Hash, error) {
 70	return c.repo.StoreData(data)
 71}
 72
 73// Fetch retrieve updates from a remote
 74// This does not change the local bugs or identities state
 75func (c *RepoCache) Fetch(remote string) (string, error) {
 76	prefixes := make([]string, len(c.subcaches))
 77	for i, subcache := range c.subcaches {
 78		prefixes[i] = subcache.GetNamespace()
 79	}
 80
 81	// fetch everything at once, to have a single auth step if required.
 82	return c.repo.FetchRefs(remote, prefixes...)
 83}
 84
 85// MergeAll will merge all the available remote bug and identities
 86func (c *RepoCache) MergeAll(remote string) <-chan entity.MergeResult {
 87	out := make(chan entity.MergeResult)
 88
 89	dependency := [][]cacheMgmt{
 90		{c.identities},
 91		{c.bugs},
 92	}
 93
 94	// run MergeAll according to entities dependencies and merge the results
 95	go func() {
 96		defer close(out)
 97
 98		for _, subcaches := range dependency {
 99			var wg sync.WaitGroup
100			for _, subcache := range subcaches {
101				wg.Add(1)
102				go func(subcache cacheMgmt) {
103					for res := range subcache.MergeAll(remote) {
104						out <- res
105					}
106					wg.Done()
107				}(subcache)
108			}
109			wg.Wait()
110		}
111	}()
112
113	return out
114}
115
116// Push update a remote with the local changes
117func (c *RepoCache) Push(remote string) (string, error) {
118	prefixes := make([]string, len(c.subcaches))
119	for i, subcache := range c.subcaches {
120		prefixes[i] = subcache.GetNamespace()
121	}
122
123	// push everything at once, to have a single auth step if required
124	return c.repo.PushRefs(remote, prefixes...)
125}
126
127// Pull will do a Fetch + MergeAll
128// This function will return an error if a merge fail
129func (c *RepoCache) Pull(remote string) error {
130	_, err := c.Fetch(remote)
131	if err != nil {
132		return err
133	}
134
135	for merge := range c.MergeAll(remote) {
136		if merge.Err != nil {
137			return merge.Err
138		}
139		if merge.Status == entity.MergeStatusInvalid {
140			return errors.Errorf("merge failure: %s", merge.Reason)
141		}
142	}
143
144	return nil
145}
146
147func (c *RepoCache) SetUserIdentity(i *IdentityCache) error {
148	c.muUserIdentity.RLock()
149	defer c.muUserIdentity.RUnlock()
150
151	// Make sure that everything is fine
152	if _, err := c.identities.Resolve(i.Id()); err != nil {
153		panic("SetUserIdentity while the identity is not from the cache, something is wrong")
154	}
155
156	err := identity.SetUserIdentity(c.repo, i.Identity)
157	if err != nil {
158		return err
159	}
160
161	c.userIdentityId = i.Id()
162
163	return nil
164}
165
166func (c *RepoCache) GetUserIdentity() (*IdentityCache, error) {
167	c.muUserIdentity.RLock()
168	if c.userIdentityId != "" {
169		defer c.muUserIdentity.RUnlock()
170		return c.identities.Resolve(c.userIdentityId)
171	}
172	c.muUserIdentity.RUnlock()
173
174	c.muUserIdentity.Lock()
175	defer c.muUserIdentity.Unlock()
176
177	i, err := identity.GetUserIdentityId(c.repo)
178	if err != nil {
179		return nil, err
180	}
181
182	c.userIdentityId = i
183
184	return c.identities.Resolve(i)
185}
186
187func (c *RepoCache) GetUserIdentityExcerpt() (*IdentityExcerpt, error) {
188	c.muUserIdentity.RLock()
189	if c.userIdentityId != "" {
190		defer c.muUserIdentity.RUnlock()
191		return c.identities.ResolveExcerpt(c.userIdentityId)
192	}
193	c.muUserIdentity.RUnlock()
194
195	c.muUserIdentity.Lock()
196	defer c.muUserIdentity.Unlock()
197
198	i, err := identity.GetUserIdentityId(c.repo)
199	if err != nil {
200		return nil, err
201	}
202
203	c.userIdentityId = i
204
205	return c.identities.ResolveExcerpt(i)
206}
207
208func (c *RepoCache) IsUserIdentitySet() (bool, error) {
209	return identity.IsUserIdentitySet(c.repo)
210}