本站源代码
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

266 lines
6.3KB

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