You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
191 lines
4.3 KiB
191 lines
4.3 KiB
// Copyright 2020 The SwiftShader Authors. 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.
|
|
|
|
// check_build_files scans all the .bp, .gn and .bazel files for source
|
|
// references to non-existent files.
|
|
|
|
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
func cwd() string {
|
|
wd, err := os.Getwd()
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
return wd
|
|
}
|
|
|
|
var root = flag.String("root", cwd(), "root project directory")
|
|
|
|
func main() {
|
|
flag.Parse()
|
|
|
|
if err := run(); err != nil {
|
|
fmt.Fprintf(os.Stderr, "%v", err)
|
|
os.Exit(1)
|
|
}
|
|
fmt.Printf("Build file check completed with no errors\n")
|
|
}
|
|
|
|
func run() error {
|
|
wd := *root
|
|
|
|
errs := []error{}
|
|
|
|
filepath.Walk(wd, func(path string, info os.FileInfo, err error) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
rel, err := filepath.Rel(wd, path)
|
|
if err != nil {
|
|
return filepath.SkipDir
|
|
}
|
|
|
|
switch rel {
|
|
case ".git", "cache", "build", "out", "third_party":
|
|
return filepath.SkipDir
|
|
}
|
|
|
|
if info.IsDir() {
|
|
return nil
|
|
}
|
|
|
|
content, err := ioutil.ReadFile(path)
|
|
if err != nil {
|
|
errs = append(errs, err)
|
|
return nil // Continue walking files
|
|
}
|
|
|
|
switch filepath.Ext(path) {
|
|
case ".bp":
|
|
errs = append(errs, checkBlueprint(path, string(content))...)
|
|
case ".gn":
|
|
errs = append(errs, checkGn(path, string(content))...)
|
|
case ".bazel":
|
|
errs = append(errs, checkBazel(path, string(content))...)
|
|
}
|
|
|
|
return nil
|
|
})
|
|
|
|
sb := strings.Builder{}
|
|
for _, err := range errs {
|
|
sb.WriteString(err.Error())
|
|
sb.WriteString("\n")
|
|
}
|
|
if sb.Len() > 0 {
|
|
return fmt.Errorf("%v", sb.String())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
var (
|
|
reSources = regexp.MustCompile(`sources\s*=\s*\[([^\]]*)\]`)
|
|
reSrc = regexp.MustCompile(`srcs\s*[:=]\s*\[([^\]]*)\]`)
|
|
reQuoted = regexp.MustCompile(`"([^\"]*)"`)
|
|
)
|
|
|
|
func checkBlueprint(path, content string) []error {
|
|
errs := []error{}
|
|
for _, sources := range matchRE(reSrc, content) {
|
|
for _, source := range matchRE(reQuoted, sources) {
|
|
if strings.HasPrefix(source, ":") {
|
|
continue // Build target, we can't resolve.
|
|
}
|
|
if err := checkSource(path, source); err != nil {
|
|
errs = append(errs, err)
|
|
}
|
|
}
|
|
}
|
|
return errs
|
|
}
|
|
|
|
func checkGn(path, content string) []error {
|
|
errs := []error{}
|
|
for _, sources := range matchRE(reSources, content) {
|
|
for _, source := range matchRE(reQuoted, sources) {
|
|
if strings.ContainsAny(source, "$") {
|
|
return nil // Env vars we can't resolve
|
|
}
|
|
if strings.HasPrefix(source, "//") {
|
|
continue // Build target, we can't resolve.
|
|
}
|
|
if err := checkSource(path, source); err != nil {
|
|
errs = append(errs, err)
|
|
}
|
|
}
|
|
}
|
|
return errs
|
|
}
|
|
|
|
func checkBazel(path, content string) []error {
|
|
errs := []error{}
|
|
for _, sources := range matchRE(reSrc, content) {
|
|
for _, source := range matchRE(reQuoted, sources) {
|
|
if strings.HasPrefix(source, "@") || strings.HasPrefix(source, ":") {
|
|
continue // Build target, we can't resolve.
|
|
}
|
|
if err := checkSource(path, source); err != nil {
|
|
errs = append(errs, err)
|
|
}
|
|
}
|
|
}
|
|
return errs
|
|
}
|
|
|
|
func checkSource(path, source string) error {
|
|
source = filepath.Join(filepath.Dir(path), source)
|
|
|
|
if strings.Contains(source, "*") {
|
|
sources, err := filepath.Glob(source)
|
|
if err != nil {
|
|
return fmt.Errorf("In '%v': %w", path, err)
|
|
}
|
|
if len(sources) == 0 {
|
|
return fmt.Errorf("In '%v': Glob '%v' does not reference any files", path, source)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
stat, err := os.Stat(source)
|
|
if err != nil {
|
|
return fmt.Errorf("In '%v': %w", path, err)
|
|
}
|
|
if stat.IsDir() {
|
|
return fmt.Errorf("In '%v': '%v' refers to a directory, not a file", path, source)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func matchRE(re *regexp.Regexp, text string) []string {
|
|
out := []string{}
|
|
for _, match := range re.FindAllStringSubmatch(text, -1) {
|
|
if len(match) < 2 {
|
|
return nil
|
|
}
|
|
out = append(out, match[1])
|
|
}
|
|
return out
|
|
}
|