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