Make Windows shell escapes optional

Prior to this commit, newt would decide whether to escape curly braces
with backslashes.  Escaping was performed for all non-MSYS Windows
machines.  Apparently, not all MSYS machines are the same, so let the
user specify whether escaping should happen.

By default, escaping is performed on all Windows machines.

The user can override the default in two ways:

1. Command line:
    --escape=true
    --escape=false

2. $HOME/.newt/newtrc.yml file:
    escape_shell: true
diff --git a/newt/newt.go b/newt/newt.go
index c18d380..4a4453c 100644
--- a/newt/newt.go
+++ b/newt/newt.go
@@ -29,6 +29,7 @@
 
 	"mynewt.apache.org/newt/newt/cli"
 	"mynewt.apache.org/newt/newt/newtutil"
+	"mynewt.apache.org/newt/newt/settings"
 	"mynewt.apache.org/newt/util"
 )
 
@@ -39,6 +40,7 @@
 var newtLogFile string
 var newtNumJobs int
 var newtHelp bool
+var newtEscapeShellCmds bool
 
 func newtDfltNumJobs() int {
 	maxProcs := runtime.GOMAXPROCS(0)
@@ -77,6 +79,9 @@
 		Long:    newtHelpText,
 		Example: newtHelpEx,
 		PersistentPreRun: func(cmd *cobra.Command, args []string) {
+			// Ensure .newtrc file gets read.
+			settings.Newtrc()
+
 			verbosity := util.VERBOSITY_DEFAULT
 			if newtSilent {
 				verbosity = util.VERBOSITY_SILENT
@@ -86,6 +91,10 @@
 				verbosity = util.VERBOSITY_VERBOSE
 			}
 
+			if newtEscapeShellCmds {
+				util.EscapeShellCmds = true
+			}
+
 			var err error
 			NewtLogLevel, err = log.ParseLevel(logLevelStr)
 			if err != nil {
@@ -118,6 +127,8 @@
 		newtDfltNumJobs(), "Number of concurrent build jobs")
 	newtCmd.PersistentFlags().BoolVarP(&newtHelp, "help", "h",
 		false, "Help for newt commands")
+	newtCmd.PersistentFlags().BoolVarP(&newtEscapeShellCmds, "escape", "",
+		false, "Apply Windows escapes to shell commands")
 
 	versHelpText := cli.FormatHelp(`Display the Newt version number`)
 	versHelpEx := "  newt version"
diff --git a/newt/settings/settings.go b/newt/settings/settings.go
index 281f8f5..faa596c 100644
--- a/newt/settings/settings.go
+++ b/newt/settings/settings.go
@@ -22,32 +22,64 @@
 import (
 	"fmt"
 	"os/user"
+	"strconv"
 
 	log "github.com/sirupsen/logrus"
 
 	"mynewt.apache.org/newt/newt/config"
 	"mynewt.apache.org/newt/newt/ycfg"
+	"mynewt.apache.org/newt/util"
 )
 
 const NEWTRC_DIR string = ".newt"
 const REPOS_FILENAME string = "repos.yml"
+const NEWTRC_FILENAME string = "newtrc.yml"
 
 // Contains general newt settings read from $HOME/.newt
 var newtrc *ycfg.YCfg
 
+func processNewtrc(yc ycfg.YCfg) {
+	s := yc.GetValString("escape_shell", nil)
+	if s != "" {
+		b, err := strconv.ParseBool(s)
+		if err != nil {
+			log.Warnf(".newtrc contains invalid \"escape_shell\" value: %s; "+
+				"expected \"true\" or \"false\"", s)
+		} else {
+			util.EscapeShellCmds = b
+		}
+	}
+}
+
 func readNewtrc() ycfg.YCfg {
 	usr, err := user.Current()
 	if err != nil {
 		return ycfg.YCfg{}
 	}
 
-	path := fmt.Sprintf("%s/%s/%s", usr.HomeDir, NEWTRC_DIR, REPOS_FILENAME)
-	yc, err := config.ReadFile(path)
-	if err != nil {
-		log.Debugf("Failed to read %s file", path)
-		return ycfg.YCfg{}
+	yc := ycfg.NewYCfg("newtrc")
+	for _, filename := range []string{NEWTRC_FILENAME, REPOS_FILENAME} {
+		path := fmt.Sprintf("%s/%s/%s", usr.HomeDir, NEWTRC_DIR, filename)
+		sub, err := config.ReadFile(path)
+		if err != nil && !util.IsNotExist(err) {
+			log.Warnf("Failed to read %s file", path)
+			return ycfg.YCfg{}
+		}
+
+		fi := util.FileInfo{
+			Path:   path,
+			Parent: nil,
+		}
+		for k, v := range sub.AllSettings() {
+			if err := yc.MergeFromFile(k, v, &fi); err != nil {
+				log.Warnf("Failed to read %s file: %s", path, err.Error())
+				return ycfg.YCfg{}
+			}
+		}
 	}
 
+	processNewtrc(yc)
+
 	return yc
 }
 
diff --git a/util/util.go b/util/util.go
index af2ef38..31008f9 100644
--- a/util/util.go
+++ b/util/util.go
@@ -43,6 +43,7 @@
 var Verbosity int
 var PrintShellCmds bool
 var ExecuteShell bool
+var EscapeShellCmds bool = runtime.GOOS == "windows"
 var logFile *os.File
 
 func ParseEqualsPair(v string) (string, string, error) {
@@ -264,7 +265,7 @@
 
 // Escapes special characters for Windows builds (not in an MSYS environment).
 func fixupCmdArgs(args []string) {
-	if runtime.GOOS == "windows" && os.Getenv("MSYSTEM") == "" {
+	if EscapeShellCmds {
 		for i, _ := range args {
 			args[i] = strings.Replace(args[i], "{", "\\{", -1)
 			args[i] = strings.Replace(args[i], "}", "\\}", -1)