Skip to content

Commit 04d7bd5

Browse files
committed
Move mirror push functions to a pushmirror service
The functions related push mirrors will be called by notification module, when sync-on-push is supported. So relevant functions are moved to pushmirror service package to avoid circular imports.
1 parent ac61c17 commit 04d7bd5

File tree

2 files changed

+262
-242
lines changed

2 files changed

+262
-242
lines changed

services/mirror/mirror_push.go

Lines changed: 6 additions & 242 deletions
Original file line numberDiff line numberDiff line change
@@ -5,252 +5,16 @@
55
package mirror
66

77
import (
8-
"context"
9-
"errors"
10-
"fmt"
11-
"io"
12-
"regexp"
13-
"strings"
14-
"time"
15-
16-
repo_model "code.gitea.io/gitea/models/repo"
17-
"code.gitea.io/gitea/modules/git"
18-
"code.gitea.io/gitea/modules/lfs"
19-
"code.gitea.io/gitea/modules/log"
20-
"code.gitea.io/gitea/modules/process"
21-
"code.gitea.io/gitea/modules/repository"
22-
"code.gitea.io/gitea/modules/setting"
23-
"code.gitea.io/gitea/modules/timeutil"
24-
"code.gitea.io/gitea/modules/util"
8+
// Implementations related to push mirrors are in `services/pushmirror` package
9+
// to avoid circular imports
10+
"code.gitea.io/gitea/services/pushmirror"
2511
)
2612

27-
var stripExitStatus = regexp.MustCompile(`exit status \d+ - `)
28-
2913
// AddPushMirrorRemote registers the push mirror remote.
30-
func AddPushMirrorRemote(ctx context.Context, m *repo_model.PushMirror, addr string) error {
31-
addRemoteAndConfig := func(addr, path string) error {
32-
cmd := git.NewCommand(ctx, "remote", "add", "--mirror=push", m.RemoteName, addr)
33-
if strings.Contains(addr, "://") && strings.Contains(addr, "@") {
34-
cmd.SetDescription(fmt.Sprintf("remote add %s --mirror=push %s [repo_path: %s]", m.RemoteName, util.SanitizeCredentialURLs(addr), path))
35-
} else {
36-
cmd.SetDescription(fmt.Sprintf("remote add %s --mirror=push %s [repo_path: %s]", m.RemoteName, addr, path))
37-
}
38-
if _, _, err := cmd.RunStdString(&git.RunOpts{Dir: path}); err != nil {
39-
return err
40-
}
41-
if _, _, err := git.NewCommand(ctx, "config", "--add", "remote."+m.RemoteName+".push", "+refs/heads/*:refs/heads/*").RunStdString(&git.RunOpts{Dir: path}); err != nil {
42-
return err
43-
}
44-
if _, _, err := git.NewCommand(ctx, "config", "--add", "remote."+m.RemoteName+".push", "+refs/tags/*:refs/tags/*").RunStdString(&git.RunOpts{Dir: path}); err != nil {
45-
return err
46-
}
47-
return nil
48-
}
49-
50-
if err := addRemoteAndConfig(addr, m.Repo.RepoPath()); err != nil {
51-
return err
52-
}
53-
54-
if m.Repo.HasUncyclo() {
55-
wikiRemoteURL := repository.UncycloRemoteURL(ctx, addr)
56-
if len(wikiRemoteURL) > 0 {
57-
if err := addRemoteAndConfig(wikiRemoteURL, m.Repo.UncycloPath()); err != nil {
58-
return err
59-
}
60-
}
61-
}
62-
63-
return nil
64-
}
14+
var AddPushMirrorRemote = pushmirror.AddPushMirrorRemote
6515

6616
// RemovePushMirrorRemote removes the push mirror remote.
67-
func RemovePushMirrorRemote(ctx context.Context, m *repo_model.PushMirror) error {
68-
cmd := git.NewCommand(ctx, "remote", "rm", m.RemoteName)
69-
_ = m.GetRepository()
70-
71-
if _, _, err := cmd.RunStdString(&git.RunOpts{Dir: m.Repo.RepoPath()}); err != nil {
72-
return err
73-
}
74-
75-
if m.Repo.HasUncyclo() {
76-
if _, _, err := cmd.RunStdString(&git.RunOpts{Dir: m.Repo.UncycloPath()}); err != nil {
77-
// The wiki remote may not exist
78-
log.Warn("Uncyclo Remote[%d] could not be removed: %v", m.ID, err)
79-
}
80-
}
81-
82-
return nil
83-
}
17+
var RemovePushMirrorRemote = pushmirror.RemovePushMirrorRemote
8418

