Merge pull request #17 from jgennis/rbase

Upstreaming some changes
diff --git a/Blueprints b/Blueprints
index 7b0d22a..c254136 100644
--- a/Blueprints
+++ b/Blueprints
@@ -2,6 +2,7 @@
     name = "blueprint",
     deps = [
         "blueprint-parser",
+        "blueprint-pathtools",
         "blueprint-proptools",
     ],
     pkgPath = "github.com/google/blueprint",
diff --git a/build.ninja.in b/build.ninja.in
index 073ed7f..ab32834 100644
--- a/build.ninja.in
+++ b/build.ninja.in
@@ -65,8 +65,9 @@
         ${g.bootstrap.srcDir}/singleton_ctx.go ${g.bootstrap.srcDir}/unpack.go $
         | ${g.bootstrap.gcCmd} $
         .bootstrap/blueprint-parser/pkg/github.com/google/blueprint/parser.a $
+        .bootstrap/blueprint-pathtools/pkg/github.com/google/blueprint/pathtools.a $
         .bootstrap/blueprint-proptools/pkg/github.com/google/blueprint/proptools.a
-    incFlags = -I .bootstrap/blueprint-parser/pkg -I .bootstrap/blueprint-proptools/pkg
+    incFlags = -I .bootstrap/blueprint-parser/pkg -I .bootstrap/blueprint-pathtools/pkg -I .bootstrap/blueprint-proptools/pkg
     pkgPath = github.com/google/blueprint
 default .bootstrap/blueprint/pkg/github.com/google/blueprint.a
 
@@ -75,7 +76,7 @@
 # Variant:
 # Type:    bootstrap_go_package
 # Factory: github.com/google/blueprint/bootstrap.newGoPackageModule
-# Defined: Blueprints:55:1
+# Defined: Blueprints:56:1
 
 build $
         .bootstrap/blueprint-bootstrap/pkg/github.com/google/blueprint/bootstrap.a $
@@ -85,11 +86,11 @@
         ${g.bootstrap.srcDir}/bootstrap/config.go $
         ${g.bootstrap.srcDir}/bootstrap/doc.go | ${g.bootstrap.gcCmd} $
         .bootstrap/blueprint-parser/pkg/github.com/google/blueprint/parser.a $
+        .bootstrap/blueprint-pathtools/pkg/github.com/google/blueprint/pathtools.a $
         .bootstrap/blueprint-proptools/pkg/github.com/google/blueprint/proptools.a $
         .bootstrap/blueprint/pkg/github.com/google/blueprint.a $
-        .bootstrap/blueprint-deptools/pkg/github.com/google/blueprint/deptools.a $
-        .bootstrap/blueprint-pathtools/pkg/github.com/google/blueprint/pathtools.a
-    incFlags = -I .bootstrap/blueprint-parser/pkg -I .bootstrap/blueprint-proptools/pkg -I .bootstrap/blueprint/pkg -I .bootstrap/blueprint-deptools/pkg -I .bootstrap/blueprint-pathtools/pkg
+        .bootstrap/blueprint-deptools/pkg/github.com/google/blueprint/deptools.a
+    incFlags = -I .bootstrap/blueprint-parser/pkg -I .bootstrap/blueprint-pathtools/pkg -I .bootstrap/blueprint-proptools/pkg -I .bootstrap/blueprint/pkg -I .bootstrap/blueprint-deptools/pkg
     pkgPath = github.com/google/blueprint/bootstrap
 default $
         .bootstrap/blueprint-bootstrap/pkg/github.com/google/blueprint/bootstrap.a
@@ -99,7 +100,7 @@
 # Variant:
 # Type:    bootstrap_go_package
 # Factory: github.com/google/blueprint/bootstrap.newGoPackageModule
-# Defined: Blueprints:34:1
+# Defined: Blueprints:35:1
 
 build .bootstrap/blueprint-deptools/pkg/github.com/google/blueprint/deptools.a $
         : g.bootstrap.gc ${g.bootstrap.srcDir}/deptools/depfile.go | $
@@ -113,7 +114,7 @@
 # Variant:
 # Type:    bootstrap_go_package
 # Factory: github.com/google/blueprint/bootstrap.newGoPackageModule
