Initial commit.

This commit is contained in:
2025-10-11 17:06:14 +00:00
commit ec521c3c91
45 changed files with 9798 additions and 0 deletions

133
internal/tools/yq.go Normal file
View File

@@ -0,0 +1,133 @@
package tools
import (
"bytes"
"fmt"
"os/exec"
"strings"
)
// YQ provides a wrapper around the yq command-line tool
type YQ struct {
yqPath string
}
// NewYQ creates a new YQ wrapper
func NewYQ() *YQ {
// Find yq in PATH
path, err := exec.LookPath("yq")
if err != nil {
// Default to "yq" and let exec handle the error
path = "yq"
}
return &YQ{yqPath: path}
}
// Get retrieves a value from a YAML file using a yq expression
func (y *YQ) Get(filePath, expression string) (string, error) {
cmd := exec.Command(y.yqPath, expression, filePath)
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
return "", fmt.Errorf("yq get failed: %w, stderr: %s", err, stderr.String())
}
return strings.TrimSpace(stdout.String()), nil
}
// Set sets a value in a YAML file using a yq expression
func (y *YQ) Set(filePath, expression, value string) error {
// yq -i '.path = "value"' file.yaml
// Ensure expression starts with '.' for yq v4 syntax
if !strings.HasPrefix(expression, ".") {
expression = "." + expression
}
// Properly quote the value to handle special characters
quotedValue := fmt.Sprintf(`"%s"`, strings.ReplaceAll(value, `"`, `\"`))
setExpr := fmt.Sprintf("%s = %s", expression, quotedValue)
cmd := exec.Command(y.yqPath, "-i", setExpr, filePath)
var stderr bytes.Buffer
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
return fmt.Errorf("yq set failed: %w, stderr: %s", err, stderr.String())
}
return nil
}
// Merge merges two YAML files
func (y *YQ) Merge(file1, file2, outputFile string) error {
// yq eval-all '. as $item ireduce ({}; . * $item)' file1.yaml file2.yaml > output.yaml
cmd := exec.Command(y.yqPath, "eval-all", ". as $item ireduce ({}; . * $item)", file1, file2)
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
return fmt.Errorf("yq merge failed: %w, stderr: %s", err, stderr.String())
}
// Write output
return exec.Command("sh", "-c", fmt.Sprintf("echo '%s' > %s", stdout.String(), outputFile)).Run()
}
// Delete removes a key from a YAML file
func (y *YQ) Delete(filePath, expression string) error {
// yq -i 'del(.path)' file.yaml
delExpr := fmt.Sprintf("del(%s)", expression)
cmd := exec.Command(y.yqPath, "-i", delExpr, filePath)
var stderr bytes.Buffer
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
return fmt.Errorf("yq delete failed: %w, stderr: %s", err, stderr.String())
}
return nil
}
// Validate checks if a YAML file is valid
func (y *YQ) Validate(filePath string) error {
cmd := exec.Command(y.yqPath, "eval", ".", filePath)
var stderr bytes.Buffer
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
return fmt.Errorf("yaml validation failed: %w, stderr: %s", err, stderr.String())
}
return nil
}
// Exec executes an arbitrary yq expression on a file
func (y *YQ) Exec(args ...string) ([]byte, error) {
cmd := exec.Command(y.yqPath, args...)
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
return nil, fmt.Errorf("yq exec failed: %w, stderr: %s", err, stderr.String())
}
return stdout.Bytes(), nil
}
// CleanYQOutput removes trailing newlines and "null" values from yq output
func CleanYQOutput(output string) string {
output = strings.TrimSpace(output)
if output == "null" {
return ""
}
return output
}