bug_actions.go

  1package bug
  2
  3import (
  4	"fmt"
  5	"io"
  6	"strings"
  7
  8	"github.com/MichaelMure/git-bug/repository"
  9)
 10
 11const MsgMergeNew = "new"
 12const MsgMergeInvalid = "invalid data"
 13const MsgMergeUpdated = "updated"
 14const MsgMergeNothing = "nothing to do"
 15
 16func Fetch(repo repository.Repo, remote string) error {
 17	remoteRefSpec := fmt.Sprintf(bugsRemoteRefPattern, remote)
 18	fetchRefSpec := fmt.Sprintf("%s*:%s*", bugsRefPattern, remoteRefSpec)
 19
 20	return repo.FetchRefs(remote, fetchRefSpec)
 21}
 22
 23func Push(repo repository.Repo, remote string) error {
 24	return repo.PushRefs(remote, bugsRefPattern+"*")
 25}
 26
 27func Pull(repo repository.Repo, out io.Writer, remote string) error {
 28	fmt.Fprintf(out, "Fetching remote ...\n")
 29
 30	if err := Fetch(repo, remote); err != nil {
 31		return err
 32	}
 33
 34	fmt.Fprintf(out, "\nMerging data ...\n")
 35
 36	for merge := range MergeAll(repo, remote) {
 37		if merge.Err != nil {
 38			return merge.Err
 39		}
 40
 41		if merge.Status != MsgMergeNothing {
 42			fmt.Fprintf(out, "%s: %s\n", merge.HumanId, merge.Status)
 43		}
 44	}
 45	return nil
 46}
 47
 48type MergeResult struct {
 49	Err error
 50
 51	Id      string
 52	HumanId string
 53	Status  string
 54}
 55
 56func newMergeError(id string, err error) MergeResult {
 57	return MergeResult{
 58		Id:      id,
 59		HumanId: formatHumanId(id),
 60		Status:  err.Error(),
 61	}
 62}
 63
 64func newMergeStatus(id string, status string) MergeResult {
 65	return MergeResult{
 66		Id:      id,
 67		HumanId: formatHumanId(id),
 68		Status:  status,
 69	}
 70}
 71
 72func MergeAll(repo repository.Repo, remote string) <-chan MergeResult {
 73	out := make(chan MergeResult)
 74
 75	go func() {
 76		defer close(out)
 77
 78		remoteRefSpec := fmt.Sprintf(bugsRemoteRefPattern, remote)
 79		remoteRefs, err := repo.ListRefs(remoteRefSpec)
 80
 81		if err != nil {
 82			out <- MergeResult{Err: err}
 83			return
 84		}
 85
 86		for _, remoteRef := range remoteRefs {
 87			refSplitted := strings.Split(remoteRef, "/")
 88			id := refSplitted[len(refSplitted)-1]
 89
 90			remoteBug, err := readBug(repo, remoteRef)
 91
 92			if err != nil {
 93				out <- newMergeError(id, err)
 94				continue
 95			}
 96
 97			// Check for error in remote data
 98			if !remoteBug.IsValid() {
 99				out <- newMergeStatus(id, MsgMergeInvalid)
100				continue
101			}
102
103			localRef := bugsRefPattern + remoteBug.Id()
104			localExist, err := repo.RefExist(localRef)
105
106			// the bug is not local yet, simply create the reference
107			if !localExist {
108				err := repo.CopyRef(remoteRef, localRef)
109
110				if err != nil {
111					out <- newMergeError(id, err)
112					return
113				}
114
115				out <- newMergeStatus(id, MsgMergeNew)
116				continue
117			}
118
119			localBug, err := readBug(repo, localRef)
120
121			if err != nil {
122				out <- newMergeError(id, err)
123				return
124			}
125
126			updated, err := localBug.Merge(repo, remoteBug)
127
128			if err != nil {
129				out <- newMergeError(id, err)
130				return
131			}
132
133			if updated {
134				out <- newMergeStatus(id, MsgMergeUpdated)
135			} else {
136				out <- newMergeStatus(id, MsgMergeNothing)
137			}
138		}
139	}()
140
141	return out
142}