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.

198 lines
4.6 KiB

  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/structs"
  9. "code.gitea.io/gitea/modules/timeutil"
  10. "xorm.io/builder"
  11. )
  12. // Task represents a task
  13. type Task struct {
  14. ID int64
  15. DoerID int64 `xorm:"index"` // operator
  16. Doer *User `xorm:"-"`
  17. OwnerID int64 `xorm:"index"` // repo owner id, when creating, the repoID maybe zero
  18. Owner *User `xorm:"-"`
  19. RepoID int64 `xorm:"index"`
  20. Repo *Repository `xorm:"-"`
  21. Type structs.TaskType
  22. Status structs.TaskStatus `xorm:"index"`
  23. StartTime timeutil.TimeStamp
  24. EndTime timeutil.TimeStamp
  25. PayloadContent string `xorm:"TEXT"`
  26. Errors string `xorm:"TEXT"` // if task failed, saved the error reason
  27. Created timeutil.TimeStamp `xorm:"created"`
  28. }
  29. // LoadRepo loads repository of the task
  30. func (task *Task) LoadRepo() error {
  31. return task.loadRepo(x)
  32. }
  33. func (task *Task) loadRepo(e Engine) error {
  34. if task.Repo != nil {
  35. return nil
  36. }
  37. var repo Repository
  38. has, err := e.ID(task.RepoID).Get(&repo)
  39. if err != nil {
  40. return err
  41. } else if !has {
  42. return ErrRepoNotExist{
  43. ID: task.RepoID,
  44. }
  45. }
  46. task.Repo = &repo
  47. return nil
  48. }
  49. // LoadDoer loads do user
  50. func (task *Task) LoadDoer() error {
  51. if task.Doer != nil {
  52. return nil
  53. }
  54. var doer User
  55. has, err := x.ID(task.DoerID).Get(&doer)
  56. if err != nil {
  57. return err
  58. } else if !has {
  59. return ErrUserNotExist{
  60. UID: task.DoerID,
  61. }
  62. }
  63. task.Doer = &doer
  64. return nil
  65. }
  66. // LoadOwner loads owner user
  67. func (task *Task) LoadOwner() error {
  68. if task.Owner != nil {
  69. return nil
  70. }
  71. var owner User
  72. has, err := x.ID(task.OwnerID).Get(&owner)
  73. if err != nil {
  74. return err
  75. } else if !has {
  76. return ErrUserNotExist{
  77. UID: task.OwnerID,
  78. }
  79. }
  80. task.Owner = &owner
  81. return nil
  82. }
  83. // UpdateCols updates some columns
  84. func (task *Task) UpdateCols(cols ...string) error {
  85. _, err := x.ID(task.ID).Cols(cols...).Update(task)
  86. return err
  87. }
  88. // MigrateConfig returns task config when migrate repository
  89. func (task *Task) MigrateConfig() (*structs.MigrateRepoOption, error) {
  90. if task.Type == structs.TaskTypeMigrateRepo {
  91. var opts structs.MigrateRepoOption
  92. err := json.Unmarshal([]byte(task.PayloadContent), &opts)
  93. if err != nil {
  94. return nil, err
  95. }
  96. return &opts, nil
  97. }
  98. return nil, fmt.Errorf("Task type is %s, not Migrate Repo", task.Type.Name())
  99. }
  100. // ErrTaskDoesNotExist represents a "TaskDoesNotExist" kind of error.
  101. type ErrTaskDoesNotExist struct {
  102. ID int64
  103. RepoID int64
  104. Type structs.TaskType
  105. }
  106. // IsErrTaskDoesNotExist checks if an error is a ErrTaskIsNotExist.
  107. func IsErrTaskDoesNotExist(err error) bool {
  108. _, ok := err.(ErrTaskDoesNotExist)
  109. return ok
  110. }
  111. func (err ErrTaskDoesNotExist) Error() string {
  112. return fmt.Sprintf("task is not exist [id: %d, repo_id: %d, type: %d]",
  113. err.ID, err.RepoID, err.Type)
  114. }
  115. // GetMigratingTask returns the migrating task by repo's id
  116. func GetMigratingTask(repoID int64) (*Task, error) {
  117. var task = Task{
  118. RepoID: repoID,
  119. Type: structs.TaskTypeMigrateRepo,
  120. }
  121. has, err := x.Get(&task)
  122. if err != nil {
  123. return nil, err
  124. } else if !has {
  125. return nil, ErrTaskDoesNotExist{0, repoID, task.Type}
  126. }
  127. return &task, nil
  128. }
  129. // FindTaskOptions find all tasks
  130. type FindTaskOptions struct {
  131. Status int
  132. }
  133. // ToConds generates conditions for database operation.
  134. func (opts FindTaskOptions) ToConds() builder.Cond {
  135. var cond = builder.NewCond()
  136. if opts.Status >= 0 {
  137. cond = cond.And(builder.Eq{"status": opts.Status})
  138. }
  139. return cond
  140. }
  141. // FindTasks find all tasks
  142. func FindTasks(opts FindTaskOptions) ([]*Task, error) {
  143. var tasks = make([]*Task, 0, 10)
  144. err := x.Where(opts.ToConds()).Find(&tasks)
  145. return tasks, err
  146. }
  147. // CreateTask creates a task on database
  148. func CreateTask(task *Task) error {
  149. return createTask(x, task)
  150. }
  151. func createTask(e Engine, task *Task) error {
  152. _, err := e.Insert(task)
  153. return err
  154. }
  155. // FinishMigrateTask updates database when migrate task finished
  156. func FinishMigrateTask(task *Task) error {
  157. task.Status = structs.TaskStatusFinished
  158. task.EndTime = timeutil.TimeStampNow()
  159. sess := x.NewSession()
  160. defer sess.Close()
  161. if err := sess.Begin(); err != nil {
  162. return err
  163. }
  164. if _, err := sess.ID(task.ID).Cols("status", "end_time").Update(task); err != nil {
  165. return err
  166. }
  167. task.Repo.Status = RepositoryReady
  168. if _, err := sess.ID(task.RepoID).Cols("status").Update(task.Repo); err != nil {
  169. return err
  170. }
  171. return sess.Commit()
  172. }