You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

mod.go 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718
  1. package imports
  2. import (
  3. "bytes"
  4. "context"
  5. "encoding/json"
  6. "fmt"
  7. "io/ioutil"
  8. "os"
  9. "path"
  10. "path/filepath"
  11. "regexp"
  12. "sort"
  13. "strconv"
  14. "strings"
  15. "golang.org/x/mod/module"
  16. "golang.org/x/mod/semver"
  17. "golang.org/x/tools/internal/gopathwalk"
  18. )
  19. // ModuleResolver implements resolver for modules using the go command as little
  20. // as feasible.
  21. type ModuleResolver struct {
  22. env *ProcessEnv
  23. moduleCacheDir string
  24. dummyVendorMod *ModuleJSON // If vendoring is enabled, the pseudo-module that represents the /vendor directory.
  25. roots []gopathwalk.Root
  26. scanSema chan struct{} // scanSema prevents concurrent scans and guards scannedRoots.
  27. scannedRoots map[gopathwalk.Root]bool
  28. initialized bool
  29. main *ModuleJSON
  30. modsByModPath []*ModuleJSON // All modules, ordered by # of path components in module Path...
  31. modsByDir []*ModuleJSON // ...or Dir.
  32. // moduleCacheCache stores information about the module cache.
  33. moduleCacheCache *dirInfoCache
  34. otherCache *dirInfoCache
  35. }
  36. type ModuleJSON struct {
  37. Path string // module path
  38. Replace *ModuleJSON // replaced by this module
  39. Main bool // is this the main module?
  40. Indirect bool // is this module only an indirect dependency of main module?
  41. Dir string // directory holding files for this module, if any
  42. GoMod string // path to go.mod file for this module, if any
  43. GoVersion string // go version used in module
  44. }
  45. func newModuleResolver(e *ProcessEnv) *ModuleResolver {
  46. r := &ModuleResolver{
  47. env: e,
  48. scanSema: make(chan struct{}, 1),
  49. }
  50. r.scanSema <- struct{}{}
  51. return r
  52. }
  53. func (r *ModuleResolver) init() error {
  54. if r.initialized {
  55. return nil
  56. }
  57. mainMod, vendorEnabled, err := vendorEnabled(r.env)
  58. if err != nil {
  59. return err
  60. }
  61. if mainMod != nil && vendorEnabled {
  62. // Vendor mode is on, so all the non-Main modules are irrelevant,
  63. // and we need to search /vendor for everything.
  64. r.main = mainMod
  65. r.dummyVendorMod = &ModuleJSON{
  66. Path: "",
  67. Dir: filepath.Join(mainMod.Dir, "vendor"),
  68. }
  69. r.modsByModPath = []*ModuleJSON{mainMod, r.dummyVendorMod}
  70. r.modsByDir = []*ModuleJSON{mainMod, r.dummyVendorMod}
  71. } else {
  72. // Vendor mode is off, so run go list -m ... to find everything.
  73. r.initAllMods()
  74. }
  75. r.moduleCacheDir = filepath.Join(filepath.SplitList(r.env.GOPATH)[0], "/pkg/mod")
  76. sort.Slice(r.modsByModPath, func(i, j int) bool {
  77. count := func(x int) int {
  78. return strings.Count(r.modsByModPath[x].Path, "/")
  79. }
  80. return count(j) < count(i) // descending order
  81. })
  82. sort.Slice(r.modsByDir, func(i, j int) bool {
  83. count := func(x int) int {
  84. return strings.Count(r.modsByDir[x].Dir, "/")
  85. }
  86. return count(j) < count(i) // descending order
  87. })
  88. r.roots = []gopathwalk.Root{
  89. {filepath.Join(r.env.GOROOT, "/src"), gopathwalk.RootGOROOT},
  90. }
  91. if r.main != nil {
  92. r.roots = append(r.roots, gopathwalk.Root{r.main.Dir, gopathwalk.RootCurrentModule})
  93. }
  94. if vendorEnabled {
  95. r.roots = append(r.roots, gopathwalk.Root{r.dummyVendorMod.Dir, gopathwalk.RootOther})
  96. } else {
  97. addDep := func(mod *ModuleJSON) {
  98. if mod.Replace == nil {
  99. // This is redundant with the cache, but we'll skip it cheaply enough.
  100. r.roots = append(r.roots, gopathwalk.Root{mod.Dir, gopathwalk.RootModuleCache})
  101. } else {
  102. r.roots = append(r.roots, gopathwalk.Root{mod.Dir, gopathwalk.RootOther})
  103. }
  104. }
  105. // Walk dependent modules before scanning the full mod cache, direct deps first.
  106. for _, mod := range r.modsByModPath {
  107. if !mod.Indirect && !mod.Main {
  108. addDep(mod)
  109. }
  110. }
  111. for _, mod := range r.modsByModPath {
  112. if mod.Indirect && !mod.Main {
  113. addDep(mod)
  114. }
  115. }
  116. r.roots = append(r.roots, gopathwalk.Root{r.moduleCacheDir, gopathwalk.RootModuleCache})
  117. }
  118. r.scannedRoots = map[gopathwalk.Root]bool{}
  119. if r.moduleCacheCache == nil {
  120. r.moduleCacheCache = &dirInfoCache{
  121. dirs: map[string]*directoryPackageInfo{},
  122. listeners: map[*int]cacheListener{},
  123. }
  124. }
  125. if r.otherCache == nil {
  126. r.otherCache = &dirInfoCache{
  127. dirs: map[string]*directoryPackageInfo{},
  128. listeners: map[*int]cacheListener{},
  129. }
  130. }
  131. r.initialized = true
  132. return nil
  133. }
  134. func (r *ModuleResolver) initAllMods() error {
  135. stdout, err := r.env.invokeGo(context.TODO(), "list", "-m", "-json", "...")
  136. if err != nil {
  137. return err
  138. }
  139. for dec := json.NewDecoder(stdout); dec.More(); {
  140. mod := &ModuleJSON{}
  141. if err := dec.Decode(mod); err != nil {
  142. return err
  143. }
  144. if mod.Dir == "" {
  145. if r.env.Logf != nil {
  146. r.env.Logf("module %v has not been downloaded and will be ignored", mod.Path)
  147. }
  148. // Can't do anything with a module that's not downloaded.
  149. continue
  150. }
  151. // golang/go#36193: the go command doesn't always clean paths.
  152. mod.Dir = filepath.Clean(mod.Dir)
  153. r.modsByModPath = append(r.modsByModPath, mod)
  154. r.modsByDir = append(r.modsByDir, mod)
  155. if mod.Main {
  156. r.main = mod
  157. }
  158. }
  159. return nil
  160. }
  161. func (r *ModuleResolver) ClearForNewScan() {
  162. <-r.scanSema
  163. r.scannedRoots = map[gopathwalk.Root]bool{}
  164. r.otherCache = &dirInfoCache{
  165. dirs: map[string]*directoryPackageInfo{},
  166. listeners: map[*int]cacheListener{},
  167. }
  168. r.scanSema <- struct{}{}
  169. }
  170. func (r *ModuleResolver) ClearForNewMod() {
  171. <-r.scanSema
  172. *r = ModuleResolver{
  173. env: r.env,
  174. moduleCacheCache: r.moduleCacheCache,
  175. otherCache: r.otherCache,
  176. scanSema: r.scanSema,
  177. }
  178. r.init()
  179. r.scanSema <- struct{}{}
  180. }
  181. // findPackage returns the module and directory that contains the package at
  182. // the given import path, or returns nil, "" if no module is in scope.
  183. func (r *ModuleResolver) findPackage(importPath string) (*ModuleJSON, string) {
  184. // This can't find packages in the stdlib, but that's harmless for all
  185. // the existing code paths.
  186. for _, m := range r.modsByModPath {
  187. if !strings.HasPrefix(importPath, m.Path) {
  188. continue
  189. }
  190. pathInModule := importPath[len(m.Path):]
  191. pkgDir := filepath.Join(m.Dir, pathInModule)
  192. if r.dirIsNestedModule(pkgDir, m) {
  193. continue
  194. }
  195. if info, ok := r.cacheLoad(pkgDir); ok {
  196. if loaded, err := info.reachedStatus(nameLoaded); loaded {
  197. if err != nil {
  198. continue // No package in this dir.
  199. }
  200. return m, pkgDir
  201. }
  202. if scanned, err := info.reachedStatus(directoryScanned); scanned && err != nil {
  203. continue // Dir is unreadable, etc.
  204. }
  205. // This is slightly wrong: a directory doesn't have to have an
  206. // importable package to count as a package for package-to-module
  207. // resolution. package main or _test files should count but
  208. // don't.
  209. // TODO(heschi): fix this.
  210. if _, err := r.cachePackageName(info); err == nil {
  211. return m, pkgDir
  212. }
  213. }
  214. // Not cached. Read the filesystem.
  215. pkgFiles, err := ioutil.ReadDir(pkgDir)
  216. if err != nil {
  217. continue
  218. }
  219. // A module only contains a package if it has buildable go
  220. // files in that directory. If not, it could be provided by an
  221. // outer module. See #29736.
  222. for _, fi := range pkgFiles {
  223. if ok, _ := r.env.buildContext().MatchFile(pkgDir, fi.Name()); ok {
  224. return m, pkgDir
  225. }
  226. }
  227. }
  228. return nil, ""
  229. }
  230. func (r *ModuleResolver) cacheLoad(dir string) (directoryPackageInfo, bool) {
  231. if info, ok := r.moduleCacheCache.Load(dir); ok {
  232. return info, ok
  233. }
  234. return r.otherCache.Load(dir)
  235. }
  236. func (r *ModuleResolver) cacheStore(info directoryPackageInfo) {
  237. if info.rootType == gopathwalk.RootModuleCache {
  238. r.moduleCacheCache.Store(info.dir, info)
  239. } else {
  240. r.otherCache.Store(info.dir, info)
  241. }
  242. }
  243. func (r *ModuleResolver) cacheKeys() []string {
  244. return append(r.moduleCacheCache.Keys(), r.otherCache.Keys()...)
  245. }
  246. // cachePackageName caches the package name for a dir already in the cache.
  247. func (r *ModuleResolver) cachePackageName(info directoryPackageInfo) (string, error) {
  248. if info.rootType == gopathwalk.RootModuleCache {
  249. return r.moduleCacheCache.CachePackageName(info)
  250. }
  251. return r.otherCache.CachePackageName(info)
  252. }
  253. func (r *ModuleResolver) cacheExports(ctx context.Context, env *ProcessEnv, info directoryPackageInfo) (string, []string, error) {
  254. if info.rootType == gopathwalk.RootModuleCache {
  255. return r.moduleCacheCache.CacheExports(ctx, env, info)
  256. }
  257. return r.otherCache.CacheExports(ctx, env, info)
  258. }
  259. // findModuleByDir returns the module that contains dir, or nil if no such
  260. // module is in scope.
  261. func (r *ModuleResolver) findModuleByDir(dir string) *ModuleJSON {
  262. // This is quite tricky and may not be correct. dir could be:
  263. // - a package in the main module.
  264. // - a replace target underneath the main module's directory.
  265. // - a nested module in the above.
  266. // - a replace target somewhere totally random.
  267. // - a nested module in the above.
  268. // - in the mod cache.
  269. // - in /vendor/ in -mod=vendor mode.
  270. // - nested module? Dunno.
  271. // Rumor has it that replace targets cannot contain other replace targets.
  272. for _, m := range r.modsByDir {
  273. if !strings.HasPrefix(dir, m.Dir) {
  274. continue
  275. }
  276. if r.dirIsNestedModule(dir, m) {
  277. continue
  278. }
  279. return m
  280. }
  281. return nil
  282. }
  283. // dirIsNestedModule reports if dir is contained in a nested module underneath
  284. // mod, not actually in mod.
  285. func (r *ModuleResolver) dirIsNestedModule(dir string, mod *ModuleJSON) bool {
  286. if !strings.HasPrefix(dir, mod.Dir) {
  287. return false
  288. }
  289. if r.dirInModuleCache(dir) {
  290. // Nested modules in the module cache are pruned,
  291. // so it cannot be a nested module.
  292. return false
  293. }
  294. if mod != nil && mod == r.dummyVendorMod {
  295. // The /vendor pseudomodule is flattened and doesn't actually count.
  296. return false
  297. }
  298. modDir, _ := r.modInfo(dir)
  299. if modDir == "" {
  300. return false
  301. }
  302. return modDir != mod.Dir
  303. }
  304. func (r *ModuleResolver) modInfo(dir string) (modDir string, modName string) {
  305. readModName := func(modFile string) string {
  306. modBytes, err := ioutil.ReadFile(modFile)
  307. if err != nil {
  308. return ""
  309. }
  310. return modulePath(modBytes)
  311. }
  312. if r.dirInModuleCache(dir) {
  313. matches := modCacheRegexp.FindStringSubmatch(dir)
  314. index := strings.Index(dir, matches[1]+"@"+matches[2])
  315. modDir := filepath.Join(dir[:index], matches[1]+"@"+matches[2])
  316. return modDir, readModName(filepath.Join(modDir, "go.mod"))
  317. }
  318. for {
  319. if info, ok := r.cacheLoad(dir); ok {
  320. return info.moduleDir, info.moduleName
  321. }
  322. f := filepath.Join(dir, "go.mod")
  323. info, err := os.Stat(f)
  324. if err == nil && !info.IsDir() {
  325. return dir, readModName(f)
  326. }
  327. d := filepath.Dir(dir)
  328. if len(d) >= len(dir) {
  329. return "", "" // reached top of file system, no go.mod
  330. }
  331. dir = d
  332. }
  333. }
  334. func (r *ModuleResolver) dirInModuleCache(dir string) bool {
  335. if r.moduleCacheDir == "" {
  336. return false
  337. }
  338. return strings.HasPrefix(dir, r.moduleCacheDir)
  339. }
  340. func (r *ModuleResolver) loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) {
  341. if err := r.init(); err != nil {
  342. return nil, err
  343. }
  344. names := map[string]string{}
  345. for _, path := range importPaths {
  346. _, packageDir := r.findPackage(path)
  347. if packageDir == "" {
  348. continue
  349. }
  350. name, err := packageDirToName(packageDir)
  351. if err != nil {
  352. continue
  353. }
  354. names[path] = name
  355. }
  356. return names, nil
  357. }
  358. func (r *ModuleResolver) scan(ctx context.Context, callback *scanCallback) error {
  359. if err := r.init(); err != nil {
  360. return err
  361. }
  362. processDir := func(info directoryPackageInfo) {
  363. // Skip this directory if we were not able to get the package information successfully.
  364. if scanned, err := info.reachedStatus(directoryScanned); !scanned || err != nil {
  365. return
  366. }
  367. pkg, err := r.canonicalize(info)
  368. if err != nil {
  369. return
  370. }
  371. if !callback.dirFound(pkg) {
  372. return
  373. }
  374. pkg.packageName, err = r.cachePackageName(info)
  375. if err != nil {
  376. return
  377. }
  378. if !callback.packageNameLoaded(pkg) {
  379. return
  380. }
  381. _, exports, err := r.loadExports(ctx, pkg, false)
  382. if err != nil {
  383. return
  384. }
  385. callback.exportsLoaded(pkg, exports)
  386. }
  387. // Start processing everything in the cache, and listen for the new stuff
  388. // we discover in the walk below.
  389. stop1 := r.moduleCacheCache.ScanAndListen(ctx, processDir)
  390. defer stop1()
  391. stop2 := r.otherCache.ScanAndListen(ctx, processDir)
  392. defer stop2()
  393. // We assume cached directories are fully cached, including all their
  394. // children, and have not changed. We can skip them.
  395. skip := func(root gopathwalk.Root, dir string) bool {
  396. info, ok := r.cacheLoad(dir)
  397. if !ok {
  398. return false
  399. }
  400. // This directory can be skipped as long as we have already scanned it.
  401. // Packages with errors will continue to have errors, so there is no need
  402. // to rescan them.
  403. packageScanned, _ := info.reachedStatus(directoryScanned)
  404. return packageScanned
  405. }
  406. // Add anything new to the cache, and process it if we're still listening.
  407. add := func(root gopathwalk.Root, dir string) {
  408. r.cacheStore(r.scanDirForPackage(root, dir))
  409. }
  410. // r.roots and the callback are not necessarily safe to use in the
  411. // goroutine below. Process them eagerly.
  412. roots := filterRoots(r.roots, callback.rootFound)
  413. // We can't cancel walks, because we need them to finish to have a usable
  414. // cache. Instead, run them in a separate goroutine and detach.
  415. scanDone := make(chan struct{})
  416. go func() {
  417. select {
  418. case <-ctx.Done():
  419. return
  420. case <-r.scanSema:
  421. }
  422. defer func() { r.scanSema <- struct{}{} }()
  423. // We have the lock on r.scannedRoots, and no other scans can run.
  424. for _, root := range roots {
  425. if ctx.Err() != nil {
  426. return
  427. }
  428. if r.scannedRoots[root] {
  429. continue
  430. }
  431. gopathwalk.WalkSkip([]gopathwalk.Root{root}, add, skip, gopathwalk.Options{Logf: r.env.Logf, ModulesEnabled: true})
  432. r.scannedRoots[root] = true
  433. }
  434. close(scanDone)
  435. }()
  436. select {
  437. case <-ctx.Done():
  438. case <-scanDone:
  439. }
  440. return nil
  441. }
  442. func (r *ModuleResolver) scoreImportPath(ctx context.Context, path string) int {
  443. if _, ok := stdlib[path]; ok {
  444. return MaxRelevance
  445. }
  446. mod, _ := r.findPackage(path)
  447. return modRelevance(mod)
  448. }
  449. func modRelevance(mod *ModuleJSON) int {
  450. switch {
  451. case mod == nil: // out of scope
  452. return MaxRelevance - 4
  453. case mod.Indirect:
  454. return MaxRelevance - 3
  455. case !mod.Main:
  456. return MaxRelevance - 2
  457. default:
  458. return MaxRelevance - 1 // main module ties with stdlib
  459. }
  460. }
  461. // canonicalize gets the result of canonicalizing the packages using the results
  462. // of initializing the resolver from 'go list -m'.
  463. func (r *ModuleResolver) canonicalize(info directoryPackageInfo) (*pkg, error) {
  464. // Packages in GOROOT are already canonical, regardless of the std/cmd modules.
  465. if info.rootType == gopathwalk.RootGOROOT {
  466. return &pkg{
  467. importPathShort: info.nonCanonicalImportPath,
  468. dir: info.dir,
  469. packageName: path.Base(info.nonCanonicalImportPath),
  470. relevance: MaxRelevance,
  471. }, nil
  472. }
  473. importPath := info.nonCanonicalImportPath
  474. mod := r.findModuleByDir(info.dir)
  475. // Check if the directory is underneath a module that's in scope.
  476. if mod != nil {
  477. // It is. If dir is the target of a replace directive,
  478. // our guessed import path is wrong. Use the real one.
  479. if mod.Dir == info.dir {
  480. importPath = mod.Path
  481. } else {
  482. dirInMod := info.dir[len(mod.Dir)+len("/"):]
  483. importPath = path.Join(mod.Path, filepath.ToSlash(dirInMod))
  484. }
  485. } else if !strings.HasPrefix(importPath, info.moduleName) {
  486. // The module's name doesn't match the package's import path. It
  487. // probably needs a replace directive we don't have.
  488. return nil, fmt.Errorf("package in %q is not valid without a replace statement", info.dir)
  489. }
  490. res := &pkg{
  491. importPathShort: importPath,
  492. dir: info.dir,
  493. relevance: modRelevance(mod),
  494. }
  495. // We may have discovered a package that has a different version
  496. // in scope already. Canonicalize to that one if possible.
  497. if _, canonicalDir := r.findPackage(importPath); canonicalDir != "" {
  498. res.dir = canonicalDir
  499. }
  500. return res, nil
  501. }
  502. func (r *ModuleResolver) loadExports(ctx context.Context, pkg *pkg, includeTest bool) (string, []string, error) {
  503. if err := r.init(); err != nil {
  504. return "", nil, err
  505. }
  506. if info, ok := r.cacheLoad(pkg.dir); ok && !includeTest {
  507. return r.cacheExports(ctx, r.env, info)
  508. }
  509. return loadExportsFromFiles(ctx, r.env, pkg.dir, includeTest)
  510. }
  511. func (r *ModuleResolver) scanDirForPackage(root gopathwalk.Root, dir string) directoryPackageInfo {
  512. subdir := ""
  513. if dir != root.Path {
  514. subdir = dir[len(root.Path)+len("/"):]
  515. }
  516. importPath := filepath.ToSlash(subdir)
  517. if strings.HasPrefix(importPath, "vendor/") {
  518. // Only enter vendor directories if they're explicitly requested as a root.
  519. return directoryPackageInfo{
  520. status: directoryScanned,
  521. err: fmt.Errorf("unwanted vendor directory"),
  522. }
  523. }
  524. switch root.Type {
  525. case gopathwalk.RootCurrentModule:
  526. importPath = path.Join(r.main.Path, filepath.ToSlash(subdir))
  527. case gopathwalk.RootModuleCache:
  528. matches := modCacheRegexp.FindStringSubmatch(subdir)
  529. if len(matches) == 0 {
  530. return directoryPackageInfo{
  531. status: directoryScanned,
  532. err: fmt.Errorf("invalid module cache path: %v", subdir),
  533. }
  534. }
  535. modPath, err := module.UnescapePath(filepath.ToSlash(matches[1]))
  536. if err != nil {
  537. if r.env.Logf != nil {
  538. r.env.Logf("decoding module cache path %q: %v", subdir, err)
  539. }
  540. return directoryPackageInfo{
  541. status: directoryScanned,
  542. err: fmt.Errorf("decoding module cache path %q: %v", subdir, err),
  543. }
  544. }
  545. importPath = path.Join(modPath, filepath.ToSlash(matches[3]))
  546. }
  547. modDir, modName := r.modInfo(dir)
  548. result := directoryPackageInfo{
  549. status: directoryScanned,
  550. dir: dir,
  551. rootType: root.Type,
  552. nonCanonicalImportPath: importPath,
  553. moduleDir: modDir,
  554. moduleName: modName,
  555. }
  556. if root.Type == gopathwalk.RootGOROOT {
  557. // stdlib packages are always in scope, despite the confusing go.mod
  558. return result
  559. }
  560. return result
  561. }
  562. // modCacheRegexp splits a path in a module cache into module, module version, and package.
  563. var modCacheRegexp = regexp.MustCompile(`(.*)@([^/\\]*)(.*)`)
  564. var (
  565. slashSlash = []byte("//")
  566. moduleStr = []byte("module")
  567. )
  568. // modulePath returns the module path from the gomod file text.
  569. // If it cannot find a module path, it returns an empty string.
  570. // It is tolerant of unrelated problems in the go.mod file.
  571. //
  572. // Copied from cmd/go/internal/modfile.
  573. func modulePath(mod []byte) string {
  574. for len(mod) > 0 {
  575. line := mod
  576. mod = nil
  577. if i := bytes.IndexByte(line, '\n'); i >= 0 {
  578. line, mod = line[:i], line[i+1:]
  579. }
  580. if i := bytes.Index(line, slashSlash); i >= 0 {
  581. line = line[:i]
  582. }
  583. line = bytes.TrimSpace(line)
  584. if !bytes.HasPrefix(line, moduleStr) {
  585. continue
  586. }
  587. line = line[len(moduleStr):]
  588. n := len(line)
  589. line = bytes.TrimSpace(line)
  590. if len(line) == n || len(line) == 0 {
  591. continue
  592. }
  593. if line[0] == '"' || line[0] == '`' {
  594. p, err := strconv.Unquote(string(line))
  595. if err != nil {
  596. return "" // malformed quoted string or multiline module path
  597. }
  598. return p
  599. }
  600. return string(line)
  601. }
  602. return "" // missing module path
  603. }
  604. var modFlagRegexp = regexp.MustCompile(`-mod[ =](\w+)`)
  605. // vendorEnabled indicates if vendoring is enabled.
  606. // Inspired by setDefaultBuildMod in modload/init.go
  607. func vendorEnabled(env *ProcessEnv) (*ModuleJSON, bool, error) {
  608. mainMod, go114, err := getMainModuleAnd114(env)
  609. if err != nil {
  610. return nil, false, err
  611. }
  612. matches := modFlagRegexp.FindStringSubmatch(env.GOFLAGS)
  613. var modFlag string
  614. if len(matches) != 0 {
  615. modFlag = matches[1]
  616. }
  617. if modFlag != "" {
  618. // Don't override an explicit '-mod=' argument.
  619. return mainMod, modFlag == "vendor", nil
  620. }
  621. if mainMod == nil || !go114 {
  622. return mainMod, false, nil
  623. }
  624. // Check 1.14's automatic vendor mode.
  625. if fi, err := os.Stat(filepath.Join(mainMod.Dir, "vendor")); err == nil && fi.IsDir() {
  626. if mainMod.GoVersion != "" && semver.Compare("v"+mainMod.GoVersion, "v1.14") >= 0 {
  627. // The Go version is at least 1.14, and a vendor directory exists.
  628. // Set -mod=vendor by default.
  629. return mainMod, true, nil
  630. }
  631. }
  632. return mainMod, false, nil
  633. }
  634. // getMainModuleAnd114 gets the main module's information and whether the
  635. // go command in use is 1.14+. This is the information needed to figure out
  636. // if vendoring should be enabled.
  637. func getMainModuleAnd114(env *ProcessEnv) (*ModuleJSON, bool, error) {
  638. const format = `{{.Path}}
  639. {{.Dir}}
  640. {{.GoMod}}
  641. {{.GoVersion}}
  642. {{range context.ReleaseTags}}{{if eq . "go1.14"}}{{.}}{{end}}{{end}}
  643. `
  644. stdout, err := env.invokeGo(context.TODO(), "list", "-m", "-f", format)
  645. if err != nil {
  646. return nil, false, nil
  647. }
  648. lines := strings.Split(stdout.String(), "\n")
  649. if len(lines) < 5 {
  650. return nil, false, fmt.Errorf("unexpected stdout: %q", stdout)
  651. }
  652. mod := &ModuleJSON{
  653. Path: lines[0],
  654. Dir: lines[1],
  655. GoMod: lines[2],
  656. GoVersion: lines[3],
  657. Main: true,
  658. }
  659. return mod, lines[4] == "go1.14", nil
  660. }