2019-12-16 13:40:24 -07:00
|
|
|
// Copyright 2019 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package cache
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"io"
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
2020-01-11 18:29:13 -07:00
|
|
|
"path/filepath"
|
2019-12-16 13:40:24 -07:00
|
|
|
"strings"
|
|
|
|
|
|
|
|
"golang.org/x/tools/internal/lsp/source"
|
2019-12-19 08:20:43 -07:00
|
|
|
"golang.org/x/tools/internal/lsp/telemetry"
|
2020-01-11 18:29:13 -07:00
|
|
|
"golang.org/x/tools/internal/span"
|
2019-12-19 08:20:43 -07:00
|
|
|
"golang.org/x/tools/internal/telemetry/log"
|
2019-12-16 13:40:24 -07:00
|
|
|
errors "golang.org/x/xerrors"
|
|
|
|
)
|
|
|
|
|
2020-01-11 18:29:13 -07:00
|
|
|
func (v *view) modFiles(ctx context.Context) (span.URI, span.URI, error) {
|
|
|
|
// Don't return errors if the view is not a module.
|
|
|
|
if v.mod == nil {
|
|
|
|
return "", "", nil
|
|
|
|
}
|
|
|
|
return v.mod.realMod, v.mod.tempMod, nil
|
|
|
|
}
|
|
|
|
|
2019-12-16 13:40:24 -07:00
|
|
|
// This function will return the main go.mod file for this folder if it exists and whether the -modfile
|
|
|
|
// flag exists for this version of go.
|
2020-01-11 18:29:13 -07:00
|
|
|
func (v *view) modfileFlagExists(ctx context.Context, env []string) (string, bool, error) {
|
|
|
|
// Check the go version by running "go list" with modules off.
|
|
|
|
// Borrowed from internal/imports/mod.go:620.
|
2019-12-23 09:07:19 -07:00
|
|
|
const format = `{{range context.ReleaseTags}}{{if eq . "go1.14"}}{{.}}{{end}}{{end}}`
|
2020-01-11 18:29:13 -07:00
|
|
|
folder := v.folder.Filename()
|
2020-01-10 11:20:44 -07:00
|
|
|
stdout, err := source.InvokeGo(ctx, folder, append(env, "GO111MODULE=off"), "list", "-e", "-f", format)
|
2019-12-16 13:40:24 -07:00
|
|
|
if err != nil {
|
|
|
|
return "", false, err
|
|
|
|
}
|
2020-01-10 11:20:44 -07:00
|
|
|
// If the output is not go1.14 or an empty string, then it could be an error.
|
2019-12-16 13:40:24 -07:00
|
|
|
lines := strings.Split(stdout.String(), "\n")
|
2020-01-10 11:20:44 -07:00
|
|
|
if len(lines) < 2 && stdout.String() != "" {
|
|
|
|
log.Error(ctx, "unexpected stdout when checking for go1.14", errors.Errorf("%q", stdout), telemetry.Directory.Of(folder))
|
|
|
|
return "", false, nil
|
2019-12-16 13:40:24 -07:00
|
|
|
}
|
2020-01-11 18:29:13 -07:00
|
|
|
modfile := strings.TrimSpace(v.gomod)
|
2019-12-23 09:07:19 -07:00
|
|
|
if modfile == os.DevNull {
|
2020-01-11 18:29:13 -07:00
|
|
|
return "", false, errors.Errorf("unable to detect a go.mod file in %s", v.folder)
|
2019-12-23 09:07:19 -07:00
|
|
|
}
|
|
|
|
return modfile, lines[0] == "go1.14", nil
|
2019-12-16 13:40:24 -07:00
|
|
|
}
|
|
|
|
|
2020-01-11 18:29:13 -07:00
|
|
|
func (v *view) setModuleInformation(ctx context.Context, enabled bool) error {
|
|
|
|
// The user has disabled the use of the -modfile flag.
|
|
|
|
if !enabled {
|
|
|
|
log.Print(ctx, "using the -modfile flag is disabled", telemetry.Directory.Of(v.folder))
|
|
|
|
return nil
|
2019-12-19 08:20:43 -07:00
|
|
|
}
|
2020-01-11 18:29:13 -07:00
|
|
|
modFile, flagExists, err := v.modfileFlagExists(ctx, v.Options().Env)
|
2019-12-16 13:40:24 -07:00
|
|
|
if err != nil {
|
2020-01-11 18:29:13 -07:00
|
|
|
return err
|
2019-12-16 13:40:24 -07:00
|
|
|
}
|
2020-01-11 18:29:13 -07:00
|
|
|
// The user's version of Go does not support the -modfile flag.
|
2019-12-16 13:40:24 -07:00
|
|
|
if !flagExists {
|
2020-01-11 18:29:13 -07:00
|
|
|
return nil
|
2019-12-16 13:40:24 -07:00
|
|
|
}
|
2020-01-11 18:29:13 -07:00
|
|
|
if modFile == "" || modFile == os.DevNull {
|
|
|
|
return errors.Errorf("unable to detect a go.mod file in %s", v.folder)
|
2019-12-16 13:40:24 -07:00
|
|
|
}
|
2019-12-17 14:13:33 -07:00
|
|
|
// Copy the current go.mod file into the temporary go.mod file.
|
2020-01-11 18:29:13 -07:00
|
|
|
// The file's name will be of the format go.1234.mod.
|
|
|
|
// It's temporary go.sum file should have the corresponding format of go.1234.sum.
|
|
|
|
tempModFile, err := ioutil.TempFile("", "go.*.mod")
|
2019-12-16 13:40:24 -07:00
|
|
|
if err != nil {
|
2020-01-11 18:29:13 -07:00
|
|
|
return err
|
2019-12-16 13:40:24 -07:00
|
|
|
}
|
2020-01-11 18:29:13 -07:00
|
|
|
defer tempModFile.Close()
|
|
|
|
|
|
|
|
origFile, err := os.Open(modFile)
|
2019-12-16 13:40:24 -07:00
|
|
|
if err != nil {
|
2020-01-11 18:29:13 -07:00
|
|
|
return err
|
2019-12-16 13:40:24 -07:00
|
|
|
}
|
|
|
|
defer origFile.Close()
|
2019-12-17 14:13:33 -07:00
|
|
|
|
2020-01-11 18:29:13 -07:00
|
|
|
if _, err := io.Copy(tempModFile, origFile); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
v.mod = &moduleInformation{
|
|
|
|
realMod: span.FileURI(modFile),
|
|
|
|
tempMod: span.FileURI(tempModFile.Name()),
|
|
|
|
}
|
|
|
|
// Copy go.sum file as well (if there is one).
|
|
|
|
sumFile := filepath.Join(filepath.Dir(modFile), "go.sum")
|
|
|
|
stat, err := os.Stat(sumFile)
|
2019-12-17 14:13:33 -07:00
|
|
|
if err != nil || !stat.Mode().IsRegular() {
|
2020-01-11 18:29:13 -07:00
|
|
|
return nil
|
2019-12-17 14:13:33 -07:00
|
|
|
}
|
2020-01-11 18:29:13 -07:00
|
|
|
contents, err := ioutil.ReadFile(sumFile)
|
2019-12-17 14:13:33 -07:00
|
|
|
if err != nil {
|
2020-01-11 18:29:13 -07:00
|
|
|
return err
|
2019-12-17 14:13:33 -07:00
|
|
|
}
|
2020-01-11 18:29:13 -07:00
|
|
|
if err := ioutil.WriteFile(v.mod.tempSumFile(), contents, stat.Mode()); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// tempSumFile returns the path to the copied temporary go.sum file.
|
|
|
|
// It simply replaces the extension of the temporary go.mod file with "sum".
|
|
|
|
func (mod *moduleInformation) tempSumFile() string {
|
|
|
|
tmp := mod.tempMod.Filename()
|
|
|
|
return tmp[:len(tmp)-len("mod")] + "sum"
|
2019-12-17 14:13:33 -07:00
|
|
|
}
|