Update Go to v1.15.7

This commit is contained in:
Ciprian Hacman 2021-01-20 07:19:13 +02:00
parent 26cb84f5e1
commit 0fb16ddf10
236 changed files with 6837 additions and 1962 deletions

View File

@ -16,7 +16,7 @@ jobs:
- name: Set up go - name: Set up go
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: 1.15.4 go-version: 1.15.7
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
@ -33,7 +33,7 @@ jobs:
- name: Set up go - name: Set up go
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: 1.15.4 go-version: 1.15.7
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
@ -50,7 +50,7 @@ jobs:
- name: Set up go - name: Set up go
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: 1.15.4 go-version: 1.15.7
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
@ -67,7 +67,7 @@ jobs:
- name: Set up go - name: Set up go
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: 1.15.4 go-version: 1.15.7
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:

View File

@ -29,8 +29,8 @@ go_rules_dependencies()
go_download_sdk( go_download_sdk(
name = "go_sdk", name = "go_sdk",
sdks = { sdks = {
"darwin_amd64": ("go1.15.6.darwin-amd64.tar.gz", "940a73b45993a3bae5792cf324140dded34af97c548af4864d22fd6d49f3bd9f"), "darwin_amd64": ("go1.15.7.darwin-amd64.tar.gz", "af423736fffded2b588bab13b8963ad071eb47600ec83d0304a9a3ab95ef49a0"),
"linux_amd64": ("go1.15.6.linux-amd64.tar.gz", "3918e6cc85e7eaaa6f859f1bdbaac772e7a825b0eb423c63d3ae68b21f84b844"), "linux_amd64": ("go1.15.7.linux-amd64.tar.gz", "0d142143794721bb63ce6c8a6180c4062bcf8ef4715e7d6d6609f3a8282629b3"),
}, },
) )

11
go.mod
View File

