mirror of https://github.com/k3s-io/k3s
Deduplicate identical typecheck errors between platforms.
parent
da440386d6
commit
137268d332
|
@ -24,6 +24,7 @@ import (
|
|||
"go/build"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -60,6 +61,8 @@ var (
|
|||
"linux/arm64", "linux/ppc64le",
|
||||
"linux/s390x", "darwin/386",
|
||||
}
|
||||
darwinPlatString = "darwin/386,darwin/amd64"
|
||||
windowsPlatString = "windows/386,windows/amd64"
|
||||
)
|
||||
|
||||
type analyzer struct {
|
||||
|
@ -69,6 +72,7 @@ type analyzer struct {
|
|||
failed bool
|
||||
platform string
|
||||
donePaths map[string]interface{}
|
||||
errors []string
|
||||
}
|
||||
|
||||
func newAnalyzer(platform string) *analyzer {
|
||||
|
@ -120,11 +124,19 @@ func (a *analyzer) handleError(err error) {
|
|||
return
|
||||
}
|
||||
}
|
||||
// TODO(rmmh): dedup errors across platforms?
|
||||
fmt.Fprintf(os.Stderr, "%sERROR(%s) %s\n", logPrefix, a.platform, err)
|
||||
a.errors = append(a.errors, err.Error())
|
||||
if *serial {
|
||||
fmt.Fprintf(os.Stderr, "%sERROR(%s) %s\n", logPrefix, a.platform, err)
|
||||
}
|
||||
a.failed = true
|
||||
}
|
||||
|
||||
func (a *analyzer) dumpAndResetErrors() []string {
|
||||
es := a.errors
|
||||
a.errors = nil
|
||||
return es
|
||||
}
|
||||
|
||||
// collect extracts test metadata from a file.
|
||||
func (a *analyzer) collect(dir string) {
|
||||
if _, ok := a.donePaths[dir]; ok {
|
||||
|
@ -262,6 +274,51 @@ func (c *collector) handlePath(path string, info os.FileInfo, err error) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
type analyzerResult struct {
|
||||
platform string
|
||||
dir string
|
||||
errors []string
|
||||
}
|
||||
|
||||
func dedupeErrors(out io.Writer, results chan analyzerResult, nDirs, nPlatforms int) {
|
||||
pkgRes := make(map[string][]analyzerResult)
|
||||
for done := 0; done < nDirs; {
|
||||
res := <-results
|
||||
pkgRes[res.dir] = append(pkgRes[res.dir], res)
|
||||
if len(pkgRes[res.dir]) != nPlatforms {
|
||||
continue // expect more results for dir
|
||||
}
|
||||
done++
|
||||
// Collect list of platforms for each error
|
||||
errPlats := map[string][]string{}
|
||||
for _, res := range pkgRes[res.dir] {
|
||||
for _, err := range res.errors {
|
||||
errPlats[err] = append(errPlats[err], res.platform)
|
||||
}
|
||||
}
|
||||
// Print each error (in the same order!) once.
|
||||
for _, res := range pkgRes[res.dir] {
|
||||
for _, err := range res.errors {
|
||||
if errPlats[err] == nil {
|
||||
continue // already printed
|
||||
}
|
||||
sort.Strings(errPlats[err])
|
||||
plats := strings.Join(errPlats[err], ",")
|
||||
if len(errPlats[err]) == len(crossPlatforms) {
|
||||
plats = "all"
|
||||
} else if plats == darwinPlatString {
|
||||
plats = "darwin"
|
||||
} else if plats == windowsPlatString {
|
||||
plats = "windows"
|
||||
}
|
||||
fmt.Fprintf(out, "%sERROR(%s) %s\n", logPrefix, plats, err)
|
||||
delete(errPlats, err)
|
||||
}
|
||||
}
|
||||
delete(pkgRes, res.dir)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
args := flag.Args()
|
||||
|
@ -296,6 +353,15 @@ func main() {
|
|||
var processedDirs int64
|
||||
var currentWork int64 // (dir_index << 8) | platform_index
|
||||
statuses := make([]int, len(ps))
|
||||
var results chan analyzerResult
|
||||
if !*serial {
|
||||
results = make(chan analyzerResult)
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
dedupeErrors(os.Stderr, results, len(c.dirs), len(ps))
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
for i, p := range ps {
|
||||
wg.Add(1)
|
||||
fn := func(i int, p string) {
|
||||
|
@ -305,6 +371,9 @@ func main() {
|
|||
a.collect(dir)
|
||||
atomic.AddInt64(&processedDirs, 1)
|
||||
atomic.StoreInt64(¤tWork, int64(n<<8|i))
|
||||
if results != nil {
|
||||
results <- analyzerResult{p, dir, a.dumpAndResetErrors()}
|
||||
}
|
||||
}
|
||||
if a.failed {
|
||||
statuses[i] = 1
|
||||
|
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
|
@ -155,3 +156,38 @@ func TestHandlePath(t *testing.T) {
|
|||
t.Error("should skip vendor")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDedupeErrors(t *testing.T) {
|
||||
testcases := []struct {
|
||||
nPlatforms int
|
||||
results []analyzerResult
|
||||
expected string
|
||||
}{
|
||||
{1, []analyzerResult{}, ""},
|
||||
{1, []analyzerResult{{"linux/arm", "test", nil}}, ""},
|
||||
{1, []analyzerResult{
|
||||
{"linux/arm", "test", []string{"a"}}},
|
||||
"ERROR(linux/arm) a\n"},
|
||||
{3, []analyzerResult{
|
||||
{"linux/arm", "test", []string{"a"}},
|
||||
{"windows/386", "test", []string{"b"}},
|
||||
{"windows/amd64", "test", []string{"b", "c"}}},
|
||||
"ERROR(linux/arm) a\n" +
|
||||
"ERROR(windows) b\n" +
|
||||
"ERROR(windows/amd64) c\n"},
|
||||
}
|
||||
for _, tc := range testcases {
|
||||
out := &bytes.Buffer{}
|
||||
results := make(chan analyzerResult, len(tc.results))
|
||||
for _, res := range tc.results {
|
||||
results <- res
|
||||
}
|
||||
close(results)
|
||||
dedupeErrors(out, results, len(tc.results)/tc.nPlatforms, tc.nPlatforms)
|
||||
outString := out.String()
|
||||
if outString != tc.expected {
|
||||
t.Errorf("dedupeErrors(%v) = '%s', expected '%s'",
|
||||
tc.results, outString, tc.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue