bug_actions.go

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