aboutsummaryrefslogtreecommitdiffstats
path: root/plumbing/format/config/encoder.go
blob: de069aed5e78764ce1ebcdf4c522c2afb1a50618 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
package config

import (
	"fmt"
	"io"
	"strings"
)

// An Encoder writes config files to an output stream.
type Encoder struct {
	w io.Writer
}

var (
	subsectionReplacer = strings.NewReplacer(`"`, `\"`, `\`, `\\`)
	valueReplacer = strings.NewReplacer(`"`, `\"`, `\`, `\\`, "\n", `\n`, "\t", `\t`, "\b", `\b`)
)
// NewEncoder returns a new encoder that writes to w.
func NewEncoder(w io.Writer) *Encoder {
	return &Encoder{w}
}

// Encode writes the config in git config format to the stream of the encoder.
func (e *Encoder) Encode(cfg *Config) error {
	for _, s := range cfg.Sections {
		if err := e.encodeSection(s); err != nil {
			return err
		}
	}

	return nil
}

func (e *Encoder) encodeSection(s *Section) error {
	if len(s.Options) > 0 {
		if err := e.printf("[%s]\n", s.Name); err != nil {
			return err
		}

		if err := e.encodeOptions(s.Options); err != nil {
			return err
		}
	}

	for _, ss := range s.Subsections {
		if err := e.encodeSubsection(s.Name, ss); err != nil {
			return err
		}
	}

	return nil
}

func (e *Encoder) encodeSubsection(sectionName string, s *Subsection) error {
	if err := e.printf("[%s \"%s\"]\n", sectionName, subsectionReplacer.Replace(s.Name)); err != nil {
		return err
	}

	return e.encodeOptions(s.Options)
}

func (e *Encoder) encodeOptions(opts Options) error {
	for _, o := range opts {
		var value string
		if strings.ContainsAny(o.Value, "#;\"\t\n\\") || strings.HasPrefix(o.Value, " ") || strings.HasSuffix(o.Value, " ") {
			value = `"`+valueReplacer.Replace(o.Value)+`"`
		} else {
			value = o.Value
		}

		if err := e.printf("\t%s = %s\n", o.Key, value); err != nil {
			return err
		}
	}

	return nil
}

func (e *Encoder) printf(msg string, args ...interface{}) error {
	_, err := fmt.Fprintf(e.w, msg, args...)
	return err
}