diff options
| author | Colin Cross <ccross@android.com> | 2016-11-01 11:10:51 -0700 |
|---|---|---|
| committer | Colin Cross <ccross@android.com> | 2016-11-03 13:54:03 -0700 |
| commit | 127d2eae8b7e706540e40c0422bfd41b063ca3e7 (patch) | |
| tree | 64137bae7834b5439dd499ea76c29d6fbefc77ce /glob.go | |
| parent | b589835c0dbaf1ad0e830c6043a0481ca916b084 (diff) | |
| download | platform_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.go | 116 |
1 files changed, 116 insertions, 0 deletions
@@ -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" +} |
