2019-10-13 16:23:14 +03:00
// Copyright 2019 Gitea. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package models
import (
"fmt"
2020-09-11 01:29:19 +03:00
migration "code.gitea.io/gitea/modules/migrations/base"
2019-10-13 16:23:14 +03:00
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"
2021-03-02 00:08:10 +03:00
jsoniter "github.com/json-iterator/go"
2019-10-13 16:23:14 +03:00
"xorm.io/builder"
)
// Task represents a task
type Task struct {
ID int64
DoerID int64 ` xorm:"index" ` // operator
Doer * User ` xorm:"-" `
OwnerID int64 ` xorm:"index" ` // repo owner id, when creating, the repoID maybe zero
Owner * User ` xorm:"-" `
RepoID int64 ` xorm:"index" `
Repo * Repository ` xorm:"-" `
Type structs . TaskType
Status structs . TaskStatus ` xorm:"index" `
StartTime timeutil . TimeStamp
EndTime timeutil . TimeStamp
PayloadContent string ` xorm:"TEXT" `
Errors string ` xorm:"TEXT" ` // if task failed, saved the error reason
Created timeutil . TimeStamp ` xorm:"created" `
}
// LoadRepo loads repository of the task
func ( task * Task ) LoadRepo ( ) error {
return task . loadRepo ( x )
}
func ( task * Task ) loadRepo ( e Engine ) error {
if task . Repo != nil {
return nil
}
var repo Repository
has , err := e . ID ( task . RepoID ) . Get ( & repo )
if err != nil {
return err
} else if ! has {
return ErrRepoNotExist {
ID : task . RepoID ,
}
}
task . Repo = & repo
return nil
}
// LoadDoer loads do user
func ( task * Task ) LoadDoer ( ) error {
if task . Doer != nil {
return nil
}
var doer User
has , err := x . ID ( task . DoerID ) . Get ( & doer )
if err != nil {
return err
} else if ! has {
return ErrUserNotExist {
UID : task . DoerID ,
}
}
task . Doer = & doer
return nil
}
// LoadOwner loads owner user
func ( task * Task ) LoadOwner ( ) error {
if task . Owner != nil {
return nil
}
var owner User
has , err := x . ID ( task . OwnerID ) . Get ( & owner )
if err != nil {
return err
} else if ! has {
return ErrUserNotExist {
UID : task . OwnerID ,
}
}
task . Owner = & owner
return nil
}
// UpdateCols updates some columns
func ( task * Task ) UpdateCols ( cols ... string ) error {
_ , err := x . ID ( task . ID ) . Cols ( cols ... ) . Update ( task )
return err
}
// MigrateConfig returns task config when migrate repository
2020-09-11 01:29:19 +03:00
func ( task * Task ) MigrateConfig ( ) ( * migration . MigrateOptions , error ) {
2019-10-13 16:23:14 +03:00
if task . Type == structs . TaskTypeMigrateRepo {
2020-09-11 01:29:19 +03:00
var opts migration . MigrateOptions
2021-03-02 00:08:10 +03:00
json := jsoniter . ConfigCompatibleWithStandardLibrary
2019-10-13 16:23:14 +03:00
err := json . Unmarshal ( [ ] byte ( task . PayloadContent ) , & opts )
if err != nil {
return nil , err
}
return & opts , nil
}
return nil , fmt . Errorf ( "Task type is %s, not Migrate Repo" , task . Type . Name ( ) )
}
// ErrTaskDoesNotExist represents a "TaskDoesNotExist" kind of error.
type ErrTaskDoesNotExist struct {
ID int64
RepoID int64
Type structs . TaskType
}
// IsErrTaskDoesNotExist checks if an error is a ErrTaskIsNotExist.
func IsErrTaskDoesNotExist ( err error ) bool {
_ , ok := err . ( ErrTaskDoesNotExist )
return ok
}
func ( err ErrTaskDoesNotExist ) Error ( ) string {
return fmt . Sprintf ( "task is not exist [id: %d, repo_id: %d, type: %d]" ,
err . ID , err . RepoID , err . Type )
}
// GetMigratingTask returns the migrating task by repo's id
func GetMigratingTask ( repoID int64 ) ( * Task , error ) {
2021-03-14 21:52:12 +03:00
task := Task {
2019-10-13 16:23:14 +03:00
RepoID : repoID ,
Type : structs . TaskTypeMigrateRepo ,
}
has , err := x . Get ( & task )
if err != nil {
return nil , err
} else if ! has {
return nil , ErrTaskDoesNotExist { 0 , repoID , task . Type }
}
return & task , nil
}
2020-10-24 02:46:35 +03:00
// GetMigratingTaskByID returns the migrating task by repo's id
func GetMigratingTaskByID ( id , doerID int64 ) ( * Task , * migration . MigrateOptions , error ) {
2021-03-14 21:52:12 +03:00
task := Task {
2020-10-24 02:46:35 +03:00
ID : id ,
DoerID : doerID ,
Type : structs . TaskTypeMigrateRepo ,
}
has , err := x . Get ( & task )
if err != nil {
return nil , nil , err
} else if ! has {
return nil , nil , ErrTaskDoesNotExist { id , 0 , task . Type }
}
var opts migration . MigrateOptions
2021-03-02 00:08:10 +03:00
json := jsoniter . ConfigCompatibleWithStandardLibrary
2020-10-24 02:46:35 +03:00
if err := json . Unmarshal ( [ ] byte ( task . PayloadContent ) , & opts ) ; err != nil {
return nil , nil , err
}
return & task , & opts , nil
}
2019-10-13 16:23:14 +03:00
// FindTaskOptions find all tasks
type FindTaskOptions struct {
Status int
}
// ToConds generates conditions for database operation.
func ( opts FindTaskOptions ) ToConds ( ) builder . Cond {
2021-03-14 21:52:12 +03:00
cond := builder . NewCond ( )
2019-10-13 16:23:14 +03:00
if opts . Status >= 0 {
cond = cond . And ( builder . Eq { "status" : opts . Status } )
}
return cond
}
// FindTasks find all tasks
func FindTasks ( opts FindTaskOptions ) ( [ ] * Task , error ) {
2021-03-14 21:52:12 +03:00
tasks := make ( [ ] * Task , 0 , 10 )
2019-10-13 16:23:14 +03:00
err := x . Where ( opts . ToConds ( ) ) . Find ( & tasks )
return tasks , err
}
2020-01-12 15:11:17 +03:00
// CreateTask creates a task on database
func CreateTask ( task * Task ) error {
return createTask ( x , task )
}
2019-10-13 16:23:14 +03:00
func createTask ( e Engine , task * Task ) error {
_ , err := e . Insert ( task )
return err
}
// FinishMigrateTask updates database when migrate task finished
func FinishMigrateTask ( task * Task ) error {
task . Status = structs . TaskStatusFinished
task . EndTime = timeutil . TimeStampNow ( )
sess := x . NewSession ( )
defer sess . Close ( )
if err := sess . Begin ( ) ; err != nil {
return err
}
if _ , err := sess . ID ( task . ID ) . Cols ( "status" , "end_time" ) . Update ( task ) ; err != nil {
return err
}
return sess . Commit ( )
}