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