diff options
Diffstat (limited to 'src/cmd/api')
-rw-r--r-- | src/cmd/api/goapi.go | 158 | ||||
-rw-r--r-- | src/cmd/api/goapi_test.go | 24 | ||||
-rw-r--r-- | src/cmd/api/run.go | 9 |
3 files changed, 168 insertions, 23 deletions
diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go index 4bde794a1..4a63eac71 100644 --- a/src/cmd/api/goapi.go +++ b/src/cmd/api/goapi.go @@ -107,6 +107,8 @@ func setContexts() { } } +var internalPkg = regexp.MustCompile(`(^|/)internal($|/)`) + func main() { flag.Parse() @@ -132,12 +134,16 @@ func main() { if err != nil { log.Fatal(err) } - pkgNames = strings.Fields(string(stds)) + for _, pkg := range strings.Fields(string(stds)) { + if !internalPkg.MatchString(pkg) { + pkgNames = append(pkgNames, pkg) + } + } } var featureCtx = make(map[string]map[string]bool) // feature -> context name -> true for _, context := range contexts { - w := NewWalker(context, filepath.Join(build.Default.GOROOT, "src/pkg")) + w := NewWalker(context, filepath.Join(build.Default.GOROOT, "src")) for _, name := range pkgNames { // - Package "unsafe" contains special signatures requiring @@ -277,7 +283,7 @@ func compareAPI(w io.Writer, features, required, optional, exception []string) ( delete(optionalSet, newFeature) } else { fmt.Fprintf(w, "+%s\n", newFeature) - if !*allowNew { + if !*allowNew || !strings.Contains(runtime.Version(), "devel") { ok = false // we're in lock-down mode for next release } } @@ -307,11 +313,15 @@ func fileFeatures(filename string) []string { if err != nil { log.Fatalf("Error reading file %s: %v", filename, err) } - text := strings.TrimSpace(string(bs)) - if text == "" { - return nil + lines := strings.Split(string(bs), "\n") + var nonblank []string + for _, line := range lines { + line = strings.TrimSpace(line) + if line != "" && !strings.HasPrefix(line, "#") { + nonblank = append(nonblank, line) + } } - return strings.Split(text, "\n") + return nonblank } var fset = token.NewFileSet() @@ -370,6 +380,106 @@ func (w *Walker) parseFile(dir, file string) (*ast.File, error) { log.Fatalf("incorrect generated file: %s", err) } } + if w.context != nil && file == fmt.Sprintf("zruntime_defs_%s_%s.go", w.context.GOOS, w.context.GOARCH) { + // Just enough to keep the api checker happy. Keep sorted. + src := "package runtime; type (" + + " _defer struct{};" + + " _func struct{};" + + " _panic struct{};" + + " _select struct{}; " + + " _type struct{};" + + " alg struct{};" + + " chantype struct{};" + + " context struct{};" + // windows + " eface struct{};" + + " epollevent struct{};" + + " funcval struct{};" + + " g struct{};" + + " gobuf struct{};" + + " hchan struct{};" + + " iface struct{};" + + " interfacetype struct{};" + + " itab struct{};" + + " keventt struct{};" + + " m struct{};" + + " maptype struct{};" + + " mcache struct{};" + + " mspan struct{};" + + " mutex struct{};" + + " note struct{};" + + " p struct{};" + + " parfor struct{};" + + " slicetype struct{};" + + " stkframe struct{};" + + " sudog struct{};" + + " timespec struct{};" + + " waitq struct{};" + + " wincallbackcontext struct{};" + + "); " + + "const (" + + " cb_max = 2000;" + + " _CacheLineSize = 64;" + + " _Gidle = 1;" + + " _Grunnable = 2;" + + " _Grunning = 3;" + + " _Gsyscall = 4;" + + " _Gwaiting = 5;" + + " _Gdead = 6;" + + " _Genqueue = 7;" + + " _Gcopystack = 8;" + + " _NSIG = 32;" + + " _FlagNoScan = iota;" + + " _FlagNoZero;" + + " _TinySize;" + + " _TinySizeClass;" + + " _MaxSmallSize;" + + " _PageShift;" + + " _PageSize;" + + " _PageMask;" + + " _BitsPerPointer;" + + " _BitsMask;" + + " _PointersPerByte;" + + " _MaxGCMask;" + + " _BitsDead;" + + " _BitsPointer;" + + " _MSpanInUse;" + + " _ConcurrentSweep;" + + " _KindBool;" + + " _KindInt;" + + " _KindInt8;" + + " _KindInt16;" + + " _KindInt32;" + + " _KindInt64;" + + " _KindUint;" + + " _KindUint8;" + + " _KindUint16;" + + " _KindUint32;" + + " _KindUint64;" + + " _KindUintptr;" + + " _KindFloat32;" + + " _KindFloat64;" + + " _KindComplex64;" + + " _KindComplex128;" + + " _KindArray;" + + " _KindChan;" + + " _KindFunc;" + + " _KindInterface;" + + " _KindMap;" + + " _KindPtr;" + + " _KindSlice;" + + " _KindString;" + + " _KindStruct;" + + " _KindUnsafePointer;" + + " _KindDirectIface;" + + " _KindGCProg;" + + " _KindNoPointers;" + + " _KindMask;" + + ")" + f, err = parser.ParseFile(fset, filename, src, 0) + if err != nil { + log.Fatalf("incorrect generated file: %s", err) + } + } if f == nil { f, err = parser.ParseFile(fset, filename, nil, 0) @@ -391,6 +501,11 @@ func contains(list []string, s string) bool { return false } +// The package cache doesn't operate correctly in rare (so far artificial) +// circumstances (issue 8425). Disable before debugging non-obvious errors +// from the type-checker. +const usePkgCache = true + var ( pkgCache = map[string]*types.Package{} // map tagKey to package pkgTags = map[string][]string{} // map import dir to list of relevant tags @@ -452,11 +567,13 @@ func (w *Walker) Import(name string) (pkg *types.Package) { // If we've already done an import with the same set // of relevant tags, reuse the result. var key string - if tags, ok := pkgTags[dir]; ok { - key = tagKey(dir, context, tags) - if pkg := pkgCache[key]; pkg != nil { - w.imported[name] = pkg - return pkg + if usePkgCache { + if tags, ok := pkgTags[dir]; ok { + key = tagKey(dir, context, tags) + if pkg := pkgCache[key]; pkg != nil { + w.imported[name] = pkg + return pkg + } } } @@ -469,9 +586,11 @@ func (w *Walker) Import(name string) (pkg *types.Package) { } // Save tags list first time we see a directory. - if _, ok := pkgTags[dir]; !ok { - pkgTags[dir] = info.AllTags - key = tagKey(dir, context, info.AllTags) + if usePkgCache { + if _, ok := pkgTags[dir]; !ok { + pkgTags[dir] = info.AllTags + key = tagKey(dir, context, info.AllTags) + } } filenames := append(append([]string{}, info.GoFiles...), info.CgoFiles...) @@ -488,6 +607,11 @@ func (w *Walker) Import(name string) (pkg *types.Package) { if !contains(filenames, n) { filenames = append(filenames, n) } + + n = fmt.Sprintf("zruntime_defs_%s_%s.go", w.context.GOOS, w.context.GOARCH) + if !contains(filenames, n) { + filenames = append(filenames, n) + } } // Parse package files. @@ -519,7 +643,9 @@ func (w *Walker) Import(name string) (pkg *types.Package) { log.Fatalf("error typechecking package %s: %s (%s)", name, err, ctxt) } - pkgCache[key] = pkg + if usePkgCache { + pkgCache[key] = pkg + } w.imported[name] = pkg return diff --git a/src/cmd/api/goapi_test.go b/src/cmd/api/goapi_test.go index b909c32b3..f4fb7d319 100644 --- a/src/cmd/api/goapi_test.go +++ b/src/cmd/api/goapi_test.go @@ -38,7 +38,7 @@ func TestGolden(t *testing.T) { continue } - goldenFile := filepath.Join("testdata", "src", "pkg", fi.Name(), "golden.txt") + goldenFile := filepath.Join("testdata", "src", fi.Name(), "golden.txt") w := NewWalker(nil, "testdata/src/pkg") w.export(w.Import(fi.Name())) @@ -142,6 +142,26 @@ func TestCompareAPI(t *testing.T) { } } +func TestSkipInternal(t *testing.T) { + tests := []struct { + pkg string + want bool + }{ + {"net/http", true}, + {"net/http/internal-foo", true}, + {"net/http/internal", false}, + {"net/http/internal/bar", false}, + {"internal/foo", false}, + {"internal", false}, + } + for _, tt := range tests { + got := !internalPkg.MatchString(tt.pkg) + if got != tt.want { + t.Errorf("%s is internal = %v; want %v", tt.pkg, got, tt.want) + } + } +} + func BenchmarkAll(b *testing.B) { stds, err := exec.Command("go", "list", "std").Output() if err != nil { @@ -156,7 +176,7 @@ func BenchmarkAll(b *testing.B) { for i := 0; i < b.N; i++ { for _, context := range contexts { - w := NewWalker(context, filepath.Join(build.Default.GOROOT, "src/pkg")) + w := NewWalker(context, filepath.Join(build.Default.GOROOT, "src")) for _, name := range pkgNames { if name != "unsafe" && !strings.HasPrefix(name, "cmd/") { w.export(w.Import(name)) diff --git a/src/cmd/api/run.go b/src/cmd/api/run.go index 896b2b4a1..ed5613edd 100644 --- a/src/cmd/api/run.go +++ b/src/cmd/api/run.go @@ -21,6 +21,7 @@ import ( "os/exec" "os/user" "path/filepath" + "runtime" "strings" ) @@ -53,7 +54,7 @@ func main() { } out, err = exec.Command("go", "tool", "api", - "-c", file("go1", "go1.1", "go1.2", "go1.3"), + "-c", file("go1", "go1.1", "go1.2", "go1.3", "go1.4"), "-next", file("next"), "-except", file("except")).CombinedOutput() if err != nil { @@ -98,16 +99,14 @@ func prepGoPath() string { if err == nil { username = u.Username } else { - // Only need to handle Unix here, as Windows's os/user uses - // native syscall and should work fine without cgo. username = os.Getenv("USER") if username == "" { - log.Fatalf("Error getting current user: %v", err) + username = "nobody" } } // The GOPATH we'll return - gopath := filepath.Join(os.TempDir(), "gopath-api-"+cleanUsername(username), goToolsVersion) + gopath := filepath.Join(os.TempDir(), "gopath-api-"+cleanUsername(username)+"-"+cleanUsername(strings.Fields(runtime.Version())[0]), goToolsVersion) // cloneDir is where we run "hg clone". cloneDir := filepath.Join(gopath, "src", "code.google.com", "p") |