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