Sunday, April 22, 2018

Golang template with switch & ForEach

Leave a Comment

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 

1 Answers

Answers 1

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.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment