executor.go 2.73 KB
Newer Older
Kamil Trzciński's avatar
Kamil Trzciński committed
1 2
package common

Kamil Trzciński's avatar
Kamil Trzciński committed
3
import (
4
	"context"
5
	"errors"
Kamil Trzciński's avatar
Kamil Trzciński committed
6
	"fmt"
Kamil Trzciński's avatar
Kamil Trzciński committed
7

8
	"github.com/sirupsen/logrus"
Kamil Trzciński's avatar
Kamil Trzciński committed
9 10
)

11 12
type ExecutorData interface{}

13
type ExecutorCommand struct {
14
	Script     string
Kamil Trzciński's avatar
Kamil Trzciński committed
15
	Stage      BuildStage
16
	Predefined bool
17
	Context    context.Context
18 19
}

20 21 22 23 24 25 26 27 28
type ExecutorStage string

const (
	ExecutorStageCreated ExecutorStage = "created"
	ExecutorStagePrepare ExecutorStage = "prepare"
	ExecutorStageFinish  ExecutorStage = "finish"
	ExecutorStageCleanup ExecutorStage = "cleanup"
)

29
type ExecutorPrepareOptions struct {
30 31 32 33 34
	Config  *RunnerConfig
	Build   *Build
	Trace   JobTrace
	User    string
	Context context.Context
35 36
}

Kamil Trzciński's avatar
Kamil Trzciński committed
37
type Executor interface {
38
	Shell() *ShellScriptInfo
39
	Prepare(options ExecutorPrepareOptions) error
40
	Run(cmd ExecutorCommand) error
41
	Finish(err error)
Kamil Trzciński's avatar
Kamil Trzciński committed
42
	Cleanup()
43 44
	GetCurrentStage() ExecutorStage
	SetCurrentStage(stage ExecutorStage)
Kamil Trzciński's avatar
Kamil Trzciński committed
45 46
}

47 48 49
type ExecutorProvider interface {
	CanCreate() bool
	Create() Executor
50
	Acquire(config *RunnerConfig) (ExecutorData, error)
51
	Release(config *RunnerConfig, data ExecutorData)
52 53
	GetFeatures(features *FeaturesInfo) error
	GetDefaultShell() string
54 55
}

Kamil Trzciński's avatar
Kamil Trzciński committed
56
type BuildError struct {
Shinya Maeda's avatar
Shinya Maeda committed
57
	Inner         error
58
	FailureReason JobFailureReason
Kamil Trzciński's avatar
Kamil Trzciński committed
59 60 61 62 63 64 65 66 67 68
}

func (b *BuildError) Error() string {
	if b.Inner == nil {
		return "error"
	}

	return b.Inner.Error()
}

69
var executors map[string]ExecutorProvider
Kamil Trzciński's avatar
Kamil Trzciński committed
70

71 72 73 74 75
func validateExecutorProvider(provider ExecutorProvider) error {
	if provider.GetDefaultShell() == "" {
		return errors.New("default shell not implemented")
	}

76
	if !provider.CanCreate() {
77 78 79
		return errors.New("cannot create executor")
	}

Kamil Trzciński's avatar
Kamil Trzciński committed
80 81
	if err := provider.GetFeatures(&FeaturesInfo{}); err != nil {
		return fmt.Errorf("cannot get features: %v", err)
82 83 84 85 86
	}

	return nil
}

87
func RegisterExecutor(executor string, provider ExecutorProvider) {
88
	logrus.Debugln("Registering", executor, "executor...")
Kamil Trzciński's avatar
Kamil Trzciński committed
89

90 91 92 93
	if err := validateExecutorProvider(provider); err != nil {
		panic("Executor cannot be registered: " + err.Error())
	}

Kamil Trzciński's avatar
Kamil Trzciński committed
94
	if executors == nil {
95
		executors = make(map[string]ExecutorProvider)
Kamil Trzciński's avatar
Kamil Trzciński committed
96
	}
97
	if _, ok := executors[executor]; ok {
Kamil Trzciński's avatar
Kamil Trzciński committed
98 99
		panic("Executor already exist: " + executor)
	}
100
	executors[executor] = provider
Kamil Trzciński's avatar
Kamil Trzciński committed
101 102
}

103
func GetExecutor(executor string) ExecutorProvider {
104 105 106 107
	if executors == nil {
		return nil
	}

108 109 110
	provider, _ := executors[executor]
	return provider
}
111

112 113 114 115 116 117
func GetExecutors() []string {
	names := []string{}
	if executors != nil {
		for name := range executors {
			names = append(names, name)
		}
118
	}
119
	return names
120 121
}

122 123 124 125 126 127 128 129 130
func GetExecutorProviders() (providers []ExecutorProvider) {
	if executors != nil {
		for _, executorProvider := range executors {
			providers = append(providers, executorProvider)
		}
	}
	return
}

131
func NewExecutor(executor string) Executor {
132
	provider := GetExecutor(executor)
133 134
	if provider != nil {
		return provider.Create()
Kamil Trzciński's avatar
Kamil Trzciński committed
135 136
	}

137
	return nil
Kamil Trzciński's avatar
Kamil Trzciński committed
138
}