@ -73,7 +73,7 @@ require (
github.com/go-ini/ini v1.51.0 github.com/go-ini/ini v1.51.0
github.com/go-logr/logr v0.2.1-0.20200730175230-ee2de8da5be6 github.com/go-logr/logr v0.2.1-0.20200730175230-ee2de8da5be6
github.com/gogo/protobuf v1.3.1 github.com/gogo/protobuf v1.3.1
github.com/google/go-cmp v0.4.0 github.com/google/go-cmp v0.5.4
github.com/google/uuid v1.1.1 github.com/google/uuid v1.1.1
github.com/gophercloud/gophercloud v0.11.1-0.20200518183226-7aec46f32c19 github.com/gophercloud/gophercloud v0.11.1-0.20200518183226-7aec46f32c19
github.com/gorilla/mux v1.7.3 github.com/gorilla/mux v1.7.3
@ -89,7 +89,7 @@ require (
github.com/pelletier/go-toml v1.8.1 github.com/pelletier/go-toml v1.8.1
github.com/pkg/sftp v0.0.0-20160930220758-4d0e916071f6 github.com/pkg/sftp v0.0.0-20160930220758-4d0e916071f6
github.com/prometheus/client_golang v1.7.1 github.com/prometheus/client_golang v1.7.1
github.com/sergi/go-diff v1.0.0 github.com/sergi/go-diff v1.1.0
github.com/spf13/cobra v1.0.0 github.com/spf13/cobra v1.0.0
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.4.0 github.com/spf13/viper v1.4.0
@ -100,15 +100,16 @@ require (
github.com/zclconf/go-cty v1.3.1 github.com/zclconf/go-cty v1.3.1
go.uber.org/zap v1.10.0 go.uber.org/zap v1.10.0
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
golang.org/x/mod v0.4.0 // indirect
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b golang.org/x/net v0.0.0-20201110031124-69a78807bb2b
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
golang.org/x/sys v0.0.0-20201112073958-5cba982894dd golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4
golang.org/x/tools v0.0.0-20200626171337-aa94e735be7f golang.org/x/tools v0.1.0
google.golang.org/api v0.22.0 google.golang.org/api v0.22.0
gopkg.in/gcfg.v1 v1.2.3 gopkg.in/gcfg.v1 v1.2.3
gopkg.in/inf.v0 v0.9.1 gopkg.in/inf.v0 v0.9.1
gopkg.in/yaml.v2 v2.3.0 gopkg.in/yaml.v2 v2.3.0
honnef.co/go/tools v0.0.1-2020.1.4 honnef.co/go/tools v0.0.1-2020.1.6
k8s.io/api v0.19.5 k8s.io/api v0.19.5
k8s.io/apimachinery v0.19.5 k8s.io/apimachinery v0.19.5
k8s.io/cli-runtime v0.19.5 k8s.io/cli-runtime v0.19.5

24
go.sum
View File

@ -389,6 +389,8 @@ github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
@ -760,6 +762,8 @@ github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo= github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
@ -838,6 +842,7 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q
github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8= github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
github.com/zclconf/go-cty v1.3.1 h1:QIOZl+CKKdkv4l2w3lG23nNzXgLoxsWLSEdg1MlX4p0= github.com/zclconf/go-cty v1.3.1 h1:QIOZl+CKKdkv4l2w3lG23nNzXgLoxsWLSEdg1MlX4p0=
github.com/zclconf/go-cty v1.3.1/go.mod h1:YO23e2L18AG+ZYQfSobnY4G65nvwvprPCxBHkufUH1k= github.com/zclconf/go-cty v1.3.1/go.mod h1:YO23e2L18AG+ZYQfSobnY4G65nvwvprPCxBHkufUH1k=
@ -904,6 +909,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0 h1:8pl+sMODzuvGJkmj2W4kZihvVb5mKm8pB/X44PIQHv8=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -940,6 +947,7 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dD
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@ -955,6 +963,8 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -1007,6 +1017,8 @@ golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201112073958-5cba982894dd h1:5CtCZbICpIOFdgO940moixOPjc0178IU44m4EjOO5IY= golang.org/x/sys v0.0.0-20201112073958-5cba982894dd h1:5CtCZbICpIOFdgO940moixOPjc0178IU44m4EjOO5IY=
golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
@ -1047,17 +1059,19 @@ golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191203134012-c197fd4bf371/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191203134012-c197fd4bf371/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200410194907-79a7a3126eef/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200626171337-aa94e735be7f h1:JcoF/bowzCDI+MXu1yLqQGNO3ibqWsWq+Sk7pOT218w= golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
golang.org/x/tools v0.0.0-20200626171337-aa94e735be7f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gomodules.xyz/jsonpatch/v2 v2.0.1 h1:xyiBuvkD2g5n7cYzx6u2sxQvsAy4QJsZFCzGVdzOXZ0= gomodules.xyz/jsonpatch/v2 v2.0.1 h1:xyiBuvkD2g5n7cYzx6u2sxQvsAy4QJsZFCzGVdzOXZ0=
gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU=
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
@ -1168,8 +1182,8 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8= honnef.co/go/tools v0.0.1-2020.1.6 h1:W18jzjh8mfPez+AwGLxmOImucz/IFjpNlrKVnaj2YVc=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.6/go.mod h1:pyyisuGw24ruLjrr1ddx39WE0y9OooInRzEYLhQB2YY=
k8s.io/api v0.19.5 h1:p0MRzyhokJ9Kn5jcJAHNup0s+COMBPfn1mTasls6mMg= k8s.io/api v0.19.5 h1:p0MRzyhokJ9Kn5jcJAHNup0s+COMBPfn1mTasls6mMg=
k8s.io/api v0.19.5/go.mod h1:yGZReuNa0vj56op6eT+NLrXJne0R0u9ktexZ8jdJzpc= k8s.io/api v0.19.5/go.mod h1:yGZReuNa0vj56op6eT+NLrXJne0R0u9ktexZ8jdJzpc=
k8s.io/apiextensions-apiserver v0.19.5 h1:LMlydaZH8UXo8Qi86IFXSQHdjb13uij7D6D+OubX5MU= k8s.io/apiextensions-apiserver v0.19.5 h1:LMlydaZH8UXo8Qi86IFXSQHdjb13uij7D6D+OubX5MU=

View File

@ -9,6 +9,7 @@ go_library(
"path.go", "path.go",
"report.go", "report.go",
"report_compare.go", "report_compare.go",
"report_references.go",
"report_reflect.go", "report_reflect.go",
"report_slices.go", "report_slices.go",
"report_text.go", "report_text.go",

View File

@ -1,11 +1,15 @@
// Copyright 2017, The Go Authors. All rights reserved. // Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file. // license that can be found in the LICENSE file.
// Package cmp determines equality of values. // Package cmp determines equality of values.
// //
// This package is intended to be a more powerful and safer alternative to // This package is intended to be a more powerful and safer alternative to
// reflect.DeepEqual for comparing whether two values are semantically equal. // reflect.DeepEqual for comparing whether two values are semantically equal.
// It is intended to only be used in tests, as performance is not a goal and
// it may panic if it cannot compare the values. Its propensity towards
// panicking means that its unsuitable for production environments where a
// spurious panic may be fatal.
// //
// The primary features of cmp are: // The primary features of cmp are:
// //
@ -86,6 +90,52 @@ import (
// If there is a cycle, then the pointed at values are considered equal // If there is a cycle, then the pointed at values are considered equal
// only if both addresses were previously visited in the same path step. // only if both addresses were previously visited in the same path step.
func Equal(x, y interface{}, opts ...Option) bool { func Equal(x, y interface{}, opts ...Option) bool {
s := newState(opts)
s.compareAny(rootStep(x, y))
return s.result.Equal()
}
// Diff returns a human-readable report of the differences between two values:
// y - x. It returns an empty string if and only if Equal returns true for the
// same input values and options.
//
// The output is displayed as a literal in pseudo-Go syntax.
// At the start of each line, a "-" prefix indicates an element removed from x,
// a "+" prefix to indicates an element added from y, and the lack of a prefix
// indicates an element common to both x and y. If possible, the output
// uses fmt.Stringer.String or error.Error methods to produce more humanly
// readable outputs. In such cases, the string is prefixed with either an
// 's' or 'e' character, respectively, to indicate that the method was called.
//
// Do not depend on this output being stable. If you need the ability to
// programmatically interpret the difference, consider using a custom Reporter.
func Diff(x, y interface{}, opts ...Option) string {
s := newState(opts)
// Optimization: If there are no other reporters, we can optimize for the
// common case where the result is equal (and thus no reported difference).
// This avoids the expensive construction of a difference tree.
if len(s.reporters) == 0 {
s.compareAny(rootStep(x, y))
if s.result.Equal() {
return ""
}
s.result = diff.Result{} // Reset results
}
r := new(defaultReporter)
s.reporters = append(s.reporters, reporter{r})
s.compareAny(rootStep(x, y))
d := r.String()
if (d == "") != s.result.Equal() {
panic("inconsistent difference and equality results")
}
return d
}
// rootStep constructs the first path step. If x and y have differing types,
// then they are stored within an empty interface type.
func rootStep(x, y interface{}) PathStep {
vx := reflect.ValueOf(x) vx := reflect.ValueOf(x)
vy := reflect.ValueOf(y) vy := reflect.ValueOf(y)
@ -108,33 +158,7 @@ func Equal(x, y interface{}, opts ...Option) bool {
t = vx.Type() t = vx.Type()
} }
s := newState(opts) return &pathStep{t, vx, vy}
s.compareAny(&pathStep{t, vx, vy})
return s.result.Equal()
}
// Diff returns a human-readable report of the differences between two values.
// It returns an empty string if and only if Equal returns true for the same
// input values and options.
//
// The output is displayed as a literal in pseudo-Go syntax.
// At the start of each line, a "-" prefix indicates an element removed from x,
// a "+" prefix to indicates an element added to y, and the lack of a prefix
// indicates an element common to both x and y. If possible, the output
// uses fmt.Stringer.String or error.Error methods to produce more humanly
// readable outputs. In such cases, the string is prefixed with either an
// 's' or 'e' character, respectively, to indicate that the method was called.
//
// Do not depend on this output being stable. If you need the ability to
// programmatically interpret the difference, consider using a custom Reporter.
func Diff(x, y interface{}, opts ...Option) string {
r := new(defaultReporter)
eq := Equal(x, y, Options(opts), Reporter(r))
d := r.String()
if (d == "") != eq {
panic("inconsistent difference and equality results")
}
return d
} }
type state struct { type state struct {
@ -352,7 +376,7 @@ func detectRaces(c chan<- reflect.Value, f reflect.Value, vs ...reflect.Value) {
// assuming that T is assignable to R. // assuming that T is assignable to R.
// Otherwise, it returns the input value as is. // Otherwise, it returns the input value as is.
func sanitizeValue(v reflect.Value, t reflect.Type) reflect.Value { func sanitizeValue(v reflect.Value, t reflect.Type) reflect.Value {
// TODO(dsnet): Workaround for reflect bug (https://golang.org/issue/22143). // TODO(≥go1.10): Workaround for reflect bug (https://golang.org/issue/22143).
if !flags.AtLeastGo110 { if !flags.AtLeastGo110 {
if v.Kind() == reflect.Interface && v.IsNil() && v.Type() != t { if v.Kind() == reflect.Interface && v.IsNil() && v.Type() != t {
return reflect.New(t).Elem() return reflect.New(t).Elem()
@ -362,6 +386,7 @@ func sanitizeValue(v reflect.Value, t reflect.Type) reflect.Value {
} }
func (s *state) compareStruct(t reflect.Type, vx, vy reflect.Value) { func (s *state) compareStruct(t reflect.Type, vx, vy reflect.Value) {
var addr bool
var vax, vay reflect.Value // Addressable versions of vx and vy var vax, vay reflect.Value // Addressable versions of vx and vy
var mayForce, mayForceInit bool var mayForce, mayForceInit bool
@ -383,6 +408,7 @@ func (s *state) compareStruct(t reflect.Type, vx, vy reflect.Value) {
// For retrieveUnexportedField to work, the parent struct must // For retrieveUnexportedField to work, the parent struct must
// be addressable. Create a new copy of the values if // be addressable. Create a new copy of the values if
// necessary to make them addressable. // necessary to make them addressable.
addr = vx.CanAddr() || vy.CanAddr()
vax = makeAddressable(vx) vax = makeAddressable(vx)
vay = makeAddressable(vy) vay = makeAddressable(vy)
} }
@ -393,6 +419,7 @@ func (s *state) compareStruct(t reflect.Type, vx, vy reflect.Value) {
mayForceInit = true mayForceInit = true
} }
step.mayForce = mayForce step.mayForce = mayForce
step.paddr = addr
step.pvx = vax step.pvx = vax
step.pvy = vay step.pvy = vay
step.field = t.Field(i) step.field = t.Field(i)

View File

@ -1,6 +1,6 @@
// Copyright 2017, The Go Authors. All rights reserved. // Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file. // license that can be found in the LICENSE file.
// +build purego // +build purego
@ -10,6 +10,6 @@ import "reflect"
const supportExporters = false const supportExporters = false
func retrieveUnexportedField(reflect.Value, reflect.StructField) reflect.Value { func retrieveUnexportedField(reflect.Value, reflect.StructField, bool) reflect.Value {
panic("no support for forcibly accessing unexported fields") panic("no support for forcibly accessing unexported fields")
} }

View File

@ -1,6 +1,6 @@
// Copyright 2017, The Go Authors. All rights reserved. // Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file. // license that can be found in the LICENSE file.
// +build !purego // +build !purego
@ -17,9 +17,19 @@ const supportExporters = true
// a struct such that the value has read-write permissions. // a struct such that the value has read-write permissions.
// //
// The parent struct, v, must be addressable, while f must be a StructField // The parent struct, v, must be addressable, while f must be a StructField
// describing the field to retrieve. // describing the field to retrieve. If addr is false,
func retrieveUnexportedField(v reflect.Value, f reflect.StructField) reflect.Value { // then the returned value will be shallowed copied to be non-addressable.
// See https://github.com/google/go-cmp/issues/167 for discussion of the func retrieveUnexportedField(v reflect.Value, f reflect.StructField, addr bool) reflect.Value {
// following expression. ve := reflect.NewAt(f.Type, unsafe.Pointer(uintptr(unsafe.Pointer(v.UnsafeAddr()))+f.Offset)).Elem()
return reflect.NewAt(f.Type, unsafe.Pointer(uintptr(unsafe.Pointer(v.UnsafeAddr()))+f.Offset)).Elem() if !addr {
// A field is addressable if and only if the struct is addressable.
// If the original parent value was not addressable, shallow copy the
// value to make it non-addressable to avoid leaking an implementation
// detail of how forcibly exporting a field works.
if ve.Kind() == reflect.Interface && ve.IsNil() {
return reflect.Zero(f.Type)
}
return reflect.ValueOf(ve.Interface()).Convert(f.Type)
}
return ve
} }

View File

@ -9,4 +9,5 @@ go_library(
importmap = "k8s.io/kops/vendor/github.com/google/go-cmp/cmp/internal/diff", importmap = "k8s.io/kops/vendor/github.com/google/go-cmp/cmp/internal/diff",
importpath = "github.com/google/go-cmp/cmp/internal/diff", importpath = "github.com/google/go-cmp/cmp/internal/diff",
visibility = ["//vendor/github.com/google/go-cmp/cmp:__subpackages__"], visibility = ["//vendor/github.com/google/go-cmp/cmp:__subpackages__"],
deps = ["//vendor/github.com/google/go-cmp/cmp/internal/flags:go_default_library"],
) )

View File

@ -1,6 +1,6 @@
// Copyright 2017, The Go Authors. All rights reserved. // Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file. // license that can be found in the LICENSE file.
// +build !cmp_debug // +build !cmp_debug

View File

@ -1,6 +1,6 @@
// Copyright 2017, The Go Authors. All rights reserved. // Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file. // license that can be found in the LICENSE file.
// +build cmp_debug // +build cmp_debug

View File

@ -1,6 +1,6 @@
// Copyright 2017, The Go Authors. All rights reserved. // Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file. // license that can be found in the LICENSE file.
// Package diff implements an algorithm for producing edit-scripts. // Package diff implements an algorithm for producing edit-scripts.
// The edit-script is a sequence of operations needed to transform one list // The edit-script is a sequence of operations needed to transform one list
@ -12,6 +12,13 @@
// is more important than obtaining a minimal Levenshtein distance. // is more important than obtaining a minimal Levenshtein distance.
package diff package diff
import (
"math/rand"
"time"
"github.com/google/go-cmp/cmp/internal/flags"
)
// EditType represents a single operation within an edit-script. // EditType represents a single operation within an edit-script.
type EditType uint8 type EditType uint8
@ -112,6 +119,8 @@ func (r Result) Similar() bool {
return r.NumSame+1 >= r.NumDiff return r.NumSame+1 >= r.NumDiff
} }
var randBool = rand.New(rand.NewSource(time.Now().Unix())).Intn(2) == 0
// Difference reports whether two lists of lengths nx and ny are equal // Difference reports whether two lists of lengths nx and ny are equal
// given the definition of equality provided as f. // given the definition of equality provided as f.
// //
@ -177,6 +186,11 @@ func Difference(nx, ny int, f EqualFunc) (es EditScript) {
// approximately the square-root of the search budget. // approximately the square-root of the search budget.
searchBudget := 4 * (nx + ny) // O(n) searchBudget := 4 * (nx + ny) // O(n)
// Running the tests with the "cmp_debug" build tag prints a visualization
// of the algorithm running in real-time. This is educational for
// understanding how the algorithm works. See debug_enable.go.
f = debug.Begin(nx, ny, f, &fwdPath.es, &revPath.es)
// The algorithm below is a greedy, meet-in-the-middle algorithm for // The algorithm below is a greedy, meet-in-the-middle algorithm for
// computing sub-optimal edit-scripts between two lists. // computing sub-optimal edit-scripts between two lists.
// //
@ -194,20 +208,26 @@ func Difference(nx, ny int, f EqualFunc) (es EditScript) {
// frontier towards the opposite corner. // frontier towards the opposite corner.
// • This algorithm terminates when either the X coordinates or the // • This algorithm terminates when either the X coordinates or the
// Y coordinates of the forward and reverse frontier points ever intersect. // Y coordinates of the forward and reverse frontier points ever intersect.
//
// This algorithm is correct even if searching only in the forward direction // This algorithm is correct even if searching only in the forward direction
// or in the reverse direction. We do both because it is commonly observed // or in the reverse direction. We do both because it is commonly observed
// that two lists commonly differ because elements were added to the front // that two lists commonly differ because elements were added to the front
// or end of the other list. // or end of the other list.
// //
// Running the tests with the "cmp_debug" build tag prints a visualization // Non-deterministically start with either the forward or reverse direction
// of the algorithm running in real-time. This is educational for // to introduce some deliberate instability so that we have the flexibility
// understanding how the algorithm works. See debug_enable.go. // to change this algorithm in the future.
f = debug.Begin(nx, ny, f, &fwdPath.es, &revPath.es) if flags.Deterministic || randBool {
for { goto forwardSearch
} else {
goto reverseSearch
}
forwardSearch:
{
// Forward search from the beginning. // Forward search from the beginning.
if fwdFrontier.X >= revFrontier.X || fwdFrontier.Y >= revFrontier.Y || searchBudget == 0 { if fwdFrontier.X >= revFrontier.X || fwdFrontier.Y >= revFrontier.Y || searchBudget == 0 {
break goto finishSearch
} }
for stop1, stop2, i := false, false, 0; !(stop1 && stop2) && searchBudget > 0; i++ { for stop1, stop2, i := false, false, 0; !(stop1 && stop2) && searchBudget > 0; i++ {
// Search in a diagonal pattern for a match. // Search in a diagonal pattern for a match.
@ -242,10 +262,14 @@ func Difference(nx, ny int, f EqualFunc) (es EditScript) {
} else { } else {
fwdFrontier.Y++ fwdFrontier.Y++
} }
goto reverseSearch
}
reverseSearch:
{
// Reverse search from the end. // Reverse search from the end.
if fwdFrontier.X >= revFrontier.X || fwdFrontier.Y >= revFrontier.Y || searchBudget == 0 { if fwdFrontier.X >= revFrontier.X || fwdFrontier.Y >= revFrontier.Y || searchBudget == 0 {
break goto finishSearch
} }
for stop1, stop2, i := false, false, 0; !(stop1 && stop2) && searchBudget > 0; i++ { for stop1, stop2, i := false, false, 0; !(stop1 && stop2) && searchBudget > 0; i++ {
// Search in a diagonal pattern for a match. // Search in a diagonal pattern for a match.
@ -280,8 +304,10 @@ func Difference(nx, ny int, f EqualFunc) (es EditScript) {
} else { } else {
revFrontier.Y-- revFrontier.Y--
} }
goto forwardSearch
} }
finishSearch:
// Join the forward and reverse paths and then append the reverse path. // Join the forward and reverse paths and then append the reverse path.
fwdPath.connect(revPath.point, f) fwdPath.connect(revPath.point, f)
for i := len(revPath.es) - 1; i >= 0; i-- { for i := len(revPath.es) - 1; i >= 0; i-- {

View File

@ -1,6 +1,6 @@
// Copyright 2019, The Go Authors. All rights reserved. // Copyright 2019, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file. // license that can be found in the LICENSE file.
package flags package flags

View File

@ -1,6 +1,6 @@
// Copyright 2019, The Go Authors. All rights reserved. // Copyright 2019, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file. // license that can be found in the LICENSE file.
// +build !go1.10 // +build !go1.10

View File

@ -1,6 +1,6 @@
// Copyright 2019, The Go Authors. All rights reserved. // Copyright 2019, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file. // license that can be found in the LICENSE file.
// +build go1.10 // +build go1.10

View File

@ -1,6 +1,6 @@
// Copyright 2017, The Go Authors. All rights reserved. // Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file. // license that can be found in the LICENSE file.
// Package function provides functionality for identifying function types. // Package function provides functionality for identifying function types.
package function package function

View File

@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library( go_library(
name = "go_default_library", name = "go_default_library",
srcs = [ srcs = [
"name.go",
"pointer_unsafe.go", "pointer_unsafe.go",
"sort.go", "sort.go",
"zero.go", "zero.go",

View File

@ -0,0 +1,157 @@
// Copyright 2020, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package value
import (
"reflect"
"strconv"
)
// TypeString is nearly identical to reflect.Type.String,
// but has an additional option to specify that full type names be used.
func TypeString(t reflect.Type, qualified bool) string {
return string(appendTypeName(nil, t, qualified, false))
}
func appendTypeName(b []byte, t reflect.Type, qualified, elideFunc bool) []byte {
// BUG: Go reflection provides no way to disambiguate two named types
// of the same name and within the same package,
// but declared within the namespace of different functions.
// Named type.
if t.Name() != "" {
if qualified && t.PkgPath() != "" {
b = append(b, '"')
b = append(b, t.PkgPath()...)
b = append(b, '"')
b = append(b, '.')
b = append(b, t.Name()...)
} else {
b = append(b, t.String()...)
}
return b
}
// Unnamed type.
switch k := t.Kind(); k {
case reflect.Bool, reflect.String, reflect.UnsafePointer,
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
b = append(b, k.String()...)
case reflect.Chan:
if t.ChanDir() == reflect.RecvDir {
b = append(b, "<-"...)
}
b = append(b, "chan"...)
if t.ChanDir() == reflect.SendDir {
b = append(b, "<-"...)
}
b = append(b, ' ')
b = appendTypeName(b, t.Elem(), qualified, false)
case reflect.Func:
if !elideFunc {
b = append(b, "func"...)
}
b = append(b, '(')
for i := 0; i < t.NumIn(); i++ {
if i > 0 {
b = append(b, ", "...)
}
if i == t.NumIn()-1 && t.IsVariadic() {
b = append(b, "..."...)
b = appendTypeName(b, t.In(i).Elem(), qualified, false)
} else {
b = appendTypeName(b, t.In(i), qualified, false)
}
}
b = append(b, ')')
switch t.NumOut() {
case 0:
// Do nothing
case 1:
b = append(b, ' ')
b = appendTypeName(b, t.Out(0), qualified, false)
default:
b = append(b, " ("...)
for i := 0; i < t.NumOut(); i++ {
if i > 0 {
b = append(b, ", "...)
}
b = appendTypeName(b, t.Out(i), qualified, false)
}
b = append(b, ')')
}
case reflect.Struct:
b = append(b, "struct{ "...)
for i := 0; i < t.NumField(); i++ {
if i > 0 {
b = append(b, "; "...)
}
sf := t.Field(i)
if !sf.Anonymous {
if qualified && sf.PkgPath != "" {
b = append(b, '"')
b = append(b, sf.PkgPath...)
b = append(b, '"')
b = append(b, '.')
}
b = append(b, sf.Name...)
b = append(b, ' ')
}
b = appendTypeName(b, sf.Type, qualified, false)
if sf.Tag != "" {
b = append(b, ' ')
b = strconv.AppendQuote(b, string(sf.Tag))
}
}
if b[len(b)-1] == ' ' {
b = b[:len(b)-1]
} else {
b = append(b, ' ')
}
b = append(b, '}')
case reflect.Slice, reflect.Array:
b = append(b, '[')
if k == reflect.Array {
b = strconv.AppendUint(b, uint64(t.Len()), 10)
}
b = append(b, ']')
b = appendTypeName(b, t.Elem(), qualified, false)
case reflect.Map:
b = append(b, "map["...)
b = appendTypeName(b, t.Key(), qualified, false)
b = append(b, ']')
b = appendTypeName(b, t.Elem(), qualified, false)
case reflect.Ptr:
b = append(b, '*')
b = appendTypeName(b, t.Elem(), qualified, false)
case reflect.Interface:
b = append(b, "interface{ "...)
for i := 0; i < t.NumMethod(); i++ {
if i > 0 {
b = append(b, "; "...)
}
m := t.Method(i)
if qualified && m.PkgPath != "" {
b = append(b, '"')
b = append(b, m.PkgPath...)
b = append(b, '"')
b = append(b, '.')
}
b = append(b, m.Name...)
b = appendTypeName(b, m.Type, qualified, true)
}
if b[len(b)-1] == ' ' {
b = b[:len(b)-1]
} else {
b = append(b, ' ')
}
b = append(b, '}')
default:
panic("invalid kind: " + k.String())
}
return b
}

View File

@ -1,6 +1,6 @@
// Copyright 2018, The Go Authors. All rights reserved. // Copyright 2018, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file. // license that can be found in the LICENSE file.
// +build purego // +build purego
@ -21,3 +21,13 @@ func PointerOf(v reflect.Value) Pointer {
// assumes that the GC implementation does not use a moving collector. // assumes that the GC implementation does not use a moving collector.
return Pointer{v.Pointer(), v.Type()} return Pointer{v.Pointer(), v.Type()}
} }
// IsNil reports whether the pointer is nil.
func (p Pointer) IsNil() bool {
return p.p == 0
}
// Uintptr returns the pointer as a uintptr.
func (p Pointer) Uintptr() uintptr {
return p.p
}

View File

@ -1,6 +1,6 @@
// Copyright 2018, The Go Authors. All rights reserved. // Copyright 2018, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file. // license that can be found in the LICENSE file.
// +build !purego // +build !purego
@ -24,3 +24,13 @@ func PointerOf(v reflect.Value) Pointer {
// which is necessary if the GC ever uses a moving collector. // which is necessary if the GC ever uses a moving collector.
return Pointer{unsafe.Pointer(v.Pointer()), v.Type()} return Pointer{unsafe.Pointer(v.Pointer()), v.Type()}
} }
// IsNil reports whether the pointer is nil.
func (p Pointer) IsNil() bool {
return p.p == nil
}
// Uintptr returns the pointer as a uintptr.
func (p Pointer) Uintptr() uintptr {
return uintptr(p.p)
}

View File

@ -1,6 +1,6 @@
// Copyright 2017, The Go Authors. All rights reserved. // Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file. // license that can be found in the LICENSE file.
package value package value

View File

@ -1,6 +1,6 @@
// Copyright 2017, The Go Authors. All rights reserved. // Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file. // license that can be found in the LICENSE file.
package value package value

View File

@ -1,6 +1,6 @@
// Copyright 2017, The Go Authors. All rights reserved. // Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file. // license that can be found in the LICENSE file.
package cmp package cmp
@ -225,11 +225,14 @@ func (validator) apply(s *state, vx, vy reflect.Value) {
// Unable to Interface implies unexported field without visibility access. // Unable to Interface implies unexported field without visibility access.
if !vx.CanInterface() || !vy.CanInterface() { if !vx.CanInterface() || !vy.CanInterface() {
const help = "consider using a custom Comparer; if you control the implementation of type, you can also consider using an Exporter, AllowUnexported, or cmpopts.IgnoreUnexported" help := "consider using a custom Comparer; if you control the implementation of type, you can also consider using an Exporter, AllowUnexported, or cmpopts.IgnoreUnexported"
var name string var name string
if t := s.curPath.Index(-2).Type(); t.Name() != "" { if t := s.curPath.Index(-2).Type(); t.Name() != "" {
// Named type with unexported fields. // Named type with unexported fields.
name = fmt.Sprintf("%q.%v", t.PkgPath(), t.Name()) // e.g., "path/to/package".MyType name = fmt.Sprintf("%q.%v", t.PkgPath(), t.Name()) // e.g., "path/to/package".MyType
if _, ok := reflect.New(t).Interface().(error); ok {
help = "consider using cmpopts.EquateErrors to compare error values"
}
} else { } else {
// Unnamed type with unexported fields. Derive PkgPath from field. // Unnamed type with unexported fields. Derive PkgPath from field.
var pkgPath string var pkgPath string

View File

@ -1,6 +1,6 @@
// Copyright 2017, The Go Authors. All rights reserved. // Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file. // license that can be found in the LICENSE file.
package cmp package cmp
@ -177,7 +177,8 @@ type structField struct {
// pvx, pvy, and field are only valid if unexported is true. // pvx, pvy, and field are only valid if unexported is true.
unexported bool unexported bool
mayForce bool // Forcibly allow visibility mayForce bool // Forcibly allow visibility
pvx, pvy reflect.Value // Parent values paddr bool // Was parent addressable?
pvx, pvy reflect.Value // Parent values (always addressible)
field reflect.StructField // Field information field reflect.StructField // Field information
} }
@ -189,8 +190,8 @@ func (sf StructField) Values() (vx, vy reflect.Value) {
// Forcibly obtain read-write access to an unexported struct field. // Forcibly obtain read-write access to an unexported struct field.
if sf.mayForce { if sf.mayForce {
vx = retrieveUnexportedField(sf.pvx, sf.field) vx = retrieveUnexportedField(sf.pvx, sf.field, sf.paddr)
vy = retrieveUnexportedField(sf.pvy, sf.field) vy = retrieveUnexportedField(sf.pvy, sf.field, sf.paddr)
return vx, vy // CanInterface reports true return vx, vy // CanInterface reports true
} }
return sf.vx, sf.vy // CanInterface reports false return sf.vx, sf.vy // CanInterface reports false

View File

@ -1,6 +1,6 @@
// Copyright 2017, The Go Authors. All rights reserved. // Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file. // license that can be found in the LICENSE file.
package cmp package cmp
@ -41,7 +41,10 @@ func (r *defaultReporter) String() string {
if r.root.NumDiff == 0 { if r.root.NumDiff == 0 {
return "" return ""
} }
return formatOptions{}.FormatDiff(r.root).String() ptrs := new(pointerReferences)
text := formatOptions{}.FormatDiff(r.root, ptrs)
resolveReferences(text)
return text.String()
} }
func assert(ok bool) { func assert(ok bool) {

View File

@ -1,6 +1,6 @@
// Copyright 2019, The Go Authors. All rights reserved. // Copyright 2019, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file. // license that can be found in the LICENSE file.
package cmp package cmp
@ -11,14 +11,6 @@ import (
"github.com/google/go-cmp/cmp/internal/value" "github.com/google/go-cmp/cmp/internal/value"
) )
// TODO: Enforce limits?
// * Enforce maximum number of records to print per node?
// * Enforce maximum size in bytes allowed?
// * As a heuristic, use less verbosity for equal nodes than unequal nodes.
// TODO: Enforce unique outputs?
// * Avoid Stringer methods if it results in same output?
// * Print pointer address if outputs still equal?
// numContextRecords is the number of surrounding equal records to print. // numContextRecords is the number of surrounding equal records to print.
const numContextRecords = 2 const numContextRecords = 2
@ -71,24 +63,66 @@ func (opts formatOptions) WithTypeMode(t typeMode) formatOptions {
opts.TypeMode = t opts.TypeMode = t
return opts return opts
} }
func (opts formatOptions) WithVerbosity(level int) formatOptions {
opts.VerbosityLevel = level
opts.LimitVerbosity = true
return opts
}
func (opts formatOptions) verbosity() uint {
switch {
case opts.VerbosityLevel < 0:
return 0
case opts.VerbosityLevel > 16:
return 16 // some reasonable maximum to avoid shift overflow
default:
return uint(opts.VerbosityLevel)
}
}
const maxVerbosityPreset = 3
// verbosityPreset modifies the verbosity settings given an index
// between 0 and maxVerbosityPreset, inclusive.
func verbosityPreset(opts formatOptions, i int) formatOptions {
opts.VerbosityLevel = int(opts.verbosity()) + 2*i
if i > 0 {
opts.AvoidStringer = true
}
if i >= maxVerbosityPreset {
opts.PrintAddresses = true
opts.QualifiedNames = true
}
return opts
}
// FormatDiff converts a valueNode tree into a textNode tree, where the later // FormatDiff converts a valueNode tree into a textNode tree, where the later
// is a textual representation of the differences detected in the former. // is a textual representation of the differences detected in the former.
func (opts formatOptions) FormatDiff(v *valueNode) textNode { func (opts formatOptions) FormatDiff(v *valueNode, ptrs *pointerReferences) (out textNode) {
if opts.DiffMode == diffIdentical {
opts = opts.WithVerbosity(1)
} else {
opts = opts.WithVerbosity(3)
}
// Check whether we have specialized formatting for this node. // Check whether we have specialized formatting for this node.
// This is not necessary, but helpful for producing more readable outputs. // This is not necessary, but helpful for producing more readable outputs.
if opts.CanFormatDiffSlice(v) { if opts.CanFormatDiffSlice(v) {
return opts.FormatDiffSlice(v) return opts.FormatDiffSlice(v)
} }
var parentKind reflect.Kind
if v.parent != nil && v.parent.TransformerName == "" {
parentKind = v.parent.Type.Kind()
}
// For leaf nodes, format the value based on the reflect.Values alone. // For leaf nodes, format the value based on the reflect.Values alone.
if v.MaxDepth == 0 { if v.MaxDepth == 0 {
switch opts.DiffMode { switch opts.DiffMode {
case diffUnknown, diffIdentical: case diffUnknown, diffIdentical:
// Format Equal. // Format Equal.
if v.NumDiff == 0 { if v.NumDiff == 0 {
outx := opts.FormatValue(v.ValueX, visitedPointers{}) outx := opts.FormatValue(v.ValueX, parentKind, ptrs)
outy := opts.FormatValue(v.ValueY, visitedPointers{}) outy := opts.FormatValue(v.ValueY, parentKind, ptrs)
if v.NumIgnored > 0 && v.NumSame == 0 { if v.NumIgnored > 0 && v.NumSame == 0 {
return textEllipsis return textEllipsis
} else if outx.Len() < outy.Len() { } else if outx.Len() < outy.Len() {
@ -101,8 +135,13 @@ func (opts formatOptions) FormatDiff(v *valueNode) textNode {
// Format unequal. // Format unequal.
assert(opts.DiffMode == diffUnknown) assert(opts.DiffMode == diffUnknown)
var list textList var list textList
outx := opts.WithTypeMode(elideType).FormatValue(v.ValueX, visitedPointers{}) outx := opts.WithTypeMode(elideType).FormatValue(v.ValueX, parentKind, ptrs)
outy := opts.WithTypeMode(elideType).FormatValue(v.ValueY, visitedPointers{}) outy := opts.WithTypeMode(elideType).FormatValue(v.ValueY, parentKind, ptrs)
for i := 0; i <= maxVerbosityPreset && outx != nil && outy != nil && outx.Equal(outy); i++ {
opts2 := verbosityPreset(opts, i).WithTypeMode(elideType)
outx = opts2.FormatValue(v.ValueX, parentKind, ptrs)
outy = opts2.FormatValue(v.ValueY, parentKind, ptrs)
}
if outx != nil { if outx != nil {
list = append(list, textRecord{Diff: '-', Value: outx}) list = append(list, textRecord{Diff: '-', Value: outx})
} }
@ -111,34 +150,57 @@ func (opts formatOptions) FormatDiff(v *valueNode) textNode {
} }
return opts.WithTypeMode(emitType).FormatType(v.Type, list) return opts.WithTypeMode(emitType).FormatType(v.Type, list)
case diffRemoved: case diffRemoved:
return opts.FormatValue(v.ValueX, visitedPointers{}) return opts.FormatValue(v.ValueX, parentKind, ptrs)
case diffInserted: case diffInserted:
return opts.FormatValue(v.ValueY, visitedPointers{}) return opts.FormatValue(v.ValueY, parentKind, ptrs)
default: default:
panic("invalid diff mode") panic("invalid diff mode")
} }
} }
// Register slice element to support cycle detection.
if parentKind == reflect.Slice {
ptrRefs := ptrs.PushPair(v.ValueX, v.ValueY, opts.DiffMode, true)
defer ptrs.Pop()
defer func() { out = wrapTrunkReferences(ptrRefs, out) }()
}
// Descend into the child value node. // Descend into the child value node.
if v.TransformerName != "" { if v.TransformerName != "" {
out := opts.WithTypeMode(emitType).FormatDiff(v.Value) out := opts.WithTypeMode(emitType).FormatDiff(v.Value, ptrs)
out = textWrap{"Inverse(" + v.TransformerName + ", ", out, ")"} out = &textWrap{Prefix: "Inverse(" + v.TransformerName + ", ", Value: out, Suffix: ")"}
return opts.FormatType(v.Type, out) return opts.FormatType(v.Type, out)
} else { } else {
switch k := v.Type.Kind(); k { switch k := v.Type.Kind(); k {
case reflect.Struct, reflect.Array, reflect.Slice, reflect.Map: case reflect.Struct, reflect.Array, reflect.Slice:
return opts.FormatType(v.Type, opts.formatDiffList(v.Records, k)) out = opts.formatDiffList(v.Records, k, ptrs)
out = opts.FormatType(v.Type, out)
case reflect.Map:
// Register map to support cycle detection.
ptrRefs := ptrs.PushPair(v.ValueX, v.ValueY, opts.DiffMode, false)
defer ptrs.Pop()
out = opts.formatDiffList(v.Records, k, ptrs)
out = wrapTrunkReferences(ptrRefs, out)
out = opts.FormatType(v.Type, out)
case reflect.Ptr: case reflect.Ptr:
return textWrap{"&", opts.FormatDiff(v.Value), ""} // Register pointer to support cycle detection.
ptrRefs := ptrs.PushPair(v.ValueX, v.ValueY, opts.DiffMode, false)
defer ptrs.Pop()
out = opts.FormatDiff(v.Value, ptrs)
out = wrapTrunkReferences(ptrRefs, out)
out = &textWrap{Prefix: "&", Value: out}
case reflect.Interface: case reflect.Interface:
return opts.WithTypeMode(emitType).FormatDiff(v.Value) out = opts.WithTypeMode(emitType).FormatDiff(v.Value, ptrs)
default: default:
panic(fmt.Sprintf("%v cannot have children", k)) panic(fmt.Sprintf("%v cannot have children", k))
} }
return out
} }
} }
func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind) textNode { func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind, ptrs *pointerReferences) textNode {
// Derive record name based on the data structure kind. // Derive record name based on the data structure kind.
var name string var name string
var formatKey func(reflect.Value) string var formatKey func(reflect.Value) string
@ -154,7 +216,17 @@ func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind) te
case reflect.Map: case reflect.Map:
name = "entry" name = "entry"
opts = opts.WithTypeMode(elideType) opts = opts.WithTypeMode(elideType)
formatKey = formatMapKey formatKey = func(v reflect.Value) string { return formatMapKey(v, false, ptrs) }
}
maxLen := -1
if opts.LimitVerbosity {
if opts.DiffMode == diffIdentical {
maxLen = ((1 << opts.verbosity()) >> 1) << 2 // 0, 4, 8, 16, 32, etc...
} else {
maxLen = (1 << opts.verbosity()) << 1 // 2, 4, 8, 16, 32, 64, etc...
}
opts.VerbosityLevel--
} }
// Handle unification. // Handle unification.
@ -163,6 +235,11 @@ func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind) te
var list textList var list textList
var deferredEllipsis bool // Add final "..." to indicate records were dropped var deferredEllipsis bool // Add final "..." to indicate records were dropped
for _, r := range recs { for _, r := range recs {
if len(list) == maxLen {
deferredEllipsis = true
break
}
// Elide struct fields that are zero value. // Elide struct fields that are zero value.
if k == reflect.Struct { if k == reflect.Struct {
var isZero bool var isZero bool
@ -186,23 +263,31 @@ func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind) te
} }
continue continue
} }
if out := opts.FormatDiff(r.Value); out != nil { if out := opts.FormatDiff(r.Value, ptrs); out != nil {
list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) list = append(list, textRecord{Key: formatKey(r.Key), Value: out})
} }
} }
if deferredEllipsis { if deferredEllipsis {
list.AppendEllipsis(diffStats{}) list.AppendEllipsis(diffStats{})
} }
return textWrap{"{", list, "}"} return &textWrap{Prefix: "{", Value: list, Suffix: "}"}
case diffUnknown: case diffUnknown:
default: default:
panic("invalid diff mode") panic("invalid diff mode")
} }
// Handle differencing. // Handle differencing.
var numDiffs int
var list textList var list textList
var keys []reflect.Value // invariant: len(list) == len(keys)
groups := coalesceAdjacentRecords(name, recs) groups := coalesceAdjacentRecords(name, recs)
maxGroup := diffStats{Name: name}
for i, ds := range groups { for i, ds := range groups {
if maxLen >= 0 && numDiffs >= maxLen {
maxGroup = maxGroup.Append(ds)
continue
}
// Handle equal records. // Handle equal records.
if ds.NumDiff() == 0 { if ds.NumDiff() == 0 {
// Compute the number of leading and trailing records to print. // Compute the number of leading and trailing records to print.
@ -226,16 +311,21 @@ func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind) te
// Format the equal values. // Format the equal values.
for _, r := range recs[:numLo] { for _, r := range recs[:numLo] {
out := opts.WithDiffMode(diffIdentical).FormatDiff(r.Value) out := opts.WithDiffMode(diffIdentical).FormatDiff(r.Value, ptrs)
list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) list = append(list, textRecord{Key: formatKey(r.Key), Value: out})
keys = append(keys, r.Key)
} }
if numEqual > numLo+numHi { if numEqual > numLo+numHi {
ds.NumIdentical -= numLo + numHi ds.NumIdentical -= numLo + numHi
list.AppendEllipsis(ds) list.AppendEllipsis(ds)
for len(keys) < len(list) {
keys = append(keys, reflect.Value{})
}
} }
for _, r := range recs[numEqual-numHi : numEqual] { for _, r := range recs[numEqual-numHi : numEqual] {
out := opts.WithDiffMode(diffIdentical).FormatDiff(r.Value) out := opts.WithDiffMode(diffIdentical).FormatDiff(r.Value, ptrs)
list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) list = append(list, textRecord{Key: formatKey(r.Key), Value: out})
keys = append(keys, r.Key)
} }
recs = recs[numEqual:] recs = recs[numEqual:]
continue continue
@ -247,24 +337,70 @@ func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind) te
case opts.CanFormatDiffSlice(r.Value): case opts.CanFormatDiffSlice(r.Value):
out := opts.FormatDiffSlice(r.Value) out := opts.FormatDiffSlice(r.Value)
list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) list = append(list, textRecord{Key: formatKey(r.Key), Value: out})
keys = append(keys, r.Key)
case r.Value.NumChildren == r.Value.MaxDepth: case r.Value.NumChildren == r.Value.MaxDepth:
outx := opts.WithDiffMode(diffRemoved).FormatDiff(r.Value) outx := opts.WithDiffMode(diffRemoved).FormatDiff(r.Value, ptrs)
outy := opts.WithDiffMode(diffInserted).FormatDiff(r.Value) outy := opts.WithDiffMode(diffInserted).FormatDiff(r.Value, ptrs)
for i := 0; i <= maxVerbosityPreset && outx != nil && outy != nil && outx.Equal(outy); i++ {
opts2 := verbosityPreset(opts, i)
outx = opts2.WithDiffMode(diffRemoved).FormatDiff(r.Value, ptrs)
outy = opts2.WithDiffMode(diffInserted).FormatDiff(r.Value, ptrs)
}
if outx != nil { if outx != nil {
list = append(list, textRecord{Diff: diffRemoved, Key: formatKey(r.Key), Value: outx}) list = append(list, textRecord{Diff: diffRemoved, Key: formatKey(r.Key), Value: outx})
keys = append(keys, r.Key)
} }
if outy != nil { if outy != nil {
list = append(list, textRecord{Diff: diffInserted, Key: formatKey(r.Key), Value: outy}) list = append(list, textRecord{Diff: diffInserted, Key: formatKey(r.Key), Value: outy})
keys = append(keys, r.Key)
} }
default: default:
out := opts.FormatDiff(r.Value) out := opts.FormatDiff(r.Value, ptrs)
list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) list = append(list, textRecord{Key: formatKey(r.Key), Value: out})
keys = append(keys, r.Key)
} }
} }
recs = recs[ds.NumDiff():] recs = recs[ds.NumDiff():]
numDiffs += ds.NumDiff()
} }
assert(len(recs) == 0) if maxGroup.IsZero() {
return textWrap{"{", list, "}"} assert(len(recs) == 0)
} else {
list.AppendEllipsis(maxGroup)
for len(keys) < len(list) {
keys = append(keys, reflect.Value{})
}
}
assert(len(list) == len(keys))
// For maps, the default formatting logic uses fmt.Stringer which may
// produce ambiguous output. Avoid calling String to disambiguate.
if k == reflect.Map {
var ambiguous bool
seenKeys := map[string]reflect.Value{}
for i, currKey := range keys {
if currKey.IsValid() {
strKey := list[i].Key
prevKey, seen := seenKeys[strKey]
if seen && prevKey.CanInterface() && currKey.CanInterface() {
ambiguous = prevKey.Interface() != currKey.Interface()
if ambiguous {
break
}
}
seenKeys[strKey] = currKey
}
}
if ambiguous {
for i, k := range keys {
if k.IsValid() {
list[i].Key = formatMapKey(k, true, ptrs)
}
}
}
}
return &textWrap{Prefix: "{", Value: list, Suffix: "}"}
} }
// coalesceAdjacentRecords coalesces the list of records into groups of // coalesceAdjacentRecords coalesces the list of records into groups of

View File

@ -0,0 +1,264 @@
// Copyright 2020, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package cmp
import (
"fmt"
"reflect"
"strings"
"github.com/google/go-cmp/cmp/internal/flags"
"github.com/google/go-cmp/cmp/internal/value"
)
const (
pointerDelimPrefix = "⟪"
pointerDelimSuffix = "⟫"
)
// formatPointer prints the address of the pointer.
func formatPointer(p value.Pointer, withDelims bool) string {
v := p.Uintptr()
if flags.Deterministic {
v = 0xdeadf00f // Only used for stable testing purposes
}
if withDelims {
return pointerDelimPrefix + formatHex(uint64(v)) + pointerDelimSuffix
}
return formatHex(uint64(v))
}
// pointerReferences is a stack of pointers visited so far.
type pointerReferences [][2]value.Pointer
func (ps *pointerReferences) PushPair(vx, vy reflect.Value, d diffMode, deref bool) (pp [2]value.Pointer) {
if deref && vx.IsValid() {
vx = vx.Addr()
}
if deref && vy.IsValid() {
vy = vy.Addr()
}
switch d {
case diffUnknown, diffIdentical:
pp = [2]value.Pointer{value.PointerOf(vx), value.PointerOf(vy)}
case diffRemoved:
pp = [2]value.Pointer{value.PointerOf(vx), value.Pointer{}}
case diffInserted:
pp = [2]value.Pointer{value.Pointer{}, value.PointerOf(vy)}
}
*ps = append(*ps, pp)
return pp
}
func (ps *pointerReferences) Push(v reflect.Value) (p value.Pointer, seen bool) {
p = value.PointerOf(v)
for _, pp := range *ps {
if p == pp[0] || p == pp[1] {
return p, true
}
}
*ps = append(*ps, [2]value.Pointer{p, p})
return p, false
}
func (ps *pointerReferences) Pop() {
*ps = (*ps)[:len(*ps)-1]
}
// trunkReferences is metadata for a textNode indicating that the sub-tree
// represents the value for either pointer in a pair of references.
type trunkReferences struct{ pp [2]value.Pointer }
// trunkReference is metadata for a textNode indicating that the sub-tree
// represents the value for the given pointer reference.
type trunkReference struct{ p value.Pointer }
// leafReference is metadata for a textNode indicating that the value is
// truncated as it refers to another part of the tree (i.e., a trunk).
type leafReference struct{ p value.Pointer }
func wrapTrunkReferences(pp [2]value.Pointer, s textNode) textNode {
switch {
case pp[0].IsNil():
return &textWrap{Value: s, Metadata: trunkReference{pp[1]}}
case pp[1].IsNil():
return &textWrap{Value: s, Metadata: trunkReference{pp[0]}}
case pp[0] == pp[1]:
return &textWrap{Value: s, Metadata: trunkReference{pp[0]}}
default:
return &textWrap{Value: s, Metadata: trunkReferences{pp}}
}
}
func wrapTrunkReference(p value.Pointer, printAddress bool, s textNode) textNode {
var prefix string
if printAddress {
prefix = formatPointer(p, true)
}
return &textWrap{Prefix: prefix, Value: s, Metadata: trunkReference{p}}
}
func makeLeafReference(p value.Pointer, printAddress bool) textNode {
out := &textWrap{Prefix: "(", Value: textEllipsis, Suffix: ")"}
var prefix string
if printAddress {
prefix = formatPointer(p, true)
}
return &textWrap{Prefix: prefix, Value: out, Metadata: leafReference{p}}
}
// resolveReferences walks the textNode tree searching for any leaf reference
// metadata and resolves each against the corresponding trunk references.
// Since pointer addresses in memory are not particularly readable to the user,
// it replaces each pointer value with an arbitrary and unique reference ID.
func resolveReferences(s textNode) {
var walkNodes func(textNode, func(textNode))
walkNodes = func(s textNode, f func(textNode)) {
f(s)
switch s := s.(type) {
case *textWrap:
walkNodes(s.Value, f)
case textList:
for _, r := range s {
walkNodes(r.Value, f)
}
}
}
// Collect all trunks and leaves with reference metadata.
var trunks, leaves []*textWrap
walkNodes(s, func(s textNode) {
if s, ok := s.(*textWrap); ok {
switch s.Metadata.(type) {
case leafReference:
leaves = append(leaves, s)
case trunkReference, trunkReferences:
trunks = append(trunks, s)
}
}
})
// No leaf references to resolve.
if len(leaves) == 0 {
return
}
// Collect the set of all leaf references to resolve.
leafPtrs := make(map[value.Pointer]bool)
for _, leaf := range leaves {
leafPtrs[leaf.Metadata.(leafReference).p] = true
}
// Collect the set of trunk pointers that are always paired together.
// This allows us to assign a single ID to both pointers for brevity.
// If a pointer in a pair ever occurs by itself or as a different pair,
// then the pair is broken.
pairedTrunkPtrs := make(map[value.Pointer]value.Pointer)
unpair := func(p value.Pointer) {
if !pairedTrunkPtrs[p].IsNil() {
pairedTrunkPtrs[pairedTrunkPtrs[p]] = value.Pointer{} // invalidate other half
}
pairedTrunkPtrs[p] = value.Pointer{} // invalidate this half
}
for _, trunk := range trunks {
switch p := trunk.Metadata.(type) {
case trunkReference:
unpair(p.p) // standalone pointer cannot be part of a pair
case trunkReferences:
p0, ok0 := pairedTrunkPtrs[p.pp[0]]
p1, ok1 := pairedTrunkPtrs[p.pp[1]]
switch {
case !ok0 && !ok1:
// Register the newly seen pair.
pairedTrunkPtrs[p.pp[0]] = p.pp[1]
pairedTrunkPtrs[p.pp[1]] = p.pp[0]
case ok0 && ok1 && p0 == p.pp[1] && p1 == p.pp[0]:
// Exact pair already seen; do nothing.
default:
// Pair conflicts with some other pair; break all pairs.
unpair(p.pp[0])
unpair(p.pp[1])
}
}
}
// Correlate each pointer referenced by leaves to a unique identifier,
// and print the IDs for each trunk that matches those pointers.
var nextID uint
ptrIDs := make(map[value.Pointer]uint)
newID := func() uint {
id := nextID
nextID++
return id
}
for _, trunk := range trunks {
switch p := trunk.Metadata.(type) {
case trunkReference:
if print := leafPtrs[p.p]; print {
id, ok := ptrIDs[p.p]
if !ok {
id = newID()
ptrIDs[p.p] = id
}
trunk.Prefix = updateReferencePrefix(trunk.Prefix, formatReference(id))
}
case trunkReferences:
print0 := leafPtrs[p.pp[0]]
print1 := leafPtrs[p.pp[1]]
if print0 || print1 {
id0, ok0 := ptrIDs[p.pp[0]]
id1, ok1 := ptrIDs[p.pp[1]]
isPair := pairedTrunkPtrs[p.pp[0]] == p.pp[1] && pairedTrunkPtrs[p.pp[1]] == p.pp[0]
if isPair {
var id uint
assert(ok0 == ok1) // must be seen together or not at all
if ok0 {
assert(id0 == id1) // must have the same ID
id = id0
} else {
id = newID()
ptrIDs[p.pp[0]] = id
ptrIDs[p.pp[1]] = id
}
trunk.Prefix = updateReferencePrefix(trunk.Prefix, formatReference(id))
} else {
if print0 && !ok0 {
id0 = newID()
ptrIDs[p.pp[0]] = id0
}
if print1 && !ok1 {
id1 = newID()
ptrIDs[p.pp[1]] = id1
}
switch {
case print0 && print1:
trunk.Prefix = updateReferencePrefix(trunk.Prefix, formatReference(id0)+","+formatReference(id1))
case print0:
trunk.Prefix = updateReferencePrefix(trunk.Prefix, formatReference(id0))
case print1:
trunk.Prefix = updateReferencePrefix(trunk.Prefix, formatReference(id1))
}
}
}
}
}
// Update all leaf references with the unique identifier.
for _, leaf := range leaves {
if id, ok := ptrIDs[leaf.Metadata.(leafReference).p]; ok {
leaf.Prefix = updateReferencePrefix(leaf.Prefix, formatReference(id))
}
}
}
func formatReference(id uint) string {
return fmt.Sprintf("ref#%d", id)
}
func updateReferencePrefix(prefix, ref string) string {
if prefix == "" {
return pointerDelimPrefix + ref + pointerDelimSuffix
}
suffix := strings.TrimPrefix(prefix, pointerDelimPrefix)
return pointerDelimPrefix + ref + ": " + suffix
}

View File

@ -1,17 +1,18 @@
// Copyright 2019, The Go Authors. All rights reserved. // Copyright 2019, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file. // license that can be found in the LICENSE file.
package cmp package cmp
import ( import (
"bytes"
"fmt" "fmt"
"reflect" "reflect"
"strconv" "strconv"
"strings" "strings"
"unicode" "unicode"
"unicode/utf8"
"github.com/google/go-cmp/cmp/internal/flags"
"github.com/google/go-cmp/cmp/internal/value" "github.com/google/go-cmp/cmp/internal/value"
) )
@ -20,14 +21,22 @@ type formatValueOptions struct {
// methods like error.Error or fmt.Stringer.String. // methods like error.Error or fmt.Stringer.String.
AvoidStringer bool AvoidStringer bool
// ShallowPointers controls whether to avoid descending into pointers.
// Useful when printing map keys, where pointer comparison is performed
// on the pointer address rather than the pointed-at value.
ShallowPointers bool
// PrintAddresses controls whether to print the address of all pointers, // PrintAddresses controls whether to print the address of all pointers,
// slice elements, and maps. // slice elements, and maps.
PrintAddresses bool PrintAddresses bool
// QualifiedNames controls whether FormatType uses the fully qualified name
// (including the full package path as opposed to just the package name).
QualifiedNames bool
// VerbosityLevel controls the amount of output to produce.
// A higher value produces more output. A value of zero or lower produces
// no output (represented using an ellipsis).
// If LimitVerbosity is false, then the level is treated as infinite.
VerbosityLevel int
// LimitVerbosity specifies that formatting should respect VerbosityLevel.
LimitVerbosity bool
} }
// FormatType prints the type as if it were wrapping s. // FormatType prints the type as if it were wrapping s.
@ -44,12 +53,15 @@ func (opts formatOptions) FormatType(t reflect.Type, s textNode) textNode {
default: default:
return s return s
} }
if opts.DiffMode == diffIdentical {
return s // elide type for identical nodes
}
case elideType: case elideType:
return s return s
} }
// Determine the type label, applying special handling for unnamed types. // Determine the type label, applying special handling for unnamed types.
typeName := t.String() typeName := value.TypeString(t, opts.QualifiedNames)
if t.Name() == "" { if t.Name() == "" {
// According to Go grammar, certain type literals contain symbols that // According to Go grammar, certain type literals contain symbols that
// do not strongly bind to the next lexicographical token (e.g., *T). // do not strongly bind to the next lexicographical token (e.g., *T).
@ -57,39 +69,77 @@ func (opts formatOptions) FormatType(t reflect.Type, s textNode) textNode {
case reflect.Chan, reflect.Func, reflect.Ptr: case reflect.Chan, reflect.Func, reflect.Ptr:
typeName = "(" + typeName + ")" typeName = "(" + typeName + ")"
} }
typeName = strings.Replace(typeName, "struct {", "struct{", -1)
typeName = strings.Replace(typeName, "interface {", "interface{", -1)
} }
return &textWrap{Prefix: typeName, Value: wrapParens(s)}
}
// Avoid wrap the value in parenthesis if unnecessary. // wrapParens wraps s with a set of parenthesis, but avoids it if the
if s, ok := s.(textWrap); ok { // wrapped node itself is already surrounded by a pair of parenthesis or braces.
hasParens := strings.HasPrefix(s.Prefix, "(") && strings.HasSuffix(s.Suffix, ")") // It handles unwrapping one level of pointer-reference nodes.
hasBraces := strings.HasPrefix(s.Prefix, "{") && strings.HasSuffix(s.Suffix, "}") func wrapParens(s textNode) textNode {
var refNode *textWrap
if s2, ok := s.(*textWrap); ok {
// Unwrap a single pointer reference node.
switch s2.Metadata.(type) {
case leafReference, trunkReference, trunkReferences:
refNode = s2
if s3, ok := refNode.Value.(*textWrap); ok {
s2 = s3
}
}
// Already has delimiters that make parenthesis unnecessary.
hasParens := strings.HasPrefix(s2.Prefix, "(") && strings.HasSuffix(s2.Suffix, ")")
hasBraces := strings.HasPrefix(s2.Prefix, "{") && strings.HasSuffix(s2.Suffix, "}")
if hasParens || hasBraces { if hasParens || hasBraces {
return textWrap{typeName, s, ""} return s
} }
} }
return textWrap{typeName + "(", s, ")"} if refNode != nil {
refNode.Value = &textWrap{Prefix: "(", Value: refNode.Value, Suffix: ")"}
return s
}
return &textWrap{Prefix: "(", Value: s, Suffix: ")"}
} }
// FormatValue prints the reflect.Value, taking extra care to avoid descending // FormatValue prints the reflect.Value, taking extra care to avoid descending
// into pointers already in m. As pointers are visited, m is also updated. // into pointers already in ptrs. As pointers are visited, ptrs is also updated.
func (opts formatOptions) FormatValue(v reflect.Value, m visitedPointers) (out textNode) { func (opts formatOptions) FormatValue(v reflect.Value, parentKind reflect.Kind, ptrs *pointerReferences) (out textNode) {
if !v.IsValid() { if !v.IsValid() {
return nil return nil
} }
t := v.Type() t := v.Type()
// Check slice element for cycles.
if parentKind == reflect.Slice {
ptrRef, visited := ptrs.Push(v.Addr())
if visited {
return makeLeafReference(ptrRef, false)
}
defer ptrs.Pop()
defer func() { out = wrapTrunkReference(ptrRef, false, out) }()
}
// Check whether there is an Error or String method to call. // Check whether there is an Error or String method to call.
if !opts.AvoidStringer && v.CanInterface() { if !opts.AvoidStringer && v.CanInterface() {
// Avoid calling Error or String methods on nil receivers since many // Avoid calling Error or String methods on nil receivers since many
// implementations crash when doing so. // implementations crash when doing so.
if (t.Kind() != reflect.Ptr && t.Kind() != reflect.Interface) || !v.IsNil() { if (t.Kind() != reflect.Ptr && t.Kind() != reflect.Interface) || !v.IsNil() {
switch v := v.Interface().(type) { var prefix, strVal string
case error: func() {
return textLine("e" + formatString(v.Error())) // Swallow and ignore any panics from String or Error.
case fmt.Stringer: defer func() { recover() }()
return textLine("s" + formatString(v.String())) switch v := v.Interface().(type) {
case error:
strVal = v.Error()
prefix = "e"
case fmt.Stringer:
strVal = v.String()
prefix = "s"
}
}()
if prefix != "" {
return opts.formatString(prefix, strVal)
} }
} }
} }
@ -102,94 +152,140 @@ func (opts formatOptions) FormatValue(v reflect.Value, m visitedPointers) (out t
} }
}() }()
var ptr string
switch t.Kind() { switch t.Kind() {
case reflect.Bool: case reflect.Bool:
return textLine(fmt.Sprint(v.Bool())) return textLine(fmt.Sprint(v.Bool()))
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return textLine(fmt.Sprint(v.Int())) return textLine(fmt.Sprint(v.Int()))
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64:
// Unnamed uints are usually bytes or words, so use hexadecimal. return textLine(fmt.Sprint(v.Uint()))
if t.PkgPath() == "" || t.Kind() == reflect.Uintptr { case reflect.Uint8:
if parentKind == reflect.Slice || parentKind == reflect.Array {
return textLine(formatHex(v.Uint())) return textLine(formatHex(v.Uint()))
} }
return textLine(fmt.Sprint(v.Uint())) return textLine(fmt.Sprint(v.Uint()))
case reflect.Uintptr:
return textLine(formatHex(v.Uint()))
case reflect.Float32, reflect.Float64: case reflect.Float32, reflect.Float64:
return textLine(fmt.Sprint(v.Float())) return textLine(fmt.Sprint(v.Float()))
case reflect.Complex64, reflect.Complex128: case reflect.Complex64, reflect.Complex128:
return textLine(fmt.Sprint(v.Complex())) return textLine(fmt.Sprint(v.Complex()))
case reflect.String: case reflect.String:
return textLine(formatString(v.String())) return opts.formatString("", v.String())
case reflect.UnsafePointer, reflect.Chan, reflect.Func: case reflect.UnsafePointer, reflect.Chan, reflect.Func:
return textLine(formatPointer(v)) return textLine(formatPointer(value.PointerOf(v), true))
case reflect.Struct: case reflect.Struct:
var list textList var list textList
v := makeAddressable(v) // needed for retrieveUnexportedField
maxLen := v.NumField()
if opts.LimitVerbosity {
maxLen = ((1 << opts.verbosity()) >> 1) << 2 // 0, 4, 8, 16, 32, etc...
opts.VerbosityLevel--
}
for i := 0; i < v.NumField(); i++ { for i := 0; i < v.NumField(); i++ {
vv := v.Field(i) vv := v.Field(i)
if value.IsZero(vv) { if value.IsZero(vv) {
continue // Elide fields with zero values continue // Elide fields with zero values
} }
s := opts.WithTypeMode(autoType).FormatValue(vv, m) if len(list) == maxLen {
list = append(list, textRecord{Key: t.Field(i).Name, Value: s}) list.AppendEllipsis(diffStats{})
break
}
sf := t.Field(i)
if supportExporters && !isExported(sf.Name) {
vv = retrieveUnexportedField(v, sf, true)
}
s := opts.WithTypeMode(autoType).FormatValue(vv, t.Kind(), ptrs)
list = append(list, textRecord{Key: sf.Name, Value: s})
} }
return textWrap{"{", list, "}"} return &textWrap{Prefix: "{", Value: list, Suffix: "}"}
case reflect.Slice: case reflect.Slice:
if v.IsNil() { if v.IsNil() {
return textNil return textNil
} }
if opts.PrintAddresses {
ptr = formatPointer(v) // Check whether this is a []byte of text data.
if t.Elem() == reflect.TypeOf(byte(0)) {
b := v.Bytes()
isPrintSpace := func(r rune) bool { return unicode.IsPrint(r) && unicode.IsSpace(r) }
if len(b) > 0 && utf8.Valid(b) && len(bytes.TrimFunc(b, isPrintSpace)) == 0 {
out = opts.formatString("", string(b))
return opts.WithTypeMode(emitType).FormatType(t, out)
}
} }
fallthrough fallthrough
case reflect.Array: case reflect.Array:
maxLen := v.Len()
if opts.LimitVerbosity {
maxLen = ((1 << opts.verbosity()) >> 1) << 2 // 0, 4, 8, 16, 32, etc...
opts.VerbosityLevel--
}
var list textList var list textList
for i := 0; i < v.Len(); i++ { for i := 0; i < v.Len(); i++ {
vi := v.Index(i) if len(list) == maxLen {
if vi.CanAddr() { // Check for cyclic elements list.AppendEllipsis(diffStats{})
p := vi.Addr() break
if m.Visit(p) {
var out textNode
out = textLine(formatPointer(p))
out = opts.WithTypeMode(emitType).FormatType(p.Type(), out)
out = textWrap{"*", out, ""}
list = append(list, textRecord{Value: out})
continue
}
} }
s := opts.WithTypeMode(elideType).FormatValue(vi, m) s := opts.WithTypeMode(elideType).FormatValue(v.Index(i), t.Kind(), ptrs)
list = append(list, textRecord{Value: s}) list = append(list, textRecord{Value: s})
} }
return textWrap{ptr + "{", list, "}"}
out = &textWrap{Prefix: "{", Value: list, Suffix: "}"}
if t.Kind() == reflect.Slice && opts.PrintAddresses {
header := fmt.Sprintf("ptr:%v, len:%d, cap:%d", formatPointer(value.PointerOf(v), false), v.Len(), v.Cap())
out = &textWrap{Prefix: pointerDelimPrefix + header + pointerDelimSuffix, Value: out}
}
return out
case reflect.Map: case reflect.Map:
if v.IsNil() { if v.IsNil() {
return textNil return textNil
} }
if m.Visit(v) {
return textLine(formatPointer(v))
}
// Check pointer for cycles.
ptrRef, visited := ptrs.Push(v)
if visited {
return makeLeafReference(ptrRef, opts.PrintAddresses)
}
defer ptrs.Pop()
maxLen := v.Len()
if opts.LimitVerbosity {
maxLen = ((1 << opts.verbosity()) >> 1) << 2 // 0, 4, 8, 16, 32, etc...
opts.VerbosityLevel--
}
var list textList var list textList
for _, k := range value.SortKeys(v.MapKeys()) { for _, k := range value.SortKeys(v.MapKeys()) {
sk := formatMapKey(k) if len(list) == maxLen {
sv := opts.WithTypeMode(elideType).FormatValue(v.MapIndex(k), m) list.AppendEllipsis(diffStats{})
break
}
sk := formatMapKey(k, false, ptrs)
sv := opts.WithTypeMode(elideType).FormatValue(v.MapIndex(k), t.Kind(), ptrs)
list = append(list, textRecord{Key: sk, Value: sv}) list = append(list, textRecord{Key: sk, Value: sv})
} }
if opts.PrintAddresses {
ptr = formatPointer(v) out = &textWrap{Prefix: "{", Value: list, Suffix: "}"}
} out = wrapTrunkReference(ptrRef, opts.PrintAddresses, out)
return textWrap{ptr + "{", list, "}"} return out
case reflect.Ptr: case reflect.Ptr:
if v.IsNil() { if v.IsNil() {
return textNil return textNil
} }
if m.Visit(v) || opts.ShallowPointers {
return textLine(formatPointer(v)) // Check pointer for cycles.
} ptrRef, visited := ptrs.Push(v)
if opts.PrintAddresses { if visited {
ptr = formatPointer(v) out = makeLeafReference(ptrRef, opts.PrintAddresses)
return &textWrap{Prefix: "&", Value: out}
} }
defer ptrs.Pop()
skipType = true // Let the underlying value print the type instead skipType = true // Let the underlying value print the type instead
return textWrap{"&" + ptr, opts.FormatValue(v.Elem(), m), ""} out = opts.FormatValue(v.Elem(), t.Kind(), ptrs)
out = wrapTrunkReference(ptrRef, opts.PrintAddresses, out)
out = &textWrap{Prefix: "&", Value: out}
return out
case reflect.Interface: case reflect.Interface:
if v.IsNil() { if v.IsNil() {
return textNil return textNil
@ -197,19 +293,67 @@ func (opts formatOptions) FormatValue(v reflect.Value, m visitedPointers) (out t
// Interfaces accept different concrete types, // Interfaces accept different concrete types,
// so configure the underlying value to explicitly print the type. // so configure the underlying value to explicitly print the type.
skipType = true // Print the concrete type instead skipType = true // Print the concrete type instead
return opts.WithTypeMode(emitType).FormatValue(v.Elem(), m) return opts.WithTypeMode(emitType).FormatValue(v.Elem(), t.Kind(), ptrs)
default: default:
panic(fmt.Sprintf("%v kind not handled", v.Kind())) panic(fmt.Sprintf("%v kind not handled", v.Kind()))
} }
} }
func (opts formatOptions) formatString(prefix, s string) textNode {
maxLen := len(s)
maxLines := strings.Count(s, "\n") + 1
if opts.LimitVerbosity {
maxLen = (1 << opts.verbosity()) << 5 // 32, 64, 128, 256, etc...
maxLines = (1 << opts.verbosity()) << 2 // 4, 8, 16, 32, 64, etc...
}
// For multiline strings, use the triple-quote syntax,
// but only use it when printing removed or inserted nodes since
// we only want the extra verbosity for those cases.
lines := strings.Split(strings.TrimSuffix(s, "\n"), "\n")
isTripleQuoted := len(lines) >= 4 && (opts.DiffMode == '-' || opts.DiffMode == '+')
for i := 0; i < len(lines) && isTripleQuoted; i++ {
lines[i] = strings.TrimPrefix(strings.TrimSuffix(lines[i], "\r"), "\r") // trim leading/trailing carriage returns for legacy Windows endline support
isPrintable := func(r rune) bool {
return unicode.IsPrint(r) || r == '\t' // specially treat tab as printable
}
line := lines[i]
isTripleQuoted = !strings.HasPrefix(strings.TrimPrefix(line, prefix), `"""`) && !strings.HasPrefix(line, "...") && strings.TrimFunc(line, isPrintable) == "" && len(line) <= maxLen
}
if isTripleQuoted {
var list textList
list = append(list, textRecord{Diff: opts.DiffMode, Value: textLine(prefix + `"""`), ElideComma: true})
for i, line := range lines {
if numElided := len(lines) - i; i == maxLines-1 && numElided > 1 {
comment := commentString(fmt.Sprintf("%d elided lines", numElided))
list = append(list, textRecord{Diff: opts.DiffMode, Value: textEllipsis, ElideComma: true, Comment: comment})
break
}
list = append(list, textRecord{Diff: opts.DiffMode, Value: textLine(line), ElideComma: true})
}
list = append(list, textRecord{Diff: opts.DiffMode, Value: textLine(prefix + `"""`), ElideComma: true})
return &textWrap{Prefix: "(", Value: list, Suffix: ")"}
}
// Format the string as a single-line quoted string.
if len(s) > maxLen+len(textEllipsis) {
return textLine(prefix + formatString(s[:maxLen]) + string(textEllipsis))
}
return textLine(prefix + formatString(s))
}
// formatMapKey formats v as if it were a map key. // formatMapKey formats v as if it were a map key.
// The result is guaranteed to be a single line. // The result is guaranteed to be a single line.
func formatMapKey(v reflect.Value) string { func formatMapKey(v reflect.Value, disambiguate bool, ptrs *pointerReferences) string {
var opts formatOptions var opts formatOptions
opts.DiffMode = diffIdentical
opts.TypeMode = elideType opts.TypeMode = elideType
opts.ShallowPointers = true opts.PrintAddresses = disambiguate
s := opts.FormatValue(v, visitedPointers{}).String() opts.AvoidStringer = disambiguate
opts.QualifiedNames = disambiguate
opts.VerbosityLevel = maxVerbosityPreset
opts.LimitVerbosity = true
s := opts.FormatValue(v, reflect.Map, ptrs).String()
return strings.TrimSpace(s) return strings.TrimSpace(s)
} }
@ -227,7 +371,7 @@ func formatString(s string) string {
rawInvalid := func(r rune) bool { rawInvalid := func(r rune) bool {
return r == '`' || r == '\n' || !(unicode.IsPrint(r) || r == '\t') return r == '`' || r == '\n' || !(unicode.IsPrint(r) || r == '\t')
} }
if strings.IndexFunc(s, rawInvalid) < 0 { if utf8.ValidString(s) && strings.IndexFunc(s, rawInvalid) < 0 {
return "`" + s + "`" return "`" + s + "`"
} }
return qs return qs
@ -256,23 +400,3 @@ func formatHex(u uint64) string {
} }
return fmt.Sprintf(f, u) return fmt.Sprintf(f, u)
} }
// formatPointer prints the address of the pointer.
func formatPointer(v reflect.Value) string {
p := v.Pointer()
if flags.Deterministic {
p = 0xdeadf00f // Only used for stable testing purposes
}
return fmt.Sprintf("⟪0x%x⟫", p)
}
type visitedPointers map[value.Pointer]struct{}
// Visit inserts pointer v into the visited map and reports whether it had
// already been visited before.
func (m visitedPointers) Visit(v reflect.Value) bool {
p := value.PointerOf(v)
_, visited := m[p]
m[p] = struct{}{}
return visited
}

