repo_cache_common.go

  1package cache
  2
  3import (
  4	"fmt"
  5
  6	"github.com/pkg/errors"
  7
  8	"github.com/MichaelMure/git-bug/bug"
  9	"github.com/MichaelMure/git-bug/entity"
 10	"github.com/MichaelMure/git-bug/identity"
 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 git global configuration
 24func (c *RepoCache) GlobalConfig() repository.Config {
 25	return c.repo.GlobalConfig()
 26}
 27
 28// GetPath returns the path to the repo.
 29func (c *RepoCache) GetPath() string {
 30	return c.repo.GetPath()
 31}
 32
 33// GetCoreEditor returns the name of the editor that the user has used to configure git.
 34func (c *RepoCache) GetCoreEditor() (string, error) {
 35	return c.repo.GetCoreEditor()
 36}
 37
 38// GetRemotes returns the configured remotes repositories.
 39func (c *RepoCache) GetRemotes() (map[string]string, error) {
 40	return c.repo.GetRemotes()
 41}
 42
 43// GetUserName returns the name the the user has used to configure git
 44func (c *RepoCache) GetUserName() (string, error) {
 45	return c.repo.GetUserName()
 46}
 47
 48// GetUserEmail returns the email address that the user has used to configure git.
 49func (c *RepoCache) GetUserEmail() (string, error) {
 50	return c.repo.GetUserEmail()
 51}
 52
 53// ReadData will attempt to read arbitrary data from the given hash
 54func (c *RepoCache) ReadData(hash repository.Hash) ([]byte, error) {
 55	return c.repo.ReadData(hash)
 56}
 57
 58// StoreData will store arbitrary data and return the corresponding hash
 59func (c *RepoCache) StoreData(data []byte) (repository.Hash, error) {
 60	return c.repo.StoreData(data)
 61}
 62
 63// Fetch retrieve updates from a remote
 64// This does not change the local bugs or identities state
 65func (c *RepoCache) Fetch(remote string) (string, error) {
 66	stdout1, err := identity.Fetch(c.repo, remote)
 67	if err != nil {
 68		return stdout1, err
 69	}
 70
 71	stdout2, err := bug.Fetch(c.repo, remote)
 72	if err != nil {
 73		return stdout2, err
 74	}
 75
 76	return stdout1 + stdout2, nil
 77}
 78
 79// MergeAll will merge all the available remote bug and identities
 80func (c *RepoCache) MergeAll(remote string) <-chan entity.MergeResult {
 81	out := make(chan entity.MergeResult)
 82
 83	// Intercept merge results to update the cache properly
 84	go func() {
 85		defer close(out)
 86
 87		results := identity.MergeAll(c.repo, remote)
 88		for result := range results {
 89			out <- result
 90
 91			if result.Err != nil {
 92				continue
 93			}
 94
 95			switch result.Status {
 96			case entity.MergeStatusNew, entity.MergeStatusUpdated:
 97				i := result.Entity.(*identity.Identity)
 98				c.muIdentity.Lock()
 99				c.identitiesExcerpts[result.Id] = NewIdentityExcerpt(i)
100				c.muIdentity.Unlock()
101			}
102		}
103
104		results = bug.MergeAll(c.repo, remote)
105		for result := range results {
106			out <- result
107
108			if result.Err != nil {
109				continue
110			}
111
112			switch result.Status {
113			case entity.MergeStatusNew, entity.MergeStatusUpdated:
114				b := result.Entity.(*bug.Bug)
115				snap := b.Compile()
116				c.muBug.Lock()
117				c.bugExcerpts[result.Id] = NewBugExcerpt(b, &snap)
118				c.muBug.Unlock()
119			}
120		}
121
122		err := c.write()
123
124		// No easy way out here ..
125		if err != nil {
126			panic(err)
127		}
128	}()
129
130	return out
131}
132
133// Push update a remote with the local changes
134func (c *RepoCache) Push(remote string) (string, error) {
135	stdout1, err := identity.Push(c.repo, remote)
136	if err != nil {
137		return stdout1, err
138	}
139
140	stdout2, err := bug.Push(c.repo, remote)
141	if err != nil {
142		return stdout2, err
143	}
144
145	return stdout1 + stdout2, nil
146}
147
148// Pull will do a Fetch + MergeAll
149// This function will return an error if a merge fail
150func (c *RepoCache) Pull(remote string) error {
151	_, err := c.Fetch(remote)
152	if err != nil {
153		return err
154	}
155
156	for merge := range c.MergeAll(remote) {
157		if merge.Err != nil {
158			return merge.Err
159		}
160		if merge.Status == entity.MergeStatusInvalid {
161			return errors.Errorf("merge failure: %s", merge.Reason)
162		}
163	}
164
165	return nil
166}
167
168func (c *RepoCache) SetUserIdentity(i *IdentityCache) error {
169	err := identity.SetUserIdentity(c.repo, i.Identity)
170	if err != nil {
171		return err
172	}
173
174	c.muIdentity.RLock()
175	defer c.muIdentity.RUnlock()
176
177	// Make sure that everything is fine
178	if _, ok := c.identities[i.Id()]; !ok {
179		panic("SetUserIdentity while the identity is not from the cache, something is wrong")
180	}
181
182	c.userIdentityId = i.Id()
183
184	return nil
185}
186
187func (c *RepoCache) GetUserIdentity() (*IdentityCache, error) {
188	if c.userIdentityId != "" {
189		i, ok := c.identities[c.userIdentityId]
190		if ok {
191			return i, nil
192		}
193	}
194
195	c.muIdentity.Lock()
196	defer c.muIdentity.Unlock()
197
198	i, err := identity.GetUserIdentity(c.repo)
199	if err != nil {
200		return nil, err
201	}
202
203	cached := NewIdentityCache(c, i)
204	c.identities[i.Id()] = cached
205	c.userIdentityId = i.Id()
206
207	return cached, nil
208}
209
210func (c *RepoCache) GetUserIdentityExcerpt() (*IdentityExcerpt, error) {
211	if c.userIdentityId == "" {
212		id, err := identity.GetUserIdentityId(c.repo)
213		if err != nil {
214			return nil, err
215		}
216		c.userIdentityId = id
217	}
218
219	c.muIdentity.RLock()
220	defer c.muIdentity.RUnlock()
221
222	excerpt, ok := c.identitiesExcerpts[c.userIdentityId]
223	if !ok {
224		return nil, fmt.Errorf("cache: missing identity excerpt %v", c.userIdentityId)
225	}
226	return excerpt, nil
227}
228
229func (c *RepoCache) IsUserIdentitySet() (bool, error) {
230	return identity.IsUserIdentitySet(c.repo)
231}