gitee.com/lonely0422/gometalinter.git@v3.0.1-0.20190307123442-32416ab75314+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  }