From dc804e96fb9bb20658a9609b8903f43bc8a803bb Mon Sep 17 00:00:00 2001 From: Luis Pater Date: Tue, 11 Nov 2025 08:37:57 +0800 Subject: [PATCH] fix(management): improve error handling and normalize YAML comment indentation Enhance error management for file operations and clean up temporary files. Add `NormalizeCommentIndentation` function to ensure YAML comments maintain consistent formatting. --- .../api/handlers/management/config_basic.go | 35 ++++++++------- internal/config/config.go | 43 +++++++++++++++++-- 2 files changed, 58 insertions(+), 20 deletions(-) diff --git a/internal/api/handlers/management/config_basic.go b/internal/api/handlers/management/config_basic.go index 3bbfd39a..e6b18ea7 100644 --- a/internal/api/handlers/management/config_basic.go +++ b/internal/api/handlers/management/config_basic.go @@ -28,7 +28,7 @@ func (h *Handler) GetConfigYAML(c *gin.Context) { return } var node yaml.Node - if err := yaml.Unmarshal(data, &node); err != nil { + if err = yaml.Unmarshal(data, &node); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "parse_failed", "message": err.Error()}) return } @@ -41,17 +41,18 @@ func (h *Handler) GetConfigYAML(c *gin.Context) { } func WriteConfig(path string, data []byte) error { + data = config.NormalizeCommentIndentation(data) f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) if err != nil { return err } - if _, err := f.Write(data); err != nil { - f.Close() - return err + if _, errWrite := f.Write(data); errWrite != nil { + _ = f.Close() + return errWrite } - if err := f.Sync(); err != nil { - f.Close() - return err + if errSync := f.Sync(); errSync != nil { + _ = f.Close() + return errSync } return f.Close() } @@ -63,7 +64,7 @@ func (h *Handler) PutConfigYAML(c *gin.Context) { return } var cfg config.Config - if err := yaml.Unmarshal(body, &cfg); err != nil { + if err = yaml.Unmarshal(body, &cfg); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid_yaml", "message": err.Error()}) return } @@ -75,18 +76,20 @@ func (h *Handler) PutConfigYAML(c *gin.Context) { return } tempFile := tmpFile.Name() - if _, err := tmpFile.Write(body); err != nil { - tmpFile.Close() - os.Remove(tempFile) - c.JSON(http.StatusInternalServerError, gin.H{"error": "write_failed", "message": err.Error()}) + if _, errWrite := tmpFile.Write(body); errWrite != nil { + _ = tmpFile.Close() + _ = os.Remove(tempFile) + c.JSON(http.StatusInternalServerError, gin.H{"error": "write_failed", "message": errWrite.Error()}) return } - if err := tmpFile.Close(); err != nil { - os.Remove(tempFile) - c.JSON(http.StatusInternalServerError, gin.H{"error": "write_failed", "message": err.Error()}) + if errClose := tmpFile.Close(); errClose != nil { + _ = os.Remove(tempFile) + c.JSON(http.StatusInternalServerError, gin.H{"error": "write_failed", "message": errClose.Error()}) return } - defer os.Remove(tempFile) + defer func() { + _ = os.Remove(tempFile) + }() _, err = config.LoadConfigOptional(tempFile, false) if err != nil { c.JSON(http.StatusUnprocessableEntity, gin.H{"error": "invalid_config", "message": err.Error()}) diff --git a/internal/config/config.go b/internal/config/config.go index cd2942d2..83426ee2 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -5,6 +5,7 @@ package config import ( + "bytes" "errors" "fmt" "os" @@ -462,13 +463,19 @@ func SaveConfigPreserveComments(configFile string, cfg *Config) error { return err } defer func() { _ = f.Close() }() - enc := yaml.NewEncoder(f) + var buf bytes.Buffer + enc := yaml.NewEncoder(&buf) enc.SetIndent(2) if err = enc.Encode(&original); err != nil { _ = enc.Close() return err } - return enc.Close() + if err = enc.Close(); err != nil { + return err + } + data = NormalizeCommentIndentation(buf.Bytes()) + _, err = f.Write(data) + return err } func sanitizeConfigForPersist(cfg *Config) *Config { @@ -518,13 +525,40 @@ func SaveConfigPreserveCommentsUpdateNestedScalar(configFile string, path []stri return err } defer func() { _ = f.Close() }() - enc := yaml.NewEncoder(f) + var buf bytes.Buffer + enc := yaml.NewEncoder(&buf) enc.SetIndent(2) if err = enc.Encode(&root); err != nil { _ = enc.Close() return err } - return enc.Close() + if err = enc.Close(); err != nil { + return err + } + data = NormalizeCommentIndentation(buf.Bytes()) + _, err = f.Write(data) + return err +} + +// NormalizeCommentIndentation removes indentation from standalone YAML comment lines to keep them left aligned. +func NormalizeCommentIndentation(data []byte) []byte { + lines := bytes.Split(data, []byte("\n")) + changed := false + for i, line := range lines { + trimmed := bytes.TrimLeft(line, " \t") + if len(trimmed) == 0 || trimmed[0] != '#' { + continue + } + if len(trimmed) == len(line) { + continue + } + lines[i] = append([]byte(nil), trimmed...) + changed = true + } + if !changed { + return data + } + return bytes.Join(lines, []byte("\n")) } // getOrCreateMapValue finds the value node for a given key in a mapping node. @@ -766,6 +800,7 @@ func matchSequenceElement(original []*yaml.Node, used []bool, target *yaml.Node) } } } + default: } // Fallback to structural equality to preserve nodes lacking explicit identifiers. for i := range original {