From 9534e464f999685125956ed7eeba5b00dc46514a Mon Sep 17 00:00:00 2001 From: Mechiel Lukkien Date: Thu, 21 Sep 2023 08:59:10 +0200 Subject: [PATCH] add comment about the sconf config file format at the top of the config files hopefully this helps admins editing the file and prevent mistakes about config files. for issue #56 by kikoreis, thanks! --- config/config.go | 4 +-- config/doc.go | 10 +++++++ go.mod | 4 +-- go.sum | 8 ++--- vendor/github.com/mjl-/sconf/describe.go | 38 +++++++++++++++++++----- vendor/github.com/mjl-/sconf/parse.go | 6 ++-- vendor/github.com/mjl-/xfmt/xfmt.go | 16 ++++++---- vendor/modules.txt | 4 +-- 8 files changed, 65 insertions(+), 25 deletions(-) diff --git a/config/config.go b/config/config.go index 3c375b5..a8f40b4 100644 --- a/config/config.go +++ b/config/config.go @@ -34,7 +34,7 @@ func Port(port, fallback int) int { // Static is a parsed form of the mox.conf configuration file, before converting it // into a mox.Config after additional processing. type Static struct { - DataDir string `sconf-doc:"Directory where all data is stored, e.g. queue, accounts and messages, ACME TLS certs/keys. If this is a relative path, it is relative to the directory of mox.conf."` + DataDir string `sconf-doc:"NOTE: This config file is in 'sconf' format. Indent with tabs. Comments must be on their own line, they don't end a line. Do not escape or quote strings. Details: https://pkg.go.dev/github.com/mjl-/sconf.\n\n\nDirectory where all data is stored, e.g. queue, accounts and messages, ACME TLS certs/keys. If this is a relative path, it is relative to the directory of mox.conf."` LogLevel string `sconf-doc:"Default log level, one of: error, info, debug, trace, traceauth, tracedata. Trace logs SMTP and IMAP protocol transcripts, with traceauth also messages with passwords, and tracedata on top of that also the full data exchanges (full messages), which can be a large amount of data."` PackageLogLevels map[string]string `sconf:"optional" sconf-doc:"Overrides of log level per package (e.g. queue, smtpclient, smtpserver, imapserver, spf, dkim, dmarc, dmarcdb, autotls, junk, mtasts, tlsrpt)."` User string `sconf:"optional" sconf-doc:"User to switch to after binding to all sockets as root. Default: mox. If the value is not a known user, it is parsed as integer and used as uid and gid."` @@ -94,7 +94,7 @@ type SpecialUseMailboxes struct { // Dynamic is the parsed form of domains.conf, and is automatically reloaded when changed. type Dynamic struct { - Domains map[string]Domain `sconf-doc:"Domains for which email is accepted. For internationalized domains, use their IDNA names in UTF-8."` + Domains map[string]Domain `sconf-doc:"NOTE: This config file is in 'sconf' format. Indent with tabs. Comments must be on their own line, they don't end a line. Do not escape or quote strings. Details: https://pkg.go.dev/github.com/mjl-/sconf.\n\n\nDomains for which email is accepted. For internationalized domains, use their IDNA names in UTF-8."` Accounts map[string]Account `sconf-doc:"Accounts to which email can be delivered. An account can accept email for multiple domains, for multiple localparts, and deliver to multiple mailboxes."` WebDomainRedirects map[string]string `sconf:"optional" sconf-doc:"Redirect all requests from domain (key) to domain (value). Always redirects to HTTPS. For plain HTTP redirects, use a WebHandler with a WebRedirect."` WebHandlers []WebHandler `sconf:"optional" sconf-doc:"Handle webserver requests by serving static files, redirecting or reverse-proxying HTTP(s). The first matching WebHandler will handle the request. Built-in handlers, e.g. for account, admin, autoconfig and mta-sts always run first. If no handler matches, the response status code is file not found (404). If functionality you need is missng, simply forward the requests to an application that can provide the needed functionality."` diff --git a/config/doc.go b/config/doc.go index dc69ffa..59bffee 100644 --- a/config/doc.go +++ b/config/doc.go @@ -13,6 +13,11 @@ describe-static" and "mox config describe-domains": # mox.conf + # NOTE: This config file is in 'sconf' format. Indent with tabs. Comments must be + # on their own line, they don't end a line. Do not escape or quote strings. + # Details: https://pkg.go.dev/github.com/mjl-/sconf. + + # Directory where all data is stored, e.g. queue, accounts and messages, ACME TLS # certs/keys. If this is a relative path, it is relative to the directory of # mox.conf. @@ -526,6 +531,11 @@ describe-static" and "mox config describe-domains": # domains.conf + # NOTE: This config file is in 'sconf' format. Indent with tabs. Comments must be + # on their own line, they don't end a line. Do not escape or quote strings. + # Details: https://pkg.go.dev/github.com/mjl-/sconf. + + # Domains for which email is accepted. For internationalized domains, use their # IDNA names in UTF-8. Domains: diff --git a/go.mod b/go.mod index a76817c..b668294 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.18 require ( github.com/mjl-/bstore v0.0.2 - github.com/mjl-/sconf v0.0.4 + github.com/mjl-/sconf v0.0.5 github.com/mjl-/sherpa v0.6.6 github.com/mjl-/sherpadoc v0.0.12 github.com/mjl-/sherpaprom v0.0.2 @@ -22,7 +22,7 @@ require ( github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect - github.com/mjl-/xfmt v0.0.0-20190521151243-39d9c00752ce // indirect + github.com/mjl-/xfmt v0.0.2 // indirect github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect diff --git a/go.sum b/go.sum index c6abf51..1ec93d1 100644 --- a/go.sum +++ b/go.sum @@ -147,8 +147,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0j github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mjl-/bstore v0.0.2 h1:4fdpIOY/+Dv1dBHyzdqa4PD90p8Mz86FeyRpI4qcehw= github.com/mjl-/bstore v0.0.2/go.mod h1:/cD25FNBaDfvL/plFRxI3Ba3E+wcB0XVOS8nJDqndg0= -github.com/mjl-/sconf v0.0.4 h1:uyfn4vv5qOULSgiwQsPbbgkiONKnMFMsSOhsHfAiYwI= -github.com/mjl-/sconf v0.0.4/go.mod h1:ezf7YOn7gtClo8y71SqgZKaEkyMQ5Te7vkv4PmTTfwM= +github.com/mjl-/sconf v0.0.5 h1:4CMUTENpSnaeP2g6RKtrs8udTxnJgjX2MCCovxGId6s= +github.com/mjl-/sconf v0.0.5/go.mod h1:uF8OdWtLT8La3i4ln176i1pB0ps9pXGCaABEU55ZkE0= github.com/mjl-/sherpa v0.6.6 h1:4Xc4/s12W2I/C1genIL8l4ZCLMsTo8498cPSjQcIHGc= github.com/mjl-/sherpa v0.6.6/go.mod h1:dSpAOdgpwdqQZ72O4n3EHo/tR68eKyan8tYYraUMPNc= github.com/mjl-/sherpadoc v0.0.0-20190505200843-c0a7f43f5f1d/go.mod h1:5khTKxoKKNXcB8bkVUO6GlzC7PFtMmkHq578lPbmnok= @@ -158,8 +158,8 @@ github.com/mjl-/sherpaprom v0.0.2 h1:1dlbkScsNafM5jURI44uiWrZMSwfZtcOFEEq7vx2C1Y github.com/mjl-/sherpaprom v0.0.2/go.mod h1:cl5nMNOvqhzMiQJ2FzccQ9ReivjHXe53JhOVkPfSvw4= github.com/mjl-/sherpats v0.0.4 h1:rZkJO4YV4MfuCi3E4ifzbhpY6VgZgsQoOcL04ABEib4= github.com/mjl-/sherpats v0.0.4/go.mod h1:MoNZJtLmu8oCZ4Ocv5vZksENN4pp6/SJMlg9uTII4KA= -github.com/mjl-/xfmt v0.0.0-20190521151243-39d9c00752ce h1:oyFmIHo3GLWZzb0odAzN9QUy0MTW6P8JaNRnNVGCBCk= -github.com/mjl-/xfmt v0.0.0-20190521151243-39d9c00752ce/go.mod h1:DIEOLmETMQHHr4OgwPG7iC37rDiN9MaZIZxNm5hBtL8= +github.com/mjl-/xfmt v0.0.2 h1:6dLgd6U3bmDJKtTxsaSYYyMaORoO4hKBAJo4XKkPRko= +github.com/mjl-/xfmt v0.0.2/go.mod h1:DIEOLmETMQHHr4OgwPG7iC37rDiN9MaZIZxNm5hBtL8= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= diff --git a/vendor/github.com/mjl-/sconf/describe.go b/vendor/github.com/mjl-/sconf/describe.go index 99cb2e3..229ea0a 100644 --- a/vendor/github.com/mjl-/sconf/describe.go +++ b/vendor/github.com/mjl-/sconf/describe.go @@ -17,6 +17,7 @@ type writeError struct{ error } type writer struct { out *bufio.Writer + wrote int prefix string keepZero bool // If set, we also write zero values. docs bool // If set, we write comments. @@ -33,8 +34,9 @@ func (w *writer) check(err error) { } func (w *writer) write(s string) { - _, err := w.out.WriteString(s) + n, err := w.out.WriteString(s) w.check(err) + w.wrote += n } func (w *writer) flush() { @@ -108,7 +110,7 @@ func isEmptyStruct(v reflect.Value) bool { for i := 0; i < n; i++ { ft := t.Field(i) tag := ft.Tag.Get("sconf") - if isIgnore(tag) { + if !ft.IsExported() || isIgnore(tag) { continue } if !isOptional(tag) { @@ -134,7 +136,7 @@ func isZeroIgnored(v reflect.Value) bool { for i := 0; i < n; i++ { ft := t.Field(i) tag := ft.Tag.Get("sconf") - if isIgnore(tag) { + if !ft.IsExported() || isIgnore(tag) { continue } if !isZeroIgnored(v.Field(i)) { @@ -153,7 +155,7 @@ func (w *writer) describeStruct(v reflect.Value) { for i := 0; i < n; i++ { f := t.Field(i) fv := v.Field(i) - if isIgnore(f.Tag.Get("sconf")) { + if !f.IsExported() || isIgnore(f.Tag.Get("sconf")) { continue } if !w.keepZero && isOptional(f.Tag.Get("sconf")) && isZeroIgnored(fv) { @@ -163,11 +165,33 @@ func (w *writer) describeStruct(v reflect.Value) { doc := f.Tag.Get("sconf-doc") optional := isOptional(f.Tag.Get("sconf")) if doc != "" || optional { - s := "\n" + w.prefix + "# " + doc + s := "\n" + if w.wrote == 0 { + // No empty line at start of file. + s = "" + } + // Treat two blank lines as section separator: the comments are not joined with + // lines with just "#", but instead with empty lines. To allow a hack where the + // first field of a config struct gives some context about the file. + sections := strings.Split(doc, "\n\n\n") + for si, section := range sections { + if si > 0 { + s += "\n\n\n" + } + for i, line := range strings.Split(section, "\n") { + if i > 0 { + s += "\n" + } + s += w.prefix + "#" + if line != "" { + s += " " + line + } + } + } if optional { opt := "(optional)" - if doc != "" { - opt = " " + opt + if !strings.HasSuffix(doc, " ") { + s += " " } s += opt } diff --git a/vendor/github.com/mjl-/sconf/parse.go b/vendor/github.com/mjl-/sconf/parse.go index 4efaf65..a4e765e 100644 --- a/vendor/github.com/mjl-/sconf/parse.go +++ b/vendor/github.com/mjl-/sconf/parse.go @@ -245,8 +245,8 @@ func (p *parser) parseStruct0(v reflect.Value) { if vv == zeroValue { p.stop(fmt.Sprintf("unknown key %q", k)) } - if ft, _ := t.FieldByName(k); isIgnore(ft.Tag.Get("sconf")) { - p.stop(fmt.Sprintf("unknown key %q (has ignore tag)", k)) + if ft, _ := t.FieldByName(k); !ft.IsExported() || isIgnore(ft.Tag.Get("sconf")) { + p.stop(fmt.Sprintf("unknown key %q (has ignore tag or not exported)", k)) } vv.Set(p.parseValue(vv)) } @@ -254,7 +254,7 @@ func (p *parser) parseStruct0(v reflect.Value) { n := t.NumField() for i := 0; i < n; i++ { f := t.Field(i) - if isIgnore(f.Tag.Get("sconf")) || isOptional(f.Tag.Get("sconf")) { + if !f.IsExported() || isIgnore(f.Tag.Get("sconf")) || isOptional(f.Tag.Get("sconf")) { continue } if _, ok := seen[f.Name]; !ok { diff --git a/vendor/github.com/mjl-/xfmt/xfmt.go b/vendor/github.com/mjl-/xfmt/xfmt.go index 2655883..3dfd686 100644 --- a/vendor/github.com/mjl-/xfmt/xfmt.go +++ b/vendor/github.com/mjl-/xfmt/xfmt.go @@ -10,8 +10,12 @@ import ( // Config tells format how to reformat text. type Config struct { - MaxWidth int // Max width of content (excluding indenting), after which lines are wrapped. - BreakPrefixes []string // String prefixes that cause a line to break, instead of being merged into the previous line. + // Max width of content (excluding indenting), after which lines are wrapped. + MaxWidth int + + // String prefixes that cause a line to break, instead of being merged into the + // previous line. + BreakPrefixes []string } // Format reads text from r and writes reformatted text to w, according to @@ -33,7 +37,7 @@ type formatter struct { curLineend string } -type parseError error +type parseError struct{ error } func (f *formatter) format() (rerr error) { defer func() { @@ -65,7 +69,7 @@ func (f *formatter) format() (rerr error) { func (f *formatter) check(err error, action string) { if err != nil { - panic(parseError(fmt.Errorf("%s: %s", action, err))) + panic(parseError{fmt.Errorf("%s: %s", action, err)}) } } @@ -108,6 +112,7 @@ func (f *formatter) gatherLine() (string, string) { var curLine, curLineend string var curPrefix string + n := 0 for { line, end := f.peekLine() if line == "" && end == "" { @@ -123,7 +128,7 @@ func (f *formatter) gatherLine() (string, string) { } break } - if curLine != "" && (curPrefix != prefix || rem == "" || f.causeBreak(rem)) { + if n > 0 && (curPrefix != prefix || rem == "" || f.causeBreak(rem)) { break } curPrefix = prefix @@ -136,6 +141,7 @@ func (f *formatter) gatherLine() (string, string) { if curLine != "" && curLine[len(curLine)-1] < 0x20 { break } + n++ } return curPrefix + curLine, curLineend diff --git a/vendor/modules.txt b/vendor/modules.txt index 039e59a..229ba40 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -14,7 +14,7 @@ github.com/matttproud/golang_protobuf_extensions/pbutil # github.com/mjl-/bstore v0.0.2 ## explicit; go 1.19 github.com/mjl-/bstore -# github.com/mjl-/sconf v0.0.4 +# github.com/mjl-/sconf v0.0.5 ## explicit; go 1.12 github.com/mjl-/sconf # github.com/mjl-/sherpa v0.6.6 @@ -31,7 +31,7 @@ github.com/mjl-/sherpaprom ## explicit; go 1.12 github.com/mjl-/sherpats github.com/mjl-/sherpats/cmd/sherpats -# github.com/mjl-/xfmt v0.0.0-20190521151243-39d9c00752ce +# github.com/mjl-/xfmt v0.0.2 ## explicit; go 1.12 github.com/mjl-/xfmt # github.com/prometheus/client_golang v1.14.0