1*333d2b36SAndroid Build Coastguard Worker// Copyright 2017 Google Inc. All rights reserved. 2*333d2b36SAndroid Build Coastguard Worker// 3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*333d2b36SAndroid Build Coastguard Worker// 7*333d2b36SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*333d2b36SAndroid Build Coastguard Worker// 9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*333d2b36SAndroid Build Coastguard Worker// limitations under the License. 14*333d2b36SAndroid Build Coastguard Worker 15*333d2b36SAndroid Build Coastguard Worker// This file provides a bpfix command-line library 16*333d2b36SAndroid Build Coastguard Worker 17*333d2b36SAndroid Build Coastguard Worker// TODO(jeffrygaston) should this file be consolidated with bpfmt.go? 18*333d2b36SAndroid Build Coastguard Worker 19*333d2b36SAndroid Build Coastguard Workerpackage cmd_lib 20*333d2b36SAndroid Build Coastguard Worker 21*333d2b36SAndroid Build Coastguard Workerimport ( 22*333d2b36SAndroid Build Coastguard Worker "bytes" 23*333d2b36SAndroid Build Coastguard Worker "flag" 24*333d2b36SAndroid Build Coastguard Worker "fmt" 25*333d2b36SAndroid Build Coastguard Worker "io" 26*333d2b36SAndroid Build Coastguard Worker "io/ioutil" 27*333d2b36SAndroid Build Coastguard Worker "os" 28*333d2b36SAndroid Build Coastguard Worker "os/exec" 29*333d2b36SAndroid Build Coastguard Worker "path/filepath" 30*333d2b36SAndroid Build Coastguard Worker 31*333d2b36SAndroid Build Coastguard Worker "github.com/google/blueprint/parser" 32*333d2b36SAndroid Build Coastguard Worker 33*333d2b36SAndroid Build Coastguard Worker "android/soong/bpfix/bpfix" 34*333d2b36SAndroid Build Coastguard Worker) 35*333d2b36SAndroid Build Coastguard Worker 36*333d2b36SAndroid Build Coastguard Workervar ( 37*333d2b36SAndroid Build Coastguard Worker // main operation modes 38*333d2b36SAndroid Build Coastguard Worker list = flag.Bool("l", false, "list files whose formatting differs from bpfmt's") 39*333d2b36SAndroid Build Coastguard Worker write = flag.Bool("w", false, "write result to (source) file instead of stdout") 40*333d2b36SAndroid Build Coastguard Worker doDiff = flag.Bool("d", false, "display diffs instead of rewriting files") 41*333d2b36SAndroid Build Coastguard Worker) 42*333d2b36SAndroid Build Coastguard Worker 43*333d2b36SAndroid Build Coastguard Workervar ( 44*333d2b36SAndroid Build Coastguard Worker exitCode = 0 45*333d2b36SAndroid Build Coastguard Worker) 46*333d2b36SAndroid Build Coastguard Worker 47*333d2b36SAndroid Build Coastguard Workerfunc report(err error) { 48*333d2b36SAndroid Build Coastguard Worker fmt.Fprintln(os.Stderr, err) 49*333d2b36SAndroid Build Coastguard Worker exitCode = 2 50*333d2b36SAndroid Build Coastguard Worker} 51*333d2b36SAndroid Build Coastguard Worker 52*333d2b36SAndroid Build Coastguard Workerfunc openAndProcess(filename string, out io.Writer, fixRequest bpfix.FixRequest) error { 53*333d2b36SAndroid Build Coastguard Worker f, err := os.Open(filename) 54*333d2b36SAndroid Build Coastguard Worker if err != nil { 55*333d2b36SAndroid Build Coastguard Worker return err 56*333d2b36SAndroid Build Coastguard Worker } 57*333d2b36SAndroid Build Coastguard Worker defer f.Close() 58*333d2b36SAndroid Build Coastguard Worker return processFile(filename, f, out, fixRequest) 59*333d2b36SAndroid Build Coastguard Worker} 60*333d2b36SAndroid Build Coastguard Worker 61*333d2b36SAndroid Build Coastguard Worker// If in == nil, the source is the contents of the file with the given filename. 62*333d2b36SAndroid Build Coastguard Workerfunc processFile(filename string, in io.Reader, out io.Writer, fixRequest bpfix.FixRequest) error { 63*333d2b36SAndroid Build Coastguard Worker // load the input file 64*333d2b36SAndroid Build Coastguard Worker src, err := ioutil.ReadAll(in) 65*333d2b36SAndroid Build Coastguard Worker if err != nil { 66*333d2b36SAndroid Build Coastguard Worker return err 67*333d2b36SAndroid Build Coastguard Worker } 68*333d2b36SAndroid Build Coastguard Worker r := bytes.NewBuffer(append([]byte(nil), src...)) 69*333d2b36SAndroid Build Coastguard Worker file, errs := parser.Parse(filename, r) 70*333d2b36SAndroid Build Coastguard Worker if len(errs) > 0 { 71*333d2b36SAndroid Build Coastguard Worker for _, err := range errs { 72*333d2b36SAndroid Build Coastguard Worker fmt.Fprintln(os.Stderr, err) 73*333d2b36SAndroid Build Coastguard Worker } 74*333d2b36SAndroid Build Coastguard Worker return fmt.Errorf("%d parsing errors", len(errs)) 75*333d2b36SAndroid Build Coastguard Worker } 76*333d2b36SAndroid Build Coastguard Worker 77*333d2b36SAndroid Build Coastguard Worker // compute and apply any requested fixes 78*333d2b36SAndroid Build Coastguard Worker fixer := bpfix.NewFixer(file) 79*333d2b36SAndroid Build Coastguard Worker file, err = fixer.Fix(fixRequest) 80*333d2b36SAndroid Build Coastguard Worker if err != nil { 81*333d2b36SAndroid Build Coastguard Worker return err 82*333d2b36SAndroid Build Coastguard Worker } 83*333d2b36SAndroid Build Coastguard Worker 84*333d2b36SAndroid Build Coastguard Worker // output the results 85*333d2b36SAndroid Build Coastguard Worker res, err := parser.Print(file) 86*333d2b36SAndroid Build Coastguard Worker if err != nil { 87*333d2b36SAndroid Build Coastguard Worker return err 88*333d2b36SAndroid Build Coastguard Worker } 89*333d2b36SAndroid Build Coastguard Worker if !bytes.Equal(src, res) { 90*333d2b36SAndroid Build Coastguard Worker // contents have changed 91*333d2b36SAndroid Build Coastguard Worker if *list { 92*333d2b36SAndroid Build Coastguard Worker fmt.Fprintln(out, filename) 93*333d2b36SAndroid Build Coastguard Worker } 94*333d2b36SAndroid Build Coastguard Worker if *write { 95*333d2b36SAndroid Build Coastguard Worker err = ioutil.WriteFile(filename, res, 0644) 96*333d2b36SAndroid Build Coastguard Worker if err != nil { 97*333d2b36SAndroid Build Coastguard Worker return err 98*333d2b36SAndroid Build Coastguard Worker } 99*333d2b36SAndroid Build Coastguard Worker } 100*333d2b36SAndroid Build Coastguard Worker if *doDiff { 101*333d2b36SAndroid Build Coastguard Worker data, err := diff(src, res) 102*333d2b36SAndroid Build Coastguard Worker if err != nil { 103*333d2b36SAndroid Build Coastguard Worker return fmt.Errorf("computing diff: %s", err) 104*333d2b36SAndroid Build Coastguard Worker } 105*333d2b36SAndroid Build Coastguard Worker fmt.Printf("diff %s bpfix/%s\n", filename, filename) 106*333d2b36SAndroid Build Coastguard Worker out.Write(data) 107*333d2b36SAndroid Build Coastguard Worker } 108*333d2b36SAndroid Build Coastguard Worker } 109*333d2b36SAndroid Build Coastguard Worker if !*list && !*write && !*doDiff { 110*333d2b36SAndroid Build Coastguard Worker _, err = out.Write(res) 111*333d2b36SAndroid Build Coastguard Worker } 112*333d2b36SAndroid Build Coastguard Worker return err 113*333d2b36SAndroid Build Coastguard Worker} 114*333d2b36SAndroid Build Coastguard Worker 115*333d2b36SAndroid Build Coastguard Workerfunc makeFileVisitor(fixRequest bpfix.FixRequest) func(string, os.FileInfo, error) error { 116*333d2b36SAndroid Build Coastguard Worker return func(path string, f os.FileInfo, err error) error { 117*333d2b36SAndroid Build Coastguard Worker if err == nil && f.Name() == "Android.bp" { 118*333d2b36SAndroid Build Coastguard Worker err = openAndProcess(path, os.Stdout, fixRequest) 119*333d2b36SAndroid Build Coastguard Worker } 120*333d2b36SAndroid Build Coastguard Worker if err != nil { 121*333d2b36SAndroid Build Coastguard Worker report(err) 122*333d2b36SAndroid Build Coastguard Worker } 123*333d2b36SAndroid Build Coastguard Worker return nil 124*333d2b36SAndroid Build Coastguard Worker } 125*333d2b36SAndroid Build Coastguard Worker} 126*333d2b36SAndroid Build Coastguard Worker 127*333d2b36SAndroid Build Coastguard Workerfunc walkDir(path string, fixRequest bpfix.FixRequest) { 128*333d2b36SAndroid Build Coastguard Worker filepath.Walk(path, makeFileVisitor(fixRequest)) 129*333d2b36SAndroid Build Coastguard Worker} 130*333d2b36SAndroid Build Coastguard Worker 131*333d2b36SAndroid Build Coastguard Workerfunc Run() { 132*333d2b36SAndroid Build Coastguard Worker flag.Parse() 133*333d2b36SAndroid Build Coastguard Worker 134*333d2b36SAndroid Build Coastguard Worker fixRequest := bpfix.NewFixRequest().AddAll() 135*333d2b36SAndroid Build Coastguard Worker 136*333d2b36SAndroid Build Coastguard Worker if flag.NArg() == 0 { 137*333d2b36SAndroid Build Coastguard Worker if *write { 138*333d2b36SAndroid Build Coastguard Worker fmt.Fprintln(os.Stderr, "error: cannot use -w with standard input") 139*333d2b36SAndroid Build Coastguard Worker exitCode = 2 140*333d2b36SAndroid Build Coastguard Worker return 141*333d2b36SAndroid Build Coastguard Worker } 142*333d2b36SAndroid Build Coastguard Worker if err := processFile("<standard input>", os.Stdin, os.Stdout, fixRequest); err != nil { 143*333d2b36SAndroid Build Coastguard Worker report(err) 144*333d2b36SAndroid Build Coastguard Worker } 145*333d2b36SAndroid Build Coastguard Worker return 146*333d2b36SAndroid Build Coastguard Worker } 147*333d2b36SAndroid Build Coastguard Worker 148*333d2b36SAndroid Build Coastguard Worker for i := 0; i < flag.NArg(); i++ { 149*333d2b36SAndroid Build Coastguard Worker path := flag.Arg(i) 150*333d2b36SAndroid Build Coastguard Worker switch dir, err := os.Stat(path); { 151*333d2b36SAndroid Build Coastguard Worker case err != nil: 152*333d2b36SAndroid Build Coastguard Worker report(err) 153*333d2b36SAndroid Build Coastguard Worker case dir.IsDir(): 154*333d2b36SAndroid Build Coastguard Worker walkDir(path, fixRequest) 155*333d2b36SAndroid Build Coastguard Worker default: 156*333d2b36SAndroid Build Coastguard Worker if err := openAndProcess(path, os.Stdout, fixRequest); err != nil { 157*333d2b36SAndroid Build Coastguard Worker report(err) 158*333d2b36SAndroid Build Coastguard Worker } 159*333d2b36SAndroid Build Coastguard Worker } 160*333d2b36SAndroid Build Coastguard Worker } 161*333d2b36SAndroid Build Coastguard Worker} 162*333d2b36SAndroid Build Coastguard Worker 163*333d2b36SAndroid Build Coastguard Workerfunc diff(b1, b2 []byte) (data []byte, err error) { 164*333d2b36SAndroid Build Coastguard Worker f1, err := ioutil.TempFile("", "bpfix") 165*333d2b36SAndroid Build Coastguard Worker if err != nil { 166*333d2b36SAndroid Build Coastguard Worker return 167*333d2b36SAndroid Build Coastguard Worker } 168*333d2b36SAndroid Build Coastguard Worker defer os.Remove(f1.Name()) 169*333d2b36SAndroid Build Coastguard Worker defer f1.Close() 170*333d2b36SAndroid Build Coastguard Worker 171*333d2b36SAndroid Build Coastguard Worker f2, err := ioutil.TempFile("", "bpfix") 172*333d2b36SAndroid Build Coastguard Worker if err != nil { 173*333d2b36SAndroid Build Coastguard Worker return 174*333d2b36SAndroid Build Coastguard Worker } 175*333d2b36SAndroid Build Coastguard Worker defer os.Remove(f2.Name()) 176*333d2b36SAndroid Build Coastguard Worker defer f2.Close() 177*333d2b36SAndroid Build Coastguard Worker 178*333d2b36SAndroid Build Coastguard Worker f1.Write(b1) 179*333d2b36SAndroid Build Coastguard Worker f2.Write(b2) 180*333d2b36SAndroid Build Coastguard Worker 181*333d2b36SAndroid Build Coastguard Worker data, err = exec.Command("diff", "-u", f1.Name(), f2.Name()).CombinedOutput() 182*333d2b36SAndroid Build Coastguard Worker if len(data) > 0 { 183*333d2b36SAndroid Build Coastguard Worker // diff exits with a non-zero status when the files don't match. 184*333d2b36SAndroid Build Coastguard Worker // Ignore that failure as long as we get output. 185*333d2b36SAndroid Build Coastguard Worker err = nil 186*333d2b36SAndroid Build Coastguard Worker } 187*333d2b36SAndroid Build Coastguard Worker return 188*333d2b36SAndroid Build Coastguard Worker 189*333d2b36SAndroid Build Coastguard Worker} 190