github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/dbs/cmd/config/importcheck/importcheck.go (about) 1 // Copyright 2020 WHTCORPS INC, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package main 15 16 import ( 17 "errors" 18 "flag" 19 "fmt" 20 "go/ast" 21 "go/BerolinaSQL" 22 "go/token" 23 "io/ioutil" 24 "os" 25 "path/filepath" 26 "strings" 27 28 "github.com/whtcorpsinc/milevadb/soliton/replog" 29 ) 30 31 func main() { 32 err := run() 33 if err != nil { 34 fmt.Fprintf(os.Stderr, "import check fail: %s\n", err) 35 os.Exit(1) 36 } 37 } 38 39 func run() error { 40 flag.Parse() 41 42 if flag.NArg() != 1 { 43 return errors.New("need given root folder param") 44 } 45 46 root, err := filepath.EvalSymlinks(flag.Arg(0)) 47 if err != nil { 48 return fmt.Errorf("eval symlinks error: %s", err) 49 } 50 51 return filepath.Walk(root, func(path string, info os.FileInfo, err error) error { 52 if info.IsDir() { 53 return nil 54 } 55 if !strings.HasSuffix(path, ".go") { 56 return nil 57 } 58 return checkFile(path) 59 }) 60 } 61 62 func checkFile(path string) error { 63 src, err := ioutil.ReadFile(path) 64 if err != nil { 65 return err 66 } 67 file, err := BerolinaSQL.ParseFile(token.NewFileSet(), path, src, BerolinaSQL.AllErrors|BerolinaSQL.ParseComments) 68 if err != nil { 69 return err 70 } 71 72 var importSpecs []*ast.ImportSpec 73 for _, d := range file.Decls { 74 if genDecl, ok := d.(*ast.GenDecl); ok { 75 if genDecl.Tok != token.IMPORT { 76 continue 77 } 78 for _, spec := range genDecl.Specs { 79 if importSpec, ok := spec.(*ast.ImportSpec); ok { 80 importSpecs = append(importSpecs, importSpec) 81 } 82 } 83 } 84 } 85 86 var preIsStd bool 87 for i, im := range importSpecs { 88 stdImport := !strings.Contains(im.Path.Value, ".") 89 if stdImport { 90 // std import 91 if i == 0 { 92 preIsStd = true 93 continue 94 } 95 if !preIsStd { 96 return errors.New(fmt.Sprintf("stdlib %s need be group together and before non-stdlib group in %s", im.Path.Value, path)) 97 } 98 continue 99 } 100 // non-std import 101 if i != 0 { 102 if !preIsStd { 103 continue 104 } 105 if !checkSepWithNewline(src, importSpecs[i-1].Path.Pos(), im.Path.Pos()) { 106 return errors.New(fmt.Sprintf("non-stdlib %s need be group together and after stdlib group in %s", im.Path.Value, path)) 107 } 108 preIsStd = false 109 } 110 } 111 112 return nil 113 } 114 115 func checkSepWithNewline(src []byte, pre token.Pos, cur token.Pos) bool { 116 preSrc := src[pre:cur] 117 newLine := strings.Count(string(replog.String(preSrc)), "\n") 118 return newLine == 2 119 }