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