github.com/keysonzzz/kmg@v0.0.0-20151121023212-05317bfd7d39/kmg/SubCommand/goCmd/GoFmt.go (about) 1 package goCmd 2 3 import ( 4 "bytes" 5 "errors" 6 "io/ioutil" 7 "os" 8 "path/filepath" 9 "strings" 10 11 "runtime" 12 "sync" 13 14 "github.com/bronze1man/kmg/encoding/kmgGob" 15 "github.com/bronze1man/kmg/kmgConfig" 16 "github.com/bronze1man/kmg/kmgConsole" 17 "github.com/bronze1man/kmg/kmgCrypto" 18 "github.com/bronze1man/kmg/kmgFile" 19 "github.com/bronze1man/kmg/kmgTask" 20 "go/format" 21 ) 22 23 func runGoFmt() { 24 runtime.GOMAXPROCS(runtime.NumCPU()) 25 26 wd, err := os.Getwd() 27 kmgConsole.ExitOnErr(err) 28 err = GoFmtDir(wd) 29 kmgConsole.ExitOnErr(err) 30 } 31 32 func isGoFile(f os.FileInfo) bool { 33 // ignore non-Go files 34 name := f.Name() 35 return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") 36 } 37 38 func GoFmtDir(path string) error { 39 dir := &goFmtDir{ 40 cacheMap: map[string]bool{}, 41 newCacheMap: map[string]bool{}, 42 tasker: kmgTask.NewLimitThreadTaskManager(runtime.NumCPU()), 43 } 44 if kmgConfig.IsWdHaveEnv() { 45 kmgGob.ReadFile(kmgConfig.DefaultEnv().PathInTmp("gofmt.gob"), &dir.cacheMap) 46 //此处故意忽略错误,如果失败cacheMap应该没有变化,表示没有缓存而已. 47 dir.cacheAble = true 48 } 49 filepath.Walk(path, func(path string, f os.FileInfo, err error) error { 50 if err != nil { 51 dir.addErr(err) 52 return errors.New(path + " " + err.Error()) 53 } 54 if !isGoFile(f) { 55 return nil 56 } 57 dir.tasker.AddFunc(func() { 58 err = dir.processFile(path) 59 if err != nil { 60 dir.addErr(errors.New(path + " " + err.Error())) 61 } 62 }) 63 return nil 64 }) 65 dir.tasker.Close() 66 err := kmgGob.WriteFile(kmgConfig.DefaultEnv().PathInTmp("gofmt.gob"), dir.newCacheMap) 67 if err != nil { 68 return err 69 } 70 if len(dir.outErrList) == 0 { 71 return nil 72 } 73 s := "" 74 for _, er := range dir.outErrList { 75 s += er.Error() + "\n" 76 } 77 return errors.New(s) 78 } 79 80 type goFmtDir struct { 81 cacheAble bool 82 cacheMap map[string]bool 83 newCacheMap map[string]bool 84 outErrList []error 85 locker sync.Mutex 86 tasker *kmgTask.LimitThreadTaskManager 87 } 88 89 func (dir *goFmtDir) addErr(err error) { 90 dir.locker.Lock() 91 dir.outErrList = append(dir.outErrList, err) 92 dir.locker.Unlock() 93 } 94 func (dir *goFmtDir) processFile(filename string) (err error) { 95 src, err := kmgFile.ReadFile(filename) 96 if err != nil { 97 return err 98 } 99 srcMd5 := kmgCrypto.Md5Hex(src) 100 if dir.cacheMap[srcMd5] { 101 dir.locker.Lock() 102 dir.newCacheMap[srcMd5] = true 103 dir.locker.Unlock() 104 return nil 105 } 106 res, err := format.Source(src) 107 if err != nil { 108 return err 109 } 110 resMd5 := kmgCrypto.Md5Hex(res) 111 dir.locker.Lock() 112 dir.newCacheMap[resMd5] = true 113 dir.locker.Unlock() 114 if srcMd5 != resMd5 { 115 // formatting has changed 116 err = ioutil.WriteFile(filename, res, 0) 117 if err != nil { 118 return err 119 } 120 } 121 122 return err 123 } 124 125 var ( 126 // main operation modes 127 //options = &imports.Options{ 128 // TabWidth: 8, 129 // TabIndent: true, 130 // Comments: true, 131 // Fragment: false, 132 //} 133 ) 134 135 func processFile(filename string) error { 136 //opt := options 137 src, err := kmgFile.ReadFile(filename) 138 if err != nil { 139 return err 140 } 141 res, err := format.Source(src) 142 if err != nil { 143 return err 144 } 145 //res, err := imports.Process(filename, src, opt) 146 //if err != nil { 147 // return err 148 //} 149 150 if !bytes.Equal(src, res) { 151 // formatting has changed 152 err = ioutil.WriteFile(filename, res, 0) 153 if err != nil { 154 return err 155 } 156 } 157 158 return err 159 }