用golang写个格式化go文件的小工具

背景:使用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
复制代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值