Merge pull request #16446 from Luap99/format-json
fix --format {{json .}} output to match docker
This commit is contained in:
commit
6555e69354
|
|
@ -1,10 +0,0 @@
|
||||||
package parse
|
|
||||||
|
|
||||||
import "regexp"
|
|
||||||
|
|
||||||
var jsonFormatRegex = regexp.MustCompile(`^\s*(json|{{\s*json\s*(\.)?\s*}})\s*$`)
|
|
||||||
|
|
||||||
// MatchesJSONFormat test CLI --format string to be a JSON request.
|
|
||||||
func MatchesJSONFormat(s string) bool {
|
|
||||||
return jsonFormatRegex.Match([]byte(s))
|
|
||||||
}
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
package parse
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMatchesJSONFormat(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
input string
|
|
||||||
expected bool
|
|
||||||
}{
|
|
||||||
{"json", true},
|
|
||||||
{" json", true},
|
|
||||||
{" json ", true},
|
|
||||||
{" json ", true},
|
|
||||||
{"{{json}}", true},
|
|
||||||
{"{{json }}", true},
|
|
||||||
{"{{json .}}", true},
|
|
||||||
{"{{ json .}}", true},
|
|
||||||
{"{{ json . }}", true},
|
|
||||||
{" {{ json . }} ", true},
|
|
||||||
{"{{ json .", false},
|
|
||||||
{"json . }}", false},
|
|
||||||
{"{{.ID }} json .", false},
|
|
||||||
{"json .", false},
|
|
||||||
{"{{json.}}", true},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
assert.Equal(t, tt.expected, MatchesJSONFormat(tt.input))
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range tests {
|
|
||||||
tc := tc
|
|
||||||
label := "MatchesJSONFormat/" + strings.ReplaceAll(tc.input, " ", "_")
|
|
||||||
t.Run(label, func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
assert.Equal(t, tc.expected, MatchesJSONFormat(tc.input), fmt.Sprintf("Scanning %q failed", tc.input))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
4
go.mod
4
go.mod
|
|
@ -12,7 +12,7 @@ require (
|
||||||
github.com/containernetworking/cni v1.1.2
|
github.com/containernetworking/cni v1.1.2
|
||||||
github.com/containernetworking/plugins v1.1.1
|
github.com/containernetworking/plugins v1.1.1
|
||||||
github.com/containers/buildah v1.28.1-0.20221029151733-c2cf9fa47ab6
|
github.com/containers/buildah v1.28.1-0.20221029151733-c2cf9fa47ab6
|
||||||
github.com/containers/common v0.50.2-0.20221104122933-582fadb8228b
|
github.com/containers/common v0.50.2-0.20221109162103-1e40f47dd90b
|
||||||
github.com/containers/conmon v2.0.20+incompatible
|
github.com/containers/conmon v2.0.20+incompatible
|
||||||
github.com/containers/image/v5 v5.23.1-0.20221101011818-2f770d6d5a0c
|
github.com/containers/image/v5 v5.23.1-0.20221101011818-2f770d6d5a0c
|
||||||
github.com/containers/ocicrypt v1.1.6
|
github.com/containers/ocicrypt v1.1.6
|
||||||
|
|
@ -135,7 +135,7 @@ require (
|
||||||
golang.org/x/crypto v0.1.0 // indirect
|
golang.org/x/crypto v0.1.0 // indirect
|
||||||
golang.org/x/mod v0.6.0 // indirect
|
golang.org/x/mod v0.6.0 // indirect
|
||||||
golang.org/x/net v0.1.0 // indirect
|
golang.org/x/net v0.1.0 // indirect
|
||||||
golang.org/x/tools v0.1.12 // indirect
|
golang.org/x/tools v0.2.0 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a // indirect
|
google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a // indirect
|
||||||
google.golang.org/grpc v1.50.1 // indirect
|
google.golang.org/grpc v1.50.1 // indirect
|
||||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||||
|
|
|
||||||
10
go.sum
10
go.sum
|
|
@ -264,8 +264,8 @@ github.com/containernetworking/plugins v1.1.1 h1:+AGfFigZ5TiQH00vhR8qPeSatj53eNG
|
||||||
github.com/containernetworking/plugins v1.1.1/go.mod h1:Sr5TH/eBsGLXK/h71HeLfX19sZPp3ry5uHSkI4LPxV8=
|
github.com/containernetworking/plugins v1.1.1/go.mod h1:Sr5TH/eBsGLXK/h71HeLfX19sZPp3ry5uHSkI4LPxV8=
|
||||||
github.com/containers/buildah v1.28.1-0.20221029151733-c2cf9fa47ab6 h1:6bFoF3QIUzza8NWAsHS1ZGDDEr+r5do46dXEbzkZb3Y=
|
github.com/containers/buildah v1.28.1-0.20221029151733-c2cf9fa47ab6 h1:6bFoF3QIUzza8NWAsHS1ZGDDEr+r5do46dXEbzkZb3Y=
|
||||||
github.com/containers/buildah v1.28.1-0.20221029151733-c2cf9fa47ab6/go.mod h1:skMuWv4FIebpsAFT7fBv2Ll0e0w2j71IUWCIrw9iTV0=
|
github.com/containers/buildah v1.28.1-0.20221029151733-c2cf9fa47ab6/go.mod h1:skMuWv4FIebpsAFT7fBv2Ll0e0w2j71IUWCIrw9iTV0=
|
||||||
github.com/containers/common v0.50.2-0.20221104122933-582fadb8228b h1:/WN9Tlng1xWqr56U2sOSLM5b1Q8DF2gr87jI+fjEA04=
|
github.com/containers/common v0.50.2-0.20221109162103-1e40f47dd90b h1:Hnd2R1izztqrDJsyFSKvbzXW3jWxLyqjEmcCubeOIn0=
|
||||||
github.com/containers/common v0.50.2-0.20221104122933-582fadb8228b/go.mod h1:XLXycBIzTc4yNU6VzqCwgjPt9mtibATtOeXKjlCAsCY=
|
github.com/containers/common v0.50.2-0.20221109162103-1e40f47dd90b/go.mod h1:Nbv796IlIsJ6h8zFhNAn2hTXzVUICfiKS8vi3og41oA=
|
||||||
github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg=
|
github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg=
|
||||||
github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
|
github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
|
||||||
github.com/containers/image/v5 v5.23.1-0.20221101011818-2f770d6d5a0c h1:Jm6GiccEre7O+KohztmIBlduJdYPvzEhhjUuUczZivQ=
|
github.com/containers/image/v5 v5.23.1-0.20221101011818-2f770d6d5a0c h1:Jm6GiccEre7O+KohztmIBlduJdYPvzEhhjUuUczZivQ=
|
||||||
|
|
@ -729,7 +729,7 @@ github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vv
|
||||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||||
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
||||||
github.com/onsi/ginkgo/v2 v2.4.0 h1:+Ig9nvqgS5OBSACXNk15PLdp0U9XPYROt9CFzVdFGIs=
|
github.com/onsi/ginkgo/v2 v2.5.0 h1:TRtrvv2vdQqzkwrQ1ke6vtXf7IK34RBUJafIy1wMwls=
|
||||||
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
|
|
@ -1319,8 +1319,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
|
||||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
|
golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
|
||||||
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/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
|
|
||||||
|
|
@ -245,10 +245,12 @@ var _ = Describe("Podman ps", func() {
|
||||||
_, ec, _ := podmanTest.RunLsContainer("test1")
|
_, ec, _ := podmanTest.RunLsContainer("test1")
|
||||||
Expect(ec).To(Equal(0))
|
Expect(ec).To(Equal(0))
|
||||||
|
|
||||||
result := podmanTest.Podman([]string{"ps", "-a", "--ns", "--format", "json"})
|
result := podmanTest.Podman([]string{"ps", "-a", "--ns", "--format", "{{ json . }}"})
|
||||||
result.WaitWithDefaultTimeout()
|
result.WaitWithDefaultTimeout()
|
||||||
Expect(result).Should(Exit(0))
|
Expect(result).Should(Exit(0))
|
||||||
Expect(result.OutputToString()).To(BeValidJSON())
|
Expect(result.OutputToString()).To(BeValidJSON())
|
||||||
|
// https://github.com/containers/podman/issues/16436
|
||||||
|
Expect(result.OutputToString()).To(HavePrefix("{"), "test for single json object and not array see #16436")
|
||||||
})
|
})
|
||||||
|
|
||||||
It("podman ps json format Created field is int64", func() {
|
It("podman ps json format Created field is int64", func() {
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,12 @@ var _ = Describe("podman system df", func() {
|
||||||
Expect(session).Should(Exit(0))
|
Expect(session).Should(Exit(0))
|
||||||
Expect(session.OutputToString()).To(ContainSubstring("Size"))
|
Expect(session.OutputToString()).To(ContainSubstring("Size"))
|
||||||
Expect(session.OutputToString()).To(ContainSubstring("Reclaimable"))
|
Expect(session.OutputToString()).To(ContainSubstring("Reclaimable"))
|
||||||
Expect(session.OutputToString()).To(BeValidJSON())
|
|
||||||
|
// Note: {{ json . }} returns one json object per line, this matches docker!
|
||||||
|
for i, out := range session.OutputToStringArray() {
|
||||||
|
Expect(out).To(BeValidJSON(), "line %d failed to be parsed", i)
|
||||||
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
It("podman system df --format with --verbose", func() {
|
It("podman system df --format with --verbose", func() {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,12 @@
|
||||||
package report
|
package report
|
||||||
|
|
||||||
import "regexp"
|
import (
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
var jsonRegex = regexp.MustCompile(`^\s*(json|{{\s*json\s*(\.)?\s*}})\s*$`)
|
// Check for json, {{json }} and {{ json. }} which are not valid go template,
|
||||||
|
// {{json .}} is valid and thus not matched to let the template handle it like docker does.
|
||||||
|
var jsonRegex = regexp.MustCompile(`^\s*(json|{{\s*json\.?\s*}})\s*$`)
|
||||||
|
|
||||||
// JSONFormat test CLI --format string to be a JSON request
|
// JSONFormat test CLI --format string to be a JSON request
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"os/user"
|
"os/user"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -289,11 +290,24 @@ func ValidateAndConfigure(uri *url.URL, iden string, insecureIsMachineConnection
|
||||||
keyFilePath := filepath.Join(homedir.Get(), ".ssh", "known_hosts")
|
keyFilePath := filepath.Join(homedir.Get(), ".ssh", "known_hosts")
|
||||||
known, err := knownhosts.New(keyFilePath)
|
known, err := knownhosts.New(keyFilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, os.ErrNotExist) {
|
if !errors.Is(err, os.ErrNotExist) {
|
||||||
logrus.Warn("please create a known_hosts file. The next time this host is connected to, podman will add it to known_hosts")
|
return err
|
||||||
return nil
|
}
|
||||||
|
keyDir := path.Dir(keyFilePath)
|
||||||
|
if _, err := os.Stat(keyDir); errors.Is(err, os.ErrNotExist) {
|
||||||
|
if err := os.Mkdir(keyDir, 0o700); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
k, err := os.OpenFile(keyFilePath, os.O_RDWR|os.O_CREATE, 0o600)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
k.Close()
|
||||||
|
known, err = knownhosts.New(keyFilePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
// we need to check if there is an error from reading known hosts for this public key and if there is an error, what is it, and why is it happening?
|
// we need to check if there is an error from reading known hosts for this public key and if there is an error, what is it, and why is it happening?
|
||||||
// if it is a key mismatch we want to error since we know the host using another key
|
// if it is a key mismatch we want to error since we know the host using another key
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ package inspector
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
|
"math"
|
||||||
|
|
||||||
"golang.org/x/tools/internal/typeparams"
|
"golang.org/x/tools/internal/typeparams"
|
||||||
)
|
)
|
||||||
|
|
@ -218,7 +219,7 @@ func typeOf(n ast.Node) uint64 {
|
||||||
|
|
||||||
func maskOf(nodes []ast.Node) uint64 {
|
func maskOf(nodes []ast.Node) uint64 {
|
||||||
if nodes == nil {
|
if nodes == nil {
|
||||||
return 1<<64 - 1 // match all node types
|
return math.MaxUint64 // match all node types
|
||||||
}
|
}
|
||||||
var mask uint64
|
var mask uint64
|
||||||
for _, n := range nodes {
|
for _, n := range nodes {
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,11 @@ func NewReader(r io.Reader) (io.Reader, error) {
|
||||||
|
|
||||||
// Read reads export data from in, decodes it, and returns type
|
// Read reads export data from in, decodes it, and returns type
|
||||||
// information for the package.
|
// information for the package.
|
||||||
// The package name is specified by path.
|
//
|
||||||
|
// The package path (effectively its linker symbol prefix) is
|
||||||
|
// specified by path, since unlike the package name, this information
|
||||||
|
// may not be recorded in the export data.
|
||||||
|
//
|
||||||
// File position information is added to fset.
|
// File position information is added to fset.
|
||||||
//
|
//
|
||||||
// Read may inspect and add to the imports map to ensure that references
|
// Read may inspect and add to the imports map to ensure that references
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,8 @@ const (
|
||||||
iexportVersionPosCol = 1
|
iexportVersionPosCol = 1
|
||||||
iexportVersionGo1_18 = 2
|
iexportVersionGo1_18 = 2
|
||||||
iexportVersionGenerics = 2
|
iexportVersionGenerics = 2
|
||||||
|
|
||||||
|
iexportVersionCurrent = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
type ident struct {
|
type ident struct {
|
||||||
|
|
@ -96,7 +98,7 @@ func IImportBundle(fset *token.FileSet, imports map[string]*types.Package, data
|
||||||
}
|
}
|
||||||
|
|
||||||
func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data []byte, bundle bool, path string) (pkgs []*types.Package, err error) {
|
func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data []byte, bundle bool, path string) (pkgs []*types.Package, err error) {
|
||||||
const currentVersion = 1
|
const currentVersion = iexportVersionCurrent
|
||||||
version := int64(-1)
|
version := int64(-1)
|
||||||
if !debug {
|
if !debug {
|
||||||
defer func() {
|
defer func() {
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,12 @@ type pkgReader struct {
|
||||||
// laterFns holds functions that need to be invoked at the end of
|
// laterFns holds functions that need to be invoked at the end of
|
||||||
// import reading.
|
// import reading.
|
||||||
laterFns []func()
|
laterFns []func()
|
||||||
|
// laterFors is used in case of 'type A B' to ensure that B is processed before A.
|
||||||
|
laterFors map[types.Type]int
|
||||||
|
|
||||||
|
// ifaces holds a list of constructed Interfaces, which need to have
|
||||||
|
// Complete called after importing is done.
|
||||||
|
ifaces []*types.Interface
|
||||||
}
|
}
|
||||||
|
|
||||||
// later adds a function to be invoked at the end of import reading.
|
// later adds a function to be invoked at the end of import reading.
|
||||||
|
|
@ -63,6 +69,15 @@ func UImportData(fset *token.FileSet, imports map[string]*types.Package, data []
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// laterFor adds a function to be invoked at the end of import reading, and records the type that function is finishing.
|
||||||
|
func (pr *pkgReader) laterFor(t types.Type, fn func()) {
|
||||||
|
if pr.laterFors == nil {
|
||||||
|
pr.laterFors = make(map[types.Type]int)
|
||||||
|
}
|
||||||
|
pr.laterFors[t] = len(pr.laterFns)
|
||||||
|
pr.laterFns = append(pr.laterFns, fn)
|
||||||
|
}
|
||||||
|
|
||||||
// readUnifiedPackage reads a package description from the given
|
// readUnifiedPackage reads a package description from the given
|
||||||
// unified IR export data decoder.
|
// unified IR export data decoder.
|
||||||
func readUnifiedPackage(fset *token.FileSet, ctxt *types.Context, imports map[string]*types.Package, input pkgbits.PkgDecoder) *types.Package {
|
func readUnifiedPackage(fset *token.FileSet, ctxt *types.Context, imports map[string]*types.Package, input pkgbits.PkgDecoder) *types.Package {
|
||||||
|
|
@ -102,6 +117,10 @@ func readUnifiedPackage(fset *token.FileSet, ctxt *types.Context, imports map[st
|
||||||
fn()
|
fn()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, iface := range pr.ifaces {
|
||||||
|
iface.Complete()
|
||||||
|
}
|
||||||
|
|
||||||
pkg.MarkComplete()
|
pkg.MarkComplete()
|
||||||
return pkg
|
return pkg
|
||||||
}
|
}
|
||||||
|
|
@ -231,11 +250,35 @@ func (r *reader) doPkg() *types.Package {
|
||||||
for i := range imports {
|
for i := range imports {
|
||||||
imports[i] = r.pkg()
|
imports[i] = r.pkg()
|
||||||
}
|
}
|
||||||
pkg.SetImports(imports)
|
pkg.SetImports(flattenImports(imports))
|
||||||
|
|
||||||
return pkg
|
return pkg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// flattenImports returns the transitive closure of all imported
|
||||||
|
// packages rooted from pkgs.
|
||||||
|
func flattenImports(pkgs []*types.Package) []*types.Package {
|
||||||
|
var res []*types.Package
|
||||||
|
|
||||||
|
seen := make(map[*types.Package]bool)
|
||||||
|
var add func(pkg *types.Package)
|
||||||
|
add = func(pkg *types.Package) {
|
||||||
|
if seen[pkg] {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
seen[pkg] = true
|
||||||
|
res = append(res, pkg)
|
||||||
|
for _, imp := range pkg.Imports() {
|
||||||
|
add(imp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pkg := range pkgs {
|
||||||
|
add(pkg)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
// @@@ Types
|
// @@@ Types
|
||||||
|
|
||||||
func (r *reader) typ() types.Type {
|
func (r *reader) typ() types.Type {
|
||||||
|
|
@ -372,6 +415,16 @@ func (r *reader) interfaceType() *types.Interface {
|
||||||
if implicit {
|
if implicit {
|
||||||
iface.MarkImplicit()
|
iface.MarkImplicit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We need to call iface.Complete(), but if there are any embedded
|
||||||
|
// defined types, then we may not have set their underlying
|
||||||
|
// interface type yet. So we need to defer calling Complete until
|
||||||
|
// after we've called SetUnderlying everywhere.
|
||||||
|
//
|
||||||
|
// TODO(mdempsky): After CL 424876 lands, it should be safe to call
|
||||||
|
// iface.Complete() immediately.
|
||||||
|
r.p.ifaces = append(r.p.ifaces, iface)
|
||||||
|
|
||||||
return iface
|
return iface
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -477,13 +530,41 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
|
||||||
|
|
||||||
named.SetTypeParams(r.typeParamNames())
|
named.SetTypeParams(r.typeParamNames())
|
||||||
|
|
||||||
// TODO(mdempsky): Rewrite receiver types to underlying is an
|
|
||||||
// Interface? The go/types importer does this (I think because
|
|
||||||
// unit tests expected that), but cmd/compile doesn't care
|
|
||||||
// about it, so maybe we can avoid worrying about that here.
|
|
||||||
rhs := r.typ()
|
rhs := r.typ()
|
||||||
r.p.later(func() {
|
pk := r.p
|
||||||
|
pk.laterFor(named, func() {
|
||||||
|
// First be sure that the rhs is initialized, if it needs to be initialized.
|
||||||
|
delete(pk.laterFors, named) // prevent cycles
|
||||||
|
if i, ok := pk.laterFors[rhs]; ok {
|
||||||
|
f := pk.laterFns[i]
|
||||||
|
pk.laterFns[i] = func() {} // function is running now, so replace it with a no-op
|
||||||
|
f() // initialize RHS
|
||||||
|
}
|
||||||
underlying := rhs.Underlying()
|
underlying := rhs.Underlying()
|
||||||
|
|
||||||
|
// If the underlying type is an interface, we need to
|
||||||
|
// duplicate its methods so we can replace the receiver
|
||||||
|
// parameter's type (#49906).
|
||||||
|
if iface, ok := underlying.(*types.Interface); ok && iface.NumExplicitMethods() != 0 {
|
||||||
|
methods := make([]*types.Func, iface.NumExplicitMethods())
|
||||||
|
for i := range methods {
|
||||||
|
fn := iface.ExplicitMethod(i)
|
||||||
|
sig := fn.Type().(*types.Signature)
|
||||||
|
|
||||||
|
recv := types.NewVar(fn.Pos(), fn.Pkg(), "", named)
|
||||||
|
methods[i] = types.NewFunc(fn.Pos(), fn.Pkg(), fn.Name(), types.NewSignature(recv, sig.Params(), sig.Results(), sig.Variadic()))
|
||||||
|
}
|
||||||
|
|
||||||
|
embeds := make([]types.Type, iface.NumEmbeddeds())
|
||||||
|
for i := range embeds {
|
||||||
|
embeds[i] = iface.EmbeddedType(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
newIface := types.NewInterfaceType(methods, embeds)
|
||||||
|
r.p.ifaces = append(r.p.ifaces, newIface)
|
||||||
|
underlying = newIface
|
||||||
|
}
|
||||||
|
|
||||||
named.SetUnderlying(underlying)
|
named.SetUnderlying(underlying)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/constant"
|
"go/constant"
|
||||||
"go/token"
|
"go/token"
|
||||||
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
@ -94,7 +95,7 @@ func NewPkgDecoder(pkgPath, input string) PkgDecoder {
|
||||||
pr.elemEnds = make([]uint32, pr.elemEndsEnds[len(pr.elemEndsEnds)-1])
|
pr.elemEnds = make([]uint32, pr.elemEndsEnds[len(pr.elemEndsEnds)-1])
|
||||||
assert(binary.Read(r, binary.LittleEndian, pr.elemEnds[:]) == nil)
|
assert(binary.Read(r, binary.LittleEndian, pr.elemEnds[:]) == nil)
|
||||||
|
|
||||||
pos, err := r.Seek(0, os.SEEK_CUR)
|
pos, err := r.Seek(0, io.SeekCurrent)
|
||||||
assert(err == nil)
|
assert(err == nil)
|
||||||
|
|
||||||
pr.elemData = input[pos:]
|
pr.elemData = input[pos:]
|
||||||
|
|
@ -237,7 +238,7 @@ func (r *Decoder) Sync(mWant SyncMarker) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
pos, _ := r.Data.Seek(0, os.SEEK_CUR) // TODO(mdempsky): io.SeekCurrent after #44505 is resolved
|
pos, _ := r.Data.Seek(0, io.SeekCurrent)
|
||||||
mHave := SyncMarker(r.rawUvarint())
|
mHave := SyncMarker(r.rawUvarint())
|
||||||
writerPCs := make([]int, r.rawUvarint())
|
writerPCs := make([]int, r.rawUvarint())
|
||||||
for i := range writerPCs {
|
for i := range writerPCs {
|
||||||
|
|
|
||||||
|
|
@ -147,8 +147,9 @@ func (pw *PkgEncoder) NewEncoderRaw(k RelocKind) Encoder {
|
||||||
type Encoder struct {
|
type Encoder struct {
|
||||||
p *PkgEncoder
|
p *PkgEncoder
|
||||||
|
|
||||||
Relocs []RelocEnt
|
Relocs []RelocEnt
|
||||||
Data bytes.Buffer // accumulated element bitstream data
|
RelocMap map[RelocEnt]uint32
|
||||||
|
Data bytes.Buffer // accumulated element bitstream data
|
||||||
|
|
||||||
encodingRelocHeader bool
|
encodingRelocHeader bool
|
||||||
|
|
||||||
|
|
@ -210,15 +211,18 @@ func (w *Encoder) rawVarint(x int64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Encoder) rawReloc(r RelocKind, idx Index) int {
|
func (w *Encoder) rawReloc(r RelocKind, idx Index) int {
|
||||||
// TODO(mdempsky): Use map for lookup; this takes quadratic time.
|
e := RelocEnt{r, idx}
|
||||||
for i, rEnt := range w.Relocs {
|
if w.RelocMap != nil {
|
||||||
if rEnt.Kind == r && rEnt.Idx == idx {
|
if i, ok := w.RelocMap[e]; ok {
|
||||||
return i
|
return int(i)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
w.RelocMap = make(map[RelocEnt]uint32)
|
||||||
}
|
}
|
||||||
|
|
||||||
i := len(w.Relocs)
|
i := len(w.Relocs)
|
||||||
w.Relocs = append(w.Relocs, RelocEnt{r, idx})
|
w.RelocMap[e] = uint32(i)
|
||||||
|
w.Relocs = append(w.Relocs, e)
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,11 @@
|
||||||
package pkgbits
|
package pkgbits
|
||||||
|
|
||||||
// A RelocKind indicates a particular section within a unified IR export.
|
// A RelocKind indicates a particular section within a unified IR export.
|
||||||
type RelocKind int
|
type RelocKind int32
|
||||||
|
|
||||||
// An Index represents a bitstream element index within a particular
|
// An Index represents a bitstream element index within a particular
|
||||||
// section.
|
// section.
|
||||||
type Index int
|
type Index int32
|
||||||
|
|
||||||
// A relocEnt (relocation entry) is an entry in an element's local
|
// A relocEnt (relocation entry) is an entry in an element's local
|
||||||
// reference table.
|
// reference table.
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ func (r *responseDeduper) addAll(dr *driverResponse) {
|
||||||
for _, root := range dr.Roots {
|
for _, root := range dr.Roots {
|
||||||
r.addRoot(root)
|
r.addRoot(root)
|
||||||
}
|
}
|
||||||
|
r.dr.GoVersion = dr.GoVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *responseDeduper) addPackage(p *Package) {
|
func (r *responseDeduper) addPackage(p *Package) {
|
||||||
|
|
@ -454,11 +455,14 @@ func (state *golistState) createDriverResponse(words ...string) (*driverResponse
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
seen := make(map[string]*jsonPackage)
|
seen := make(map[string]*jsonPackage)
|
||||||
pkgs := make(map[string]*Package)
|
pkgs := make(map[string]*Package)
|
||||||
additionalErrors := make(map[string][]Error)
|
additionalErrors := make(map[string][]Error)
|
||||||
// Decode the JSON and convert it to Package form.
|
// Decode the JSON and convert it to Package form.
|
||||||
var response driverResponse
|
response := &driverResponse{
|
||||||
|
GoVersion: goVersion,
|
||||||
|
}
|
||||||
for dec := json.NewDecoder(buf); dec.More(); {
|
for dec := json.NewDecoder(buf); dec.More(); {
|
||||||
p := new(jsonPackage)
|
p := new(jsonPackage)
|
||||||
if err := dec.Decode(p); err != nil {
|
if err := dec.Decode(p); err != nil {
|
||||||
|
|
@ -730,7 +734,7 @@ func (state *golistState) createDriverResponse(words ...string) (*driverResponse
|
||||||
}
|
}
|
||||||
sort.Slice(response.Packages, func(i, j int) bool { return response.Packages[i].ID < response.Packages[j].ID })
|
sort.Slice(response.Packages, func(i, j int) bool { return response.Packages[i].ID < response.Packages[j].ID })
|
||||||
|
|
||||||
return &response, nil
|
return response, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (state *golistState) shouldAddFilenameFromError(p *jsonPackage) bool {
|
func (state *golistState) shouldAddFilenameFromError(p *jsonPackage) bool {
|
||||||
|
|
@ -756,6 +760,7 @@ func (state *golistState) shouldAddFilenameFromError(p *jsonPackage) bool {
|
||||||
return len(p.Error.ImportStack) == 0 || p.Error.ImportStack[len(p.Error.ImportStack)-1] == p.ImportPath
|
return len(p.Error.ImportStack) == 0 || p.Error.ImportStack[len(p.Error.ImportStack)-1] == p.ImportPath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getGoVersion returns the effective minor version of the go command.
|
||||||
func (state *golistState) getGoVersion() (int, error) {
|
func (state *golistState) getGoVersion() (int, error) {
|
||||||
state.goVersionOnce.Do(func() {
|
state.goVersionOnce.Do(func() {
|
||||||
state.goVersion, state.goVersionError = gocommand.GoVersion(state.ctx, state.cfgInvocation(), state.cfg.gocmdRunner)
|
state.goVersion, state.goVersionError = gocommand.GoVersion(state.ctx, state.cfgInvocation(), state.cfg.gocmdRunner)
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -233,6 +234,11 @@ type driverResponse struct {
|
||||||
// Imports will be connected and then type and syntax information added in a
|
// Imports will be connected and then type and syntax information added in a
|
||||||
// later pass (see refine).
|
// later pass (see refine).
|
||||||
Packages []*Package
|
Packages []*Package
|
||||||
|
|
||||||
|
// GoVersion is the minor version number used by the driver
|
||||||
|
// (e.g. the go command on the PATH) when selecting .go files.
|
||||||
|
// Zero means unknown.
|
||||||
|
GoVersion int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load loads and returns the Go packages named by the given patterns.
|
// Load loads and returns the Go packages named by the given patterns.
|
||||||
|
|
@ -256,7 +262,7 @@ func Load(cfg *Config, patterns ...string) ([]*Package, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
l.sizes = response.Sizes
|
l.sizes = response.Sizes
|
||||||
return l.refine(response.Roots, response.Packages...)
|
return l.refine(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
// defaultDriver is a driver that implements go/packages' fallback behavior.
|
// defaultDriver is a driver that implements go/packages' fallback behavior.
|
||||||
|
|
@ -532,6 +538,7 @@ type loaderPackage struct {
|
||||||
needsrc bool // load from source (Mode >= LoadTypes)
|
needsrc bool // load from source (Mode >= LoadTypes)
|
||||||
needtypes bool // type information is either requested or depended on
|
needtypes bool // type information is either requested or depended on
|
||||||
initial bool // package was matched by a pattern
|
initial bool // package was matched by a pattern
|
||||||
|
goVersion int // minor version number of go command on PATH
|
||||||
}
|
}
|
||||||
|
|
||||||
// loader holds the working state of a single call to load.
|
// loader holds the working state of a single call to load.
|
||||||
|
|
@ -618,7 +625,8 @@ func newLoader(cfg *Config) *loader {
|
||||||
|
|
||||||
// refine connects the supplied packages into a graph and then adds type and
|
// refine connects the supplied packages into a graph and then adds type and
|
||||||
// and syntax information as requested by the LoadMode.
|
// and syntax information as requested by the LoadMode.
|
||||||
func (ld *loader) refine(roots []string, list ...*Package) ([]*Package, error) {
|
func (ld *loader) refine(response *driverResponse) ([]*Package, error) {
|
||||||
|
roots := response.Roots
|
||||||
rootMap := make(map[string]int, len(roots))
|
rootMap := make(map[string]int, len(roots))
|
||||||
for i, root := range roots {
|
for i, root := range roots {
|
||||||
rootMap[root] = i
|
rootMap[root] = i
|
||||||
|
|
@ -626,7 +634,7 @@ func (ld *loader) refine(roots []string, list ...*Package) ([]*Package, error) {
|
||||||
ld.pkgs = make(map[string]*loaderPackage)
|
ld.pkgs = make(map[string]*loaderPackage)
|
||||||
// first pass, fixup and build the map and roots
|
// first pass, fixup and build the map and roots
|
||||||
var initial = make([]*loaderPackage, len(roots))
|
var initial = make([]*loaderPackage, len(roots))
|
||||||
for _, pkg := range list {
|
for _, pkg := range response.Packages {
|
||||||
rootIndex := -1
|
rootIndex := -1
|
||||||
if i, found := rootMap[pkg.ID]; found {
|
if i, found := rootMap[pkg.ID]; found {
|
||||||
rootIndex = i
|
rootIndex = i
|
||||||
|
|
@ -648,6 +656,7 @@ func (ld *loader) refine(roots []string, list ...*Package) ([]*Package, error) {
|
||||||
Package: pkg,
|
Package: pkg,
|
||||||
needtypes: needtypes,
|
needtypes: needtypes,
|
||||||
needsrc: needsrc,
|
needsrc: needsrc,
|
||||||
|
goVersion: response.GoVersion,
|
||||||
}
|
}
|
||||||
ld.pkgs[lpkg.ID] = lpkg
|
ld.pkgs[lpkg.ID] = lpkg
|
||||||
if rootIndex >= 0 {
|
if rootIndex >= 0 {
|
||||||
|
|
@ -923,6 +932,33 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) {
|
||||||
lpkg.Errors = append(lpkg.Errors, errs...)
|
lpkg.Errors = append(lpkg.Errors, errs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the go command on the PATH is newer than the runtime,
|
||||||
|
// then the go/{scanner,ast,parser,types} packages from the
|
||||||
|
// standard library may be unable to process the files
|
||||||
|
// selected by go list.
|
||||||
|
//
|
||||||
|
// There is currently no way to downgrade the effective
|
||||||
|
// version of the go command (see issue 52078), so we proceed
|
||||||
|
// with the newer go command but, in case of parse or type
|
||||||
|
// errors, we emit an additional diagnostic.
|
||||||
|
//
|
||||||
|
// See:
|
||||||
|
// - golang.org/issue/52078 (flag to set release tags)
|
||||||
|
// - golang.org/issue/50825 (gopls legacy version support)
|
||||||
|
// - golang.org/issue/55883 (go/packages confusing error)
|
||||||
|
var runtimeVersion int
|
||||||
|
if _, err := fmt.Sscanf(runtime.Version(), "go1.%d", &runtimeVersion); err == nil && runtimeVersion < lpkg.goVersion {
|
||||||
|
defer func() {
|
||||||
|
if len(lpkg.Errors) > 0 {
|
||||||
|
appendError(Error{
|
||||||
|
Pos: "-",
|
||||||
|
Msg: fmt.Sprintf("This application uses version go1.%d of the source-processing packages but runs version go1.%d of 'go list'. It may fail to process source files that rely on newer language features. If so, rebuild the application using a newer version of Go.", runtimeVersion, lpkg.goVersion),
|
||||||
|
Kind: UnknownError,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
if ld.Config.Mode&NeedTypes != 0 && len(lpkg.CompiledGoFiles) == 0 && lpkg.ExportFile != "" {
|
if ld.Config.Mode&NeedTypes != 0 && len(lpkg.CompiledGoFiles) == 0 && lpkg.ExportFile != "" {
|
||||||
// The config requested loading sources and types, but sources are missing.
|
// The config requested loading sources and types, but sources are missing.
|
||||||
// Add an error to the package and fall back to loading from export data.
|
// Add an error to the package and fall back to loading from export data.
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,10 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
@ -232,6 +234,12 @@ func (i *Invocation) run(ctx context.Context, stdout, stderr io.Writer) error {
|
||||||
return runCmdContext(ctx, cmd)
|
return runCmdContext(ctx, cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DebugHangingGoCommands may be set by tests to enable additional
|
||||||
|
// instrumentation (including panics) for debugging hanging Go commands.
|
||||||
|
//
|
||||||
|
// See golang/go#54461 for details.
|
||||||
|
var DebugHangingGoCommands = false
|
||||||
|
|
||||||
// runCmdContext is like exec.CommandContext except it sends os.Interrupt
|
// runCmdContext is like exec.CommandContext except it sends os.Interrupt
|
||||||
// before os.Kill.
|
// before os.Kill.
|
||||||
func runCmdContext(ctx context.Context, cmd *exec.Cmd) error {
|
func runCmdContext(ctx context.Context, cmd *exec.Cmd) error {
|
||||||
|
|
@ -243,11 +251,24 @@ func runCmdContext(ctx context.Context, cmd *exec.Cmd) error {
|
||||||
resChan <- cmd.Wait()
|
resChan <- cmd.Wait()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
select {
|
// If we're interested in debugging hanging Go commands, stop waiting after a
|
||||||
case err := <-resChan:
|
// minute and panic with interesting information.
|
||||||
return err
|
if DebugHangingGoCommands {
|
||||||
case <-ctx.Done():
|
select {
|
||||||
|
case err := <-resChan:
|
||||||
|
return err
|
||||||
|
case <-time.After(1 * time.Minute):
|
||||||
|
HandleHangingGoCommand(cmd.Process)
|
||||||
|
case <-ctx.Done():
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
select {
|
||||||
|
case err := <-resChan:
|
||||||
|
return err
|
||||||
|
case <-ctx.Done():
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cancelled. Interrupt and see if it ends voluntarily.
|
// Cancelled. Interrupt and see if it ends voluntarily.
|
||||||
cmd.Process.Signal(os.Interrupt)
|
cmd.Process.Signal(os.Interrupt)
|
||||||
select {
|
select {
|
||||||
|
|
@ -255,11 +276,63 @@ func runCmdContext(ctx context.Context, cmd *exec.Cmd) error {
|
||||||
return err
|
return err
|
||||||
case <-time.After(time.Second):
|
case <-time.After(time.Second):
|
||||||
}
|
}
|
||||||
|
|
||||||
// Didn't shut down in response to interrupt. Kill it hard.
|
// Didn't shut down in response to interrupt. Kill it hard.
|
||||||
cmd.Process.Kill()
|
// TODO(rfindley): per advice from bcmills@, it may be better to send SIGQUIT
|
||||||
|
// on certain platforms, such as unix.
|
||||||
|
if err := cmd.Process.Kill(); err != nil && DebugHangingGoCommands {
|
||||||
|
// Don't panic here as this reliably fails on windows with EINVAL.
|
||||||
|
log.Printf("error killing the Go command: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// See above: don't wait indefinitely if we're debugging hanging Go commands.
|
||||||
|
if DebugHangingGoCommands {
|
||||||
|
select {
|
||||||
|
case err := <-resChan:
|
||||||
|
return err
|
||||||
|
case <-time.After(10 * time.Second): // a shorter wait as resChan should return quickly following Kill
|
||||||
|
HandleHangingGoCommand(cmd.Process)
|
||||||
|
}
|
||||||
|
}
|
||||||
return <-resChan
|
return <-resChan
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func HandleHangingGoCommand(proc *os.Process) {
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "linux", "darwin", "freebsd", "netbsd":
|
||||||
|
fmt.Fprintln(os.Stderr, `DETECTED A HANGING GO COMMAND
|
||||||
|
|
||||||
|
The gopls test runner has detected a hanging go command. In order to debug
|
||||||
|
this, the output of ps and lsof/fstat is printed below.
|
||||||
|
|
||||||
|
See golang/go#54461 for more details.`)
|
||||||
|
|
||||||
|
fmt.Fprintln(os.Stderr, "\nps axo ppid,pid,command:")
|
||||||
|
fmt.Fprintln(os.Stderr, "-------------------------")
|
||||||
|
psCmd := exec.Command("ps", "axo", "ppid,pid,command")
|
||||||
|
psCmd.Stdout = os.Stderr
|
||||||
|
psCmd.Stderr = os.Stderr
|
||||||
|
if err := psCmd.Run(); err != nil {
|
||||||
|
panic(fmt.Sprintf("running ps: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
listFiles := "lsof"
|
||||||
|
if runtime.GOOS == "freebsd" || runtime.GOOS == "netbsd" {
|
||||||
|
listFiles = "fstat"
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintln(os.Stderr, "\n"+listFiles+":")
|
||||||
|
fmt.Fprintln(os.Stderr, "-----")
|
||||||
|
listFilesCmd := exec.Command(listFiles)
|
||||||
|
listFilesCmd.Stdout = os.Stderr
|
||||||
|
listFilesCmd.Stderr = os.Stderr
|
||||||
|
if err := listFilesCmd.Run(); err != nil {
|
||||||
|
panic(fmt.Sprintf("running %s: %v", listFiles, err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic(fmt.Sprintf("detected hanging go command (pid %d): see golang/go#54461 for more details", proc.Pid))
|
||||||
|
}
|
||||||
|
|
||||||
func cmdDebugStr(cmd *exec.Cmd) string {
|
func cmdDebugStr(cmd *exec.Cmd) string {
|
||||||
env := make(map[string]string)
|
env := make(map[string]string)
|
||||||
for _, kv := range cmd.Env {
|
for _, kv := range cmd.Env {
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,15 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GoVersion checks the go version by running "go list" with modules off.
|
// GoVersion reports the minor version number of the highest release
|
||||||
// It returns the X in Go 1.X.
|
// tag built into the go command on the PATH.
|
||||||
|
//
|
||||||
|
// Note that this may be higher than the version of the go tool used
|
||||||
|
// to build this application, and thus the versions of the standard
|
||||||
|
// go/{scanner,parser,ast,types} packages that are linked into it.
|
||||||
|
// In that case, callers should either downgrade to the version of
|
||||||
|
// go used to build the application, or report an error that the
|
||||||
|
// application is too old to use the go command on the PATH.
|
||||||
func GoVersion(ctx context.Context, inv Invocation, r *Runner) (int, error) {
|
func GoVersion(ctx context.Context, inv Invocation, r *Runner) (int, error) {
|
||||||
inv.Verb = "list"
|
inv.Verb = "list"
|
||||||
inv.Args = []string{"-e", "-f", `{{context.ReleaseTags}}`, `--`, `unsafe`}
|
inv.Args = []string{"-e", "-f", `{{context.ReleaseTags}}`, `--`, `unsafe`}
|
||||||
|
|
@ -38,7 +45,7 @@ func GoVersion(ctx context.Context, inv Invocation, r *Runner) (int, error) {
|
||||||
if len(stdout) < 3 {
|
if len(stdout) < 3 {
|
||||||
return 0, fmt.Errorf("bad ReleaseTags output: %q", stdout)
|
return 0, fmt.Errorf("bad ReleaseTags output: %q", stdout)
|
||||||
}
|
}
|
||||||
// Split up "[go1.1 go1.15]"
|
// Split up "[go1.1 go1.15]" and return highest go1.X value.
|
||||||
tags := strings.Fields(stdout[1 : len(stdout)-2])
|
tags := strings.Fields(stdout[1 : len(stdout)-2])
|
||||||
for i := len(tags) - 1; i >= 0; i-- {
|
for i := len(tags) - 1; i >= 0; i-- {
|
||||||
var version int
|
var version int
|
||||||
|
|
|
||||||
|
|
@ -118,7 +118,7 @@ github.com/containers/buildah/pkg/rusage
|
||||||
github.com/containers/buildah/pkg/sshagent
|
github.com/containers/buildah/pkg/sshagent
|
||||||
github.com/containers/buildah/pkg/util
|
github.com/containers/buildah/pkg/util
|
||||||
github.com/containers/buildah/util
|
github.com/containers/buildah/util
|
||||||
# github.com/containers/common v0.50.2-0.20221104122933-582fadb8228b
|
# github.com/containers/common v0.50.2-0.20221109162103-1e40f47dd90b
|
||||||
## explicit; go 1.17
|
## explicit; go 1.17
|
||||||
github.com/containers/common/libimage
|
github.com/containers/common/libimage
|
||||||
github.com/containers/common/libimage/define
|
github.com/containers/common/libimage/define
|
||||||
|
|
@ -855,7 +855,7 @@ golang.org/x/text/secure/bidirule
|
||||||
golang.org/x/text/transform
|
golang.org/x/text/transform
|
||||||
golang.org/x/text/unicode/bidi
|
golang.org/x/text/unicode/bidi
|
||||||
golang.org/x/text/unicode/norm
|
golang.org/x/text/unicode/norm
|
||||||
# golang.org/x/tools v0.1.12
|
# golang.org/x/tools v0.2.0
|
||||||
## explicit; go 1.18
|
## explicit; go 1.18
|
||||||
golang.org/x/tools/cmd/stringer
|
golang.org/x/tools/cmd/stringer
|
||||||
golang.org/x/tools/go/ast/inspector
|
golang.org/x/tools/go/ast/inspector
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue