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:31 UTC

[mynewt-newt] branch master updated (244753a -> fc6fb5c)

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

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


    from 244753a  sysinit: Don't use unintialized result on failure
     new 0934cdf  Move `OneTimeWarning()` to util package
     new 8d32a7a  ycfg: Add name string
     new fc6fb5c  Merge conflicting dependency conditionals

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 newt/builder/depgraph.go      |   5 +-
 newt/cli/target_cmds.go       |   3 +-
 newt/downloader/downloader.go |   3 +-
 newt/install/install.go       |   8 +--
 newt/newtutil/newtutil.go     |  27 ++++------
 newt/parse/parse.go           |  34 +++++++++++--
 newt/pkg/bsp_package.go       |  14 ++++--
 newt/pkg/localpackage.go      |  42 ++++++++--------
 newt/project/project.go       |   4 +-
 newt/repo/version.go          |   6 +--
 newt/resolve/resolve.go       |  85 ++++++++++++++++++++++++++++---
 newt/settings/settings.go     |   9 ++--
 newt/syscfg/restrict.go       |   4 +-
 newt/target/target.go         |  23 +++++----
 newt/ycfg/ycfg.go             | 114 ++++++++++++++++++++++++++----------------
 util/util.go                  |  15 ++++++
 16 files changed, 267 insertions(+), 129 deletions(-)


[mynewt-newt] 03/03: Merge conflicting dependency conditionals

Posted by cc...@apache.org.
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 fc6fb5c26ab53d1a4b6d40be89f4cd8091d2d39c
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Wed Nov 7 17:33:55 2018 -0800

    Merge conflicting dependency conditionals
    
    This commit addresses the following example:
    
        pkg.deps.FOO:
            - my_pkg
        pkg.deps.BAR:
            - my_pkg
    
    This package has two conflicting conditional dependencies.
    
    Before this commit, newt would only process one of the dependencies, and
    it did so in an inconsistent order.  So, the build would end up with one
    or the other of the dependencies, but never both.
    
    Now, newt merges such conflicting conditional dependencies into a single
    dependency.  The resulting dependency is conditional on the union of all
    the sub expreessions.  Newt would (internally) convert the above example
    to:
    
        pkg.deps.'(FOO) || (BAR)'
            - my_pkg
---
 newt/builder/depgraph.go |  5 +--
 newt/parse/parse.go      | 34 ++++++++++++++++---
 newt/resolve/resolve.go  | 85 ++++++++++++++++++++++++++++++++++++++++++++----
 3 files changed, 111 insertions(+), 13 deletions(-)

diff --git a/newt/builder/depgraph.go b/newt/builder/depgraph.go
index ba12d3c..165efef 100644
--- a/newt/builder/depgraph.go
+++ b/newt/builder/depgraph.go
@@ -118,8 +118,9 @@ func depString(dep *resolve.ResolveDep) string {
 		reasons = append(reasons, fmt.Sprintf("api:%s", dep.Api))
 	}
 
