aboutsummaryrefslogtreecommitdiffstats
path: root/glob.go
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2016-11-01 11:10:51 -0700
committerColin Cross <ccross@android.com>2016-11-03 13:54:03 -0700
commit127d2eae8b7e706540e40c0422bfd41b063ca3e7 (patch)
tree64137bae7834b5439dd499ea76c29d6fbefc77ce /glob.go
parentb589835c0dbaf1ad0e830c6043a0481ca916b084 (diff)
downloadplatform_build_blueprint-127d2eae8b7e706540e40c0422bfd41b063ca3e7.tar.gz
platform_build_blueprint-127d2eae8b7e706540e40c0422bfd41b063ca3e7.tar.bz2
platform_build_blueprint-127d2eae8b7e706540e40c0422bfd41b063ca3e7.zip
Import globbing from Soong
Add globbing with dependency checking to blueprint. Calling ModuleContext.GlobWithDeps or SingletonContext.GlobWithDeps will return a list of files that match the globs, while also adding efficient dependencies to rerun the primary builder if a file that matches the glob is added or removed. Also use the globbing support for optional_subdirs=, subdirs= and build= lines in blueprints files. The globbing slightly changes the behavior of subname= lines, it no longer falls back to looking for a file called "Blueprints". Blueprint files that need to include a subdirectory with a different name can use build= instead of subdir= to directly include them. The Blueprints file is updated to reset subname="Blueprints" in case we want to include subdirectories inside blueprint and the primary builder has changed the subname. Also adds a new test directory that contains a simple primary builder tree to test regeneration for globbing, and runs the tests in travis. Change-Id: I83ce525fd11e11579cc58ba5308d01ca8eea7bc6
Diffstat (limited to 'glob.go')
-rw-r--r--glob.go116
1 files changed, 116 insertions, 0 deletions
diff --git a/glob.go b/glob.go
new file mode 100644
index 0000000..dad5edf
--- /dev/null
+++ b/glob.go
@@ -0,0 +1,116 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package blueprint
+
+import (
+ "fmt"
+ "reflect"
+ "sort"
+
+ "github.com/google/blueprint/pathtools"
+)
+
+type GlobPath struct {
+ Pattern string
+ Excludes []string
+ Files []string
+ Deps []string
+ Name string
+}
+
+func verifyGlob(fileName, pattern string, excludes []string, g GlobPath) {
+ if pattern != g.Pattern {
+ panic(fmt.Errorf("Mismatched patterns %q and %q for glob file %q", pattern, g.Pattern, fileName))
+ }
+ if !reflect.DeepEqual(g.Excludes, excludes) {
+ panic(fmt.Errorf("Mismatched excludes %v and %v for glob file %q", excludes, g.Excludes, fileName))
+ }
+}
+
+func (c *Context) glob(pattern string, excludes []string) ([]string, error) {
+ fileName := globToFileName(pattern, excludes)
+
+ // Try to get existing glob from the stored results
+ c.globLock.Lock()
+ g, exists := c.globs[fileName]
+ c.globLock.Unlock()
+
+ if exists {
+ // Glob has already been done, double check it is identical
+ verifyGlob(fileName, pattern, excludes, g)
+ return g.Files, nil
+ }
+
+ // Get a globbed file list
+ files, deps, err := pathtools.GlobWithExcludes(pattern, excludes)
+ if err != nil {
+ return nil, err
+ }
+
+ // Store the results
+ c.globLock.Lock()
+ if g, exists = c.globs[fileName]; !exists {
+ c.globs[fileName] = GlobPath{pattern, excludes, files, deps, fileName}
+ }
+ c.globLock.Unlock()
+
+ // Getting the list raced with another goroutine, throw away the results and use theirs
+ if exists {
+ verifyGlob(fileName, pattern, excludes, g)
+ return g.Files, nil
+ }
+
+ return files, nil
+}
+
+func (c *Context) Globs() []GlobPath {
+ fileNames := make([]string, 0, len(c.globs))
+ for k := range c.globs {
+ fileNames = append(fileNames, k)
+ }
+ sort.Strings(fileNames)
+
+ globs := make([]GlobPath, len(fileNames))
+ for i, fileName := range fileNames {
+ globs[i] = c.globs[fileName]
+ }
+
+ return globs
+}
+
+func globToString(pattern string) string {
+ ret := ""
+ for _, c := range pattern {
+ switch {
+ case c >= 'a' && c <= 'z',
+ c >= 'A' && c <= 'Z',
+ c >= '0' && c <= '9',
+ c == '_', c == '-', c == '/':
+ ret += string(c)
+ default:
+ ret += "_"
+ }
+ }
+
+ return ret
+}
+
+func globToFileName(pattern string, excludes []string) string {
+ ret := globToString(pattern)
+ for _, e := range excludes {
+ ret += "__" + globToString(e)
+ }
+ return ret + ".glob"
+}