Modify existing yaml file and add new data and comments

后端 未结 2 1700
借酒劲吻你
借酒劲吻你 2021-02-05 14:38

I recently saw that the go yaml lib has new version (V3)

with the nodes capabilities (which in my opinion is a killer feature :) ) which can helps a lots with modifying

2条回答
  •  野性不改
    2021-02-05 15:30

    You could create a new node and directly append to the contents, without deleting the previous node. The following example illustrates this point:

    package main
    
    import (
        "fmt"
        "log"
    
        "gopkg.in/yaml.v3"
    )
    
    var (
        sourceYaml = `version: 1
    type: verbose
    kind : bfr
    
    # my list of applications
    applications:
    
    #  First app
      - name: app1
        kind: nodejs
        path: app1
        exec:
          platforms: k8s
          builder: test
    `
    )
    
    type Application struct {
        Name string `yaml:"name,omitempty" json:"name,omitempty"`
        Kind string `yaml:"kind,omitempty" json:"kind,omitempty"`
        Path string `yaml:"path,omitempty" json:"path,omitempty"`
        Exec struct {
            Platforms string `yaml:"platforms,omitempty" json:"platforms,omitempty"`
            Builder   string `yaml:"builder,omitempty" json:"builder,omitempty"`
        } `yaml:"exec,omitempty" json:"exec,omitempty"`
    }
    
    func newApplicationNode(
        name string,
        kind string,
        path string,
        platforms string,
        builder string,
        comment string) (*yaml.Node, error) {
    
        app := Application{
            Name: name,
            Kind: kind,
            Path: path,
            Exec: struct {
                Platforms string `yaml:"platforms,omitempty" json:"platforms,omitempty"`
                Builder   string `yaml:"builder,omitempty" json:"builder,omitempty"`
            }{platforms, builder},
        }
        marshalledApp, err := yaml.Marshal(&app)
        if err != nil {
            return nil, err
        }
    
        node := yaml.Node{}
        if err := yaml.Unmarshal(marshalledApp, &node); err != nil {
            return nil, err
        }
        node.Content[0].HeadComment = comment
        return &node, nil
    }
    
    func main() {
        yamlNode := yaml.Node{}
    
        err := yaml.Unmarshal([]byte(sourceYaml), &yamlNode)
        if err != nil {
            log.Fatalf("error: %v", err)
        }
    
        newApp, err := newApplicationNode("app2", "golang", "app2", "dockerh",
            "test", "Second app")
        if err != nil {
            log.Fatalf("error: %v", err)
        }
    
        appIdx := -1
        for i, k := range yamlNode.Content[0].Content {
            if k.Value == "applications" {
                appIdx = i + 1
                break
            }
        }
    
        yamlNode.Content[0].Content[appIdx].Content = append(
            yamlNode.Content[0].Content[appIdx].Content, newApp.Content[0])
    
        out, err := yaml.Marshal(&yamlNode)
        if err != nil {
            log.Fatal(err)
        }
        fmt.Println(string(out))
    }
    
    

    Clearly instead of going the hacky way as I did in newApplicationNode you can unmarshal properly from your JSON. However, as stated in previous answers, it is important to notice that the key and actual value are in subsequent indexes inside Content, therefore you need to take this into account when modifying the document. (e.g., look up applications key but then consider the next index (appIdx = i + 1 in my example) for its contents.

    Hope that helps!

提交回复
热议问题