package fsutils import ( "context" "fmt" "go/build" "os" "path" "path/filepath" "strings" "time" "github.com/sirupsen/logrus" ) var stdExcludeDirRegexps = []string{ "^vendor$", "^third_party$", "^testdata$", "^examples$", "^Godeps$", "^builtin$", } func GetProjectRoot() string { return path.Join(build.Default.GOPATH, "src", "github.com", "golangci", "golangci-worker") } type ProjectPaths struct { Files []string Dirs []string IsDirsRun bool } func (p ProjectPaths) MixedPaths() []string { if p.IsDirsRun { return p.Dirs } return p.Files } func (p ProjectPaths) FilesGrouppedByDirs() [][]string { dirToFiles := map[string][]string{} for _, f := range p.Files { dir := filepath.Dir(f) dirToFiles[dir] = append(dirToFiles[dir], f) } ret := [][]string{} for _, files := range dirToFiles { ret = append(ret, files) } return ret } func processPaths(root string, paths []string, maxPaths int) ([]string, error) { if len(paths) > maxPaths { logrus.Warnf("Gofmt: got too much paths (%d), analyze first %d", len(paths), maxPaths) paths = paths[:maxPaths] } ret := []string{} for _, p := range paths { if !filepath.IsAbs(p) { ret = append(ret, p) continue } relPath, err := filepath.Rel(root, p) if err != nil { return nil, fmt.Errorf("can't get relative path for path %s and root %s: %s", p, root, err) } ret = append(ret, relPath) } return ret, nil } func processResolvedPaths(paths *PathResolveResult) (*ProjectPaths, error) { root, err := os.Getwd() if err != nil { return nil, fmt.Errorf("can't get working dir: %s", err) } files, err := processPaths(root, paths.Files(), 10000) if err != nil { return nil, fmt.Errorf("can't process resolved files: %s", err) } dirs, err := processPaths(root, paths.Dirs(), 1000) if err != nil { return nil, fmt.Errorf("can't process resolved dirs: %s", err) } for i := range dirs { dir := dirs[i] if dir != "." && !filepath.IsAbs(dir) { dirs[i] = "./" + dir } } return &ProjectPaths{ Files: files, Dirs: dirs, IsDirsRun: len(dirs) != 0, }, nil } func GetPathsForAnalysis(ctx context.Context, inputPaths []string, includeTests bool, skipDirRegexps []string) (ret *ProjectPaths, err error) { defer func(startedAt time.Time) { if ret != nil { logrus.Infof("Found paths for analysis for %s: %s", time.Since(startedAt), ret.MixedPaths()) } }(time.Now()) for _, path := range inputPaths { if strings.HasSuffix(path, ".go") && len(inputPaths) != 1 { return nil, fmt.Errorf("specific files for analysis are allowed only if one file is set") } } // TODO: don't analyze skipped files also, when be able to do it excludeDirs := append([]string{}, stdExcludeDirRegexps...) excludeDirs = append(excludeDirs, skipDirRegexps...) pr, err := NewPathResolver(excludeDirs, []string{".go"}, includeTests) if err != nil { return nil, fmt.Errorf("can't make path resolver: %s", err) } paths, err := pr.Resolve(inputPaths...) if err != nil { return nil, fmt.Errorf("can't resolve paths %v: %s", inputPaths, err) } return processResolvedPaths(paths) } func IsDir(filename string) bool { fi, err := os.Stat(filename) return err == nil && fi.IsDir() }