346 lines
6.6 KiB
Go
346 lines
6.6 KiB
Go
package lib
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"github.com/fatih/color"
|
|
"go.digitalcircle.com.br/open/shelly"
|
|
"gopkg.in/yaml.v3"
|
|
"log"
|
|
"os"
|
|
"os/exec"
|
|
"os/user"
|
|
"runtime"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
var model *MkModel
|
|
|
|
func FileExists(filename string) bool {
|
|
info, err := os.Stat(filename)
|
|
if os.IsNotExist(err) {
|
|
return false
|
|
}
|
|
return !info.IsDir()
|
|
}
|
|
|
|
func ResolveConfig() (err error) {
|
|
if CLI.File != "" {
|
|
if CLI.Init && FileExists(CLI.File) {
|
|
println(fmt.Sprintf("Using file: %s", CLI.File))
|
|
return
|
|
} else {
|
|
err = errors.New(fmt.Sprintf("Config File %s not found", CLI.File))
|
|
}
|
|
}
|
|
deffiles := []string{".mk.yaml", ".mk", "mk", "mk.yaml"}
|
|
for _, v := range deffiles {
|
|
if CLI.Init || FileExists(v) {
|
|
println(fmt.Sprintf("Using file: %s", v))
|
|
CLI.File = v
|
|
return
|
|
}
|
|
}
|
|
err = errors.New(fmt.Sprintf("No Config File found"))
|
|
return
|
|
}
|
|
|
|
func ResolveTask(n string) *MkTask {
|
|
osname := runtime.GOOS
|
|
arch := runtime.GOARCH
|
|
vars["BASETASK"] = n
|
|
t, ok := model.Tasks[n+"_"+osname+"_"+arch]
|
|
if ok {
|
|
vars["TASK"] = n + "_" + osname + "_" + arch
|
|
return t
|
|
}
|
|
t, ok = model.Tasks[n+"_"+osname]
|
|
if ok {
|
|
vars["TASK"] = n + "_" + osname
|
|
return t
|
|
}
|
|
vars["TASK"] = n
|
|
|
|
return model.Tasks[n]
|
|
}
|
|
|
|
func Log(i int, task string, stream string, b string) {
|
|
timeLb := time.Now().Format("15:04:05")
|
|
tab := ""
|
|
for x := 0; x < i; x++ {
|
|
tab = tab + "\t"
|
|
}
|
|
if stream == "O" {
|
|
println(color.GreenString(fmt.Sprintf("%s %s [%s - %s]: %s", timeLb, tab, task, stream, b)))
|
|
} else if stream == "E" {
|
|
println(color.RedString(fmt.Sprintf("%s %s [%s - %s]: %s", timeLb, tab, task, stream, b)))
|
|
} else {
|
|
println(fmt.Sprintf("%s %s [%s - %s]: %s", timeLb, tab, task, stream, b))
|
|
}
|
|
|
|
}
|
|
|
|
func RunTask(name string, t *MkTask, variant string, l int) error {
|
|
cmd := t.Cmd
|
|
if len(t.Variants) > 0 && variant == "" {
|
|
for _, v := range t.Variants {
|
|
err := RunTask(name, t, v, l+1)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
if t.Model != "" {
|
|
cmd = model.Tasks[t.Model].Cmd
|
|
for k, v := range t.Vars {
|
|
cmd = strings.Replace(cmd, "${"+k+"}", v, -1)
|
|
}
|
|
}
|
|
|
|
for k, v := range t.Vars {
|
|
if strings.HasPrefix(k, variant+".") {
|
|
nk := strings.Replace(k, variant+".", "", 1)
|
|
cmd = strings.Replace(cmd, "${"+nk+"}", v, -1)
|
|
}
|
|
}
|
|
|
|
if variant != "" {
|
|
Log(l, name, "**", fmt.Sprintf("Starting %s::%s", name, variant))
|
|
} else {
|
|
Log(l, name, "**", fmt.Sprintf("Starting %s", name))
|
|
}
|
|
|
|
if len(t.Pre) > 0 {
|
|
Log(l, name, "**", fmt.Sprintf("Will run Pre tasks: [%s]", strings.Join(t.Pre, ",")))
|
|
for _, v := range t.Pre {
|
|
caller, repeat := model.Stack[v]
|
|
if repeat {
|
|
Log(l, name, "**", fmt.Sprintf("Task %s already called by %s - skipping.", v, caller))
|
|
continue
|
|
} else {
|
|
model.Stack[v] = name
|
|
}
|
|
|
|
pr, ok := model.Tasks[v]
|
|
if ok {
|
|
err := RunTask(v, pr, "", l+1)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
return errors.New(fmt.Sprintf("Task %s, prereq of: %s not found in model", v, name))
|
|
}
|
|
}
|
|
}
|
|
|
|
_, err := shelly.Exec(cmd, &shelly.Opts{
|
|
Debug: model.Debug,
|
|
Trace: model.Trace,
|
|
SetupProc: func(cmd *exec.Cmd) {
|
|
for k, v := range t.Env {
|
|
env[k] = v
|
|
}
|
|
|
|
for k, v := range t.Vars {
|
|
vars[k] = v
|
|
}
|
|
},
|
|
})
|
|
return err
|
|
|
|
}
|
|
|
|
func DumpEnv() {
|
|
if CLI.Env {
|
|
println("Vars:")
|
|
|
|
varnames := make([]string, 0)
|
|
for k := range vars {
|
|
varnames = append(varnames, k)
|
|
}
|
|
sort.Strings(varnames)
|
|
for _, k := range varnames {
|
|
v := vars[k]
|
|
println(fmt.Sprintf("%s => %s", k, v))
|
|
}
|
|
|
|
println("========")
|
|
println("Env:")
|
|
|
|
envnames := make([]string, 0)
|
|
for k := range env {
|
|
envnames = append(envnames, k)
|
|
}
|
|
sort.Strings(envnames)
|
|
for _, k := range envnames {
|
|
v := env[k]
|
|
println(fmt.Sprintf("%s => %s", k, v))
|
|
}
|
|
|
|
os.Exit(0)
|
|
}
|
|
}
|
|
|
|
func jsonConvert(src interface{}, dst interface{}) error {
|
|
bs, err := json.Marshal(src)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = json.Unmarshal(bs, dst)
|
|
return err
|
|
}
|
|
|
|
func Prepare() error {
|
|
|
|
InitCli()
|
|
err := ResolveConfig()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if CLI.Init {
|
|
err = InitFile()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
os.Exit(0)
|
|
}
|
|
|
|
if CLI.DumpValidator {
|
|
err = DumpValidator()
|
|
if err != nil {
|
|
log.Printf("Error DumpValidator: %s", err.Error())
|
|
}
|
|
os.Exit(0)
|
|
}
|
|
|
|
bs, err := os.ReadFile(CLI.File)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
model = &MkModel{}
|
|
err = yaml.Unmarshal(bs, model)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if model.Default == "" {
|
|
model.Default = "main"
|
|
}
|
|
model.Tasks = make(map[string]*MkTask)
|
|
|
|
for k, v := range model.RawTasks {
|
|
nv := &MkTask{}
|
|
nv.Name = k
|
|
nv.Vars = make(map[string]string)
|
|
switch v1 := v.(type) {
|
|
case string:
|
|
nv.Cmd = v1
|
|
case map[string]interface{}:
|
|
err = jsonConvert(v1, nv)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
for k1, v1 := range model.Vars {
|
|
nv.Vars[k1] = v1
|
|
}
|
|
model.Tasks[k] = nv
|
|
}
|
|
|
|
if CLI.List {
|
|
println("Tasks:")
|
|
tasknames := make([]string, 0)
|
|
for k := range model.Tasks {
|
|
tasknames = append(tasknames, k)
|
|
}
|
|
sort.Strings(tasknames)
|
|
for _, k := range tasknames {
|
|
v := model.Tasks[k]
|
|
def := ""
|
|
if v.Name == model.Default {
|
|
def = "DEF>"
|
|
} else {
|
|
def = ""
|
|
}
|
|
println(fmt.Sprintf("%s %s [%s]: %s", def, k, strings.Join(v.Pre, ","), v.Help))
|
|
}
|
|
os.Exit(0)
|
|
}
|
|
|
|
if len(CLI.Tasks) < 1 || CLI.Tasks[0] == "" || CLI.Tasks[0] == "." {
|
|
CLI.Tasks = []string{model.Default}
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
var env map[string]string
|
|
var vars map[string]string
|
|
|
|
func Run() error {
|
|
env = make(map[string]string)
|
|
vars = make(map[string]string)
|
|
envstrs := os.Environ()
|
|
for _, k := range envstrs {
|
|
parts := strings.Split(k, "=")
|
|
ek := strings.TrimSpace(parts[0])
|
|
ev := os.Getenv(ek)
|
|
env[ek] = ev
|
|
}
|
|
|
|
err := Prepare()
|
|
if err != nil {
|
|
log.Printf("Could not execute: %s", err.Error())
|
|
os.Exit(0)
|
|
}
|
|
|
|
for k, v := range model.Env {
|
|
env[k] = v
|
|
}
|
|
|
|
for k, v := range model.Vars {
|
|
vars[k] = v
|
|
}
|
|
now := time.Now()
|
|
vars["DT_YYMMDDHHmmss"] = now.Format("060102150405")
|
|
vars["DT_YYMMDD"] = now.Format("060102")
|
|
vars["DS_TS"] = fmt.Sprintf("%d", now.Unix())
|
|
|
|
u, err := user.Current()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
vars["USERNAME"] = u.Username
|
|
vars["HOMEDIR"] = u.HomeDir
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
DumpEnv()
|
|
model.Stack = make(map[string]string)
|
|
for _, v := range CLI.Tasks {
|
|
taskparts := strings.Split(v, ",")
|
|
tasko := ResolveTask(taskparts[0])
|
|
if tasko != nil {
|
|
if len(taskparts) > 1 {
|
|
for i := 1; i < len(taskparts); i++ {
|
|
err = RunTask(taskparts[0], tasko, taskparts[1], 0)
|
|
}
|
|
} else {
|
|
err = RunTask(taskparts[0], tasko, "", 0)
|
|
}
|
|
} else {
|
|
return errors.New(fmt.Sprintf("No task named %s found", v))
|
|
}
|
|
}
|
|
|
|
return err
|
|
}
|