Skip to content

Instantly share code, notes, and snippets.

@weakpixel
Created April 2, 2022 13:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save weakpixel/c92f8427b6197a501c1a8d0595e5b5db to your computer and use it in GitHub Desktop.
Save weakpixel/c92f8427b6197a501c1a8d0595e5b5db to your computer and use it in GitHub Desktop.
package main
import (
"fmt"
"os"
"strings"
"github.com/spf13/cobra"
"github.com/zclconf/go-cty/cty"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/gohcl"
"github.com/hashicorp/hcl/v2/hclsimple"
)
var (
exampleHCL = `
task "first_task" {
step "mkdir" "build_dir" {
path = var.buildDir
}
step "exec" "list_build_dir" {
command = "ls ${var.buildDir}"
}
}
`
)
func main() {
root := cobra.Command{
Use: "taskexec",
}
root.AddCommand(newRunCommand())
err := root.Execute()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}
func newRunCommand() *cobra.Command {
vars := []string{}
cmd := cobra.Command{
Use: "run",
Short: "Executes tasks",
RunE: func(cmd *cobra.Command, args []string) error {
ctx, err := newEvalContext(vars)
if err != nil {
return err
}
config := &Config{}
err = hclsimple.Decode("example.hcl", []byte(exampleHCL), ctx, config)
if err != nil {
return err
}
for _, task := range config.Tasks {
fmt.Printf("Task: %s\n", task.Name)
for _, step := range task.Steps {
fmt.Printf(" Step: %s %s\n", step.Type, step.Name)
var runner Runner
switch step.Type {
case "mkdir":
runner = &MkdirStep{}
case "exec":
runner = &ExecStep{}
default:
return fmt.Errorf("unknown step type %q", step.Type)
}
diags := gohcl.DecodeBody(step.Remain, ctx, runner)
if diags.HasErrors() {
return diags
}
err = runner.Run()
if err != nil {
return err
}
}
}
return nil
},
}
cmd.Flags().StringArrayVar(&vars, "var", nil, "Sets variable. Format <name>=<value>")
return &cmd
}
func newEvalContext(vars []string) (*hcl.EvalContext, error) {
varMap := map[string]cty.Value{}
for _, v := range vars {
el := strings.Split(v, "=")
if len(el) != 2 {
return nil, fmt.Errorf("invalid format: %s", v)
}
varMap[el[0]] = cty.StringVal(el[1])
}
ctx := &hcl.EvalContext{}
ctx.Variables = map[string]cty.Value{
"var": cty.ObjectVal(varMap),
}
return ctx, nil
}
type Config struct {
Tasks []*Task `hcl:"task,block"`
}
type Task struct {
Name string `hcl:"name,label"`
Steps []*Step `hcl:"step,block"`
}
type Step struct {
Type string `hcl:"type,label"`
Name string `hcl:"name,label"`
Remain hcl.Body `hcl:",remain"`
}
type ExecStep struct {
Command string `hcl:"command"`
}
func (s *ExecStep) Run() error {
return nil
}
type MkdirStep struct {
Path string `hcl:"path"`
}
func (s *MkdirStep) Run() error {
return nil
}
type Runner interface {
Run() error
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment