9b6826f7cf
Put quotes around the glob exclude options to avoid accidentally expanding globs during execution. Change-Id: Ia6fc7fa7dbe1d75e97d6039642e1c89be027689a
147 lines
4.3 KiB
Go
147 lines
4.3 KiB
Go
// 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 common
|
|
|
|
import (
|
|
"fmt"
|
|
"path/filepath"
|
|
|
|
"github.com/google/blueprint"
|
|
"github.com/google/blueprint/bootstrap"
|
|
|
|
"android/soong/glob"
|
|
)
|
|
|
|
// This file supports globbing source files in Blueprints files.
|
|
//
|
|
// The build.ninja file needs to be regenerated any time a file matching the glob is added
|
|
// or removed. The naive solution is to have the build.ninja file depend on all the
|
|
// traversed directories, but this will cause the regeneration step to run every time a
|
|
// non-matching file is added to a traversed directory, including backup files created by
|
|
// editors.
|
|
//
|
|
// The solution implemented here optimizes out regenerations when the directory modifications
|
|
// don't match the glob by having the build.ninja file depend on an intermedate file that
|
|
// is only updated when a file matching the glob is added or removed. The intermediate file
|
|
// depends on the traversed directories via a depfile. The depfile is used to avoid build
|
|
// errors if a directory is deleted - a direct dependency on the deleted directory would result
|
|
// in a build failure with a "missing and no known rule to make it" error.
|
|
|
|
var (
|
|
globCmd = filepath.Join(bootstrap.BinDir, "soong_glob")
|
|
|
|
// globRule rule traverses directories to produce a list of files that match $glob
|
|
// and writes it to $out if it has changed, and writes the directories to $out.d
|
|
globRule = pctx.StaticRule("globRule",
|
|
blueprint.RuleParams{
|
|
Command: fmt.Sprintf(`%s -o $out $excludes "$glob"`, globCmd),
|
|
Description: "glob $glob",
|
|
|
|
Restat: true,
|
|
Generator: true,
|
|
Deps: blueprint.DepsGCC,
|
|
Depfile: "$out.d",
|
|
},
|
|
"glob", "excludes")
|
|
)
|
|
|
|
func hasGlob(in []string) bool {
|
|
for _, s := range in {
|
|
if glob.IsGlob(s) {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func expandGlobs(ctx AndroidModuleContext, in []string) []string {
|
|
if !hasGlob(in) {
|
|
return in
|
|
}
|
|
|
|
var excludes []string
|
|
for _, s := range in {
|
|
if s[0] == '-' {
|
|
excludes = append(excludes, s[1:])
|
|
}
|
|
}
|
|
|
|
out := make([]string, 0, len(in))
|
|
for _, s := range in {
|
|
if glob.IsGlob(s) {
|
|
out = append(out, Glob(ctx, s, excludes)...)
|
|
} else if s[0] != '-' {
|
|
out = append(out, s)
|
|
}
|
|
}
|
|
|
|
return out
|
|
}
|
|
|
|
func Glob(ctx AndroidModuleContext, globPattern string, excludes []string) []string {
|
|
fileListFile := filepath.Join(ModuleOutDir(ctx), "glob", globToString(globPattern))
|
|
depFile := fileListFile + ".d"
|
|
|
|
// Get a globbed file list, and write out fileListFile and depFile
|
|
files, err := glob.GlobWithDepFile(globPattern, fileListFile, depFile, excludes)
|
|
if err != nil {
|
|
ctx.ModuleErrorf("glob: %s", err.Error())
|
|
return []string{globPattern}
|
|
}
|
|
|
|
GlobRule(ctx, globPattern, excludes, fileListFile, depFile)
|
|
|
|
// Make build.ninja depend on the fileListFile
|
|
ctx.AddNinjaFileDeps(fileListFile)
|
|
|
|
return files
|
|
}
|
|
|
|
func GlobRule(ctx AndroidModuleContext, globPattern string, excludes []string,
|
|
fileListFile, depFile string) {
|
|
|
|
// Create a rule to rebuild fileListFile if a directory in depFile changes. fileListFile
|
|
// will only be rewritten if it has changed, preventing unnecesary build.ninja regenerations.
|
|
ctx.Build(pctx, blueprint.BuildParams{
|
|
Rule: globRule,
|
|
Outputs: []string{fileListFile},
|
|
Implicits: []string{globCmd},
|
|
Args: map[string]string{
|
|
"glob": globPattern,
|
|
"excludes": JoinWithPrefixAndQuote(excludes, "-e "),
|
|
},
|
|
})
|
|
|
|
// Phony rule so the cleanup phase doesn't delete the depFile
|
|
ctx.Build(pctx, blueprint.BuildParams{
|
|
Rule: blueprint.Phony,
|
|
Outputs: []string{depFile},
|
|
})
|
|
}
|
|
|
|
func globToString(glob string) string {
|
|
ret := ""
|
|
for _, c := range glob {
|
|
if c >= 'a' && c <= 'z' ||
|
|
c >= 'A' && c <= 'Z' ||
|
|
c >= '0' && c <= '9' ||
|
|
c == '_' || c == '-' || c == '/' {
|
|
ret += string(c)
|
|
}
|
|
}
|
|
|
|
return ret
|
|
}
|