github.com/corona10/go@v0.0.0-20180224231303-7a218942be57/src/cmd/go/internal/fmtcmd/fmt.go (about)

     1  // Copyright 2011 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 fmtcmd implements the ``go fmt'' command.
     6  package fmtcmd
     7  
     8  import (
     9  	"os"
    10  	"path/filepath"
    11  	"runtime"
    12  	"strings"
    13  	"sync"
    14  
    15  	"cmd/go/internal/base"
    16  	"cmd/go/internal/cfg"
    17  	"cmd/go/internal/load"
    18  	"cmd/go/internal/str"
    19  )
    20  
    21  func init() {
    22  	base.AddBuildFlagsNX(&CmdFmt.Flag)
    23  }
    24  
    25  var CmdFmt = &base.Command{
    26  	Run:       runFmt,
    27  	UsageLine: "fmt [-n] [-x] [packages]",
    28  	Short:     "gofmt (reformat) package sources",
    29  	Long: `
    30  Fmt runs the command 'gofmt -l -w' on the packages named
    31  by the import paths. It prints the names of the files that are modified.
    32  
    33  For more about gofmt, see 'go doc cmd/gofmt'.
    34  For more about specifying packages, see 'go help packages'.
    35  
    36  The -n flag prints commands that would be executed.
    37  The -x flag prints commands as they are executed.
    38  
    39  To run gofmt with specific options, run gofmt itself.
    40  
    41  See also: go fix, go vet.
    42  	`,
    43  }
    44  
    45  func runFmt(cmd *base.Command, args []string) {
    46  	gofmt := gofmtPath()
    47  	procs := runtime.GOMAXPROCS(0)
    48  	var wg sync.WaitGroup
    49  	wg.Add(procs)
    50  	fileC := make(chan string, 2*procs)
    51  	for i := 0; i < procs; i++ {
    52  		go func() {
    53  			defer wg.Done()
    54  			for file := range fileC {
    55  				base.Run(str.StringList(gofmt, "-l", "-w", file))
    56  			}
    57  		}()
    58  	}
    59  	for _, pkg := range load.PackagesAndErrors(args) {
    60  		if pkg.Error != nil {
    61  			if strings.HasPrefix(pkg.Error.Err, "build constraints exclude all Go files") {
    62  				// Skip this error, as we will format
    63  				// all files regardless.
    64  			} else {
    65  				base.Errorf("can't load package: %s", pkg.Error)
    66  				continue
    67  			}
    68  		}
    69  		// Use pkg.gofiles instead of pkg.Dir so that
    70  		// the command only applies to this package,
    71  		// not to packages in subdirectories.
    72  		files := base.RelPaths(pkg.InternalAllGoFiles())
    73  		for _, file := range files {
    74  			fileC <- file
    75  		}
    76  	}
    77  	close(fileC)
    78  	wg.Wait()
    79  }
    80  
    81  func gofmtPath() string {
    82  	gofmt := "gofmt"
    83  	if base.ToolIsWindows {
    84  		gofmt += base.ToolWindowsExtension
    85  	}
    86  
    87  	gofmtPath := filepath.Join(cfg.GOBIN, gofmt)
    88  	if _, err := os.Stat(gofmtPath); err == nil {
    89  		return gofmtPath
    90  	}
    91  
    92  	gofmtPath = filepath.Join(cfg.GOROOT, "bin", gofmt)
    93  	if _, err := os.Stat(gofmtPath); err == nil {
    94  		return gofmtPath
    95  	}
    96  
    97  	// fallback to looking for gofmt in $PATH
    98  	return "gofmt"
    99  }