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 6.0KB

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