loading up the forgejo repo on tangled to test page performance
at forgejo 6.2 kB view raw
1// Copyright 2019 Gitea. All rights reserved. 2// SPDX-License-Identifier: MIT 3 4package admin 5 6import ( 7 "context" 8 "fmt" 9 10 "forgejo.org/models/db" 11 repo_model "forgejo.org/models/repo" 12 user_model "forgejo.org/models/user" 13 "forgejo.org/modules/json" 14 "forgejo.org/modules/migration" 15 "forgejo.org/modules/secret" 16 "forgejo.org/modules/setting" 17 "forgejo.org/modules/structs" 18 "forgejo.org/modules/timeutil" 19 "forgejo.org/modules/util" 20) 21 22// Task represents a task 23type Task struct { 24 ID int64 25 DoerID int64 `xorm:"index"` // operator 26 Doer *user_model.User `xorm:"-"` 27 OwnerID int64 `xorm:"index"` // repo owner id, when creating, the repoID maybe zero 28 Owner *user_model.User `xorm:"-"` 29 RepoID int64 `xorm:"index"` 30 Repo *repo_model.Repository `xorm:"-"` 31 Type structs.TaskType 32 Status structs.TaskStatus `xorm:"index"` 33 StartTime timeutil.TimeStamp 34 EndTime timeutil.TimeStamp 35 PayloadContent string `xorm:"TEXT"` 36 Message string `xorm:"TEXT"` // if task failed, saved the error reason, it could be a JSON string of TranslatableMessage or a plain message 37 Created timeutil.TimeStamp `xorm:"created"` 38} 39 40func init() { 41 db.RegisterModel(new(Task)) 42} 43 44// TranslatableMessage represents JSON struct that can be translated with a Locale 45type TranslatableMessage struct { 46 Format string 47 Args []any `json:",omitempty"` 48} 49 50// LoadRepo loads repository of the task 51func (task *Task) LoadRepo(ctx context.Context) error { 52 if task.Repo != nil { 53 return nil 54 } 55 var repo repo_model.Repository 56 has, err := db.GetEngine(ctx).ID(task.RepoID).Get(&repo) 57 if err != nil { 58 return err 59 } else if !has { 60 return repo_model.ErrRepoNotExist{ 61 ID: task.RepoID, 62 } 63 } 64 task.Repo = &repo 65 return nil 66} 67 68// LoadDoer loads do user 69func (task *Task) LoadDoer(ctx context.Context) error { 70 if task.Doer != nil { 71 return nil 72 } 73 74 var doer user_model.User 75 has, err := db.GetEngine(ctx).ID(task.DoerID).Get(&doer) 76 if err != nil { 77 return err 78 } else if !has { 79 return user_model.ErrUserNotExist{ 80 UID: task.DoerID, 81 } 82 } 83 task.Doer = &doer 84 85 return nil 86} 87 88// LoadOwner loads owner user 89func (task *Task) LoadOwner(ctx context.Context) error { 90 if task.Owner != nil { 91 return nil 92 } 93 94 var owner user_model.User 95 has, err := db.GetEngine(ctx).ID(task.OwnerID).Get(&owner) 96 if err != nil { 97 return err 98 } else if !has { 99 return user_model.ErrUserNotExist{ 100 UID: task.OwnerID, 101 } 102 } 103 task.Owner = &owner 104 105 return nil 106} 107 108// UpdateCols updates some columns 109func (task *Task) UpdateCols(ctx context.Context, cols ...string) error { 110 _, err := db.GetEngine(ctx).ID(task.ID).Cols(cols...).Update(task) 111 return err 112} 113 114// MigrateConfig returns task config when migrate repository 115func (task *Task) MigrateConfig() (*migration.MigrateOptions, error) { 116 if task.Type == structs.TaskTypeMigrateRepo { 117 var opts migration.MigrateOptions 118 err := json.Unmarshal([]byte(task.PayloadContent), &opts) 119 if err != nil { 120 return nil, err 121 } 122 123 // decrypt credentials 124 if opts.CloneAddrEncrypted != "" { 125 if opts.CloneAddr, err = secret.DecryptSecret(setting.SecretKey, opts.CloneAddrEncrypted); err != nil { 126 return nil, err 127 } 128 } 129 if opts.AuthPasswordEncrypted != "" { 130 if opts.AuthPassword, err = secret.DecryptSecret(setting.SecretKey, opts.AuthPasswordEncrypted); err != nil { 131 return nil, err 132 } 133 } 134 if opts.AuthTokenEncrypted != "" { 135 if opts.AuthToken, err = secret.DecryptSecret(setting.SecretKey, opts.AuthTokenEncrypted); err != nil { 136 return nil, err 137 } 138 } 139 140 return &opts, nil 141 } 142 return nil, fmt.Errorf("Task type is %s, not Migrate Repo", task.Type.Name()) 143} 144 145// ErrTaskDoesNotExist represents a "TaskDoesNotExist" kind of error. 146type ErrTaskDoesNotExist struct { 147 ID int64 148 RepoID int64 149 Type structs.TaskType 150} 151 152// IsErrTaskDoesNotExist checks if an error is a ErrTaskDoesNotExist. 153func IsErrTaskDoesNotExist(err error) bool { 154 _, ok := err.(ErrTaskDoesNotExist) 155 return ok 156} 157 158func (err ErrTaskDoesNotExist) Error() string { 159 return fmt.Sprintf("task does not exist [id: %d, repo_id: %d, type: %d]", 160 err.ID, err.RepoID, err.Type) 161} 162 163func (err ErrTaskDoesNotExist) Unwrap() error { 164 return util.ErrNotExist 165} 166 167// GetMigratingTask returns the migrating task by repo's id 168func GetMigratingTask(ctx context.Context, repoID int64) (*Task, error) { 169 task := Task{ 170 RepoID: repoID, 171 Type: structs.TaskTypeMigrateRepo, 172 } 173 has, err := db.GetEngine(ctx).Get(&task) 174 if err != nil { 175 return nil, err 176 } else if !has { 177 return nil, ErrTaskDoesNotExist{0, repoID, task.Type} 178 } 179 return &task, nil 180} 181 182// GetMigratingTaskByID returns the migrating task by repo's id 183func GetMigratingTaskByID(ctx context.Context, id, doerID int64) (*Task, *migration.MigrateOptions, error) { 184 task := Task{ 185 ID: id, 186 DoerID: doerID, 187 Type: structs.TaskTypeMigrateRepo, 188 } 189 has, err := db.GetEngine(ctx).Get(&task) 190 if err != nil { 191 return nil, nil, err 192 } else if !has { 193 return nil, nil, ErrTaskDoesNotExist{id, 0, task.Type} 194 } 195 196 var opts migration.MigrateOptions 197 if err := json.Unmarshal([]byte(task.PayloadContent), &opts); err != nil { 198 return nil, nil, err 199 } 200 return &task, &opts, nil 201} 202 203// CreateTask creates a task on database 204func CreateTask(ctx context.Context, task *Task) error { 205 return db.Insert(ctx, task) 206} 207 208// FinishMigrateTask updates database when migrate task finished 209func FinishMigrateTask(ctx context.Context, task *Task) error { 210 task.Status = structs.TaskStatusFinished 211 task.EndTime = timeutil.TimeStampNow() 212 213 // delete credentials when we're done, they're a liability. 214 conf, err := task.MigrateConfig() 215 if err != nil { 216 return err 217 } 218 conf.AuthPassword = "" 219 conf.AuthToken = "" 220 conf.CloneAddr = util.SanitizeCredentialURLs(conf.CloneAddr) 221 conf.AuthPasswordEncrypted = "" 222 conf.AuthTokenEncrypted = "" 223 conf.CloneAddrEncrypted = "" 224 confBytes, err := json.Marshal(conf) 225 if err != nil { 226 return err 227 } 228 task.PayloadContent = string(confBytes) 229 230 _, err = db.GetEngine(ctx).ID(task.ID).Cols("status", "end_time", "payload_content").Update(task) 231 return err 232}