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  }