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.

task.go 5.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. // Copyright 2019 Gitea. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package models
  5. import (
  6. "encoding/json"
  7. "fmt"
  8. "code.gitea.io/gitea/modules/log"
  9. "code.gitea.io/gitea/modules/migrations/base"
  10. "code.gitea.io/gitea/modules/structs"
  11. "code.gitea.io/gitea/modules/timeutil"
  12. "xorm.io/builder"
  13. )
  14. // Task represents a task
  15. type Task struct {
  16. ID int64
  17. DoerID int64 `xorm:"index"` // operator
  18. Doer *User `xorm:"-"`
  19. OwnerID int64 `xorm:"index"` // repo owner id, when creating, the repoID maybe zero
  20. Owner *User `xorm:"-"`
  21. RepoID int64 `xorm:"index"`
  22. Repo *Repository `xorm:"-"`
  23. Type structs.TaskType
  24. Status structs.TaskStatus `xorm:"index"`
  25. StartTime timeutil.TimeStamp
  26. EndTime timeutil.TimeStamp
  27. PayloadContent string `xorm:"TEXT"`
  28. Errors string `xorm:"TEXT"` // if task failed, saved the error reason
  29. Created timeutil.TimeStamp `xorm:"created"`
  30. }
  31. // LoadRepo loads repository of the task
  32. func (task *Task) LoadRepo() error {
  33. return task.loadRepo(x)
  34. }
  35. func (task *Task) loadRepo(e Engine) error {
  36. if task.Repo != nil {
  37. return nil
  38. }
  39. var repo Repository
  40. has, err := e.ID(task.RepoID).Get(&repo)
  41. if err != nil {
  42. return err
  43. } else if !has {
  44. return ErrRepoNotExist{
  45. ID: task.RepoID,
  46. }
  47. }
  48. task.Repo = &repo
  49. return nil
  50. }
  51. // LoadDoer loads do user
  52. func (task *Task) LoadDoer() error {
  53. if task.Doer != nil {
  54. return nil
  55. }
  56. var doer User
  57. has, err := x.ID(task.DoerID).Get(&doer)
  58. if err != nil {
  59. return err
  60. } else if !has {
  61. return ErrUserNotExist{
  62. UID: task.DoerID,
  63. }
  64. }
  65. task.Doer = &doer
  66. return nil
  67. }
  68. // LoadOwner loads owner user
  69. func (task *Task) LoadOwner() error {
  70. if task.Owner != nil {
  71. return nil
  72. }
  73. var owner User
  74. has, err := x.ID(task.OwnerID).Get(&owner)
  75. if err != nil {
  76. return err
  77. } else if !has {
  78. return ErrUserNotExist{
  79. UID: task.OwnerID,
  80. }
  81. }
  82. task.Owner = &owner
  83. return nil
  84. }
  85. // UpdateCols updates some columns
  86. func (task *Task) UpdateCols(cols ...string) error {
  87. _, err := x.ID(task.ID).Cols(cols...).Update(task)
  88. return err
  89. }
  90. // MigrateConfig returns task config when migrate repository
  91. func (task *Task) MigrateConfig() (*structs.MigrateRepoOption, error) {
  92. if task.Type == structs.TaskTypeMigrateRepo {
  93. var opts structs.MigrateRepoOption
  94. err := json.Unmarshal([]byte(task.PayloadContent), &opts)
  95. if err != nil {
  96. return nil, err
  97. }
  98. return &opts, nil
  99. }
  100. return nil, fmt.Errorf("Task type is %s, not Migrate Repo", task.Type.Name())
  101. }
  102. // ErrTaskDoesNotExist represents a "TaskDoesNotExist" kind of error.
  103. type ErrTaskDoesNotExist struct {
  104. ID int64
  105. RepoID int64
  106. Type structs.TaskType
  107. }
  108. // IsErrTaskDoesNotExist checks if an error is a ErrTaskIsNotExist.
  109. func IsErrTaskDoesNotExist(err error) bool {
  110. _, ok := err.(ErrTaskDoesNotExist)
  111. return ok
  112. }
  113. func (err ErrTaskDoesNotExist) Error() string {
  114. return fmt.Sprintf("task is not exist [id: %d, repo_id: %d, type: %d]",
  115. err.ID, err.RepoID, err.Type)
  116. }
  117. // GetMigratingTask returns the migrating task by repo's id
  118. func GetMigratingTask(repoID int64) (*Task, error) {
  119. var task = Task{
  120. RepoID: repoID,
  121. Type: structs.TaskTypeMigrateRepo,
  122. }
  123. has, err := x.Get(&task)
  124. if err != nil {
  125. return nil, err
  126. } else if !has {
  127. return nil, ErrTaskDoesNotExist{0, repoID, task.Type}
  128. }
  129. return &task, nil
  130. }
  131. // FindTaskOptions find all tasks
  132. type FindTaskOptions struct {
  133. Status int
  134. }
  135. // ToConds generates conditions for database operation.
  136. func (opts FindTaskOptions) ToConds() builder.Cond {
  137. var cond = builder.NewCond()
  138. if opts.Status >= 0 {
  139. cond = cond.And(builder.Eq{"status": opts.Status})
  140. }
  141. return cond
  142. }
  143. // FindTasks find all tasks
  144. func FindTasks(opts FindTaskOptions) ([]*Task, error) {
  145. var tasks = make([]*Task, 0, 10)
  146. err := x.Where(opts.ToConds()).Find(&tasks)
  147. return tasks, err
  148. }
  149. func createTask(e Engine, task *Task) error {
  150. _, err := e.Insert(task)
  151. return err
  152. }
  153. // CreateMigrateTask creates a migrate task
  154. func CreateMigrateTask(doer, u *User, opts base.MigrateOptions) (*Task, error) {
  155. bs, err := json.Marshal(&opts)
  156. if err != nil {
  157. return nil, err
  158. }
  159. var task = Task{
  160. DoerID: doer.ID,
  161. OwnerID: u.ID,
  162. Type: structs.TaskTypeMigrateRepo,
  163. Status: structs.TaskStatusQueue,
  164. PayloadContent: string(bs),
  165. }
  166. if err := createTask(x, &task); err != nil {
  167. return nil, err
  168. }
  169. repo, err := CreateRepository(doer, u, CreateRepoOptions{
  170. Name: opts.RepoName,
  171. Description: opts.Description,
  172. OriginalURL: opts.CloneAddr,
  173. IsPrivate: opts.Private,
  174. IsMirror: opts.Mirror,
  175. Status: RepositoryBeingMigrated,
  176. })
  177. if err != nil {
  178. task.EndTime = timeutil.TimeStampNow()
  179. task.Status = structs.TaskStatusFailed
  180. err2 := task.UpdateCols("end_time", "status")
  181. if err2 != nil {
  182. log.Error("UpdateCols Failed: %v", err2.Error())
  183. }
  184. return nil, err
  185. }
  186. task.RepoID = repo.ID
  187. if err = task.UpdateCols("repo_id"); err != nil {
  188. return nil, err
  189. }
  190. return &task, nil
  191. }
  192. // FinishMigrateTask updates database when migrate task finished
  193. func FinishMigrateTask(task *Task) error {
  194. task.Status = structs.TaskStatusFinished
  195. task.EndTime = timeutil.TimeStampNow()
  196. sess := x.NewSession()
  197. defer sess.Close()
  198. if err := sess.Begin(); err != nil {
  199. return err
  200. }
  201. if _, err := sess.ID(task.ID).Cols("status", "end_time").Update(task); err != nil {
  202. return err
  203. }
  204. task.Repo.Status = RepositoryReady
  205. if _, err := sess.ID(task.RepoID).Cols("status").Update(task.Repo); err != nil {
  206. return err
  207. }
  208. return sess.Commit()
  209. }