2019-05-07 09:12:51 +08:00
// Copyright 2019 The Gitea Authors. All rights reserved.
// Copyright 2018 Jonas Franz. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
import (
2019-12-17 12:16:54 +08:00
"context"
2019-10-13 21:23:14 +08:00
"fmt"
2019-05-07 09:12:51 +08:00
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/migrations/base"
2019-11-16 16:30:06 +08:00
"code.gitea.io/gitea/modules/setting"
2019-10-14 14:10:42 +08:00
"code.gitea.io/gitea/modules/structs"
2019-05-07 09:12:51 +08:00
)
// MigrateOptions is equal to base.MigrateOptions
type MigrateOptions = base . MigrateOptions
var (
factories [ ] base . DownloaderFactory
)
// RegisterDownloaderFactory registers a downloader factory
func RegisterDownloaderFactory ( factory base . DownloaderFactory ) {
factories = append ( factories , factory )
}
// MigrateRepository migrate repository according MigrateOptions
2019-12-17 12:16:54 +08:00
func MigrateRepository ( ctx context . Context , doer * models . User , ownerName string , opts base . MigrateOptions ) ( * models . Repository , error ) {
2019-05-07 09:12:51 +08:00
var (
downloader base . Downloader
2019-12-17 12:16:54 +08:00
uploader = NewGiteaLocalUploader ( ctx , doer , ownerName , opts . RepoName )
2019-10-14 14:10:42 +08:00
theFactory base . DownloaderFactory
2019-05-07 09:12:51 +08:00
)
for _ , factory := range factories {
if match , err := factory . Match ( opts ) ; err != nil {
return nil , err
} else if match {
downloader , err = factory . New ( opts )
if err != nil {
return nil , err
}
2019-10-14 14:10:42 +08:00
theFactory = factory
2019-05-07 09:12:51 +08:00
break
}
}
if downloader == nil {
opts . Wiki = true
opts . Milestones = false
opts . Labels = false
opts . Releases = false
opts . Comments = false
opts . Issues = false
opts . PullRequests = false
2019-10-14 14:10:42 +08:00
opts . GitServiceType = structs . PlainGitService
2019-10-13 21:23:14 +08:00
downloader = NewPlainGitDownloader ( ownerName , opts . RepoName , opts . CloneAddr )
2019-12-18 16:49:56 -05:00
log . Trace ( "Will migrate from git: %s" , opts . OriginalURL )
2019-10-14 14:10:42 +08:00
} else if opts . GitServiceType == structs . NotMigrated {
opts . GitServiceType = theFactory . GitServiceType ( )
2019-05-07 09:12:51 +08:00
}
2019-10-14 14:10:42 +08:00
uploader . gitServiceType = opts . GitServiceType
2019-11-16 16:30:06 +08:00
if setting . Migrations . MaxAttempts > 1 {
downloader = base . NewRetryDownloader ( downloader , setting . Migrations . MaxAttempts , setting . Migrations . RetryBackoff )
}
2019-12-17 12:16:54 +08:00
downloader . SetContext ( ctx )
2019-05-07 09:12:51 +08:00
if err := migrateRepository ( downloader , uploader , opts ) ; err != nil {
if err1 := uploader . Rollback ( ) ; err1 != nil {
log . Error ( "rollback failed: %v" , err1 )
}
2019-10-13 21:23:14 +08:00
2019-12-18 16:49:56 -05:00
if err2 := models . CreateRepositoryNotice ( fmt . Sprintf ( "Migrate repository from %s failed: %v" , opts . OriginalURL , err ) ) ; err2 != nil {
2019-10-13 21:23:14 +08:00
log . Error ( "create respotiry notice failed: " , err2 )
}
2019-05-07 09:12:51 +08:00
return nil , err
}
return uploader . repo , nil
}
// migrateRepository will download informations and upload to Uploader, this is a simple
// process for small repository. For a big repository, save all the data to disk
// before upload is better
func migrateRepository ( downloader base . Downloader , uploader base . Uploader , opts base . MigrateOptions ) error {
repo , err := downloader . GetRepoInfo ( )
if err != nil {
return err
}
repo . IsPrivate = opts . Private
repo . IsMirror = opts . Mirror
2019-05-20 20:43:43 +08:00
if opts . Description != "" {
repo . Description = opts . Description
}
2019-05-07 09:12:51 +08:00
log . Trace ( "migrating git data" )
2019-07-02 05:17:16 +08:00
if err := uploader . CreateRepo ( repo , opts ) ; err != nil {
2019-05-07 09:12:51 +08:00
return err
}
2019-11-13 07:01:19 +00:00
defer uploader . Close ( )
2019-05-07 09:12:51 +08:00
2019-08-14 08:16:12 +02:00
log . Trace ( "migrating topics" )
topics , err := downloader . GetTopics ( )
if err != nil {
return err
}
if len ( topics ) > 0 {
if err := uploader . CreateTopics ( topics ... ) ; err != nil {
return err
}
}
2019-05-07 09:12:51 +08:00
if opts . Milestones {
log . Trace ( "migrating milestones" )
milestones , err := downloader . GetMilestones ( )
if err != nil {
return err
}
2019-07-07 03:24:50 +08:00
msBatchSize := uploader . MaxBatchInsertSize ( "milestone" )
for len ( milestones ) > 0 {
if len ( milestones ) < msBatchSize {
msBatchSize = len ( milestones )
}
if err := uploader . CreateMilestones ( milestones ... ) ; err != nil {
return err
}
milestones = milestones [ msBatchSize : ]
2019-05-07 09:12:51 +08:00
}
}
if opts . Labels {
log . Trace ( "migrating labels" )
labels , err := downloader . GetLabels ( )
if err != nil {
return err
}
2019-07-07 03:24:50 +08:00
lbBatchSize := uploader . MaxBatchInsertSize ( "label" )
for len ( labels ) > 0 {
if len ( labels ) < lbBatchSize {
lbBatchSize = len ( labels )
}
if err := uploader . CreateLabels ( labels ... ) ; err != nil {
return err
}
labels = labels [ lbBatchSize : ]
2019-05-07 09:12:51 +08:00
}
}
if opts . Releases {
log . Trace ( "migrating releases" )
releases , err := downloader . GetReleases ( )
if err != nil {
return err
}
2019-07-07 03:24:50 +08:00
relBatchSize := uploader . MaxBatchInsertSize ( "release" )
for len ( releases ) > 0 {
2019-12-11 18:20:11 -06:00
if len ( releases ) < relBatchSize {
relBatchSize = len ( releases )
2019-07-07 03:24:50 +08:00
}
2019-12-11 18:20:11 -06:00
if err := uploader . CreateReleases ( releases [ : relBatchSize ] ... ) ; err != nil {
2019-07-07 03:24:50 +08:00
return err
}
releases = releases [ relBatchSize : ]
2019-05-07 09:12:51 +08:00
}
2019-12-11 18:20:11 -06:00
// Once all releases (if any) are inserted, sync any remaining non-release tags
if err := uploader . SyncTags ( ) ; err != nil {
return err
}
2019-05-07 09:12:51 +08:00
}
2019-07-07 03:24:50 +08:00
var commentBatchSize = uploader . MaxBatchInsertSize ( "comment" )
2019-05-07 09:12:51 +08:00
if opts . Issues {
log . Trace ( "migrating issues and comments" )
2019-07-07 03:24:50 +08:00
var issueBatchSize = uploader . MaxBatchInsertSize ( "issue" )
2019-05-31 04:26:57 +08:00
for i := 1 ; ; i ++ {
2019-07-07 03:24:50 +08:00
issues , isEnd , err := downloader . GetIssues ( i , issueBatchSize )
2019-05-07 09:12:51 +08:00
if err != nil {
return err
}
2019-06-29 21:38:22 +08:00
if err := uploader . CreateIssues ( issues ... ) ; err != nil {
return err
}
2019-05-07 09:12:51 +08:00
2019-06-29 21:38:22 +08:00
if ! opts . Comments {
continue
}
2019-05-07 09:12:51 +08:00
2019-07-07 03:24:50 +08:00
var allComments = make ( [ ] * base . Comment , 0 , commentBatchSize )
2019-06-29 21:38:22 +08:00
for _ , issue := range issues {
2019-05-07 09:12:51 +08:00
comments , err := downloader . GetComments ( issue . Number )
if err != nil {
return err
}
2019-07-07 22:14:12 -04:00
2019-06-29 21:38:22 +08:00
allComments = append ( allComments , comments ... )
2019-07-07 03:24:50 +08:00
if len ( allComments ) >= commentBatchSize {
if err := uploader . CreateComments ( allComments [ : commentBatchSize ] ... ) ; err != nil {
2019-05-07 09:12:51 +08:00
return err
}
2019-07-07 03:24:50 +08:00
allComments = allComments [ commentBatchSize : ]
2019-06-29 21:38:22 +08:00
}
}
if len ( allComments ) > 0 {
if err := uploader . CreateComments ( allComments ... ) ; err != nil {
return err
2019-05-07 09:12:51 +08:00
}
}
2019-05-31 04:26:57 +08:00
if isEnd {
2019-05-07 09:12:51 +08:00
break
}
}
}
if opts . PullRequests {
log . Trace ( "migrating pull requests and comments" )
2019-07-06 16:32:15 -04:00
var prBatchSize = uploader . MaxBatchInsertSize ( "pullrequest" )
2019-05-31 04:26:57 +08:00
for i := 1 ; ; i ++ {
2019-07-07 03:24:50 +08:00
prs , err := downloader . GetPullRequests ( i , prBatchSize )
2019-05-07 09:12:51 +08:00
if err != nil {
return err
}
2019-06-29 21:38:22 +08:00
if err := uploader . CreatePullRequests ( prs ... ) ; err != nil {
return err
}
2019-05-07 09:12:51 +08:00
2019-06-29 21:38:22 +08:00
if ! opts . Comments {
continue
}
2019-07-07 03:24:50 +08:00
var allComments = make ( [ ] * base . Comment , 0 , commentBatchSize )
2019-06-29 21:38:22 +08:00
for _ , pr := range prs {
2019-05-07 09:12:51 +08:00
comments , err := downloader . GetComments ( pr . Number )
if err != nil {
return err
}
2019-06-29 21:38:22 +08:00
allComments = append ( allComments , comments ... )
2019-07-07 03:24:50 +08:00
if len ( allComments ) >= commentBatchSize {
if err := uploader . CreateComments ( allComments [ : commentBatchSize ] ... ) ; err != nil {
2019-05-07 09:12:51 +08:00
return err
}
2019-07-07 03:24:50 +08:00
allComments = allComments [ commentBatchSize : ]
2019-05-07 09:12:51 +08:00
}
}
2019-06-29 21:38:22 +08:00
if len ( allComments ) > 0 {
if err := uploader . CreateComments ( allComments ... ) ; err != nil {
return err
}
}
2019-07-07 03:24:50 +08:00
if len ( prs ) < prBatchSize {
2019-05-07 09:12:51 +08:00
break
}
}
}
return nil
}