Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Golang template with switch & ForEach

Tags:

templates

go

I need to create bash.sh file from golang program which should do the following:

Create ForEach loop on dependencies and read the type and according to type print different echo message (commands) I need it to work with switch on the type of the dependency with Golang

e.g. something like following

For each dependency entry add the type message of echo

#!/bin/bash
for a in $(dependencies.type) 
  echo $runner  //from type 
done

what I did is the following which doesn't work

  1. The idea that for dependencies type "runner1"(see the type property value in dependency struct instance) I need to run several commands and for "runner2" I need to run several different commands
  2. And those commands (like echo api1 for runner1 etc )above should be written in the bash.script that I need to create from the template

package main

import (
    "fmt"
    "log"
    "text/template"
    "gopkg.in/yaml.v2"
    "os"
)

type File struct {
    TypeVersion string `yaml:"_type-version"`
    Dependency  []Dependency
}

type Dependency struct {
    Name    string
    Type    string
    CWD     string
    Install []Install
}

type Install map[string]string

var data = `
_type-version: "1.0.0"
dependency:
  - name: ui
    type: runner
    cwd: /ui
    install:
       - name: api

  - name: ui2
    type: runner2
    cwd: /ui2
    install:
       - name: api2

`

func main() {
    f := File{}

    err := yaml.Unmarshal([]byte(data), &f)
    if err != nil {
        log.Fatalf("error: %v", err)
    }

    d, err := yaml.Marshal(&f)
    if err != nil {
        log.Fatalf("error: %v", err)
    }
    fmt.Printf("--- t dump:\n%s\n\n", string(d))

    wd, _ := os.Getwd()

    newfile, err := os.Create(wd + "/" + "bash.sh") // Truncates if file already exists
    if err != nil {
        fmt.Errorf("Failed to create file: %s , %s", wd+"/"+"bash.sh", err)
    }

    fmt.Println(newfile)

    const File = `
#!/bin/bash
{{.dependency}},
{{if .Type runner2}}
 echo "type is runner2"
{{- else}}
echo "type is %S"
{{- end}}
{{end}}
`

    t := template.Must(template.New("bash.sh").Parse(File))

    for _, r := range f.Dependency {
        err := t.Execute(os.Stdout, r)
        if err != nil {
            log.Println("executing template:", err)
        }
    }

}

update

For example

lets say i’ve map like following and the dependencies struct should work with the API struct to know which command to run for each type value

API := map[string]string {
{
“runner1” : “api1”,
},
{
“runner2” : “api2”,
}
}

This is how should the script look like at the end

#bin/bash

// in context of dep1
echo runner1
submitting api1


// in context of dep2
echo runner2
submitting api2
like image 552
Jenny Hilton Avatar asked Oct 01 '17 10:10

Jenny Hilton


1 Answers

Some minimal changes to get to working for the above are here:

package main

import (
    "log"
    "text/template"
    "gopkg.in/yaml.v2"
    "os"
)

type File struct {
    TypeVersion string `yaml:"_type-version"`
    Dependency  []Dependency
}

type Dependency struct {
    Name    string
    Type    string
    CWD     string
    Install []Install
}

type Install map[string]string

var data = `
_type-version: "1.0.0"
dependency:
  - name: ui
    type: runner
    cwd: /ui
    install:
       - name: api

  - name: ui2
    type: runner2
    cwd: /ui2
    install:
       - name: api2

`

func main() {
    f := File{}

    err := yaml.Unmarshal([]byte(data), &f)
    if err != nil {
        log.Fatalf("error: %v", err)
    }

   const t = `
#!/bin/bash

{{range .Dependency}}
echo "type is {{.Type}}"
echo "cwd is {{.CWD}}"
{{range .Install}}
echo "install {{.name}}"
{{end}}
{{end}}
`

    tt := template.Must(template.New("").Parse(t))
    err = tt.Execute(os.Stdout, f)
    if err != nil {
        log.Println("executing template:", err)
    }
}

This produces

$ go run main.go 

#!/bin/bash


echo "type is runner"
echo "cwd is /ui"

echo "install api"


echo "type is runner2"
echo "cwd is /ui2"

echo "install api2"

The key change is to let the template do the work- use the range function on the Dependency array, and then again on the Install array, to traverse the data structure.

The other change is just to write to stdout, rather than to a file. If it is desirable to turn this into a script, just pipe it to a file.

More broadly, I think there is a tension in the data model around ownership of the install steps. Are the install steps fixed for each runner type? Or may they vary? If they are fixed, then having a map[string][string] of runner type to array of install steps probably makes sense, which would then relieve the Dependency object of having a copy of install steps.

I also wonder about the YAML- is it a source of truth? Or is it derivative? If derivative, perhaps it is unnecessary. Probably better to have the go program interrogate the actual source of truth and generate a script.

In any event, I hope that's helpful.

like image 119
Jonah Benton Avatar answered Sep 29 '22 11:09

Jonah Benton