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 2019/12/18 00:04:45 UTC

[mynewt-newt] 03/05: ycfg: Indicate parse failures in returned error

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 d0c80912591a31ac8bff53f4147233f9cf48b811
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Thu Nov 7 10:37:24 2019 -0800

    ycfg: Indicate parse failures in returned error
    
    Prior to this commit, when a YCfg Get function encountered a parse
    error, it printed a warning to the console.
    
    After commit, parse errors are returned in an error object instead.
    
    See <https://github.com/apache/mynewt-newt/pull/350> for more
    information.
---
 newt/builder/buildpackage.go  |  25 +++--
 newt/cli/target_cmds.go       |  15 ++-
 newt/cli/vars.go              |   2 +-
 newt/compat/compat.go         |   2 +-
 newt/downloader/downloader.go |   2 +-
 newt/logcfg/logcfg.go         |   3 +-
 newt/manifest/manifest.go     |   3 +-
 newt/mfg/decode.go            |  11 ++-
 newt/pkg/bsp_package.go       |  14 +--
 newt/pkg/localpackage.go      |  32 ++++---
 newt/project/project.go       |   9 +-
 newt/repo/repo.go             |   6 +-
 newt/repo/version.go          |   3 +-
 newt/resolve/expr.go          |   2 +-
 newt/settings/settings.go     |   2 +-
 newt/syscfg/syscfg.go         |   9 +-
 newt/target/target.go         |  20 ++--
 newt/toolchain/compiler.go    |  27 +++---
 newt/ycfg/ycfg.go             | 210 ++++++++++++++++++++++++++++++------------
 19 files changed, 262 insertions(+), 135 deletions(-)

