Move doc-comment logic to the config pkg

This commit is contained in:
Łukasz Magiera 2021-07-23 14:55:19 +02:00
parent 97f5bb66c7
commit 8b1f19e94c
4 changed files with 127 additions and 85 deletions

View File

@ -1,13 +1,8 @@
package main
import (
"bytes"
"fmt"
"github.com/filecoin-project/lotus/node/repo"
"reflect"
"strings"
"github.com/BurntSushi/toml"
"github.com/urfave/cli/v2"
"golang.org/x/xerrors"
@ -35,19 +30,7 @@ var configDefaultCmd = &cli.Command{
Action: func(cctx *cli.Context) error {
c := config.DefaultFullNode()
if cctx.Bool("no-comment") {
buf := new(bytes.Buffer)
_, _ = buf.WriteString("# Default config:\n")
e := toml.NewEncoder(buf)
if err := e.Encode(c); err != nil {
return xerrors.Errorf("encoding default config: %w", err)
}
fmt.Println(buf.String())
return nil
}
cb, err := config.ConfigComment(c)
cb, err := config.ConfigUpdate(c, nil, !cctx.Bool("no-comment"))
if err != nil {
return err
}
@ -99,64 +82,12 @@ var configUpdateCmd = &cli.Command{
cfgDef := config.DefaultFullNode()
var nodeStr, defStr string
{
buf := new(bytes.Buffer)
e := toml.NewEncoder(buf)
if err := e.Encode(cfgDef); err != nil {
return xerrors.Errorf("encoding default config: %w", err)
}
defStr = buf.String()
updated, err := config.ConfigUpdate(cfgNode, cfgDef, !cctx.Bool("no-comment"))
if err != nil {
return err
}
{
buf := new(bytes.Buffer)
e := toml.NewEncoder(buf)
if err := e.Encode(cfgNode); err != nil {
return xerrors.Errorf("encoding node config: %w", err)
}
nodeStr = buf.String()
}
if !cctx.Bool("no-comment") {
defLines := strings.Split(defStr, "\n")
defaults := map[string]struct{}{}
for i := range defLines {
l := strings.TrimSpace(defLines[i])
if len(l) == 0 {
continue
}
if l[0] == '#' || l[0] == '[' {
continue
}
defaults[l] = struct{}{}
}
nodeLines := strings.Split(nodeStr, "\n")
for i := range nodeLines {
if _, found := defaults[strings.TrimSpace(nodeLines[i])]; found {
nodeLines[i] = "#" + nodeLines[i]
}
}
nodeStr = strings.Join(nodeLines, "\n")
}
// sanity-check that the updated config parses the same way as the current one
{
cfgUpdated, err := config.FromReader(strings.NewReader(nodeStr), config.DefaultFullNode())
if err != nil {
return xerrors.Errorf("parsing updated config: %w", err)
}
if !reflect.DeepEqual(cfgNode, cfgUpdated) {
return xerrors.Errorf("updated config didn't match current config")
}
}
fmt.Println(nodeStr)
fmt.Print(string(updated))
return nil
},
}

View File

@ -13,7 +13,7 @@ var Doc = map[string][]DocField{
{
Name: "ListenAddress",
Type: "string",
Comment: ``,
Comment: `Binding address for the Lotus API`,
},
{
Name: "RemoteListenAddress",

View File

@ -5,6 +5,10 @@ import (
"fmt"
"io"
"os"
"reflect"
"regexp"
"strings"
"unicode"
"github.com/BurntSushi/toml"
"github.com/kelseyhightower/envconfig"
@ -42,15 +46,121 @@ func FromReader(reader io.Reader, def interface{}) (interface{}, error) {
return cfg, nil
}
func ConfigComment(t interface{}) ([]byte, error) {
buf := new(bytes.Buffer)
_, _ = buf.WriteString("# Default config:\n")
e := toml.NewEncoder(buf)
if err := e.Encode(t); err != nil {
return nil, xerrors.Errorf("encoding config: %w", err)
func ConfigUpdate(cfgCur, cfgDef interface{}, comment bool) ([]byte, error) {
var nodeStr, defStr string
if cfgDef != nil {
buf := new(bytes.Buffer)
e := toml.NewEncoder(buf)
if err := e.Encode(cfgDef); err != nil {
return nil, xerrors.Errorf("encoding default config: %w", err)
}
defStr = buf.String()
}
b := buf.Bytes()
b = bytes.ReplaceAll(b, []byte("\n"), []byte("\n#"))
b = bytes.ReplaceAll(b, []byte("#["), []byte("["))
return b, nil
{
buf := new(bytes.Buffer)
e := toml.NewEncoder(buf)
if err := e.Encode(cfgCur); err != nil {
return nil, xerrors.Errorf("encoding node config: %w", err)
}
nodeStr = buf.String()
}
if comment {
// create a map of default lines so we can comment those out later
defLines := strings.Split(defStr, "\n")
defaults := map[string]struct{}{}
for i := range defLines {
l := strings.TrimSpace(defLines[i])
if len(l) == 0 {
continue
}
if l[0] == '#' || l[0] == '[' {
continue
}
defaults[l] = struct{}{}
}
nodeLines := strings.Split(nodeStr, "\n")
var outLines []string
sectionRx := regexp.MustCompile(`[\[.]([^.]+)]`)
var section string
for i, line := range nodeLines {
// if this is a section, track it
trimmed := strings.TrimSpace(line)
if len(trimmed) > 0 {
if trimmed[0] == '[' {
m := sectionRx.FindSubmatch([]byte(trimmed))
if len(m) != 2 {
return nil, xerrors.Errorf("section didn't match (line %d)", i)
}
section = string(m[1])
// never comment sections
outLines = append(outLines, line)
continue
}
}
pad := strings.Repeat(" ", len(line) - len(strings.TrimLeftFunc(line, unicode.IsSpace)))
// see if we have docs for this field
{
lf := strings.Fields(line)
if len(lf) > 1 {
var doc *DocField
for _, df := range Doc[section] {
if df.Name == lf[0] {
doc = &df
break
}
}
if doc != nil {
// found docfield, emit doc comment
if len(doc.Comment) > 0 {
for _, docLine := range strings.Split(doc.Comment, "\n") {
outLines = append(outLines, pad + "# " + docLine)
}
outLines = append(outLines, pad + "#")
}
outLines = append(outLines, pad + "# type: " + doc.Type)
}
}
}
// if there is the same line in the default config, comment it out it output
if _, found := defaults[strings.TrimSpace(nodeLines[i])]; (cfgDef == nil || found) && len(line) > 0 {
line = pad + "#" + line[len(pad):]
outLines = append(outLines, line, "")
} else {
outLines = append(outLines, line)
}
}
nodeStr = strings.Join(outLines, "\n")
}
// sanity-check that the updated config parses the same way as the current one
if cfgDef != nil {
cfgUpdated, err := FromReader(strings.NewReader(nodeStr), cfgDef)
if err != nil {
return nil, xerrors.Errorf("parsing updated config: %w", err)
}
if !reflect.DeepEqual(cfgCur, cfgUpdated) {
return nil, xerrors.Errorf("updated config didn't match current config")
}
}
return []byte(nodeStr), nil
}
func ConfigComment(t interface{}) ([]byte, error) {
return ConfigUpdate(t, nil, true)
}

View File

@ -200,6 +200,7 @@ type MinerAddressConfig struct {
// API contains configs for API endpoint
type API struct {
// Binding address for the Lotus API
ListenAddress string
RemoteListenAddress string
Timeout Duration