main.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. package main
  2. import (
  3. "bufio"
  4. "bytes"
  5. "crypto/sha256"
  6. "fmt"
  7. "go/ast"
  8. "go/format"
  9. "go/parser"
  10. "go/token"
  11. "io/ioutil"
  12. "log"
  13. "os"
  14. "path/filepath"
  15. "strings"
  16. "github.com/xinliangnote/go-gin-api/pkg/errors"
  17. "go.uber.org/zap"
  18. "golang.org/x/tools/go/packages"
  19. )
  20. var stdlib = make(map[string]bool)
  21. func init() {
  22. pkgs, err := packages.Load(nil, "std")
  23. if err != nil {
  24. log.Fatal("get go stdlib err", zap.Error(err))
  25. }
  26. for _, pkg := range pkgs {
  27. if !strings.HasPrefix(pkg.ID, "vendor") {
  28. stdlib[pkg.ID] = true
  29. }
  30. }
  31. }
  32. var module string
  33. func init() {
  34. file, err := os.Open("./go.mod")
  35. if err != nil {
  36. log.Fatal("no go.mod file found", zap.Error(err))
  37. }
  38. defer file.Close()
  39. scanner := bufio.NewScanner(file)
  40. for scanner.Scan() {
  41. line := strings.TrimSpace(scanner.Text())
  42. if strings.HasPrefix(line, "module ") {
  43. module = strings.TrimSpace(line[7:])
  44. break
  45. }
  46. }
  47. if module == "" {
  48. log.Fatal("go.mod illegal")
  49. }
  50. }
  51. func main() {
  52. err := filepath.Walk("./", func(path string, info os.FileInfo, err error) error {
  53. if err != nil {
  54. return err
  55. }
  56. if info.IsDir() || strings.HasPrefix(path, ".") || strings.HasPrefix(path, "vendor") || strings.HasSuffix(path, ".pb.go") || filepath.Ext(path) != ".go" {
  57. return nil
  58. }
  59. raw, err := ioutil.ReadFile(path)
  60. if err != nil {
  61. return errors.Wrapf(err, "read file %s err", path)
  62. }
  63. digest0 := sha256.Sum256(raw)
  64. if raw, err = format.Source(raw); err != nil {
  65. return errors.Wrapf(err, "format file %s err", path)
  66. }
  67. file, err := parser.ParseFile(token.NewFileSet(), "", raw, 0)
  68. if err != nil {
  69. return errors.Wrapf(err, "parse file %s err", path)
  70. }
  71. var first, last int
  72. var imports []*ast.ImportSpec
  73. comments := make(map[string]string)
  74. ast.Inspect(file, func(n ast.Node) bool {
  75. switch spec := n.(type) {
  76. case *ast.ImportSpec:
  77. if first == 0 {
  78. first = int(spec.Pos())
  79. }
  80. last = int(spec.End())
  81. imports = append(imports, spec)
  82. k := last - 1
  83. for ; k < len(raw); k++ {
  84. if raw[k] == '\r' || raw[k] == '\n' {
  85. break
  86. }
  87. }
  88. comment := string(raw[last-1 : k])
  89. if index := strings.Index(comment, "//"); index != -1 {
  90. comments[spec.Path.Value] = strings.TrimSpace(comment[index+2:])
  91. }
  92. }
  93. return true
  94. })
  95. if imports != nil {
  96. buf := bytes.NewBuffer(nil)
  97. buf.Write(raw[:first-2])
  98. buf.WriteString(sort(imports, comments))
  99. buf.Write(raw[last-1:])
  100. if raw, err = format.Source(buf.Bytes()); err != nil {
  101. return errors.Wrapf(err, "double format file %s err", path)
  102. }
  103. }
  104. digest1 := sha256.Sum256(raw)
  105. if !bytes.Equal(digest0[:], digest1[:]) {
  106. fmt.Println(path)
  107. }
  108. if err = ioutil.WriteFile(path, raw, info.Mode()); err != nil {
  109. return errors.Wrapf(err, "write file %s err", path)
  110. }
  111. return nil
  112. })
  113. if err != nil {
  114. log.Fatal("scan project err", zap.Error(err))
  115. }
  116. }
  117. func sort(imports []*ast.ImportSpec, comments map[string]string) string {
  118. system := bytes.NewBuffer(nil)
  119. group := bytes.NewBuffer(nil)
  120. others := bytes.NewBuffer(nil)
  121. for _, pkg := range imports {
  122. value := strings.Trim(pkg.Path.Value, `"`)
  123. switch {
  124. case stdlib[value]:
  125. if pkg.Name != nil {
  126. system.WriteString(pkg.Name.String())
  127. system.WriteString(" ")
  128. }
  129. system.WriteString(pkg.Path.Value)
  130. if comment, ok := comments[pkg.Path.Value]; ok {
  131. system.WriteString(" ")
  132. system.WriteString("// ")
  133. system.WriteString(comment)
  134. }
  135. system.WriteString("\n")
  136. case strings.HasPrefix(value, module):
  137. if pkg.Name != nil {
  138. group.WriteString(pkg.Name.String())
  139. group.WriteString(" ")
  140. }
  141. group.WriteString(pkg.Path.Value)
  142. if comment, ok := comments[pkg.Path.Value]; ok {
  143. group.WriteString(" ")
  144. group.WriteString("// ")
  145. group.WriteString(comment)
  146. }
  147. group.WriteString("\n")
  148. default:
  149. if pkg.Name != nil {
  150. others.WriteString(pkg.Name.String())
  151. others.WriteString(" ")
  152. }
  153. others.WriteString(pkg.Path.Value)
  154. if comment, ok := comments[pkg.Path.Value]; ok {
  155. others.WriteString(" ")
  156. others.WriteString("// ")
  157. others.WriteString(comment)
  158. }
  159. others.WriteString("\n")
  160. }
  161. }
  162. return fmt.Sprintf("%s\n%s\n%s", system.String(), group.String(), others.String())
  163. }