x/exp/apidiff: copy changes from x/tools/internal/apidiff

We copied golang.org/x/exp/apidiff to x/tools a few months ago in
anticipation of developing gorelease in x/tools, which would depend on
apidiff.

We've decided to develop gorelease here in x/exp instead, which means
the copy in x/tools is no longer needed. This CL copies changes made
to the copy in x/tools since it was made. Another CL will delete the
copy in x/tools.

Change-Id: Ied79138616c2f3b2f49a0ee5ca95ff3179351354
Reviewed-on: https://go-review.googlesource.com/c/exp/+/197298
Run-TryBot: Jay Conrod <jayconrod@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
This commit is contained in:
Jay Conrod 2019-09-25 13:47:09 -04:00
Родитель 81c71964d7
Коммит 26a69ce95b
6 изменённых файлов: 111 добавлений и 19 удалений

Просмотреть файл

@ -265,7 +265,7 @@ var x = C // old type is int64, new is int
var y int64 = x // fails with new: different types in assignment
```
A change to the value of a constant can break compatiblity if the value is used
A change to the value of a constant can break compatibility if the value is used
in an array type:
```

Просмотреть файл

@ -24,10 +24,14 @@ import (
func Changes(old, new *types.Package) Report {
d := newDiffer(old, new)
d.checkPackage()
return Report{
Incompatible: d.incompatibles.collect(),
Compatible: d.compatibles.collect(),
r := Report{}
for _, m := range d.incompatibles.collect() {
r.Changes = append(r.Changes, Change{Message: m, Compatible: false})
}
for _, m := range d.compatibles.collect() {
r.Changes = append(r.Changes, Change{Message: m, Compatible: true})
}
return r
}
type differ struct {

Просмотреть файл

@ -6,8 +6,10 @@ import (
"go/types"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"reflect"
"runtime"
"sort"
"strings"
"testing"
@ -26,22 +28,24 @@ func TestChanges(t *testing.T) {
sort.Strings(wanti)
sort.Strings(wantc)
oldpkg, err := load("apidiff/old", dir)
oldpkg, err := load(t, "apidiff/old", dir)
if err != nil {
t.Fatal(err)
}
newpkg, err := load("apidiff/new", dir)
newpkg, err := load(t, "apidiff/new", dir)
if err != nil {
t.Fatal(err)
}
report := Changes(oldpkg.Types, newpkg.Types)
if !reflect.DeepEqual(report.Incompatible, wanti) {
t.Errorf("incompatibles: got %v\nwant %v\n", report.Incompatible, wanti)
got := report.messages(false)
if !reflect.DeepEqual(got, wanti) {
t.Errorf("incompatibles: got %v\nwant %v\n", got, wanti)
}
if !reflect.DeepEqual(report.Compatible, wantc) {
t.Errorf("compatibles: got %v\nwant %v\n", report.Compatible, wantc)
got = report.messages(true)
if !reflect.DeepEqual(got, wantc) {
t.Errorf("compatibles: got %v\nwant %v\n", got, wantc)
}
}
@ -113,7 +117,9 @@ func splitIntoPackages(t *testing.T, dir string) (incompatibles, compatibles []s
return
}
func load(importPath, goPath string) (*packages.Package, error) {
func load(t *testing.T, importPath, goPath string) (*packages.Package, error) {
needsGoPackages(t)
cfg := &packages.Config{
Mode: packages.LoadTypes,
}
@ -132,7 +138,7 @@ func load(importPath, goPath string) (*packages.Package, error) {
}
func TestExportedFields(t *testing.T) {
pkg, err := load("golang.org/x/exp/apidiff/testdata/exported_fields", "")
pkg, err := load(t, "golang.org/x/exp/apidiff/testdata/exported_fields", "")
if err != nil {
t.Fatal(err)
}
@ -164,3 +170,69 @@ func TestExportedFields(t *testing.T) {
}
}
}
// needsGoPackages skips t if the go/packages driver (or 'go' tool) implied by
// the current process environment is not present in the path.
//
// Copied and adapted from golang.org/x/tools/internal/testenv.
func needsGoPackages(t *testing.T) {
t.Helper()
tool := os.Getenv("GOPACKAGESDRIVER")
switch tool {
case "off":
// "off" forces go/packages to use the go command.
tool = "go"
case "":
if _, err := exec.LookPath("gopackagesdriver"); err == nil {
tool = "gopackagesdriver"
} else {
tool = "go"
}
}
needsTool(t, tool)
}
// needsTool skips t if the named tool is not present in the path.
//
// Copied and adapted from golang.org/x/tools/internal/testenv.
func needsTool(t *testing.T, tool string) {
_, err := exec.LookPath(tool)
if err == nil {
return
}
t.Helper()
if allowMissingTool(tool) {
t.Skipf("skipping because %s tool not available: %v", tool, err)
} else {
t.Fatalf("%s tool not available: %v", tool, err)
}
}
func allowMissingTool(tool string) bool {
if runtime.GOOS == "android" {
// Android builds generally run tests on a separate machine from the build,
// so don't expect any external tools to be available.
return true
}
if tool == "go" && os.Getenv("GO_BUILDER_NAME") == "illumos-amd64-joyent" {
// Work around a misconfigured builder (see https://golang.org/issue/33950).
return true
}
// If a developer is actively working on this test, we expect them to have all
// of its dependencies installed. However, if it's just a dependency of some
// other module (for example, being run via 'go test all'), we should be more
// tolerant of unusual environments.
return !packageMainIsDevel()
}
// packageMainIsDevel reports whether the module containing package main
// is a development version (if module information is available).
//
// Builds in GOPATH mode and builds that lack module information are assumed to
// be development versions.
var packageMainIsDevel = func() bool { return true }

Просмотреть файл

@ -8,7 +8,23 @@ import (
// Report describes the changes detected by Changes.
type Report struct {
Incompatible, Compatible []string
Changes []Change
}
// A Change describes a single API change.
type Change struct {
Message string
Compatible bool
}
func (r Report) messages(compatible bool) []string {
var msgs []string
for _, c := range r.Changes {
if c.Compatible == compatible {
msgs = append(msgs, c.Message)
}
}
return msgs
}
func (r Report) String() string {
@ -28,13 +44,13 @@ func (r Report) Text(w io.Writer) error {
func (r Report) TextIncompatible(w io.Writer, withHeader bool) error {
if withHeader {
return r.writeMessages(w, "Incompatible changes:", r.Incompatible)
return r.writeMessages(w, "Incompatible changes:", r.messages(false))
}
return r.writeMessages(w, "", r.Incompatible)
return r.writeMessages(w, "", r.messages(false))
}
func (r Report) TextCompatible(w io.Writer) error {
return r.writeMessages(w, "Compatible changes:", r.Compatible)
return r.writeMessages(w, "Compatible changes:", r.messages(true))
}
func (r Report) writeMessages(w io.Writer, header string, msgs []string) error {

2
go.mod
Просмотреть файл

@ -10,5 +10,5 @@ require (
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028
golang.org/x/mod v0.1.0
golang.org/x/sys v0.0.0-20190412213103-97732733099d
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479
golang.org/x/tools v0.0.0-20190925164712-ae58c0ff6b32
)

4
go.sum
Просмотреть файл

@ -23,6 +23,6 @@ golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479 h1:lfN2PY/jymfnxkNHlbBF5DwPsUvhqUnrdgfK01iH2s0=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190925164712-ae58c0ff6b32 h1:xE6VFETO5vvJp3W3iihukTHFkQiu9yrTMJNKu20CwE4=
golang.org/x/tools v0.0.0-20190925164712-ae58c0ff6b32/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=