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

migrate.go 5.8KB

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