1*1fa6dee9SAndroid Build Coastguard Worker// Mostly copied from Go's src/cmd/gofmt: 2*1fa6dee9SAndroid Build Coastguard Worker// Copyright 2009 The Go Authors. All rights reserved. 3*1fa6dee9SAndroid Build Coastguard Worker// Use of this source code is governed by a BSD-style 4*1fa6dee9SAndroid Build Coastguard Worker// license that can be found in the LICENSE file. 5*1fa6dee9SAndroid Build Coastguard Worker 6*1fa6dee9SAndroid Build Coastguard Workerpackage main 7*1fa6dee9SAndroid Build Coastguard Worker 8*1fa6dee9SAndroid Build Coastguard Workerimport ( 9*1fa6dee9SAndroid Build Coastguard Worker "bytes" 10*1fa6dee9SAndroid Build Coastguard Worker "flag" 11*1fa6dee9SAndroid Build Coastguard Worker "fmt" 12*1fa6dee9SAndroid Build Coastguard Worker "io" 13*1fa6dee9SAndroid Build Coastguard Worker "io/ioutil" 14*1fa6dee9SAndroid Build Coastguard Worker "os" 15*1fa6dee9SAndroid Build Coastguard Worker "os/exec" 16*1fa6dee9SAndroid Build Coastguard Worker "path/filepath" 17*1fa6dee9SAndroid Build Coastguard Worker "strings" 18*1fa6dee9SAndroid Build Coastguard Worker 19*1fa6dee9SAndroid Build Coastguard Worker "github.com/google/blueprint/parser" 20*1fa6dee9SAndroid Build Coastguard Worker) 21*1fa6dee9SAndroid Build Coastguard Worker 22*1fa6dee9SAndroid Build Coastguard Workervar ( 23*1fa6dee9SAndroid Build Coastguard Worker // main operation modes 24*1fa6dee9SAndroid Build Coastguard Worker list = flag.Bool("l", false, "list files whose formatting differs from bpfmt's") 25*1fa6dee9SAndroid Build Coastguard Worker overwriteSourceFile = flag.Bool("w", false, "write result to (source) file") 26*1fa6dee9SAndroid Build Coastguard Worker writeToStout = flag.Bool("o", false, "write result to stdout") 27*1fa6dee9SAndroid Build Coastguard Worker doDiff = flag.Bool("d", false, "display diffs instead of rewriting files") 28*1fa6dee9SAndroid Build Coastguard Worker sortLists = flag.Bool("s", false, "sort arrays") 29*1fa6dee9SAndroid Build Coastguard Worker) 30*1fa6dee9SAndroid Build Coastguard Worker 31*1fa6dee9SAndroid Build Coastguard Workervar ( 32*1fa6dee9SAndroid Build Coastguard Worker exitCode = 0 33*1fa6dee9SAndroid Build Coastguard Worker) 34*1fa6dee9SAndroid Build Coastguard Worker 35*1fa6dee9SAndroid Build Coastguard Workerfunc report(err error) { 36*1fa6dee9SAndroid Build Coastguard Worker fmt.Fprintln(os.Stderr, err) 37*1fa6dee9SAndroid Build Coastguard Worker exitCode = 2 38*1fa6dee9SAndroid Build Coastguard Worker} 39*1fa6dee9SAndroid Build Coastguard Worker 40*1fa6dee9SAndroid Build Coastguard Workerfunc usage() { 41*1fa6dee9SAndroid Build Coastguard Worker usageViolation("") 42*1fa6dee9SAndroid Build Coastguard Worker} 43*1fa6dee9SAndroid Build Coastguard Worker 44*1fa6dee9SAndroid Build Coastguard Workerfunc usageViolation(violation string) { 45*1fa6dee9SAndroid Build Coastguard Worker fmt.Fprintln(os.Stderr, violation) 46*1fa6dee9SAndroid Build Coastguard Worker fmt.Fprintln(os.Stderr, "usage: bpfmt [flags] [path ...]") 47*1fa6dee9SAndroid Build Coastguard Worker flag.PrintDefaults() 48*1fa6dee9SAndroid Build Coastguard Worker os.Exit(2) 49*1fa6dee9SAndroid Build Coastguard Worker} 50*1fa6dee9SAndroid Build Coastguard Worker 51*1fa6dee9SAndroid Build Coastguard Workerfunc processFile(filename string, out io.Writer) error { 52*1fa6dee9SAndroid Build Coastguard Worker f, err := os.Open(filename) 53*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 54*1fa6dee9SAndroid Build Coastguard Worker return err 55*1fa6dee9SAndroid Build Coastguard Worker } 56*1fa6dee9SAndroid Build Coastguard Worker defer f.Close() 57*1fa6dee9SAndroid Build Coastguard Worker 58*1fa6dee9SAndroid Build Coastguard Worker return processReader(filename, f, out) 59*1fa6dee9SAndroid Build Coastguard Worker} 60*1fa6dee9SAndroid Build Coastguard Worker 61*1fa6dee9SAndroid Build Coastguard Workerfunc processReader(filename string, in io.Reader, out io.Writer) error { 62*1fa6dee9SAndroid Build Coastguard Worker src, err := ioutil.ReadAll(in) 63*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 64*1fa6dee9SAndroid Build Coastguard Worker return err 65*1fa6dee9SAndroid Build Coastguard Worker } 66*1fa6dee9SAndroid Build Coastguard Worker 67*1fa6dee9SAndroid Build Coastguard Worker r := bytes.NewBuffer(src) 68*1fa6dee9SAndroid Build Coastguard Worker 69*1fa6dee9SAndroid Build Coastguard Worker file, errs := parser.Parse(filename, r) 70*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 71*1fa6dee9SAndroid Build Coastguard Worker for _, err := range errs { 72*1fa6dee9SAndroid Build Coastguard Worker fmt.Fprintln(os.Stderr, err) 73*1fa6dee9SAndroid Build Coastguard Worker } 74*1fa6dee9SAndroid Build Coastguard Worker return fmt.Errorf("%d parsing errors", len(errs)) 75*1fa6dee9SAndroid Build Coastguard Worker } 76*1fa6dee9SAndroid Build Coastguard Worker 77*1fa6dee9SAndroid Build Coastguard Worker if *sortLists { 78*1fa6dee9SAndroid Build Coastguard Worker parser.SortLists(file) 79*1fa6dee9SAndroid Build Coastguard Worker } 80*1fa6dee9SAndroid Build Coastguard Worker 81*1fa6dee9SAndroid Build Coastguard Worker res, err := parser.Print(file) 82*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 83*1fa6dee9SAndroid Build Coastguard Worker return err 84*1fa6dee9SAndroid Build Coastguard Worker } 85*1fa6dee9SAndroid Build Coastguard Worker 86*1fa6dee9SAndroid Build Coastguard Worker if !bytes.Equal(src, res) { 87*1fa6dee9SAndroid Build Coastguard Worker // formatting has changed 88*1fa6dee9SAndroid Build Coastguard Worker if *list { 89*1fa6dee9SAndroid Build Coastguard Worker fmt.Fprintln(out, filename) 90*1fa6dee9SAndroid Build Coastguard Worker } 91*1fa6dee9SAndroid Build Coastguard Worker if *overwriteSourceFile { 92*1fa6dee9SAndroid Build Coastguard Worker err = ioutil.WriteFile(filename, res, 0644) 93*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 94*1fa6dee9SAndroid Build Coastguard Worker return err 95*1fa6dee9SAndroid Build Coastguard Worker } 96*1fa6dee9SAndroid Build Coastguard Worker } 97*1fa6dee9SAndroid Build Coastguard Worker if *doDiff { 98*1fa6dee9SAndroid Build Coastguard Worker data, err := diff(src, res) 99*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 100*1fa6dee9SAndroid Build Coastguard Worker return fmt.Errorf("computing diff: %s", err) 101*1fa6dee9SAndroid Build Coastguard Worker } 102*1fa6dee9SAndroid Build Coastguard Worker fmt.Printf("diff %s bpfmt/%s\n", filename, filename) 103*1fa6dee9SAndroid Build Coastguard Worker out.Write(data) 104*1fa6dee9SAndroid Build Coastguard Worker } 105*1fa6dee9SAndroid Build Coastguard Worker } 106*1fa6dee9SAndroid Build Coastguard Worker 107*1fa6dee9SAndroid Build Coastguard Worker if !*list && !*overwriteSourceFile && !*doDiff { 108*1fa6dee9SAndroid Build Coastguard Worker _, err = out.Write(res) 109*1fa6dee9SAndroid Build Coastguard Worker } 110*1fa6dee9SAndroid Build Coastguard Worker 111*1fa6dee9SAndroid Build Coastguard Worker return err 112*1fa6dee9SAndroid Build Coastguard Worker} 113*1fa6dee9SAndroid Build Coastguard Worker 114*1fa6dee9SAndroid Build Coastguard Workerfunc isBlueprintFile(f os.FileInfo) bool { 115*1fa6dee9SAndroid Build Coastguard Worker name := f.Name() 116*1fa6dee9SAndroid Build Coastguard Worker return !f.IsDir() && (name == "Blueprints" || (!strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".bp"))) 117*1fa6dee9SAndroid Build Coastguard Worker} 118*1fa6dee9SAndroid Build Coastguard Worker 119*1fa6dee9SAndroid Build Coastguard Workerfunc walkDir(path string) { 120*1fa6dee9SAndroid Build Coastguard Worker visitFile := func(path string, f os.FileInfo, err error) error { 121*1fa6dee9SAndroid Build Coastguard Worker if err == nil && isBlueprintFile(f) { 122*1fa6dee9SAndroid Build Coastguard Worker err = processFile(path, os.Stdout) 123*1fa6dee9SAndroid Build Coastguard Worker } 124*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 125*1fa6dee9SAndroid Build Coastguard Worker report(err) 126*1fa6dee9SAndroid Build Coastguard Worker } 127*1fa6dee9SAndroid Build Coastguard Worker return nil 128*1fa6dee9SAndroid Build Coastguard Worker } 129*1fa6dee9SAndroid Build Coastguard Worker 130*1fa6dee9SAndroid Build Coastguard Worker filepath.Walk(path, visitFile) 131*1fa6dee9SAndroid Build Coastguard Worker} 132*1fa6dee9SAndroid Build Coastguard Worker 133*1fa6dee9SAndroid Build Coastguard Workerfunc main() { 134*1fa6dee9SAndroid Build Coastguard Worker flag.Usage = usage 135*1fa6dee9SAndroid Build Coastguard Worker flag.Parse() 136*1fa6dee9SAndroid Build Coastguard Worker 137*1fa6dee9SAndroid Build Coastguard Worker if !*writeToStout && !*overwriteSourceFile && !*doDiff && !*list { 138*1fa6dee9SAndroid Build Coastguard Worker usageViolation("one of -d, -l, -o, or -w is required") 139*1fa6dee9SAndroid Build Coastguard Worker } 140*1fa6dee9SAndroid Build Coastguard Worker 141*1fa6dee9SAndroid Build Coastguard Worker if flag.NArg() == 0 { 142*1fa6dee9SAndroid Build Coastguard Worker // file to parse is stdin 143*1fa6dee9SAndroid Build Coastguard Worker if *overwriteSourceFile { 144*1fa6dee9SAndroid Build Coastguard Worker fmt.Fprintln(os.Stderr, "error: cannot use -w with standard input") 145*1fa6dee9SAndroid Build Coastguard Worker os.Exit(2) 146*1fa6dee9SAndroid Build Coastguard Worker } 147*1fa6dee9SAndroid Build Coastguard Worker if err := processReader("<standard input>", os.Stdin, os.Stdout); err != nil { 148*1fa6dee9SAndroid Build Coastguard Worker report(err) 149*1fa6dee9SAndroid Build Coastguard Worker } 150*1fa6dee9SAndroid Build Coastguard Worker os.Exit(exitCode) 151*1fa6dee9SAndroid Build Coastguard Worker } 152*1fa6dee9SAndroid Build Coastguard Worker 153*1fa6dee9SAndroid Build Coastguard Worker for i := 0; i < flag.NArg(); i++ { 154*1fa6dee9SAndroid Build Coastguard Worker path := flag.Arg(i) 155*1fa6dee9SAndroid Build Coastguard Worker switch dir, err := os.Stat(path); { 156*1fa6dee9SAndroid Build Coastguard Worker case err != nil: 157*1fa6dee9SAndroid Build Coastguard Worker report(err) 158*1fa6dee9SAndroid Build Coastguard Worker case dir.IsDir(): 159*1fa6dee9SAndroid Build Coastguard Worker walkDir(path) 160*1fa6dee9SAndroid Build Coastguard Worker default: 161*1fa6dee9SAndroid Build Coastguard Worker if err := processFile(path, os.Stdout); err != nil { 162*1fa6dee9SAndroid Build Coastguard Worker report(err) 163*1fa6dee9SAndroid Build Coastguard Worker } 164*1fa6dee9SAndroid Build Coastguard Worker } 165*1fa6dee9SAndroid Build Coastguard Worker } 166*1fa6dee9SAndroid Build Coastguard Worker 167*1fa6dee9SAndroid Build Coastguard Worker os.Exit(exitCode) 168*1fa6dee9SAndroid Build Coastguard Worker} 169*1fa6dee9SAndroid Build Coastguard Worker 170*1fa6dee9SAndroid Build Coastguard Workerfunc diff(b1, b2 []byte) (data []byte, err error) { 171*1fa6dee9SAndroid Build Coastguard Worker f1, err := ioutil.TempFile("", "bpfmt") 172*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 173*1fa6dee9SAndroid Build Coastguard Worker return 174*1fa6dee9SAndroid Build Coastguard Worker } 175*1fa6dee9SAndroid Build Coastguard Worker defer os.Remove(f1.Name()) 176*1fa6dee9SAndroid Build Coastguard Worker defer f1.Close() 177*1fa6dee9SAndroid Build Coastguard Worker 178*1fa6dee9SAndroid Build Coastguard Worker f2, err := ioutil.TempFile("", "bpfmt") 179*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 180*1fa6dee9SAndroid Build Coastguard Worker return 181*1fa6dee9SAndroid Build Coastguard Worker } 182*1fa6dee9SAndroid Build Coastguard Worker defer os.Remove(f2.Name()) 183*1fa6dee9SAndroid Build Coastguard Worker defer f2.Close() 184*1fa6dee9SAndroid Build Coastguard Worker 185*1fa6dee9SAndroid Build Coastguard Worker f1.Write(b1) 186*1fa6dee9SAndroid Build Coastguard Worker f2.Write(b2) 187*1fa6dee9SAndroid Build Coastguard Worker 188*1fa6dee9SAndroid Build Coastguard Worker data, err = exec.Command("diff", "-u", f1.Name(), f2.Name()).CombinedOutput() 189*1fa6dee9SAndroid Build Coastguard Worker if len(data) > 0 { 190*1fa6dee9SAndroid Build Coastguard Worker // diff exits with a non-zero status when the files don't match. 191*1fa6dee9SAndroid Build Coastguard Worker // Ignore that failure as long as we get output. 192*1fa6dee9SAndroid Build Coastguard Worker err = nil 193*1fa6dee9SAndroid Build Coastguard Worker } 194*1fa6dee9SAndroid Build Coastguard Worker return 195*1fa6dee9SAndroid Build Coastguard Worker 196*1fa6dee9SAndroid Build Coastguard Worker} 197