You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

migrate.go 6.8 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. // Copyright 2019 The Gitea Authors. All rights reserved.
  2. // Copyright 2018 Jonas Franz. All rights reserved.
  3. // Use of this source code is governed by a MIT-style
  4. // license that can be found in the LICENSE file.
  5. package migrations
  6. import (
  7. "fmt"
  8. "code.gitea.io/gitea/models"
  9. "code.gitea.io/gitea/modules/log"
  10. "code.gitea.io/gitea/modules/migrations/base"
  11. "code.gitea.io/gitea/modules/setting"
  12. "code.gitea.io/gitea/modules/structs"
  13. )
  14. // MigrateOptions is equal to base.MigrateOptions
  15. type MigrateOptions = base.MigrateOptions
  16. var (
  17. factories []base.DownloaderFactory
  18. )
  19. // RegisterDownloaderFactory registers a downloader factory
  20. func RegisterDownloaderFactory(factory base.DownloaderFactory) {
  21. factories = append(factories, factory)
  22. }
  23. // MigrateRepository migrate repository according MigrateOptions
  24. func MigrateRepository(doer *models.User, ownerName string, opts base.MigrateOptions) (*models.Repository, error) {
  25. var (
  26. downloader base.Downloader
  27. uploader = NewGiteaLocalUploader(doer, ownerName, opts.RepoName)
  28. theFactory base.DownloaderFactory
  29. )
  30. for _, factory := range factories {
  31. if match, err := factory.Match(opts); err != nil {
  32. return nil, err
  33. } else if match {
  34. downloader, err = factory.New(opts)
  35. if err != nil {
  36. return nil, err
  37. }
  38. theFactory = factory
  39. break
  40. }
  41. }
  42. if downloader == nil {
  43. opts.Wiki = true
  44. opts.Milestones = false
  45. opts.Labels = false
  46. opts.Releases = false
  47. opts.Comments = false
  48. opts.Issues = false
  49. opts.PullRequests = false
  50. opts.GitServiceType = structs.PlainGitService
  51. downloader = NewPlainGitDownloader(ownerName, opts.RepoName, opts.CloneAddr)
  52. log.Trace("Will migrate from git: %s", opts.CloneAddr)
  53. } else if opts.GitServiceType == structs.NotMigrated {
  54. opts.GitServiceType = theFactory.GitServiceType()
  55. }
  56. uploader.gitServiceType = opts.GitServiceType
  57. if setting.Migrations.MaxAttempts > 1 {
  58. downloader = base.NewRetryDownloader(downloader, setting.Migrations.MaxAttempts, setting.Migrations.RetryBackoff)
  59. }
  60. if err := migrateRepository(downloader, uploader, opts); err != nil {
  61. if err1 := uploader.Rollback(); err1 != nil {
  62. log.Error("rollback failed: %v", err1)
  63. }
  64. if err2 := models.CreateRepositoryNotice(fmt.Sprintf("Migrate repository from %s failed: %v", opts.CloneAddr, err)); err2 != nil {
  65. log.Error("create respotiry notice failed: ", err2)
  66. }
  67. return nil, err
  68. }
  69. return uploader.repo, nil
  70. }
  71. // migrateRepository will download informations and upload to Uploader, this is a simple
  72. // process for small repository. For a big repository, save all the data to disk
  73. // before upload is better
  74. func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts base.MigrateOptions) error {
  75. repo, err := downloader.GetRepoInfo()
  76. if err != nil {
  77. return err
  78. }
  79. repo.IsPrivate = opts.Private
  80. repo.IsMirror = opts.Mirror
  81. if opts.Description != "" {
  82. repo.Description = opts.Description
  83. }
  84. log.Trace("migrating git data")
  85. if err := uploader.CreateRepo(repo, opts); err != nil {
  86. return err
  87. }
  88. defer uploader.Close()
  89. log.Trace("migrating topics")
  90. topics, err := downloader.GetTopics()
  91. if err != nil {
  92. return err
  93. }
  94. if len(topics) > 0 {
  95. if err := uploader.CreateTopics(topics...); err != nil {
  96. return err
  97. }
  98. }
  99. if opts.Milestones {
  100. log.Trace("migrating milestones")
  101. milestones, err := downloader.GetMilestones()
  102. if err != nil {
  103. return err
  104. }
  105. msBatchSize := uploader.MaxBatchInsertSize("milestone")
  106. for len(milestones) > 0 {
  107. if len(milestones) < msBatchSize {
  108. msBatchSize = len(milestones)
  109. }
  110. if err := uploader.CreateMilestones(milestones...); err != nil {
  111. return err
  112. }
  113. milestones = milestones[msBatchSize:]
  114. }
  115. }
  116. if opts.Labels {
  117. log.Trace("migrating labels")
  118. labels, err := downloader.GetLabels()
  119. if err != nil {
  120. return err
  121. }
  122. lbBatchSize := uploader.MaxBatchInsertSize("label")
  123. for len(labels) > 0 {
  124. if len(labels) < lbBatchSize {
  125. lbBatchSize = len(labels)
  126. }
  127. if err := uploader.CreateLabels(labels...); err != nil {
  128. return err
  129. }
  130. labels = labels[lbBatchSize:]
  131. }
  132. }
  133. if opts.Releases {
  134. log.Trace("migrating releases")
  135. releases, err := downloader.GetReleases()
  136. if err != nil {
  137. return err
  138. }
  139. relBatchSize := uploader.MaxBatchInsertSize("release")
  140. for len(releases) > 0 {
  141. if len(releases) < relBatchSize {
  142. relBatchSize = len(releases)
  143. }
  144. if err := uploader.CreateReleases(releases[:relBatchSize]...); err != nil {
  145. return err
  146. }
  147. releases = releases[relBatchSize:]
  148. }
  149. // Once all releases (if any) are inserted, sync any remaining non-release tags
  150. if err := uploader.SyncTags(); err != nil {
  151. return err
  152. }
  153. }
  154. var commentBatchSize = uploader.MaxBatchInsertSize("comment")
  155. if opts.Issues {
  156. log.Trace("migrating issues and comments")
  157. var issueBatchSize = uploader.MaxBatchInsertSize("issue")
  158. for i := 1; ; i++ {
  159. issues, isEnd, err := downloader.GetIssues(i, issueBatchSize)
  160. if err != nil {
  161. return err
  162. }
  163. if err := uploader.CreateIssues(issues...); err != nil {
  164. return err
  165. }
  166. if !opts.Comments {
  167. continue
  168. }
  169. var allComments = make([]*base.Comment, 0, commentBatchSize)
  170. for _, issue := range issues {
  171. comments, err := downloader.GetComments(issue.Number)
  172. if err != nil {
  173. return err
  174. }
  175. allComments = append(allComments, comments...)
  176. if len(allComments) >= commentBatchSize {
  177. if err := uploader.CreateComments(allComments[:commentBatchSize]...); err != nil {
  178. return err
  179. }
  180. allComments = allComments[commentBatchSize:]
  181. }
  182. }
  183. if len(allComments) > 0 {
  184. if err := uploader.CreateComments(allComments...); err != nil {
  185. return err
  186. }
  187. }
  188. if isEnd {
  189. break
  190. }
  191. }
  192. }
  193. if opts.PullRequests {
  194. log.Trace("migrating pull requests and comments")
  195. var prBatchSize = uploader.MaxBatchInsertSize("pullrequest")
  196. for i := 1; ; i++ {
  197. prs, err := downloader.GetPullRequests(i, prBatchSize)
  198. if err != nil {
  199. return err
  200. }
  201. if err := uploader.CreatePullRequests(prs...); err != nil {
  202. return err
  203. }
  204. if !opts.Comments {
  205. continue
  206. }
  207. var allComments = make([]*base.Comment, 0, commentBatchSize)
  208. for _, pr := range prs {
  209. comments, err := downloader.GetComments(pr.Number)
  210. if err != nil {
  211. return err
  212. }
  213. allComments = append(allComments, comments...)
  214. if len(allComments) >= commentBatchSize {
  215. if err := uploader.CreateComments(allComments[:commentBatchSize]...); err != nil {
  216. return err
  217. }
  218. allComments = allComments[commentBatchSize:]
  219. }
  220. }
  221. if len(allComments) > 0 {
  222. if err := uploader.CreateComments(allComments...); err != nil {
  223. return err
  224. }
  225. }
  226. if len(prs) < prBatchSize {
  227. break
  228. }
  229. }
  230. }
  231. return nil
  232. }