Saltar al contenido

Modifique el archivo yaml existente y agregue nuevos datos y comentarios

Luego de mucho batallar hemos dado con el arreglo de este atasco que muchos de nuestros usuarios de esta web presentan. Si deseas aportar algún detalle no dejes de aportar tu conocimiento.

Solución:

Primero, déjeme comenzar diciendo que usar yaml.Node no produce un yaml válido cuando se calcula a partir de un yaml válido, dado por el siguiente ejemplo. Probablemente debería presentar un problema.

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
`
)

func main() 
    t := yaml.Node

    err := yaml.Unmarshal([]byte(sourceYaml), &t)
    if err != nil 
        log.Fatalf("error: %v", err)
    

    b, err := yaml.Marshal(&t)
    if err != nil 
        log.Fatal(err)
    
    fmt.Println(string(b))

Produce el siguiente yaml no válido en la versión go1.12.3 windows / amd64

version: 1
type: verbose
kind: bfr


# my list of applications
applications:
-   #  First app
name: app1
    kind: nodejs
    path: app1
    exec:
        platforms: k8s
        builder: test

En segundo lugar, usando una estructura como

type VTS struct 
    Version string       `yaml:"version" json:"version"`
    Types   string       `yaml:"type" json:"type"`
    Kind    string       `yaml:"kind,omitempty" json:"kind,omitempty"`
    Apps    yaml.Node `yaml:"applications,omitempty" json:"applications,omitempty"`

Desde el blog de ubuntu y la documentación de origen, parecía que identificaría correctamente los campos dentro de la estructura que son nodos y construiría ese árbol por separado, pero ese no es el caso. Cuando no se ordena, dará un árbol de nodos correcto, pero cuando se vuelve a ordenar, producirá el siguiente yaml con todos los campos que expone yaml.Node. Lamentablemente no podemos seguir este camino, debemos encontrar otro camino.

version: "1"
type: verbose
kind: bfr
applications:
    kind: 2
    style: 0
    tag: '!!seq'
    value: ""
    anchor: ""
    alias: null
    content:
    -   #  First app
name: app1
        kind: nodejs
        path: app1
        exec:
            platforms: k8s
            builder: test
    headcomment: ""
    linecomment: ""
    footcomment: ""
    line: 9
    column: 3

Pasando por alto el primer problema y el error marshal para yaml.Nodes en una estructura (en gopkg.in/yaml.v3 v3.0.0-20190409140830-cdc409dda467) ahora podemos manipular los nodos que expone el paquete. Desafortunadamente, no existe una abstracción que agregue nodos con facilidad, por lo que los usos pueden variar y la identificación de nodos puede ser una molestia. La reflexión podría ayudar un poco aquí, así que lo dejo como ejercicio para ti.

Encontrará comentarios arrojados. Volcados que descargan todo el árbol de nodos en un formato agradable, esto ayudó con la depuración al agregar nodos al árbol de origen.

Ciertamente, también puede eliminar nodos, solo tendrá que identificar qué nodos particulares deben eliminarse. Solo debe asegurarse de eliminar los nodos principales si fuera un mapa o una secuencia.

package main

import (
    "encoding/json"
    "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
`
    modifyJsonSource = `
[

    
        "comment": "Second app",
        "name": "app2",
        "kind": "golang",
        "path": "app2",
        "exec": 
            "platforms": "dockerh",
            "builder": "test"
        
    
]
`
)

// VTS Need to Make Fields Public otherwise unmarshalling will not fill in the unexported fields.
type VTS struct 
    Version string       `yaml:"version" json:"version"`
    Types   string       `yaml:"type" json:"type"`
    Kind    string       `yaml:"kind,omitempty" json:"kind,omitempty"`
    Apps    Applications `yaml:"applications,omitempty" json:"applications,omitempty"`


type Applications []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"`
    Comment string `yaml:"comment,omitempty" json:"comment,omitempty"`


