diff options
author | Robert Griesemer <gri@golang.org> | 2009-10-20 12:07:31 -0700 |
---|---|---|
committer | Robert Griesemer <gri@golang.org> | 2009-10-20 12:07:31 -0700 |
commit | a16808f7d83d2dce5fda23a49404c84cf15f5759 (patch) | |
tree | 719dffea33bd5034f3bad8fe0bef5dd12d3d1de4 | |
parent | 93fb42f1b2dda62a5dcb9a945b4ec621fdbbfcbe (diff) | |
download | golang-a16808f7d83d2dce5fda23a49404c84cf15f5759.tar.gz |
Updated and simplified gofmt.
- operates on stdin, a single file, or all files in a file tree
- setting -w flag writes to (source) file instead of stdout
- setting -l flag lists files whose formatting has changed
R=rsc
DELTA=201 (102 added, 71 deleted, 28 changed)
OCL=35890
CL=35926
-rw-r--r-- | src/cmd/gofmt/gofmt.go | 207 | ||||
-rwxr-xr-x | src/cmd/gofmt/test.sh | 2 |
2 files changed, 120 insertions, 89 deletions
diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go index bdcfbc5f3..c751e0c3d 100644 --- a/src/cmd/gofmt/gofmt.go +++ b/src/cmd/gofmt/gofmt.go @@ -5,40 +5,45 @@ package main import ( - "flag"; - "fmt"; - "go/ast"; - "go/parser"; - "go/printer"; - "go/scanner"; - "os"; - pathutil "path"; - "strings"; + "bytes"; + "flag"; + "fmt"; + "go/parser"; + "go/printer"; + "go/scanner"; + "io"; + "os"; + pathutil "path"; + "strings"; ) -const pkgDir = "src/pkg" // relative to $GOROOT - - var ( - goroot = flag.String("goroot", os.Getenv("GOROOT"), "Go root directory"); + // main operation modes + list = flag.Bool("l", false, "list files whose formatting differs from gofmt's"); + write = flag.Bool("w", false, "write result to (source) file instead of stdout"); - // operation modes - allgo = flag.Bool("a", false, "include all .go files for package"); - comments = flag.Bool("c", false, "omit comments"); - silent = flag.Bool("s", false, "silent mode: parsing only"); - verbose = flag.Bool("v", false, "verbose mode: trace parsing"); - exports = flag.Bool("x", false, "show exports only"); + // debugging support + comments = flag.Bool("comments", true, "print comments"); + trace = flag.Bool("trace", false, "print names of processed files to stderr and parse traces to stdout"); // layout control + align = flag.Bool("align", true, "align columns"); tabwidth = flag.Int("tabwidth", 8, "tab width"); - rawformat = flag.Bool("rawformat", false, "do not use a tabwriter"); - usespaces = flag.Bool("spaces", false, "align with blanks instead of tabs"); + usespaces = flag.Bool("spaces", false, "align with spaces instead of tabs"); ) +var exitCode = 0 + +func report(err os.Error) { + scanner.PrintError(os.Stderr, err); + exitCode = 2; +} + + func usage() { - fmt.Fprintf(os.Stderr, "usage: gofmt [flags] [file.go | pkgpath]\n"); + fmt.Fprintf(os.Stderr, "usage: gofmt [flags] [path ...]\n"); flag.PrintDefaults(); os.Exit(2); } @@ -46,67 +51,106 @@ func usage() { func parserMode() uint { mode := uint(0); - if !*comments { + if *comments { mode |= parser.ParseComments; } - if *verbose { + if *trace { mode |= parser.Trace; } return mode; } -func isPkgFile(d *os.Dir) bool { - // ignore non-Go files - if !d.IsRegular() || strings.HasPrefix(d.Name, ".") || !strings.HasSuffix(d.Name, ".go") { - return false; +func printerMode() uint { + mode := uint(0); + if !*align { + mode |= printer.RawFormat; } + if *usespaces { + mode |= printer.UseSpaces; + } + return mode; +} + - // ignore test files unless explicitly included - return *allgo || !strings.HasSuffix(d.Name, "_test.go"); +func isGoFile(d *os.Dir) bool { + // ignore non-Go files + return d.IsRegular() && !strings.HasPrefix(d.Name, ".") && strings.HasSuffix(d.Name, ".go"); } -func getPackage(path string) (*ast.Package, os.Error) { - if len(path) == 0 { - return nil, os.NewError("no path specified"); +func processFile(filename string) os.Error { + if *trace { + fmt.Fprintln(os.Stderr, filename); } - if strings.HasSuffix(path, ".go") || path == "/dev/stdin" { - // single go file - src, err := parser.ParseFile(path, nil, parserMode()); - if err != nil { - return nil, err; - } - dirname, filename := pathutil.Split(path); - return &ast.Package{src.Name.Value, dirname, map[string]*ast.File{filename: src}}, nil; + src, err := io.ReadFile(filename); + if err != nil { + return err; + } + + file, err := parser.ParseFile(filename, src, parserMode()); + if err != nil { + return err; + } + + var res bytes.Buffer; + _, err = printer.Fprint(&res, file, printerMode(), *tabwidth); + if err != nil { + return err; } - // len(path) > 0 - switch ch := path[0]; { - case ch == '.': - // cwd-relative path - if cwd, err := os.Getwd(); err == nil { - path = pathutil.Join(cwd, path); + if bytes.Compare(src, res.Bytes()) != 0 { + // formatting has changed + if *list { + fmt.Fprintln(os.Stdout, filename); + } + if *write { + err = io.WriteFile(filename, res.Bytes(), 0); + if err != nil { + return err; + } } - case ch != '/': - // goroot/pkgDir-relative path - path = pathutil.Join(pathutil.Join(*goroot, pkgDir), path); } - return parser.ParsePackage(path, isPkgFile, parserMode()); + if !*list && !*write { + _, err = os.Stdout.Write(res.Bytes()); + } + + return err; } -func printerMode() uint { - mode := uint(0); - if *rawformat { - mode |= printer.RawFormat; - } - if *usespaces { - mode |= printer.UseSpaces; +type fileVisitor chan os.Error + +func (v fileVisitor) VisitDir(path string, d *os.Dir) bool { + return true; +} + + +func (v fileVisitor) VisitFile(path string, d *os.Dir) { + if isGoFile(d) { + v <- nil; // synchronize error handler + if err := processFile(path); err != nil { + v <- err; + } } - return mode; +} + + +func walkDir(path string) { + // start an error handler + v := make(fileVisitor); + go func() { + for err := range v { + if err != nil { + report(err); + } + } + }(); + // walk the tree + pathutil.Walk(path, v, v); + close(v); } @@ -114,38 +158,25 @@ func main() { flag.Usage = usage; flag.Parse(); - path := ""; - switch flag.NArg() { - case 0: - path = "/dev/stdin"; - case 1: - path = flag.Arg(0); - default: - usage(); - } - - pkg, err := getPackage(path); - if err != nil { - scanner.PrintError(os.Stderr, err); - os.Exit(1); + if flag.NArg() == 0 { + if err := processFile("/dev/stdin"); err != nil { + report(err); + } } - if !*silent { - if *exports { - ast.PackageExports(pkg); - _, err := printer.Fprint(os.Stdout, ast.MergePackageFiles(pkg), printerMode(), *tabwidth); - if err != nil { - fmt.Fprint(os.Stderr, err); - os.Exit(2); - } - } else { - for _, src := range pkg.Files { - _, err := printer.Fprint(os.Stdout, src, printerMode(), *tabwidth); - if err != nil { - fmt.Fprint(os.Stderr, err); - os.Exit(2); - } + for i := 0; i < flag.NArg(); i++ { + path := flag.Arg(i); + switch dir, err := os.Stat(path); { + case err != nil: + report(err); + case dir.IsRegular(): + if err := processFile(path); err != nil { + report(err); } + case dir.IsDirectory(): + walkDir(path); } } + + os.Exit(exitCode); } diff --git a/src/cmd/gofmt/test.sh b/src/cmd/gofmt/test.sh index 79d1a34de..8e465c3c6 100755 --- a/src/cmd/gofmt/test.sh +++ b/src/cmd/gofmt/test.sh @@ -70,7 +70,7 @@ cleanup() { silent() { cleanup - $CMD -s $1 > $TMP1 + $CMD $1 > /dev/null 2> $TMP1 if [ $? != 0 ]; then cat $TMP1 echo "Error (silent mode test): test.sh $1" |