github.com/yasushi-saito/gometalinter@v2.0.13-0.20190118091058-bb04f89050ef+incompatible/partition.go (about) 1 package main 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "path/filepath" 7 ) 8 9 // MaxCommandBytes is the maximum number of bytes used when executing a command 10 const MaxCommandBytes = 32000 11 12 type partitionStrategy func([]string, []string) ([][]string, error) 13 14 func (ps *partitionStrategy) UnmarshalJSON(raw []byte) error { 15 var strategyName string 16 if err := json.Unmarshal(raw, &strategyName); err != nil { 17 return err 18 } 19 20 switch strategyName { 21 case "directories": 22 *ps = partitionPathsAsDirectories 23 case "files": 24 *ps = partitionPathsAsFiles 25 case "packages": 26 *ps = partitionPathsAsPackages 27 case "files-by-package": 28 *ps = partitionPathsAsFilesGroupedByPackage 29 case "single-directory": 30 *ps = partitionPathsByDirectory 31 default: 32 return fmt.Errorf("unknown parition strategy %s", strategyName) 33 } 34 return nil 35 } 36 37 func pathsToFileGlobs(paths []string) ([]string, error) { 38 filePaths := []string{} 39 for _, dir := range paths { 40 paths, err := filepath.Glob(filepath.Join(dir, "*.go")) 41 if err != nil { 42 return nil, err 43 } 44 filePaths = append(filePaths, paths...) 45 } 46 return filePaths, nil 47 } 48 49 func partitionPathsAsDirectories(cmdArgs []string, paths []string) ([][]string, error) { 50 return partitionToMaxSize(cmdArgs, paths, MaxCommandBytes), nil 51 } 52 53 func partitionToMaxSize(cmdArgs []string, paths []string, maxSize int) [][]string { 54 partitions := newSizePartitioner(cmdArgs, maxSize) 55 for _, path := range paths { 56 partitions.add(path) 57 } 58 return partitions.end() 59 } 60 61 type sizePartitioner struct { 62 base []string 63 parts [][]string 64 current []string 65 size int 66 max int 67 } 68 69 func newSizePartitioner(base []string, max int) *sizePartitioner { 70 p := &sizePartitioner{base: base, max: max} 71 p.new() 72 return p 73 } 74 75 func (p *sizePartitioner) add(arg string) { 76 if p.size+len(arg)+1 > p.max { 77 p.new() 78 } 79 p.current = append(p.current, arg) 80 p.size += len(arg) + 1 81 } 82 83 func (p *sizePartitioner) new() { 84 p.end() 85 p.size = 0 86 p.current = []string{} 87 for _, arg := range p.base { 88 p.add(arg) 89 } 90 } 91 92 func (p *sizePartitioner) end() [][]string { 93 if len(p.current) > 0 { 94 p.parts = append(p.parts, p.current) 95 } 96 return p.parts 97 } 98 99 func partitionPathsAsFiles(cmdArgs []string, paths []string) ([][]string, error) { 100 filePaths, err := pathsToFileGlobs(paths) 101 if err != nil || len(filePaths) == 0 { 102 return nil, err 103 } 104 return partitionPathsAsDirectories(cmdArgs, filePaths) 105 } 106 107 func partitionPathsAsFilesGroupedByPackage(cmdArgs []string, paths []string) ([][]string, error) { 108 parts := [][]string{} 109 for _, path := range paths { 110 filePaths, err := pathsToFileGlobs([]string{path}) 111 if err != nil { 112 return nil, err 113 } 114 if len(filePaths) == 0 { 115 continue 116 } 117 parts = append(parts, append(cmdArgs, filePaths...)) 118 } 119 return parts, nil 120 } 121 122 func partitionPathsAsPackages(cmdArgs []string, paths []string) ([][]string, error) { 123 packagePaths, err := pathsToPackagePaths(paths) 124 if err != nil || len(packagePaths) == 0 { 125 return nil, err 126 } 127 return partitionPathsAsDirectories(cmdArgs, packagePaths) 128 } 129 130 func pathsToPackagePaths(paths []string) ([]string, error) { 131 packages := []string{} 132 133 for _, path := range paths { 134 pkg, err := packageNameFromPath(path) 135 if err != nil { 136 return nil, err 137 } 138 packages = append(packages, pkg) 139 } 140 return packages, nil 141 } 142 143 func packageNameFromPath(path string) (string, error) { 144 if !filepath.IsAbs(path) { 145 return path, nil 146 } 147 for _, gopath := range getGoPathList() { 148 rel, err := filepath.Rel(filepath.Join(gopath, "src"), path) 149 if err != nil { 150 continue 151 } 152 return rel, nil 153 } 154 return "", fmt.Errorf("%s not in GOPATH", path) 155 } 156 157 func partitionPathsByDirectory(cmdArgs []string, paths []string) ([][]string, error) { 158 parts := [][]string{} 159 for _, path := range paths { 160 parts = append(parts, append(cmdArgs, path)) 161 } 162 return parts, nil 163 }