-# Defined: Blueprints:23:1
+# Defined: Blueprints:24:1
 
 build .bootstrap/blueprint-parser/pkg/github.com/google/blueprint/parser.a: $
         g.bootstrap.gc ${g.bootstrap.srcDir}/parser/modify.go $
@@ -128,7 +129,7 @@
 # Variant:
 # Type:    bootstrap_go_package
 # Factory: github.com/google/blueprint/bootstrap.newGoPackageModule
-# Defined: Blueprints:40:1
+# Defined: Blueprints:41:1
 
 build $
         .bootstrap/blueprint-pathtools/pkg/github.com/google/blueprint/pathtools.a $
@@ -143,7 +144,7 @@
 # Variant:
 # Type:    bootstrap_go_package
 # Factory: github.com/google/blueprint/bootstrap.newGoPackageModule
-# Defined: Blueprints:49:1
+# Defined: Blueprints:50:1
 
 build $
         .bootstrap/blueprint-proptools/pkg/github.com/google/blueprint/proptools.a $
@@ -158,7 +159,7 @@
 # Variant:
 # Type:    bootstrap_go_binary
 # Factory: github.com/google/blueprint/bootstrap.newGoBinaryModule
-# Defined: Blueprints:81:1
+# Defined: Blueprints:82:1
 
 build .bootstrap/bpfmt/obj/bpfmt.a: g.bootstrap.gc $
         ${g.bootstrap.srcDir}/bpfmt/bpfmt.go | ${g.bootstrap.gcCmd} $
@@ -180,7 +181,7 @@
 # Variant:
 # Type:    bootstrap_go_binary
 # Factory: github.com/google/blueprint/bootstrap.newGoBinaryModule
-# Defined: Blueprints:87:1
+# Defined: Blueprints:88:1
 
 build .bootstrap/bpmodify/obj/bpmodify.a: g.bootstrap.gc $
         ${g.bootstrap.srcDir}/bpmodify/bpmodify.go | ${g.bootstrap.gcCmd} $
@@ -202,23 +203,23 @@
 # Variant:
 # Type:    bootstrap_go_binary
 # Factory: github.com/google/blueprint/bootstrap.newGoBinaryModule
-# Defined: Blueprints:72:1
+# Defined: Blueprints:73:1
 
 build .bootstrap/minibp/obj/minibp.a: g.bootstrap.gc $
         ${g.bootstrap.srcDir}/bootstrap/minibp/main.go | ${g.bootstrap.gcCmd} $
         .bootstrap/blueprint-parser/pkg/github.com/google/blueprint/parser.a $
+        .bootstrap/blueprint-pathtools/pkg/github.com/google/blueprint/pathtools.a $
         .bootstrap/blueprint-proptools/pkg/github.com/google/blueprint/proptools.a $
         .bootstrap/blueprint/pkg/github.com/google/blueprint.a $
         .bootstrap/blueprint-deptools/pkg/github.com/google/blueprint/deptools.a $
-        .bootstrap/blueprint-pathtools/pkg/github.com/google/blueprint/pathtools.a $
         .bootstrap/blueprint-bootstrap/pkg/github.com/google/blueprint/bootstrap.a
-    incFlags = -I .bootstrap/blueprint-parser/pkg -I .bootstrap/blueprint-proptools/pkg -I .bootstrap/blueprint/pkg -I .bootstrap/blueprint-deptools/pkg -I .bootstrap/blueprint-pathtools/pkg -I .bootstrap/blueprint-bootstrap/pkg
+    incFlags = -I .bootstrap/blueprint-parser/pkg -I .bootstrap/blueprint-pathtools/pkg -I .bootstrap/blueprint-proptools/pkg -I .bootstrap/blueprint/pkg -I .bootstrap/blueprint-deptools/pkg -I .bootstrap/blueprint-bootstrap/pkg
     pkgPath = minibp
 default .bootstrap/minibp/obj/minibp.a
 
 build .bootstrap/minibp/obj/a.out: g.bootstrap.link $
         .bootstrap/minibp/obj/minibp.a | ${g.bootstrap.linkCmd}
