github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/pkg/projectfile/yamlfield.go (about)

     1  package projectfile
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"os"
     7  	"regexp"
     8  
     9  	"github.com/ActiveState/cli/internal/errs"
    10  	"gopkg.in/yaml.v2"
    11  )
    12  
    13  type yamlField struct {
    14  	field string
    15  	value interface{}
    16  }
    17  
    18  func NewYamlField(field string, value interface{}) *yamlField {
    19  	return &yamlField{field: field, value: value}
    20  }
    21  
    22  func (y *yamlField) update(data []byte) ([]byte, error) {
    23  	lineSep := []byte("\n")
    24  	if bytes.Contains(data, []byte("\r\n")) {
    25  		lineSep = []byte("\r\n")
    26  	}
    27  
    28  	var re = regexp.MustCompile(fmt.Sprintf(`(?m:^%s:\s+?(.*?)$)`, regexp.QuoteMeta(y.field)))
    29  	addLine, err := yaml.Marshal(map[string]interface{}{y.field: y.value})
    30  	if err != nil {
    31  		return []byte{}, errs.Wrap(err, "Could not marshal yaml")
    32  	}
    33  
    34  	addLine = bytes.TrimRight(addLine, string(lineSep))
    35  
    36  	out := re.ReplaceAll(data, addLine)
    37  	if !bytes.Contains(out, addLine) {
    38  		// Nothing to replace; append to the end of the file instead
    39  		addLine = append(lineSep, addLine...) // Prepend line ending
    40  		addLine = append(addLine, lineSep...) // Append line ending
    41  		out = append(bytes.TrimRight(out, string(lineSep)), addLine...)
    42  	}
    43  
    44  	return out, nil
    45  }
    46  
    47  func (y *yamlField) Save(path string) error {
    48  	data, err := os.ReadFile(path)
    49  	if err != nil {
    50  		return errs.Wrap(err, "ioutil.ReadFile %s failed", path)
    51  	}
    52  
    53  	out, err := y.update(data)
    54  	if err != nil {
    55  		return errs.Wrap(err, "Update failed")
    56  	}
    57  
    58  	if err := os.WriteFile(path, out, 0664); err != nil {
    59  		return errs.Wrap(err, "ioutil.WriteFile %s failed", path)
    60  	}
    61  
    62  	return nil
    63  }