func main() 
    t := yaml.Node

    err := yaml.Unmarshal([]byte(sourceYaml), &t)
    if err != nil 
        log.Fatalf("error: %v", err)
    

    // Look for the Map Node with the seq array of items
    applicationNode := iterateNode(&t, "applications")

    // spew.Dump(iterateNode(&t, "applications"))

    var addFromJson Applications
    err = json.Unmarshal([]byte(modifyJsonSource), &addFromJson)
    if err != nil 
        log.Fatalf("error: %v", err)
    

    // Delete the Original Applications the following options:
    // applicationNode.Content = []*yaml.Node
    // deleteAllContents(applicationNode)
    deleteApplication(applicationNode, "name", "app1")


    for _, app := range addFromJson 
        // Build New Map Node for new sequences coming in from json
        mapNode := &yaml.NodeKind: yaml.MappingNode, Tag: "!!map"

        // Build Name, Kind, and Path Nodes
        mapNode.Content = append(mapNode.Content, buildStringNodes("name", app.Name, app.Comment)...)
        mapNode.Content = append(mapNode.Content, buildStringNodes("kind", app.Kind, "")...)
        mapNode.Content = append(mapNode.Content, buildStringNodes("path", app.Path, "")...)

        // Build the Exec Nodes and the Platform and Builder Nodes within it
        keyMapNode, keyMapValuesNode := buildMapNodes("exec")
        keyMapValuesNode.Content = append(keyMapValuesNode.Content, buildStringNodes("platform", app.Exec.Platforms, "")...)
        keyMapValuesNode.Content = append(keyMapValuesNode.Content, buildStringNodes("builder", app.Exec.Builder, "")...)

        // Add to parent map Node
        mapNode.Content = append(mapNode.Content, keyMapNode, keyMapValuesNode)

        // Add to applications Node
        applicationNode.Content = append(applicationNode.Content, mapNode)
    
    // spew.Dump(t)
    b, err := yaml.Marshal(&t)
    if err != nil 
        log.Fatal(err)
    
    fmt.Println(string(b))


// iterateNode will recursive look for the node following the identifier Node,
// as go-yaml has a node for the key and the value itself
// we want to manipulate the value Node
func iterateNode(node *yaml.Node, identifier string) *yaml.Node 
    returnNode := false
    for _, n := range node.Content 
        if n.Value == identifier 
            returnNode = true
            continue
        
        if returnNode 
            return n
        
        if len(n.Content) > 0 
            ac_node := iterateNode(n, identifier)
            if ac_node != nil 
                return ac_node
            
        
    
    return nil


// deleteAllContents will remove all the contents of a node
// Mark sure to pass the correct node in otherwise bad things will happen
func deleteAllContents(node *yaml.Node) 
    node.Content = []*yaml.Node


// deleteApplication expects that a sequence Node with all the applications are present
// if the key value are not found it will not log any errors, and return silently
// this is expecting a map like structure for the applications
func deleteApplication(node *yaml.Node, key, value string) 
    state := -1
    indexRemove := -1
    for index, parentNode := range node.Content 
        for _, childNode := range parentNode.Content 
            if key == childNode.Value && state == -1 
                state += 1
                continue // found expected move onto next
            
            if value == childNode.Value && state == 0 
                state += 1
                indexRemove = index
                break // found the target exit out of the loop
             else if state == 0 
                state = -1
            
        
    
    if state == 1 
        // Remove node from contents
        // node.Content = append(node.Content[:indexRemove], node.Content[indexRemove+1:]...)
        // Don't Do this you might have a potential memory leak source: https://github.com/golang/go/wiki/SliceTricks
        // Since the underlying nodes are pointers
        length := len(node.Content)
        copy(node.Content[indexRemove:], node.Content[indexRemove+1:])
        node.Content[length-1] = nil
        node.Content = node.Content[:length-1]
    



// buildStringNodes builds Nodes for a single key: value instance
func buildStringNodes(key, value, comment string) []*yaml.Node 
    keyNode := &yaml.Node
        Kind:        yaml.ScalarNode,
        Tag:         "!!str",
        Value:       key,
        HeadComment: comment,
    
    valueNode := &yaml.Node
        Kind:  yaml.ScalarNode,
        Tag:   "!!str",
        Value: value,
    
    return []*yaml.NodekeyNode, valueNode


// buildMapNodes builds Nodes for a key: map instance
func buildMapNodes(key string) (*yaml.Node, *yaml.Node) 
    n1, n2 := &yaml.Node
        Kind:  yaml.ScalarNode,
        Tag:   "!!str",
        Value: key,
    , &yaml.NodeKind: yaml.MappingNode,
        Tag: "!!map",
    
    return n1, n2


Produce yaml

version: 1
type: verbose
kind: bfr


# my list of applications
applications:
-   #  First app
name: app1
    kind: nodejs
    path: app1
    exec:
        platforms: k8s
        builder: test
-   # Second app
name: app2
    kind: golang
    path: app2
    exec:
        platform: dockerh
        builder: test

Te invitamos a confirmar nuestro quehacer mostrando un comentario y dejando una valoración te damos la bienvenida.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *