From 24b94acc2aa470366325f138fb32b8fd9fc6b3ce Mon Sep 17 00:00:00 2001 From: Sauyon Lee Date: Thu, 4 Jul 2019 11:56:59 +0100 Subject: [PATCH] go/packages: Ignore more errors in go list Adds some hacks to work around go list bugs causing golang/go#31462 and golang/go#32755. In addition, appends error messages generated in this manner to stdout instead of discarding stdout entirely, and ensures that this does not cause a conflicting package error by adding an internal field to packageJson. --- go/packages/golist.go | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/go/packages/golist.go b/go/packages/golist.go index 00e21a755c0..74b53eb3fbb 100644 --- a/go/packages/golist.go +++ b/go/packages/golist.go @@ -553,6 +553,8 @@ type jsonPackage struct { ForTest string // q in a "p [q.test]" package, else "" DepOnly bool + Gen bool // generated by this code + Error *jsonPackageError } @@ -611,11 +613,15 @@ func golistDriver(cfg *Config, words ...string) (*driverResponse, error) { } if old, found := seen[p.ImportPath]; found { - if !reflect.DeepEqual(p, old) { + if p.Gen { + // new package is generated, skip it + continue + } else if !reflect.DeepEqual(p, old) { return nil, fmt.Errorf("internal error: go list gives conflicting information for package %v", p.ImportPath) + } else if !old.Gen { + // skip the duplicate if the old package wasn't generated + continue } - // skip the duplicate - continue } seen[p.ImportPath] = p @@ -804,15 +810,28 @@ func invokeGo(cfg *Config, args ...string) (*bytes.Buffer, error) { // a zero exit status and set an error on that package. if len(stderr.String()) > 0 && strings.Contains(stderr.String(), "no Go files in") { // try to extract package name from string - stderrStr := stderr.String() - var importPath string - colon := strings.Index(stderrStr, ":") - if colon > 0 && strings.HasPrefix(stderrStr, "go build ") { - importPath = stderrStr[len("go build "):colon] + noFileRe := regexp.MustCompile(`(?m)^go build ([\p{L}\p{Nd}\/.]+): (no Go files in.*)$`) + + for _, matches := range noFileRe.FindAllStringSubmatch(stderr.String(), -1) { + stdout.WriteString(fmt.Sprintf(`{"ImportPath": %q,"Incomplete": true,"Error": {"Pos": "","Err": %q},"Gen": true}`+"\n", + matches[1], matches[2])) } - output := fmt.Sprintf(`{"ImportPath": %q,"Incomplete": true,"Error": {"Pos": "","Err": %q}}`, - importPath, strings.Trim(stderrStr, "\n")) - return bytes.NewBufferString(output), nil + return stdout, nil + } + + // Workaround for an instance of golang.org/issue/26755: go list -e will + // return a non-zero exit status if cgo preprocessing fails. But it should + // return a zero exit status and set an error on that package. + if len(stderr.String()) > 0 && + (strings.Contains(stderr.String(), "collect2: error: ld returned 1 exit status") || + strings.Contains(stderr.String(), "could not determine kind of name for C.")) { + pkgRe := regexp.MustCompile(`(?m)^# ([\p{L}\p{Nd}\/.]+)\n((?[^#].*\n)+)`) + + for _, matches := range pkgRe.FindAllStringSubmatch(stderr.String(), -1) { + stdout.WriteString(fmt.Sprintf(`{"ImportPath": %q,"Incomplete":true,"Error" {"Pos": "","Err": %q,"Gen": true}}`+"\n", + matches[1], strings.Trim(matches[2], "\n"))) + } + return stdout, nil } // Export mode entails a build.