gopkg.in/alecthomas/gometalinter.v3@v3.0.0/_linters/src/golang.org/x/tools/go/packages/golist_overlay.go (about) 1 package packages 2 3 import ( 4 "go/parser" 5 "go/token" 6 "path/filepath" 7 "strconv" 8 "strings" 9 ) 10 11 // processGolistOverlay provides rudimentary support for adding 12 // files that don't exist on disk to an overlay. The results can be 13 // sometimes incorrect. 14 // TODO(matloob): Handle unsupported cases, including the following: 15 // - test files 16 // - adding test and non-test files to test variants of packages 17 // - determining the correct package to add given a new import path 18 // - creating packages that don't exist 19 func processGolistOverlay(cfg *Config, response *driverResponse) (modifiedPkgs, needPkgs []string, err error) { 20 havePkgs := make(map[string]string) // importPath -> non-test package ID 21 needPkgsSet := make(map[string]bool) 22 modifiedPkgsSet := make(map[string]bool) 23 24 for _, pkg := range response.Packages { 25 // This is an approximation of import path to id. This can be 26 // wrong for tests, vendored packages, and a number of other cases. 27 havePkgs[pkg.PkgPath] = pkg.ID 28 } 29 30 outer: 31 for path, contents := range cfg.Overlay { 32 base := filepath.Base(path) 33 if strings.HasSuffix(path, "_test.go") { 34 // Overlays don't support adding new test files yet. 35 // TODO(matloob): support adding new test files. 36 continue 37 } 38 dir := filepath.Dir(path) 39 for _, pkg := range response.Packages { 40 var dirContains, fileExists bool 41 for _, f := range pkg.GoFiles { 42 if sameFile(filepath.Dir(f), dir) { 43 dirContains = true 44 } 45 if filepath.Base(f) == base { 46 fileExists = true 47 } 48 } 49 if dirContains { 50 if !fileExists { 51 pkg.GoFiles = append(pkg.GoFiles, path) // TODO(matloob): should the file just be added to GoFiles? 52 pkg.CompiledGoFiles = append(pkg.CompiledGoFiles, path) 53 modifiedPkgsSet[pkg.ID] = true 54 } 55 imports, err := extractImports(path, contents) 56 if err != nil { 57 // Let the parser or type checker report errors later. 58 continue outer 59 } 60 for _, imp := range imports { 61 _, found := pkg.Imports[imp] 62 if !found { 63 needPkgsSet[imp] = true 64 // TODO(matloob): Handle cases when the following block isn't correct. 65 // These include imports of test variants, imports of vendored packages, etc. 66 id, ok := havePkgs[imp] 67 if !ok { 68 id = imp 69 } 70 pkg.Imports[imp] = &Package{ID: id} 71 } 72 } 73 continue outer 74 } 75 } 76 } 77 78 needPkgs = make([]string, 0, len(needPkgsSet)) 79 for pkg := range needPkgsSet { 80 needPkgs = append(needPkgs, pkg) 81 } 82 modifiedPkgs = make([]string, 0, len(modifiedPkgsSet)) 83 for pkg := range modifiedPkgsSet { 84 modifiedPkgs = append(modifiedPkgs, pkg) 85 } 86 return modifiedPkgs, needPkgs, err 87 } 88 89 func extractImports(filename string, contents []byte) ([]string, error) { 90 f, err := parser.ParseFile(token.NewFileSet(), filename, contents, parser.ImportsOnly) // TODO(matloob): reuse fileset? 91 if err != nil { 92 return nil, err 93 } 94 var res []string 95 for _, imp := range f.Imports { 96 quotedPath := imp.Path.Value 97 path, err := strconv.Unquote(quotedPath) 98 if err != nil { 99 return nil, err 100 } 101 res = append(res, path) 102 } 103 return res, nil 104 }