8519
// SyncPushMirror starts the sync of the push mirror and schedules the next run.
86-
func SyncPushMirror(ctx context.Context, mirrorID int64) bool {
87-
log.Trace("SyncPushMirror [mirror: %d]", mirrorID)
88-
defer func() {
89-
err := recover()
90-
if err == nil {
91-
return
92-
}
93-
// There was a panic whilst syncPushMirror...
94-
log.Error("PANIC whilst syncPushMirror[%d] Panic: %v\nStacktrace: %s", mirrorID, err, log.Stack(2))
95-
}()
96-
97-
m, err := repo_model.GetPushMirrorByID(mirrorID)
98-
if err != nil {
99-
log.Error("GetPushMirrorByID [%d]: %v", mirrorID, err)
100-
return false
101-
}
102-
103-
_ = m.GetRepository()
104-
105-
m.LastError = ""
106-
107-
ctx, _, finished := process.GetManager().AddContext(ctx, fmt.Sprintf("Syncing PushMirror %s/%s to %s", m.Repo.OwnerName, m.Repo.Name, m.RemoteName))
108-
defer finished()
109-
110-
log.Trace("SyncPushMirror [mirror: %d][repo: %-v]: Running Sync", m.ID, m.Repo)
111-
err = runPushSync(ctx, m)
112-
if err != nil {
113-
log.Error("SyncPushMirror [mirror: %d][repo: %-v]: %v", m.ID, m.Repo, err)
114-
m.LastError = stripExitStatus.ReplaceAllLiteralString(err.Error(), "")
115-
}
116-
117-
m.LastUpdateUnix = timeutil.TimeStampNow()
118-
119-
if err := repo_model.UpdatePushMirror(m); err != nil {
120-
log.Error("UpdatePushMirror [%d]: %v", m.ID, err)
121-
122-
return false
123-
}
124-
125-
log.Trace("SyncPushMirror [mirror: %d][repo: %-v]: Finished", m.ID, m.Repo)
126-
127-
return err == nil
128-
}
129-
130-
func runPushSync(ctx context.Context, m *repo_model.PushMirror) error {
131-
timeout := time.Duration(setting.Git.Timeout.Mirror) * time.Second
132-
133-
performPush := func(path string) error {
134-
remoteURL, err := git.GetRemoteURL(ctx, path, m.RemoteName)
135-
if err != nil {
136-
log.Error("GetRemoteAddress(%s) Error %v", path, err)
137-
return errors.New("Unexpected error")
138-
}
139-
140-
if setting.LFS.StartServer {
141-
log.Trace("SyncMirrors [repo: %-v]: syncing LFS objects...", m.Repo)
142-
143-
gitRepo, err := git.OpenRepository(ctx, path)
144-
if err != nil {
145-
log.Error("OpenRepository: %v", err)
146-
return errors.New("Unexpected error")
147-
}
148-
defer gitRepo.Close()
149-
150-
endpoint := lfs.DetermineEndpoint(remoteURL.String(), "")
151-
lfsClient := lfs.NewClient(endpoint, nil)
152-
if err := pushAllLFSObjects(ctx, gitRepo, lfsClient); err != nil {
153-
return util.SanitizeErrorCredentialURLs(err)
154-
}
155-
}
156-
157-
log.Trace("Pushing %s mirror[%d] remote %s", path, m.ID, m.RemoteName)
158-
159-
if err := git.Push(ctx, path, git.PushOptions{
160-
Remote: m.RemoteName,
161-
Force: true,
162-
Mirror: true,
163-
Timeout: timeout,
164-
}); err != nil {
165-
log.Error("Error pushing %s mirror[%d] remote %s: %v", path, m.ID, m.RemoteName, err)
166-
167-
return util.SanitizeErrorCredentialURLs(err)
168-
}
169-
170-
return nil
171-
}
172-
173-
err := performPush(m.Repo.RepoPath())
174-
if err != nil {
175-
return err
176-
}
177-
178-
if m.Repo.HasUncyclo() {
179-
wikiPath := m.Repo.UncycloPath()
180-
_, err := git.GetRemoteAddress(ctx, wikiPath, m.RemoteName)
181-
if err == nil {
182-
err := performPush(wikiPath)
183-
if err != nil {
184-
return err
185-
}
186-
} else {
187-
log.Trace("Skipping wiki: No remote configured")
188-
}
189-
}
190-
191-
return nil
192-
}
193-
194-
func pushAllLFSObjects(ctx context.Context, gitRepo *git.Repository, lfsClient lfs.Client) error {
195-
contentStore := lfs.NewContentStore()
196-
197-
pointerChan := make(chan lfs.PointerBlob)
198-
errChan := make(chan error, 1)
199-
go lfs.SearchPointerBlobs(ctx, gitRepo, pointerChan, errChan)
200-
201-
uploadObjects := func(pointers []lfs.Pointer) error {
202-
err := lfsClient.Upload(ctx, pointers, func(p lfs.Pointer, objectError error) (io.ReadCloser, error) {
203-
if objectError != nil {
204-
return nil, objectError
205-
}
206-
207-
content, err := contentStore.Get(p)
208-
if err != nil {
209-
log.Error("Error reading LFS object %v: %v", p, err)
210-
}
211-
return content, err
212-
})
213-
if err != nil {
214-
select {
215-
case <-ctx.Done():
216-
return nil
217-
default:
218-
}
219-
}
220-
return err
221-
}
222-
223-
var batch []lfs.Pointer
224-
for pointerBlob := range pointerChan {
225-
exists, err := contentStore.Exists(pointerBlob.Pointer)
226-
if err != nil {
227-
log.Error("Error checking if LFS object %v exists: %v", pointerBlob.Pointer, err)
228-
return err
229-
}
230-
if !exists {
231-
log.Trace("Skipping missing LFS object %v", pointerBlob.Pointer)
232-
continue
233-
}
234-
235-
batch = append(batch, pointerBlob.Pointer)
236-
if len(batch) >= lfsClient.BatchSize() {
237-
if err := uploadObjects(batch); err != nil {
238-
return err
239-
}
240-
batch = nil
241-
}
242-
}
243-
if len(batch) > 0 {
244-
if err := uploadObjects(batch); err != nil {
245-
return err
246-
}
247-
}
248-
249-
err, has := <-errChan
250-
if has {
251-
log.Error("Error enumerating LFS objects for repository: %v", err)
252-
return err
253-
}
254-
255-
return nil
256-
}
20+
var SyncPushMirror = pushmirror.SyncPushMirror

0 commit comments

Comments
 (0)