@@ -35,7 +35,7 @@ func UpdateYamlValue(yamlBytes []byte, path []string, value string) ([]byte, err
3535 }
3636
3737 // Convert the updated YAML node back to YAML bytes.
38- updatedYAMLBytes , err := yamlMarshal (body )
38+ updatedYAMLBytes , err := YamlMarshal (body )
3939 if err != nil {
4040 return nil , fmt .Errorf ("failed to convert YAML node to bytes: %w" , err )
4141 }
@@ -100,147 +100,101 @@ func lookupKey(node *yaml.Node, key string) (*yaml.Node, *yaml.Node) {
100100 return nil , nil
101101}
102102
103- // Walks a yaml document to the specified path, and then applies the transformation to that node.
104- //
105- // The transform must return true if it made changes to the node.
103+ // Walks a yaml document from the root node to the specified path, and then applies the transformation to that node.
106104// If the requested path is not defined in the document, no changes are made to the document.
107- //
108- // If no changes are made, the original document is returned.
109- // If changes are made, a newly marshalled document is returned. (This may result in different indentation for all nodes)
110- func TransformNode (yamlBytes []byte , path []string , transform func (node * yaml.Node ) (bool , error )) ([]byte , error ) {
111- // Parse the YAML file.
112- var node yaml.Node
113- err := yaml .Unmarshal (yamlBytes , & node )
114- if err != nil {
115- return nil , fmt .Errorf ("failed to parse YAML: %w" , err )
116- }
117-
105+ func TransformNode (rootNode * yaml.Node , path []string , transform func (node * yaml.Node ) error ) error {
118106 // Empty document: nothing to do.
119- if len (node .Content ) == 0 {
120- return yamlBytes , nil
107+ if len (rootNode .Content ) == 0 {
108+ return nil
121109 }
122110
123- body := node .Content [0 ]
124-
125- if didTransform , err := transformNode (body , path , transform ); err != nil || ! didTransform {
126- return yamlBytes , err
127- }
111+ body := rootNode .Content [0 ]
128112
129- // Convert the updated YAML node back to YAML bytes.
130- updatedYAMLBytes , err := yamlMarshal (body )
131- if err != nil {
132- return nil , fmt .Errorf ("failed to convert YAML node to bytes: %w" , err )
113+ if err := transformNode (body , path , transform ); err != nil {
114+ return err
133115 }
134116
135- return updatedYAMLBytes , nil
117+ return nil
136118}
137119
138120// A recursive function to walk down the tree. See TransformNode for more details.
139- func transformNode (node * yaml.Node , path []string , transform func (node * yaml.Node ) ( bool , error )) ( bool , error ) {
121+ func transformNode (node * yaml.Node , path []string , transform func (node * yaml.Node ) error ) error {
140122 if len (path ) == 0 {
141123 return transform (node )
142124 }
143125
144126 keyNode , valueNode := lookupKey (node , path [0 ])
145127 if keyNode == nil {
146- return false , nil
128+ return nil
147129 }
148130
149131 return transformNode (valueNode , path [1 :], transform )
150132}
151133
152- // takes a yaml document in bytes , a path to a key, and a new name for the key.
134+ // Takes the root node of a yaml document, a path to a key, and a new name for the key.
153135// Will rename the key to the new name if it exists, and do nothing otherwise.
154- func RenameYamlKey (yamlBytes []byte , path []string , newKey string ) ([]byte , error ) {
155- // Parse the YAML file.
156- var node yaml.Node
157- err := yaml .Unmarshal (yamlBytes , & node )
158- if err != nil {
159- return nil , fmt .Errorf ("failed to parse YAML: %w for bytes %s" , err , string (yamlBytes ))
160- }
161-
136+ func RenameYamlKey (rootNode * yaml.Node , path []string , newKey string ) error {
162137 // Empty document: nothing to do.
163- if len (node .Content ) == 0 {
164- return yamlBytes , nil
138+ if len (rootNode .Content ) == 0 {
139+ return nil
165140 }
166141
167- body := node .Content [0 ]
142+ body := rootNode .Content [0 ]
168143
169- if didRename , err := renameYamlKey (body , path , newKey ); err != nil || ! didRename {
170- return yamlBytes , err
144+ if err := renameYamlKey (body , path , newKey ); err != nil {
145+ return err
171146 }
172147
173- // Convert the updated YAML node back to YAML bytes.
174- updatedYAMLBytes , err := yamlMarshal (body )
175- if err != nil {
176- return nil , fmt .Errorf ("failed to convert YAML node to bytes: %w" , err )
177- }
178-
179- return updatedYAMLBytes , nil
148+ return nil
180149}
181150
182151// Recursive function to rename the YAML key.
183- func renameYamlKey (node * yaml.Node , path []string , newKey string ) ( bool , error ) {
152+ func renameYamlKey (node * yaml.Node , path []string , newKey string ) error {
184153 if node .Kind != yaml .MappingNode {
185- return false , errors .New ("yaml node in path is not a dictionary" )
154+ return errors .New ("yaml node in path is not a dictionary" )
186155 }
187156
188157 keyNode , valueNode := lookupKey (node , path [0 ])
189158 if keyNode == nil {
190- return false , nil
159+ return nil
191160 }
192161
193162 // end of path reached: rename key
194163 if len (path ) == 1 {
195164 // Check that new key doesn't exist yet
196165 if newKeyNode , _ := lookupKey (node , newKey ); newKeyNode != nil {
197- return false , fmt .Errorf ("new key `%s' already exists" , newKey )
166+ return fmt .Errorf ("new key `%s' already exists" , newKey )
198167 }
199168
200169 keyNode .Value = newKey
201- return true , nil
170+ return nil
202171 }
203172
204173 return renameYamlKey (valueNode , path [1 :], newKey )
205174}
206175
207176// Traverses a yaml document, calling the callback function for each node. The
208- // callback is allowed to modify the node in place, in which case it should
209- // return true. The function returns the original yaml document if none of the
210- // callbacks returned true, and the modified document otherwise.
211- func Walk (yamlBytes []byte , callback func (node * yaml.Node , path string ) bool ) ([]byte , error ) {
212- // Parse the YAML file.
213- var node yaml.Node
214- err := yaml .Unmarshal (yamlBytes , & node )
215- if err != nil {
216- return nil , fmt .Errorf ("failed to parse YAML: %w" , err )
217- }
218-
177+ // callback is expected to modify the node in place
178+ func Walk (rootNode * yaml.Node , callback func (node * yaml.Node , path string )) error {
219179 // Empty document: nothing to do.
220- if len (node .Content ) == 0 {
221- return yamlBytes , nil
180+ if len (rootNode .Content ) == 0 {
181+ return nil
222182 }
223183
224- body := node .Content [0 ]
225-
226- if didChange , err := walk (body , "" , callback ); err != nil || ! didChange {
227- return yamlBytes , err
228- }
184+ body := rootNode .Content [0 ]
229185
230- // Convert the updated YAML node back to YAML bytes.
231- updatedYAMLBytes , err := yamlMarshal (body )
232- if err != nil {
233- return nil , fmt .Errorf ("failed to convert YAML node to bytes: %w" , err )
186+ if err := walk (body , "" , callback ); err != nil {
187+ return err
234188 }
235189
236- return updatedYAMLBytes , nil
190+ return nil
237191}
238192
239- func walk (node * yaml.Node , path string , callback func (* yaml.Node , string ) bool ) ( bool , error ) {
240- didChange := callback (node , path )
193+ func walk (node * yaml.Node , path string , callback func (* yaml.Node , string )) error {
194+ callback (node , path )
241195 switch node .Kind {
242196 case yaml .DocumentNode :
243- return false , errors .New ("Unexpected document node in the middle of a yaml tree" )
197+ return errors .New ("Unexpected document node in the middle of a yaml tree" )
244198 case yaml .MappingNode :
245199 for i := 0 ; i < len (node .Content ); i += 2 {
246200 name := node .Content [i ].Value
@@ -251,31 +205,29 @@ func walk(node *yaml.Node, path string, callback func(*yaml.Node, string) bool)
251205 } else {
252206 childPath = fmt .Sprintf ("%s.%s" , path , name )
253207 }
254- didChangeChild , err := walk (childNode , childPath , callback )
208+ err := walk (childNode , childPath , callback )
255209 if err != nil {
256- return false , err
210+ return err
257211 }
258- didChange = didChange || didChangeChild
259212 }
260213 case yaml .SequenceNode :
261214 for i := 0 ; i < len (node .Content ); i ++ {
262215 childPath := fmt .Sprintf ("%s[%d]" , path , i )
263- didChangeChild , err := walk (node .Content [i ], childPath , callback )
216+ err := walk (node .Content [i ], childPath , callback )
264217 if err != nil {
265- return false , err
218+ return err
266219 }
267- didChange = didChange || didChangeChild
268220 }
269221 case yaml .ScalarNode :
270222 // nothing to do
271223 case yaml .AliasNode :
272- return false , errors .New ("Alias nodes are not supported" )
224+ return errors .New ("Alias nodes are not supported" )
273225 }
274226
275- return didChange , nil
227+ return nil
276228}
277229
278- func yamlMarshal (node * yaml.Node ) ([]byte , error ) {
230+ func YamlMarshal (node * yaml.Node ) ([]byte , error ) {
279231 var buffer bytes.Buffer
280232 encoder := yaml .NewEncoder (& buffer )
281233 encoder .SetIndent (2 )
0 commit comments