-    libDirFlags = -L .bootstrap/blueprint-parser/pkg -L .bootstrap/blueprint-proptools/pkg -L .bootstrap/blueprint/pkg -L .bootstrap/blueprint-deptools/pkg -L .bootstrap/blueprint-pathtools/pkg -L .bootstrap/blueprint-bootstrap/pkg
+    libDirFlags = -L .bootstrap/blueprint-parser/pkg -L .bootstrap/blueprint-pathtools/pkg -L .bootstrap/blueprint-proptools/pkg -L .bootstrap/blueprint/pkg -L .bootstrap/blueprint-deptools/pkg -L .bootstrap/blueprint-bootstrap/pkg
 default .bootstrap/minibp/obj/a.out
 
 build .bootstrap/bin/minibp: g.bootstrap.cp .bootstrap/minibp/obj/a.out
diff --git a/context.go b/context.go
index 73b5e35..811ce76 100644
--- a/context.go
+++ b/context.go
@@ -19,6 +19,7 @@
 	"errors"
 	"fmt"
 	"github.com/google/blueprint/parser"
+	"github.com/google/blueprint/pathtools"
 	"github.com/google/blueprint/proptools"
 	"io"
 	"os"
@@ -471,6 +472,7 @@
 	}
 
 	subdirs, newErrs := c.processSubdirs(scope)
+
 	if len(newErrs) > 0 {
 		errs = append(errs, newErrs...)
 	}
