Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

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