bug_actions.go

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