@@ -590,77 +592,50 @@
 	modulesCh <- modules
 
 	for _, subdir := range subdirs {
-		subdir = filepath.Join(dir, subdir)
+		globPattern := filepath.Join(dir, subdir)
+		matches, matchedDirs, err := pathtools.Glob(globPattern)
+		if err != nil {
+			errsCh <- []error{err}
+			return
+		}
 
-		dirPart, filePart := filepath.Split(subdir)
-		dirPart = filepath.Clean(dirPart)
+		// Depend on all searched directories so we pick up future changes.
+		for _, matchedDir := range matchedDirs {
+			depsCh <- matchedDir
+		}
 
-		if filePart == "*" {
-			foundSubdirs, err := listSubdirs(dirPart)
-			if err != nil {
-				errsCh <- []error{err}
-				return
+		for _, foundSubdir := range matches {
+			fileInfo, subdirStatErr := os.Stat(foundSubdir)
+			if subdirStatErr != nil {
+				errsCh <- []error{subdirStatErr}
+				continue
 			}
 
-			for _, foundSubdir := range foundSubdirs {
-				subBlueprints := filepath.Join(dirPart, foundSubdir,
-					"Blueprints")
+			// Skip files
+			if !fileInfo.IsDir() {
+				continue
+			}
 
-				_, err := os.Stat(subBlueprints)
-				if os.IsNotExist(err) {
-					// There is no Blueprints file in this subdirectory.  We
-					// need to add the directory to the list of dependencies
-					// so that if someone adds a Blueprints file in the
-					// future we'll pick it up.
-					depsCh <- filepath.Dir(subBlueprints)
-				} else {
-					depsCh <- subBlueprints
-					blueprintsCh <- stringAndScope{
-						subBlueprints,
-						subScope,
-					}
+			subBlueprints := filepath.Join(foundSubdir, "Blueprints")
+
+			_, err := os.Stat(subBlueprints)
+			if os.IsNotExist(err) {
+				// There is no Blueprints file in this subdirectory.  We
+				// need to add the directory to the list of dependencies
+				// so that if someone adds a Blueprints file in the
+				// future we'll pick it up.
+				depsCh <- filepath.Dir(subBlueprints)
+			} else {
+				depsCh <- subBlueprints
+				blueprintsCh <- stringAndScope{
+					subBlueprints,
+					subScope,
 				}
 			}
-
-			// We now depend on the directory itself because if any new
-			// subdirectories get added or removed we need to rebuild the
-			// Ninja manifest.
-			depsCh <- dirPart
-		} else {
-			subBlueprints := filepath.Join(subdir, "Blueprints")
-			depsCh <- subBlueprints
-			blueprintsCh <- stringAndScope{
-				subBlueprints,
-				subScope,
-			}
-
 		}
 	}
 }
 
-func listSubdirs(dir string) ([]string, error) {
-	d, err := os.Open(dir)
-	if err != nil {
-		return nil, err
-	}
-	defer d.Close()
-
-	infos, err := d.Readdir(-1)
-	if err != nil {
-		return nil, err
-	}
-
-	var subdirs []string
-	for _, info := range infos {
-		isDotFile := strings.HasPrefix(info.Name(), ".")
-		if info.IsDir() && !isDotFile {
-			subdirs = append(subdirs, info.Name())
-		}
-	}
-
-	return subdirs, nil
-}
-
 func (c *Context) processSubdirs(
 	scope *parser.Scope) (subdirs []string, errs []error) {
 
@@ -675,19 +650,6 @@
 					panic("non-string value found in list")
 				}
 
-				dirPart, filePart := filepath.Split(value.StringValue)
-				if (filePart != "*" && strings.ContainsRune(filePart, '*')) ||
-					strings.ContainsRune(dirPart, '*') {
-
-					errs = append(errs, &Error{
-						Err: fmt.Errorf("subdirs may only wildcard whole " +
-							"directories"),
-						Pos: value.Pos,
-					})
-
-					continue
-				}
-
 				subdirs = append(subdirs, value.StringValue)
 			}
 
@@ -1415,11 +1377,13 @@
 func (c *Context) runBottomUpMutator(config interface{},
 	name string, mutator BottomUpMutator) (errs []error) {
 
-	dependenciesModified := false
-
 	for _, module := range c.modulesSorted {
 		newModules := make([]*moduleInfo, 0, 1)
 
+		if module.splitModules != nil {
+			panic("split module found in sorted module list")
+		}
+
 		mctx := &mutatorContext{
 			baseModuleContext: baseModuleContext{
 				context: c,
@@ -1443,10 +1407,6 @@
 			}
 		}
 
-		if mctx.dependenciesModified {
-			dependenciesModified = true
-		}
-
 		if module.splitModules != nil {
 			newModules = append(newModules, module.splitModules...)
 		} else {
@@ -1456,11 +1416,9 @@
 		module.group.modules = spliceModules(module.group.modules, module, newModules)
 	}
 
-	if dependenciesModified {
-		errs = c.updateDependencies()
-		if len(errs) > 0 {
-			return errs
-		}
+	errs = c.updateDependencies()
+	if len(errs) > 0 {
+		return errs
 	}
 
 	return errs
diff --git a/deptools/depfile.go b/deptools/depfile.go
index cc114f6..bfcf2ce 100644
--- a/deptools/depfile.go
+++ b/deptools/depfile.go
@@ -20,6 +20,16 @@
 	"strings"
 )
 
+var (
+	pathEscaper = strings.NewReplacer(
+		`\`, `\\`,
+		` `, `\ `,
+		`#`, `\#`,
+		`*`, `\*`,
+		`[`, `\[`,
+		`|`, `\|`)
+)
+
 // WriteDepFile creates a new gcc-style depfile and populates it with content
 // indicating that target depends on deps.
 func WriteDepFile(filename, target string, deps []string) error {
@@ -29,8 +39,14 @@
 	}
 	defer f.Close()
 
+	var escapedDeps []string
+
+	for _, dep := range deps {
+		escapedDeps = append(escapedDeps, pathEscaper.Replace(dep))
+	}
+
 	_, err = fmt.Fprintf(f, "%s: \\\n %s\n", target,
-		strings.Join(deps, " \\\n "))
+		strings.Join(escapedDeps, " \\\n "))
 	if err != nil {
 		return err
 	}
diff --git a/pathtools/glob.go b/pathtools/glob.go
index bb3358e..507983e 100644
--- a/pathtools/glob.go
+++ b/pathtools/glob.go
@@ -59,3 +59,27 @@
 func isWild(pattern string) bool {
 	return strings.ContainsAny(pattern, "*?[")
 }
+
+func GlobPatternList(patterns []string, prefix string) (globedList []string, depDirs []string, err error) {
+	var (
+		matches []string
+		deps         []string
+	)
+
+	globedList = make([]string, 0)
+	depDirs = make([]string, 0)
+
+	for _, pattern := range patterns {
+		if isWild(pattern) {
+			matches, deps, err = Glob(filepath.Join(prefix, pattern))
+			if err != nil {
+				return nil, nil, err
+			}
+			globedList = append(globedList, matches...)
+			depDirs = append(depDirs, deps...)
+		} else {
+			globedList = append(globedList, filepath.Join(prefix, pattern))
+		}
+	}
+	return globedList, depDirs, nil
+}