背景:使用Goland開發,沒有vscode那種儲存檔案後自動格式化的功能,每次都得Alt+Shift+F來格式化,而且每次只能格式化一個檔案。而用Goland的Go fmt projects又會把vendor下的包也格式化了,這樣又很不科學。然後不想去找外掛,於是決定自己來折騰一下。預期目標是可以開發完成一個專案後,執行一條命令就能格式化專案中除vendor的所有go檔案。
實現原理
golang提供了格式化檔案的工具go fmt,使用方法是在控制檯執行go fmt *.go,就能格式化對應的go檔案。也就是說,只要我在程式碼裡面能夠獲取到某個專案目錄下除vendor外的所有go檔案,然後對每一個go檔案都執行go fmt操作即可。
具體實現
golang執行控制檯命令
golang自帶的os/exec包內建了對控制檯命令的操作,如下
func main(){
cmd := exec.Command("go","version")
cmd.Stdout = os.Stdout
cmd.Run()
}
複製程式碼
其中cmd.Stdout = os.Stdout是把此次執行的命令的輸出結果列印到系統的控制檯。還有更多的用法這裡不多解釋。
獲取某個資料夾下所有的go檔案
思路如下:開啟資料夾,遍歷資料夾下所有的東西,若是go檔案,則執行go fmt命令,若是資料夾,則遞迴一下。
func formatDir(path string) {
fileInfo, err := ioutil.ReadDir(path)
if err != nil {
fmt.Println("open directory error,", err.Error())
return
}
for _, file := range fileInfo {
fileName := path+"/"+file.Name()
if file.IsDir() {
// fmt.Println("dir :", fileName)
if file.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()
}
複製程式碼
加入goroutine
功能總體是完成了,但是因為本質上是一個檔案一個檔案地執行go fmt。其次開啟檔案的IO操作更是容易造成IO阻塞,那這樣就有用多執行緒的思想來改造的價值了,於是引入go routine。
func formatDir(path string) {
fileInfo, err := ioutil.ReadDir(path)
if err != nil {
fmt.Println("open directory error,", err.Error())
return
}
for _, fi := range fileInfo {
f.Add(1)
go func(file os.FileInfo) {// 這裡要注意避免直接使用for迴圈的引用變數fi,不然所有go routine操作的物件都是最後一次for迴圈取到的物件
defer f.Done()
fileName := path+"/"+file.Name()
if file.IsDir() {
// fmt.Println("dir :", fileName)
if file.Name() != "vendor" {
formatDir(fileName)
}
} else {
if strings.HasSuffix(file.Name(), "go") {
fmt.Println("format go file :", fileName)
goFormatFile(fileName)
}
}
}(fi)
}
}
複製程式碼
所有的程式
加點簡單的錯誤處理和封裝,加一個函式入口,程式碼就完成了,這裡就不重複貼了。程式碼全放在LSivan/fmt_directory,有興趣的觀眾老爺可以下載玩一下。
效果
相對路徑
$ go run main -d .
format go file : ./test_cmd/main.go
main.go
複製程式碼
絕對路徑
$ 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.go
複製程式碼