diff --git a/language/go/modules.go b/language/go/modules.go index 828cb8da7..affa0069f 100644 --- a/language/go/modules.go +++ b/language/go/modules.go @@ -17,14 +17,35 @@ package golang import ( "bytes" - "fmt" + "encoding/json" + "io" "os" "path/filepath" - "strings" "github.com/bazelbuild/bazel-gazelle/language" ) +func copyFile(src, dst string) error { + source, err := os.Open(src) + if err != nil { + return err + } + defer source.Close() + + destination, err := os.Create(dst) + if err != nil { + return err + } + defer destination.Close() + + _, err = io.Copy(destination, source) + if err != nil { + return err + } + + return nil +} + func importReposFromModules(args language.ImportReposArgs) language.ImportReposResult { // run go list in the dir where go.mod is located data, err := goListModules(filepath.Dir(args.Path)) @@ -37,29 +58,38 @@ func importReposFromModules(args language.ImportReposArgs) language.ImportReposR return language.ImportReposResult{Error: err} } - // Load sums from go.sum. Ideally, they're all there. - goSumPath := filepath.Join(filepath.Dir(args.Path), "go.sum") - data, _ = os.ReadFile(goSumPath) - lines := bytes.Split(data, []byte("\n")) - for _, line := range lines { - line = bytes.TrimSpace(line) - fields := bytes.Fields(line) - if len(fields) != 3 { - continue - } - path, version, sum := string(fields[0]), string(fields[1]), string(fields[2]) - if strings.HasSuffix(version, "/go.mod") { - continue - } - if mod, ok := pathToModule[path+"@"+version]; ok { - mod.Sum = sum - } + // filtered 'go list' result with 'go mod download' + filteredMapToModule := make(map[string]*moduleFromList) + tmpDir, err := os.MkdirTemp("", "") + if err != nil { + return language.ImportReposResult{Error: err} } - - pathToModule, err = fillMissingSums(pathToModule) + defer os.RemoveAll(tmpDir) + wsPath := filepath.Dir(args.Path) + if err := copyFile(filepath.Join(wsPath, "go.mod"), filepath.Join(tmpDir, "go.mod")); err != nil { + return language.ImportReposResult{Error: err} + } + if err := copyFile(filepath.Join(wsPath, "go.sum"), filepath.Join(tmpDir, "go.sum")); err != nil { + // ignore if go.sum is not found + } + downloadData, err := goModDownload(tmpDir, []string{}) if err != nil { - return language.ImportReposResult{Error: fmt.Errorf("finding module sums: %v", err)} + return language.ImportReposResult{Error: err} + } + dec := json.NewDecoder(bytes.NewReader(downloadData)) + for dec.More() { + var dl moduleFromDownload + if err := dec.Decode(&dl); err != nil { + return language.ImportReposResult{Error: err} + } + path := dl.Path + "@" + dl.Version + if mod, ok := pathToModule[path]; ok { + if mod.Sum == "" { + mod.Sum = dl.Sum + } + filteredMapToModule[path] = mod + } } - return language.ImportReposResult{Gen: toRepositoryRules(pathToModule)} + return language.ImportReposResult{Gen: toRepositoryRules(filteredMapToModule)} } diff --git a/language/go/update.go b/language/go/update.go index d1be928f4..23280c5b9 100644 --- a/language/go/update.go +++ b/language/go/update.go @@ -69,6 +69,9 @@ func (*goLang) CanImport(path string) bool { func (*goLang) ImportRepos(args language.ImportReposArgs) language.ImportReposResult { res := repoImportFuncs[filepath.Base(args.Path)](args) + if res.Error != nil { + return res + } for _, r := range res.Gen { setBuildAttrs(getGoConfig(args.Config), r) } diff --git a/repo/remote.go b/repo/remote.go index 1b2805854..cd1bc3763 100644 --- a/repo/remote.go +++ b/repo/remote.go @@ -607,7 +607,7 @@ func (rc *RemoteCache) initTmp() { if rc.tmpErr != nil { return } - rc.tmpErr = os.WriteFile(filepath.Join(rc.tmpDir, "go.mod"), []byte("module gazelle_remote_cache\ngo 1.15\n"), 0o666) + rc.tmpErr = os.WriteFile(filepath.Join(rc.tmpDir, "go.mod"), []byte("module gazelle_remote_cache\ngo 1.22\n"), 0o666) }) }