View File

@ -1,6 +1,6 @@
// Copyright 2019, The Go Authors. All rights reserved. // Copyright 2019, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file. // license that can be found in the LICENSE file.
package cmp package cmp
@ -8,6 +8,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"reflect" "reflect"
"strconv"
"strings" "strings"
"unicode" "unicode"
"unicode/utf8" "unicode/utf8"
@ -23,11 +24,25 @@ func (opts formatOptions) CanFormatDiffSlice(v *valueNode) bool {
return false // Must be formatting in diff mode return false // Must be formatting in diff mode
case v.NumDiff == 0: case v.NumDiff == 0:
return false // No differences detected return false // No differences detected
case v.NumIgnored+v.NumCompared+v.NumTransformed > 0:
// TODO: Handle the case where someone uses bytes.Equal on a large slice.
return false // Some custom option was used to determined equality
case !v.ValueX.IsValid() || !v.ValueY.IsValid(): case !v.ValueX.IsValid() || !v.ValueY.IsValid():
return false // Both values must be valid return false // Both values must be valid
case v.Type.Kind() == reflect.Slice && (v.ValueX.Len() == 0 || v.ValueY.Len() == 0):
return false // Both slice values have to be non-empty
case v.NumIgnored > 0:
return false // Some ignore option was used
case v.NumTransformed > 0:
return false // Some transform option was used
case v.NumCompared > 1:
return false // More than one comparison was used
case v.NumCompared == 1 && v.Type.Name() != "":
// The need for cmp to check applicability of options on every element
// in a slice is a significant performance detriment for large []byte.
// The workaround is to specify Comparer(bytes.Equal),
// which enables cmp to compare []byte more efficiently.
// If they differ, we still want to provide batched diffing.
// The logic disallows named types since they tend to have their own
// String method, with nicer formatting than what this provides.
return false
} }
switch t := v.Type; t.Kind() { switch t := v.Type; t.Kind() {
@ -82,7 +97,7 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode {
} }
if isText || isBinary { if isText || isBinary {
var numLines, lastLineIdx, maxLineLen int var numLines, lastLineIdx, maxLineLen int
isBinary = false isBinary = !utf8.ValidString(sx) || !utf8.ValidString(sy)
for i, r := range sx + sy { for i, r := range sx + sy {
if !(unicode.IsPrint(r) || unicode.IsSpace(r)) || r == utf8.RuneError { if !(unicode.IsPrint(r) || unicode.IsSpace(r)) || r == utf8.RuneError {
isBinary = true isBinary = true
@ -97,7 +112,7 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode {
} }
} }
isText = !isBinary isText = !isBinary
isLinedText = isText && numLines >= 4 && maxLineLen <= 256 isLinedText = isText && numLines >= 4 && maxLineLen <= 1024
} }
// Format the string into printable records. // Format the string into printable records.
@ -117,6 +132,83 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode {
}, },
) )
delim = "\n" delim = "\n"
// If possible, use a custom triple-quote (""") syntax for printing
// differences in a string literal. This format is more readable,
// but has edge-cases where differences are visually indistinguishable.
// This format is avoided under the following conditions:
// • A line starts with `"""`
// • A line starts with "..."
// • A line contains non-printable characters
// • Adjacent different lines differ only by whitespace
//
// For example:
// """
// ... // 3 identical lines
// foo
// bar
// - baz
// + BAZ
// """
isTripleQuoted := true
prevRemoveLines := map[string]bool{}
prevInsertLines := map[string]bool{}
var list2 textList
list2 = append(list2, textRecord{Value: textLine(`"""`), ElideComma: true})
for _, r := range list {
if !r.Value.Equal(textEllipsis) {
line, _ := strconv.Unquote(string(r.Value.(textLine)))
line = strings.TrimPrefix(strings.TrimSuffix(line, "\r"), "\r") // trim leading/trailing carriage returns for legacy Windows endline support
normLine := strings.Map(func(r rune) rune {
if unicode.IsSpace(r) {
return -1 // drop whitespace to avoid visually indistinguishable output
}
return r
}, line)
isPrintable := func(r rune) bool {
return unicode.IsPrint(r) || r == '\t' // specially treat tab as printable
}
isTripleQuoted = !strings.HasPrefix(line, `"""`) && !strings.HasPrefix(line, "...") && strings.TrimFunc(line, isPrintable) == ""
switch r.Diff {
case diffRemoved:
isTripleQuoted = isTripleQuoted && !prevInsertLines[normLine]
prevRemoveLines[normLine] = true
case diffInserted:
isTripleQuoted = isTripleQuoted && !prevRemoveLines[normLine]
prevInsertLines[normLine] = true
}
if !isTripleQuoted {
break
}
r.Value = textLine(line)
r.ElideComma = true
}
if !(r.Diff == diffRemoved || r.Diff == diffInserted) { // start a new non-adjacent difference group
prevRemoveLines = map[string]bool{}
prevInsertLines = map[string]bool{}
}
list2 = append(list2, r)
}
if r := list2[len(list2)-1]; r.Diff == diffIdentical && len(r.Value.(textLine)) == 0 {
list2 = list2[:len(list2)-1] // elide single empty line at the end
}
list2 = append(list2, textRecord{Value: textLine(`"""`), ElideComma: true})
if isTripleQuoted {
var out textNode = &textWrap{Prefix: "(", Value: list2, Suffix: ")"}
switch t.Kind() {
case reflect.String:
if t != reflect.TypeOf(string("")) {
out = opts.FormatType(t, out)
}
case reflect.Slice:
// Always emit type for slices since the triple-quote syntax
// looks like a string (not a slice).
opts = opts.WithTypeMode(emitType)
out = opts.FormatType(t, out)
}
return out
}
// If the text appears to be single-lined text, // If the text appears to be single-lined text,
// then perform differencing in approximately fixed-sized chunks. // then perform differencing in approximately fixed-sized chunks.
// The output is printed as quoted strings. // The output is printed as quoted strings.
@ -129,6 +221,7 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode {
}, },
) )
delim = "" delim = ""
// If the text appears to be binary data, // If the text appears to be binary data,
// then perform differencing in approximately fixed-sized chunks. // then perform differencing in approximately fixed-sized chunks.
// The output is inspired by hexdump. // The output is inspired by hexdump.
@ -145,6 +238,7 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode {
return textRecord{Diff: d, Value: textLine(s), Comment: comment} return textRecord{Diff: d, Value: textLine(s), Comment: comment}
}, },
) )
// For all other slices of primitive types, // For all other slices of primitive types,
// then perform differencing in approximately fixed-sized chunks. // then perform differencing in approximately fixed-sized chunks.
// The size of each chunk depends on the width of the element kind. // The size of each chunk depends on the width of the element kind.
@ -172,7 +266,9 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode {
switch t.Elem().Kind() { switch t.Elem().Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
ss = append(ss, fmt.Sprint(v.Index(i).Int())) ss = append(ss, fmt.Sprint(v.Index(i).Int()))
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64:
ss = append(ss, fmt.Sprint(v.Index(i).Uint()))
case reflect.Uint8, reflect.Uintptr:
ss = append(ss, formatHex(v.Index(i).Uint())) ss = append(ss, formatHex(v.Index(i).Uint()))
case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128: case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
ss = append(ss, fmt.Sprint(v.Index(i).Interface())) ss = append(ss, fmt.Sprint(v.Index(i).Interface()))
@ -185,7 +281,7 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode {
} }
// Wrap the output with appropriate type information. // Wrap the output with appropriate type information.
var out textNode = textWrap{"{", list, "}"} var out textNode = &textWrap{Prefix: "{", Value: list, Suffix: "}"}
if !isText { if !isText {
// The "{...}" byte-sequence literal is not valid Go syntax for strings. // The "{...}" byte-sequence literal is not valid Go syntax for strings.
// Emit the type for extra clarity (e.g. "string{...}"). // Emit the type for extra clarity (e.g. "string{...}").
@ -196,12 +292,12 @@ func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode {
} }
switch t.Kind() { switch t.Kind() {
case reflect.String: case reflect.String:
out = textWrap{"strings.Join(", out, fmt.Sprintf(", %q)", delim)} out = &textWrap{Prefix: "strings.Join(", Value: out, Suffix: fmt.Sprintf(", %q)", delim)}
if t != reflect.TypeOf(string("")) { if t != reflect.TypeOf(string("")) {
out = opts.FormatType(t, out) out = opts.FormatType(t, out)
} }
case reflect.Slice: case reflect.Slice:
out = textWrap{"bytes.Join(", out, fmt.Sprintf(", %q)", delim)} out = &textWrap{Prefix: "bytes.Join(", Value: out, Suffix: fmt.Sprintf(", %q)", delim)}
if t != reflect.TypeOf([]byte(nil)) { if t != reflect.TypeOf([]byte(nil)) {
out = opts.FormatType(t, out) out = opts.FormatType(t, out)
} }
@ -242,9 +338,22 @@ func (opts formatOptions) formatDiffSlice(
return n0 - v.Len() return n0 - v.Len()
} }
var numDiffs int
maxLen := -1
if opts.LimitVerbosity {
maxLen = (1 << opts.verbosity()) << 2 // 4, 8, 16, 32, 64, etc...
opts.VerbosityLevel--
}
groups := coalesceAdjacentEdits(name, es) groups := coalesceAdjacentEdits(name, es)
groups = coalesceInterveningIdentical(groups, chunkSize/4) groups = coalesceInterveningIdentical(groups, chunkSize/4)
maxGroup := diffStats{Name: name}
for i, ds := range groups { for i, ds := range groups {
if maxLen >= 0 && numDiffs >= maxLen {
maxGroup = maxGroup.Append(ds)
continue
}
// Print equal. // Print equal.
if ds.NumDiff() == 0 { if ds.NumDiff() == 0 {
// Compute the number of leading and trailing equal bytes to print. // Compute the number of leading and trailing equal bytes to print.
@ -273,12 +382,18 @@ func (opts formatOptions) formatDiffSlice(
} }
// Print unequal. // Print unequal.
len0 := len(list)
nx := appendChunks(vx.Slice(0, ds.NumIdentical+ds.NumRemoved+ds.NumModified), diffRemoved) nx := appendChunks(vx.Slice(0, ds.NumIdentical+ds.NumRemoved+ds.NumModified), diffRemoved)
vx = vx.Slice(nx, vx.Len()) vx = vx.Slice(nx, vx.Len())
ny := appendChunks(vy.Slice(0, ds.NumIdentical+ds.NumInserted+ds.NumModified), diffInserted) ny := appendChunks(vy.Slice(0, ds.NumIdentical+ds.NumInserted+ds.NumModified), diffInserted)
vy = vy.Slice(ny, vy.Len()) vy = vy.Slice(ny, vy.Len())
numDiffs += len(list) - len0
}
if maxGroup.IsZero() {
assert(vx.Len() == 0 && vy.Len() == 0)
} else {
list.AppendEllipsis(maxGroup)
} }
assert(vx.Len() == 0 && vy.Len() == 0)
return list return list
} }

View File

@ -1,6 +1,6 @@
// Copyright 2019, The Go Authors. All rights reserved. // Copyright 2019, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file. // license that can be found in the LICENSE file.
package cmp package cmp
@ -10,12 +10,15 @@ import (
"math/rand" "math/rand"
"strings" "strings"
"time" "time"
"unicode/utf8"
"github.com/google/go-cmp/cmp/internal/flags" "github.com/google/go-cmp/cmp/internal/flags"
) )
var randBool = rand.New(rand.NewSource(time.Now().Unix())).Intn(2) == 0 var randBool = rand.New(rand.NewSource(time.Now().Unix())).Intn(2) == 0
const maxColumnLength = 80
type indentMode int type indentMode int
func (n indentMode) appendIndent(b []byte, d diffMode) []byte { func (n indentMode) appendIndent(b []byte, d diffMode) []byte {
@ -91,21 +94,22 @@ type textNode interface {
// textWrap is a wrapper that concatenates a prefix and/or a suffix // textWrap is a wrapper that concatenates a prefix and/or a suffix
// to the underlying node. // to the underlying node.
type textWrap struct { type textWrap struct {
Prefix string // e.g., "bytes.Buffer{" Prefix string // e.g., "bytes.Buffer{"
Value textNode // textWrap | textList | textLine Value textNode // textWrap | textList | textLine
Suffix string // e.g., "}" Suffix string // e.g., "}"
Metadata interface{} // arbitrary metadata; has no effect on formatting
} }
func (s textWrap) Len() int { func (s *textWrap) Len() int {
return len(s.Prefix) + s.Value.Len() + len(s.Suffix) return len(s.Prefix) + s.Value.Len() + len(s.Suffix)
} }
func (s1 textWrap) Equal(s2 textNode) bool { func (s1 *textWrap) Equal(s2 textNode) bool {
if s2, ok := s2.(textWrap); ok { if s2, ok := s2.(*textWrap); ok {
return s1.Prefix == s2.Prefix && s1.Value.Equal(s2.Value) && s1.Suffix == s2.Suffix return s1.Prefix == s2.Prefix && s1.Value.Equal(s2.Value) && s1.Suffix == s2.Suffix
} }
return false return false
} }
func (s textWrap) String() string { func (s *textWrap) String() string {
var d diffMode var d diffMode
var n indentMode var n indentMode
_, s2 := s.formatCompactTo(nil, d) _, s2 := s.formatCompactTo(nil, d)
@ -114,7 +118,7 @@ func (s textWrap) String() string {
b = append(b, '\n') // Trailing newline b = append(b, '\n') // Trailing newline
return string(b) return string(b)
} }
func (s textWrap) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) { func (s *textWrap) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) {
n0 := len(b) // Original buffer length n0 := len(b) // Original buffer length
b = append(b, s.Prefix...) b = append(b, s.Prefix...)
b, s.Value = s.Value.formatCompactTo(b, d) b, s.Value = s.Value.formatCompactTo(b, d)
@ -124,7 +128,7 @@ func (s textWrap) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) {
} }
return b, s return b, s
} }
func (s textWrap) formatExpandedTo(b []byte, d diffMode, n indentMode) []byte { func (s *textWrap) formatExpandedTo(b []byte, d diffMode, n indentMode) []byte {
b = append(b, s.Prefix...) b = append(b, s.Prefix...)
b = s.Value.formatExpandedTo(b, d, n) b = s.Value.formatExpandedTo(b, d, n)
b = append(b, s.Suffix...) b = append(b, s.Suffix...)
@ -136,22 +140,23 @@ func (s textWrap) formatExpandedTo(b []byte, d diffMode, n indentMode) []byte {
// of the textList.formatCompactTo method. // of the textList.formatCompactTo method.
type textList []textRecord type textList []textRecord
type textRecord struct { type textRecord struct {
Diff diffMode // e.g., 0 or '-' or '+' Diff diffMode // e.g., 0 or '-' or '+'
Key string // e.g., "MyField" Key string // e.g., "MyField"
Value textNode // textWrap | textLine Value textNode // textWrap | textLine
Comment fmt.Stringer // e.g., "6 identical fields" ElideComma bool // avoid trailing comma
Comment fmt.Stringer // e.g., "6 identical fields"
} }
// AppendEllipsis appends a new ellipsis node to the list if none already // AppendEllipsis appends a new ellipsis node to the list if none already
// exists at the end. If cs is non-zero it coalesces the statistics with the // exists at the end. If cs is non-zero it coalesces the statistics with the
// previous diffStats. // previous diffStats.
func (s *textList) AppendEllipsis(ds diffStats) { func (s *textList) AppendEllipsis(ds diffStats) {
hasStats := ds != diffStats{} hasStats := !ds.IsZero()
if len(*s) == 0 || !(*s)[len(*s)-1].Value.Equal(textEllipsis) { if len(*s) == 0 || !(*s)[len(*s)-1].Value.Equal(textEllipsis) {
if hasStats { if hasStats {
*s = append(*s, textRecord{Value: textEllipsis, Comment: ds}) *s = append(*s, textRecord{Value: textEllipsis, ElideComma: true, Comment: ds})
} else { } else {
*s = append(*s, textRecord{Value: textEllipsis}) *s = append(*s, textRecord{Value: textEllipsis, ElideComma: true})
} }
return return
} }
@ -191,7 +196,7 @@ func (s1 textList) Equal(s2 textNode) bool {
} }
func (s textList) String() string { func (s textList) String() string {
return textWrap{"{", s, "}"}.String() return (&textWrap{Prefix: "{", Value: s, Suffix: "}"}).String()
} }
func (s textList) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) { func (s textList) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) {
@ -221,7 +226,7 @@ func (s textList) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) {
} }
// Force multi-lined output when printing a removed/inserted node that // Force multi-lined output when printing a removed/inserted node that
// is sufficiently long. // is sufficiently long.
if (d == diffInserted || d == diffRemoved) && len(b[n0:]) > 80 { if (d == diffInserted || d == diffRemoved) && len(b[n0:]) > maxColumnLength {
multiLine = true multiLine = true
} }
if !multiLine { if !multiLine {
@ -236,16 +241,50 @@ func (s textList) formatExpandedTo(b []byte, d diffMode, n indentMode) []byte {
_, isLine := r.Value.(textLine) _, isLine := r.Value.(textLine)
return r.Key == "" || !isLine return r.Key == "" || !isLine
}, },
func(r textRecord) int { return len(r.Key) }, func(r textRecord) int { return utf8.RuneCountInString(r.Key) },
) )
alignValueLens := s.alignLens( alignValueLens := s.alignLens(
func(r textRecord) bool { func(r textRecord) bool {
_, isLine := r.Value.(textLine) _, isLine := r.Value.(textLine)
return !isLine || r.Value.Equal(textEllipsis) || r.Comment == nil return !isLine || r.Value.Equal(textEllipsis) || r.Comment == nil
}, },
func(r textRecord) int { return len(r.Value.(textLine)) }, func(r textRecord) int { return utf8.RuneCount(r.Value.(textLine)) },
) )
// Format lists of simple lists in a batched form.
// If the list is sequence of only textLine values,
// then batch multiple values on a single line.
var isSimple bool
for _, r := range s {
_, isLine := r.Value.(textLine)
isSimple = r.Diff == 0 && r.Key == "" && isLine && r.Comment == nil
if !isSimple {
break
}
}
if isSimple {
n++
var batch []byte
emitBatch := func() {
if len(batch) > 0 {
b = n.appendIndent(append(b, '\n'), d)
b = append(b, bytes.TrimRight(batch, " ")...)
batch = batch[:0]
}
}
for _, r := range s {
line := r.Value.(textLine)
if len(batch)+len(line)+len(", ") > maxColumnLength {
emitBatch()
}
batch = append(batch, line...)
batch = append(batch, ", "...)
}
emitBatch()
n--
return n.appendIndent(append(b, '\n'), d)
}
// Format the list as a multi-lined output. // Format the list as a multi-lined output.
n++ n++
for i, r := range s { for i, r := range s {
@ -256,7 +295,7 @@ func (s textList) formatExpandedTo(b []byte, d diffMode, n indentMode) []byte {
b = alignKeyLens[i].appendChar(b, ' ') b = alignKeyLens[i].appendChar(b, ' ')
b = r.Value.formatExpandedTo(b, d|r.Diff, n) b = r.Value.formatExpandedTo(b, d|r.Diff, n)
if !r.Value.Equal(textEllipsis) { if !r.ElideComma {
b = append(b, ',') b = append(b, ',')
} }
b = alignValueLens[i].appendChar(b, ' ') b = alignValueLens[i].appendChar(b, ' ')
@ -332,6 +371,11 @@ type diffStats struct {
NumModified int NumModified int
} }
func (s diffStats) IsZero() bool {
s.Name = ""
return s == diffStats{}
}
func (s diffStats) NumDiff() int { func (s diffStats) NumDiff() int {
return s.NumRemoved + s.NumInserted + s.NumModified return s.NumRemoved + s.NumInserted + s.NumModified
} }

View File

@ -1,6 +1,6 @@
// Copyright 2019, The Go Authors. All rights reserved. // Copyright 2019, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file. // license that can be found in the LICENSE file.
package cmp package cmp

View File

@ -7,6 +7,7 @@ go_library(
"diffmatchpatch.go", "diffmatchpatch.go",
"match.go", "match.go",
"mathutil.go", "mathutil.go",
"operation_string.go",
"patch.go", "patch.go",
"stringutil.go", "stringutil.go",
], ],

View File

@ -25,6 +25,8 @@ import (
// Operation defines the operation of a diff item. // Operation defines the operation of a diff item.
type Operation int8 type Operation int8
//go:generate stringer -type=Operation -trimprefix=Diff
const ( const (
// DiffDelete item represents a delete diff. // DiffDelete item represents a delete diff.
DiffDelete Operation = -1 DiffDelete Operation = -1
@ -40,8 +42,41 @@ type Diff struct {
Text string Text string
} }
// splice removes amount elements from slice at index index, replacing them with elements.
func splice(slice []Diff, index int, amount int, elements ...Diff) []Diff { func splice(slice []Diff, index int, amount int, elements ...Diff) []Diff {
return append(slice[:index], append(elements, slice[index+amount:]...)...) if len(elements) == amount {
// Easy case: overwrite the relevant items.
copy(slice[index:], elements)
return slice
}
if len(elements) < amount {
// Fewer new items than old.
// Copy in the new items.
copy(slice[index:], elements)
// Shift the remaining items left.
copy(slice[index+len(elements):], slice[index+amount:])
// Calculate the new end of the slice.
end := len(slice) - amount + len(elements)
// Zero stranded elements at end so that they can be garbage collected.
tail := slice[end:]
for i := range tail {
tail[i] = Diff{}
}
return slice[:end]
}
// More new items than old.
// Make room in slice for new elements.
// There's probably an even more efficient way to do this,
// but this is simple and clear.
need := len(slice) - amount + len(elements)
for len(slice) < need {
slice = append(slice, Diff{})
}
// Shift slice elements right to make room for new elements.
copy(slice[index+len(elements):], slice[index+amount:])
// Copy in new elements.
copy(slice[index:], elements)
return slice
} }
// DiffMain finds the differences between two texts. // DiffMain finds the differences between two texts.
@ -145,7 +180,10 @@ func (dmp *DiffMatchPatch) diffCompute(text1, text2 []rune, checklines bool, dea
diffsA := dmp.diffMainRunes(text1A, text2A, checklines, deadline) diffsA := dmp.diffMainRunes(text1A, text2A, checklines, deadline)
diffsB := dmp.diffMainRunes(text1B, text2B, checklines, deadline) diffsB := dmp.diffMainRunes(text1B, text2B, checklines, deadline)
// Merge the results. // Merge the results.
return append(diffsA, append([]Diff{Diff{DiffEqual, string(midCommon)}}, diffsB...)...) diffs := diffsA
diffs = append(diffs, Diff{DiffEqual, string(midCommon)})
diffs = append(diffs, diffsB...)
return diffs
} else if checklines && len(text1) > 100 && len(text2) > 100 { } else if checklines && len(text1) > 100 && len(text2) > 100 {
return dmp.diffLineMode(text1, text2, deadline) return dmp.diffLineMode(text1, text2, deadline)
} }
@ -247,7 +285,7 @@ func (dmp *DiffMatchPatch) diffBisect(runes1, runes2 []rune, deadline time.Time)
k2end := 0 k2end := 0
for d := 0; d < maxD; d++ { for d := 0; d < maxD; d++ {
// Bail out if deadline is reached. // Bail out if deadline is reached.
if !deadline.IsZero() && time.Now().After(deadline) { if !deadline.IsZero() && d%16 == 0 && time.Now().After(deadline) {
break break
} }
@ -434,48 +472,29 @@ func (dmp *DiffMatchPatch) DiffCommonSuffix(text1, text2 string) int {
// commonPrefixLength returns the length of the common prefix of two rune slices. // commonPrefixLength returns the length of the common prefix of two rune slices.
func commonPrefixLength(text1, text2 []rune) int { func commonPrefixLength(text1, text2 []rune) int {
short, long := text1, text2 // Linear search. See comment in commonSuffixLength.
if len(short) > len(long) { n := 0
short, long = long, short for ; n < len(text1) && n < len(text2); n++ {
} if text1[n] != text2[n] {
for i, r := range short { return n
if r != long[i] {
return i
} }
} }
return len(short) return n
} }
// commonSuffixLength returns the length of the common suffix of two rune slices. // commonSuffixLength returns the length of the common suffix of two rune slices.
func commonSuffixLength(text1, text2 []rune) int { func commonSuffixLength(text1, text2 []rune) int {
n := min(len(text1), len(text2)) // Use linear search rather than the binary search discussed at https://neil.fraser.name/news/2007/10/09/.
for i := 0; i < n; i++ { // See discussion at https://github.com/sergi/go-diff/issues/54.
if text1[len(text1)-i-1] != text2[len(text2)-i-1] { i1 := len(text1)
return i i2 := len(text2)
for n := 0; ; n++ {
i1--
i2--
if i1 < 0 || i2 < 0 || text1[i1] != text2[i2] {
return n
} }
} }
return n
// TODO research and benchmark this, why is it not activated? https://github.com/sergi/go-diff/issues/54
// Binary search.
// Performance analysis: http://neil.fraser.name/news/2007/10/09/
/*
pointermin := 0
pointermax := math.Min(len(text1), len(text2))
pointermid := pointermax
pointerend := 0
for pointermin < pointermid {
if text1[len(text1)-pointermid:len(text1)-pointerend] ==
text2[len(text2)-pointermid:len(text2)-pointerend] {
pointermin = pointermid
pointerend = pointermin
} else {
pointermax = pointermid
}
pointermid = math.Floor((pointermax-pointermin)/2 + pointermin)
}
return pointermid
*/
} }
// DiffCommonOverlap determines if the suffix of one string is the prefix of another. // DiffCommonOverlap determines if the suffix of one string is the prefix of another.
@ -628,11 +647,7 @@ func (dmp *DiffMatchPatch) diffHalfMatchI(l, s []rune, i int) [][]rune {
func (dmp *DiffMatchPatch) DiffCleanupSemantic(diffs []Diff) []Diff { func (dmp *DiffMatchPatch) DiffCleanupSemantic(diffs []Diff) []Diff {
changes := false changes := false
// Stack of indices where equalities are found. // Stack of indices where equalities are found.
type equality struct { equalities := make([]int, 0, len(diffs))
data int
next *equality
}
var equalities *equality
var lastequality string var lastequality string
// Always equal to diffs[equalities[equalitiesLength - 1]][1] // Always equal to diffs[equalities[equalitiesLength - 1]][1]
@ -645,11 +660,7 @@ func (dmp *DiffMatchPatch) DiffCleanupSemantic(diffs []Diff) []Diff {
for pointer < len(diffs) { for pointer < len(diffs) {
if diffs[pointer].Type == DiffEqual { if diffs[pointer].Type == DiffEqual {
// Equality found. // Equality found.
equalities = append(equalities, pointer)
equalities = &equality{
data: pointer,
next: equalities,
}
lengthInsertions1 = lengthInsertions2 lengthInsertions1 = lengthInsertions2
lengthDeletions1 = lengthDeletions2 lengthDeletions1 = lengthDeletions2
lengthInsertions2 = 0 lengthInsertions2 = 0
@ -670,23 +681,20 @@ func (dmp *DiffMatchPatch) DiffCleanupSemantic(diffs []Diff) []Diff {
(len(lastequality) <= difference1) && (len(lastequality) <= difference1) &&
(len(lastequality) <= difference2) { (len(lastequality) <= difference2) {
// Duplicate record. // Duplicate record.
insPoint := equalities.data insPoint := equalities[len(equalities)-1]
diffs = append( diffs = splice(diffs, insPoint, 0, Diff{DiffDelete, lastequality})
diffs[:insPoint],
append([]Diff{Diff{DiffDelete, lastequality}}, diffs[insPoint:]...)...)
// Change second copy to insert. // Change second copy to insert.
diffs[insPoint+1].Type = DiffInsert diffs[insPoint+1].Type = DiffInsert
// Throw away the equality we just deleted. // Throw away the equality we just deleted.
equalities = equalities.next equalities = equalities[:len(equalities)-1]
if equalities != nil { if len(equalities) > 0 {
equalities = equalities.next equalities = equalities[:len(equalities)-1]
} }
if equalities != nil { pointer = -1
pointer = equalities.data if len(equalities) > 0 {
} else { pointer = equalities[len(equalities)-1]
pointer = -1
} }
lengthInsertions1 = 0 // Reset the counters. lengthInsertions1 = 0 // Reset the counters.
@ -724,10 +732,7 @@ func (dmp *DiffMatchPatch) DiffCleanupSemantic(diffs []Diff) []Diff {
float64(overlapLength1) >= float64(len(insertion))/2 { float64(overlapLength1) >= float64(len(insertion))/2 {
// Overlap found. Insert an equality and trim the surrounding edits. // Overlap found. Insert an equality and trim the surrounding edits.
diffs = append( diffs = splice(diffs, pointer, 0, Diff{DiffEqual, insertion[:overlapLength1]})
diffs[:pointer],
append([]Diff{Diff{DiffEqual, insertion[:overlapLength1]}}, diffs[pointer:]...)...)
diffs[pointer-1].Text = diffs[pointer-1].Text =
deletion[0 : len(deletion)-overlapLength1] deletion[0 : len(deletion)-overlapLength1]
diffs[pointer+1].Text = insertion[overlapLength1:] diffs[pointer+1].Text = insertion[overlapLength1:]
@ -738,10 +743,7 @@ func (dmp *DiffMatchPatch) DiffCleanupSemantic(diffs []Diff) []Diff {
float64(overlapLength2) >= float64(len(insertion))/2 { float64(overlapLength2) >= float64(len(insertion))/2 {
// Reverse overlap found. Insert an equality and swap and trim the surrounding edits. // Reverse overlap found. Insert an equality and swap and trim the surrounding edits.
overlap := Diff{DiffEqual, deletion[:overlapLength2]} overlap := Diff{DiffEqual, deletion[:overlapLength2]}
diffs = append( diffs = splice(diffs, pointer, 0, overlap)
diffs[:pointer],
append([]Diff{overlap}, diffs[pointer:]...)...)
diffs[pointer-1].Type = DiffInsert diffs[pointer-1].Type = DiffInsert
diffs[pointer-1].Text = insertion[0 : len(insertion)-overlapLength2] diffs[pointer-1].Text = insertion[0 : len(insertion)-overlapLength2]
diffs[pointer+1].Type = DiffDelete diffs[pointer+1].Type = DiffDelete
@ -954,8 +956,7 @@ func (dmp *DiffMatchPatch) DiffCleanupEfficiency(diffs []Diff) []Diff {
insPoint := equalities.data insPoint := equalities.data
// Duplicate record. // Duplicate record.
diffs = append(diffs[:insPoint], diffs = splice(diffs, insPoint, 0, Diff{DiffDelete, lastequality})
append([]Diff{Diff{DiffDelete, lastequality}}, diffs[insPoint:]...)...)
// Change second copy to insert. // Change second copy to insert.
diffs[insPoint+1].Type = DiffInsert diffs[insPoint+1].Type = DiffInsert
@ -1235,9 +1236,9 @@ func (dmp *DiffMatchPatch) DiffLevenshtein(diffs []Diff) int {
for _, aDiff := range diffs { for _, aDiff := range diffs {
switch aDiff.Type { switch aDiff.Type {
case DiffInsert: case DiffInsert:
insertions += len(aDiff.Text) insertions += utf8.RuneCountInString(aDiff.Text)
case DiffDelete: case DiffDelete:
deletions += len(aDiff.Text) deletions += utf8.RuneCountInString(aDiff.Text)
case DiffEqual: case DiffEqual:
// A deletion and an insertion is one substitution. // A deletion and an insertion is one substitution.
levenshtein += max(insertions, deletions) levenshtein += max(insertions, deletions)

View File

@ -0,0 +1,17 @@
// Code generated by "stringer -type=Operation -trimprefix=Diff"; DO NOT EDIT.
package diffmatchpatch
import "fmt"
const _Operation_name = "DeleteEqualInsert"
var _Operation_index = [...]uint8{0, 6, 11, 17}
func (i Operation) String() string {
i -= -1
if i < 0 || i >= Operation(len(_Operation_index)-1) {
return fmt.Sprintf("Operation(%d)", i+-1)
}
return _Operation_name[_Operation_index[i]:_Operation_index[i+1]]
}

View File

@ -97,6 +97,7 @@ package module
import ( import (
"fmt" "fmt"
"path"
"sort" "sort"
"strings" "strings"
"unicode" "unicode"
@ -224,13 +225,13 @@ func firstPathOK(r rune) bool {
} }
// pathOK reports whether r can appear in an import path element. // pathOK reports whether r can appear in an import path element.
// Paths can be ASCII letters, ASCII digits, and limited ASCII punctuation: + - . _ and ~. // Paths can be ASCII letters, ASCII digits, and limited ASCII punctuation: - . _ and ~.
// This matches what "go get" has historically recognized in import paths. // This matches what "go get" has historically recognized in import paths.
// TODO(rsc): We would like to allow Unicode letters, but that requires additional // TODO(rsc): We would like to allow Unicode letters, but that requires additional
// care in the safe encoding (see "escaped paths" above). // care in the safe encoding (see "escaped paths" above).
func pathOK(r rune) bool { func pathOK(r rune) bool {
if r < utf8.RuneSelf { if r < utf8.RuneSelf {
return r == '+' || r == '-' || r == '.' || r == '_' || r == '~' || return r == '-' || r == '.' || r == '_' || r == '~' ||
'0' <= r && r <= '9' || '0' <= r && r <= '9' ||
'A' <= r && r <= 'Z' || 'A' <= r && r <= 'Z' ||
'a' <= r && r <= 'z' 'a' <= r && r <= 'z'
@ -313,11 +314,13 @@ func CheckPath(path string) error {
// separated by slashes (U+002F). (It must not begin with nor end in a slash.) // separated by slashes (U+002F). (It must not begin with nor end in a slash.)
// //
// A valid path element is a non-empty string made up of // A valid path element is a non-empty string made up of
// ASCII letters, ASCII digits, and limited ASCII punctuation: + - . _ and ~. // ASCII letters, ASCII digits, and limited ASCII punctuation: - . _ and ~.
// It must not begin or end with a dot (U+002E), nor contain two dots in a row. // It must not begin or end with a dot (U+002E), nor contain two dots in a row.
// //
// The element prefix up to the first dot must not be a reserved file name // The element prefix up to the first dot must not be a reserved file name
// on Windows, regardless of case (CON, com1, NuL, and so on). // on Windows, regardless of case (CON, com1, NuL, and so on). The element
// must not have a suffix of a tilde followed by one or more ASCII digits
// (to exclude paths elements that look like Windows short-names).
// //
// CheckImportPath may be less restrictive in the future, but see the // CheckImportPath may be less restrictive in the future, but see the
// top-level package documentation for additional information about // top-level package documentation for additional information about
@ -402,6 +405,29 @@ func checkElem(elem string, fileName bool) error {
return fmt.Errorf("%q disallowed as path element component on Windows", short) return fmt.Errorf("%q disallowed as path element component on Windows", short)
} }
} }
if fileName {
// don't check for Windows short-names in file names. They're
// only an issue for import paths.
return nil
}
// Reject path components that look like Windows short-names.
// Those usually end in a tilde followed by one or more ASCII digits.
if tilde := strings.LastIndexByte(short, '~'); tilde >= 0 && tilde < len(short)-1 {
suffix := short[tilde+1:]
suffixIsDigits := true
for _, r := range suffix {
if r < '0' || r > '9' {
suffixIsDigits = false
break
}
}
if suffixIsDigits {
return fmt.Errorf("trailing tilde and digits in path element")
}
}
return nil return nil
} }
@ -716,3 +742,49 @@ func unescapeString(escaped string) (string, bool) {
} }
return string(buf), true return string(buf), true
} }
// MatchPrefixPatterns reports whether any path prefix of target matches one of
// the glob patterns (as defined by path.Match) in the comma-separated globs
// list. This implements the algorithm used when matching a module path to the
// GOPRIVATE environment variable, as described by 'go help module-private'.
//
// It ignores any empty or malformed patterns in the list.
func MatchPrefixPatterns(globs, target string) bool {
for globs != "" {
// Extract next non-empty glob in comma-separated list.
var glob string
if i := strings.Index(globs, ","); i >= 0 {
glob, globs = globs[:i], globs[i+1:]
} else {
glob, globs = globs, ""
}
if glob == "" {
continue
}
// A glob with N+1 path elements (N slashes) needs to be matched
// against the first N+1 path elements of target,
// which end just before the N+1'th slash.
n := strings.Count(glob, "/")
prefix := target
// Walk target, counting slashes, truncating at the N+1'th slash.
for i := 0; i < len(target); i++ {
if target[i] == '/' {
if n == 0 {
prefix = target[:i]
break
}
n--
}
}
if n > 0 {
// Not enough prefix elements.
continue
}
matched, _ := path.Match(glob, prefix)
if matched {
return true
}
}
return false
}

View File

@ -138,6 +138,9 @@ func Compare(v, w string) int {
// Max canonicalizes its arguments and then returns the version string // Max canonicalizes its arguments and then returns the version string
// that compares greater. // that compares greater.
//
// Deprecated: use Compare instead. In most cases, returning a canonicalized
// version is not expected or desired.
func Max(v, w string) string { func Max(v, w string) string {
v = Canonical(v) v = Canonical(v)
w = Canonical(w) w = Canonical(w)

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
package cpu package cpu

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
package cpu package cpu

View File

@ -3,7 +3,7 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build 386 amd64 amd64p32 // +build 386 amd64 amd64p32
// +build !gccgo // +build gc
package cpu package cpu

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -3,7 +3,7 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build 386 amd64 amd64p32 // +build 386 amd64 amd64p32
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -7,7 +7,7 @@
// (See golang.org/issue/32102) // (See golang.org/issue/32102)
// +build aix,ppc64 // +build aix,ppc64
// +build !gccgo // +build gc
package cpu package cpu

9
vendor/golang.org/x/sys/execabs/BUILD.bazel generated vendored Normal file
View File

@ -0,0 +1,9 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["execabs.go"],
importmap = "k8s.io/kops/vendor/golang.org/x/sys/execabs",
importpath = "golang.org/x/sys/execabs",
visibility = ["//visibility:public"],
)

102
vendor/golang.org/x/sys/execabs/execabs.go generated vendored Normal file
View File

@ -0,0 +1,102 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package execabs is a drop-in replacement for os/exec
// that requires PATH lookups to find absolute paths.
// That is, execabs.Command("cmd") runs the same PATH lookup
// as exec.Command("cmd"), but if the result is a path
// which is relative, the Run and Start methods will report
// an error instead of running the executable.
//
// See https://blog.golang.org/path-security for more information
// about when it may be necessary or appropriate to use this package.
package execabs
import (
"context"
"fmt"
"os/exec"
"path/filepath"
"reflect"
"unsafe"
)
// ErrNotFound is the error resulting if a path search failed to find an executable file.
// It is an alias for exec.ErrNotFound.
var ErrNotFound = exec.ErrNotFound
// Cmd represents an external command being prepared or run.
// It is an alias for exec.Cmd.
type Cmd = exec.Cmd
// Error is returned by LookPath when it fails to classify a file as an executable.
// It is an alias for exec.Error.
type Error = exec.Error
// An ExitError reports an unsuccessful exit by a command.
// It is an alias for exec.ExitError.
type ExitError = exec.ExitError
func relError(file, path string) error {
return fmt.Errorf("%s resolves to executable in current directory (.%c%s)", file, filepath.Separator, path)
}
// LookPath searches for an executable named file in the directories
// named by the PATH environment variable. If file contains a slash,
// it is tried directly and the PATH is not consulted. The result will be
// an absolute path.
//
// LookPath differs from exec.LookPath in its handling of PATH lookups,
// which are used for file names without slashes. If exec.LookPath's
// PATH lookup would have returned an executable from the current directory,
// LookPath instead returns an error.
func LookPath(file string) (string, error) {
path, err := exec.LookPath(file)
if err != nil {
return "", err
}
if filepath.Base(file) == file && !filepath.IsAbs(path) {
return "", relError(file, path)
}
return path, nil
}
func fixCmd(name string, cmd *exec.Cmd) {
if filepath.Base(name) == name && !filepath.IsAbs(cmd.Path) {
// exec.Command was called with a bare binary name and
// exec.LookPath returned a path which is not absolute.
// Set cmd.lookPathErr and clear cmd.Path so that it
// cannot be run.
lookPathErr := (*error)(unsafe.Pointer(reflect.ValueOf(cmd).Elem().FieldByName("lookPathErr").Addr().Pointer()))
if *lookPathErr == nil {
*lookPathErr = relError(name, cmd.Path)
}
cmd.Path = ""
}
}
// CommandContext is like Command but includes a context.
//
// The provided context is used to kill the process (by calling os.Process.Kill)
// if the context becomes done before the command completes on its own.
func CommandContext(ctx context.Context, name string, arg ...string) *exec.Cmd {
cmd := exec.CommandContext(ctx, name, arg...)
fixCmd(name, cmd)
return cmd
}
// Command returns the Cmd struct to execute the named program with the given arguments.
// See exec.Command for most details.
//
// Command differs from exec.Command in its handling of PATH lookups,
// which are used when the program name contains no slashes.
// If exec.Command would have returned an exec.Cmd configured to run an
// executable from the current directory, Command instead
// returns an exec.Cmd that will return an error from Start or Run.
func Command(name string, arg ...string) *exec.Cmd {
cmd := exec.Command(name, arg...)
fixCmd(name, cmd)
return cmd
}

View File

@ -52,6 +52,8 @@ go_library(
"ioctl.go", "ioctl.go",
"pagesize_unix.go", "pagesize_unix.go",
"pledge_openbsd.go", "pledge_openbsd.go",
"ptrace_darwin.go",
"ptrace_ios.go",
"race.go", "race.go",
"race0.go", "race0.go",
"readdirent_getdents.go", "readdirent_getdents.go",

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
// +build arm,darwin // +build arm,darwin
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
// +build arm64,darwin // +build arm64,darwin
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -4,7 +4,7 @@
// +build linux // +build linux
// +build arm64 // +build arm64
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -4,7 +4,7 @@
// +build linux // +build linux
// +build mips64 mips64le // +build mips64 mips64le
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -4,7 +4,7 @@
// +build linux // +build linux
// +build mips mipsle // +build mips mipsle
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -4,7 +4,7 @@
// +build linux // +build linux
// +build ppc64 ppc64le // +build ppc64 ppc64le
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build riscv64,!gccgo // +build riscv64,gc
#include "textflag.h" #include "textflag.h"

View File

@ -4,7 +4,7 @@
// +build s390x // +build s390x
// +build linux // +build linux
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !gccgo // +build gc
#include "textflag.h" #include "textflag.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// //
// +build ppc64 s390x mips mips64 // +build armbe arm64be m68k mips mips64 mips64p32 ppc ppc64 s390 s390x shbe sparc sparc64
package unix package unix

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// //
// +build 386 amd64 amd64p32 arm arm64 ppc64le mipsle mips64le riscv64 // +build 386 amd64 amd64p32 alpha arm arm64 mipsle mips64le mips64p32le nios2 ppc64le riscv riscv64 sh
package unix package unix

View File

@ -204,6 +204,7 @@ struct ltchars {
#include <linux/devlink.h> #include <linux/devlink.h>
#include <linux/dm-ioctl.h> #include <linux/dm-ioctl.h>
#include <linux/errqueue.h> #include <linux/errqueue.h>
#include <linux/ethtool_netlink.h>
#include <linux/falloc.h> #include <linux/falloc.h>
#include <linux/fanotify.h> #include <linux/fanotify.h>
#include <linux/filter.h> #include <linux/filter.h>
@ -225,6 +226,7 @@ struct ltchars {
#include <linux/kexec.h> #include <linux/kexec.h>
#include <linux/keyctl.h> #include <linux/keyctl.h>
#include <linux/loop.h> #include <linux/loop.h>
#include <linux/lwtunnel.h>
#include <linux/magic.h> #include <linux/magic.h>
#include <linux/memfd.h> #include <linux/memfd.h>
#include <linux/module.h> #include <linux/module.h>
@ -560,7 +562,10 @@ ccflags="$@"
$2 ~ /^(HDIO|WIN|SMART)_/ || $2 ~ /^(HDIO|WIN|SMART)_/ ||
$2 ~ /^CRYPTO_/ || $2 ~ /^CRYPTO_/ ||
$2 ~ /^TIPC_/ || $2 ~ /^TIPC_/ ||
$2 !~ "DEVLINK_RELOAD_LIMITS_VALID_MASK" &&
$2 ~ /^DEVLINK_/ || $2 ~ /^DEVLINK_/ ||
$2 ~ /^ETHTOOL_/ ||
$2 ~ /^LWTUNNEL_IP/ ||
$2 !~ "WMESGLEN" && $2 !~ "WMESGLEN" &&
$2 ~ /^W[A-Z0-9]+$/ || $2 ~ /^W[A-Z0-9]+$/ ||
$2 ~/^PPPIOC/ || $2 ~/^PPPIOC/ ||

11
vendor/golang.org/x/sys/unix/ptrace_darwin.go generated vendored Normal file
View File

@ -0,0 +1,11 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin,!ios
package unix
func ptrace(request int, pid int, addr uintptr, data uintptr) error {
return ptrace1(request, pid, addr, data)
}

11
vendor/golang.org/x/sys/unix/ptrace_ios.go generated vendored Normal file
View File

@ -0,0 +1,11 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ios
package unix
func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
return ENOTSUP
}

View File

@ -26,7 +26,6 @@ func fdopendir(fd int) (dir uintptr, err error) {
func libc_fdopendir_trampoline() func libc_fdopendir_trampoline()
//go:linkname libc_fdopendir libc_fdopendir
//go:cgo_import_dynamic libc_fdopendir fdopendir "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic libc_fdopendir fdopendir "/usr/lib/libSystem.B.dylib"
func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {

View File

@ -119,13 +119,16 @@ type attrList struct {
Forkattr uint32 Forkattr uint32
} }
//sysnb pipe() (r int, w int, err error) //sysnb pipe(p *[2]int32) (err error)
func Pipe(p []int) (err error) { func Pipe(p []int) (err error) {
if len(p) != 2 { if len(p) != 2 {
return EINVAL return EINVAL
} }
p[0], p[1], err = pipe() var x [2]int32
err = pipe(&x)
p[0] = int(x[0])
p[1] = int(x[1])
return return
} }

View File

@ -45,6 +45,6 @@ func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr,
//sys Fstatfs(fd int, stat *Statfs_t) (err error) = SYS_FSTATFS64 //sys Fstatfs(fd int, stat *Statfs_t) (err error) = SYS_FSTATFS64
//sys getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) = SYS_GETFSSTAT64 //sys getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) = SYS_GETFSSTAT64
//sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64 //sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64
//sys ptrace(request int, pid int, addr uintptr, data uintptr) (err error) //sys ptrace1(request int, pid int, addr uintptr, data uintptr) (err error) = SYS_ptrace
//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64 //sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
//sys Statfs(path string, stat *Statfs_t) (err error) = SYS_STATFS64 //sys Statfs(path string, stat *Statfs_t) (err error) = SYS_STATFS64

View File

@ -45,6 +45,6 @@ func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr,
//sys Fstatfs(fd int, stat *Statfs_t) (err error) = SYS_FSTATFS64 //sys Fstatfs(fd int, stat *Statfs_t) (err error) = SYS_FSTATFS64
//sys getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) = SYS_GETFSSTAT64 //sys getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) = SYS_GETFSSTAT64
//sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64 //sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64
//sys ptrace(request int, pid int, addr uintptr, data uintptr) (err error) //sys ptrace1(request int, pid int, addr uintptr, data uintptr) (err error) = SYS_ptrace
//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64 //sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
//sys Statfs(path string, stat *Statfs_t) (err error) = SYS_STATFS64 //sys Statfs(path string, stat *Statfs_t) (err error) = SYS_STATFS64

View File

@ -6,7 +6,7 @@ package unix
import "syscall" import "syscall"
func ptrace(request int, pid int, addr uintptr, data uintptr) error { func ptrace1(request int, pid int, addr uintptr, data uintptr) error {
return ENOTSUP return ENOTSUP
} }

View File

@ -45,6 +45,6 @@ func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr,
//sys Fstatfs(fd int, stat *Statfs_t) (err error) //sys Fstatfs(fd int, stat *Statfs_t) (err error)
//sys getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) = SYS_GETFSSTAT //sys getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) = SYS_GETFSSTAT
//sys Lstat(path string, stat *Stat_t) (err error) //sys Lstat(path string, stat *Stat_t) (err error)
//sys ptrace(request int, pid int, addr uintptr, data uintptr) (err error) //sys ptrace1(request int, pid int, addr uintptr, data uintptr) (err error) = SYS_ptrace
//sys Stat(path string, stat *Stat_t) (err error) //sys Stat(path string, stat *Stat_t) (err error)
//sys Statfs(path string, stat *Statfs_t) (err error) //sys Statfs(path string, stat *Statfs_t) (err error)

View File

@ -105,6 +105,19 @@ func Pipe(p []int) (err error) {
return return
} }
//sysnb pipe2(p *[2]_C_int, flags int) (err error)
func Pipe2(p []int, flags int) error {
if len(p) != 2 {
return EINVAL
}
var pp [2]_C_int
err := pipe2(&pp, flags)
p[0] = int(pp[0])
p[1] = int(pp[1])
return err
}
//sys extpread(fd int, p []byte, flags int, offset int64) (n int, err error) //sys extpread(fd int, p []byte, flags int, offset int64) (n int, err error)
func Pread(fd int, p []byte, offset int64) (n int, err error) { func Pread(fd int, p []byte, offset int64) (n int, err error) {
return extpread(fd, p, 0, offset) return extpread(fd, p, 0, offset)

View File

@ -75,16 +75,3 @@ func Accept4(fd int, flags int) (nfd int, sa Sockaddr, err error) {
} }
return return
} }
//sysnb pipe2(p *[2]_C_int, flags int) (err error)
func Pipe2(p []int, flags int) error {
if len(p) != 2 {
return EINVAL
}
var pp [2]_C_int
err := pipe2(&pp, flags)
p[0] = int(pp[0])
p[1] = int(pp[1])
return err
}

View File

@ -641,6 +641,36 @@ func (sa *SockaddrCAN) sockaddr() (unsafe.Pointer, _Socklen, error) {
return unsafe.Pointer(&sa.raw), SizeofSockaddrCAN, nil return unsafe.Pointer(&sa.raw), SizeofSockaddrCAN, nil
} }
// SockaddrCANJ1939 implements the Sockaddr interface for AF_CAN using J1939
// protocol (https://en.wikipedia.org/wiki/SAE_J1939). For more information
// on the purposes of the fields, check the official linux kernel documentation
// available here: https://www.kernel.org/doc/Documentation/networking/j1939.rst
type SockaddrCANJ1939 struct {
Ifindex int
Name uint64
PGN uint32
Addr uint8
raw RawSockaddrCAN
}
func (sa *SockaddrCANJ1939) sockaddr() (unsafe.Pointer, _Socklen, error) {
if sa.Ifindex < 0 || sa.Ifindex > 0x7fffffff {
return nil, 0, EINVAL
}
sa.raw.Family = AF_CAN
sa.raw.Ifindex = int32(sa.Ifindex)
n := (*[8]byte)(unsafe.Pointer(&sa.Name))
for i := 0; i < 8; i++ {
sa.raw.Addr[i] = n[i]
}
p := (*[4]byte)(unsafe.Pointer(&sa.PGN))
for i := 0; i < 4; i++ {
sa.raw.Addr[i+8] = p[i]
}
sa.raw.Addr[12] = sa.Addr
return unsafe.Pointer(&sa.raw), SizeofSockaddrCAN, nil
}
// SockaddrALG implements the Sockaddr interface for AF_ALG type sockets. // SockaddrALG implements the Sockaddr interface for AF_ALG type sockets.
// SockaddrALG enables userspace access to the Linux kernel's cryptography // SockaddrALG enables userspace access to the Linux kernel's cryptography
// subsystem. The Type and Name fields specify which type of hash or cipher // subsystem. The Type and Name fields specify which type of hash or cipher
@ -952,6 +982,10 @@ func (sa *SockaddrIUCV) sockaddr() (unsafe.Pointer, _Socklen, error) {
return unsafe.Pointer(&sa.raw), SizeofSockaddrIUCV, nil return unsafe.Pointer(&sa.raw), SizeofSockaddrIUCV, nil
} }
var socketProtocol = func(fd int) (int, error) {
return GetsockoptInt(fd, SOL_SOCKET, SO_PROTOCOL)
}
func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
switch rsa.Addr.Family { switch rsa.Addr.Family {
case AF_NETLINK: case AF_NETLINK:
@ -1002,7 +1036,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
return sa, nil return sa, nil
case AF_INET: case AF_INET:
proto, err := GetsockoptInt(fd, SOL_SOCKET, SO_PROTOCOL) proto, err := socketProtocol(fd)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1028,7 +1062,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
} }
case AF_INET6: case AF_INET6:
proto, err := GetsockoptInt(fd, SOL_SOCKET, SO_PROTOCOL) proto, err := socketProtocol(fd)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1063,7 +1097,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
} }
return sa, nil return sa, nil
case AF_BLUETOOTH: case AF_BLUETOOTH:
proto, err := GetsockoptInt(fd, SOL_SOCKET, SO_PROTOCOL) proto, err := socketProtocol(fd)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1150,20 +1184,43 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
return sa, nil return sa, nil
case AF_CAN: case AF_CAN:
pp := (*RawSockaddrCAN)(unsafe.Pointer(rsa)) proto, err := socketProtocol(fd)
sa := &SockaddrCAN{ if err != nil {
Ifindex: int(pp.Ifindex), return nil, err
} }
rx := (*[4]byte)(unsafe.Pointer(&sa.RxID))
for i := 0; i < 4; i++ {
rx[i] = pp.Addr[i]
}
tx := (*[4]byte)(unsafe.Pointer(&sa.TxID))
for i := 0; i < 4; i++ {
tx[i] = pp.Addr[i+4]
}
return sa, nil
pp := (*RawSockaddrCAN)(unsafe.Pointer(rsa))
switch proto {
case CAN_J1939:
sa := &SockaddrCANJ1939{
Ifindex: int(pp.Ifindex),
}
name := (*[8]byte)(unsafe.Pointer(&sa.Name))
for i := 0; i < 8; i++ {
name[i] = pp.Addr[i]
}
pgn := (*[4]byte)(unsafe.Pointer(&sa.PGN))
for i := 0; i < 4; i++ {
pgn[i] = pp.Addr[i+8]
}
addr := (*[1]byte)(unsafe.Pointer(&sa.Addr))
addr[0] = pp.Addr[12]
return sa, nil
default:
sa := &SockaddrCAN{
Ifindex: int(pp.Ifindex),
}
rx := (*[4]byte)(unsafe.Pointer(&sa.RxID))
for i := 0; i < 4; i++ {
rx[i] = pp.Addr[i]
}
tx := (*[4]byte)(unsafe.Pointer(&sa.TxID))
for i := 0; i < 4; i++ {
tx[i] = pp.Addr[i+4]
}
return sa, nil
}
} }
return nil, EAFNOSUPPORT return nil, EAFNOSUPPORT
} }

View File

@ -3,7 +3,7 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build amd64,linux // +build amd64,linux
// +build !gccgo // +build gc
package unix package unix

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build linux,!gccgo // +build linux,gc
package unix package unix

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build linux,!gccgo,386 // +build linux,gc,386
package unix package unix

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build arm,!gccgo,linux // +build arm,gc,linux
package unix package unix

View File

@ -68,6 +68,19 @@ func Pipe(p []int) (err error) {
return nil return nil
} }
//sysnb pipe2(p *[2]_C_int, flags int) (err error)
func Pipe2(p []int, flags int) error {
if len(p) != 2 {
return EINVAL
}
var pp [2]_C_int
err := pipe2(&pp, flags)
p[0] = int(pp[0])
p[1] = int(pp[1])
return err
}
func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) { func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) {
if sa.Port < 0 || sa.Port > 0xFFFF { if sa.Port < 0 || sa.Port > 0xFFFF {
return nil, 0, EINVAL return nil, 0, EINVAL

View File

@ -3,7 +3,7 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux netbsd openbsd solaris // +build darwin dragonfly freebsd linux netbsd openbsd solaris
// +build !gccgo,!ppc64le,!ppc64 // +build gc,!ppc64le,!ppc64
package unix package unix

View File

@ -4,7 +4,7 @@
// +build linux // +build linux
// +build ppc64le ppc64 // +build ppc64le ppc64
// +build !gccgo // +build gc
package unix package unix

View File

@ -8,12 +8,10 @@ package unix
import "time" import "time"
// TimespecToNsec converts a Timespec value into a number of // TimespecToNSec returns the time stored in ts as nanoseconds.
// nanoseconds since the Unix epoch. func TimespecToNsec(ts Timespec) int64 { return ts.Nano() }
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
// NsecToTimespec takes a number of nanoseconds since the Unix epoch // NsecToTimespec converts a number of nanoseconds into a Timespec.
// and returns the corresponding Timespec value.
func NsecToTimespec(nsec int64) Timespec { func NsecToTimespec(nsec int64) Timespec {
sec := nsec / 1e9 sec := nsec / 1e9
nsec = nsec % 1e9 nsec = nsec % 1e9
@ -42,12 +40,10 @@ func TimeToTimespec(t time.Time) (Timespec, error) {
return ts, nil return ts, nil
} }
// TimevalToNsec converts a Timeval value into a number of nanoseconds // TimevalToNsec returns the time stored in tv as nanoseconds.
// since the Unix epoch. func TimevalToNsec(tv Timeval) int64 { return tv.Nano() }
func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
// NsecToTimeval takes a number of nanoseconds since the Unix epoch // NsecToTimeval converts a number of nanoseconds into a Timeval.
// and returns the corresponding Timeval value.
func NsecToTimeval(nsec int64) Timeval { func NsecToTimeval(nsec int64) Timeval {
nsec += 999 // round up to microsecond nsec += 999 // round up to microsecond
usec := nsec % 1e9 / 1e3 usec := nsec % 1e9 / 1e3
@ -59,24 +55,22 @@ func NsecToTimeval(nsec int64) Timeval {
return setTimeval(sec, usec) return setTimeval(sec, usec)
} }
// Unix returns ts as the number of seconds and nanoseconds elapsed since the // Unix returns the time stored in ts as seconds plus nanoseconds.
// Unix epoch.
func (ts *Timespec) Unix() (sec int64, nsec int64) { func (ts *Timespec) Unix() (sec int64, nsec int64) {
return int64(ts.Sec), int64(ts.Nsec) return int64(ts.Sec), int64(ts.Nsec)
} }
// Unix returns tv as the number of seconds and nanoseconds elapsed since the // Unix returns the time stored in tv as seconds plus nanoseconds.
// Unix epoch.
func (tv *Timeval) Unix() (sec int64, nsec int64) { func (tv *Timeval) Unix() (sec int64, nsec int64) {
return int64(tv.Sec), int64(tv.Usec) * 1000 return int64(tv.Sec), int64(tv.Usec) * 1000
} }
// Nano returns ts as the number of nanoseconds elapsed since the Unix epoch. // Nano returns the time stored in ts as nanoseconds.
func (ts *Timespec) Nano() int64 { func (ts *Timespec) Nano() int64 {
return int64(ts.Sec)*1e9 + int64(ts.Nsec) return int64(ts.Sec)*1e9 + int64(ts.Nsec)
} }
// Nano returns tv as the number of nanoseconds elapsed since the Unix epoch. // Nano returns the time stored in tv as nanoseconds.
func (tv *Timeval) Nano() int64 { func (tv *Timeval) Nano() int64 {
return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000 return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000
} }

View File

@ -65,6 +65,7 @@ const (
ALG_OP_ENCRYPT = 0x1 ALG_OP_ENCRYPT = 0x1
ALG_SET_AEAD_ASSOCLEN = 0x4 ALG_SET_AEAD_ASSOCLEN = 0x4
ALG_SET_AEAD_AUTHSIZE = 0x5 ALG_SET_AEAD_AUTHSIZE = 0x5
ALG_SET_DRBG_ENTROPY = 0x6
ALG_SET_IV = 0x2 ALG_SET_IV = 0x2
ALG_SET_KEY = 0x1 ALG_SET_KEY = 0x1
ALG_SET_OP = 0x3 ALG_SET_OP = 0x3
@ -179,8 +180,10 @@ const (
BPF_F_ANY_ALIGNMENT = 0x2 BPF_F_ANY_ALIGNMENT = 0x2
BPF_F_QUERY_EFFECTIVE = 0x1 BPF_F_QUERY_EFFECTIVE = 0x1
BPF_F_REPLACE = 0x4 BPF_F_REPLACE = 0x4
BPF_F_SLEEPABLE = 0x10
BPF_F_STRICT_ALIGNMENT = 0x1 BPF_F_STRICT_ALIGNMENT = 0x1
BPF_F_TEST_RND_HI32 = 0x4 BPF_F_TEST_RND_HI32 = 0x4
BPF_F_TEST_RUN_ON_CPU = 0x1
BPF_F_TEST_STATE_FREQ = 0x8 BPF_F_TEST_STATE_FREQ = 0x8
BPF_H = 0x8 BPF_H = 0x8
BPF_IMM = 0x0 BPF_IMM = 0x0
@ -219,6 +222,7 @@ const (
BPF_NET_OFF = -0x100000 BPF_NET_OFF = -0x100000
BPF_OBJ_NAME_LEN = 0x10 BPF_OBJ_NAME_LEN = 0x10
BPF_OR = 0x40 BPF_OR = 0x40
BPF_PSEUDO_BTF_ID = 0x3
BPF_PSEUDO_CALL = 0x1 BPF_PSEUDO_CALL = 0x1
BPF_PSEUDO_MAP_FD = 0x1 BPF_PSEUDO_MAP_FD = 0x1
BPF_PSEUDO_MAP_VALUE = 0x2 BPF_PSEUDO_MAP_VALUE = 0x2
@ -429,10 +433,13 @@ const (
DEBUGFS_MAGIC = 0x64626720 DEBUGFS_MAGIC = 0x64626720
DEVLINK_CMD_ESWITCH_MODE_GET = 0x1d DEVLINK_CMD_ESWITCH_MODE_GET = 0x1d
DEVLINK_CMD_ESWITCH_MODE_SET = 0x1e DEVLINK_CMD_ESWITCH_MODE_SET = 0x1e
DEVLINK_FLASH_OVERWRITE_IDENTIFIERS = 0x2
DEVLINK_FLASH_OVERWRITE_SETTINGS = 0x1
DEVLINK_GENL_MCGRP_CONFIG_NAME = "config" DEVLINK_GENL_MCGRP_CONFIG_NAME = "config"
DEVLINK_GENL_NAME = "devlink" DEVLINK_GENL_NAME = "devlink"
DEVLINK_GENL_VERSION = 0x1 DEVLINK_GENL_VERSION = 0x1
DEVLINK_SB_THRESHOLD_TO_ALPHA_MAX = 0x14 DEVLINK_SB_THRESHOLD_TO_ALPHA_MAX = 0x14
DEVLINK_SUPPORTED_FLASH_OVERWRITE_SECTIONS = 0x3
DEVMEM_MAGIC = 0x454d444d DEVMEM_MAGIC = 0x454d444d
DEVPTS_SUPER_MAGIC = 0x1cd1 DEVPTS_SUPER_MAGIC = 0x1cd1
DMA_BUF_MAGIC = 0x444d4142 DMA_BUF_MAGIC = 0x444d4142
@ -477,9 +484,9 @@ const (
DM_UUID_FLAG = 0x4000 DM_UUID_FLAG = 0x4000
DM_UUID_LEN = 0x81 DM_UUID_LEN = 0x81
DM_VERSION = 0xc138fd00 DM_VERSION = 0xc138fd00
DM_VERSION_EXTRA = "-ioctl (2020-02-27)" DM_VERSION_EXTRA = "-ioctl (2020-10-01)"
DM_VERSION_MAJOR = 0x4 DM_VERSION_MAJOR = 0x4
DM_VERSION_MINOR = 0x2a DM_VERSION_MINOR = 0x2b
DM_VERSION_PATCHLEVEL = 0x0 DM_VERSION_PATCHLEVEL = 0x0
DT_BLK = 0x6 DT_BLK = 0x6
DT_CHR = 0x2 DT_CHR = 0x2
@ -520,6 +527,119 @@ const (
EPOLL_CTL_DEL = 0x2 EPOLL_CTL_DEL = 0x2
EPOLL_CTL_MOD = 0x3 EPOLL_CTL_MOD = 0x3
EROFS_SUPER_MAGIC_V1 = 0xe0f5e1e2 EROFS_SUPER_MAGIC_V1 = 0xe0f5e1e2
ESP_V4_FLOW = 0xa
ESP_V6_FLOW = 0xc
ETHER_FLOW = 0x12
ETHTOOL_BUSINFO_LEN = 0x20
ETHTOOL_EROMVERS_LEN = 0x20
ETHTOOL_FEC_AUTO = 0x2
ETHTOOL_FEC_BASER = 0x10
ETHTOOL_FEC_LLRS = 0x20
ETHTOOL_FEC_NONE = 0x1
ETHTOOL_FEC_OFF = 0x4
ETHTOOL_FEC_RS = 0x8
ETHTOOL_FLAG_ALL = 0x7
ETHTOOL_FLAG_COMPACT_BITSETS = 0x1
ETHTOOL_FLAG_OMIT_REPLY = 0x2
ETHTOOL_FLAG_STATS = 0x4
ETHTOOL_FLASHDEV = 0x33
ETHTOOL_FLASH_MAX_FILENAME = 0x80
ETHTOOL_FWVERS_LEN = 0x20
ETHTOOL_F_COMPAT = 0x4
ETHTOOL_F_UNSUPPORTED = 0x1
ETHTOOL_F_WISH = 0x2
ETHTOOL_GCHANNELS = 0x3c
ETHTOOL_GCOALESCE = 0xe
ETHTOOL_GDRVINFO = 0x3
ETHTOOL_GEEE = 0x44
ETHTOOL_GEEPROM = 0xb
ETHTOOL_GENL_NAME = "ethtool"
ETHTOOL_GENL_VERSION = 0x1
ETHTOOL_GET_DUMP_DATA = 0x40
ETHTOOL_GET_DUMP_FLAG = 0x3f
ETHTOOL_GET_TS_INFO = 0x41
ETHTOOL_GFEATURES = 0x3a
ETHTOOL_GFECPARAM = 0x50
ETHTOOL_GFLAGS = 0x25
ETHTOOL_GGRO = 0x2b
ETHTOOL_GGSO = 0x23
ETHTOOL_GLINK = 0xa
ETHTOOL_GLINKSETTINGS = 0x4c
ETHTOOL_GMODULEEEPROM = 0x43
ETHTOOL_GMODULEINFO = 0x42
ETHTOOL_GMSGLVL = 0x7
ETHTOOL_GPAUSEPARAM = 0x12
ETHTOOL_GPERMADDR = 0x20
ETHTOOL_GPFLAGS = 0x27
ETHTOOL_GPHYSTATS = 0x4a
ETHTOOL_GREGS = 0x4
ETHTOOL_GRINGPARAM = 0x10
ETHTOOL_GRSSH = 0x46
ETHTOOL_GRXCLSRLALL = 0x30
ETHTOOL_GRXCLSRLCNT = 0x2e
ETHTOOL_GRXCLSRULE = 0x2f
ETHTOOL_GRXCSUM = 0x14
ETHTOOL_GRXFH = 0x29
ETHTOOL_GRXFHINDIR = 0x38
ETHTOOL_GRXNTUPLE = 0x36
ETHTOOL_GRXRINGS = 0x2d
ETHTOOL_GSET = 0x1
ETHTOOL_GSG = 0x18
ETHTOOL_GSSET_INFO = 0x37
ETHTOOL_GSTATS = 0x1d
ETHTOOL_GSTRINGS = 0x1b
ETHTOOL_GTSO = 0x1e
ETHTOOL_GTUNABLE = 0x48
ETHTOOL_GTXCSUM = 0x16
ETHTOOL_GUFO = 0x21
ETHTOOL_GWOL = 0x5
ETHTOOL_MCGRP_MONITOR_NAME = "monitor"
ETHTOOL_NWAY_RST = 0x9
ETHTOOL_PERQUEUE = 0x4b
ETHTOOL_PHYS_ID = 0x1c
ETHTOOL_PHY_EDPD_DFLT_TX_MSECS = 0xffff
ETHTOOL_PHY_EDPD_DISABLE = 0x0
ETHTOOL_PHY_EDPD_NO_TX = 0xfffe
ETHTOOL_PHY_FAST_LINK_DOWN_OFF = 0xff
ETHTOOL_PHY_FAST_LINK_DOWN_ON = 0x0
ETHTOOL_PHY_GTUNABLE = 0x4e
ETHTOOL_PHY_STUNABLE = 0x4f
ETHTOOL_RESET = 0x34
ETHTOOL_RXNTUPLE_ACTION_CLEAR = -0x2
ETHTOOL_RXNTUPLE_ACTION_DROP = -0x1
ETHTOOL_RX_FLOW_SPEC_RING = 0xffffffff
ETHTOOL_RX_FLOW_SPEC_RING_VF = 0xff00000000
ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF = 0x20
ETHTOOL_SCHANNELS = 0x3d
ETHTOOL_SCOALESCE = 0xf
ETHTOOL_SEEE = 0x45
ETHTOOL_SEEPROM = 0xc
ETHTOOL_SET_DUMP = 0x3e
ETHTOOL_SFEATURES = 0x3b
ETHTOOL_SFECPARAM = 0x51
ETHTOOL_SFLAGS = 0x26
ETHTOOL_SGRO = 0x2c
ETHTOOL_SGSO = 0x24
ETHTOOL_SLINKSETTINGS = 0x4d
ETHTOOL_SMSGLVL = 0x8
ETHTOOL_SPAUSEPARAM = 0x13
ETHTOOL_SPFLAGS = 0x28
ETHTOOL_SRINGPARAM = 0x11
ETHTOOL_SRSSH = 0x47
ETHTOOL_SRXCLSRLDEL = 0x31
ETHTOOL_SRXCLSRLINS = 0x32
ETHTOOL_SRXCSUM = 0x15
ETHTOOL_SRXFH = 0x2a
ETHTOOL_SRXFHINDIR = 0x39
ETHTOOL_SRXNTUPLE = 0x35
ETHTOOL_SSET = 0x2
ETHTOOL_SSG = 0x19
ETHTOOL_STSO = 0x1f
ETHTOOL_STUNABLE = 0x49
ETHTOOL_STXCSUM = 0x17
ETHTOOL_SUFO = 0x22
ETHTOOL_SWOL = 0x6
ETHTOOL_TEST = 0x1a
ETH_P_1588 = 0x88f7 ETH_P_1588 = 0x88f7
ETH_P_8021AD = 0x88a8 ETH_P_8021AD = 0x88a8
ETH_P_8021AH = 0x88e7 ETH_P_8021AH = 0x88e7
@ -989,6 +1109,7 @@ const (
IPV6_DONTFRAG = 0x3e IPV6_DONTFRAG = 0x3e
IPV6_DROP_MEMBERSHIP = 0x15 IPV6_DROP_MEMBERSHIP = 0x15
IPV6_DSTOPTS = 0x3b IPV6_DSTOPTS = 0x3b
IPV6_FLOW = 0x11
IPV6_FREEBIND = 0x4e IPV6_FREEBIND = 0x4e
IPV6_HDRINCL = 0x24 IPV6_HDRINCL = 0x24
IPV6_HOPLIMIT = 0x34 IPV6_HOPLIMIT = 0x34
@ -1038,6 +1159,7 @@ const (
IPV6_TRANSPARENT = 0x4b IPV6_TRANSPARENT = 0x4b
IPV6_UNICAST_HOPS = 0x10 IPV6_UNICAST_HOPS = 0x10
IPV6_UNICAST_IF = 0x4c IPV6_UNICAST_IF = 0x4c
IPV6_USER_FLOW = 0xe
IPV6_V6ONLY = 0x1a IPV6_V6ONLY = 0x1a
IPV6_XFRM_POLICY = 0x23 IPV6_XFRM_POLICY = 0x23
IP_ADD_MEMBERSHIP = 0x23 IP_ADD_MEMBERSHIP = 0x23
@ -1094,6 +1216,7 @@ const (
IP_TTL = 0x2 IP_TTL = 0x2
IP_UNBLOCK_SOURCE = 0x25 IP_UNBLOCK_SOURCE = 0x25
IP_UNICAST_IF = 0x32 IP_UNICAST_IF = 0x32
IP_USER_FLOW = 0xd
IP_XFRM_POLICY = 0x11 IP_XFRM_POLICY = 0x11
ISOFS_SUPER_MAGIC = 0x9660 ISOFS_SUPER_MAGIC = 0x9660
ISTRIP = 0x20 ISTRIP = 0x20
@ -1217,6 +1340,12 @@ const (
LOOP_SET_STATUS_SETTABLE_FLAGS = 0xc LOOP_SET_STATUS_SETTABLE_FLAGS = 0xc
LO_KEY_SIZE = 0x20 LO_KEY_SIZE = 0x20
LO_NAME_SIZE = 0x40 LO_NAME_SIZE = 0x40
LWTUNNEL_IP6_MAX = 0x8
LWTUNNEL_IP_MAX = 0x8
LWTUNNEL_IP_OPTS_MAX = 0x3
LWTUNNEL_IP_OPT_ERSPAN_MAX = 0x4
LWTUNNEL_IP_OPT_GENEVE_MAX = 0x3
LWTUNNEL_IP_OPT_VXLAN_MAX = 0x1
MADV_COLD = 0x14 MADV_COLD = 0x14
MADV_DODUMP = 0x11 MADV_DODUMP = 0x11
MADV_DOFORK = 0xb MADV_DOFORK = 0xb
@ -1325,6 +1454,7 @@ const (
MS_NOREMOTELOCK = 0x8000000 MS_NOREMOTELOCK = 0x8000000
MS_NOSEC = 0x10000000 MS_NOSEC = 0x10000000
MS_NOSUID = 0x2 MS_NOSUID = 0x2
MS_NOSYMFOLLOW = 0x100
MS_NOUSER = -0x80000000 MS_NOUSER = -0x80000000
MS_POSIXACL = 0x10000 MS_POSIXACL = 0x10000
MS_PRIVATE = 0x40000 MS_PRIVATE = 0x40000
@ -1566,7 +1696,7 @@ const (
PERF_MEM_REMOTE_REMOTE = 0x1 PERF_MEM_REMOTE_REMOTE = 0x1
PERF_MEM_REMOTE_SHIFT = 0x25 PERF_MEM_REMOTE_SHIFT = 0x25
PERF_MEM_SNOOPX_FWD = 0x1 PERF_MEM_SNOOPX_FWD = 0x1
PERF_MEM_SNOOPX_SHIFT = 0x25 PERF_MEM_SNOOPX_SHIFT = 0x26
PERF_MEM_SNOOP_HIT = 0x4 PERF_MEM_SNOOP_HIT = 0x4
PERF_MEM_SNOOP_HITM = 0x10 PERF_MEM_SNOOP_HITM = 0x10
PERF_MEM_SNOOP_MISS = 0x8 PERF_MEM_SNOOP_MISS = 0x8
@ -1666,6 +1796,13 @@ const (
PR_MCE_KILL_SET = 0x1 PR_MCE_KILL_SET = 0x1
PR_MPX_DISABLE_MANAGEMENT = 0x2c PR_MPX_DISABLE_MANAGEMENT = 0x2c
PR_MPX_ENABLE_MANAGEMENT = 0x2b PR_MPX_ENABLE_MANAGEMENT = 0x2b
PR_MTE_TAG_MASK = 0x7fff8
PR_MTE_TAG_SHIFT = 0x3
PR_MTE_TCF_ASYNC = 0x4
PR_MTE_TCF_MASK = 0x6
PR_MTE_TCF_NONE = 0x0
PR_MTE_TCF_SHIFT = 0x1
PR_MTE_TCF_SYNC = 0x2
PR_PAC_APDAKEY = 0x4 PR_PAC_APDAKEY = 0x4
PR_PAC_APDBKEY = 0x8 PR_PAC_APDBKEY = 0x8
PR_PAC_APGAKEY = 0x10 PR_PAC_APGAKEY = 0x10
@ -2200,7 +2337,7 @@ const (
STATX_ATTR_APPEND = 0x20 STATX_ATTR_APPEND = 0x20
STATX_ATTR_AUTOMOUNT = 0x1000 STATX_ATTR_AUTOMOUNT = 0x1000
STATX_ATTR_COMPRESSED = 0x4 STATX_ATTR_COMPRESSED = 0x4
STATX_ATTR_DAX = 0x2000 STATX_ATTR_DAX = 0x200000
STATX_ATTR_ENCRYPTED = 0x800 STATX_ATTR_ENCRYPTED = 0x800
STATX_ATTR_IMMUTABLE = 0x10 STATX_ATTR_IMMUTABLE = 0x10
STATX_ATTR_MOUNT_ROOT = 0x2000 STATX_ATTR_MOUNT_ROOT = 0x2000
@ -2319,6 +2456,8 @@ const (
TCP_TX_DELAY = 0x25 TCP_TX_DELAY = 0x25
TCP_ULP = 0x1f TCP_ULP = 0x1f
TCP_USER_TIMEOUT = 0x12 TCP_USER_TIMEOUT = 0x12
TCP_V4_FLOW = 0x1
TCP_V6_FLOW = 0x5
TCP_WINDOW_CLAMP = 0xa TCP_WINDOW_CLAMP = 0xa
TCP_ZEROCOPY_RECEIVE = 0x23 TCP_ZEROCOPY_RECEIVE = 0x23
TFD_TIMER_ABSTIME = 0x1 TFD_TIMER_ABSTIME = 0x1
@ -2384,6 +2523,7 @@ const (
TIPC_NODE_STATE = 0x0 TIPC_NODE_STATE = 0x0
TIPC_OK = 0x0 TIPC_OK = 0x0
TIPC_PUBLISHED = 0x1 TIPC_PUBLISHED = 0x1
TIPC_REKEYING_NOW = 0xffffffff
TIPC_RESERVED_TYPES = 0x40 TIPC_RESERVED_TYPES = 0x40
TIPC_RETDATA = 0x2 TIPC_RETDATA = 0x2
TIPC_SERVICE_ADDR = 0x2 TIPC_SERVICE_ADDR = 0x2
@ -2444,6 +2584,7 @@ const (
VM_SOCKETS_INVALID_VERSION = 0xffffffff VM_SOCKETS_INVALID_VERSION = 0xffffffff
VQUIT = 0x1 VQUIT = 0x1
VT0 = 0x0 VT0 = 0x0
WAKE_MAGIC = 0x20
WALL = 0x40000000 WALL = 0x40000000
WCLONE = 0x80000000 WCLONE = 0x80000000
WCONTINUED = 0x8 WCONTINUED = 0x8

View File

@ -4,7 +4,7 @@
// +build 386,linux // +build 386,linux
// Code generated by cmd/cgo -godefs; DO NOT EDIT. // Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs -- -Wall -Werror -static -I/tmp/include -m32 _const.go // cgo -godefs -- -Wall -Werror -static -I/tmp/include -m32 /build/_const.go
package unix package unix

Some files were not shown because too many files have changed in this diff Show More