1*03ce13f7SAndroid Build Coastguard Worker// Copyright 2020 The SwiftShader Authors. All Rights Reserved. 2*03ce13f7SAndroid Build Coastguard Worker// 3*03ce13f7SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*03ce13f7SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*03ce13f7SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*03ce13f7SAndroid Build Coastguard Worker// 7*03ce13f7SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*03ce13f7SAndroid Build Coastguard Worker// 9*03ce13f7SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*03ce13f7SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*03ce13f7SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*03ce13f7SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*03ce13f7SAndroid Build Coastguard Worker// limitations under the License. 14*03ce13f7SAndroid Build Coastguard Worker 15*03ce13f7SAndroid Build Coastguard Worker// check_build_files scans all the .bp, .gn and .bazel files for source 16*03ce13f7SAndroid Build Coastguard Worker// references to non-existent files. 17*03ce13f7SAndroid Build Coastguard Worker 18*03ce13f7SAndroid Build Coastguard Workerpackage main 19*03ce13f7SAndroid Build Coastguard Worker 20*03ce13f7SAndroid Build Coastguard Workerimport ( 21*03ce13f7SAndroid Build Coastguard Worker "flag" 22*03ce13f7SAndroid Build Coastguard Worker "fmt" 23*03ce13f7SAndroid Build Coastguard Worker "io/ioutil" 24*03ce13f7SAndroid Build Coastguard Worker "os" 25*03ce13f7SAndroid Build Coastguard Worker "path/filepath" 26*03ce13f7SAndroid Build Coastguard Worker "regexp" 27*03ce13f7SAndroid Build Coastguard Worker "strings" 28*03ce13f7SAndroid Build Coastguard Worker) 29*03ce13f7SAndroid Build Coastguard Worker 30*03ce13f7SAndroid Build Coastguard Workerfunc cwd() string { 31*03ce13f7SAndroid Build Coastguard Worker wd, err := os.Getwd() 32*03ce13f7SAndroid Build Coastguard Worker if err != nil { 33*03ce13f7SAndroid Build Coastguard Worker return "" 34*03ce13f7SAndroid Build Coastguard Worker } 35*03ce13f7SAndroid Build Coastguard Worker return wd 36*03ce13f7SAndroid Build Coastguard Worker} 37*03ce13f7SAndroid Build Coastguard Worker 38*03ce13f7SAndroid Build Coastguard Workervar root = flag.String("root", cwd(), "root project directory") 39*03ce13f7SAndroid Build Coastguard Worker 40*03ce13f7SAndroid Build Coastguard Workerfunc main() { 41*03ce13f7SAndroid Build Coastguard Worker flag.Parse() 42*03ce13f7SAndroid Build Coastguard Worker 43*03ce13f7SAndroid Build Coastguard Worker if err := run(); err != nil { 44*03ce13f7SAndroid Build Coastguard Worker fmt.Fprintf(os.Stderr, "%v", err) 45*03ce13f7SAndroid Build Coastguard Worker os.Exit(1) 46*03ce13f7SAndroid Build Coastguard Worker } 47*03ce13f7SAndroid Build Coastguard Worker fmt.Printf("Build file check completed with no errors\n") 48*03ce13f7SAndroid Build Coastguard Worker} 49*03ce13f7SAndroid Build Coastguard Worker 50*03ce13f7SAndroid Build Coastguard Workerfunc run() error { 51*03ce13f7SAndroid Build Coastguard Worker wd := *root 52*03ce13f7SAndroid Build Coastguard Worker 53*03ce13f7SAndroid Build Coastguard Worker errs := []error{} 54*03ce13f7SAndroid Build Coastguard Worker 55*03ce13f7SAndroid Build Coastguard Worker filepath.Walk(wd, func(path string, info os.FileInfo, err error) error { 56*03ce13f7SAndroid Build Coastguard Worker if err != nil { 57*03ce13f7SAndroid Build Coastguard Worker return err 58*03ce13f7SAndroid Build Coastguard Worker } 59*03ce13f7SAndroid Build Coastguard Worker 60*03ce13f7SAndroid Build Coastguard Worker rel, err := filepath.Rel(wd, path) 61*03ce13f7SAndroid Build Coastguard Worker if err != nil { 62*03ce13f7SAndroid Build Coastguard Worker return filepath.SkipDir 63*03ce13f7SAndroid Build Coastguard Worker } 64*03ce13f7SAndroid Build Coastguard Worker 65*03ce13f7SAndroid Build Coastguard Worker switch rel { 66*03ce13f7SAndroid Build Coastguard Worker case ".git", "cache", "build", "out", "third_party": 67*03ce13f7SAndroid Build Coastguard Worker return filepath.SkipDir 68*03ce13f7SAndroid Build Coastguard Worker } 69*03ce13f7SAndroid Build Coastguard Worker 70*03ce13f7SAndroid Build Coastguard Worker if info.IsDir() { 71*03ce13f7SAndroid Build Coastguard Worker return nil 72*03ce13f7SAndroid Build Coastguard Worker } 73*03ce13f7SAndroid Build Coastguard Worker 74*03ce13f7SAndroid Build Coastguard Worker content, err := ioutil.ReadFile(path) 75*03ce13f7SAndroid Build Coastguard Worker if err != nil { 76*03ce13f7SAndroid Build Coastguard Worker errs = append(errs, err) 77*03ce13f7SAndroid Build Coastguard Worker return nil // Continue walking files 78*03ce13f7SAndroid Build Coastguard Worker } 79*03ce13f7SAndroid Build Coastguard Worker 80*03ce13f7SAndroid Build Coastguard Worker switch filepath.Ext(path) { 81*03ce13f7SAndroid Build Coastguard Worker case ".bp": 82*03ce13f7SAndroid Build Coastguard Worker errs = append(errs, checkBlueprint(path, string(content))...) 83*03ce13f7SAndroid Build Coastguard Worker case ".gn": 84*03ce13f7SAndroid Build Coastguard Worker errs = append(errs, checkGn(path, string(content))...) 85*03ce13f7SAndroid Build Coastguard Worker case ".bazel": 86*03ce13f7SAndroid Build Coastguard Worker errs = append(errs, checkBazel(path, string(content))...) 87*03ce13f7SAndroid Build Coastguard Worker } 88*03ce13f7SAndroid Build Coastguard Worker 89*03ce13f7SAndroid Build Coastguard Worker return nil 90*03ce13f7SAndroid Build Coastguard Worker }) 91*03ce13f7SAndroid Build Coastguard Worker 92*03ce13f7SAndroid Build Coastguard Worker sb := strings.Builder{} 93*03ce13f7SAndroid Build Coastguard Worker for _, err := range errs { 94*03ce13f7SAndroid Build Coastguard Worker sb.WriteString(err.Error()) 95*03ce13f7SAndroid Build Coastguard Worker sb.WriteString("\n") 96*03ce13f7SAndroid Build Coastguard Worker } 97*03ce13f7SAndroid Build Coastguard Worker if sb.Len() > 0 { 98*03ce13f7SAndroid Build Coastguard Worker return fmt.Errorf("%v", sb.String()) 99*03ce13f7SAndroid Build Coastguard Worker } 100*03ce13f7SAndroid Build Coastguard Worker return nil 101*03ce13f7SAndroid Build Coastguard Worker} 102*03ce13f7SAndroid Build Coastguard Worker 103*03ce13f7SAndroid Build Coastguard Workervar ( 104*03ce13f7SAndroid Build Coastguard Worker reSources = regexp.MustCompile(`sources\s*=\s*\[([^\]]*)\]`) 105*03ce13f7SAndroid Build Coastguard Worker reSrc = regexp.MustCompile(`srcs\s*[:=]\s*\[([^\]]*)\]`) 106*03ce13f7SAndroid Build Coastguard Worker reQuoted = regexp.MustCompile(`"([^\"]*)"`) 107*03ce13f7SAndroid Build Coastguard Worker) 108*03ce13f7SAndroid Build Coastguard Worker 109*03ce13f7SAndroid Build Coastguard Workerfunc checkBlueprint(path, content string) []error { 110*03ce13f7SAndroid Build Coastguard Worker errs := []error{} 111*03ce13f7SAndroid Build Coastguard Worker for _, sources := range matchRE(reSrc, content) { 112*03ce13f7SAndroid Build Coastguard Worker for _, source := range matchRE(reQuoted, sources) { 113*03ce13f7SAndroid Build Coastguard Worker if strings.HasPrefix(source, ":") { 114*03ce13f7SAndroid Build Coastguard Worker continue // Build target, we can't resolve. 115*03ce13f7SAndroid Build Coastguard Worker } 116*03ce13f7SAndroid Build Coastguard Worker if err := checkSource(path, source); err != nil { 117*03ce13f7SAndroid Build Coastguard Worker errs = append(errs, err) 118*03ce13f7SAndroid Build Coastguard Worker } 119*03ce13f7SAndroid Build Coastguard Worker } 120*03ce13f7SAndroid Build Coastguard Worker } 121*03ce13f7SAndroid Build Coastguard Worker return errs 122*03ce13f7SAndroid Build Coastguard Worker} 123*03ce13f7SAndroid Build Coastguard Worker 124*03ce13f7SAndroid Build Coastguard Workerfunc checkGn(path, content string) []error { 125*03ce13f7SAndroid Build Coastguard Worker errs := []error{} 126*03ce13f7SAndroid Build Coastguard Worker for _, sources := range matchRE(reSources, content) { 127*03ce13f7SAndroid Build Coastguard Worker for _, source := range matchRE(reQuoted, sources) { 128*03ce13f7SAndroid Build Coastguard Worker if strings.ContainsAny(source, "$") { 129*03ce13f7SAndroid Build Coastguard Worker return nil // Env vars we can't resolve 130*03ce13f7SAndroid Build Coastguard Worker } 131*03ce13f7SAndroid Build Coastguard Worker if strings.HasPrefix(source, "//") { 132*03ce13f7SAndroid Build Coastguard Worker continue // Build target, we can't resolve. 133*03ce13f7SAndroid Build Coastguard Worker } 134*03ce13f7SAndroid Build Coastguard Worker if err := checkSource(path, source); err != nil { 135*03ce13f7SAndroid Build Coastguard Worker errs = append(errs, err) 136*03ce13f7SAndroid Build Coastguard Worker } 137*03ce13f7SAndroid Build Coastguard Worker } 138*03ce13f7SAndroid Build Coastguard Worker } 139*03ce13f7SAndroid Build Coastguard Worker return errs 140*03ce13f7SAndroid Build Coastguard Worker} 141*03ce13f7SAndroid Build Coastguard Worker 142*03ce13f7SAndroid Build Coastguard Workerfunc checkBazel(path, content string) []error { 143*03ce13f7SAndroid Build Coastguard Worker errs := []error{} 144*03ce13f7SAndroid Build Coastguard Worker for _, sources := range matchRE(reSrc, content) { 145*03ce13f7SAndroid Build Coastguard Worker for _, source := range matchRE(reQuoted, sources) { 146*03ce13f7SAndroid Build Coastguard Worker if strings.HasPrefix(source, "@") || strings.HasPrefix(source, ":") { 147*03ce13f7SAndroid Build Coastguard Worker continue // Build target, we can't resolve. 148*03ce13f7SAndroid Build Coastguard Worker } 149*03ce13f7SAndroid Build Coastguard Worker if err := checkSource(path, source); err != nil { 150*03ce13f7SAndroid Build Coastguard Worker errs = append(errs, err) 151*03ce13f7SAndroid Build Coastguard Worker } 152*03ce13f7SAndroid Build Coastguard Worker } 153*03ce13f7SAndroid Build Coastguard Worker } 154*03ce13f7SAndroid Build Coastguard Worker return errs 155*03ce13f7SAndroid Build Coastguard Worker} 156*03ce13f7SAndroid Build Coastguard Worker 157*03ce13f7SAndroid Build Coastguard Workerfunc checkSource(path, source string) error { 158*03ce13f7SAndroid Build Coastguard Worker source = filepath.Join(filepath.Dir(path), source) 159*03ce13f7SAndroid Build Coastguard Worker 160*03ce13f7SAndroid Build Coastguard Worker if strings.Contains(source, "*") { 161*03ce13f7SAndroid Build Coastguard Worker sources, err := filepath.Glob(source) 162*03ce13f7SAndroid Build Coastguard Worker if err != nil { 163*03ce13f7SAndroid Build Coastguard Worker return fmt.Errorf("In '%v': %w", path, err) 164*03ce13f7SAndroid Build Coastguard Worker } 165*03ce13f7SAndroid Build Coastguard Worker if len(sources) == 0 { 166*03ce13f7SAndroid Build Coastguard Worker return fmt.Errorf("In '%v': Glob '%v' does not reference any files", path, source) 167*03ce13f7SAndroid Build Coastguard Worker } 168*03ce13f7SAndroid Build Coastguard Worker return nil 169*03ce13f7SAndroid Build Coastguard Worker } 170*03ce13f7SAndroid Build Coastguard Worker 171*03ce13f7SAndroid Build Coastguard Worker stat, err := os.Stat(source) 172*03ce13f7SAndroid Build Coastguard Worker if err != nil { 173*03ce13f7SAndroid Build Coastguard Worker return fmt.Errorf("In '%v': %w", path, err) 174*03ce13f7SAndroid Build Coastguard Worker } 175*03ce13f7SAndroid Build Coastguard Worker if stat.IsDir() { 176*03ce13f7SAndroid Build Coastguard Worker return fmt.Errorf("In '%v': '%v' refers to a directory, not a file", path, source) 177*03ce13f7SAndroid Build Coastguard Worker } 178*03ce13f7SAndroid Build Coastguard Worker return nil 179*03ce13f7SAndroid Build Coastguard Worker} 180*03ce13f7SAndroid Build Coastguard Worker 181*03ce13f7SAndroid Build Coastguard Workerfunc matchRE(re *regexp.Regexp, text string) []string { 182*03ce13f7SAndroid Build Coastguard Worker out := []string{} 183*03ce13f7SAndroid Build Coastguard Worker for _, match := range re.FindAllStringSubmatch(text, -1) { 184*03ce13f7SAndroid Build Coastguard Worker if len(match) < 2 { 185*03ce13f7SAndroid Build Coastguard Worker return nil 186*03ce13f7SAndroid Build Coastguard Worker } 187*03ce13f7SAndroid Build Coastguard Worker out = append(out, match[1]) 188*03ce13f7SAndroid Build Coastguard Worker } 189*03ce13f7SAndroid Build Coastguard Worker return out 190*03ce13f7SAndroid Build Coastguard Worker} 191