diff --git a/newt/builder/buildpackage.go b/newt/builder/buildpackage.go
index c4f2698..8e93c75 100644
--- a/newt/builder/buildpackage.go
+++ b/newt/builder/buildpackage.go
@@ -123,7 +123,10 @@ func expandFlags(flags []string) {
 // returned.
 func (bpkg *BuildPackage) BuildProfile(b *Builder) string {
 	settings := b.cfg.AllSettingsForLpkg(bpkg.rpkg.Lpkg)
-	return bpkg.rpkg.Lpkg.PkgY.GetValString("pkg.build_profile", settings)
+
+	profile, _ := bpkg.rpkg.Lpkg.PkgY.GetValString("pkg.build_profile", settings)
+
+	return profile
 }
 
 func (bpkg *BuildPackage) CompilerInfo(
@@ -140,16 +143,16 @@ func (bpkg *BuildPackage) CompilerInfo(
 
 	// Read each set of flags and expand repo designators ("@<repo-name>") into
 	// paths.
-	ci.Cflags = bpkg.rpkg.Lpkg.PkgY.GetValStringSlice("pkg.cflags", settings)
+	ci.Cflags, _ = bpkg.rpkg.Lpkg.PkgY.GetValStringSlice("pkg.cflags", settings)
 	expandFlags(ci.Cflags)
 
-	ci.CXXflags = bpkg.rpkg.Lpkg.PkgY.GetValStringSlice("pkg.cxxflags", settings)
+	ci.CXXflags, _ = bpkg.rpkg.Lpkg.PkgY.GetValStringSlice("pkg.cxxflags", settings)
 	expandFlags(ci.CXXflags)
 
-	ci.Lflags = bpkg.rpkg.Lpkg.PkgY.GetValStringSlice("pkg.lflags", settings)
+	ci.Lflags, _ = bpkg.rpkg.Lpkg.PkgY.GetValStringSlice("pkg.lflags", settings)
 	expandFlags(ci.Lflags)
 
-	ci.Aflags = bpkg.rpkg.Lpkg.PkgY.GetValStringSlice("pkg.aflags", settings)
+	ci.Aflags, _ = bpkg.rpkg.Lpkg.PkgY.GetValStringSlice("pkg.aflags", settings)
 	expandFlags(ci.Aflags)
 
 	// Package-specific injected settings get specified as C flags on the
@@ -159,7 +162,10 @@ func (bpkg *BuildPackage) CompilerInfo(
 	}
 
 	ci.IgnoreFiles = []*regexp.Regexp{}
-	ignPats := bpkg.rpkg.Lpkg.PkgY.GetValStringSlice("pkg.ign_files", settings)
+
+	ignPats, _ := bpkg.rpkg.Lpkg.PkgY.GetValStringSlice(
+		"pkg.ign_files", settings)
+
 	for _, str := range ignPats {
 		re, err := regexp.Compile(str)
 		if err != nil {
@@ -170,7 +176,10 @@ func (bpkg *BuildPackage) CompilerInfo(
 	}
 
 	ci.IgnoreDirs = []*regexp.Regexp{}
-	ignPats = bpkg.rpkg.Lpkg.PkgY.GetValStringSlice("pkg.ign_dirs", settings)
+
+	ignPats, _ = bpkg.rpkg.Lpkg.PkgY.GetValStringSlice(
+		"pkg.ign_dirs", settings)
+
 	for _, str := range ignPats {
 		re, err := regexp.Compile(str)
 		if err != nil {
@@ -180,7 +189,7 @@ func (bpkg *BuildPackage) CompilerInfo(
 		ci.IgnoreDirs = append(ci.IgnoreDirs, re)
 	}
 
-	bpkg.SourceDirectories = bpkg.rpkg.Lpkg.PkgY.GetValStringSlice(
+	bpkg.SourceDirectories, _ = bpkg.rpkg.Lpkg.PkgY.GetValStringSlice(
 		"pkg.src_dirs", settings)
 
 	includePaths, err := bpkg.recursiveIncludePaths(b)
diff --git a/newt/cli/target_cmds.go b/newt/cli/target_cmds.go
index fa31395..11f3000 100644
--- a/newt/cli/target_cmds.go
+++ b/newt/cli/target_cmds.go
@@ -79,7 +79,8 @@ func targetContainsUserFiles(t *target.Target) (bool, error) {
 }
 
 func pkgVarSliceString(pack *pkg.LocalPackage, key string) string {
-	vals := pack.PkgY.GetValStringSlice(key, nil)
+	vals, _ := pack.PkgY.GetValStringSlice(key, nil)
+
 	sort.Strings(vals)
 	var buffer bytes.Buffer
 	for _, v := range vals {
@@ -92,7 +93,7 @@ func pkgVarSliceString(pack *pkg.LocalPackage, key string) string {
 //Process amend command for syscfg target variable
 func amendSysCfg(value string, t *target.Target) error {
 	// Get the current syscfg.vals name-value pairs
-	sysVals := t.Package().SyscfgY.GetValStringMapString("syscfg.vals", nil)
+	sysVals, _ := t.Package().SyscfgY.GetValStringMapString("syscfg.vals", nil)
 
 	// Convert the input syscfg into name-value pairs
 	amendSysVals, err := syscfg.KeyValueFromStr(value)
@@ -125,7 +126,9 @@ func amendSysCfg(value string, t *target.Target) error {
 //Process amend command for aflags, cflags, cxxflags, and lflags target variables.
 func amendBuildFlags(kv []string, t *target.Target) error {
 	pkgVar := "pkg." + kv[0]
-	curFlags := t.Package().PkgY.GetValStringSlice(pkgVar, nil)
+
+	curFlags, _ := t.Package().PkgY.GetValStringSlice(pkgVar, nil)
+
 	amendFlags := strings.Fields(kv[1])
 
 	newFlags := []string{}
@@ -217,8 +220,10 @@ func targetShowCmd(cmd *cobra.Command, args []string) {
 		}
 
 		// A few variables come from the base package rather than the target.
-		kvPairs["syscfg"] = syscfg.KeyValueToStr(
-			target.Package().SyscfgY.GetValStringMapString("syscfg.vals", nil))
+		scfg, _ := target.Package().SyscfgY.GetValStringMapString(
+			"syscfg.vals", nil)
+		kvPairs["syscfg"] = syscfg.KeyValueToStr(scfg)
+
 		kvPairs["cflags"] = pkgVarSliceString(target.Package(), "pkg.cflags")
 		kvPairs["cxxflags"] = pkgVarSliceString(target.Package(), "pkg.cxxflags")
 		kvPairs["lflags"] = pkgVarSliceString(target.Package(), "pkg.lflags")
diff --git a/newt/cli/vars.go b/newt/cli/vars.go
index ffde730..79098ce 100644
--- a/newt/cli/vars.go
+++ b/newt/cli/vars.go
@@ -58,7 +58,7 @@ func settingValues(settingName string) ([]string, error) {
 
 	packs := project.GetProject().PackagesOfType(-1)
 	for _, pack := range packs {
-		settings :=
+		settings, _ :=
 			pack.(*pkg.LocalPackage).PkgY.GetValStringSlice(settingName, nil)
 
 		for _, setting := range settings {
diff --git a/newt/compat/compat.go b/newt/compat/compat.go
index 1e3c363..f86144d 100644
--- a/newt/compat/compat.go
+++ b/newt/compat/compat.go
@@ -106,7 +106,7 @@ func ParseNcTable(strMap map[string]string) (NewtCompatTable, error) {
 
 func ReadNcMap(yc ycfg.YCfg) (NewtCompatMap, error) {
 	mp := NewtCompatMap{}
-	ncMap := yc.GetValStringMap("repo.newt_compatibility", nil)
+	ncMap, _ := yc.GetValStringMap("repo.newt_compatibility", nil)
 
 	for k, v := range ncMap {
 		repoVer, err := newtutil.ParseVersion(k)
diff --git a/newt/downloader/downloader.go b/newt/downloader/downloader.go
index 8b3a607..375ba3e 100644
--- a/newt/downloader/downloader.go
+++ b/newt/downloader/downloader.go
@@ -1055,7 +1055,7 @@ func LoadDownloader(repoName string, repoVars map[string]string) (
 		// Alternatively, the user can put security material in
 		// $HOME/.newt/repos.yml.
 		newtrc := settings.Newtrc()
-		privRepo := newtrc.GetValStringMapString("repository."+repoName, nil)
+		privRepo, _ := newtrc.GetValStringMapString("repository."+repoName, nil)
 		if privRepo != nil {
 			if gd.Login == "" {
 				gd.Login = privRepo["login"]
diff --git a/newt/logcfg/logcfg.go b/newt/logcfg/logcfg.go
index 62e9bf9..1516732 100644
--- a/newt/logcfg/logcfg.go
+++ b/newt/logcfg/logcfg.go
@@ -157,7 +157,8 @@ func parseOneLog(name string, lpkg *pkg.LocalPackage, logMapItf interface{},
 // are read from the `syscfg.logs` map in the package's `syscfg.yml` file.
 func (lcfg *LCfg) readOnePkg(lpkg *pkg.LocalPackage, cfg *syscfg.Cfg) {
 	lsettings := cfg.AllSettingsForLpkg(lpkg)
-	logMaps := lpkg.SyscfgY.GetValStringMap("syscfg.logs", lsettings)
+	logMaps, _ := lpkg.SyscfgY.GetValStringMap("syscfg.logs", lsettings)
+
 	for name, logMapItf := range logMaps {
 		cl, err := parseOneLog(name, lpkg, logMapItf, cfg)
 		if err != nil {
diff --git a/newt/manifest/manifest.go b/newt/manifest/manifest.go
index 51cf1e5..d0311fc 100644
--- a/newt/manifest/manifest.go
+++ b/newt/manifest/manifest.go
@@ -303,8 +303,9 @@ func CreateManifest(opts ManifestCreateOpts) (manifest.Manifest, error) {
 	for _, k := range keys {
 		m.TgtVars = append(m.TgtVars, k+"="+vars[k])
 	}
-	syscfgKV := t.GetTarget().Package().SyscfgY.GetValStringMapString(
+	syscfgKV, _ := t.GetTarget().Package().SyscfgY.GetValStringMapString(
 		"syscfg.vals", nil)
+
 	if len(syscfgKV) > 0 {
 		tgtSyscfg := fmt.Sprintf("target.syscfg=%s",
 			syscfg.KeyValueToStr(syscfgKV))
diff --git a/newt/mfg/decode.go b/newt/mfg/decode.go
index ec3ff30..9e33fa2 100644
--- a/newt/mfg/decode.go
+++ b/newt/mfg/decode.go
@@ -326,7 +326,8 @@ func decodeMeta(
 func decodeMfg(yc ycfg.YCfg) (DecodedMfg, error) {
 	dm := DecodedMfg{}
 
-	yamlTargets := yc.GetValSlice("mfg.targets", nil)
+	yamlTargets, _ := yc.GetValSlice("mfg.targets", nil)
+
 	if yamlTargets != nil {
 		for _, yamlTarget := range yamlTargets {
 			t, err := decodeTarget(yamlTarget)
@@ -338,14 +339,15 @@ func decodeMfg(yc ycfg.YCfg) (DecodedMfg, error) {
 		}
 	}
 
-	dm.Bsp = yc.GetValString("mfg.bsp", nil)
+	dm.Bsp, _ = yc.GetValString("mfg.bsp", nil)
 
 	if len(dm.Targets) == 0 && dm.Bsp == "" {
 		return dm, util.FmtNewtError(
 			"\"mfg.bsp\" field required for mfg images without any targets")
 	}
 
-	itf := yc.GetValSlice("mfg.raw", nil)
+	itf, _ := yc.GetValSlice("mfg.raw", nil)
+
 	slice := cast.ToSlice(itf)
 	if slice != nil {
 		for i, yamlRaw := range slice {
@@ -358,7 +360,8 @@ func decodeMfg(yc ycfg.YCfg) (DecodedMfg, error) {
 		}
 	}
 
-	yamlMeta := yc.GetValStringMap("mfg.meta", nil)
+	yamlMeta, _ := yc.GetValStringMap("mfg.meta", nil)
+
 	if yamlMeta != nil {
 		meta, err := decodeMeta(yamlMeta)
 		if err != nil {
diff --git a/newt/pkg/bsp_package.go b/newt/pkg/bsp_package.go
index c8a7ef1..bb06346 100644
--- a/newt/pkg/bsp_package.go
+++ b/newt/pkg/bsp_package.go
@@ -57,7 +57,7 @@ func (bsp *BspPackage) resolvePathSetting(
 
 	proj := interfaces.GetProject()
 
-	val := bsp.BspV.GetValString(key, settings)
+	val, _ := bsp.BspV.GetValString(key, settings)
 	if val == "" {
 		return "", nil
 	}
@@ -78,7 +78,7 @@ func (bsp *BspPackage) resolveLinkerScriptSetting(
 	paths := []string{}
 
 	// Assume config file specifies a list of scripts.
-	vals := bsp.BspV.GetValStringSlice(key, settings)
+	vals, _ := bsp.BspV.GetValStringSlice(key, settings)
 	if vals == nil {
 		// Couldn't read a list of scripts; try to interpret setting as a
 		// single script.
@@ -125,12 +125,12 @@ func (bsp *BspPackage) Reload(settings map[string]string) error {
 	}
 	bsp.AddCfgFilename(bsp.BspYamlPath())
 
-	bsp.CompilerName = bsp.BspV.GetValString("bsp.compiler", settings)
-	bsp.Arch = bsp.BspV.GetValString("bsp.arch", settings)
+	bsp.CompilerName, _ = bsp.BspV.GetValString("bsp.compiler", settings)
+	bsp.Arch, _ = bsp.BspV.GetValString("bsp.arch", settings)
 
-	bsp.ImageOffset = bsp.BspV.GetValInt("bsp.image_offset", settings)
+	bsp.ImageOffset, _ = bsp.BspV.GetValInt("bsp.image_offset", settings)
 
-	bsp.ImagePad = bsp.BspV.GetValInt("bsp.image_pad", settings)
+	bsp.ImagePad, _ = bsp.BspV.GetValInt("bsp.image_pad", settings)
 
 	bsp.LinkerScripts, err = bsp.resolveLinkerScriptSetting(
 		settings, "bsp.linkerscript")
@@ -167,7 +167,7 @@ func (bsp *BspPackage) Reload(settings map[string]string) error {
 			"(bsp.arch)")
 	}
 
-	ymlFlashMap := bsp.BspV.GetValStringMap("bsp.flash_map", settings)
+	ymlFlashMap, _ := bsp.BspV.GetValStringMap("bsp.flash_map", settings)
 	if ymlFlashMap == nil {
 		return util.NewNewtError("BSP does not specify a flash map " +
 			"(bsp.flash_map)")
diff --git a/newt/pkg/localpackage.go b/newt/pkg/localpackage.go
index bd48455..034c310 100644
--- a/newt/pkg/localpackage.go
+++ b/newt/pkg/localpackage.go
@@ -200,10 +200,10 @@ func (pkg *LocalPackage) AddCfgFilename(cfgFilename string) {
 func (pkg *LocalPackage) readDesc(yc ycfg.YCfg) (*PackageDesc, error) {
 	pdesc := &PackageDesc{}
 
-	pdesc.Author = yc.GetValString("pkg.author", nil)
-	pdesc.Homepage = yc.GetValString("pkg.homepage", nil)
-	pdesc.Description = yc.GetValString("pkg.description", nil)
-	pdesc.Keywords = yc.GetValStringSlice("pkg.keywords", nil)
+	pdesc.Author, _ = yc.GetValString("pkg.author", nil)
+	pdesc.Homepage, _ = yc.GetValString("pkg.homepage", nil)
+	pdesc.Description, _ = yc.GetValString("pkg.description", nil)
+	pdesc.Keywords, _ = yc.GetValStringSlice("pkg.keywords", nil)
 
 	return pdesc, nil
 }
@@ -211,7 +211,8 @@ func (pkg *LocalPackage) readDesc(yc ycfg.YCfg) (*PackageDesc, error) {
 func (pkg *LocalPackage) sequenceString(key string) string {
 	var buffer bytes.Buffer
 
-	for _, f := range pkg.PkgY.GetValStringSlice(key, nil) {
+	vals, _ := pkg.PkgY.GetValStringSlice(key, nil)
+	for _, f := range vals {
 		buffer.WriteString("    - " + yaml.EscapeString(f) + "\n")
 	}
 
@@ -299,7 +300,7 @@ func (pkg *LocalPackage) Load() error {
 	pkg.AddCfgFilename(pkg.PkgYamlPath())
 
 	// Set package name from the package
-	pkg.name = pkg.PkgY.GetValString("pkg.name", nil)
+	pkg.name, _ = pkg.PkgY.GetValString("pkg.name", nil)
 	if pkg.name == "" {
 		return util.FmtNewtError(
 			"Package \"%s\" missing \"pkg.name\" field in its `pkg.yml` file",
@@ -312,7 +313,7 @@ func (pkg *LocalPackage) Load() error {
 				"`pkg.yml` file (pkg.name=%s)", pkg.basePath, pkg.name)
 	}
 
-	typeString := pkg.PkgY.GetValString("pkg.type", nil)
+	typeString, _ := pkg.PkgY.GetValString("pkg.type", nil)
 	pkg.packageType = PACKAGE_TYPE_LIB
 	if len(typeString) > 0 {
 		found := false
@@ -332,7 +333,7 @@ func (pkg *LocalPackage) Load() error {
 	}
 
 	if pkg.packageType == PACKAGE_TYPE_TRANSIENT {
-		n := pkg.PkgY.GetValString("pkg.link", nil)
+		n, _ := pkg.PkgY.GetValString("pkg.link", nil)
 		if len(n) == 0 {
 			return util.FmtNewtError(
 				"Transient package \"%s\" does not specify target "+
@@ -366,7 +367,8 @@ func (pkg *LocalPackage) Load() error {
 func (pkg *LocalPackage) InitFuncs(
 	settings map[string]string) map[string]string {
 
-	return pkg.PkgY.GetValStringMapString("pkg.init", settings)
+	vals, _ := pkg.PkgY.GetValStringMapString("pkg.init", settings)
+	return vals
 }
 
 // DownFuncs retrieves the package's shutdown functions.  The returned map has:
@@ -374,25 +376,29 @@ func (pkg *LocalPackage) InitFuncs(
 func (pkg *LocalPackage) DownFuncs(
 	settings map[string]string) map[string]string {
 
-	return pkg.PkgY.GetValStringMapString("pkg.down", settings)
+	vals, _ := pkg.PkgY.GetValStringMapString("pkg.down", settings)
+	return vals
 }
 
 func (pkg *LocalPackage) PreBuildCmds(
 	settings map[string]string) map[string]string {
 
-	return pkg.PkgY.GetValStringMapString("pkg.pre_build_cmds", settings)
+	vals, _ := pkg.PkgY.GetValStringMapString("pkg.pre_build_cmds", settings)
+	return vals
 }
 
 func (pkg *LocalPackage) PreLinkCmds(
 	settings map[string]string) map[string]string {
 
-	return pkg.PkgY.GetValStringMapString("pkg.pre_link_cmds", settings)
+	vals, _ := pkg.PkgY.GetValStringMapString("pkg.pre_link_cmds", settings)
+	return vals
 }
 
 func (pkg *LocalPackage) PostLinkCmds(
 	settings map[string]string) map[string]string {
 
-	return pkg.PkgY.GetValStringMapString("pkg.post_link_cmds", settings)
+	vals, _ := pkg.PkgY.GetValStringMapString("pkg.post_link_cmds", settings)
+	return vals
 }
 
 func (pkg *LocalPackage) InjectedSettings() map[string]string {
diff --git a/newt/project/project.go b/newt/project/project.go
index 8c40621..93d5a41 100644
--- a/newt/project/project.go
+++ b/newt/project/project.go
@@ -346,7 +346,7 @@ func (proj *Project) loadRepo(name string, fields map[string]string) (
 }
 
 func (proj *Project) checkNewtVer() error {
-	compatSms := proj.yc.GetValStringMapString(
+	compatSms, _ := proj.yc.GetValStringMapString(
 		"project.newt_compatibility", nil)
 
 	// If this project doesn't have a newt compatibility map, just assume there
@@ -517,7 +517,7 @@ func (proj *Project) loadConfig() error {
 	// we need to process it later.
 	proj.yc = yc
 
-	proj.name = yc.GetValString("project.name", nil)
+	proj.name, _ = yc.GetValString("project.name", nil)
 
 	// Local repository always included in initialization
 	r, err := repo.NewLocalRepo(proj.name)
@@ -536,7 +536,8 @@ func (proj *Project) loadConfig() error {
 	for k, _ := range yc.AllSettings() {
 		repoName := strings.TrimPrefix(k, "repository.")
 		if repoName != k {
-			fields := yc.GetValStringMapString(k, nil)
+			fields, _ := yc.GetValStringMapString(k, nil)
+
 			r, err := proj.loadRepo(repoName, fields)
 			if err != nil {
 				// if `repository.yml` does not exist, it is not an error; we
@@ -572,7 +573,7 @@ func (proj *Project) loadConfig() error {
 		return err
 	}
 
-	ignoreDirs := yc.GetValStringSlice("project.ignore_dirs", nil)
+	ignoreDirs, _ := yc.GetValStringSlice("project.ignore_dirs", nil)
 	for _, ignDir := range ignoreDirs {
 		repoName, dirName, err := newtutil.ParsePackageString(ignDir)
 		if err != nil {
diff --git a/newt/repo/repo.go b/newt/repo/repo.go
index 60c6460..96a9d2b 100644
--- a/newt/repo/repo.go
+++ b/newt/repo/repo.go
@@ -450,7 +450,8 @@ func parseRepoDepMap(depName string,
 }
 
 func (r *Repo) readDepRepos(yc ycfg.YCfg) error {
-	depMap := yc.GetValStringMap("repo.deps", nil)
+	depMap, _ := yc.GetValStringMap("repo.deps", nil)
+
 	for depName, repoMapYml := range depMap {
 		rdm, err := parseRepoDepMap(depName, repoMapYml)
 		if err != nil {
@@ -477,7 +478,8 @@ func (r *Repo) Read() error {
 		return err
 	}
 
-	versMap := yc.GetValStringMapString("repo.versions", nil)
+	versMap, _ := yc.GetValStringMapString("repo.versions", nil)
+
 	for versStr, commit := range versMap {
 		log.Debugf("Printing version %s for remote repo %s", versStr, r.name)
 		vers, err := newtutil.ParseRepoVersion(versStr)
diff --git a/newt/repo/version.go b/newt/repo/version.go
index 70f437f..09660a4 100644
--- a/newt/repo/version.go
+++ b/newt/repo/version.go
@@ -315,7 +315,8 @@ func parseVersionYml(path string) (newtutil.RepoVersion, error) {
 		}
 	}
 
-	verString := yc.GetValString("repo.version", nil)
+	verString, _ := yc.GetValString("repo.version", nil)
+
 	if verString == "" {
 		return newtutil.RepoVersion{}, versionYmlBad
 	}
diff --git a/newt/resolve/expr.go b/newt/resolve/expr.go
index 6e72bce..71b282b 100644
--- a/newt/resolve/expr.go
+++ b/newt/resolve/expr.go
@@ -30,7 +30,7 @@ func getExprMapStringSlice(
 	yc ycfg.YCfg, key string, settings map[string]string) (
 	map[*parse.Node][]string, error) {
 
-	entries := yc.GetSlice(key, settings)
+	entries, _ := yc.GetSlice(key, settings)
 	if len(entries) == 0 {
 		return nil, nil
 	}
diff --git a/newt/settings/settings.go b/newt/settings/settings.go
index faa596c..03d0232 100644
--- a/newt/settings/settings.go
+++ b/newt/settings/settings.go
@@ -39,7 +39,7 @@ const NEWTRC_FILENAME string = "newtrc.yml"
 var newtrc *ycfg.YCfg
 
 func processNewtrc(yc ycfg.YCfg) {
-	s := yc.GetValString("escape_shell", nil)
+	s, _ := yc.GetValString("escape_shell", nil)
 	if s != "" {
 		b, err := strconv.ParseBool(s)
 		if err != nil {
diff --git a/newt/syscfg/syscfg.go b/newt/syscfg/syscfg.go
index ec07c4f..4af4591 100644
--- a/newt/syscfg/syscfg.go
+++ b/newt/syscfg/syscfg.go
@@ -538,7 +538,8 @@ func (cfg *Cfg) readDefsOnce(lpkg *pkg.LocalPackage,
 
 	lsettings := cfg.settingsForLpkg(lpkg, settings)
 
-	defs := yc.GetValStringMap("syscfg.defs", lsettings)
+	defs, _ := yc.GetValStringMap("syscfg.defs", lsettings)
+
 	if defs != nil {
 		for k, v := range defs {
 			vals, ok := v.(map[interface{}]interface{})
@@ -602,7 +603,8 @@ func (cfg *Cfg) readRestrictions(lpkg *pkg.LocalPackage,
 	yc := lpkg.SyscfgY
 	lsettings := cfg.settingsForLpkg(lpkg, settings)
 
-	restrictionStrings := yc.GetValStringSlice("syscfg.restrictions", lsettings)
+	restrictionStrings, _ := yc.GetValStringSlice("syscfg.restrictions", lsettings)
+
 	for _, rstring := range restrictionStrings {
 		r, err := readRestriction("", rstring)
 		if err != nil {
@@ -621,7 +623,8 @@ func (cfg *Cfg) readValsOnce(lpkg *pkg.LocalPackage,
 
 	lsettings := cfg.settingsForLpkg(lpkg, settings)
 
-	values := yc.GetValStringMap("syscfg.vals", lsettings)
+	values, _ := yc.GetValStringMap("syscfg.vals", lsettings)
+
 	for k, v := range values {
 		switch v.(type) {
 		case map[interface{}]interface{}, []interface{}:
diff --git a/newt/target/target.go b/newt/target/target.go
index ad458df..e2bf2e0 100644
--- a/newt/target/target.go
+++ b/newt/target/target.go
@@ -88,25 +88,27 @@ func (target *Target) Load(basePkg *pkg.LocalPackage) error {
 
 	target.TargetY = yc
 
-	target.BspName = yc.GetValString("target.bsp", nil)
-	target.AppName = yc.GetValString("target.app", nil)
-	target.LoaderName = yc.GetValString("target.loader", nil)
+	target.BspName, _ = yc.GetValString("target.bsp", nil)
+	target.AppName, _ = yc.GetValString("target.app", nil)
+	target.LoaderName, _ = yc.GetValString("target.loader", nil)
 
-	target.BuildProfile = yc.GetValString("target.build_profile", nil)
+	target.BuildProfile, _ = yc.GetValString("target.build_profile", nil)
 	if target.BuildProfile == "" {
 		target.BuildProfile = DEFAULT_BUILD_PROFILE
 	}
 
 	target.HeaderSize = DEFAULT_HEADER_SIZE
-	if yc.GetValString("target.header_size", nil) != "" {
-		hs, err := strconv.ParseUint(
-			yc.GetValString("target.header_size", nil), 0, 32)
+
+	hsStr, _ := yc.GetValString("target.header_size", nil)
+	if hsStr != "" {
+		hs, err := strconv.ParseUint(hsStr, 0, 32)
 		if err == nil {
 			target.HeaderSize = uint32(hs)
 		}
 	}
 
-	target.KeyFile = yc.GetValString("target.key_file", nil)
+	target.KeyFile, _ = yc.GetValString("target.key_file", nil)
+
 	if target.KeyFile != "" {
 		proj := interfaces.GetProject()
 		path, err := proj.ResolvePath(proj.Path(), target.KeyFile)
@@ -115,7 +117,7 @@ func (target *Target) Load(basePkg *pkg.LocalPackage) error {
 		}
 	}
 
-	target.PkgProfiles = yc.GetValStringMapString(
+	target.PkgProfiles, _ = yc.GetValStringMapString(
 		"target.package_profiles", nil)
 
 	// Note: App not required in the case of unit tests.
diff --git a/newt/toolchain/compiler.go b/newt/toolchain/compiler.go
index 5473fa6..3c644f4 100644
--- a/newt/toolchain/compiler.go
+++ b/newt/toolchain/compiler.go
@@ -277,10 +277,12 @@ func NewCompiler(compilerDir string, dstDir string,
 func loadFlags(yc ycfg.YCfg, settings map[string]string, key string) []string {
 	flags := []string{}
 
-	rawFlags := yc.GetValStringSlice(key, settings)
+	rawFlags, _ := yc.GetValStringSlice(key, settings)
+
 	for _, rawFlag := range rawFlags {
 		if strings.HasPrefix(rawFlag, key) {
-			expandedFlags := yc.GetValStringSlice(rawFlag, settings)
+			expandedFlags, _ := yc.GetValStringSlice(rawFlag, settings)
+
 			flags = append(flags, expandedFlags...)
 		} else {
 			flags = append(flags, strings.Trim(rawFlag, "\n"))
@@ -301,23 +303,24 @@ func (c *Compiler) load(compilerDir string, buildProfile string) error {
 		strings.ToUpper(runtime.GOOS): "1",
 	}
 
-	c.ccPath = yc.GetValString("compiler.path.cc", settings)
-	c.cppPath = yc.GetValString("compiler.path.cpp", settings)
-	c.asPath = yc.GetValString("compiler.path.as", settings)
-	c.arPath = yc.GetValString("compiler.path.archive", settings)
-	c.odPath = yc.GetValString("compiler.path.objdump", settings)
-	c.osPath = yc.GetValString("compiler.path.objsize", settings)
-	c.ocPath = yc.GetValString("compiler.path.objcopy", settings)
+	c.ccPath, _ = yc.GetValString("compiler.path.cc", settings)
+	c.cppPath, _ = yc.GetValString("compiler.path.cpp", settings)
+	c.asPath, _ = yc.GetValString("compiler.path.as", settings)
+	c.arPath, _ = yc.GetValString("compiler.path.archive", settings)
+	c.odPath, _ = yc.GetValString("compiler.path.objdump", settings)
+	c.osPath, _ = yc.GetValString("compiler.path.objsize", settings)
+	c.ocPath, _ = yc.GetValString("compiler.path.objcopy", settings)
 
 	c.lclInfo.Cflags = loadFlags(yc, settings, "compiler.flags")
 	c.lclInfo.CXXflags = loadFlags(yc, settings, "compiler.cxx.flags")
 	c.lclInfo.Lflags = loadFlags(yc, settings, "compiler.ld.flags")
 	c.lclInfo.Aflags = loadFlags(yc, settings, "compiler.as.flags")
 
-	c.ldResolveCircularDeps = yc.GetValBool(
+	c.ldResolveCircularDeps, _ = yc.GetValBool(
 		"compiler.ld.resolve_circular_deps", settings)
-	c.ldMapFile = yc.GetValBool("compiler.ld.mapfile", settings)
-	c.ldBinFile = yc.GetValBoolDflt("compiler.ld.binfile", settings, true)
+
+	c.ldMapFile, _ = yc.GetValBool("compiler.ld.mapfile", settings)
+	c.ldBinFile, _ = yc.GetValBoolDflt("compiler.ld.binfile", settings, true)
 
 	if len(c.lclInfo.Cflags) == 0 {
 		// Assume no Cflags implies an unsupported build profile.
diff --git a/newt/ycfg/ycfg.go b/newt/ycfg/ycfg.go
index 742343b..46f8803 100644
--- a/newt/ycfg/ycfg.go
+++ b/newt/ycfg/ycfg.go
@@ -266,10 +266,17 @@ func (yc *YCfg) find(key string) *YCfgNode {
 	return cur
 }
 
-func (yc *YCfg) Get(key string, settings map[string]string) []YCfgEntry {
+// Get retrieves all nodes with the specified key.  If it encounters a parse
+// error in the tree, it ignores the bad node and continues the search.  All
+// bad nodes are indicated in the returned error.  In this sense, the returned
+// object is valid even if there is an error, and the error can be thought of
+// as a set of warnings.
+func (yc *YCfg) Get(key string,
+	settings map[string]string) ([]YCfgEntry, error) {
+
 	node := yc.find(key)
 	if node == nil {
-		return nil
+		return nil, nil
 	}
 
 	entries := []YCfgEntry{}
@@ -279,15 +286,18 @@ func (yc *YCfg) Get(key string, settings map[string]string) []YCfgEntry {
 		entries = append(entries, entry)
 	}
 
+	var errLines []string
 	for _, child := range node.Children {
 		expr, err := parse.LexAndParse(child.Name)
 		if err != nil {
-			util.OneTimeWarning("%s: %s", yc.name, err.Error())
+			errLines = append(errLines,
+				fmt.Sprintf("%s: %s", yc.name, err.Error()))
 			continue
 		}
 		val, err := parse.Eval(expr, settings)
 		if err != nil {
-			util.OneTimeWarning("%s: %s", yc.name, err.Error())
+			errLines = append(errLines,
+				fmt.Sprintf("%s: %s", yc.name, err.Error()))
 			continue
 		}
 		if val {
@@ -296,20 +306,29 @@ func (yc *YCfg) Get(key string, settings map[string]string) []YCfgEntry {
 				Expr:  expr,
 			}
 			if child.Overwrite {
-				return []YCfgEntry{entry}
+				entries = []YCfgEntry{entry}
+				break
 			}
 
 			entries = append(entries, entry)
 		}
 	}
 
-	return entries
+	if len(errLines) > 0 {
+		return entries, util.NewNewtError(strings.Join(errLines, "\n"))
+	} else {
+		return entries, nil
+	}
 }
 
-func (yc *YCfg) GetSlice(key string, settings map[string]string) []YCfgEntry {
-	sliceEntries := yc.Get(key, settings)
+// GetSlice retrieves all entries with the specified key and coerces their
+// values to type []interface{}.  The returned []YCfgEntry is formed from the
+// union of all these slices.  The returned error is a set of warnings just as
+// in `Get`.
+func (yc *YCfg) GetSlice(key string, settings map[string]string) ([]YCfgEntry, error) {
+	sliceEntries, getErr := yc.Get(key, settings)
 	if len(sliceEntries) == 0 {
-		return nil
+		return nil, getErr
 	}
 
 	result := []YCfgEntry{}
@@ -330,15 +349,18 @@ func (yc *YCfg) GetSlice(key string, settings map[string]string) []YCfgEntry {
 		}
 	}
 
-	return result
+	return result, getErr
 }
 
+// GetValSlice retrieves all entries with the specified key and coerces their
+// values to type []interface{}.  The returned slice is the union of all these
+// slices. The returned error is a set of warnings just as in `Get`.
 func (yc *YCfg) GetValSlice(
-	key string, settings map[string]string) []interface{} {
+	key string, settings map[string]string) ([]interface{}, error) {
 
-	entries := yc.GetSlice(key, settings)
+	entries, getErr := yc.GetSlice(key, settings)
 	if len(entries) == 0 {
-		return nil
+		return nil, getErr
 	}
 
 	vals := make([]interface{}, len(entries))
@@ -346,15 +368,19 @@ func (yc *YCfg) GetValSlice(
 		vals[i] = e.Value
 	}
 
-	return vals
+	return vals, getErr
 }
 
+// GetStringSlice retrieves all entries with the specified key and coerces
+// their values to type []string.  The returned []YCfgEntry is formed from the
+// union of all these slices.  The returned error is a set of warnings just as
+// in `Get`.
 func (yc *YCfg) GetStringSlice(key string,
-	settings map[string]string) []YCfgEntry {
+	settings map[string]string) ([]YCfgEntry, error) {
 
-	sliceEntries := yc.Get(key, settings)
+	sliceEntries, getErr := yc.Get(key, settings)
 	if len(sliceEntries) == 0 {
-		return nil
+		return nil, getErr
 	}
 
 	result := []YCfgEntry{}
@@ -375,15 +401,18 @@ func (yc *YCfg) GetStringSlice(key string,
 		}
 	}
 
-	return result
+	return result, getErr
 }
 
+// GetValStringSlice retrieves all entries with the specified key and coerces
+// their values to type []string.  The returned []string is the union of all
+// these slices.  The returned error is a set of warnings just as in `Get`.
 func (yc *YCfg) GetValStringSlice(
-	key string, settings map[string]string) []string {
+	key string, settings map[string]string) ([]string, error) {
 
-	entries := yc.GetStringSlice(key, settings)
+	entries, getErr := yc.GetStringSlice(key, settings)
 	if len(entries) == 0 {
-		return nil
+		return nil, getErr
 	}
 
 	vals := make([]string, len(entries))
@@ -393,13 +422,17 @@ func (yc *YCfg) GetValStringSlice(
 		}
 	}
 
-	return vals
+	return vals, getErr
 }
 
+// GetValStringSliceNonempty retrieves all entries with the specified key and
+// coerces their values to type []string.  The returned []string is the union
+// of all these slices.  Empty strings are excluded from this union.  The
+// returned error is a set of warnings just as in `Get`.
 func (yc *YCfg) GetValStringSliceNonempty(
-	key string, settings map[string]string) []string {
+	key string, settings map[string]string) ([]string, error) {
 
-	strs := yc.GetValStringSlice(key, settings)
+	strs, getErr := yc.GetValStringSlice(key, settings)
 	filtered := make([]string, 0, len(strs))
 	for _, s := range strs {
 		if s != "" {
@@ -407,15 +440,19 @@ func (yc *YCfg) GetValStringSliceNonempty(
 		}
 	}
 
-	return filtered
+	return filtered, getErr
 }
 
+// GetStringMap retrieves all entries with the specified key and coerces their
+// values to type map[string]interface{}.  The returned map[string]YCfgEntry is
+// formed from the union of all these maps.  The returned error is a set of
+// warnings just as in `Get`.
 func (yc *YCfg) GetStringMap(
-	key string, settings map[string]string) map[string]YCfgEntry {
+	key string, settings map[string]string) (map[string]YCfgEntry, error) {
 
-	mapEntries := yc.Get(key, settings)
+	mapEntries, getErr := yc.Get(key, settings)
 	if len(mapEntries) == 0 {
-		return nil
+		return nil, getErr
 	}
 
 	result := map[string]YCfgEntry{}
@@ -432,13 +469,17 @@ func (yc *YCfg) GetStringMap(
 		}
 	}
 
-	return result
+	return result, getErr
 }
 
+// GetValStringMap retrieves all entries with the specified key and coerces
+// their values to type map[string]interface{}.  The returned
+// map[string]YCfgEntry is the union of all these maps.  The returned error is
+// a set of warnings just as in `Get`.
 func (yc *YCfg) GetValStringMap(
-	key string, settings map[string]string) map[string]interface{} {
+	key string, settings map[string]string) (map[string]interface{}, error) {
 
-	entryMap := yc.GetStringMap(key, settings)
+	entryMap, getErr := yc.GetStringMap(key, settings)
 
 	smap := make(map[string]interface{}, len(entryMap))
 	for k, v := range entryMap {
@@ -447,66 +488,97 @@ func (yc *YCfg) GetValStringMap(
 		}
 	}
 
-	return smap
+	return smap, getErr
 }
 
-func (yc *YCfg) GetFirst(key string, settings map[string]string) (YCfgEntry, bool) {
-	entries := yc.Get(key, settings)
+// GetFirst retrieves the first entry with the specified key.  The bool return
+// value is true if a matching entry was found.  The returned error is a set of
+// warnings just as in `Get`.
+func (yc *YCfg) GetFirst(key string,
+	settings map[string]string) (YCfgEntry, bool, error) {
+
+	entries, getErr := yc.Get(key, settings)
 	if len(entries) == 0 {
-		return YCfgEntry{}, false
+		return YCfgEntry{}, false, getErr
 	}
 
-	return entries[0], true
+	return entries[0], true, getErr
 }
 
-func (yc *YCfg) GetFirstVal(key string, settings map[string]string) interface{} {
-	entry, ok := yc.GetFirst(key, settings)
+// GetFirstVal retrieves the first entry with the specified key and returns its
+// value.  It returns nil if no matching entry is found.  The returned error is
+// a set of warnings just as in `Get`.
+func (yc *YCfg) GetFirstVal(key string,
+	settings map[string]string) (interface{}, error) {
+
+	entry, ok, getErr := yc.GetFirst(key, settings)
 	if !ok {
-		return nil
+		return nil, getErr
 	}
 
-	return entry.Value
+	return entry.Value, getErr
 }
 
-func (yc *YCfg) GetValString(key string, settings map[string]string) string {
-	entry, ok := yc.GetFirst(key, settings)
+// GetValString retrieves the first entry with the specified key and returns
+// its value coerced to a string.  It returns "" if no matching entry is found.
+// The returned error is a set of warnings just as in `Get`.
+func (yc *YCfg) GetValString(key string,
+	settings map[string]string) (string, error) {
+
+	entry, ok, getErr := yc.GetFirst(key, settings)
 	if !ok {
-		return ""
+		return "", getErr
 	} else {
-		return cast.ToString(entry.Value)
+		return cast.ToString(entry.Value), getErr
 	}
 }
 
-func (yc *YCfg) GetValInt(key string, settings map[string]string) int {
-	entry, ok := yc.GetFirst(key, settings)
+// GetValInt retrieves the first entry with the specified key and returns its
+// value coerced to an int.  It returns 0 if no matching entry is found.  The
+// returned error is a set of warnings just as in `Get`.
+func (yc *YCfg) GetValInt(key string, settings map[string]string) (int, error) {
+	entry, ok, getErr := yc.GetFirst(key, settings)
 	if !ok {
-		return 0
+		return 0, getErr
 	} else {
-		return cast.ToInt(entry.Value)
+		return cast.ToInt(entry.Value), getErr
 	}
 }
 
+// GetValBoolDflt retrieves the first entry with the specified key and returns
+// its value coerced to a bool.  It returns the specified default if no
+// matching entry is found.  The returned error is a set of warnings just as in
+// `Get`.
 func (yc *YCfg) GetValBoolDflt(key string, settings map[string]string,
-	dflt bool) bool {
+	dflt bool) (bool, error) {
 
-	entry, ok := yc.GetFirst(key, settings)
+	entry, ok, getErr := yc.GetFirst(key, settings)
 	if !ok {
-		return dflt
+		return dflt, getErr
 	} else {
-		return cast.ToBool(entry.Value)
+		return cast.ToBool(entry.Value), getErr
 	}
 }
 
-func (yc *YCfg) GetValBool(key string, settings map[string]string) bool {
+// GetValBoolDflt retrieves the first entry with the specified key and returns
+// its value coerced to a bool.  It returns false if no matching entry is
+// found.  The returned error is a set of warnings just as in `Get`.
+func (yc *YCfg) GetValBool(key string,
+	settings map[string]string) (bool, error) {
+
 	return yc.GetValBoolDflt(key, settings, false)
 }
 
+// GetStringMapString retrieves all entries with the specified key and coerces
+// their values to type map[string]string.  The returned map[string]YCfgEntry
+// is formed from the union of all these maps.  The returned error is a set of
+// warnings just as in `Get`.
 func (yc *YCfg) GetStringMapString(key string,
-	settings map[string]string) map[string]YCfgEntry {
+	settings map[string]string) (map[string]YCfgEntry, error) {
 
-	mapEntries := yc.Get(key, settings)
+	mapEntries, getErr := yc.Get(key, settings)
 	if len(mapEntries) == 0 {
-		return nil
+		return nil, getErr
 	}
 
 	result := map[string]YCfgEntry{}
@@ -523,13 +595,17 @@ func (yc *YCfg) GetStringMapString(key string,
 		}
 	}
 
-	return result
+	return result, getErr
 }
 
+// GetStringMapString retrieves all entries with the specified key and coerces
+// their values to type map[string]string.  The returned map[string]YCfgEntry
+// is the union of all these maps.  The returned error is a set of warnings
+// just as in `Get`.
 func (yc *YCfg) GetValStringMapString(key string,
-	settings map[string]string) map[string]string {
+	settings map[string]string) (map[string]string, error) {
 
-	entryMap := yc.GetStringMapString(key, settings)
+	entryMap, getErr := yc.GetStringMapString(key, settings)
 
 	valMap := make(map[string]string, len(entryMap))
 	for k, v := range entryMap {
@@ -538,9 +614,11 @@ func (yc *YCfg) GetValStringMapString(key string,
 		}
 	}
 
-	return valMap
+	return valMap, getErr
 }
 
+// FullName calculates a node's name with the following form:
+//     [...].<grandparent>.<parent>.<node>
 func (node *YCfgNode) FullName() string {
 	tokens := []string{}
 
@@ -556,14 +634,18 @@ func (node *YCfgNode) FullName() string {
 	return strings.Join(tokens, ".")
 }
 
+// Delete deletes all entries with the specified key.
 func (yc *YCfg) Delete(key string) {
 	delete(yc.tree, key)
 }
 
+// Clear removes all entries from the YCfg.
 func (yc *YCfg) Clear() {
 	yc.tree = YCfgTree{}
 }
 
+// Traverse performs an in-order traversal of the YCfg tree.  The specified
+// function is applied to each node.
 func (yc *YCfg) Traverse(cb func(node *YCfgNode, depth int)) {
 	var traverseLevel func(
 		node *YCfgNode,
@@ -586,6 +668,8 @@ func (yc *YCfg) Traverse(cb func(node *YCfgNode, depth int)) {
 	}
 }
 
+// AllSettings converts the YCfg into a map with the following form:
+//     <node-full-name>: <node-value>
 func (yc *YCfg) AllSettings() map[string]interface{} {
 	settings := map[string]interface{}{}
 
@@ -598,6 +682,10 @@ func (yc *YCfg) AllSettings() map[string]interface{} {
 	return settings
 }
 
+// AllSettingsAsStrings converts the YCfg into a map with the following form:
+//     <node-full-name>: <node-value>
+//
+// All values in the map have been coerced to strings.
 func (yc *YCfg) AllSettingsAsStrings() map[string]string {
 	settings := yc.AllSettings()
 	smap := make(map[string]string, len(settings))
@@ -608,6 +696,7 @@ func (yc *YCfg) AllSettingsAsStrings() map[string]string {
 	return smap
 }
 
+// String produces a user-friendly string representation of the YCfg.
 func (yc *YCfg) String() string {
 	lines := make([]string, 0, len(yc.tree))
 	yc.Traverse(func(node *YCfgNode, depth int) {
@@ -621,6 +710,7 @@ func (yc *YCfg) String() string {
 	return strings.Join(lines, "\n")
 }
 
+// YAML converts the YCfg to a map and encodes the map as YAML.
 func (yc *YCfg) YAML() string {
 	return yaml.MapToYaml(yc.AllSettings())
 }