@@ -10,6 +10,7 @@ import (
10
10
"path/filepath"
11
11
"regexp"
12
12
"runtime"
13
+ "sort"
13
14
"strings"
14
15
15
16
"golang.org/x/mod/semver"
@@ -240,28 +241,109 @@ func getSourceDir() string {
240
241
return srcdir
241
242
}
242
243
244
+ func getDirs (paths []string ) []string {
245
+ dirs := make ([]string , len (paths ))
246
+ for i , path := range paths {
247
+ dirs [i ] = filepath .Dir (path )
248
+ }
249
+ return dirs
250
+ }
251
+
252
+ // Note this has the side effect of sorting `dirs`
253
+ func checkDirsNested (dirs []string ) bool {
254
+ // the paths were generated by a depth-first search so I think they might
255
+ // be sorted, but we sort them just in case
256
+ sort .Strings (dirs )
257
+ for _ , dir := range dirs {
258
+ if ! strings .HasPrefix (dir , dirs [0 ]) {
259
+ return false
260
+ }
261
+ }
262
+ return true
263
+ }
264
+
265
+ func findGoModFiles (emitDiagnostics bool ) (string , bool ) {
266
+ goModPaths := util .FindAllFilesWithName ("." , "go.mod" , "vendor" )
267
+ if len (goModPaths ) == 0 {
268
+ // preserve current behaviour
269
+ return "." , false
270
+ }
271
+ goModDirs := getDirs (goModPaths )
272
+ if util .AnyGoFilesOutsideDirs ("." , goModDirs ... ) {
273
+ if emitDiagnostics {
274
+ diagnostics .EmitGoFilesOutsideGoModules (goModPaths )
275
+ }
276
+ // preserve current behaviour
277
+ return "." , true
278
+ }
279
+ if len (goModPaths ) > 1 {
280
+ // currently not supported
281
+ if emitDiagnostics {
282
+ if checkDirsNested (goModDirs ) {
283
+ diagnostics .EmitMultipleGoModFoundNested (goModPaths )
284
+ } else {
285
+ diagnostics .EmitMultipleGoModFoundNotNested (goModPaths )
286
+ }
287
+ }
288
+ // preserve current behaviour
289
+ return "." , true
290
+ }
291
+ if emitDiagnostics {
292
+ if goModDirs [0 ] == "." {
293
+ diagnostics .EmitSingleRootGoModFound (goModPaths [0 ])
294
+ } else {
295
+ diagnostics .EmitSingleNonRootGoModFound (goModPaths [0 ])
296
+ }
297
+ }
298
+ return goModDirs [0 ], true
299
+ }
300
+
243
301
// Returns the appropriate DependencyInstallerMode for the current project
244
- func getDepMode () DependencyInstallerMode {
245
- if util .FileExists ("go.mod" ) {
302
+ func getDepMode (emitDiagnostics bool ) (DependencyInstallerMode , string ) {
303
+ if util .FileExists ("BUILD" ) {
304
+ // currently not supported
305
+ if emitDiagnostics {
306
+ diagnostics .EmitBazelBuildFileFound ()
307
+ }
308
+ }
309
+
310
+ goWorkPaths := util .FindAllFilesWithName ("." , "go.work" , "vendor" )
311
+ if len (goWorkPaths ) > 0 {
312
+ // currently not supported
313
+ if emitDiagnostics {
314
+ diagnostics .EmitGoWorkFound (goWorkPaths )
315
+ }
316
+ }
317
+
318
+ baseDir , goModFound := findGoModFiles (emitDiagnostics )
319
+ if goModFound {
246
320
log .Println ("Found go.mod, enabling go modules" )
247
- return GoGetWithModules
321
+ return GoGetWithModules , baseDir
248
322
}
323
+
249
324
if util .FileExists ("Gopkg.toml" ) {
325
+ if emitDiagnostics {
326
+ diagnostics .EmitGopkgTomlFound ()
327
+ }
250
328
log .Println ("Found Gopkg.toml, using dep instead of go get" )
251
- return Dep
329
+ return Dep , "."
252
330
}
331
+
253
332
if util .FileExists ("glide.yaml" ) {
333
+ if emitDiagnostics {
334
+ diagnostics .EmitGlideYamlFound ()
335
+ }
254
336
log .Println ("Found glide.yaml, using Glide instead of go get" )
255
- return Glide
337
+ return Glide , "."
256
338
}
257
- return GoGetNoModules
339
+ return GoGetNoModules , "."
258
340
}
259
341
260
342
// Tries to open `go.mod` and read a go directive, returning the version and whether it was found.
261
- func tryReadGoDirective (depMode DependencyInstallerMode ) (string , bool ) {
343
+ func tryReadGoDirective (depMode DependencyInstallerMode , baseDir string ) (string , bool ) {
262
344
if depMode == GoGetWithModules {
263
345
versionRe := regexp .MustCompile (`(?m)^go[ \t\r]+([0-9]+\.[0-9]+)$` )
264
- goMod , err := os .ReadFile ("go.mod" )
346
+ goMod , err := os .ReadFile (filepath . Join ( baseDir , "go.mod" ) )
265
347
if err != nil {
266
348
log .Println ("Failed to read go.mod to check for missing Go version" )
267
349
} else {
@@ -277,13 +359,13 @@ func tryReadGoDirective(depMode DependencyInstallerMode) (string, bool) {
277
359
}
278
360
279
361
// Returns the appropriate ModMode for the current project
280
- func getModMode (depMode DependencyInstallerMode ) ModMode {
362
+ func getModMode (depMode DependencyInstallerMode , baseDir string ) ModMode {
281
363
if depMode == GoGetWithModules {
282
364
// if a vendor/modules.txt file exists, we assume that there are vendored Go dependencies, and
283
365
// skip the dependency installation step and run the extractor with `-mod=vendor`
284
- if util .FileExists (" vendor/modules.txt" ) {
366
+ if util .FileExists (baseDir + "/ vendor/modules.txt" ) {
285
367
return ModVendor
286
- } else if util .DirExists (" vendor" ) {
368
+ } else if util .DirExists (baseDir + "/ vendor" ) {
287
369
return ModMod
288
370
}
289
371
}
@@ -344,25 +426,29 @@ func getNeedGopath(depMode DependencyInstallerMode, importpath string) bool {
344
426
}
345
427
346
428
// Try to update `go.mod` and `go.sum` if the go version is >= 1.16.
347
- func tryUpdateGoModAndGoSum (modMode ModMode , depMode DependencyInstallerMode ) {
429
+ func tryUpdateGoModAndGoSum (modMode ModMode , depMode DependencyInstallerMode , baseDir string ) {
348
430
// Go 1.16 and later won't automatically attempt to update go.mod / go.sum during package loading, so try to update them here:
349
431
if modMode != ModVendor && depMode == GoGetWithModules && semver .Compare (getEnvGoSemVer (), "v1.16" ) >= 0 {
350
432
// stat go.mod and go.sum
351
- beforeGoModFileInfo , beforeGoModErr := os .Stat ("go.mod" )
433
+ goModPath := filepath .Join (baseDir , "go.mod" )
434
+ beforeGoModFileInfo , beforeGoModErr := os .Stat (goModPath )
352
435
if beforeGoModErr != nil {
353
436
log .Println ("Failed to stat go.mod before running `go mod tidy -e`" )
354
437
}
355
438
356
- beforeGoSumFileInfo , beforeGoSumErr := os .Stat ("go.sum" )
439
+ goSumPath := filepath .Join (baseDir , "go.sum" )
440
+ beforeGoSumFileInfo , beforeGoSumErr := os .Stat (goSumPath )
357
441
358
442
// run `go mod tidy -e`
359
- res := util .RunCmd (exec .Command ("go" , "mod" , "tidy" , "-e" ))
443
+ cmd := exec .Command ("go" , "mod" , "tidy" , "-e" )
444
+ cmd .Dir = baseDir
445
+ res := util .RunCmd (cmd )
360
446
361
447
if ! res {
362
448
log .Println ("Failed to run `go mod tidy -e`" )
363
449
} else {
364
450
if beforeGoModFileInfo != nil {
365
- afterGoModFileInfo , afterGoModErr := os .Stat ("go.mod" )
451
+ afterGoModFileInfo , afterGoModErr := os .Stat (goModPath )
366
452
if afterGoModErr != nil {
367
453
log .Println ("Failed to stat go.mod after running `go mod tidy -e`" )
368
454
} else if afterGoModFileInfo .ModTime ().After (beforeGoModFileInfo .ModTime ()) {
@@ -371,7 +457,7 @@ func tryUpdateGoModAndGoSum(modMode ModMode, depMode DependencyInstallerMode) {
371
457
}
372
458
}
373
459
374
- afterGoSumFileInfo , afterGoSumErr := os .Stat ("go.sum" )
460
+ afterGoSumFileInfo , afterGoSumErr := os .Stat (goSumPath )
375
461
if afterGoSumErr != nil {
376
462
log .Println ("Failed to stat go.sum after running `go mod tidy -e`" )
377
463
} else {
@@ -560,7 +646,7 @@ func buildWithCustomCommands(inst string) {
560
646
}
561
647
562
648
// Install dependencies using the given dependency installer mode.
563
- func installDependencies (depMode DependencyInstallerMode ) {
649
+ func installDependencies (depMode DependencyInstallerMode , baseDir string ) {
564
650
// automatically determine command to install dependencies
565
651
var install * exec.Cmd
566
652
if depMode == Dep {
@@ -606,31 +692,28 @@ func installDependencies(depMode DependencyInstallerMode) {
606
692
607
693
// get dependencies
608
694
install = exec .Command ("go" , "get" , "-v" , "./..." )
609
- log .Println ("Installing dependencies using `go get -v ./...`." )
695
+ install .Dir = baseDir
696
+ log .Printf ("Installing dependencies using `go get -v ./...` in `%s`.\n " , baseDir )
610
697
}
611
698
util .RunCmd (install )
612
699
}
613
700
614
701
// Run the extractor.
615
- func extract (depMode DependencyInstallerMode , modMode ModMode ) {
702
+ func extract (depMode DependencyInstallerMode , modMode ModMode , baseDir string ) {
616
703
extractor , err := util .GetExtractorPath ()
617
704
if err != nil {
618
705
log .Fatalf ("Could not determine path of extractor: %v.\n " , err )
619
706
}
620
707
621
- cwd , err := os .Getwd ()
622
- if err != nil {
623
- log .Fatalf ("Unable to determine current directory: %s\n " , err .Error ())
624
- }
625
-
626
708
extractorArgs := []string {}
627
709
if depMode == GoGetWithModules {
628
710
extractorArgs = append (extractorArgs , modMode .argsForGoVersion (getEnvGoSemVer ())... )
629
711
}
630
712
extractorArgs = append (extractorArgs , "./..." )
631
713
632
- log .Printf ("Running extractor command '%s %v' from directory '%s'.\n " , extractor , extractorArgs , cwd )
714
+ log .Printf ("Running extractor command '%s %v' from directory '%s'.\n " , extractor , extractorArgs , baseDir )
633
715
cmd := exec .Command (extractor , extractorArgs ... )
716
+ cmd .Dir = baseDir
634
717
cmd .Stdout = os .Stdout
635
718
cmd .Stderr = os .Stderr
636
719
err = cmd .Run ()
@@ -650,21 +733,21 @@ func installDependenciesAndBuild() {
650
733
651
734
// determine how to install dependencies and whether a GOPATH needs to be set up before
652
735
// extraction
653
- depMode := getDepMode ()
736
+ depMode , baseDir := getDepMode (true )
654
737
if _ , present := os .LookupEnv ("GO111MODULE" ); ! present {
655
738
os .Setenv ("GO111MODULE" , "auto" )
656
739
}
657
740
658
- goModVersion , goModVersionFound := tryReadGoDirective (depMode )
741
+ goModVersion , goModVersionFound := tryReadGoDirective (depMode , baseDir )
659
742
660
743
if semver .Compare ("v" + goModVersion , getEnvGoSemVer ()) >= 0 {
661
744
diagnostics .EmitNewerGoVersionNeeded ()
662
745
}
663
746
664
- modMode := getModMode (depMode )
747
+ modMode := getModMode (depMode , baseDir )
665
748
modMode = fixGoVendorIssues (modMode , depMode , goModVersionFound )
666
749
667
- tryUpdateGoModAndGoSum (modMode , depMode )
750
+ tryUpdateGoModAndGoSum (modMode , depMode , baseDir )
668
751
669
752
importpath := getImportPath ()
670
753
needGopath := getNeedGopath (depMode , importpath )
@@ -707,11 +790,11 @@ func installDependenciesAndBuild() {
707
790
if modMode == ModVendor {
708
791
log .Printf ("Skipping dependency installation because a Go vendor directory was found." )
709
792
} else {
710
- installDependencies (depMode )
793
+ installDependencies (depMode , baseDir )
711
794
}
712
795
}
713
796
714
- extract (depMode , modMode )
797
+ extract (depMode , modMode , baseDir )
715
798
}
716
799
717
800
const minGoVersion = "1.11"
@@ -976,8 +1059,8 @@ func isGoInstalled() bool {
976
1059
// Get the version of Go to install and output it to stdout as json.
977
1060
func identifyEnvironment () {
978
1061
var v versionInfo
979
- depMode := getDepMode ()
980
- v .goModVersion , v .goModVersionFound = tryReadGoDirective (depMode )
1062
+ depMode , baseDir := getDepMode (false )
1063
+ v .goModVersion , v .goModVersionFound = tryReadGoDirective (depMode , baseDir )
981
1064
982
1065
v .goEnvVersionFound = isGoInstalled ()
983
1066
if v .goEnvVersionFound {
0 commit comments