You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by cc...@apache.org on 2018/11/19 18:22:33 UTC

[mynewt-newt] 02/03: ycfg: Add name string

This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-newt.git

commit 8d32a7a185b784d39a5d1dde27ed33a0e43e61f7
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Wed Nov 7 17:22:10 2018 -0800

    ycfg: Add name string
    
    This is to help users debug bad YAML files.  When a YCfg object is
    created, the YAML filename is associated with the YCfg.  When an error
    is encountered, the warning / error text can contain the name of the bad
    file.
---
 newt/cli/target_cmds.go   |   3 +-
 newt/newtutil/newtutil.go |  13 ++++--
 newt/pkg/bsp_package.go   |  14 ++++--
 newt/pkg/localpackage.go  |  42 +++++++++--------
 newt/settings/settings.go |   9 ++--
 newt/target/target.go     |  23 +++++-----
 newt/ycfg/ycfg.go         | 114 ++++++++++++++++++++++++++++------------------
 7 files changed, 129 insertions(+), 89 deletions(-)

diff --git a/newt/cli/target_cmds.go b/newt/cli/target_cmds.go
index 04c3260..62182af 100644
--- a/newt/cli/target_cmds.go
+++ b/newt/cli/target_cmds.go
@@ -35,7 +35,6 @@ import (
 	"mynewt.apache.org/newt/newt/resolve"
 	"mynewt.apache.org/newt/newt/syscfg"
 	"mynewt.apache.org/newt/newt/target"
-	"mynewt.apache.org/newt/newt/ycfg"
 	"mynewt.apache.org/newt/util"
 )
 
