@@ -5,27 +5,22 @@ package repository
55
66import (
77 "context"
8- "errors"
98 "fmt"
109 "io"
11- "net/http"
1210 "strings"
1311 "time"
1412
1513 "code.gitea.io/gitea/models/db"
1614 git_model "code.gitea.io/gitea/models/git"
17- "code.gitea.io/gitea/models/organization"
1815 repo_model "code.gitea.io/gitea/models/repo"
1916 user_model "code.gitea.io/gitea/models/user"
2017 "code.gitea.io/gitea/modules/container"
2118 "code.gitea.io/gitea/modules/git"
2219 "code.gitea.io/gitea/modules/gitrepo"
2320 "code.gitea.io/gitea/modules/lfs"
2421 "code.gitea.io/gitea/modules/log"
25- "code.gitea.io/gitea/modules/migration"
2622 "code.gitea.io/gitea/modules/setting"
2723 "code.gitea.io/gitea/modules/timeutil"
28- "code.gitea.io/gitea/modules/util"
2924)
3025
3126/*
@@ -47,244 +42,6 @@ func WikiRemoteURL(ctx context.Context, remote string) string {
4742 return ""
4843}
4944
50- // MigrateRepositoryGitData starts migrating git related data after created migrating repository
51- func MigrateRepositoryGitData (ctx context.Context , u * user_model.User ,
52- repo * repo_model.Repository , opts migration.MigrateOptions ,
53- httpTransport * http.Transport ,
54- ) (* repo_model.Repository , error ) {
55- repoPath := repo_model .RepoPath (u .Name , opts .RepoName )
56-
57- if u .IsOrganization () {
58- t , err := organization .OrgFromUser (u ).GetOwnerTeam (ctx )
59- if err != nil {
60- return nil , err
61- }
62- repo .NumWatches = t .NumMembers
63- } else {
64- repo .NumWatches = 1
65- }
66-
67- migrateTimeout := time .Duration (setting .Git .Timeout .Migrate ) * time .Second
68-
69- var err error
70- if err = util .RemoveAll (repoPath ); err != nil {
71- return repo , fmt .Errorf ("Failed to remove %s: %w" , repoPath , err )
72- }
73-
74- if err = git .Clone (ctx , opts .CloneAddr , repoPath , git.CloneRepoOptions {
75- Mirror : true ,
76- Quiet : true ,
77- Timeout : migrateTimeout ,
78- SkipTLSVerify : setting .Migrations .SkipTLSVerify ,
79- }); err != nil {
80- if errors .Is (err , context .DeadlineExceeded ) {
81- return repo , fmt .Errorf ("Clone timed out. Consider increasing [git.timeout] MIGRATE in app.ini. Underlying Error: %w" , err )
82- }
83- return repo , fmt .Errorf ("Clone: %w" , err )
84- }
85-
86- if err := git .WriteCommitGraph (ctx , repoPath ); err != nil {
87- return repo , err
88- }
89-
90- if opts .Wiki {
91- wikiPath := repo_model .WikiPath (u .Name , opts .RepoName )
92- wikiRemotePath := WikiRemoteURL (ctx , opts .CloneAddr )
93- if len (wikiRemotePath ) > 0 {
94- if err := util .RemoveAll (wikiPath ); err != nil {
95- return repo , fmt .Errorf ("Failed to remove %s: %w" , wikiPath , err )
96- }
97-
98- if err := git .Clone (ctx , wikiRemotePath , wikiPath , git.CloneRepoOptions {
99- Mirror : true ,
100- Quiet : true ,
101- Timeout : migrateTimeout ,
102- Branch : "master" ,
103- SkipTLSVerify : setting .Migrations .SkipTLSVerify ,
104- }); err != nil {
105- log .Warn ("Clone wiki: %v" , err )
106- if err := util .RemoveAll (wikiPath ); err != nil {
107- return repo , fmt .Errorf ("Failed to remove %s: %w" , wikiPath , err )
108- }
109- } else {
110- if err := git .WriteCommitGraph (ctx , wikiPath ); err != nil {
111- return repo , err
112- }
113- }
114- }
115- }
116-
117- if repo .OwnerID == u .ID {
118- repo .Owner = u
119- }
120-
121- if err = CheckDaemonExportOK (ctx , repo ); err != nil {
122- return repo , fmt .Errorf ("checkDaemonExportOK: %w" , err )
123- }
124-
125- if stdout , _ , err := git .NewCommand (ctx , "update-server-info" ).
126- SetDescription (fmt .Sprintf ("MigrateRepositoryGitData(git update-server-info): %s" , repoPath )).
127- RunStdString (& git.RunOpts {Dir : repoPath }); err != nil {
128- log .Error ("MigrateRepositoryGitData(git update-server-info) in %v: Stdout: %s\n Error: %v" , repo , stdout , err )
129- return repo , fmt .Errorf ("error in MigrateRepositoryGitData(git update-server-info): %w" , err )
130- }
131-
132- gitRepo , err := git .OpenRepository (ctx , repoPath )
133- if err != nil {
134- return repo , fmt .Errorf ("OpenRepository: %w" , err )
135- }
136- defer gitRepo .Close ()
137-
138- repo .IsEmpty , err = gitRepo .IsEmpty ()
139- if err != nil {
140- return repo , fmt .Errorf ("git.IsEmpty: %w" , err )
141- }
142-
143- if ! repo .IsEmpty {
144- if len (repo .DefaultBranch ) == 0 {
145- // Try to get HEAD branch and set it as default branch.
146- headBranch , err := gitRepo .GetHEADBranch ()
147- if err != nil {
148- return repo , fmt .Errorf ("GetHEADBranch: %w" , err )
149- }
150- if headBranch != nil {
151- repo .DefaultBranch = headBranch .Name
152- }
153- }
154-
155- if _ , err := SyncRepoBranchesWithRepo (ctx , repo , gitRepo , u .ID ); err != nil {
156- return repo , fmt .Errorf ("SyncRepoBranchesWithRepo: %v" , err )
157- }
158-
159- if ! opts .Releases {
160- // note: this will greatly improve release (tag) sync
161- // for pull-mirrors with many tags
162- repo .IsMirror = opts .Mirror
163- if err = SyncReleasesWithTags (ctx , repo , gitRepo ); err != nil {
164- log .Error ("Failed to synchronize tags to releases for repository: %v" , err )
165- }
166- }
167-
168- if opts .LFS {
169- endpoint := lfs .DetermineEndpoint (opts .CloneAddr , opts .LFSEndpoint )
170- lfsClient := lfs .NewClient (endpoint , httpTransport )
171- if err = StoreMissingLfsObjectsInRepository (ctx , repo , gitRepo , lfsClient ); err != nil {
172- log .Error ("Failed to store missing LFS objects for repository: %v" , err )
173- }
174- }
175- }
176-
177- ctx , committer , err := db .TxContext (ctx )
178- if err != nil {
179- return nil , err
180- }
181- defer committer .Close ()
182-
183- if opts .Mirror {
184- remoteAddress , err := util .SanitizeURL (opts .CloneAddr )
185- if err != nil {
186- return repo , err
187- }
188- mirrorModel := repo_model.Mirror {
189- RepoID : repo .ID ,
190- Interval : setting .Mirror .DefaultInterval ,
191- EnablePrune : true ,
192- NextUpdateUnix : timeutil .TimeStampNow ().AddDuration (setting .Mirror .DefaultInterval ),
193- LFS : opts .LFS ,
194- RemoteAddress : remoteAddress ,
195- }
196- if opts .LFS {
197- mirrorModel .LFSEndpoint = opts .LFSEndpoint
198- }
199-
200- if opts .MirrorInterval != "" {
201- parsedInterval , err := time .ParseDuration (opts .MirrorInterval )
202- if err != nil {
203- log .Error ("Failed to set Interval: %v" , err )
204- return repo , err
205- }
206- if parsedInterval == 0 {
207- mirrorModel .Interval = 0
208- mirrorModel .NextUpdateUnix = 0
209- } else if parsedInterval < setting .Mirror .MinInterval {
210- err := fmt .Errorf ("interval %s is set below Minimum Interval of %s" , parsedInterval , setting .Mirror .MinInterval )
211- log .Error ("Interval: %s is too frequent" , opts .MirrorInterval )
212- return repo , err
213- } else {
214- mirrorModel .Interval = parsedInterval
215- mirrorModel .NextUpdateUnix = timeutil .TimeStampNow ().AddDuration (parsedInterval )
216- }
217- }
218-
219- if err = repo_model .InsertMirror (ctx , & mirrorModel ); err != nil {
220- return repo , fmt .Errorf ("InsertOne: %w" , err )
221- }
222-
223- repo .IsMirror = true
224- if err = UpdateRepository (ctx , repo , false ); err != nil {
225- return nil , err
226- }
227-
228- // this is necessary for sync local tags from remote
229- configName := fmt .Sprintf ("remote.%s.fetch" , mirrorModel .GetRemoteName ())
230- if stdout , _ , err := git .NewCommand (ctx , "config" ).
231- AddOptionValues ("--add" , configName , `+refs/tags/*:refs/tags/*` ).
232- RunStdString (& git.RunOpts {Dir : repoPath }); err != nil {
233- log .Error ("MigrateRepositoryGitData(git config --add <remote> +refs/tags/*:refs/tags/*) in %v: Stdout: %s\n Error: %v" , repo , stdout , err )
234- return repo , fmt .Errorf ("error in MigrateRepositoryGitData(git config --add <remote> +refs/tags/*:refs/tags/*): %w" , err )
235- }
236- } else {
237- if err = UpdateRepoSize (ctx , repo ); err != nil {
238- log .Error ("Failed to update size for repository: %v" , err )
239- }
240- if repo , err = CleanUpMigrateInfo (ctx , repo ); err != nil {
241- return nil , err
242- }
243- }
244-
245- return repo , committer .Commit ()
246- }
247-
248- // cleanUpMigrateGitConfig removes mirror info which prevents "push --all".
249- // This also removes possible user credentials.
250- func cleanUpMigrateGitConfig (ctx context.Context , repoPath string ) error {
251- cmd := git .NewCommand (ctx , "remote" , "rm" , "origin" )
252- // if the origin does not exist
253- _ , stderr , err := cmd .RunStdString (& git.RunOpts {
254- Dir : repoPath ,
255- })
256- if err != nil && ! strings .HasPrefix (stderr , "fatal: No such remote" ) {
257- return err
258- }
259- return nil
260- }
261-
262- // CleanUpMigrateInfo finishes migrating repository and/or wiki with things that don't need to be done for mirrors.
263- func CleanUpMigrateInfo (ctx context.Context , repo * repo_model.Repository ) (* repo_model.Repository , error ) {
264- repoPath := repo .RepoPath ()
265- if err := CreateDelegateHooks (repoPath ); err != nil {
266- return repo , fmt .Errorf ("createDelegateHooks: %w" , err )
267- }
268- if repo .HasWiki () {
269- if err := CreateDelegateHooks (repo .WikiPath ()); err != nil {
270- return repo , fmt .Errorf ("createDelegateHooks.(wiki): %w" , err )
271- }
272- }
273-
274- _ , _ , err := git .NewCommand (ctx , "remote" , "rm" , "origin" ).RunStdString (& git.RunOpts {Dir : repoPath })
275- if err != nil && ! strings .HasPrefix (err .Error (), "exit status 128 - fatal: No such remote " ) {
276- return repo , fmt .Errorf ("CleanUpMigrateInfo: %w" , err )
277- }
278-
279- if repo .HasWiki () {
280- if err := cleanUpMigrateGitConfig (ctx , repo .WikiPath ()); err != nil {
281- return repo , fmt .Errorf ("cleanUpMigrateGitConfig (wiki): %w" , err )
282- }
283- }
284-
285- return repo , UpdateRepository (ctx , repo , false )
286- }
287-
28845// SyncRepoTags synchronizes releases table with repository tags
28946func SyncRepoTags (ctx context.Context , repoID int64 ) error {
29047 repo , err := repo_model .GetRepositoryByID (ctx , repoID )
0 commit comments