@@ -11,6 +11,8 @@ import (
11
11
"fmt"
12
12
"go/ast"
13
13
"go/token"
14
+ "io"
15
+ "io/ioutil"
14
16
stdlog "log"
15
17
"os"
16
18
"path/filepath"
@@ -23,6 +25,7 @@ import (
23
25
"golang.org/x/tools/internal/imports"
24
26
"golang.org/x/tools/internal/lsp/debug"
25
27
"golang.org/x/tools/internal/lsp/source"
28
+ "golang.org/x/tools/internal/lsp/telemetry"
26
29
"golang.org/x/tools/internal/memoize"
27
30
"golang.org/x/tools/internal/span"
28
31
"golang.org/x/tools/internal/telemetry/log"
@@ -660,3 +663,85 @@ func (v *view) setGoEnv(ctx context.Context, dir string, env []string) (string,
660
663
}
661
664
return "" , nil
662
665
}
666
+
667
+ // This function will return the main go.mod file for this folder if it exists and whether the -modfile
668
+ // flag exists for this version of go.
669
+ func (v * view ) modfileFlagExists (ctx context.Context , env []string ) (bool , error ) {
670
+ // Check the go version by running "go list" with modules off.
671
+ // Borrowed from internal/imports/mod.go:620.
672
+ const format = `{{range context.ReleaseTags}}{{if eq . "go1.14"}}{{.}}{{end}}{{end}}`
673
+ folder := v .folder .Filename ()
674
+ stdout , err := source .InvokeGo (ctx , folder , append (env , "GO111MODULE=off" ), "list" , "-e" , "-f" , format )
675
+ if err != nil {
676
+ return false , err
677
+ }
678
+ // If the output is not go1.14 or an empty string, then it could be an error.
679
+ lines := strings .Split (stdout .String (), "\n " )
680
+ if len (lines ) < 2 && stdout .String () != "" {
681
+ log .Error (ctx , "unexpected stdout when checking for go1.14" , errors .Errorf ("%q" , stdout ), telemetry .Directory .Of (folder ))
682
+ return false , nil
683
+ }
684
+ return lines [0 ] == "go1.14" , nil
685
+ }
686
+
687
+ func (v * view ) setModuleInformation (ctx context.Context , gomod string , modfileFlagEnabled bool ) error {
688
+ modFile := strings .TrimSpace (gomod )
689
+ if modFile == os .DevNull {
690
+ return nil
691
+ }
692
+ v .mod = moduleInformation {
693
+ realMod : span .FileURI (modFile ),
694
+ }
695
+ // The user has disabled the use of the -modfile flag.
696
+ if ! modfileFlagEnabled {
697
+ return nil
698
+ }
699
+ if modfileFlag , err := v .modfileFlagExists (ctx , v .Options ().Env ); err != nil {
700
+ return err
701
+ } else if ! modfileFlag {
702
+ return nil
703
+ }
704
+ // Copy the current go.mod file into the temporary go.mod file.
705
+ // The file's name will be of the format go.1234.mod.
706
+ // It's temporary go.sum file should have the corresponding format of go.1234.sum.
707
+ tempModFile , err := ioutil .TempFile ("" , "go.*.mod" )
708
+ if err != nil {
709
+ return err
710
+ }
711
+ defer tempModFile .Close ()
712
+
713
+ origFile , err := os .Open (modFile )
714
+ if err != nil {
715
+ return err
716
+ }
717
+ defer origFile .Close ()
718
+
719
+ if _ , err := io .Copy (tempModFile , origFile ); err != nil {
720
+ return err
721
+ }
722
+ v .mod .tempMod = span .FileURI (tempModFile .Name ())
723
+
724
+ // Copy go.sum file as well (if there is one).
725
+ sumFile := filepath .Join (filepath .Dir (modFile ), "go.sum" )
726
+ stat , err := os .Stat (sumFile )
727
+ if err != nil || ! stat .Mode ().IsRegular () {
728
+ return nil
729
+ }
730
+ contents , err := ioutil .ReadFile (sumFile )
731
+ if err != nil {
732
+ return err
733
+ }
734
+ if err := ioutil .WriteFile (tempSumFile (tempModFile .Name ()), contents , stat .Mode ()); err != nil {
735
+ return err
736
+ }
737
+ return nil
738
+ }
739
+
740
+ // tempSumFile returns the path to the copied temporary go.sum file.
741
+ // It simply replaces the extension of the temporary go.mod file with "sum".
742
+ func tempSumFile (filename string ) string {
743
+ if filename == "" {
744
+ return ""
745
+ }
746
+ return filename [:len (filename )- len ("mod" )] + "sum"
747
+ }
0 commit comments