xref: /aosp_15_r20/build/blueprint/bpfmt/bpfmt.go (revision 1fa6dee971e1612fa5cc0aa5ca2d35a22e2c34a3)
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