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) (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) (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	stdout, err := Fetch(repo, remote)
 31	if err != nil {
 32		return err
 33	}
 34
 35	out.Write([]byte(stdout))
 36
 37	fmt.Fprintf(out, "Merging data ...\n")
 38
 39	for merge := range MergeAll(repo, remote) {
 40		if merge.Err != nil {
 41			return merge.Err
 42		}
 43
 44		if merge.Status != MsgMergeNothing {
 45			fmt.Fprintf(out, "%s: %s\n", merge.HumanId, merge.Status)
 46		}
 47	}
 48
 49	return nil
 50}
 51
 52type MergeResult struct {
 53	Err error
 54
 55	Id      string
 56	HumanId string
 57	Status  string
 58}
 59
 60func newMergeError(id string, err error) MergeResult {
 61	return MergeResult{
 62		Id:      id,
 63		HumanId: formatHumanId(id),
 64		Status:  err.Error(),
 65	}
 66}
 67
 68func newMergeStatus(id string, status string) MergeResult {
 69	return MergeResult{
 70		Id:      id,
 71		HumanId: formatHumanId(id),
 72		Status:  status,
 73	}
 74}
 75
 76func MergeAll(repo repository.Repo, remote string) <-chan MergeResult {
 77	out := make(chan MergeResult)
 78
 79	go func() {
 80		defer close(out)
 81
 82		remoteRefSpec := fmt.Sprintf(bugsRemoteRefPattern, remote)
 83		remoteRefs, err := repo.ListRefs(remoteRefSpec)
 84
 85		if err != nil {
 86			out <- MergeResult{Err: err}
 87			return
 88		}
 89
 90		for _, remoteRef := range remoteRefs {
 91			refSplitted := strings.Split(remoteRef, "/")
 92			id := refSplitted[len(refSplitted)-1]
 93
 94			remoteBug, err := readBug(repo, remoteRef)
 95
 96			if err != nil {
 97				out <- newMergeError(id, err)
 98				continue
 99			}
100
101			// Check for error in remote data
102			if !remoteBug.IsValid() {
103				out <- newMergeStatus(id, MsgMergeInvalid)
104				continue
105			}
106
107			localRef := bugsRefPattern + remoteBug.Id()
108			localExist, err := repo.RefExist(localRef)
109
110			if err != nil {
111				out <- newMergeError(id, err)
112				continue
113			}
114
115			// the bug is not local yet, simply create the reference
116			if !localExist {
117				err := repo.CopyRef(remoteRef, localRef)
118
119				if err != nil {
120					out <- newMergeError(id, err)
121					return
122				}
123
124				out <- newMergeStatus(id, MsgMergeNew)
125				continue
126			}
127
128			localBug, err := readBug(repo, localRef)
129
130			if err != nil {
131				out <- newMergeError(id, err)
132				return
133			}
134
135			updated, err := localBug.Merge(repo, remoteBug)
136
137			if err != nil {
138				out <- newMergeError(id, err)
139				return
140			}
141
142			if updated {
143				out <- newMergeStatus(id, MsgMergeUpdated)
144			} else {
145				out <- newMergeStatus(id, MsgMergeNothing)
146			}
147		}
148	}()
149
150	return out
151}