1*9e94795aSAndroid Build Coastguard Worker// Copyright 2022 Google LLC 2*9e94795aSAndroid Build Coastguard Worker// 3*9e94795aSAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*9e94795aSAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*9e94795aSAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*9e94795aSAndroid Build Coastguard Worker// 7*9e94795aSAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*9e94795aSAndroid Build Coastguard Worker// 9*9e94795aSAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*9e94795aSAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*9e94795aSAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*9e94795aSAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*9e94795aSAndroid Build Coastguard Worker// limitations under the License. 14*9e94795aSAndroid Build Coastguard Worker 15*9e94795aSAndroid Build Coastguard Workerpackage main 16*9e94795aSAndroid Build Coastguard Worker 17*9e94795aSAndroid Build Coastguard Workerimport ( 18*9e94795aSAndroid Build Coastguard Worker "bytes" 19*9e94795aSAndroid Build Coastguard Worker "flag" 20*9e94795aSAndroid Build Coastguard Worker "fmt" 21*9e94795aSAndroid Build Coastguard Worker "io" 22*9e94795aSAndroid Build Coastguard Worker "io/fs" 23*9e94795aSAndroid Build Coastguard Worker "os" 24*9e94795aSAndroid Build Coastguard Worker "path/filepath" 25*9e94795aSAndroid Build Coastguard Worker "strings" 26*9e94795aSAndroid Build Coastguard Worker 27*9e94795aSAndroid Build Coastguard Worker "android/soong/response" 28*9e94795aSAndroid Build Coastguard Worker "android/soong/tools/compliance" 29*9e94795aSAndroid Build Coastguard Worker "android/soong/tools/compliance/projectmetadata" 30*9e94795aSAndroid Build Coastguard Worker) 31*9e94795aSAndroid Build Coastguard Worker 32*9e94795aSAndroid Build Coastguard Workervar ( 33*9e94795aSAndroid Build Coastguard Worker failNoneRequested = fmt.Errorf("\nNo projects requested") 34*9e94795aSAndroid Build Coastguard Worker) 35*9e94795aSAndroid Build Coastguard Worker 36*9e94795aSAndroid Build Coastguard Workerfunc main() { 37*9e94795aSAndroid Build Coastguard Worker var expandedArgs []string 38*9e94795aSAndroid Build Coastguard Worker for _, arg := range os.Args[1:] { 39*9e94795aSAndroid Build Coastguard Worker if strings.HasPrefix(arg, "@") { 40*9e94795aSAndroid Build Coastguard Worker f, err := os.Open(strings.TrimPrefix(arg, "@")) 41*9e94795aSAndroid Build Coastguard Worker if err != nil { 42*9e94795aSAndroid Build Coastguard Worker fmt.Fprintln(os.Stderr, err.Error()) 43*9e94795aSAndroid Build Coastguard Worker os.Exit(1) 44*9e94795aSAndroid Build Coastguard Worker } 45*9e94795aSAndroid Build Coastguard Worker 46*9e94795aSAndroid Build Coastguard Worker respArgs, err := response.ReadRspFile(f) 47*9e94795aSAndroid Build Coastguard Worker f.Close() 48*9e94795aSAndroid Build Coastguard Worker if err != nil { 49*9e94795aSAndroid Build Coastguard Worker fmt.Fprintln(os.Stderr, err.Error()) 50*9e94795aSAndroid Build Coastguard Worker os.Exit(1) 51*9e94795aSAndroid Build Coastguard Worker } 52*9e94795aSAndroid Build Coastguard Worker expandedArgs = append(expandedArgs, respArgs...) 53*9e94795aSAndroid Build Coastguard Worker } else { 54*9e94795aSAndroid Build Coastguard Worker expandedArgs = append(expandedArgs, arg) 55*9e94795aSAndroid Build Coastguard Worker } 56*9e94795aSAndroid Build Coastguard Worker } 57*9e94795aSAndroid Build Coastguard Worker 58*9e94795aSAndroid Build Coastguard Worker flags := flag.NewFlagSet("flags", flag.ExitOnError) 59*9e94795aSAndroid Build Coastguard Worker 60*9e94795aSAndroid Build Coastguard Worker flags.Usage = func() { 61*9e94795aSAndroid Build Coastguard Worker fmt.Fprintf(os.Stderr, `Usage: %s {-o outfile} projectdir {projectdir...} 62*9e94795aSAndroid Build Coastguard Worker 63*9e94795aSAndroid Build Coastguard WorkerTries to open the METADATA.android or METADATA file in each projectdir 64*9e94795aSAndroid Build Coastguard Workerreporting any errors on stderr. 65*9e94795aSAndroid Build Coastguard Worker 66*9e94795aSAndroid Build Coastguard WorkerReports "FAIL" to stdout if any errors found and exits with status 1. 67*9e94795aSAndroid Build Coastguard Worker 68*9e94795aSAndroid Build Coastguard WorkerOtherwise, reports "PASS" and the number of project metadata files 69*9e94795aSAndroid Build Coastguard Workerfound exiting with status 0. 70*9e94795aSAndroid Build Coastguard Worker`, filepath.Base(os.Args[0])) 71*9e94795aSAndroid Build Coastguard Worker flags.PrintDefaults() 72*9e94795aSAndroid Build Coastguard Worker } 73*9e94795aSAndroid Build Coastguard Worker 74*9e94795aSAndroid Build Coastguard Worker outputFile := flags.String("o", "-", "Where to write the output. (default stdout)") 75*9e94795aSAndroid Build Coastguard Worker 76*9e94795aSAndroid Build Coastguard Worker flags.Parse(expandedArgs) 77*9e94795aSAndroid Build Coastguard Worker 78*9e94795aSAndroid Build Coastguard Worker // Must specify at least one root target. 79*9e94795aSAndroid Build Coastguard Worker if flags.NArg() == 0 { 80*9e94795aSAndroid Build Coastguard Worker flags.Usage() 81*9e94795aSAndroid Build Coastguard Worker os.Exit(2) 82*9e94795aSAndroid Build Coastguard Worker } 83*9e94795aSAndroid Build Coastguard Worker 84*9e94795aSAndroid Build Coastguard Worker if len(*outputFile) == 0 { 85*9e94795aSAndroid Build Coastguard Worker flags.Usage() 86*9e94795aSAndroid Build Coastguard Worker fmt.Fprintf(os.Stderr, "must specify file for -o; use - for stdout\n") 87*9e94795aSAndroid Build Coastguard Worker os.Exit(2) 88*9e94795aSAndroid Build Coastguard Worker } else { 89*9e94795aSAndroid Build Coastguard Worker dir, err := filepath.Abs(filepath.Dir(*outputFile)) 90*9e94795aSAndroid Build Coastguard Worker if err != nil { 91*9e94795aSAndroid Build Coastguard Worker fmt.Fprintf(os.Stderr, "cannot determine path to %q: %s\n", *outputFile, err) 92*9e94795aSAndroid Build Coastguard Worker os.Exit(1) 93*9e94795aSAndroid Build Coastguard Worker } 94*9e94795aSAndroid Build Coastguard Worker fi, err := os.Stat(dir) 95*9e94795aSAndroid Build Coastguard Worker if err != nil { 96*9e94795aSAndroid Build Coastguard Worker fmt.Fprintf(os.Stderr, "cannot read directory %q of %q: %s\n", dir, *outputFile, err) 97*9e94795aSAndroid Build Coastguard Worker os.Exit(1) 98*9e94795aSAndroid Build Coastguard Worker } 99*9e94795aSAndroid Build Coastguard Worker if !fi.IsDir() { 100*9e94795aSAndroid Build Coastguard Worker fmt.Fprintf(os.Stderr, "parent %q of %q is not a directory\n", dir, *outputFile) 101*9e94795aSAndroid Build Coastguard Worker os.Exit(1) 102*9e94795aSAndroid Build Coastguard Worker } 103*9e94795aSAndroid Build Coastguard Worker } 104*9e94795aSAndroid Build Coastguard Worker 105*9e94795aSAndroid Build Coastguard Worker var ofile io.Writer 106*9e94795aSAndroid Build Coastguard Worker ofile = os.Stdout 107*9e94795aSAndroid Build Coastguard Worker var obuf *bytes.Buffer 108*9e94795aSAndroid Build Coastguard Worker if *outputFile != "-" { 109*9e94795aSAndroid Build Coastguard Worker obuf = &bytes.Buffer{} 110*9e94795aSAndroid Build Coastguard Worker ofile = obuf 111*9e94795aSAndroid Build Coastguard Worker } 112*9e94795aSAndroid Build Coastguard Worker 113*9e94795aSAndroid Build Coastguard Worker err := checkProjectMetadata(ofile, os.Stderr, compliance.FS, flags.Args()...) 114*9e94795aSAndroid Build Coastguard Worker if err != nil { 115*9e94795aSAndroid Build Coastguard Worker if err == failNoneRequested { 116*9e94795aSAndroid Build Coastguard Worker flags.Usage() 117*9e94795aSAndroid Build Coastguard Worker } 118*9e94795aSAndroid Build Coastguard Worker fmt.Fprintf(os.Stderr, "%s\n", err.Error()) 119*9e94795aSAndroid Build Coastguard Worker fmt.Fprintln(ofile, "FAIL") 120*9e94795aSAndroid Build Coastguard Worker os.Exit(1) 121*9e94795aSAndroid Build Coastguard Worker } 122*9e94795aSAndroid Build Coastguard Worker if *outputFile != "-" { 123*9e94795aSAndroid Build Coastguard Worker err := os.WriteFile(*outputFile, obuf.Bytes(), 0666) 124*9e94795aSAndroid Build Coastguard Worker if err != nil { 125*9e94795aSAndroid Build Coastguard Worker fmt.Fprintf(os.Stderr, "could not write output to %q from %q: %s\n", *outputFile, os.Getenv("PWD"), err) 126*9e94795aSAndroid Build Coastguard Worker os.Exit(1) 127*9e94795aSAndroid Build Coastguard Worker } 128*9e94795aSAndroid Build Coastguard Worker } 129*9e94795aSAndroid Build Coastguard Worker os.Exit(0) 130*9e94795aSAndroid Build Coastguard Worker} 131*9e94795aSAndroid Build Coastguard Worker 132*9e94795aSAndroid Build Coastguard Worker// checkProjectMetadata implements the checkmetadata utility. 133*9e94795aSAndroid Build Coastguard Workerfunc checkProjectMetadata(stdout, stderr io.Writer, rootFS fs.FS, projects ...string) error { 134*9e94795aSAndroid Build Coastguard Worker 135*9e94795aSAndroid Build Coastguard Worker if len(projects) < 1 { 136*9e94795aSAndroid Build Coastguard Worker return failNoneRequested 137*9e94795aSAndroid Build Coastguard Worker } 138*9e94795aSAndroid Build Coastguard Worker 139*9e94795aSAndroid Build Coastguard Worker // Read the project metadata files from `projects` 140*9e94795aSAndroid Build Coastguard Worker ix := projectmetadata.NewIndex(rootFS) 141*9e94795aSAndroid Build Coastguard Worker pms, err := ix.MetadataForProjects(projects...) 142*9e94795aSAndroid Build Coastguard Worker if err != nil { 143*9e94795aSAndroid Build Coastguard Worker return fmt.Errorf("Unable to read project metadata file(s) %q from %q: %w\n", projects, os.Getenv("PWD"), err) 144*9e94795aSAndroid Build Coastguard Worker } 145*9e94795aSAndroid Build Coastguard Worker 146*9e94795aSAndroid Build Coastguard Worker fmt.Fprintf(stdout, "PASS -- parsed %d project metadata files for %d projects\n", len(pms), len(projects)) 147*9e94795aSAndroid Build Coastguard Worker return nil 148*9e94795aSAndroid Build Coastguard Worker} 149