github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/tools/cmd/goimports/goimports.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "bytes" 9 "flag" 10 "fmt" 11 "go/scanner" 12 "io" 13 "io/ioutil" 14 "os" 15 "os/exec" 16 "path/filepath" 17 "runtime" 18 "strings" 19 20 "golang.org/x/tools/imports" 21 ) 22 23 var ( 24 // main operation modes 25 list = flag.Bool("l", false, "list files whose formatting differs from goimport's") 26 write = flag.Bool("w", false, "write result to (source) file instead of stdout") 27 doDiff = flag.Bool("d", false, "display diffs instead of rewriting files") 28 29 options = &imports.Options{ 30 TabWidth: 8, 31 TabIndent: true, 32 Comments: true, 33 Fragment: true, 34 } 35 exitCode = 0 36 ) 37 38 func init() { 39 flag.BoolVar(&options.AllErrors, "e", false, "report all errors (not just the first 10 on different lines)") 40 } 41 42 func report(err error) { 43 scanner.PrintError(os.Stderr, err) 44 exitCode = 2 45 } 46 47 func usage() { 48 fmt.Fprintf(os.Stderr, "usage: goimports [flags] [path ...]\n") 49 flag.PrintDefaults() 50 os.Exit(2) 51 } 52 53 func isGoFile(f os.FileInfo) bool { 54 // ignore non-Go files 55 name := f.Name() 56 return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") 57 } 58 59 func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error { 60 opt := options 61 if stdin { 62 nopt := *options 63 nopt.Fragment = true 64 opt = &nopt 65 } 66 67 if in == nil { 68 f, err := os.Open(filename) 69 if err != nil { 70 return err 71 } 72 defer f.Close() 73 in = f 74 } 75 76 src, err := ioutil.ReadAll(in) 77 if err != nil { 78 return err 79 } 80 81 res, err := imports.Process(filename, src, opt) 82 if err != nil { 83 return err 84 } 85 86 if !bytes.Equal(src, res) { 87 // formatting has changed 88 if *list { 89 fmt.Fprintln(out, filename) 90 } 91 if *write { 92 err = ioutil.WriteFile(filename, res, 0) 93 if err != nil { 94 return err 95 } 96 } 97 if *doDiff { 98 data, err := diff(src, res) 99 if err != nil { 100 return fmt.Errorf("computing diff: %s", err) 101 } 102 fmt.Printf("diff %s gofmt/%s\n", filename, filename) 103 out.Write(data) 104 } 105 } 106 107 if !*list && !*write && !*doDiff { 108 _, err = out.Write(res) 109 } 110 111 return err 112 } 113 114 func visitFile(path string, f os.FileInfo, err error) error { 115 if err == nil && isGoFile(f) { 116 err = processFile(path, nil, os.Stdout, false) 117 } 118 if err != nil { 119 report(err) 120 } 121 return nil 122 } 123 124 func walkDir(path string) { 125 filepath.Walk(path, visitFile) 126 } 127 128 func main() { 129 runtime.GOMAXPROCS(runtime.NumCPU()) 130 131 // call gofmtMain in a separate function 132 // so that it can use defer and have them 133 // run before the exit. 134 gofmtMain() 135 os.Exit(exitCode) 136 } 137 138 // parseFlags parses command line flags and returns the paths to process. 139 // It's a var so that custom implementations can replace it in other files. 140 var parseFlags = func() []string { 141 flag.Parse() 142 return flag.Args() 143 } 144 145 func gofmtMain() { 146 flag.Usage = usage 147 paths := parseFlags() 148 149 if options.TabWidth < 0 { 150 fmt.Fprintf(os.Stderr, "negative tabwidth %d\n", options.TabWidth) 151 exitCode = 2 152 return 153 } 154 155 if len(paths) == 0 { 156 if err := processFile("<standard input>", os.Stdin, os.Stdout, true); err != nil { 157 report(err) 158 } 159 return 160 } 161 162 for _, path := range paths { 163 switch dir, err := os.Stat(path); { 164 case err != nil: 165 report(err) 166 case dir.IsDir(): 167 walkDir(path) 168 default: 169 if err := processFile(path, nil, os.Stdout, false); err != nil { 170 report(err) 171 } 172 } 173 } 174 } 175 176 func diff(b1, b2 []byte) (data []byte, err error) { 177 f1, err := ioutil.TempFile("", "gofmt") 178 if err != nil { 179 return 180 } 181 defer os.Remove(f1.Name()) 182 defer f1.Close() 183 184 f2, err := ioutil.TempFile("", "gofmt") 185 if err != nil { 186 return 187 } 188 defer os.Remove(f2.Name()) 189 defer f2.Close() 190 191 f1.Write(b1) 192 f2.Write(b2) 193 194 data, err = exec.Command("diff", "-u", f1.Name(), f2.Name()).CombinedOutput() 195 if len(data) > 0 { 196 // diff exits with a non-zero status when the files don't match. 197 // Ignore that failure as long as we get output. 198 err = nil 199 } 200 return 201 }