feat(platform): add textblock helper for idempotent config-file blocks
This commit is contained in:
78
internal/platform/textblock.go
Normal file
78
internal/platform/textblock.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package platform
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func blockMarkers(marker string) (string, string) {
|
||||
return fmt.Sprintf("# >>> %s >>>", marker), fmt.Sprintf("# <<< %s <<<", marker)
|
||||
}
|
||||
|
||||
// EnsureBlock writes a marker-delimited block into path. If the file does
|
||||
// not exist it is created. If a block with the same marker already exists
|
||||
// it is replaced in place. Surrounding content is preserved.
|
||||
func EnsureBlock(path, marker, content string) error {
|
||||
start, end := blockMarkers(marker)
|
||||
existing, err := os.ReadFile(path)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
block := start + "\n" + strings.TrimRight(content, "\n") + "\n" + end + "\n"
|
||||
|
||||
text := string(existing)
|
||||
si := strings.Index(text, start)
|
||||
ei := strings.Index(text, end)
|
||||
if si >= 0 && ei > si {
|
||||
endPos := ei + len(end)
|
||||
if endPos < len(text) && text[endPos] == '\n' {
|
||||
endPos++
|
||||
}
|
||||
text = text[:si] + block + text[endPos:]
|
||||
} else {
|
||||
if text != "" && !strings.HasSuffix(text, "\n") {
|
||||
text += "\n"
|
||||
}
|
||||
text += block
|
||||
}
|
||||
return os.WriteFile(path, []byte(text), 0o644)
|
||||
}
|
||||
|
||||
// HasBlock reports whether path contains a block with the given marker.
|
||||
// A missing file yields (false, nil).
|
||||
func HasBlock(path, marker string) (bool, error) {
|
||||
start, _ := blockMarkers(marker)
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
return strings.Contains(string(data), start), nil
|
||||
}
|
||||
|
||||
// RemoveBlock deletes a marker-delimited block if present.
|
||||
func RemoveBlock(path, marker string) error {
|
||||
start, end := blockMarkers(marker)
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
text := string(data)
|
||||
si := strings.Index(text, start)
|
||||
ei := strings.Index(text, end)
|
||||
if si < 0 || ei <= si {
|
||||
return nil
|
||||
}
|
||||
endPos := ei + len(end)
|
||||
if endPos < len(text) && text[endPos] == '\n' {
|
||||
endPos++
|
||||
}
|
||||
text = text[:si] + text[endPos:]
|
||||
return os.WriteFile(path, []byte(text), 0o644)
|
||||
}
|
||||
Reference in New Issue
Block a user