-	if dep.Expr != "" {
-		reasons = append(reasons, fmt.Sprintf("syscfg:%s", dep.Expr))
+	exprStr := dep.ExprString()
+	if exprStr != "" {
+		reasons = append(reasons, fmt.Sprintf("syscfg:%s", exprStr))
 	}
 
 	if len(reasons) > 0 {
diff --git a/newt/parse/parse.go b/newt/parse/parse.go
index f6aeba0..89e1371 100644
--- a/newt/parse/parse.go
+++ b/newt/parse/parse.go
@@ -554,6 +554,21 @@ func Eval(expr *Node, settings map[string]string) (bool, error) {
 	}
 }
 
+func lexAndParse(expr string) (*Node, error) {
+	tokens, err := Lex(expr)
+	if err != nil {
+		return nil, err
+	}
+
+	n, err := Parse(tokens)
+	if err != nil {
+		return nil, util.FmtNewtError("error parsing [%s]: %s",
+			expr, err.Error())
+	}
+
+	return n, nil
+}
+
 // Parses and evaluates string containing a syscfg expression.
 //
 // @param expr                  The expression to parse.
@@ -561,18 +576,27 @@ func Eval(expr *Node, settings map[string]string) (bool, error) {
 //
 // @return bool                 Whether the expression evaluates to true.
 func ParseAndEval(expr string, settings map[string]string) (bool, error) {
-	tokens, err := Lex(expr)
+	n, err := lexAndParse(expr)
 	if err != nil {
 		return false, err
 	}
 
-	n, err := Parse(tokens)
+	v, err := Eval(n, settings)
+	return v, err
+}
+
+// Parses an expression and converts it to its normalized text form.
+func NormalizeExpr(expr string) (string, error) {
+	n, err := lexAndParse(expr)
 	if err != nil {
-		return false, fmt.Errorf("error parsing [%s]: %s\n", expr, err.Error())
+		return "", err
 	}
 
-	v, err := Eval(n, settings)
-	return v, err
+	if n == nil {
+		return "", nil
+	}
+
+	return n.String(), nil
 }
 
 // Evaluates the truthfulness of a text expression.
diff --git a/newt/resolve/resolve.go b/newt/resolve/resolve.go
index ef13e6a..46e6294 100644
--- a/newt/resolve/resolve.go
+++ b/newt/resolve/resolve.go
@@ -28,6 +28,7 @@ import (
 
 	"mynewt.apache.org/newt/newt/flash"
 	"mynewt.apache.org/newt/newt/logcfg"
+	"mynewt.apache.org/newt/newt/parse"
 	"mynewt.apache.org/newt/newt/pkg"
 	"mynewt.apache.org/newt/newt/project"
 	"mynewt.apache.org/newt/newt/syscfg"
@@ -77,8 +78,8 @@ type ResolveDep struct {
 	// Name of API that generated the dependency; "" if a hard dependency.
 	Api string
 
-	// Text of syscfg expression that generated this dependency; "" for none.
-	Expr string
+	// Set of syscfg expressions that generated this dependency.
+	ExprMap map[string]struct{}
 }
 
 type ResolvePackage struct {
@@ -175,7 +176,48 @@ func NewResolvePkg(lpkg *pkg.LocalPackage) *ResolvePackage {
 	}
 }
 
-func (r *Resolver) resolveDep(dep *pkg.Dependency, depender string) (*pkg.LocalPackage, error) {
+// Creates an expression string from all the conditionals associated with the
+// dependency.  The resulting expression is the union of all sub expressions.
+// For example:
+//     pkg.deps.FOO:
+//         - my_pkg
+//     pkg.deps.BAR:
+//         - my_pkg
+//
+// The expression string for the `my_pkg` dependency is:
+//     (FOO) || (BAR)
+func (rdep *ResolveDep) ExprString() string {
+	// If there is an unconditional dependency, the conditional dependencies
+	// can be ignored.
+	if _, ok := rdep.ExprMap[""]; ok {
+		return ""
+	}
+
+	exprs := make([]string, 0, len(rdep.ExprMap))
+	for expr, _ := range rdep.ExprMap {
+		exprs = append(exprs, expr)
+	}
+
+	// The union of one object is itself.
+	if len(exprs) == 1 {
+		return exprs[0]
+	}
+
+	// Sort all the subexpressions and OR them together.
+	sort.Strings(exprs)
+	s := ""
+	for i, expr := range exprs {
+		if i != 0 {
+			s += fmt.Sprintf(" || ")
+		}
+		s += fmt.Sprintf("(%s)", expr)
+	}
+	return s
+}
+
+func (r *Resolver) resolveDep(dep *pkg.Dependency,
+	depender string) (*pkg.LocalPackage, error) {
+
 	proj := project.GetProject()
 
 	if proj.ResolveDependency(dep) == nil {
@@ -193,16 +235,47 @@ func (rpkg *ResolvePackage) AddDep(
 	depPkg *ResolvePackage, api string, expr string) bool {
 
 	if dep := rpkg.Deps[depPkg]; dep != nil {
+		// This package already depends on dep.  If the conditional expression
+		// is new, or if the API string is different, then the existing
+		// dependency needs to be updated with the new information.  Otherwise,
+		// ignore the duplicate.
+
+		// Determine if this is a new conditional expression.
+		oldExpr := dep.ExprString()
+
+		norm, err := parse.NormalizeExpr(expr)
+		if err != nil {
+			panic("invalid expression, should have been caught earlier: " +
+				err.Error())
+		}
+
+		dep.ExprMap[norm] = struct{}{}
+		merged := dep.ExprString()
+
+		changed := false
+
+		if oldExpr != merged {
+			log.Debugf("Package %s has conflicting dependencies on %s: "+
+				"old=`%s` new=`%s`; merging them into a single conditional: "+
+				"`%s`",
+				rpkg.Lpkg.FullName(), dep.Rpkg.Lpkg.FullName(),
+				oldExpr, expr, merged)
+			changed = true
+		}
+
 		if dep.Api != "" && api == "" {
 			dep.Api = api
-		} else {
-			return false
+			changed = true
 		}
+
+		return changed
 	} else {
 		rpkg.Deps[depPkg] = &ResolveDep{
 			Rpkg: depPkg,
 			Api:  api,
-			Expr: expr,
+			ExprMap: map[string]struct{}{
+				expr: struct{}{},
+			},
 		}
 	}
 


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

Posted by cc...@apache.org.
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 {


[mynewt-newt] 01/03: Move `OneTimeWarning()` to util package

Posted by cc...@apache.org.
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 0934cdf5a99545e593e6d81b1eeb6b3bce8ad6e8
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Wed Nov 7 17:16:37 2018 -0800

    Move `OneTimeWarning()` to util package
    
    This function used to be in the newtutil package.  Keeping it in
    newtutil leads to circular dependency issues: ycfg needs OneTimeWarning,
    but newtutil requires ycfg.
---
 newt/downloader/downloader.go |  3 +--
 newt/install/install.go       |  8 ++++----
 newt/newtutil/newtutil.go     | 22 ++++------------------
 newt/project/project.go       |  4 ++--
 newt/repo/version.go          |  6 +++---
 newt/syscfg/restrict.go       |  4 ++--
 util/util.go                  | 15 +++++++++++++++
 7 files changed, 31 insertions(+), 31 deletions(-)

diff --git a/newt/downloader/downloader.go b/newt/downloader/downloader.go
index 02f54fa..60c2bd6 100644
--- a/newt/downloader/downloader.go
+++ b/newt/downloader/downloader.go
@@ -30,7 +30,6 @@ import (
 
 	log "github.com/Sirupsen/logrus"
 
-	"mynewt.apache.org/newt/newt/newtutil"
 	"mynewt.apache.org/newt/newt/settings"
 	"mynewt.apache.org/newt/util"
 )
@@ -421,7 +420,7 @@ func setRemoteUrl(path string, remote string, url string, logCmd bool) error {
 }
 
 func warnWrongOriginUrl(path string, curUrl string, goodUrl string) {
-	newtutil.OneTimeWarning(
+	util.OneTimeWarning(
 		"Repo's \"origin\" remote points to unexpected URL: "+
 			"%s; correcting it to %s.  Repo contents may be incorrect.",
 		curUrl, goodUrl)
diff --git a/newt/install/install.go b/newt/install/install.go
index 7f3d0d5..f09054f 100644
--- a/newt/install/install.go
+++ b/newt/install/install.go
@@ -157,7 +157,7 @@ func detectVersion(r *repo.Repo) (newtutil.RepoVersion, error) {
 			Commit: commit,
 		}
 
-		newtutil.OneTimeWarning(
+		util.OneTimeWarning(
 			"Could not detect version of installed repo \"%s\"; assuming %s",
 			r.Name(), ver.String())
 	}
@@ -292,7 +292,7 @@ func (inst *Installer) inferReqVers(repos []*repo.Repo) error {
 					}
 
 					if ver == nil {
-						newtutil.OneTimeWarning(
+						util.OneTimeWarning(
 							"Could not detect version of requested repo "+
 								"%s:%s; assuming 0.0.0",
 							r.Name(), req.Ver.Commit)
@@ -732,7 +732,7 @@ func verifyRepoDirtyState(repos []*repo.Repo, force bool) error {
 			s += "Specify the `-f` (force) switch to attempt anyway"
 			return util.NewNewtError(s)
 		} else {
-			newtutil.OneTimeWarning("%s", s)
+			util.OneTimeWarning("%s", s)
 		}
 	}
 
@@ -749,7 +749,7 @@ func verifyNewtCompat(repos []*repo.Repo, vm deprepo.VersionMap) error {
 
 		switch code {
 		case compat.NEWT_COMPAT_WARN:
-			newtutil.OneTimeWarning("%s", msg)
+			util.OneTimeWarning("%s", msg)
 		case compat.NEWT_COMPAT_ERROR:
 			errors = append(errors, msg)
 		}
diff --git a/newt/newtutil/newtutil.go b/newt/newtutil/newtutil.go
index c377bf3..96795cd 100644
--- a/newt/newtutil/newtutil.go
+++ b/newt/newtutil/newtutil.go
@@ -178,17 +178,17 @@ func MakeTempRepoDir() (string, error) {
 func ReadConfigPath(path string) (ycfg.YCfg, error) {
 	file, err := ioutil.ReadFile(path)
 	if err != nil {
-		return nil, util.NewNewtError(fmt.Sprintf("Error reading %s: %s",
-			path, err.Error()))
+		return ycfg.YCfg{}, util.FmtNewtError("Error reading %s: %s",
+			path, err.Error())
 	}
 
 	settings := map[string]interface{}{}
 	if err := yaml.Unmarshal(file, &settings); err != nil {
-		return nil, util.FmtNewtError("Failure parsing \"%s\": %s",
+		return ycfg.YCfg{}, util.FmtNewtError("Failure parsing \"%s\": %s",
 			path, err.Error())
 	}
 
-	return ycfg.NewYCfg(settings)
+	return ycfg.NewYCfg(path, settings)
 }
 
 // Read in the configuration file specified by name, in path
@@ -201,17 +201,3 @@ func ReadConfig(dir string, filename string) (ycfg.YCfg, error) {
 func YCfgToYaml(yc ycfg.YCfg) string {
 	return yaml.MapToYaml(yc.AllSettings())
 }
-
-// Keeps track of warnings that have already been reported.
-// [warning-text] => struct{}
-var warnings = map[string]struct{}{}
-
-// Displays the specified warning if it has not been displayed yet.
-func OneTimeWarning(text string, args ...interface{}) {
-	if _, ok := warnings[text]; !ok {
-		warnings[text] = struct{}{}
-
-		body := fmt.Sprintf(text, args...)
-		util.StatusMessage(util.VERBOSITY_QUIET, "WARNING: %s\n", body)
-	}
-}
diff --git a/newt/project/project.go b/newt/project/project.go
index 34adc7b..2de2aec 100644
--- a/newt/project/project.go
+++ b/newt/project/project.go
@@ -392,7 +392,7 @@ func (proj *Project) checkNewtVer() error {
 	case compat.NEWT_COMPAT_GOOD:
 		return nil
 	case compat.NEWT_COMPAT_WARN:
-		newtutil.OneTimeWarning("%s", msg)
+		util.OneTimeWarning("%s", msg)
 		return nil
 	case compat.NEWT_COMPAT_ERROR:
 		return util.NewNewtError(msg)
@@ -496,7 +496,7 @@ func (proj *Project) verifyNewtCompat() error {
 			switch code {
 			case compat.NEWT_COMPAT_GOOD:
 			case compat.NEWT_COMPAT_WARN:
-				newtutil.OneTimeWarning("%s", msg)
+				util.OneTimeWarning("%s", msg)
 			case compat.NEWT_COMPAT_ERROR:
 				errors = append(errors, msg)
 			}
diff --git a/newt/repo/version.go b/newt/repo/version.go
index d8dbfa2..89ecfac 100644
--- a/newt/repo/version.go
+++ b/newt/repo/version.go
@@ -392,7 +392,7 @@ func (r *Repo) inferVersion(commit string, vyVer *newtutil.RepoVersion) (
 				}
 			}
 
-			newtutil.OneTimeWarning(
+			util.OneTimeWarning(
 				"Version mismatch in %s:%s; repository.yml:%s, version.yml:%s",
 				r.Name(), commit, versString(ryVers), vyVer.String())
 		} else {
@@ -463,11 +463,11 @@ func (r *Repo) NonInstalledVersion(
 
 	if ver == nil {
 		if versionYmlErr == versionYmlMissing {
-			newtutil.OneTimeWarning(
+			util.OneTimeWarning(
 				"%s:%s does not contain a `version.yml` file.",
 				r.Name(), commit)
 		} else if versionYmlErr == versionYmlBad {
-			newtutil.OneTimeWarning(
+			util.OneTimeWarning(
 				"%s:%s contains a malformed `version.yml` file.",
 				r.Name(), commit)
 		}
diff --git a/newt/syscfg/restrict.go b/newt/syscfg/restrict.go
index fe1ca83..ebfbffd 100644
--- a/newt/syscfg/restrict.go
+++ b/newt/syscfg/restrict.go
@@ -59,8 +59,8 @@ import (
 
 	log "github.com/Sirupsen/logrus"
 
-	"mynewt.apache.org/newt/newt/newtutil"
 	"mynewt.apache.org/newt/newt/parse"
+	"mynewt.apache.org/newt/util"
 )
 
 type CfgRestrictionCode int
@@ -201,7 +201,7 @@ func (cfg *Cfg) restrictionMet(
 
 		val, err := parse.ParseAndEval(expr, settings)
 		if err != nil {
-			newtutil.OneTimeWarning(
+			util.OneTimeWarning(
 				"Ignoring illegal expression for setting \"%s\": "+
 					"`%s` %s\n", r.BaseSetting, r.Expr, err.Error())
 			return true
diff --git a/util/util.go b/util/util.go
index d3abfc3..fa9098b 100644
--- a/util/util.go
+++ b/util/util.go
@@ -713,3 +713,18 @@ func FileContains(contents []byte, path string) (bool, error) {
 	rc := bytes.Compare(oldSrc, contents)
 	return rc == 0, nil
 }
+
+// Keeps track of warnings that have already been reported.
+// [warning-text] => struct{}
+var warnings = map[string]struct{}{}
+
+// Displays the specified warning if it has not been displayed yet.
+func OneTimeWarning(text string, args ...interface{}) {
+	body := fmt.Sprintf(text, args...)
+	if _, ok := warnings[body]; !ok {
+		warnings[body] = struct{}{}
+
+		body := fmt.Sprintf(text, args...)
+		StatusMessage(VERBOSITY_QUIET, "WARNING: %s\n", body)
+	}
+}