package scpt import ( "errors" "fmt" "github.com/alecthomas/participle" "github.com/gen2brain/dlgs" "io" "os" "os/exec" "reflect" "strings" ) var Vars = map[string]interface{}{} type FuncMap map[string]func(map[string]interface{}) (interface{}, error) var Funcs = FuncMap{ "displaydialog": displayDialog, "doshellscript": doShellScript, } func AddFuncs(fnMap FuncMap) { for name, fn := range fnMap { Funcs[name] = fn } } func AddVars(varMap map[string]interface{}) { for name, val := range varMap { Vars[name] = val } } func Parse(r io.Reader) (*AST, error) { parser, err := participle.Build(&AST{}) if err != nil { return nil, err } ast := &AST{} err = parser.Parse("", r, ast) if err != nil { return nil, err } return ast, nil } func Execute(ast AST) { for _, cmd := range ast.Commands { if cmd.Vars != nil { for _, Var := range cmd.Vars { val := ParseValue(Var.Value) if strings.Contains(reflect.TypeOf(val).String(), ".FuncCall") { Call := val.(*FuncCall) Vars[Var.Key], _ = CallFunction(Call) } else { Vars[Var.Key] = val } } } else if cmd.Calls != nil { for _, Call := range cmd.Calls { _, _ = CallFunction(Call) } } } } func ParseValue(val *Value) interface{} { if val.String != nil { return strings.Trim(*val.String, `"`) } else if val.Bool != nil { return *val.Bool } else if val.Float != nil { return *val.Float } else if val.Integer != nil { return *val.Integer } else if val.SubCmd != nil { return val.SubCmd } else if val.VarVal != nil { return Vars[*val.VarVal] } return nil } func UnwrapArgs(args []*Arg) map[string]interface{} { argMap := map[string]interface{}{} for _, arg := range args { argMap[arg.Key] = ParseValue(arg.Value) } return argMap } func CallFunction(call *FuncCall) (interface{}, error) { argMap := UnwrapArgs(call.Args) return Funcs[call.Name](argMap) } func displayDialog(args map[string]interface{}) (interface{}, error) { title, ok := args["title"] if !ok { return nil, errors.New("title not provided") } text, ok := args["text"] if !ok { return nil, errors.New("text not provided") } switch args["type"] { case "yesno": return dlgs.Question(fmt.Sprint(title), fmt.Sprint(text), true) case "info": return dlgs.Info(fmt.Sprint(title), fmt.Sprint(text)) case "error": return dlgs.Error(fmt.Sprint(title), fmt.Sprint(text)) case "entry": defaultText, ok := args["default"] if !ok { defaultText = "" } input, _, err := dlgs.Entry(fmt.Sprint(title), fmt.Sprint(text), fmt.Sprint(defaultText)) return input, err } return nil, nil } func doShellScript(args map[string]interface{}) (interface{}, error) { script, ok := args["content"].(string) if ok { cmd := exec.Command("sh", "-c", script) cmd.Stdout = os.Stdout _ = cmd.Run() return "", nil } else { return nil, errors.New("script not provided") } }