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

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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()
}