Background: Goland does not automatically format files as vscode does. You have to use Alt+Shift+F to format files at a time, and only one file at a time. Goland’s Go FMT Projects will format the package under vendor, which is very unscientific. Instead of looking for plug-ins, he decided to do it himself. The goal is to be able to develop a project and run a command to format all go files in the project except vendor.

Realize the principle of

Golang provides a file formatting tool called Go FMT, which is used by running go FMT *. Go from the console to format the corresponding GO file. That is to say, as long as I can get all the GO files in a project directory except vendor in the code, I can perform the GO FMT operation on each go file.

The specific implementation

Golang executes the console command

The OS /exec package that comes with Golang has built-in operations on console commands, as shown below

func main(){
	cmd := exec.Command("go"."version")
	cmd.Stdout = os.Stdout
	cmd.Run()
}
Copy the code

Cmd. Stdout = os.Stdout prints the output of the command to the console of the system. There are many more uses that are not explained here.

Get all go files in a folder

The idea is as follows: Open a folder and iterate through everything in it. If it’s a go file, run the go FMT command. If it’s a folder, recurse.

func formatDir(path string) {
        fileInfo, err := ioutil.ReadDir(path)
        iferr ! = nil { fmt.Println("open directory error,", err.Error())
                return
        }
        for _, file := range fileInfo {
			fileName := path+"/"+file.Name()
			if file.IsDir() {
					// fmt.Println("dir :", fileName)
					iffile.Name() ! ="vendor" {
							formatDir(fileName)
					}
			} else {
					if strings.HasSuffix(file.Name(), "go") {
							fmt.Println("format go file :", fileName)
							goFormatFile(fileName)
					}
			}
                
        }
}
func goFormatFile(fileName string) {
        cmd := exec.Command("go"."fmt", fileName)
        cmd.Stdout = os.Stdout
        cmd.Run()
}
Copy the code

Join goroutine

The functionality is generally complete, but because of the nature of doing go FMT file by file. Secondly, the IO operation of opening files is more likely to cause I/O blocking, so it is useful to change the value of multi-threading, so the go routine is introduced.

func formatDir(path string) {
        fileInfo, err := ioutil.ReadDir(path)
        iferr ! = nil { fmt.Println("open directory error,", err.Error())
                return
        }
        for _, fiFileInfo := range fileInfo {f.dd (1) go func(file os.fileinfo)forThe reference variable of the loopfiOtherwise, all go routine objects are the last timeforThe looping object defer f.one () fileName := path+"/"+file.Name()
                        if file.IsDir() {
                                // fmt.Println("dir :", fileName)
                                iffile.Name() ! ="vendor" {
                                        formatDir(fileName)
                                }
                        } else {
                                if strings.HasSuffix(file.Name(), "go") {
                                        fmt.Println("format go file :", fileName)
                                        goFormatFile(fileName)
                                }
                        }
                }(fi)}}Copy the code

All the programs

Add some simple error handling and encapsulation, add a function entry, and the code is done. Code in LSivan/ FMt_directory, interested audience master can download to play.

The effect

Relative paths

$ go run main -d .
format go file : ./test_cmd/main.go
main.go
Copy the code

An absolute path

$ go run main.go -d $GOPATH/src/works_demo/liangxingwei/ format go file : /home/superman/workspace/go/src/works_demo/liangxingwei/test_goc/main.go format go file : /home/superman/workspace/go/src/works_demo/liangxingwei/test_influxdb/msg_queue/queue.go format go file : /home/superman/workspace/go/src/works_demo/liangxingwei/test_radix/main.go format go file : /home/superman/workspace/go/src/works_demo/liangxingwei/test_redigo/main.go format go file : /home/superman/workspace/go/src/works_demo/liangxingwei/test_redis/main.go format go file : /home/superman/workspace/go/src/works_demo/liangxingwei/test_worker/main.go format go file : /home/superman/workspace/go/src/works_demo/liangxingwei/test_goc/add/add.go .. /test_goc/add/add.go .. /test_goc/main.goCopy the code