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.

145 lines
2.9 KiB

package framework
import (
"k8s.io/apimachinery/pkg/util/validation/field"
"os"
"os/exec"
"path/filepath"
"strings"
"sync"
)
// 使用步骤:
// 1. installer = NewInstallerconfig
// 2. installer.Install()
type Installer struct {
Steps []Install `json:"steps"`
config *Config
once sync.Once
}
func NewInstaller(config *Config) *Installer {
return &Installer{config: config}
}
// 加载配置到 installer 对象
func (i *Installer) init() error {
var err error
// 只能执行一次
i.once.Do(func() {
// 安全检查config不能为空
if i.config == nil || i.config.Sub("install") == nil {
err = field.Invalid(
field.NewPath("install"),
nil,
"Not inital config object")
return
}
installer := new(Installer)
if e := i.config.Sub("install").Unmarshal(installer); e != nil {
err = e
return
}
if installer.Steps != nil {
i.Steps = installer.Steps
}
})
return err
}
func (i *Installer) Install() error {
// 1. 初始化,加载配置
if err := i.init(); err != nil {
return err
}
// 2. 判断执行的队列是否存在
if len(i.Steps) == 0 {
return nil
}
// 3. 遍历这个队列,执行 validate
root := field.NewPath("install")
for index, inst := range i.Steps {
fld := root.Index(index)
if err := (&inst).validate(fld); err != nil {
return err
}
}
// 4. 遍历这个队列,执行 install
for _, inst := range i.Steps {
inst.config = i.config
if err := (&inst).install(); err != nil {
return err
}
}
return nil
}
type Install struct {
Name string `json:"name"`
Cmd string `json:"cmd"`
Args []string `json:"args"`
Path string `json:"path"`
IgnoreFail bool `json:"ignoreFail"`
config *Config `json:"-"`
}
func (i *Install) validate(root *field.Path) error {
errs := field.ErrorList{}
// 1. 验证 name 字段
if strings.TrimSpace(i.Name) == "" {
errs = append(errs, field.Invalid(root.Child("name"), i.Name, "Cannot be empty"))
}
// 2. 验证 cmd 字段
if strings.TrimSpace(i.Cmd) == "" {
errs = append(errs, field.Invalid(root.Child("cmd"), i.Cmd, "Cannot be empty"))
}
// 3. 检查并设置 path 默认值
if strings.TrimSpace(i.Path) == "" {
i.Path = "."
}
return errs.ToAggregate()
}
func (i *Install) install() error {
// 1. 获取当前路径
currentDir, err := os.Getwd()
if err != nil {
return err
}
absPath := i.Path
if !filepath.IsAbs(absPath) {
if absPath, err = filepath.Abs(absPath); err != nil {
return err
}
}
// 2. 切换路径
// 2.1 判断路径是否相同
if currentDir != absPath {
// 2.1.1 不同责切换路径
if err := os.Chdir(absPath); err != nil {
return err
}
}
// 3. defer 推出前回到之前的路径
defer func() { _ = os.Chdir(currentDir) }()
// 4. 执行命令
cmd := exec.Command(i.Cmd, i.Args...)
cmd.Stdout = i.config.Stdout
cmd.Stderr = i.config.Stderr
return cmd.Run()
}