@@ -304,7 +303,7 @@ func targetSetCmd(cmd *cobra.Command, args []string) {
 		// A few variables are special cases; they get set in the base package
 		// instead of the target.
 		if kv[0] == "target.syscfg" {
-			t.Package().SyscfgY = ycfg.YCfg{}
+			t.Package().SyscfgY.Clear()
 			kv, err := syscfg.KeyValueFromStr(kv[1])
 			if err != nil {
 				NewtUsage(cmd, err)
diff --git a/newt/newtutil/newtutil.go b/newt/newtutil/newtutil.go
index 96795cd..3ea9fe2 100644
--- a/newt/newtutil/newtutil.go
+++ b/newt/newtutil/newtutil.go
@@ -176,19 +176,24 @@ func MakeTempRepoDir() (string, error) {
 }
 
 func ReadConfigPath(path string) (ycfg.YCfg, error) {
+	yc := ycfg.NewYCfg(path)
+
 	file, err := ioutil.ReadFile(path)
 	if err != nil {
-		return ycfg.YCfg{}, util.FmtNewtError("Error reading %s: %s",
-			path, err.Error())
+		return yc, util.ChildNewtError(err)
 	}
 
 	settings := map[string]interface{}{}
 	if err := yaml.Unmarshal(file, &settings); err != nil {
-		return ycfg.YCfg{}, util.FmtNewtError("Failure parsing \"%s\": %s",
+		return yc, util.FmtNewtError("Failure parsing \"%s\": %s",
 			path, err.Error())
 	}
 
-	return ycfg.NewYCfg(path, settings)
+	if err := yc.Populate(settings); err != nil {
+		return yc, err
+	}
+
+	return yc, nil
 }
 
 // Read in the configuration file specified by name, in path
diff --git a/newt/pkg/bsp_package.go b/newt/pkg/bsp_package.go
index 56399a0..1406593 100644
--- a/newt/pkg/bsp_package.go
+++ b/newt/pkg/bsp_package.go
@@ -20,6 +20,7 @@
 package pkg
 
 import (
+	"fmt"
 	"runtime"
 	"strings"
 
@@ -44,6 +45,10 @@ type BspPackage struct {
 	BspV               ycfg.YCfg
 }
 
+func (bsp *BspPackage) BspYamlPath() string {
+	return fmt.Sprintf("%s/%s", bsp.BasePath(), BSP_YAML_FILENAME)
+}
+
 func (bsp *BspPackage) resolvePathSetting(
 	settings map[string]string, key string) (string, error) {
 
@@ -111,12 +116,11 @@ func (bsp *BspPackage) Reload(settings map[string]string) error {
 	}
 	settings[strings.ToUpper(runtime.GOOS)] = "1"
 
-	bsp.BspV, err = newtutil.ReadConfig(bsp.BasePath(),
-		strings.TrimSuffix(BSP_YAML_FILENAME, ".yml"))
+	bsp.BspV, err = newtutil.ReadConfigPath(bsp.BspYamlPath())
 	if err != nil {
 		return err
 	}
-	bsp.AddCfgFilename(bsp.BasePath() + BSP_YAML_FILENAME)
+	bsp.AddCfgFilename(bsp.BspYamlPath())
 
 	bsp.CompilerName = bsp.BspV.GetValString("bsp.compiler", settings)
 	bsp.Arch = bsp.BspV.GetValString("bsp.arch", settings)
@@ -171,10 +175,12 @@ func NewBspPackage(lpkg *LocalPackage) (*BspPackage, error) {
 		CompilerName:   "",
 		DownloadScript: "",
 		DebugScript:    "",
-		BspV:           ycfg.YCfg{},
 	}
+
 	lpkg.Load()
 	bsp.LocalPackage = lpkg
+	bsp.BspV = ycfg.NewYCfg(bsp.BspYamlPath())
+
 	err := bsp.Reload(nil)
 
 	return bsp, err
diff --git a/newt/pkg/localpackage.go b/newt/pkg/localpackage.go
index 0b23036..072726f 100644
--- a/newt/pkg/localpackage.go
+++ b/newt/pkg/localpackage.go
@@ -77,12 +77,13 @@ type LocalPackage struct {
 func NewLocalPackage(r *repo.Repo, pkgDir string) *LocalPackage {
 	pkg := &LocalPackage{
 		desc:             &PackageDesc{},
-		PkgY:             ycfg.YCfg{},
-		SyscfgY:          ycfg.YCfg{},
 		repo:             r,
 		basePath:         filepath.ToSlash(filepath.Clean(pkgDir)),
 		injectedSettings: map[string]string{},
 	}
+
+	pkg.PkgY = ycfg.NewYCfg(pkg.PkgYamlPath())
+	pkg.SyscfgY = ycfg.NewYCfg(pkg.SyscfgYamlPath())
 	return pkg
 }
 
@@ -117,6 +118,14 @@ func (pkg *LocalPackage) RelativePath() string {
 	return strings.TrimPrefix(pkg.BasePath(), proj.Path())
 }
 
+func (pkg *LocalPackage) PkgYamlPath() string {
+	return fmt.Sprintf("%s/%s", pkg.BasePath(), PACKAGE_FILE_NAME)
+}
+
+func (pkg *LocalPackage) SyscfgYamlPath() string {
+	return fmt.Sprintf("%s/%s", pkg.BasePath(), SYSCFG_YAML_FILENAME)
+}
+
 func (pkg *LocalPackage) Type() interfaces.PackageType {
 	return pkg.packageType
 }
@@ -203,10 +212,8 @@ func (pkg *LocalPackage) readDesc(yc ycfg.YCfg) (*PackageDesc, error) {
 func (pkg *LocalPackage) sequenceString(key string) string {
 	var buffer bytes.Buffer
 
-	if pkg.PkgY != nil {
-		for _, f := range pkg.PkgY.GetValStringSlice(key, nil) {
-			buffer.WriteString("    - " + yaml.EscapeString(f) + "\n")
-		}
+	for _, f := range pkg.PkgY.GetValStringSlice(key, nil) {
+		buffer.WriteString("    - " + yaml.EscapeString(f) + "\n")
 	}
 
 	if buffer.Len() == 0 {
@@ -222,8 +229,7 @@ func (lpkg *LocalPackage) SaveSyscfg() error {
 		return util.NewNewtError(err.Error())
 	}
 
-	filepath := dirpath + "/" + SYSCFG_YAML_FILENAME
-	file, err := os.Create(filepath)
+	file, err := os.Create(lpkg.SyscfgYamlPath())
 	if err != nil {
 		return util.NewNewtError(err.Error())
 	}
@@ -244,8 +250,7 @@ func (pkg *LocalPackage) Save() error {
 		return util.NewNewtError(err.Error())
 	}
 
-	filepath := dirpath + "/" + PACKAGE_FILE_NAME
-	file, err := os.Create(filepath)
+	file, err := os.Create(pkg.PkgYamlPath())
 	if err != nil {
 		return util.NewNewtError(err.Error())
 	}
@@ -291,12 +296,11 @@ func (pkg *LocalPackage) Load() error {
 
 	var err error
 
-	pkg.PkgY, err = newtutil.ReadConfig(pkg.basePath,
-		strings.TrimSuffix(PACKAGE_FILE_NAME, ".yml"))
+	pkg.PkgY, err = newtutil.ReadConfigPath(pkg.PkgYamlPath())
 	if err != nil {
 		return err
 	}
-	pkg.AddCfgFilename(pkg.basePath + "/" + PACKAGE_FILE_NAME)
+	pkg.AddCfgFilename(pkg.PkgYamlPath())
 
 	// Set package name from the package
 	pkg.name = pkg.PkgY.GetValString("pkg.name", nil)
@@ -353,15 +357,13 @@ func (pkg *LocalPackage) Load() error {
 	}
 
 	// Load syscfg settings.
-	if util.NodeExist(pkg.basePath + "/" + SYSCFG_YAML_FILENAME) {
-		pkg.SyscfgY, err = newtutil.ReadConfig(pkg.basePath,
-			strings.TrimSuffix(SYSCFG_YAML_FILENAME, ".yml"))
-		if err != nil {
-			return err
-		}
-		pkg.AddCfgFilename(pkg.basePath + "/" + SYSCFG_YAML_FILENAME)
+	pkg.SyscfgY, err = newtutil.ReadConfigPath(pkg.SyscfgYamlPath())
+	if err != nil && !util.IsNotExist(err) {
+		return err
 	}
 
+	pkg.AddCfgFilename(pkg.SyscfgYamlPath())
+
 	return nil
 }
 
diff --git a/newt/settings/settings.go b/newt/settings/settings.go
index 1613505..24cd6a5 100644
--- a/newt/settings/settings.go
+++ b/newt/settings/settings.go
@@ -33,7 +33,7 @@ const NEWTRC_DIR string = ".newt"
 const REPOS_FILENAME string = "repos.yml"
 
 // Contains general newt settings read from $HOME/.newt
-var newtrc ycfg.YCfg
+var newtrc *ycfg.YCfg
 
 func readNewtrc() ycfg.YCfg {
 	usr, err := user.Current()
@@ -54,9 +54,10 @@ func readNewtrc() ycfg.YCfg {
 
 func Newtrc() ycfg.YCfg {
 	if newtrc != nil {
-		return newtrc
+		return *newtrc
 	}
 
-	newtrc = readNewtrc()
-	return newtrc
+	yc := readNewtrc()
+	newtrc = &yc
+	return yc
 }
diff --git a/newt/target/target.go b/newt/target/target.go
index 0979854..ee3acdc 100644
--- a/newt/target/target.go
+++ b/newt/target/target.go
@@ -20,10 +20,10 @@
 package target
 
 import (
+	"fmt"
 	"os"
 	"path/filepath"
 	"strconv"
-	"strings"
 
 	"mynewt.apache.org/newt/newt/newtutil"
 	"mynewt.apache.org/newt/newt/pkg"
@@ -56,9 +56,13 @@ type Target struct {
 
 func NewTarget(basePkg *pkg.LocalPackage) *Target {
 	target := &Target{
-		TargetY: ycfg.YCfg{},
+		basePkg: basePkg,
 	}
-	target.Init(basePkg)
+
+	if basePkg.SyscfgY.Tree() == nil {
+		panic("Fatal: target missing syscfg")
+	}
+	target.TargetY = ycfg.NewYCfg(target.TargetYamlPath())
 	return target
 }
 
@@ -71,13 +75,12 @@ func LoadTarget(basePkg *pkg.LocalPackage) (*Target, error) {
 	return target, nil
 }
 
-func (target *Target) Init(basePkg *pkg.LocalPackage) {
-	target.basePkg = basePkg
+func (target *Target) TargetYamlPath() string {
+	return fmt.Sprintf("%s/%s", target.basePkg.BasePath(), TARGET_FILENAME)
 }
 
 func (target *Target) Load(basePkg *pkg.LocalPackage) error {
-	yc, err := newtutil.ReadConfig(basePkg.BasePath(),
-		strings.TrimSuffix(TARGET_FILENAME, ".yml"))
+	yc, err := newtutil.ReadConfigPath(target.TargetYamlPath())
 	if err != nil {
 		return err
 	}
@@ -110,7 +113,7 @@ func (target *Target) Load(basePkg *pkg.LocalPackage) error {
 
 	// Remember the name of the configuration file so that it can be specified
 	// as a dependency to the compiler.
-	target.basePkg.AddCfgFilename(basePkg.BasePath() + TARGET_FILENAME)
+	target.basePkg.AddCfgFilename(target.TargetYamlPath())
 
 	return nil
 }
@@ -263,9 +266,7 @@ func (t *Target) Save() error {
 		return err
 	}
 
-	dirpath := t.basePkg.BasePath()
-	filepath := dirpath + "/" + TARGET_FILENAME
-	file, err := os.Create(filepath)
+	file, err := os.Create(t.TargetYamlPath())
 	if err != nil {
 		return util.NewNewtError(err.Error())
 	}
diff --git a/newt/ycfg/ycfg.go b/newt/ycfg/ycfg.go
index db0f1fb..53b4d71 100644
--- a/newt/ycfg/ycfg.go
+++ b/newt/ycfg/ycfg.go
@@ -23,10 +23,10 @@ import (
 	"fmt"
 	"strings"
 
-	log "github.com/Sirupsen/logrus"
 	"github.com/spf13/cast"
 
 	"mynewt.apache.org/newt/newt/parse"
+	"mynewt.apache.org/newt/util"
 )
 
 // YAML configuration object.  This is a substitute for a viper configuration
@@ -66,7 +66,13 @@ import (
 // Since each expression is a child node of the setting in question, they are
 // all known at the time of the lookup.  To determine the value of the setting,
 // each expression is parsed, and only the one evaluating to true is selected.
-type YCfg map[string]*YCfgNode
+type YCfg struct {
+	// Name of config; typically a YAML filename.
+	name string
+
+	// The settings.
+	tree YCfgTree
+}
 
 type YCfgEntry struct {
 	Value interface{}
@@ -77,29 +83,39 @@ type YCfgNode struct {
 	Overwrite bool
 	Name      string
 	Value     interface{}
-	Children  YCfg
+	Children  YCfgTree
 	Parent    *YCfgNode
 }
 
+func (yc *YCfg) Tree() YCfgTree {
+	return yc.tree
+}
+
+type YCfgTree map[string]*YCfgNode
+
+func NewYCfgNode() *YCfgNode {
+	return &YCfgNode{Children: YCfgTree{}}
+}
+
 func (node *YCfgNode) addChild(name string) (*YCfgNode, error) {
 	if node.Children == nil {
-		node.Children = YCfg{}
+		node.Children = YCfgTree{}
 	}
 
 	if node.Children[name] != nil {
 		return nil, fmt.Errorf("Duplicate YCfgNode: %s", name)
 	}
 
-	child := &YCfgNode{
-		Name:   name,
-		Parent: node,
-	}
+	child := NewYCfgNode()
+	child.Name = name
+	child.Parent = node
+
 	node.Children[name] = child
 
 	return child, nil
 }
 
-func (yc YCfg) Replace(key string, val interface{}) error {
+func (yc *YCfg) Replace(key string, val interface{}) error {
 	elems := strings.Split(key, ".")
 	if len(elems) == 0 {
 		return fmt.Errorf("Invalid ycfg key: \"\"")
@@ -113,12 +129,12 @@ func (yc YCfg) Replace(key string, val interface{}) error {
 
 	var parent *YCfgNode
 	for i, e := range elems {
-		var parentChildren YCfg
+		var parentChildren YCfgTree
 		if parent == nil {
-			parentChildren = yc
+			parentChildren = yc.tree
 		} else {
 			if parent.Children == nil {
-				parent.Children = YCfg{}
+				parent.Children = YCfgTree{}
 			}
 			parentChildren = parent.Children
 		}
@@ -131,7 +147,8 @@ func (yc YCfg) Replace(key string, val interface{}) error {
 					return err
 				}
 			} else {
-				child = &YCfgNode{Name: e}
+				child = NewYCfgNode()
+				child.Name = e
 				parentChildren[e] = child
 			}
 		}
@@ -147,26 +164,31 @@ func (yc YCfg) Replace(key string, val interface{}) error {
 	return nil
 }
 
-func NewYCfg(kv map[string]interface{}) (YCfg, error) {
-	yc := YCfg{}
+func NewYCfg(name string) YCfg {
+	return YCfg{
+		name: name,
+		tree: YCfgTree{},
+	}
+}
 
+func (yc *YCfg) Populate(kv map[string]interface{}) error {
 	for k, v := range kv {
 		if err := yc.Replace(k, v); err != nil {
-			return nil, err
+			return err
 		}
 	}
 
-	return yc, nil
+	return nil
 }
 
-func (yc YCfg) find(key string) *YCfgNode {
+func (yc *YCfg) find(key string) *YCfgNode {
 	elems := strings.Split(key, ".")
 	if len(elems) == 0 {
 		return nil
 	}
 
 	cur := &YCfgNode{
-		Children: yc,
+		Children: yc.tree,
 	}
 	for _, e := range elems {
 		if cur.Children == nil {
@@ -182,7 +204,7 @@ func (yc YCfg) find(key string) *YCfgNode {
 	return cur
 }
 
-func (yc YCfg) Get(key string, settings map[string]string) []YCfgEntry {
+func (yc *YCfg) Get(key string, settings map[string]string) []YCfgEntry {
 	node := yc.find(key)
 	if node == nil {
 		return nil
@@ -198,7 +220,7 @@ func (yc YCfg) Get(key string, settings map[string]string) []YCfgEntry {
 	for _, child := range node.Children {
 		val, err := parse.ParseAndEval(child.Name, settings)
 		if err != nil {
-			log.Error(err.Error())
+			util.OneTimeWarning("%s: %s", yc.name, err.Error())
 		} else if val {
 			entry := YCfgEntry{
 				Value: child.Value,
@@ -215,7 +237,7 @@ func (yc YCfg) Get(key string, settings map[string]string) []YCfgEntry {
 	return entries
 }
 
-func (yc YCfg) GetSlice(key string, settings map[string]string) []YCfgEntry {
+func (yc *YCfg) GetSlice(key string, settings map[string]string) []YCfgEntry {
 	sliceEntries := yc.Get(key, settings)
 	if len(sliceEntries) == 0 {
 		return nil
@@ -242,7 +264,7 @@ func (yc YCfg) GetSlice(key string, settings map[string]string) []YCfgEntry {
 	return result
 }
 
-func (yc YCfg) GetValSlice(
+func (yc *YCfg) GetValSlice(
 	key string, settings map[string]string) []interface{} {
 
 	entries := yc.GetSlice(key, settings)
@@ -258,7 +280,7 @@ func (yc YCfg) GetValSlice(
 	return vals
 }
 
-func (yc YCfg) GetStringSlice(key string,
+func (yc *YCfg) GetStringSlice(key string,
 	settings map[string]string) []YCfgEntry {
 
 	sliceEntries := yc.Get(key, settings)
@@ -287,7 +309,7 @@ func (yc YCfg) GetStringSlice(key string,
 	return result
 }
 
-func (yc YCfg) GetValStringSlice(
+func (yc *YCfg) GetValStringSlice(
 	key string, settings map[string]string) []string {
 
 	entries := yc.GetStringSlice(key, settings)
@@ -305,7 +327,7 @@ func (yc YCfg) GetValStringSlice(
 	return vals
 }
 
-func (yc YCfg) GetValStringSliceNonempty(
+func (yc *YCfg) GetValStringSliceNonempty(
 	key string, settings map[string]string) []string {
 
 	strs := yc.GetValStringSlice(key, settings)
@@ -319,7 +341,7 @@ func (yc YCfg) GetValStringSliceNonempty(
 	return filtered
 }
 
-func (yc YCfg) GetStringMap(
+func (yc *YCfg) GetStringMap(
 	key string, settings map[string]string) map[string]YCfgEntry {
 
 	mapEntries := yc.Get(key, settings)
@@ -344,7 +366,7 @@ func (yc YCfg) GetStringMap(
 	return result
 }
 
-func (yc YCfg) GetValStringMap(
+func (yc *YCfg) GetValStringMap(
 	key string, settings map[string]string) map[string]interface{} {
 
 	entryMap := yc.GetStringMap(key, settings)
@@ -359,7 +381,7 @@ func (yc YCfg) GetValStringMap(
 	return smap
 }
 
-func (yc YCfg) GetFirst(key string, settings map[string]string) (YCfgEntry, bool) {
+func (yc *YCfg) GetFirst(key string, settings map[string]string) (YCfgEntry, bool) {
 	entries := yc.Get(key, settings)
 	if len(entries) == 0 {
 		return YCfgEntry{}, false
@@ -368,7 +390,7 @@ func (yc YCfg) GetFirst(key string, settings map[string]string) (YCfgEntry, bool
 	return entries[0], true
 }
 
-func (yc YCfg) GetFirstVal(key string, settings map[string]string) interface{} {
+func (yc *YCfg) GetFirstVal(key string, settings map[string]string) interface{} {
 	entry, ok := yc.GetFirst(key, settings)
 	if !ok {
 		return nil
@@ -377,7 +399,7 @@ func (yc YCfg) GetFirstVal(key string, settings map[string]string) interface{} {
 	return entry.Value
 }
 
-func (yc YCfg) GetValString(key string, settings map[string]string) string {
+func (yc *YCfg) GetValString(key string, settings map[string]string) string {
 	entry, ok := yc.GetFirst(key, settings)
 	if !ok {
 		return ""
@@ -386,7 +408,7 @@ func (yc YCfg) GetValString(key string, settings map[string]string) string {
 	}
 }
 
-func (yc YCfg) GetValInt(key string, settings map[string]string) int {
+func (yc *YCfg) GetValInt(key string, settings map[string]string) int {
 	entry, ok := yc.GetFirst(key, settings)
 	if !ok {
 		return 0
@@ -395,7 +417,7 @@ func (yc YCfg) GetValInt(key string, settings map[string]string) int {
 	}
 }
 
-func (yc YCfg) GetValBoolDflt(key string, settings map[string]string,
+func (yc *YCfg) GetValBoolDflt(key string, settings map[string]string,
 	dflt bool) bool {
 
 	entry, ok := yc.GetFirst(key, settings)
@@ -406,11 +428,11 @@ func (yc YCfg) GetValBoolDflt(key string, settings map[string]string,
 	}
 }
 
-func (yc YCfg) GetValBool(key string, settings map[string]string) bool {
+func (yc *YCfg) GetValBool(key string, settings map[string]string) bool {
 	return yc.GetValBoolDflt(key, settings, false)
 }
 
-func (yc YCfg) GetStringMapString(key string,
+func (yc *YCfg) GetStringMapString(key string,
 	settings map[string]string) map[string]YCfgEntry {
 
 	mapEntries := yc.Get(key, settings)
@@ -435,7 +457,7 @@ func (yc YCfg) GetStringMapString(key string,
 	return result
 }
 
-func (yc YCfg) GetValStringMapString(key string,
+func (yc *YCfg) GetValStringMapString(key string,
 	settings map[string]string) map[string]string {
 
 	entryMap := yc.GetStringMapString(key, settings)
@@ -465,11 +487,15 @@ func (node *YCfgNode) FullName() string {
 	return strings.Join(tokens, ".")
 }
 
-func (yc YCfg) Delete(name string) {
-	delete(yc, name)
+func (yc *YCfg) Delete(key string) {
+	delete(yc.tree, key)
+}
+
+func (yc *YCfg) Clear() {
+	yc.tree = YCfgTree{}
 }
 
-func (yc YCfg) Traverse(cb func(node *YCfgNode, depth int)) {
+func (yc *YCfg) Traverse(cb func(node *YCfgNode, depth int)) {
 	var traverseLevel func(
 		node *YCfgNode,
 		cb func(node *YCfgNode, depth int),
@@ -486,12 +512,12 @@ func (yc YCfg) Traverse(cb func(node *YCfgNode, depth int)) {
 		}
 	}
 
-	for _, n := range yc {
+	for _, n := range yc.tree {
 		traverseLevel(n, cb, 0)
 	}
 }
 
-func (yc YCfg) AllSettings() map[string]interface{} {
+func (yc *YCfg) AllSettings() map[string]interface{} {
 	settings := map[string]interface{}{}
 
 	yc.Traverse(func(node *YCfgNode, depth int) {
@@ -503,7 +529,7 @@ func (yc YCfg) AllSettings() map[string]interface{} {
 	return settings
 }
 
-func (yc YCfg) AllSettingsAsStrings() map[string]string {
+func (yc *YCfg) AllSettingsAsStrings() map[string]string {
 	settings := yc.AllSettings()
 	smap := make(map[string]string, len(settings))
 	for k, v := range settings {
@@ -513,8 +539,8 @@ func (yc YCfg) AllSettingsAsStrings() map[string]string {
 	return smap
 }
 
-func (yc YCfg) String() string {
-	lines := make([]string, 0, len(yc))
+func (yc *YCfg) String() string {
+	lines := make([]string, 0, len(yc.tree))
 	yc.Traverse(func(node *YCfgNode, depth int) {
 		line := strings.Repeat(" ", depth*4) + node.Name
 		if node.Value != nil {