add task variants

master
Paulo Simão 2021-11-03 13:25:44 -03:00
parent 481ebc30e0
commit 8fee228701
4 changed files with 107 additions and 140 deletions

7
go.mod
View File

@ -2,6 +2,10 @@ module go.digitalcircle.com.br/open/mk
go 1.17 go 1.17
replace (
go.digitalcircle.com.br/open/shelly => ../shelly
)
require ( require (
github.com/alecthomas/kong v0.2.17 github.com/alecthomas/kong v0.2.17
github.com/fatih/color v1.13.0 github.com/fatih/color v1.13.0
@ -10,4 +14,5 @@ require (
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e // indirect golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
) go.digitalcircle.com.br/open/shelly v0.0.0-20211103011122-59a4e22ee8ce // indirect
)

8
go.sum
View File

@ -17,6 +17,14 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
go.digitalcircle.com.br/open/shelly v0.0.0-20211030113731-e855d65d6014 h1:4WIAT2wEfG6Ype5PSscio8Ezd+nwFUb60ivVDl71fiU=
go.digitalcircle.com.br/open/shelly v0.0.0-20211030113731-e855d65d6014/go.mod h1:J4ZSPkhjtyQz1yDxFGTemtz+Z7Z3YkzLd7iw9Jqo1+E=
go.digitalcircle.com.br/open/shelly v0.0.0-20211103003803-2665d10c09c2 h1:X3s/yNZMW6lEl8AHuM5WScWZz5Aq0XkfObBow/Q/VJ8=
go.digitalcircle.com.br/open/shelly v0.0.0-20211103003803-2665d10c09c2/go.mod h1:J4ZSPkhjtyQz1yDxFGTemtz+Z7Z3YkzLd7iw9Jqo1+E=
go.digitalcircle.com.br/open/shelly v0.0.0-20211103004736-5ff5942b4ff3 h1:urFhugLuu02mir7lV2l9ifMNxcdE1risO3QQDvDFiBM=
go.digitalcircle.com.br/open/shelly v0.0.0-20211103004736-5ff5942b4ff3/go.mod h1:J4ZSPkhjtyQz1yDxFGTemtz+Z7Z3YkzLd7iw9Jqo1+E=
go.digitalcircle.com.br/open/shelly v0.0.0-20211103011122-59a4e22ee8ce h1:JJi0bh4gOhgklrdfht4hOnaeWwRWBnBPEamPmpfJ2Q4=
go.digitalcircle.com.br/open/shelly v0.0.0-20211103011122-59a4e22ee8ce/go.mod h1:J4ZSPkhjtyQz1yDxFGTemtz+Z7Z3YkzLd7iw9Jqo1+E=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

View File

@ -1,10 +1,11 @@
package lib package lib
import ( import (
"bufio" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"github.com/fatih/color" "github.com/fatih/color"
"go.digitalcircle.com.br/open/shelly"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
"log" "log"
"os" "os"
@ -13,7 +14,6 @@ import (
"runtime" "runtime"
"sort" "sort"
"strings" "strings"
"sync"
"time" "time"
) )
@ -83,17 +83,38 @@ func Log(i int, task string, stream string, b string) {
} }
func RunTask(name string, t *MkTask, l int) error { 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
}
for k, v := range t.Env { if t.Model != "" {
env[k] = v 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 { for k, v := range t.Vars {
vars[k] = v 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)) Log(l, name, "**", fmt.Sprintf("Starting %s", name))
}
if len(t.Pre) > 0 { if len(t.Pre) > 0 {
Log(l, name, "**", fmt.Sprintf("Will run Pre tasks: [%s]", strings.Join(t.Pre, ","))) Log(l, name, "**", fmt.Sprintf("Will run Pre tasks: [%s]", strings.Join(t.Pre, ",")))
for _, v := range t.Pre { for _, v := range t.Pre {
@ -107,7 +128,7 @@ func RunTask(name string, t *MkTask, l int) error {
pr, ok := model.Tasks[v] pr, ok := model.Tasks[v]
if ok { if ok {
err := RunTask(v, pr, l+1) err := RunTask(v, pr, "", l+1)
if err != nil { if err != nil {
return err return err
} }
@ -116,125 +137,20 @@ func RunTask(name string, t *MkTask, l int) error {
} }
} }
} }
var c *exec.Cmd
if runtime.GOOS == "windows" { _, err := shelly.Exec(cmd, &shelly.Opts{
c = exec.Command("cmd.exe") Debug: model.Debug,
} else { Trace: model.Trace,
c = exec.Command("sh") SetupProc: func(cmd *exec.Cmd) {
} for k, v := range t.Env {
for k, v := range env { env[k] = v
c.Env = append(c.Env, fmt.Sprintf("%s=%s", k, v))
} }
pi, _ := c.StdinPipe() for k, v := range t.Vars {
vars[k] = v
po, err := c.StdoutPipe()
if err != nil {
log.Printf(err.Error())
return err
} }
scannero := bufio.NewScanner(po) },
})
pe, err := c.StderrPipe()
if err != nil {
log.Printf(err.Error())
return err
}
scannere := bufio.NewScanner(pe)
wg := sync.WaitGroup{}
wg.Add(2)
ch := make(chan string)
go func() {
time.Sleep(time.Millisecond * 100)
defer wg.Done()
for scannero.Scan() {
line := scannero.Text()
if strings.Contains(line, "__CMD_ENDED__:") {
ret := strings.Split(line, "__CMD_ENDED__:")[1]
if ret != "%errorlevel%" {
ch <- ret
}
} else {
Log(l+1, name, "O", line)
}
}
}()
go func() {
time.Sleep(time.Millisecond * 100)
defer wg.Done()
for scannere.Scan() {
Log(l+1, name, "E", scannere.Text())
}
}()
err = c.Start()
if err != nil {
return err
}
lines := bufio.NewScanner(strings.NewReader(t.Cmd))
//if runtime.GOOS == "windows" {
// pi.Write([]byte("@echo off\n"))
//}
for lines.Scan() {
txt := lines.Text()
for k, v := range vars {
txt = strings.Replace(txt, fmt.Sprintf("${%s}", k), v, -1)
}
if strings.HasPrefix(txt, "@") {
txt = strings.TrimLeft(txt, "@")
} else {
Log(l+1, name, "I", txt)
}
if strings.HasPrefix(txt, "mk:") {
txt = strings.Replace(txt, "mk:", "", 1)
txt = strings.TrimSpace(txt)
err = RunMkCmd(l+1, txt)
if err != nil {
log.Printf("Error running: %s", txt)
}
} else {
_, err = pi.Write([]byte(txt + "\n"))
if runtime.GOOS == "windows" {
_, err = pi.Write([]byte("echo __CMD_ENDED__:%errorlevel%" + "\n"))
} else {
_, err = pi.Write([]byte("echo __CMD_ENDED__:$?" + "\n"))
}
ret := <-ch
if ret != "0" && t.Onerror == "skip" {
Log(l+1, name, "E", "Error Code: "+ret+" will continue, but watch out")
} else if ret != "0" && t.Onerror != "skip" {
Log(l+1, name, "E", "Error Code is: "+ret+" ABORTING")
break
}
}
}
_, err = pi.Write([]byte("exit\n"))
if err != nil {
return err
}
wg.Wait()
err = c.Wait()
Log(l, name, "**", "End")
return err return err
} }
@ -270,6 +186,15 @@ func DumpEnv() {
} }
} }
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 { func Prepare() error {
InitCli() InitCli()
@ -306,9 +231,26 @@ func Prepare() error {
if model.Default == "" { if model.Default == "" {
model.Default = "main" model.Default = "main"
} }
model.Tasks = make(map[string]*MkTask)
for k, v := range model.Tasks { for k, v := range model.RawTasks {
v.Name = k 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 { if CLI.List {
@ -384,9 +326,16 @@ func Run() error {
DumpEnv() DumpEnv()
model.Stack = make(map[string]string) model.Stack = make(map[string]string)
for _, v := range CLI.Tasks { for _, v := range CLI.Tasks {
tasko := ResolveTask(v) taskparts := strings.Split(v, ",")
tasko := ResolveTask(taskparts[0])
if tasko != nil { if tasko != nil {
err = RunTask(v, tasko, 0) 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 { } else {
return errors.New(fmt.Sprintf("No task named %s found", v)) return errors.New(fmt.Sprintf("No task named %s found", v))
} }

View File

@ -8,11 +8,16 @@ type MkTask struct {
Onerror string `yaml:"onerror"` Onerror string `yaml:"onerror"`
Env map[string]string `yaml:"env"` Env map[string]string `yaml:"env"`
Vars map[string]string `yaml:"vars"` Vars map[string]string `yaml:"vars"`
Model string `yaml:"model"`
Variants []string `yaml:"variants"`
} }
type MkModel struct { type MkModel struct {
Env map[string]string `yaml:"env"` Env map[string]string `yaml:"env"`
Vars map[string]string `yaml:"vars"` Vars map[string]string `yaml:"vars"`
Tasks map[string]*MkTask `yaml:"tasks"` RawTasks map[string]interface{} `yaml:"tasks"`
Tasks map[string]*MkTask `yaml:"-"`
Default string `yaml:"default"` Default string `yaml:"default"`
Stack map[string]string `yaml:"-"` Stack map[string]string `yaml:"-"`
Debug bool `yaml:"debug"`
Trace bool `yaml:"trace"`
} }