mirror of git://gcc.gnu.org/git/gcc.git
libgo: update to Go1.16rc1
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/287493
This commit is contained in:
parent
91a95ad2ae
commit
726b7aa004
|
@ -1,4 +1,4 @@
|
||||||
83eea1930671ce2bba863582a67f2609bc4f9f36
|
2663206528a6d46cbde60dbccf84c8288707ab8d
|
||||||
|
|
||||||
The first line of this file holds the git revision number of the last
|
The first line of this file holds the git revision number of the last
|
||||||
merge done from the gofrontend repository.
|
merge done from the gofrontend repository.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
2ff33f5e443165e55a080f3a649e4c070c4096d1
|
3e06467282c6d5678a6273747658c04314e013ef
|
||||||
|
|
||||||
The first line of this file holds the git revision number of the
|
The first line of this file holds the git revision number of the
|
||||||
last merge done from the master library sources.
|
last merge done from the master library sources.
|
||||||
|
|
|
@ -656,7 +656,7 @@ noinst_DATA += zdefaultcc.go
|
||||||
|
|
||||||
# Generate the list of go std packages that were included in libgo
|
# Generate the list of go std packages that were included in libgo
|
||||||
zstdpkglist.go: s-zstdpkglist; @true
|
zstdpkglist.go: s-zstdpkglist; @true
|
||||||
s-zstdpkglist: Makefile
|
s-zstdpkglist: Makefile libgo-packages.txt
|
||||||
rm -f zstdpkglist.go.tmp
|
rm -f zstdpkglist.go.tmp
|
||||||
echo 'package goroot' > zstdpkglist.go.tmp
|
echo 'package goroot' > zstdpkglist.go.tmp
|
||||||
echo "" >> zstdpkglist.go.tmp
|
echo "" >> zstdpkglist.go.tmp
|
||||||
|
|
|
@ -2828,7 +2828,7 @@ s-runtime-inc: runtime.lo mkruntimeinc.sh Makefile
|
||||||
|
|
||||||
# Generate the list of go std packages that were included in libgo
|
# Generate the list of go std packages that were included in libgo
|
||||||
zstdpkglist.go: s-zstdpkglist; @true
|
zstdpkglist.go: s-zstdpkglist; @true
|
||||||
s-zstdpkglist: Makefile
|
s-zstdpkglist: Makefile libgo-packages.txt
|
||||||
rm -f zstdpkglist.go.tmp
|
rm -f zstdpkglist.go.tmp
|
||||||
echo 'package goroot' > zstdpkglist.go.tmp
|
echo 'package goroot' > zstdpkglist.go.tmp
|
||||||
echo "" >> zstdpkglist.go.tmp
|
echo "" >> zstdpkglist.go.tmp
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
go1.16beta1
|
go1.16rc1
|
||||||
|
|
|
@ -80,6 +80,7 @@ flag
|
||||||
fmt
|
fmt
|
||||||
go/ast
|
go/ast
|
||||||
go/build
|
go/build
|
||||||
|
go/build/constraint
|
||||||
go/constant
|
go/constant
|
||||||
go/doc
|
go/doc
|
||||||
go/format
|
go/format
|
||||||
|
@ -107,6 +108,7 @@ image/jpeg
|
||||||
image/png
|
image/png
|
||||||
index/suffixarray
|
index/suffixarray
|
||||||
internal/cpu
|
internal/cpu
|
||||||
|
internal/execabs
|
||||||
internal/fmtsort
|
internal/fmtsort
|
||||||
internal/poll
|
internal/poll
|
||||||
internal/profile
|
internal/profile
|
||||||
|
|
|
@ -28,7 +28,7 @@ func isASCII(s string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// toASCII converts the input to an ASCII C-style string.
|
// toASCII converts the input to an ASCII C-style string.
|
||||||
// This a best effort conversion, so invalid characters are dropped.
|
// This is a best effort conversion, so invalid characters are dropped.
|
||||||
func toASCII(s string) string {
|
func toASCII(s string) string {
|
||||||
if isASCII(s) {
|
if isASCII(s) {
|
||||||
return s
|
return s
|
||||||
|
|
|
@ -1567,7 +1567,14 @@ func (p *Package) gccBaseCmd() []string {
|
||||||
func (p *Package) gccMachine() []string {
|
func (p *Package) gccMachine() []string {
|
||||||
switch goarch {
|
switch goarch {
|
||||||
case "amd64":
|
case "amd64":
|
||||||
|
if goos == "darwin" {
|
||||||
|
return []string{"-arch", "x86_64", "-m64"}
|
||||||
|
}
|
||||||
return []string{"-m64"}
|
return []string{"-m64"}
|
||||||
|
case "arm64":
|
||||||
|
if goos == "darwin" {
|
||||||
|
return []string{"-arch", "arm64"}
|
||||||
|
}
|
||||||
case "386":
|
case "386":
|
||||||
return []string{"-m32"}
|
return []string{"-m32"}
|
||||||
case "arm":
|
case "arm":
|
||||||
|
|
|
@ -14,10 +14,10 @@ import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/printer"
|
"go/printer"
|
||||||
"go/token"
|
"go/token"
|
||||||
|
exec "internal/execabs"
|
||||||
"internal/xcoff"
|
"internal/xcoff"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
|
@ -958,9 +958,9 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||||
// Build the wrapper function compiled by gcc.
|
// Build the wrapper function compiled by gcc.
|
||||||
gccExport := ""
|
gccExport := ""
|
||||||
if goos == "windows" {
|
if goos == "windows" {
|
||||||
gccExport = "__declspec(dllexport)"
|
gccExport = "__declspec(dllexport) "
|
||||||
}
|
}
|
||||||
s := fmt.Sprintf("%s %s %s(", gccExport, gccResult, exp.ExpName)
|
s := fmt.Sprintf("%s%s %s(", gccExport, gccResult, exp.ExpName)
|
||||||
if fn.Recv != nil {
|
if fn.Recv != nil {
|
||||||
s += p.cgoType(fn.Recv.List[0].Type).C.String()
|
s += p.cgoType(fn.Recv.List[0].Type).C.String()
|
||||||
s += " recv"
|
s += " recv"
|
||||||
|
|
|
@ -8,9 +8,9 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/token"
|
"go/token"
|
||||||
|
exec "internal/execabs"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// run runs the command argv, feeding in stdin on standard input.
|
// run runs the command argv, feeding in stdin on standard input.
|
||||||
|
@ -63,7 +63,7 @@ func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
|
||||||
p.Env = append(os.Environ(), "TERM=dumb")
|
p.Env = append(os.Environ(), "TERM=dumb")
|
||||||
err := p.Run()
|
err := p.Run()
|
||||||
if _, ok := err.(*exec.ExitError); err != nil && !ok {
|
if _, ok := err.(*exec.ExitError); err != nil && !ok {
|
||||||
fatalf("%s", err)
|
fatalf("exec %s: %s", argv[0], err)
|
||||||
}
|
}
|
||||||
ok = p.ProcessState.Success()
|
ok = p.ProcessState.Success()
|
||||||
stdout, stderr = bout.Bytes(), berr.Bytes()
|
stdout, stderr = bout.Bytes(), berr.Bytes()
|
||||||
|
@ -88,7 +88,7 @@ func fatalf(msg string, args ...interface{}) {
|
||||||
// If we've already printed other errors, they might have
|
// If we've already printed other errors, they might have
|
||||||
// caused the fatal condition. Assume they're enough.
|
// caused the fatal condition. Assume they're enough.
|
||||||
if nerrors == 0 {
|
if nerrors == 0 {
|
||||||
fmt.Fprintf(os.Stderr, msg+"\n", args...)
|
fmt.Fprintf(os.Stderr, "cgo: "+msg+"\n", args...)
|
||||||
}
|
}
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ require (
|
||||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2
|
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2
|
||||||
golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff
|
golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff
|
||||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897
|
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897
|
||||||
golang.org/x/mod v0.4.0
|
golang.org/x/mod v0.4.1
|
||||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88 // indirect
|
golang.org/x/sys v0.0.0-20201204225414-ed752295db88 // indirect
|
||||||
golang.org/x/tools v0.0.0-20201211025543-abf6a1d87e11
|
golang.org/x/tools v0.0.0-20210107193943-4ed967dd8eff
|
||||||
)
|
)
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -216,6 +216,7 @@ func TestMain(m *testing.M) {
|
||||||
}
|
}
|
||||||
// Don't let these environment variables confuse the test.
|
// Don't let these environment variables confuse the test.
|
||||||
os.Setenv("GOENV", "off")
|
os.Setenv("GOENV", "off")
|
||||||
|
os.Unsetenv("GOFLAGS")
|
||||||
os.Unsetenv("GOBIN")
|
os.Unsetenv("GOBIN")
|
||||||
os.Unsetenv("GOPATH")
|
os.Unsetenv("GOPATH")
|
||||||
os.Unsetenv("GIT_ALLOW_PROTOCOL")
|
os.Unsetenv("GIT_ALLOW_PROTOCOL")
|
||||||
|
@ -2655,12 +2656,12 @@ func TestBadCommandLines(t *testing.T) {
|
||||||
tg.tempFile("src/@x/x.go", "package x\n")
|
tg.tempFile("src/@x/x.go", "package x\n")
|
||||||
tg.setenv("GOPATH", tg.path("."))
|
tg.setenv("GOPATH", tg.path("."))
|
||||||
tg.runFail("build", "@x")
|
tg.runFail("build", "@x")
|
||||||
tg.grepStderr("invalid input directory name \"@x\"|cannot use path@version syntax", "did not reject @x directory")
|
tg.grepStderr("invalid input directory name \"@x\"|can only use path@version syntax with 'go get' and 'go install' in module-aware mode", "did not reject @x directory")
|
||||||
|
|
||||||
tg.tempFile("src/@x/y/y.go", "package y\n")
|
tg.tempFile("src/@x/y/y.go", "package y\n")
|
||||||
tg.setenv("GOPATH", tg.path("."))
|
tg.setenv("GOPATH", tg.path("."))
|
||||||
tg.runFail("build", "@x/y")
|
tg.runFail("build", "@x/y")
|
||||||
tg.grepStderr("invalid import path \"@x/y\"|cannot use path@version syntax", "did not reject @x/y import path")
|
tg.grepStderr("invalid import path \"@x/y\"|can only use path@version syntax with 'go get' and 'go install' in module-aware mode", "did not reject @x/y import path")
|
||||||
|
|
||||||
tg.tempFile("src/-x/x.go", "package x\n")
|
tg.tempFile("src/-x/x.go", "package x\n")
|
||||||
tg.setenv("GOPATH", tg.path("."))
|
tg.setenv("GOPATH", tg.path("."))
|
||||||
|
|
|
@ -10,9 +10,9 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
exec "internal/execabs"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,10 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
exec "internal/execabs"
|
||||||
"io"
|
"io"
|
||||||
urlpkg "net/url"
|
urlpkg "net/url"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
|
@ -75,7 +75,8 @@ func runFmt(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
}
|
}
|
||||||
if pkg.Error != nil {
|
if pkg.Error != nil {
|
||||||
var nogo *load.NoGoError
|
var nogo *load.NoGoError
|
||||||
if errors.As(pkg.Error, &nogo) && len(pkg.InternalAllGoFiles()) > 0 {
|
var embed *load.EmbedError
|
||||||
|
if (errors.As(pkg.Error, &nogo) || errors.As(pkg.Error, &embed)) && len(pkg.InternalAllGoFiles()) > 0 {
|
||||||
// Skip this error, as we will format
|
// Skip this error, as we will format
|
||||||
// all files regardless.
|
// all files regardless.
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -12,10 +12,10 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/parser"
|
"go/parser"
|
||||||
"go/token"
|
"go/token"
|
||||||
|
exec "internal/execabs"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -52,15 +52,6 @@ that can be run locally. It must either be in the shell path
|
||||||
(gofmt), a fully qualified path (/usr/you/bin/mytool), or a
|
(gofmt), a fully qualified path (/usr/you/bin/mytool), or a
|
||||||
command alias, described below.
|
command alias, described below.
|
||||||
|
|
||||||
To convey to humans and machine tools that code is generated,
|
|
||||||
generated source should have a line that matches the following
|
|
||||||
regular expression (in Go syntax):
|
|
||||||
|
|
||||||
^// Code generated .* DO NOT EDIT\.$
|
|
||||||
|
|
||||||
The line may appear anywhere in the file, but is typically
|
|
||||||
placed near the beginning so it is easy to find.
|
|
||||||
|
|
||||||
Note that go generate does not parse the file, so lines that look
|
Note that go generate does not parse the file, so lines that look
|
||||||
like directives in comments or multiline strings will be treated
|
like directives in comments or multiline strings will be treated
|
||||||
as directives.
|
as directives.
|
||||||
|
@ -72,6 +63,15 @@ arguments when it is run.
|
||||||
Quoted strings use Go syntax and are evaluated before execution; a
|
Quoted strings use Go syntax and are evaluated before execution; a
|
||||||
quoted string appears as a single argument to the generator.
|
quoted string appears as a single argument to the generator.
|
||||||
|
|
||||||
|
To convey to humans and machine tools that code is generated,
|
||||||
|
generated source should have a line that matches the following
|
||||||
|
regular expression (in Go syntax):
|
||||||
|
|
||||||
|
^// Code generated .* DO NOT EDIT\.$
|
||||||
|
|
||||||
|
This line must appear before the first non-comment, non-blank
|
||||||
|
text in the file.
|
||||||
|
|
||||||
Go generate sets several variables when it runs the generator:
|
Go generate sets several variables when it runs the generator:
|
||||||
|
|
||||||
$GOARCH
|
$GOARCH
|
||||||
|
|
|
@ -202,7 +202,7 @@ func runGet(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
func downloadPaths(patterns []string) []string {
|
func downloadPaths(patterns []string) []string {
|
||||||
for _, arg := range patterns {
|
for _, arg := range patterns {
|
||||||
if strings.Contains(arg, "@") {
|
if strings.Contains(arg, "@") {
|
||||||
base.Fatalf("go: cannot use path@version syntax in GOPATH mode")
|
base.Fatalf("go: can only use path@version syntax with 'go get' and 'go install' in module-aware mode")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -266,7 +266,7 @@ listed in the GOPATH environment variable.
|
||||||
(See 'go help gopath-get' and 'go help gopath'.)
|
(See 'go help gopath-get' and 'go help gopath'.)
|
||||||
|
|
||||||
When using modules, downloaded packages are stored in the module cache.
|
When using modules, downloaded packages are stored in the module cache.
|
||||||
(See 'go help module-get' and 'go help goproxy'.)
|
See https://golang.org/ref/mod#module-cache.
|
||||||
|
|
||||||
When using modules, an additional variant of the go-import meta tag is
|
When using modules, an additional variant of the go-import meta tag is
|
||||||
recognized and is preferred over those listing version control systems.
|
recognized and is preferred over those listing version control systems.
|
||||||
|
@ -276,7 +276,8 @@ That variant uses "mod" as the vcs in the content value, as in:
|
||||||
|
|
||||||
This tag means to fetch modules with paths beginning with example.org
|
This tag means to fetch modules with paths beginning with example.org
|
||||||
from the module proxy available at the URL https://code.org/moduleproxy.
|
from the module proxy available at the URL https://code.org/moduleproxy.
|
||||||
See 'go help goproxy' for details about the proxy protocol.
|
See https://golang.org/ref/mod#goproxy-protocol for details about the
|
||||||
|
proxy protocol.
|
||||||
|
|
||||||
Import path checking
|
Import path checking
|
||||||
|
|
||||||
|
@ -483,6 +484,10 @@ See 'go help env' for details.
|
||||||
|
|
||||||
General-purpose environment variables:
|
General-purpose environment variables:
|
||||||
|
|
||||||
|
GO111MODULE
|
||||||
|
Controls whether the go command runs in module-aware mode or GOPATH mode.
|
||||||
|
May be "off", "on", or "auto".
|
||||||
|
See https://golang.org/ref/mod#mod-commands.
|
||||||
GCCGO
|
GCCGO
|
||||||
The gccgo command to run for 'go build -compiler=gccgo'.
|
The gccgo command to run for 'go build -compiler=gccgo'.
|
||||||
GOARCH
|
GOARCH
|
||||||
|
@ -521,20 +526,24 @@ General-purpose environment variables:
|
||||||
GOPATH
|
GOPATH
|
||||||
For more details see: 'go help gopath'.
|
For more details see: 'go help gopath'.
|
||||||
GOPROXY
|
GOPROXY
|
||||||
URL of Go module proxy. See 'go help modules'.
|
URL of Go module proxy. See https://golang.org/ref/mod#environment-variables
|
||||||
|
and https://golang.org/ref/mod#module-proxy for details.
|
||||||
GOPRIVATE, GONOPROXY, GONOSUMDB
|
GOPRIVATE, GONOPROXY, GONOSUMDB
|
||||||
Comma-separated list of glob patterns (in the syntax of Go's path.Match)
|
Comma-separated list of glob patterns (in the syntax of Go's path.Match)
|
||||||
of module path prefixes that should always be fetched directly
|
of module path prefixes that should always be fetched directly
|
||||||
or that should not be compared against the checksum database.
|
or that should not be compared against the checksum database.
|
||||||
See 'go help private'.
|
See https://golang.org/ref/mod#private-modules.
|
||||||
GOROOT
|
GOROOT
|
||||||
The root of the go tree.
|
The root of the go tree.
|
||||||
GOSUMDB
|
GOSUMDB
|
||||||
The name of checksum database to use and optionally its public key and
|
The name of checksum database to use and optionally its public key and
|
||||||
URL. See 'go help module-auth'.
|
URL. See https://golang.org/ref/mod#authenticating.
|
||||||
GOTMPDIR
|
GOTMPDIR
|
||||||
The directory where the go command will write
|
The directory where the go command will write
|
||||||
temporary source files, packages, and binaries.
|
temporary source files, packages, and binaries.
|
||||||
|
GOVCS
|
||||||
|
Lists version control commands that may be used with matching servers.
|
||||||
|
See 'go help vcs'.
|
||||||
|
|
||||||
Environment variables for use with cgo:
|
Environment variables for use with cgo:
|
||||||
|
|
||||||
|
|
|
@ -89,6 +89,14 @@ to -f '{{.ImportPath}}'. The struct being passed to the template is:
|
||||||
TestGoFiles []string // _test.go files in package
|
TestGoFiles []string // _test.go files in package
|
||||||
XTestGoFiles []string // _test.go files outside package
|
XTestGoFiles []string // _test.go files outside package
|
||||||
|
|
||||||
|
// Embedded files
|
||||||
|
EmbedPatterns []string // //go:embed patterns
|
||||||
|
EmbedFiles []string // files matched by EmbedPatterns
|
||||||
|
TestEmbedPatterns []string // //go:embed patterns in TestGoFiles
|
||||||
|
TestEmbedFiles []string // files matched by TestEmbedPatterns
|
||||||
|
XTestEmbedPatterns []string // //go:embed patterns in XTestGoFiles
|
||||||
|
XTestEmbedFiles []string // files matched by XTestEmbedPatterns
|
||||||
|
|
||||||
// Cgo directives
|
// Cgo directives
|
||||||
CgoCFLAGS []string // cgo: flags for C compiler
|
CgoCFLAGS []string // cgo: flags for C compiler
|
||||||
CgoCPPFLAGS []string // cgo: flags for C preprocessor
|
CgoCPPFLAGS []string // cgo: flags for C preprocessor
|
||||||
|
@ -300,7 +308,7 @@ For more about build flags, see 'go help build'.
|
||||||
|
|
||||||
For more about specifying packages, see 'go help packages'.
|
For more about specifying packages, see 'go help packages'.
|
||||||
|
|
||||||
For more about modules, see 'go help modules'.
|
For more about modules, see https://golang.org/ref/mod.
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -577,8 +585,6 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
// Show vendor-expanded paths in listing
|
// Show vendor-expanded paths in listing
|
||||||
p.TestImports = p.Resolve(p.TestImports)
|
p.TestImports = p.Resolve(p.TestImports)
|
||||||
p.XTestImports = p.Resolve(p.XTestImports)
|
p.XTestImports = p.Resolve(p.XTestImports)
|
||||||
p.TestEmbedFiles = p.ResolveEmbed(p.TestEmbedPatterns)
|
|
||||||
p.XTestEmbedFiles = p.ResolveEmbed(p.XTestEmbedPatterns)
|
|
||||||
p.DepOnly = !cmdline[p]
|
p.DepOnly = !cmdline[p]
|
||||||
|
|
||||||
if *listCompiled {
|
if *listCompiled {
|
||||||
|
|
|
@ -96,7 +96,7 @@ type PackagePublic struct {
|
||||||
|
|
||||||
// Embedded files
|
// Embedded files
|
||||||
EmbedPatterns []string `json:",omitempty"` // //go:embed patterns
|
EmbedPatterns []string `json:",omitempty"` // //go:embed patterns
|
||||||
EmbedFiles []string `json:",omitempty"` // files and directories matched by EmbedPatterns
|
EmbedFiles []string `json:",omitempty"` // files matched by EmbedPatterns
|
||||||
|
|
||||||
// Cgo directives
|
// Cgo directives
|
||||||
CgoCFLAGS []string `json:",omitempty"` // cgo: flags for C compiler
|
CgoCFLAGS []string `json:",omitempty"` // cgo: flags for C compiler
|
||||||
|
@ -122,11 +122,11 @@ type PackagePublic struct {
|
||||||
TestGoFiles []string `json:",omitempty"` // _test.go files in package
|
TestGoFiles []string `json:",omitempty"` // _test.go files in package
|
||||||
TestImports []string `json:",omitempty"` // imports from TestGoFiles
|
TestImports []string `json:",omitempty"` // imports from TestGoFiles
|
||||||
TestEmbedPatterns []string `json:",omitempty"` // //go:embed patterns
|
TestEmbedPatterns []string `json:",omitempty"` // //go:embed patterns
|
||||||
TestEmbedFiles []string `json:",omitempty"` // //files matched by EmbedPatterns
|
TestEmbedFiles []string `json:",omitempty"` // files matched by TestEmbedPatterns
|
||||||
XTestGoFiles []string `json:",omitempty"` // _test.go files outside package
|
XTestGoFiles []string `json:",omitempty"` // _test.go files outside package
|
||||||
XTestImports []string `json:",omitempty"` // imports from XTestGoFiles
|
XTestImports []string `json:",omitempty"` // imports from XTestGoFiles
|
||||||
XTestEmbedPatterns []string `json:",omitempty"` // //go:embed patterns
|
XTestEmbedPatterns []string `json:",omitempty"` // //go:embed patterns
|
||||||
XTestEmbedFiles []string `json:",omitempty"` // //files matched by EmbedPatterns
|
XTestEmbedFiles []string `json:",omitempty"` // files matched by XTestEmbedPatterns
|
||||||
}
|
}
|
||||||
|
|
||||||
// AllFiles returns the names of all the files considered for the package.
|
// AllFiles returns the names of all the files considered for the package.
|
||||||
|
@ -304,7 +304,7 @@ func (p *Package) setLoadPackageDataError(err error, path string, stk *ImportSta
|
||||||
}
|
}
|
||||||
|
|
||||||
if path != stk.Top() {
|
if path != stk.Top() {
|
||||||
p = setErrorPos(p, importPos)
|
p.Error.setPos(importPos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -412,6 +412,9 @@ type PackageError struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PackageError) Error() string {
|
func (p *PackageError) Error() string {
|
||||||
|
// TODO(#43696): decide when to print the stack or the position based on
|
||||||
|
// the error type and whether the package is in the main module.
|
||||||
|
// Document the rationale.
|
||||||
if p.Pos != "" && (len(p.ImportStack) == 0 || !p.alwaysPrintStack) {
|
if p.Pos != "" && (len(p.ImportStack) == 0 || !p.alwaysPrintStack) {
|
||||||
// Omit import stack. The full path to the file where the error
|
// Omit import stack. The full path to the file where the error
|
||||||
// is the most important thing.
|
// is the most important thing.
|
||||||
|
@ -447,6 +450,15 @@ func (p *PackageError) MarshalJSON() ([]byte, error) {
|
||||||
return json.Marshal(perr)
|
return json.Marshal(perr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *PackageError) setPos(posList []token.Position) {
|
||||||
|
if len(posList) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pos := posList[0]
|
||||||
|
pos.Filename = base.ShortPath(pos.Filename)
|
||||||
|
p.Pos = pos.String()
|
||||||
|
}
|
||||||
|
|
||||||
// ImportPathError is a type of error that prevents a package from being loaded
|
// ImportPathError is a type of error that prevents a package from being loaded
|
||||||
// for a given import path. When such a package is loaded, a *Package is
|
// for a given import path. When such a package is loaded, a *Package is
|
||||||
// returned with Err wrapping an ImportPathError: the error is attached to
|
// returned with Err wrapping an ImportPathError: the error is attached to
|
||||||
|
@ -695,17 +707,19 @@ func loadImport(ctx context.Context, pre *preload, path, srcDir string, parent *
|
||||||
Err: ImportErrorf(path, "non-canonical import path %q: should be %q", path, pathpkg.Clean(path)),
|
Err: ImportErrorf(path, "non-canonical import path %q: should be %q", path, pathpkg.Clean(path)),
|
||||||
}
|
}
|
||||||
p.Incomplete = true
|
p.Incomplete = true
|
||||||
setErrorPos(p, importPos)
|
p.Error.setPos(importPos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checked on every import because the rules depend on the code doing the importing.
|
// Checked on every import because the rules depend on the code doing the importing.
|
||||||
if perr := disallowInternal(srcDir, parent, parentPath, p, stk); perr != p {
|
if perr := disallowInternal(srcDir, parent, parentPath, p, stk); perr != p {
|
||||||
return setErrorPos(perr, importPos)
|
perr.Error.setPos(importPos)
|
||||||
|
return perr
|
||||||
}
|
}
|
||||||
if mode&ResolveImport != 0 {
|
if mode&ResolveImport != 0 {
|
||||||
if perr := disallowVendor(srcDir, path, parentPath, p, stk); perr != p {
|
if perr := disallowVendor(srcDir, path, parentPath, p, stk); perr != p {
|
||||||
return setErrorPos(perr, importPos)
|
perr.Error.setPos(importPos)
|
||||||
|
return perr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -715,7 +729,8 @@ func loadImport(ctx context.Context, pre *preload, path, srcDir string, parent *
|
||||||
ImportStack: stk.Copy(),
|
ImportStack: stk.Copy(),
|
||||||
Err: ImportErrorf(path, "import %q is a program, not an importable package", path),
|
Err: ImportErrorf(path, "import %q is a program, not an importable package", path),
|
||||||
}
|
}
|
||||||
return setErrorPos(&perr, importPos)
|
perr.Error.setPos(importPos)
|
||||||
|
return &perr
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.Internal.Local && parent != nil && !parent.Internal.Local {
|
if p.Internal.Local && parent != nil && !parent.Internal.Local {
|
||||||
|
@ -730,21 +745,13 @@ func loadImport(ctx context.Context, pre *preload, path, srcDir string, parent *
|
||||||
ImportStack: stk.Copy(),
|
ImportStack: stk.Copy(),
|
||||||
Err: err,
|
Err: err,
|
||||||
}
|
}
|
||||||
return setErrorPos(&perr, importPos)
|
perr.Error.setPos(importPos)
|
||||||
|
return &perr
|
||||||
}
|
}
|
||||||
|
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
func setErrorPos(p *Package, importPos []token.Position) *Package {
|
|
||||||
if len(importPos) > 0 {
|
|
||||||
pos := importPos[0]
|
|
||||||
pos.Filename = base.ShortPath(pos.Filename)
|
|
||||||
p.Error.Pos = pos.String()
|
|
||||||
}
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
// loadPackageData loads information needed to construct a *Package. The result
|
// loadPackageData loads information needed to construct a *Package. The result
|
||||||
// is cached, and later calls to loadPackageData for the same package will return
|
// is cached, and later calls to loadPackageData for the same package will return
|
||||||
// the same data.
|
// the same data.
|
||||||
|
@ -769,11 +776,7 @@ func loadPackageData(path, parentPath, parentDir, parentRoot string, parentIsStd
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.Contains(path, "@") {
|
if strings.Contains(path, "@") {
|
||||||
if cfg.ModulesEnabled {
|
return nil, false, errors.New("can only use path@version syntax with 'go get' and 'go install' in module-aware mode")
|
||||||
return nil, false, errors.New("can only use path@version syntax with 'go get'")
|
|
||||||
} else {
|
|
||||||
return nil, false, errors.New("cannot use path@version syntax in GOPATH mode")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine canonical package path and directory.
|
// Determine canonical package path and directory.
|
||||||
|
@ -1659,7 +1662,7 @@ func (p *Package) load(ctx context.Context, path string, stk *ImportStack, impor
|
||||||
// must be either in an explicit command-line argument,
|
// must be either in an explicit command-line argument,
|
||||||
// or on the importer side (indicated by a non-empty importPos).
|
// or on the importer side (indicated by a non-empty importPos).
|
||||||
if path != stk.Top() && len(importPos) > 0 {
|
if path != stk.Top() && len(importPos) > 0 {
|
||||||
p = setErrorPos(p, importPos)
|
p.Error.setPos(importPos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1669,11 +1672,6 @@ func (p *Package) load(ctx context.Context, path string, stk *ImportStack, impor
|
||||||
p.setLoadPackageDataError(err, path, stk, importPos)
|
p.setLoadPackageDataError(err, path, stk, importPos)
|
||||||
}
|
}
|
||||||
|
|
||||||
p.EmbedFiles, p.Internal.Embed, err = p.resolveEmbed(p.EmbedPatterns)
|
|
||||||
if err != nil {
|
|
||||||
setError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
useBindir := p.Name == "main"
|
useBindir := p.Name == "main"
|
||||||
if !p.Standard {
|
if !p.Standard {
|
||||||
switch cfg.BuildBuildmode {
|
switch cfg.BuildBuildmode {
|
||||||
|
@ -1809,9 +1807,20 @@ func (p *Package) load(ctx context.Context, path string, stk *ImportStack, impor
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Errors after this point are caused by this package, not the importing
|
||||||
|
// package. Pushing the path here prevents us from reporting the error
|
||||||
|
// with the position of the import declaration.
|
||||||
stk.Push(path)
|
stk.Push(path)
|
||||||
defer stk.Pop()
|
defer stk.Pop()
|
||||||
|
|
||||||
|
p.EmbedFiles, p.Internal.Embed, err = resolveEmbed(p.Dir, p.EmbedPatterns)
|
||||||
|
if err != nil {
|
||||||
|
p.Incomplete = true
|
||||||
|
setError(err)
|
||||||
|
embedErr := err.(*EmbedError)
|
||||||
|
p.Error.setPos(p.Internal.Build.EmbedPatternPos[embedErr.Pattern])
|
||||||
|
}
|
||||||
|
|
||||||
// Check for case-insensitive collision of input files.
|
// Check for case-insensitive collision of input files.
|
||||||
// To avoid problems on case-insensitive files, we reject any package
|
// To avoid problems on case-insensitive files, we reject any package
|
||||||
// where two different input files have equal names under a case-insensitive
|
// where two different input files have equal names under a case-insensitive
|
||||||
|
@ -1915,35 +1924,62 @@ func (p *Package) load(ctx context.Context, path string, stk *ImportStack, impor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// An EmbedError indicates a problem with a go:embed directive.
|
||||||
|
type EmbedError struct {
|
||||||
|
Pattern string
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EmbedError) Error() string {
|
||||||
|
return fmt.Sprintf("pattern %s: %v", e.Pattern, e.Err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EmbedError) Unwrap() error {
|
||||||
|
return e.Err
|
||||||
|
}
|
||||||
|
|
||||||
// ResolveEmbed resolves //go:embed patterns and returns only the file list.
|
// ResolveEmbed resolves //go:embed patterns and returns only the file list.
|
||||||
// For use by go list to compute p.TestEmbedFiles and p.XTestEmbedFiles.
|
// For use by go mod vendor to find embedded files it should copy into the
|
||||||
func (p *Package) ResolveEmbed(patterns []string) []string {
|
// vendor directory.
|
||||||
files, _, _ := p.resolveEmbed(patterns)
|
// TODO(#42504): Once go mod vendor uses load.PackagesAndErrors, just
|
||||||
return files
|
// call (*Package).ResolveEmbed
|
||||||
|
func ResolveEmbed(dir string, patterns []string) ([]string, error) {
|
||||||
|
files, _, err := resolveEmbed(dir, patterns)
|
||||||
|
return files, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolveEmbed resolves //go:embed patterns to precise file lists.
|
// resolveEmbed resolves //go:embed patterns to precise file lists.
|
||||||
// It sets files to the list of unique files matched (for go list),
|
// It sets files to the list of unique files matched (for go list),
|
||||||
// and it sets pmap to the more precise mapping from
|
// and it sets pmap to the more precise mapping from
|
||||||
// patterns to files.
|
// patterns to files.
|
||||||
// TODO(rsc): All these messages need position information for better error reports.
|
func resolveEmbed(pkgdir string, patterns []string) (files []string, pmap map[string][]string, err error) {
|
||||||
func (p *Package) resolveEmbed(patterns []string) (files []string, pmap map[string][]string, err error) {
|
var pattern string
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
err = &EmbedError{
|
||||||
|
Pattern: pattern,
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// TODO(rsc): All these messages need position information for better error reports.
|
||||||
pmap = make(map[string][]string)
|
pmap = make(map[string][]string)
|
||||||
have := make(map[string]int)
|
have := make(map[string]int)
|
||||||
dirOK := make(map[string]bool)
|
dirOK := make(map[string]bool)
|
||||||
pid := 0 // pattern ID, to allow reuse of have map
|
pid := 0 // pattern ID, to allow reuse of have map
|
||||||
for _, pattern := range patterns {
|
for _, pattern = range patterns {
|
||||||
pid++
|
pid++
|
||||||
|
|
||||||
// Check pattern is valid for //go:embed.
|
// Check pattern is valid for //go:embed.
|
||||||
if _, err := path.Match(pattern, ""); err != nil || !validEmbedPattern(pattern) {
|
if _, err := path.Match(pattern, ""); err != nil || !validEmbedPattern(pattern) {
|
||||||
return nil, nil, fmt.Errorf("pattern %s: invalid pattern syntax", pattern)
|
return nil, nil, fmt.Errorf("invalid pattern syntax")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Glob to find matches.
|
// Glob to find matches.
|
||||||
match, err := fsys.Glob(p.Dir + string(filepath.Separator) + filepath.FromSlash(pattern))
|
match, err := fsys.Glob(pkgdir + string(filepath.Separator) + filepath.FromSlash(pattern))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("pattern %s: %v", pattern, err)
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter list of matches down to the ones that will still exist when
|
// Filter list of matches down to the ones that will still exist when
|
||||||
|
@ -1952,7 +1988,7 @@ func (p *Package) resolveEmbed(patterns []string) (files []string, pmap map[stri
|
||||||
// then there may be other things lying around, like symbolic links or .git directories.)
|
// then there may be other things lying around, like symbolic links or .git directories.)
|
||||||
var list []string
|
var list []string
|
||||||
for _, file := range match {
|
for _, file := range match {
|
||||||
rel := filepath.ToSlash(file[len(p.Dir)+1:]) // file, relative to p.Dir
|
rel := filepath.ToSlash(file[len(pkgdir)+1:]) // file, relative to p.Dir
|
||||||
|
|
||||||
what := "file"
|
what := "file"
|
||||||
info, err := fsys.Lstat(file)
|
info, err := fsys.Lstat(file)
|
||||||
|
@ -1965,28 +2001,28 @@ func (p *Package) resolveEmbed(patterns []string) (files []string, pmap map[stri
|
||||||
|
|
||||||
// Check that directories along path do not begin a new module
|
// Check that directories along path do not begin a new module
|
||||||
// (do not contain a go.mod).
|
// (do not contain a go.mod).
|
||||||
for dir := file; len(dir) > len(p.Dir)+1 && !dirOK[dir]; dir = filepath.Dir(dir) {
|
for dir := file; len(dir) > len(pkgdir)+1 && !dirOK[dir]; dir = filepath.Dir(dir) {
|
||||||
if _, err := fsys.Stat(filepath.Join(dir, "go.mod")); err == nil {
|
if _, err := fsys.Stat(filepath.Join(dir, "go.mod")); err == nil {
|
||||||
return nil, nil, fmt.Errorf("pattern %s: cannot embed %s %s: in different module", pattern, what, rel)
|
return nil, nil, fmt.Errorf("cannot embed %s %s: in different module", what, rel)
|
||||||
}
|
}
|
||||||
if dir != file {
|
if dir != file {
|
||||||
if info, err := fsys.Lstat(dir); err == nil && !info.IsDir() {
|
if info, err := fsys.Lstat(dir); err == nil && !info.IsDir() {
|
||||||
return nil, nil, fmt.Errorf("pattern %s: cannot embed %s %s: in non-directory %s", pattern, what, rel, dir[len(p.Dir)+1:])
|
return nil, nil, fmt.Errorf("cannot embed %s %s: in non-directory %s", what, rel, dir[len(pkgdir)+1:])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dirOK[dir] = true
|
dirOK[dir] = true
|
||||||
if elem := filepath.Base(dir); isBadEmbedName(elem) {
|
if elem := filepath.Base(dir); isBadEmbedName(elem) {
|
||||||
if dir == file {
|
if dir == file {
|
||||||
return nil, nil, fmt.Errorf("pattern %s: cannot embed %s %s: invalid name %s", pattern, what, rel, elem)
|
return nil, nil, fmt.Errorf("cannot embed %s %s: invalid name %s", what, rel, elem)
|
||||||
} else {
|
} else {
|
||||||
return nil, nil, fmt.Errorf("pattern %s: cannot embed %s %s: in invalid directory %s", pattern, what, rel, elem)
|
return nil, nil, fmt.Errorf("cannot embed %s %s: in invalid directory %s", what, rel, elem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
default:
|
default:
|
||||||
return nil, nil, fmt.Errorf("pattern %s: cannot embed irregular file %s", pattern, rel)
|
return nil, nil, fmt.Errorf("cannot embed irregular file %s", rel)
|
||||||
|
|
||||||
case info.Mode().IsRegular():
|
case info.Mode().IsRegular():
|
||||||
if have[rel] != pid {
|
if have[rel] != pid {
|
||||||
|
@ -2002,7 +2038,7 @@ func (p *Package) resolveEmbed(patterns []string) (files []string, pmap map[stri
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
rel := filepath.ToSlash(path[len(p.Dir)+1:])
|
rel := filepath.ToSlash(path[len(pkgdir)+1:])
|
||||||
name := info.Name()
|
name := info.Name()
|
||||||
if path != file && (isBadEmbedName(name) || name[0] == '.' || name[0] == '_') {
|
if path != file && (isBadEmbedName(name) || name[0] == '.' || name[0] == '_') {
|
||||||
// Ignore bad names, assuming they won't go into modules.
|
// Ignore bad names, assuming they won't go into modules.
|
||||||
|
@ -2033,13 +2069,13 @@ func (p *Package) resolveEmbed(patterns []string) (files []string, pmap map[stri
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
return nil, nil, fmt.Errorf("pattern %s: cannot embed directory %s: contains no embeddable files", pattern, rel)
|
return nil, nil, fmt.Errorf("cannot embed directory %s: contains no embeddable files", rel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(list) == 0 {
|
if len(list) == 0 {
|
||||||
return nil, nil, fmt.Errorf("pattern %s: no matching files found", pattern)
|
return nil, nil, fmt.Errorf("no matching files found")
|
||||||
}
|
}
|
||||||
sort.Strings(list)
|
sort.Strings(list)
|
||||||
pmap[pattern] = list
|
pmap[pattern] = list
|
||||||
|
|
|
@ -124,12 +124,14 @@ func TestPackagesAndErrors(ctx context.Context, p *Package, cover *TestCover) (p
|
||||||
imports = append(imports, p1)
|
imports = append(imports, p1)
|
||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
p.TestEmbedFiles, testEmbed, err = p.resolveEmbed(p.TestEmbedPatterns)
|
p.TestEmbedFiles, testEmbed, err = resolveEmbed(p.Dir, p.TestEmbedPatterns)
|
||||||
if err != nil && ptestErr == nil {
|
if err != nil && ptestErr == nil {
|
||||||
ptestErr = &PackageError{
|
ptestErr = &PackageError{
|
||||||
ImportStack: stk.Copy(),
|
ImportStack: stk.Copy(),
|
||||||
Err: err,
|
Err: err,
|
||||||
}
|
}
|
||||||
|
embedErr := err.(*EmbedError)
|
||||||
|
ptestErr.setPos(p.Internal.Build.TestEmbedPatternPos[embedErr.Pattern])
|
||||||
}
|
}
|
||||||
stk.Pop()
|
stk.Pop()
|
||||||
|
|
||||||
|
@ -145,12 +147,14 @@ func TestPackagesAndErrors(ctx context.Context, p *Package, cover *TestCover) (p
|
||||||
}
|
}
|
||||||
p.XTestImports[i] = p1.ImportPath
|
p.XTestImports[i] = p1.ImportPath
|
||||||
}
|
}
|
||||||
p.XTestEmbedFiles, xtestEmbed, err = p.resolveEmbed(p.XTestEmbedPatterns)
|
p.XTestEmbedFiles, xtestEmbed, err = resolveEmbed(p.Dir, p.XTestEmbedPatterns)
|
||||||
if err != nil && pxtestErr == nil {
|
if err != nil && pxtestErr == nil {
|
||||||
pxtestErr = &PackageError{
|
pxtestErr = &PackageError{
|
||||||
ImportStack: stk.Copy(),
|
ImportStack: stk.Copy(),
|
||||||
Err: err,
|
Err: err,
|
||||||
}
|
}
|
||||||
|
embedErr := err.(*EmbedError)
|
||||||
|
pxtestErr.setPos(p.Internal.Build.XTestEmbedPatternPos[embedErr.Pattern])
|
||||||
}
|
}
|
||||||
stk.Pop()
|
stk.Pop()
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,9 @@ corresponding to this Go struct:
|
||||||
|
|
||||||
The -x flag causes download to print the commands download executes.
|
The -x flag causes download to print the commands download executes.
|
||||||
|
|
||||||
See 'go help modules' for more about module queries.
|
See https://golang.org/ref/mod#go-mod-download for more about 'go mod download'.
|
||||||
|
|
||||||
|
See https://golang.org/ref/mod#version-queries for more about version queries.
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,6 +95,7 @@ writing it back to go.mod. The JSON output corresponds to these Go types:
|
||||||
Require []Require
|
Require []Require
|
||||||
Exclude []Module
|
Exclude []Module
|
||||||
Replace []Replace
|
Replace []Replace
|
||||||
|
Retract []Retract
|
||||||
}
|
}
|
||||||
|
|
||||||
type Require struct {
|
type Require struct {
|
||||||
|
@ -121,9 +122,7 @@ Note that this only describes the go.mod file itself, not other modules
|
||||||
referred to indirectly. For the full set of modules available to a build,
|
referred to indirectly. For the full set of modules available to a build,
|
||||||
use 'go list -m -json all'.
|
use 'go list -m -json all'.
|
||||||
|
|
||||||
For example, a tool can obtain the go.mod as a data structure by
|
See https://golang.org/ref/mod#go-mod-edit for more about 'go mod edit'.
|
||||||
parsing the output of 'go mod edit -json' and can then make changes
|
|
||||||
by invoking 'go mod edit' with -require, -exclude, and so on.
|
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,8 @@ Graph prints the module requirement graph (with replacements applied)
|
||||||
in text form. Each line in the output has two space-separated fields: a module
|
in text form. Each line in the output has two space-separated fields: a module
|
||||||
and one of its requirements. Each module is identified as a string of the form
|
and one of its requirements. Each module is identified as a string of the form
|
||||||
path@version, except for the main module, which has no @version suffix.
|
path@version, except for the main module, which has no @version suffix.
|
||||||
|
|
||||||
|
See https://golang.org/ref/mod#go-mod-graph for more about 'go mod graph'.
|
||||||
`,
|
`,
|
||||||
Run: runGraph,
|
Run: runGraph,
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,8 @@ Gopkg.lock), and the current directory (if in GOPATH).
|
||||||
|
|
||||||
If a configuration file for a vendoring tool is present, init will attempt to
|
If a configuration file for a vendoring tool is present, init will attempt to
|
||||||
import module requirements from it.
|
import module requirements from it.
|
||||||
|
|
||||||
|
See https://golang.org/ref/mod#go-mod-init for more about 'go mod init'.
|
||||||
`,
|
`,
|
||||||
Run: runInit,
|
Run: runInit,
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,8 @@ to standard error.
|
||||||
|
|
||||||
The -e flag causes tidy to attempt to proceed despite errors
|
The -e flag causes tidy to attempt to proceed despite errors
|
||||||
encountered while loading packages.
|
encountered while loading packages.
|
||||||
|
|
||||||
|
See https://golang.org/ref/mod#go-mod-tidy for more about 'go mod tidy'.
|
||||||
`,
|
`,
|
||||||
Run: runTidy,
|
Run: runTidy,
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,9 @@ package modcmd
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"go/build"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
|
@ -19,7 +21,9 @@ import (
|
||||||
"cmd/go/internal/cfg"
|
"cmd/go/internal/cfg"
|
||||||
"cmd/go/internal/fsys"
|
"cmd/go/internal/fsys"
|
||||||
"cmd/go/internal/imports"
|
"cmd/go/internal/imports"
|
||||||
|
"cmd/go/internal/load"
|
||||||
"cmd/go/internal/modload"
|
"cmd/go/internal/modload"
|
||||||
|
"cmd/go/internal/str"
|
||||||
|
|
||||||
"golang.org/x/mod/module"
|
"golang.org/x/mod/module"
|
||||||
"golang.org/x/mod/semver"
|
"golang.org/x/mod/semver"
|
||||||
|
@ -38,6 +42,8 @@ modules and packages to standard error.
|
||||||
|
|
||||||
The -e flag causes vendor to attempt to proceed despite errors
|
The -e flag causes vendor to attempt to proceed despite errors
|
||||||
encountered while loading packages.
|
encountered while loading packages.
|
||||||
|
|
||||||
|
See https://golang.org/ref/mod#go-mod-vendor for more about 'go mod vendor'.
|
||||||
`,
|
`,
|
||||||
Run: runVendor,
|
Run: runVendor,
|
||||||
}
|
}
|
||||||
|
@ -180,19 +186,76 @@ func moduleLine(m, r module.Version) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func vendorPkg(vdir, pkg string) {
|
func vendorPkg(vdir, pkg string) {
|
||||||
|
// TODO(#42504): Instead of calling modload.ImportMap then build.ImportDir,
|
||||||
|
// just call load.PackagesAndErrors. To do that, we need to add a good way
|
||||||
|
// to ignore build constraints.
|
||||||
realPath := modload.ImportMap(pkg)
|
realPath := modload.ImportMap(pkg)
|
||||||
if realPath != pkg && modload.ImportMap(realPath) != "" {
|
if realPath != pkg && modload.ImportMap(realPath) != "" {
|
||||||
fmt.Fprintf(os.Stderr, "warning: %s imported as both %s and %s; making two copies.\n", realPath, realPath, pkg)
|
fmt.Fprintf(os.Stderr, "warning: %s imported as both %s and %s; making two copies.\n", realPath, realPath, pkg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
copiedFiles := make(map[string]bool)
|
||||||
dst := filepath.Join(vdir, pkg)
|
dst := filepath.Join(vdir, pkg)
|
||||||
src := modload.PackageDir(realPath)
|
src := modload.PackageDir(realPath)
|
||||||
if src == "" {
|
if src == "" {
|
||||||
fmt.Fprintf(os.Stderr, "internal error: no pkg for %s -> %s\n", pkg, realPath)
|
fmt.Fprintf(os.Stderr, "internal error: no pkg for %s -> %s\n", pkg, realPath)
|
||||||
}
|
}
|
||||||
copyDir(dst, src, matchPotentialSourceFile)
|
copyDir(dst, src, matchPotentialSourceFile, copiedFiles)
|
||||||
if m := modload.PackageModule(realPath); m.Path != "" {
|
if m := modload.PackageModule(realPath); m.Path != "" {
|
||||||
copyMetadata(m.Path, realPath, dst, src)
|
copyMetadata(m.Path, realPath, dst, src, copiedFiles)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := build.Default
|
||||||
|
ctx.UseAllFiles = true
|
||||||
|
bp, err := ctx.ImportDir(src, build.IgnoreVendor)
|
||||||
|
// Because UseAllFiles is set on the build.Context, it's possible ta get
|
||||||
|
// a MultiplePackageError on an otherwise valid package: the package could
|
||||||
|
// have different names for GOOS=windows and GOOS=mac for example. On the
|
||||||
|
// other hand if there's a NoGoError, the package might have source files
|
||||||
|
// specifying "// +build ignore" those packages should be skipped because
|
||||||
|
// embeds from ignored files can't be used.
|
||||||
|
// TODO(#42504): Find a better way to avoid errors from ImportDir. We'll
|
||||||
|
// need to figure this out when we switch to PackagesAndErrors as per the
|
||||||
|
// TODO above.
|
||||||
|
var multiplePackageError *build.MultiplePackageError
|
||||||
|
var noGoError *build.NoGoError
|
||||||
|
if err != nil {
|
||||||
|
if errors.As(err, &noGoError) {
|
||||||
|
return // No source files in this package are built. Skip embeds in ignored files.
|
||||||
|
} else if !errors.As(err, &multiplePackageError) { // multiplePackgeErrors are okay, but others are not.
|
||||||
|
base.Fatalf("internal error: failed to find embedded files of %s: %v\n", pkg, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
embedPatterns := str.StringList(bp.EmbedPatterns, bp.TestEmbedPatterns, bp.XTestEmbedPatterns)
|
||||||
|
embeds, err := load.ResolveEmbed(bp.Dir, embedPatterns)
|
||||||
|
if err != nil {
|
||||||
|
base.Fatalf("go mod vendor: %v", err)
|
||||||
|
}
|
||||||
|
for _, embed := range embeds {
|
||||||
|
embedDst := filepath.Join(dst, embed)
|
||||||
|
if copiedFiles[embedDst] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the file as is done by copyDir below.
|
||||||
|
r, err := os.Open(filepath.Join(src, embed))
|
||||||
|
if err != nil {
|
||||||
|
base.Fatalf("go mod vendor: %v", err)
|
||||||
|
}
|
||||||
|
if err := os.MkdirAll(filepath.Dir(embedDst), 0777); err != nil {
|
||||||
|
base.Fatalf("go mod vendor: %v", err)
|
||||||
|
}
|
||||||
|
w, err := os.Create(embedDst)
|
||||||
|
if err != nil {
|
||||||
|
base.Fatalf("go mod vendor: %v", err)
|
||||||
|
}
|
||||||
|
if _, err := io.Copy(w, r); err != nil {
|
||||||
|
base.Fatalf("go mod vendor: %v", err)
|
||||||
|
}
|
||||||
|
r.Close()
|
||||||
|
if err := w.Close(); err != nil {
|
||||||
|
base.Fatalf("go mod vendor: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,14 +268,14 @@ var copiedMetadata = make(map[metakey]bool)
|
||||||
|
|
||||||
// copyMetadata copies metadata files from parents of src to parents of dst,
|
// copyMetadata copies metadata files from parents of src to parents of dst,
|
||||||
// stopping after processing the src parent for modPath.
|
// stopping after processing the src parent for modPath.
|
||||||
func copyMetadata(modPath, pkg, dst, src string) {
|
func copyMetadata(modPath, pkg, dst, src string, copiedFiles map[string]bool) {
|
||||||
for parent := 0; ; parent++ {
|
for parent := 0; ; parent++ {
|
||||||
if copiedMetadata[metakey{modPath, dst}] {
|
if copiedMetadata[metakey{modPath, dst}] {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
copiedMetadata[metakey{modPath, dst}] = true
|
copiedMetadata[metakey{modPath, dst}] = true
|
||||||
if parent > 0 {
|
if parent > 0 {
|
||||||
copyDir(dst, src, matchMetadata)
|
copyDir(dst, src, matchMetadata, copiedFiles)
|
||||||
}
|
}
|
||||||
if modPath == pkg {
|
if modPath == pkg {
|
||||||
break
|
break
|
||||||
|
@ -280,7 +343,7 @@ func matchPotentialSourceFile(dir string, info fs.DirEntry) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// copyDir copies all regular files satisfying match(info) from src to dst.
|
// copyDir copies all regular files satisfying match(info) from src to dst.
|
||||||
func copyDir(dst, src string, match func(dir string, info fs.DirEntry) bool) {
|
func copyDir(dst, src string, match func(dir string, info fs.DirEntry) bool, copiedFiles map[string]bool) {
|
||||||
files, err := os.ReadDir(src)
|
files, err := os.ReadDir(src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf("go mod vendor: %v", err)
|
base.Fatalf("go mod vendor: %v", err)
|
||||||
|
@ -292,11 +355,14 @@ func copyDir(dst, src string, match func(dir string, info fs.DirEntry) bool) {
|
||||||
if file.IsDir() || !file.Type().IsRegular() || !match(src, file) {
|
if file.IsDir() || !file.Type().IsRegular() || !match(src, file) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
copiedFiles[file.Name()] = true
|
||||||
r, err := os.Open(filepath.Join(src, file.Name()))
|
r, err := os.Open(filepath.Join(src, file.Name()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf("go mod vendor: %v", err)
|
base.Fatalf("go mod vendor: %v", err)
|
||||||
}
|
}
|
||||||
w, err := os.Create(filepath.Join(dst, file.Name()))
|
dstPath := filepath.Join(dst, file.Name())
|
||||||
|
copiedFiles[dstPath] = true
|
||||||
|
w, err := os.Create(dstPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf("go mod vendor: %v", err)
|
base.Fatalf("go mod vendor: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,8 @@ modified since being downloaded. If all the modules are unmodified,
|
||||||
verify prints "all modules verified." Otherwise it reports which
|
verify prints "all modules verified." Otherwise it reports which
|
||||||
modules have been changed and causes 'go mod' to exit with a
|
modules have been changed and causes 'go mod' to exit with a
|
||||||
non-zero status.
|
non-zero status.
|
||||||
|
|
||||||
|
See https://golang.org/ref/mod#go-mod-verify for more about 'go mod verify'.
|
||||||
`,
|
`,
|
||||||
Run: runVerify,
|
Run: runVerify,
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,8 @@ For example:
|
||||||
# golang.org/x/text/encoding
|
# golang.org/x/text/encoding
|
||||||
(main module does not need package golang.org/x/text/encoding)
|
(main module does not need package golang.org/x/text/encoding)
|
||||||
$
|
$
|
||||||
|
|
||||||
|
See https://golang.org/ref/mod#go-mod-why for more about 'go mod why'.
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,10 +10,10 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
exec "internal/execabs"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
|
@ -8,11 +8,11 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
exec "internal/execabs"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
|
@ -768,90 +768,14 @@ var HelpModuleAuth = &base.Command{
|
||||||
UsageLine: "module-auth",
|
UsageLine: "module-auth",
|
||||||
Short: "module authentication using go.sum",
|
Short: "module authentication using go.sum",
|
||||||
Long: `
|
Long: `
|
||||||
The go command tries to authenticate every downloaded module,
|
When the go command downloads a module zip file or go.mod file into the
|
||||||
checking that the bits downloaded for a specific module version today
|
module cache, it computes a cryptographic hash and compares it with a known
|
||||||
match bits downloaded yesterday. This ensures repeatable builds
|
value to verify the file hasn't changed since it was first downloaded. Known
|
||||||
and detects introduction of unexpected changes, malicious or not.
|
hashes are stored in a file in the module root directory named go.sum. Hashes
|
||||||
|
may also be downloaded from the checksum database depending on the values of
|
||||||
|
GOSUMDB, GOPRIVATE, and GONOSUMDB.
|
||||||
|
|
||||||
In each module's root, alongside go.mod, the go command maintains
|
For details, see https://golang.org/ref/mod#authenticating.
|
||||||
a file named go.sum containing the cryptographic checksums of the
|
|
||||||
module's dependencies.
|
|
||||||
|
|
||||||
The form of each line in go.sum is three fields:
|
|
||||||
|
|
||||||
<module> <version>[/go.mod] <hash>
|
|
||||||
|
|
||||||
Each known module version results in two lines in the go.sum file.
|
|
||||||
The first line gives the hash of the module version's file tree.
|
|
||||||
The second line appends "/go.mod" to the version and gives the hash
|
|
||||||
of only the module version's (possibly synthesized) go.mod file.
|
|
||||||
The go.mod-only hash allows downloading and authenticating a
|
|
||||||
module version's go.mod file, which is needed to compute the
|
|
||||||
dependency graph, without also downloading all the module's source code.
|
|
||||||
|
|
||||||
The hash begins with an algorithm prefix of the form "h<N>:".
|
|
||||||
The only defined algorithm prefix is "h1:", which uses SHA-256.
|
|
||||||
|
|
||||||
Module authentication failures
|
|
||||||
|
|
||||||
The go command maintains a cache of downloaded packages and computes
|
|
||||||
and records the cryptographic checksum of each package at download time.
|
|
||||||
In normal operation, the go command checks the main module's go.sum file
|
|
||||||
against these precomputed checksums instead of recomputing them on
|
|
||||||
each command invocation. The 'go mod verify' command checks that
|
|
||||||
the cached copies of module downloads still match both their recorded
|
|
||||||
checksums and the entries in go.sum.
|
|
||||||
|
|
||||||
In day-to-day development, the checksum of a given module version
|
|
||||||
should never change. Each time a dependency is used by a given main
|
|
||||||
module, the go command checks its local cached copy, freshly
|
|
||||||
downloaded or not, against the main module's go.sum. If the checksums
|
|
||||||
don't match, the go command reports the mismatch as a security error
|
|
||||||
and refuses to run the build. When this happens, proceed with caution:
|
|
||||||
code changing unexpectedly means today's build will not match
|
|
||||||
yesterday's, and the unexpected change may not be beneficial.
|
|
||||||
|
|
||||||
If the go command reports a mismatch in go.sum, the downloaded code
|
|
||||||
for the reported module version does not match the one used in a
|
|
||||||
previous build of the main module. It is important at that point
|
|
||||||
to find out what the right checksum should be, to decide whether
|
|
||||||
go.sum is wrong or the downloaded code is wrong. Usually go.sum is right:
|
|
||||||
you want to use the same code you used yesterday.
|
|
||||||
|
|
||||||
If a downloaded module is not yet included in go.sum and it is a publicly
|
|
||||||
available module, the go command consults the Go checksum database to fetch
|
|
||||||
the expected go.sum lines. If the downloaded code does not match those
|
|
||||||
lines, the go command reports the mismatch and exits. Note that the
|
|
||||||
database is not consulted for module versions already listed in go.sum.
|
|
||||||
|
|
||||||
If a go.sum mismatch is reported, it is always worth investigating why
|
|
||||||
the code downloaded today differs from what was downloaded yesterday.
|
|
||||||
|
|
||||||
The GOSUMDB environment variable identifies the name of checksum database
|
|
||||||
to use and optionally its public key and URL, as in:
|
|
||||||
|
|
||||||
GOSUMDB="sum.golang.org"
|
|
||||||
GOSUMDB="sum.golang.org+<publickey>"
|
|
||||||
GOSUMDB="sum.golang.org+<publickey> https://sum.golang.org"
|
|
||||||
|
|
||||||
The go command knows the public key of sum.golang.org, and also that the name
|
|
||||||
sum.golang.google.cn (available inside mainland China) connects to the
|
|
||||||
sum.golang.org checksum database; use of any other database requires giving
|
|
||||||
the public key explicitly.
|
|
||||||
The URL defaults to "https://" followed by the database name.
|
|
||||||
|
|
||||||
GOSUMDB defaults to "sum.golang.org", the Go checksum database run by Google.
|
|
||||||
See https://sum.golang.org/privacy for the service's privacy policy.
|
|
||||||
|
|
||||||
If GOSUMDB is set to "off", or if "go get" is invoked with the -insecure flag,
|
|
||||||
the checksum database is not consulted, and all unrecognized modules are
|
|
||||||
accepted, at the cost of giving up the security guarantee of verified repeatable
|
|
||||||
downloads for all modules. A better way to bypass the checksum database
|
|
||||||
for specific modules is to use the GOPRIVATE or GONOSUMDB environment
|
|
||||||
variables. See 'go help private' for details.
|
|
||||||
|
|
||||||
The 'go env -w' command (see 'go help env') can be used to set these variables
|
|
||||||
for future go command invocations.
|
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -865,8 +789,8 @@ regardless of source, against the public Go checksum database at sum.golang.org.
|
||||||
These defaults work well for publicly available source code.
|
These defaults work well for publicly available source code.
|
||||||
|
|
||||||
The GOPRIVATE environment variable controls which modules the go command
|
The GOPRIVATE environment variable controls which modules the go command
|
||||||
considers to be private (not available publicly) and should therefore not use the
|
considers to be private (not available publicly) and should therefore not use
|
||||||
proxy or checksum database. The variable is a comma-separated list of
|
the proxy or checksum database. The variable is a comma-separated list of
|
||||||
glob patterns (in the syntax of Go's path.Match) of module path prefixes.
|
glob patterns (in the syntax of Go's path.Match) of module path prefixes.
|
||||||
For example,
|
For example,
|
||||||
|
|
||||||
|
@ -876,10 +800,6 @@ causes the go command to treat as private any module with a path prefix
|
||||||
matching either pattern, including git.corp.example.com/xyzzy, rsc.io/private,
|
matching either pattern, including git.corp.example.com/xyzzy, rsc.io/private,
|
||||||
and rsc.io/private/quux.
|
and rsc.io/private/quux.
|
||||||
|
|
||||||
The GOPRIVATE environment variable may be used by other tools as well to
|
|
||||||
identify non-public modules. For example, an editor could use GOPRIVATE
|
|
||||||
to decide whether to hyperlink a package import to a godoc.org page.
|
|
||||||
|
|
||||||
For fine-grained control over module download and validation, the GONOPROXY
|
For fine-grained control over module download and validation, the GONOPROXY
|
||||||
and GONOSUMDB environment variables accept the same kind of glob list
|
and GONOSUMDB environment variables accept the same kind of glob list
|
||||||
and override GOPRIVATE for the specific decision of whether to use the proxy
|
and override GOPRIVATE for the specific decision of whether to use the proxy
|
||||||
|
@ -892,12 +812,6 @@ users would configure go using:
|
||||||
GOPROXY=proxy.example.com
|
GOPROXY=proxy.example.com
|
||||||
GONOPROXY=none
|
GONOPROXY=none
|
||||||
|
|
||||||
This would tell the go command and other tools that modules beginning with
|
|
||||||
a corp.example.com subdomain are private but that the company proxy should
|
|
||||||
be used for downloading both public and private modules, because
|
|
||||||
GONOPROXY has been set to a pattern that won't match any modules,
|
|
||||||
overriding GOPRIVATE.
|
|
||||||
|
|
||||||
The GOPRIVATE variable is also used to define the "public" and "private"
|
The GOPRIVATE variable is also used to define the "public" and "private"
|
||||||
patterns for the GOVCS variable; see 'go help vcs'. For that usage,
|
patterns for the GOVCS variable; see 'go help vcs'. For that usage,
|
||||||
GOPRIVATE applies even in GOPATH mode. In that case, it matches import paths
|
GOPRIVATE applies even in GOPATH mode. In that case, it matches import paths
|
||||||
|
@ -905,5 +819,7 @@ instead of module paths.
|
||||||
|
|
||||||
The 'go env -w' command (see 'go help env') can be used to set these variables
|
The 'go env -w' command (see 'go help env') can be used to set these variables
|
||||||
for future go command invocations.
|
for future go command invocations.
|
||||||
|
|
||||||
|
For more details, see https://golang.org/ref/mod#private-modules.
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,65 +36,8 @@ URLs of a specified form. The requests have no query parameters, so even
|
||||||
a site serving from a fixed file system (including a file:/// URL)
|
a site serving from a fixed file system (including a file:/// URL)
|
||||||
can be a module proxy.
|
can be a module proxy.
|
||||||
|
|
||||||
The GET requests sent to a Go module proxy are:
|
For details on the GOPROXY protocol, see
|
||||||
|
https://golang.org/ref/mod#goproxy-protocol.
|
||||||
GET $GOPROXY/<module>/@v/list returns a list of known versions of the given
|
|
||||||
module, one per line.
|
|
||||||
|
|
||||||
GET $GOPROXY/<module>/@v/<version>.info returns JSON-formatted metadata
|
|
||||||
about that version of the given module.
|
|
||||||
|
|
||||||
GET $GOPROXY/<module>/@v/<version>.mod returns the go.mod file
|
|
||||||
for that version of the given module.
|
|
||||||
|
|
||||||
GET $GOPROXY/<module>/@v/<version>.zip returns the zip archive
|
|
||||||
for that version of the given module.
|
|
||||||
|
|
||||||
GET $GOPROXY/<module>/@latest returns JSON-formatted metadata about the
|
|
||||||
latest known version of the given module in the same format as
|
|
||||||
<module>/@v/<version>.info. The latest version should be the version of
|
|
||||||
the module the go command may use if <module>/@v/list is empty or no
|
|
||||||
listed version is suitable. <module>/@latest is optional and may not
|
|
||||||
be implemented by a module proxy.
|
|
||||||
|
|
||||||
When resolving the latest version of a module, the go command will request
|
|
||||||
<module>/@v/list, then, if no suitable versions are found, <module>/@latest.
|
|
||||||
The go command prefers, in order: the semantically highest release version,
|
|
||||||
the semantically highest pre-release version, and the chronologically
|
|
||||||
most recent pseudo-version. In Go 1.12 and earlier, the go command considered
|
|
||||||
pseudo-versions in <module>/@v/list to be pre-release versions, but this is
|
|
||||||
no longer true since Go 1.13.
|
|
||||||
|
|
||||||
To avoid problems when serving from case-sensitive file systems,
|
|
||||||
the <module> and <version> elements are case-encoded, replacing every
|
|
||||||
uppercase letter with an exclamation mark followed by the corresponding
|
|
||||||
lower-case letter: github.com/Azure encodes as github.com/!azure.
|
|
||||||
|
|
||||||
The JSON-formatted metadata about a given module corresponds to
|
|
||||||
this Go data structure, which may be expanded in the future:
|
|
||||||
|
|
||||||
type Info struct {
|
|
||||||
Version string // version string
|
|
||||||
Time time.Time // commit time
|
|
||||||
}
|
|
||||||
|
|
||||||
The zip archive for a specific version of a given module is a
|
|
||||||
standard zip file that contains the file tree corresponding
|
|
||||||
to the module's source code and related files. The archive uses
|
|
||||||
slash-separated paths, and every file path in the archive must
|
|
||||||
begin with <module>@<version>/, where the module and version are
|
|
||||||
substituted directly, not case-encoded. The root of the module
|
|
||||||
file tree corresponds to the <module>@<version>/ prefix in the
|
|
||||||
archive.
|
|
||||||
|
|
||||||
Even when downloading directly from version control systems,
|
|
||||||
the go command synthesizes explicit info, mod, and zip files
|
|
||||||
and stores them in its local cache, $GOPATH/pkg/mod/cache/download,
|
|
||||||
the same as if it had downloaded them directly from a proxy.
|
|
||||||
The cache layout is the same as the proxy URL space, so
|
|
||||||
serving $GOPATH/pkg/mod/cache/download at (or copying it to)
|
|
||||||
https://example.com/proxy would let other users access those
|
|
||||||
cached module versions with GOPROXY=https://example.com/proxy.
|
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,85 +56,49 @@ var CmdGet = &base.Command{
|
||||||
UsageLine: "go get [-d] [-t] [-u] [-v] [-insecure] [build flags] [packages]",
|
UsageLine: "go get [-d] [-t] [-u] [-v] [-insecure] [build flags] [packages]",
|
||||||
Short: "add dependencies to current module and install them",
|
Short: "add dependencies to current module and install them",
|
||||||
Long: `
|
Long: `
|
||||||
Get resolves and adds dependencies to the current development module
|
Get resolves its command-line arguments to packages at specific module versions,
|
||||||
and then builds and installs them.
|
updates go.mod to require those versions, downloads source code into the
|
||||||
|
module cache, then builds and installs the named packages.
|
||||||
|
|
||||||
The first step is to resolve which dependencies to add.
|
To add a dependency for a package or upgrade it to its latest version:
|
||||||
|
|
||||||
For each named package or package pattern, get must decide which version of
|
go get example.com/pkg
|
||||||
the corresponding module to use. By default, get looks up the latest tagged
|
|
||||||
release version, such as v0.4.5 or v1.2.3. If there are no tagged release
|
|
||||||
versions, get looks up the latest tagged pre-release version, such as
|
|
||||||
v0.0.1-pre1. If there are no tagged versions at all, get looks up the latest
|
|
||||||
known commit. If the module is not already required at a later version
|
|
||||||
(for example, a pre-release newer than the latest release), get will use
|
|
||||||
the version it looked up. Otherwise, get will use the currently
|
|
||||||
required version.
|
|
||||||
|
|
||||||
This default version selection can be overridden by adding an @version
|
To upgrade or downgrade a package to a specific version:
|
||||||
suffix to the package argument, as in 'go get golang.org/x/text@v0.3.0'.
|
|
||||||
The version may be a prefix: @v1 denotes the latest available version starting
|
|
||||||
with v1. See 'go help modules' under the heading 'Module queries' for the
|
|
||||||
full query syntax.
|
|
||||||
|
|
||||||
For modules stored in source control repositories, the version suffix can
|
go get example.com/pkg@v1.2.3
|
||||||
also be a commit hash, branch identifier, or other syntax known to the
|
|
||||||
source control system, as in 'go get golang.org/x/text@master'. Note that
|
|
||||||
branches with names that overlap with other module query syntax cannot be
|
|
||||||
selected explicitly. For example, the suffix @v2 means the latest version
|
|
||||||
starting with v2, not the branch named v2.
|
|
||||||
|
|
||||||
If a module under consideration is already a dependency of the current
|
To remove a dependency on a module and downgrade modules that require it:
|
||||||
development module, then get will update the required version.
|
|
||||||
Specifying a version earlier than the current required version is valid and
|
|
||||||
downgrades the dependency. The version suffix @none indicates that the
|
|
||||||
dependency should be removed entirely, downgrading or removing modules
|
|
||||||
depending on it as needed.
|
|
||||||
|
|
||||||
The version suffix @latest explicitly requests the latest minor release of
|
go get example.com/mod@none
|
||||||
the module named by the given path. The suffix @upgrade is like @latest but
|
|
||||||
will not downgrade a module if it is already required at a revision or
|
|
||||||
pre-release version newer than the latest released version. The suffix
|
|
||||||
@patch requests the latest patch release: the latest released version
|
|
||||||
with the same major and minor version numbers as the currently required
|
|
||||||
version. Like @upgrade, @patch will not downgrade a module already required
|
|
||||||
at a newer version. If the path is not already required, @upgrade is
|
|
||||||
equivalent to @latest, and @patch is disallowed.
|
|
||||||
|
|
||||||
Although get defaults to using the latest version of the module containing
|
See https://golang.org/ref/mod#go-get for details.
|
||||||
a named package, it does not use the latest version of that module's
|
|
||||||
dependencies. Instead it prefers to use the specific dependency versions
|
The 'go install' command may be used to build and install packages. When a
|
||||||
requested by that module. For example, if the latest A requires module
|
version is specified, 'go install' runs in module-aware mode and ignores
|
||||||
B v1.2.3, while B v1.2.4 and v1.3.1 are also available, then 'go get A'
|
the go.mod file in the current directory. For example:
|
||||||
will use the latest A but then use B v1.2.3, as requested by A. (If there
|
|
||||||
are competing requirements for a particular module, then 'go get' resolves
|
go install example.com/pkg@v1.2.3
|
||||||
those requirements by taking the maximum requested version.)
|
go install example.com/pkg@latest
|
||||||
|
|
||||||
|
See 'go help install' or https://golang.org/ref/mod#go-install for details.
|
||||||
|
|
||||||
|
In addition to build flags (listed in 'go help build') 'go get' accepts the
|
||||||
|
following flags.
|
||||||
|
|
||||||
The -t flag instructs get to consider modules needed to build tests of
|
The -t flag instructs get to consider modules needed to build tests of
|
||||||
packages specified on the command line.
|
packages specified on the command line.
|
||||||
|
|
||||||
The -u flag instructs get to update modules providing dependencies
|
The -u flag instructs get to update modules providing dependencies
|
||||||
of packages named on the command line to use newer minor or patch
|
of packages named on the command line to use newer minor or patch
|
||||||
releases when available. Continuing the previous example, 'go get -u A'
|
releases when available.
|
||||||
will use the latest A with B v1.3.1 (not B v1.2.3). If B requires module C,
|
|
||||||
but C does not provide any packages needed to build packages in A
|
|
||||||
(not including tests), then C will not be updated.
|
|
||||||
|
|
||||||
The -u=patch flag (not -u patch) also instructs get to update dependencies,
|
The -u=patch flag (not -u patch) also instructs get to update dependencies,
|
||||||
but changes the default to select patch releases.
|
but changes the default to select patch releases.
|
||||||
Continuing the previous example,
|
|
||||||
'go get -u=patch A@latest' will use the latest A with B v1.2.4 (not B v1.2.3),
|
|
||||||
while 'go get -u=patch A' will use a patch release of A instead.
|
|
||||||
|
|
||||||
When the -t and -u flags are used together, get will update
|
When the -t and -u flags are used together, get will update
|
||||||
test dependencies as well.
|
test dependencies as well.
|
||||||
|
|
||||||
In general, adding a new dependency may require upgrading
|
|
||||||
existing dependencies to keep a working build, and 'go get' does
|
|
||||||
this automatically. Similarly, downgrading one dependency may
|
|
||||||
require downgrading other dependencies, and 'go get' does
|
|
||||||
this automatically as well.
|
|
||||||
|
|
||||||
The -insecure flag permits fetching from repositories and resolving
|
The -insecure flag permits fetching from repositories and resolving
|
||||||
custom domains using insecure schemes such as HTTP, and also bypassess
|
custom domains using insecure schemes such as HTTP, and also bypassess
|
||||||
module sum validation using the checksum database. Use with caution.
|
module sum validation using the checksum database. Use with caution.
|
||||||
|
@ -143,12 +107,8 @@ To permit the use of insecure schemes, use the GOINSECURE environment
|
||||||
variable instead. To bypass module sum validation, use GOPRIVATE or
|
variable instead. To bypass module sum validation, use GOPRIVATE or
|
||||||
GONOSUMDB. See 'go help environment' for details.
|
GONOSUMDB. See 'go help environment' for details.
|
||||||
|
|
||||||
The second step is to download (if needed), build, and install
|
The -d flag instructs get not to build or install packages. get will only
|
||||||
the named packages.
|
update go.mod and download source code needed to build packages.
|
||||||
|
|
||||||
The -d flag instructs get to skip this step, downloading source code
|
|
||||||
needed to build the named packages and their dependencies, but not
|
|
||||||
building or installing.
|
|
||||||
|
|
||||||
Building and installing packages with get is deprecated. In a future release,
|
Building and installing packages with get is deprecated. In a future release,
|
||||||
the -d flag will be enabled by default, and 'go get' will be only be used to
|
the -d flag will be enabled by default, and 'go get' will be only be used to
|
||||||
|
@ -157,31 +117,14 @@ dependencies from the current module, use 'go install'. To install a package
|
||||||
ignoring the current module, use 'go install' with an @version suffix like
|
ignoring the current module, use 'go install' with an @version suffix like
|
||||||
"@latest" after each argument.
|
"@latest" after each argument.
|
||||||
|
|
||||||
If an argument names a module but not a package (because there is no
|
For more about modules, see https://golang.org/ref/mod.
|
||||||
Go source code in the module's root directory), then the install step
|
|
||||||
is skipped for that argument, instead of causing a build failure.
|
|
||||||
For example 'go get golang.org/x/perf' succeeds even though there
|
|
||||||
is no code corresponding to that import path.
|
|
||||||
|
|
||||||
Note that package patterns are allowed and are expanded after resolving
|
|
||||||
the module versions. For example, 'go get golang.org/x/perf/cmd/...'
|
|
||||||
adds the latest golang.org/x/perf and then installs the commands in that
|
|
||||||
latest version.
|
|
||||||
|
|
||||||
With no package arguments, 'go get' applies to Go package in the
|
|
||||||
current directory, if any. In particular, 'go get -u' and
|
|
||||||
'go get -u=patch' update all the dependencies of that package.
|
|
||||||
With no package arguments and also without -u, 'go get' is not much more
|
|
||||||
than 'go install', and 'go get -d' not much more than 'go list'.
|
|
||||||
|
|
||||||
For more about modules, see 'go help modules'.
|
|
||||||
|
|
||||||
For more about specifying packages, see 'go help packages'.
|
For more about specifying packages, see 'go help packages'.
|
||||||
|
|
||||||
This text describes the behavior of get using modules to manage source
|
This text describes the behavior of get using modules to manage source
|
||||||
code and dependencies. If instead the go command is running in GOPATH
|
code and dependencies. If instead the go command is running in GOPATH
|
||||||
mode, the details of get's flags and effects change, as does 'go help get'.
|
mode, the details of get's flags and effects change, as does 'go help get'.
|
||||||
See 'go help modules' and 'go help gopath-get'.
|
See 'go help gopath-get'.
|
||||||
|
|
||||||
See also: go build, go install, go clean, go mod.
|
See also: go build, go install, go clean, go mod.
|
||||||
`,
|
`,
|
||||||
|
@ -1558,7 +1501,7 @@ func (r *resolver) checkPackagesAndRetractions(ctx context.Context, pkgPatterns
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if retractPath != "" {
|
if retractPath != "" {
|
||||||
fmt.Fprintf(os.Stderr, "go: run 'go get %s@latest' to switch to the latest unretracted version\n", retractPath)
|
fmt.Fprintf(os.Stderr, "go: to switch to the latest unretracted version, run:\n\tgo get %s@latest", retractPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -281,14 +281,14 @@ func reportError(q *query, err error) {
|
||||||
// TODO(bcmills): Use errors.As to unpack these errors instead of parsing
|
// TODO(bcmills): Use errors.As to unpack these errors instead of parsing
|
||||||
// strings with regular expressions.
|
// strings with regular expressions.
|
||||||
|
|
||||||
patternRE := regexp.MustCompile("(?m)(?:[ \t(\"`]|^)" + regexp.QuoteMeta(q.pattern) + "(?:[ @:)\"`]|$)")
|
patternRE := regexp.MustCompile("(?m)(?:[ \t(\"`]|^)" + regexp.QuoteMeta(q.pattern) + "(?:[ @:;)\"`]|$)")
|
||||||
if patternRE.MatchString(errStr) {
|
if patternRE.MatchString(errStr) {
|
||||||
if q.rawVersion == "" {
|
if q.rawVersion == "" {
|
||||||
base.Errorf("go get: %s", errStr)
|
base.Errorf("go get: %s", errStr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
versionRE := regexp.MustCompile("(?m)(?:[ @(\"`]|^)" + regexp.QuoteMeta(q.version) + "(?:[ :)\"`]|$)")
|
versionRE := regexp.MustCompile("(?m)(?:[ @(\"`]|^)" + regexp.QuoteMeta(q.version) + "(?:[ :;)\"`]|$)")
|
||||||
if versionRE.MatchString(errStr) {
|
if versionRE.MatchString(errStr) {
|
||||||
base.Errorf("go get: %s", errStr)
|
base.Errorf("go get: %s", errStr)
|
||||||
return
|
return
|
||||||
|
|
|
@ -28,6 +28,11 @@ import (
|
||||||
//
|
//
|
||||||
var buildList []module.Version
|
var buildList []module.Version
|
||||||
|
|
||||||
|
// additionalExplicitRequirements is a list of modules paths for which
|
||||||
|
// WriteGoMod should record explicit requirements, even if they would be
|
||||||
|
// selected without those requirements. Each path must also appear in buildList.
|
||||||
|
var additionalExplicitRequirements []string
|
||||||
|
|
||||||
// capVersionSlice returns s with its cap reduced to its length.
|
// capVersionSlice returns s with its cap reduced to its length.
|
||||||
func capVersionSlice(s []module.Version) []module.Version {
|
func capVersionSlice(s []module.Version) []module.Version {
|
||||||
return s[:len(s):len(s)]
|
return s[:len(s):len(s)]
|
||||||
|
@ -121,6 +126,12 @@ func EditBuildList(ctx context.Context, add, mustSelect []module.Version) error
|
||||||
|
|
||||||
if !inconsistent {
|
if !inconsistent {
|
||||||
buildList = final
|
buildList = final
|
||||||
|
additionalExplicitRequirements = make([]string, 0, len(mustSelect))
|
||||||
|
for _, m := range mustSelect {
|
||||||
|
if m.Version != "none" {
|
||||||
|
additionalExplicitRequirements = append(additionalExplicitRequirements, m.Path)
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,395 +12,16 @@ var HelpModules = &base.Command{
|
||||||
UsageLine: "modules",
|
UsageLine: "modules",
|
||||||
Short: "modules, module versions, and more",
|
Short: "modules, module versions, and more",
|
||||||
Long: `
|
Long: `
|
||||||
A module is a collection of related Go packages.
|
Modules are how Go manages dependencies.
|
||||||
Modules are the unit of source code interchange and versioning.
|
|
||||||
The go command has direct support for working with modules,
|
|
||||||
including recording and resolving dependencies on other modules.
|
|
||||||
Modules replace the old GOPATH-based approach to specifying
|
|
||||||
which source files are used in a given build.
|
|
||||||
|
|
||||||
Module support
|
A module is a collection of packages that are released, versioned, and
|
||||||
|
distributed together. Modules may be downloaded directly from version control
|
||||||
|
repositories or from module proxy servers.
|
||||||
|
|
||||||
The go command includes support for Go modules. Module-aware mode is active
|
For a series of tutorials on modules, see
|
||||||
by default whenever a go.mod file is found in the current directory or in
|
https://golang.org/doc/tutorial/create-module.
|
||||||
any parent directory.
|
|
||||||
|
|
||||||
The quickest way to take advantage of module support is to check out your
|
For a detailed reference on modules, see https://golang.org/ref/mod.
|
||||||
repository, create a go.mod file (described in the next section) there, and run
|
|
||||||
go commands from within that file tree.
|
|
||||||
|
|
||||||
For more fine-grained control, the go command continues to respect
|
|
||||||
a temporary environment variable, GO111MODULE, which can be set to one
|
|
||||||
of three string values: off, on, or auto (the default).
|
|
||||||
If GO111MODULE=on, then the go command requires the use of modules,
|
|
||||||
never consulting GOPATH. We refer to this as the command
|
|
||||||
being module-aware or running in "module-aware mode".
|
|
||||||
If GO111MODULE=off, then the go command never uses
|
|
||||||
module support. Instead it looks in vendor directories and GOPATH
|
|
||||||
to find dependencies; we now refer to this as "GOPATH mode."
|
|
||||||
If GO111MODULE=auto or is unset, then the go command enables or disables
|
|
||||||
module support based on the current directory.
|
|
||||||
Module support is enabled only when the current directory contains a
|
|
||||||
go.mod file or is below a directory containing a go.mod file.
|
|
||||||
|
|
||||||
In module-aware mode, GOPATH no longer defines the meaning of imports
|
|
||||||
during a build, but it still stores downloaded dependencies (in GOPATH/pkg/mod)
|
|
||||||
and installed commands (in GOPATH/bin, unless GOBIN is set).
|
|
||||||
|
|
||||||
Defining a module
|
|
||||||
|
|
||||||
A module is defined by a tree of Go source files with a go.mod file
|
|
||||||
in the tree's root directory. The directory containing the go.mod file
|
|
||||||
is called the module root. Typically the module root will also correspond
|
|
||||||
to a source code repository root (but in general it need not).
|
|
||||||
The module is the set of all Go packages in the module root and its
|
|
||||||
subdirectories, but excluding subtrees with their own go.mod files.
|
|
||||||
|
|
||||||
The "module path" is the import path prefix corresponding to the module root.
|
|
||||||
The go.mod file defines the module path and lists the specific versions
|
|
||||||
of other modules that should be used when resolving imports during a build,
|
|
||||||
by giving their module paths and versions.
|
|
||||||
|
|
||||||
For example, this go.mod declares that the directory containing it is the root
|
|
||||||
of the module with path example.com/m, and it also declares that the module
|
|
||||||
depends on specific versions of golang.org/x/text and gopkg.in/yaml.v2:
|
|
||||||
|
|
||||||
module example.com/m
|
|
||||||
|
|
||||||
require (
|
|
||||||
golang.org/x/text v0.3.0
|
|
||||||
gopkg.in/yaml.v2 v2.1.0
|
|
||||||
)
|
|
||||||
|
|
||||||
The go.mod file can also specify replacements and excluded versions
|
|
||||||
that only apply when building the module directly; they are ignored
|
|
||||||
when the module is incorporated into a larger build.
|
|
||||||
For more about the go.mod file, see 'go help go.mod'.
|
|
||||||
|
|
||||||
To start a new module, simply create a go.mod file in the root of the
|
|
||||||
module's directory tree, containing only a module statement.
|
|
||||||
The 'go mod init' command can be used to do this:
|
|
||||||
|
|
||||||
go mod init example.com/m
|
|
||||||
|
|
||||||
In a project already using an existing dependency management tool like
|
|
||||||
godep, glide, or dep, 'go mod init' will also add require statements
|
|
||||||
matching the existing configuration.
|
|
||||||
|
|
||||||
Once the go.mod file exists, no additional steps are required:
|
|
||||||
go commands like 'go build', 'go test', or even 'go list' will automatically
|
|
||||||
add new dependencies as needed to satisfy imports.
|
|
||||||
|
|
||||||
The main module and the build list
|
|
||||||
|
|
||||||
The "main module" is the module containing the directory where the go command
|
|
||||||
is run. The go command finds the module root by looking for a go.mod in the
|
|
||||||
current directory, or else the current directory's parent directory,
|
|
||||||
or else the parent's parent directory, and so on.
|
|
||||||
|
|
||||||
The main module's go.mod file defines the precise set of packages available
|
|
||||||
for use by the go command, through require, replace, and exclude statements.
|
|
||||||
Dependency modules, found by following require statements, also contribute
|
|
||||||
to the definition of that set of packages, but only through their go.mod
|
|
||||||
files' require statements: any replace and exclude statements in dependency
|
|
||||||
modules are ignored. The replace and exclude statements therefore allow the
|
|
||||||
main module complete control over its own build, without also being subject
|
|
||||||
to complete control by dependencies.
|
|
||||||
|
|
||||||
The set of modules providing packages to builds is called the "build list".
|
|
||||||
The build list initially contains only the main module. Then the go command
|
|
||||||
adds to the list the exact module versions required by modules already
|
|
||||||
on the list, recursively, until there is nothing left to add to the list.
|
|
||||||
If multiple versions of a particular module are added to the list,
|
|
||||||
then at the end only the latest version (according to semantic version
|
|
||||||
ordering) is kept for use in the build.
|
|
||||||
|
|
||||||
The 'go list' command provides information about the main module
|
|
||||||
and the build list. For example:
|
|
||||||
|
|
||||||
go list -m # print path of main module
|
|
||||||
go list -m -f={{.Dir}} # print root directory of main module
|
|
||||||
go list -m all # print build list
|
|
||||||
|
|
||||||
Maintaining module requirements
|
|
||||||
|
|
||||||
The go.mod file is meant to be readable and editable by both programmers and
|
|
||||||
tools. Most updates to dependencies can be performed using "go get" and
|
|
||||||
"go mod tidy". Other module-aware build commands may be invoked using the
|
|
||||||
-mod=mod flag to automatically add missing requirements and fix inconsistencies.
|
|
||||||
|
|
||||||
The "go get" command updates go.mod to change the module versions used in a
|
|
||||||
build. An upgrade of one module may imply upgrading others, and similarly a
|
|
||||||
downgrade of one module may imply downgrading others. The "go get" command
|
|
||||||
makes these implied changes as well. See "go help module-get".
|
|
||||||
|
|
||||||
The "go mod" command provides other functionality for use in maintaining
|
|
||||||
and understanding modules and go.mod files. See "go help mod", particularly
|
|
||||||
"go help mod tidy" and "go help mod edit".
|
|
||||||
|
|
||||||
As part of maintaining the require statements in go.mod, the go command
|
|
||||||
tracks which ones provide packages imported directly by the current module
|
|
||||||
and which ones provide packages only used indirectly by other module
|
|
||||||
dependencies. Requirements needed only for indirect uses are marked with a
|
|
||||||
"// indirect" comment in the go.mod file. Indirect requirements may be
|
|
||||||
automatically removed from the go.mod file once they are implied by other
|
|
||||||
direct requirements. Indirect requirements only arise when using modules
|
|
||||||
that fail to state some of their own dependencies or when explicitly
|
|
||||||
upgrading a module's dependencies ahead of its own stated requirements.
|
|
||||||
|
|
||||||
The -mod build flag provides additional control over the updating and use of
|
|
||||||
go.mod for commands that build packages like "go build" and "go test".
|
|
||||||
|
|
||||||
If invoked with -mod=readonly (the default in most situations), the go command
|
|
||||||
reports an error if a package named on the command line or an imported package
|
|
||||||
is not provided by any module in the build list computed from the main module's
|
|
||||||
requirements. The go command also reports an error if a module's checksum is
|
|
||||||
missing from go.sum (see Module downloading and verification). Either go.mod or
|
|
||||||
go.sum must be updated in these situations.
|
|
||||||
|
|
||||||
If invoked with -mod=mod, the go command automatically updates go.mod and
|
|
||||||
go.sum, fixing inconsistencies and adding missing requirements and checksums
|
|
||||||
as needed. If the go command finds an unfamiliar import, it looks up the
|
|
||||||
module containing that import and adds a requirement for the latest version
|
|
||||||
of that module to go.mod. In most cases, therefore, one may add an import to
|
|
||||||
source code and run "go build", "go test", or even "go list" with -mod=mod:
|
|
||||||
as part of analyzing the package, the go command will resolve the import and
|
|
||||||
update the go.mod file.
|
|
||||||
|
|
||||||
If invoked with -mod=vendor, the go command loads packages from the main
|
|
||||||
module's vendor directory instead of downloading modules to and loading packages
|
|
||||||
from the module cache. The go command assumes the vendor directory holds
|
|
||||||
correct copies of dependencies, and it does not compute the set of required
|
|
||||||
module versions from go.mod files. However, the go command does check that
|
|
||||||
vendor/modules.txt (generated by "go mod vendor") contains metadata consistent
|
|
||||||
with go.mod.
|
|
||||||
|
|
||||||
If the go command is not invoked with a -mod flag, and the vendor directory
|
|
||||||
is present, and the "go" version in go.mod is 1.14 or higher, the go command
|
|
||||||
will act as if it were invoked with -mod=vendor. Otherwise, the -mod flag
|
|
||||||
defaults to -mod=readonly.
|
|
||||||
|
|
||||||
Note that neither "go get" nor the "go mod" subcommands accept the -mod flag.
|
|
||||||
|
|
||||||
Pseudo-versions
|
|
||||||
|
|
||||||
The go.mod file and the go command more generally use semantic versions as
|
|
||||||
the standard form for describing module versions, so that versions can be
|
|
||||||
compared to determine which should be considered earlier or later than another.
|
|
||||||
A module version like v1.2.3 is introduced by tagging a revision in the
|
|
||||||
underlying source repository. Untagged revisions can be referred to
|
|
||||||
using a "pseudo-version" like v0.0.0-yyyymmddhhmmss-abcdefabcdef,
|
|
||||||
where the time is the commit time in UTC and the final suffix is the prefix
|
|
||||||
of the commit hash. The time portion ensures that two pseudo-versions can
|
|
||||||
be compared to determine which happened later, the commit hash identifes
|
|
||||||
the underlying commit, and the prefix (v0.0.0- in this example) is derived from
|
|
||||||
the most recent tagged version in the commit graph before this commit.
|
|
||||||
|
|
||||||
There are three pseudo-version forms:
|
|
||||||
|
|
||||||
vX.0.0-yyyymmddhhmmss-abcdefabcdef is used when there is no earlier
|
|
||||||
versioned commit with an appropriate major version before the target commit.
|
|
||||||
(This was originally the only form, so some older go.mod files use this form
|
|
||||||
even for commits that do follow tags.)
|
|
||||||
|
|
||||||
vX.Y.Z-pre.0.yyyymmddhhmmss-abcdefabcdef is used when the most
|
|
||||||
recent versioned commit before the target commit is vX.Y.Z-pre.
|
|
||||||
|
|
||||||
vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdefabcdef is used when the most
|
|
||||||
recent versioned commit before the target commit is vX.Y.Z.
|
|
||||||
|
|
||||||
Pseudo-versions never need to be typed by hand: the go command will accept
|
|
||||||
the plain commit hash and translate it into a pseudo-version (or a tagged
|
|
||||||
version if available) automatically. This conversion is an example of a
|
|
||||||
module query.
|
|
||||||
|
|
||||||
Module queries
|
|
||||||
|
|
||||||
The go command accepts a "module query" in place of a module version
|
|
||||||
both on the command line and in the main module's go.mod file.
|
|
||||||
(After evaluating a query found in the main module's go.mod file,
|
|
||||||
the go command updates the file to replace the query with its result.)
|
|
||||||
|
|
||||||
A fully-specified semantic version, such as "v1.2.3",
|
|
||||||
evaluates to that specific version.
|
|
||||||
|
|
||||||
A semantic version prefix, such as "v1" or "v1.2",
|
|
||||||
evaluates to the latest available tagged version with that prefix.
|
|
||||||
|
|
||||||
A semantic version comparison, such as "<v1.2.3" or ">=v1.5.6",
|
|
||||||
evaluates to the available tagged version nearest to the comparison target
|
|
||||||
(the latest version for < and <=, the earliest version for > and >=).
|
|
||||||
|
|
||||||
The string "latest" matches the latest available tagged version,
|
|
||||||
or else the underlying source repository's latest untagged revision.
|
|
||||||
|
|
||||||
The string "upgrade" is like "latest", but if the module is
|
|
||||||
currently required at a later version than the version "latest"
|
|
||||||
would select (for example, a newer pre-release version), "upgrade"
|
|
||||||
will select the later version instead.
|
|
||||||
|
|
||||||
The string "patch" matches the latest available tagged version
|
|
||||||
of a module with the same major and minor version numbers as the
|
|
||||||
currently required version. If no version is currently required,
|
|
||||||
"patch" is equivalent to "latest".
|
|
||||||
|
|
||||||
A revision identifier for the underlying source repository, such as
|
|
||||||
a commit hash prefix, revision tag, or branch name, selects that
|
|
||||||
specific code revision. If the revision is also tagged with a
|
|
||||||
semantic version, the query evaluates to that semantic version.
|
|
||||||
Otherwise the query evaluates to a pseudo-version for the commit.
|
|
||||||
Note that branches and tags with names that are matched by other
|
|
||||||
query syntax cannot be selected this way. For example, the query
|
|
||||||
"v2" means the latest version starting with "v2", not the branch
|
|
||||||
named "v2".
|
|
||||||
|
|
||||||
All queries prefer release versions to pre-release versions.
|
|
||||||
For example, "<v1.2.3" will prefer to return "v1.2.2"
|
|
||||||
instead of "v1.2.3-pre1", even though "v1.2.3-pre1" is nearer
|
|
||||||
to the comparison target.
|
|
||||||
|
|
||||||
Module versions disallowed by exclude statements in the
|
|
||||||
main module's go.mod are considered unavailable and cannot
|
|
||||||
be returned by queries.
|
|
||||||
|
|
||||||
For example, these commands are all valid:
|
|
||||||
|
|
||||||
go get github.com/gorilla/mux@latest # same (@latest is default for 'go get')
|
|
||||||
go get github.com/gorilla/mux@v1.6.2 # records v1.6.2
|
|
||||||
go get github.com/gorilla/mux@e3702bed2 # records v1.6.2
|
|
||||||
go get github.com/gorilla/mux@c856192 # records v0.0.0-20180517173623-c85619274f5d
|
|
||||||
go get github.com/gorilla/mux@master # records current meaning of master
|
|
||||||
|
|
||||||
Module compatibility and semantic versioning
|
|
||||||
|
|
||||||
The go command requires that modules use semantic versions and expects that
|
|
||||||
the versions accurately describe compatibility: it assumes that v1.5.4 is a
|
|
||||||
backwards-compatible replacement for v1.5.3, v1.4.0, and even v1.0.0.
|
|
||||||
More generally the go command expects that packages follow the
|
|
||||||
"import compatibility rule", which says:
|
|
||||||
|
|
||||||
"If an old package and a new package have the same import path,
|
|
||||||
the new package must be backwards compatible with the old package."
|
|
||||||
|
|
||||||
Because the go command assumes the import compatibility rule,
|
|
||||||
a module definition can only set the minimum required version of one
|
|
||||||
of its dependencies: it cannot set a maximum or exclude selected versions.
|
|
||||||
Still, the import compatibility rule is not a guarantee: it may be that
|
|
||||||
v1.5.4 is buggy and not a backwards-compatible replacement for v1.5.3.
|
|
||||||
Because of this, the go command never updates from an older version
|
|
||||||
to a newer version of a module unasked.
|
|
||||||
|
|
||||||
In semantic versioning, changing the major version number indicates a lack
|
|
||||||
of backwards compatibility with earlier versions. To preserve import
|
|
||||||
compatibility, the go command requires that modules with major version v2
|
|
||||||
or later use a module path with that major version as the final element.
|
|
||||||
For example, version v2.0.0 of example.com/m must instead use module path
|
|
||||||
example.com/m/v2, and packages in that module would use that path as
|
|
||||||
their import path prefix, as in example.com/m/v2/sub/pkg. Including the
|
|
||||||
major version number in the module path and import paths in this way is
|
|
||||||
called "semantic import versioning". Pseudo-versions for modules with major
|
|
||||||
version v2 and later begin with that major version instead of v0, as in
|
|
||||||
v2.0.0-20180326061214-4fc5987536ef.
|
|
||||||
|
|
||||||
As a special case, module paths beginning with gopkg.in/ continue to use the
|
|
||||||
conventions established on that system: the major version is always present,
|
|
||||||
and it is preceded by a dot instead of a slash: gopkg.in/yaml.v1
|
|
||||||
and gopkg.in/yaml.v2, not gopkg.in/yaml and gopkg.in/yaml/v2.
|
|
||||||
|
|
||||||
The go command treats modules with different module paths as unrelated:
|
|
||||||
it makes no connection between example.com/m and example.com/m/v2.
|
|
||||||
Modules with different major versions can be used together in a build
|
|
||||||
and are kept separate by the fact that their packages use different
|
|
||||||
import paths.
|
|
||||||
|
|
||||||
In semantic versioning, major version v0 is for initial development,
|
|
||||||
indicating no expectations of stability or backwards compatibility.
|
|
||||||
Major version v0 does not appear in the module path, because those
|
|
||||||
versions are preparation for v1.0.0, and v1 does not appear in the
|
|
||||||
module path either.
|
|
||||||
|
|
||||||
Code written before the semantic import versioning convention
|
|
||||||
was introduced may use major versions v2 and later to describe
|
|
||||||
the same set of unversioned import paths as used in v0 and v1.
|
|
||||||
To accommodate such code, if a source code repository has a
|
|
||||||
v2.0.0 or later tag for a file tree with no go.mod, the version is
|
|
||||||
considered to be part of the v1 module's available versions
|
|
||||||
and is given an +incompatible suffix when converted to a module
|
|
||||||
version, as in v2.0.0+incompatible. The +incompatible tag is also
|
|
||||||
applied to pseudo-versions derived from such versions, as in
|
|
||||||
v2.0.1-0.yyyymmddhhmmss-abcdefabcdef+incompatible.
|
|
||||||
|
|
||||||
In general, having a dependency in the build list (as reported by 'go list -m all')
|
|
||||||
on a v0 version, pre-release version, pseudo-version, or +incompatible version
|
|
||||||
is an indication that problems are more likely when upgrading that
|
|
||||||
dependency, since there is no expectation of compatibility for those.
|
|
||||||
|
|
||||||
See https://research.swtch.com/vgo-import for more information about
|
|
||||||
semantic import versioning, and see https://semver.org/ for more about
|
|
||||||
semantic versioning.
|
|
||||||
|
|
||||||
Module code layout
|
|
||||||
|
|
||||||
For now, see https://research.swtch.com/vgo-module for information
|
|
||||||
about how source code in version control systems is mapped to
|
|
||||||
module file trees.
|
|
||||||
|
|
||||||
Module downloading and verification
|
|
||||||
|
|
||||||
The go command can fetch modules from a proxy or connect to source control
|
|
||||||
servers directly, according to the setting of the GOPROXY environment
|
|
||||||
variable (see 'go help env'). The default setting for GOPROXY is
|
|
||||||
"https://proxy.golang.org,direct", which means to try the
|
|
||||||
Go module mirror run by Google and fall back to a direct connection
|
|
||||||
if the proxy reports that it does not have the module (HTTP error 404 or 410).
|
|
||||||
See https://proxy.golang.org/privacy for the service's privacy policy.
|
|
||||||
|
|
||||||
If GOPROXY is set to the string "direct", downloads use a direct connection to
|
|
||||||
source control servers. Setting GOPROXY to "off" disallows downloading modules
|
|
||||||
from any source. Otherwise, GOPROXY is expected to be list of module proxy URLs
|
|
||||||
separated by either comma (,) or pipe (|) characters, which control error
|
|
||||||
fallback behavior. For each request, the go command tries each proxy in
|
|
||||||
sequence. If there is an error, the go command will try the next proxy in the
|
|
||||||
list if the error is a 404 or 410 HTTP response or if the current proxy is
|
|
||||||
followed by a pipe character, indicating it is safe to fall back on any error.
|
|
||||||
|
|
||||||
The GOPRIVATE and GONOPROXY environment variables allow bypassing
|
|
||||||
the proxy for selected modules. See 'go help private' for details.
|
|
||||||
|
|
||||||
No matter the source of the modules, the go command checks downloads against
|
|
||||||
known checksums, to detect unexpected changes in the content of any specific
|
|
||||||
module version from one day to the next. This check first consults the current
|
|
||||||
module's go.sum file but falls back to the Go checksum database, controlled by
|
|
||||||
the GOSUMDB and GONOSUMDB environment variables. See 'go help module-auth'
|
|
||||||
for details.
|
|
||||||
|
|
||||||
See 'go help goproxy' for details about the proxy protocol and also
|
|
||||||
the format of the cached downloaded packages.
|
|
||||||
|
|
||||||
Modules and vendoring
|
|
||||||
|
|
||||||
When using modules, the go command typically satisfies dependencies by
|
|
||||||
downloading modules from their sources and using those downloaded copies
|
|
||||||
(after verification, as described in the previous section). Vendoring may
|
|
||||||
be used to allow interoperation with older versions of Go, or to ensure
|
|
||||||
that all files used for a build are stored together in a single file tree.
|
|
||||||
|
|
||||||
The command 'go mod vendor' constructs a directory named vendor in the main
|
|
||||||
module's root directory that contains copies of all packages needed to support
|
|
||||||
builds and tests of packages in the main module. 'go mod vendor' also
|
|
||||||
creates the file vendor/modules.txt that contains metadata about vendored
|
|
||||||
packages and module versions. This file should be kept consistent with go.mod:
|
|
||||||
when vendoring is used, 'go mod vendor' should be run after go.mod is updated.
|
|
||||||
|
|
||||||
If the vendor directory is present in the main module's root directory, it will
|
|
||||||
be used automatically if the "go" version in the main module's go.mod file is
|
|
||||||
1.14 or higher. Build commands like 'go build' and 'go test' will load packages
|
|
||||||
from the vendor directory instead of accessing the network or the local module
|
|
||||||
cache. To explicitly enable vendoring, invoke the go command with the flag
|
|
||||||
-mod=vendor. To disable vendoring, use the flag -mod=mod.
|
|
||||||
|
|
||||||
Unlike vendoring in GOPATH, the go command ignores vendor directories in
|
|
||||||
locations other than the main module's root directory.
|
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,87 +34,22 @@ file in its root. When the go command is run, it looks in the current
|
||||||
directory and then successive parent directories to find the go.mod
|
directory and then successive parent directories to find the go.mod
|
||||||
marking the root of the main (current) module.
|
marking the root of the main (current) module.
|
||||||
|
|
||||||
The go.mod file itself is line-oriented, with // comments but
|
The go.mod file format is described in detail at
|
||||||
no /* */ comments. Each line holds a single directive, made up of a
|
https://golang.org/ref/mod#go-mod-file.
|
||||||
verb followed by arguments. For example:
|
|
||||||
|
|
||||||
module my/thing
|
To create a new go.mod file, use 'go help init'. For details see
|
||||||
go 1.12
|
'go help mod init' or https://golang.org/ref/mod#go-mod-init.
|
||||||
require other/thing v1.0.2
|
|
||||||
require new/thing/v2 v2.3.4
|
|
||||||
exclude old/thing v1.2.3
|
|
||||||
replace bad/thing v1.4.5 => good/thing v1.4.5
|
|
||||||
retract v1.5.6
|
|
||||||
|
|
||||||
The verbs are
|
To add missing module requirements or remove unneeded requirements,
|
||||||
module, to define the module path;
|
use 'go mod tidy'. For details, see 'go help mod tidy' or
|
||||||
go, to set the expected language version;
|
https://golang.org/ref/mod#go-mod-tidy.
|
||||||
require, to require a particular module at a given version or later;
|
|
||||||
exclude, to exclude a particular module version from use;
|
|
||||||
replace, to replace a module version with a different module version; and
|
|
||||||
retract, to indicate a previously released version should not be used.
|
|
||||||
Exclude and replace apply only in the main module's go.mod and are ignored
|
|
||||||
in dependencies. See https://golang.org/ref/mod for details.
|
|
||||||
|
|
||||||
The leading verb can be factored out of adjacent lines to create a block,
|
To add, upgrade, downgrade, or remove a specific module requirement, use
|
||||||
like in Go imports:
|
'go get'. For details, see 'go help module-get' or
|
||||||
|
https://golang.org/ref/mod#go-get.
|
||||||
|
|
||||||
require (
|
To make other changes or to parse go.mod as JSON for use by other tools,
|
||||||
new/thing/v2 v2.3.4
|
use 'go mod edit'. See 'go help mod edit' or
|
||||||
old/thing v1.2.3
|
https://golang.org/ref/mod#go-mod-edit.
|
||||||
)
|
|
||||||
|
|
||||||
The go.mod file is designed both to be edited directly and to be
|
|
||||||
easily updated by tools. The 'go mod edit' command can be used to
|
|
||||||
parse and edit the go.mod file from programs and tools.
|
|
||||||
See 'go help mod edit'.
|
|
||||||
|
|
||||||
The go command automatically updates go.mod each time it uses the
|
|
||||||
module graph, to make sure go.mod always accurately reflects reality
|
|
||||||
and is properly formatted. For example, consider this go.mod file:
|
|
||||||
|
|
||||||
module M
|
|
||||||
|
|
||||||
require (
|
|
||||||
A v1
|
|
||||||
B v1.0.0
|
|
||||||
C v1.0.0
|
|
||||||
D v1.2.3
|
|
||||||
E dev
|
|
||||||
)
|
|
||||||
|
|
||||||
exclude D v1.2.3
|
|
||||||
|
|
||||||
The update rewrites non-canonical version identifiers to semver form,
|
|
||||||
so A's v1 becomes v1.0.0 and E's dev becomes the pseudo-version for the
|
|
||||||
latest commit on the dev branch, perhaps v0.0.0-20180523231146-b3f5c0f6e5f1.
|
|
||||||
|
|
||||||
The update modifies requirements to respect exclusions, so the
|
|
||||||
requirement on the excluded D v1.2.3 is updated to use the next
|
|
||||||
available version of D, perhaps D v1.2.4 or D v1.3.0.
|
|
||||||
|
|
||||||
The update removes redundant or misleading requirements.
|
|
||||||
For example, if A v1.0.0 itself requires B v1.2.0 and C v1.0.0,
|
|
||||||
then go.mod's requirement of B v1.0.0 is misleading (superseded by
|
|
||||||
A's need for v1.2.0), and its requirement of C v1.0.0 is redundant
|
|
||||||
(implied by A's need for the same version), so both will be removed.
|
|
||||||
If module M contains packages that directly import packages from B or
|
|
||||||
C, then the requirements will be kept but updated to the actual
|
|
||||||
versions being used.
|
|
||||||
|
|
||||||
Finally, the update reformats the go.mod in a canonical formatting, so
|
|
||||||
that future mechanical changes will result in minimal diffs.
|
|
||||||
|
|
||||||
Because the module graph defines the meaning of import statements, any
|
|
||||||
commands that load packages also use and therefore update go.mod,
|
|
||||||
including go build, go get, go install, go list, go test, go mod graph,
|
|
||||||
go mod tidy, and go mod why.
|
|
||||||
|
|
||||||
The expected language version, set by the go directive, determines
|
|
||||||
which language features are available when compiling the module.
|
|
||||||
Language features available in that version will be available for use.
|
|
||||||
Language features removed in earlier versions, or added in later versions,
|
|
||||||
will not be available. Note that the language version does not affect
|
|
||||||
build tags, which are determined by the Go release being used.
|
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,10 +31,6 @@ type ImportMissingError struct {
|
||||||
Module module.Version
|
Module module.Version
|
||||||
QueryErr error
|
QueryErr error
|
||||||
|
|
||||||
// inAll indicates whether Path is in the "all" package pattern,
|
|
||||||
// and thus would be added by 'go mod tidy'.
|
|
||||||
inAll bool
|
|
||||||
|
|
||||||
// isStd indicates whether we would expect to find the package in the standard
|
// isStd indicates whether we would expect to find the package in the standard
|
||||||
// library. This is normally true for all dotless import paths, but replace
|
// library. This is normally true for all dotless import paths, but replace
|
||||||
// directives can cause us to treat the replaced paths as also being in
|
// directives can cause us to treat the replaced paths as also being in
|
||||||
|
@ -58,7 +54,7 @@ func (e *ImportMissingError) Error() string {
|
||||||
if e.QueryErr != nil {
|
if e.QueryErr != nil {
|
||||||
return fmt.Sprintf("cannot find module providing package %s: %v", e.Path, e.QueryErr)
|
return fmt.Sprintf("cannot find module providing package %s: %v", e.Path, e.QueryErr)
|
||||||
}
|
}
|
||||||
if cfg.BuildMod == "mod" {
|
if cfg.BuildMod == "mod" || (cfg.BuildMod == "readonly" && allowMissingModuleImports) {
|
||||||
return "cannot find module providing package " + e.Path
|
return "cannot find module providing package " + e.Path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,16 +63,14 @@ func (e *ImportMissingError) Error() string {
|
||||||
if !modfetch.IsZeroPseudoVersion(e.replaced.Version) {
|
if !modfetch.IsZeroPseudoVersion(e.replaced.Version) {
|
||||||
suggestArg = e.replaced.String()
|
suggestArg = e.replaced.String()
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("module %s provides package %s and is replaced but not required; try 'go get -d %s' to add it", e.replaced.Path, e.Path, suggestArg)
|
return fmt.Sprintf("module %s provides package %s and is replaced but not required; to add it:\n\tgo get %s", e.replaced.Path, e.Path, suggestArg)
|
||||||
}
|
}
|
||||||
|
|
||||||
suggestion := ""
|
suggestion := ""
|
||||||
if !HasModRoot() {
|
if !HasModRoot() {
|
||||||
suggestion = ": working directory is not part of a module"
|
suggestion = ": working directory is not part of a module"
|
||||||
} else if e.inAll {
|
|
||||||
suggestion = "; try 'go mod tidy' to add it"
|
|
||||||
} else {
|
} else {
|
||||||
suggestion = fmt.Sprintf("; try 'go get -d %s' to add it", e.Path)
|
suggestion = fmt.Sprintf("; to add it:\n\tgo get %s", e.Path)
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("no required module provides package %s%s", e.Path, suggestion)
|
return fmt.Sprintf("no required module provides package %s%s", e.Path, suggestion)
|
||||||
}
|
}
|
||||||
|
@ -136,24 +130,57 @@ func (e *AmbiguousImportError) Error() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImportMissingSumError is reported in readonly mode when we need to check
|
// ImportMissingSumError is reported in readonly mode when we need to check
|
||||||
// if a module in the build list contains a package, but we don't have a sum
|
// if a module contains a package, but we don't have a sum for its .zip file.
|
||||||
// for its .zip file.
|
// We might need sums for multiple modules to verify the package is unique.
|
||||||
|
//
|
||||||
|
// TODO(#43653): consolidate multiple errors of this type into a single error
|
||||||
|
// that suggests a 'go get' command for root packages that transtively import
|
||||||
|
// packages from modules with missing sums. load.CheckPackageErrors would be
|
||||||
|
// a good place to consolidate errors, but we'll need to attach the import
|
||||||
|
// stack here.
|
||||||
type ImportMissingSumError struct {
|
type ImportMissingSumError struct {
|
||||||
importPath string
|
importPath string
|
||||||
found, inAll bool
|
found bool
|
||||||
|
mods []module.Version
|
||||||
|
importer, importerVersion string // optional, but used for additional context
|
||||||
|
importerIsTest bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ImportMissingSumError) Error() string {
|
func (e *ImportMissingSumError) Error() string {
|
||||||
|
var importParen string
|
||||||
|
if e.importer != "" {
|
||||||
|
importParen = fmt.Sprintf(" (imported by %s)", e.importer)
|
||||||
|
}
|
||||||
var message string
|
var message string
|
||||||
if e.found {
|
if e.found {
|
||||||
message = fmt.Sprintf("missing go.sum entry needed to verify package %s is provided by exactly one module", e.importPath)
|
message = fmt.Sprintf("missing go.sum entry needed to verify package %s%s is provided by exactly one module", e.importPath, importParen)
|
||||||
} else {
|
} else {
|
||||||
message = fmt.Sprintf("missing go.sum entry for module providing package %s", e.importPath)
|
message = fmt.Sprintf("missing go.sum entry for module providing package %s%s", e.importPath, importParen)
|
||||||
}
|
}
|
||||||
if e.inAll {
|
var hint string
|
||||||
return message + "; try 'go mod tidy' to add it"
|
if e.importer == "" {
|
||||||
|
// Importing package is unknown, or the missing package was named on the
|
||||||
|
// command line. Recommend 'go mod download' for the modules that could
|
||||||
|
// provide the package, since that shouldn't change go.mod.
|
||||||
|
args := make([]string, len(e.mods))
|
||||||
|
for i, mod := range e.mods {
|
||||||
|
args[i] = mod.Path
|
||||||
|
}
|
||||||
|
hint = fmt.Sprintf("; to add:\n\tgo mod download %s", strings.Join(args, " "))
|
||||||
|
} else {
|
||||||
|
// Importing package is known (common case). Recommend 'go get' on the
|
||||||
|
// current version of the importing package.
|
||||||
|
tFlag := ""
|
||||||
|
if e.importerIsTest {
|
||||||
|
tFlag = " -t"
|
||||||
|
}
|
||||||
|
version := ""
|
||||||
|
if e.importerVersion != "" {
|
||||||
|
version = "@" + e.importerVersion
|
||||||
|
}
|
||||||
|
hint = fmt.Sprintf("; to add:\n\tgo get%s %s%s", tFlag, e.importer, version)
|
||||||
}
|
}
|
||||||
return message
|
return message + hint
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ImportMissingSumError) ImportPath() string {
|
func (e *ImportMissingSumError) ImportPath() string {
|
||||||
|
@ -244,7 +271,7 @@ func importFromBuildList(ctx context.Context, path string, buildList []module.Ve
|
||||||
// Check each module on the build list.
|
// Check each module on the build list.
|
||||||
var dirs []string
|
var dirs []string
|
||||||
var mods []module.Version
|
var mods []module.Version
|
||||||
haveSumErr := false
|
var sumErrMods []module.Version
|
||||||
for _, m := range buildList {
|
for _, m := range buildList {
|
||||||
if !maybeInModule(path, m.Path) {
|
if !maybeInModule(path, m.Path) {
|
||||||
// Avoid possibly downloading irrelevant modules.
|
// Avoid possibly downloading irrelevant modules.
|
||||||
|
@ -257,8 +284,9 @@ func importFromBuildList(ctx context.Context, path string, buildList []module.Ve
|
||||||
// We are missing a sum needed to fetch a module in the build list.
|
// We are missing a sum needed to fetch a module in the build list.
|
||||||
// We can't verify that the package is unique, and we may not find
|
// We can't verify that the package is unique, and we may not find
|
||||||
// the package at all. Keep checking other modules to decide which
|
// the package at all. Keep checking other modules to decide which
|
||||||
// error to report.
|
// error to report. Multiple sums may be missing if we need to look in
|
||||||
haveSumErr = true
|
// multiple nested modules to resolve the import.
|
||||||
|
sumErrMods = append(sumErrMods, m)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Report fetch error.
|
// Report fetch error.
|
||||||
|
@ -279,8 +307,12 @@ func importFromBuildList(ctx context.Context, path string, buildList []module.Ve
|
||||||
if len(mods) > 1 {
|
if len(mods) > 1 {
|
||||||
return module.Version{}, "", &AmbiguousImportError{importPath: path, Dirs: dirs, Modules: mods}
|
return module.Version{}, "", &AmbiguousImportError{importPath: path, Dirs: dirs, Modules: mods}
|
||||||
}
|
}
|
||||||
if haveSumErr {
|
if len(sumErrMods) > 0 {
|
||||||
return module.Version{}, "", &ImportMissingSumError{importPath: path, found: len(mods) > 0}
|
return module.Version{}, "", &ImportMissingSumError{
|
||||||
|
importPath: path,
|
||||||
|
mods: sumErrMods,
|
||||||
|
found: len(mods) > 0,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if len(mods) == 1 {
|
if len(mods) == 1 {
|
||||||
return mods[0], dirs[0], nil
|
return mods[0], dirs[0], nil
|
||||||
|
@ -365,7 +397,7 @@ func queryImport(ctx context.Context, path string) (module.Version, error) {
|
||||||
return module.Version{}, &ImportMissingError{Path: path, isStd: true}
|
return module.Version{}, &ImportMissingError{Path: path, isStd: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.BuildMod == "readonly" {
|
if cfg.BuildMod == "readonly" && !allowMissingModuleImports {
|
||||||
// In readonly mode, we can't write go.mod, so we shouldn't try to look up
|
// In readonly mode, we can't write go.mod, so we shouldn't try to look up
|
||||||
// the module. If readonly mode was enabled explicitly, include that in
|
// the module. If readonly mode was enabled explicitly, include that in
|
||||||
// the error message.
|
// the error message.
|
||||||
|
@ -547,7 +579,7 @@ func fetch(ctx context.Context, mod module.Version, needSum bool) (dir string, i
|
||||||
mod = r
|
mod = r
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.BuildMod == "readonly" && needSum && !modfetch.HaveSum(mod) {
|
if HasModRoot() && cfg.BuildMod == "readonly" && needSum && !modfetch.HaveSum(mod) {
|
||||||
return "", false, module.VersionError(mod, &sumMissingError{})
|
return "", false, module.VersionError(mod, &sumMissingError{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,10 +58,15 @@ var importTests = []struct {
|
||||||
func TestQueryImport(t *testing.T) {
|
func TestQueryImport(t *testing.T) {
|
||||||
testenv.MustHaveExternalNetwork(t)
|
testenv.MustHaveExternalNetwork(t)
|
||||||
testenv.MustHaveExecPath(t, "git")
|
testenv.MustHaveExecPath(t, "git")
|
||||||
defer func(old bool) {
|
|
||||||
allowMissingModuleImports = old
|
oldAllowMissingModuleImports := allowMissingModuleImports
|
||||||
}(allowMissingModuleImports)
|
oldRootMode := RootMode
|
||||||
AllowMissingModuleImports()
|
defer func() {
|
||||||
|
allowMissingModuleImports = oldAllowMissingModuleImports
|
||||||
|
RootMode = oldRootMode
|
||||||
|
}()
|
||||||
|
allowMissingModuleImports = true
|
||||||
|
RootMode = NoRoot
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -27,6 +28,7 @@ import (
|
||||||
"cmd/go/internal/modfetch"
|
"cmd/go/internal/modfetch"
|
||||||
"cmd/go/internal/mvs"
|
"cmd/go/internal/mvs"
|
||||||
"cmd/go/internal/search"
|
"cmd/go/internal/search"
|
||||||
|
"cmd/go/internal/str"
|
||||||
|
|
||||||
"golang.org/x/mod/modfile"
|
"golang.org/x/mod/modfile"
|
||||||
"golang.org/x/mod/module"
|
"golang.org/x/mod/module"
|
||||||
|
@ -200,6 +202,8 @@ func Init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// We're in module mode. Set any global variables that need to be set.
|
// We're in module mode. Set any global variables that need to be set.
|
||||||
|
cfg.ModulesEnabled = true
|
||||||
|
setDefaultBuildMod()
|
||||||
list := filepath.SplitList(cfg.BuildContext.GOPATH)
|
list := filepath.SplitList(cfg.BuildContext.GOPATH)
|
||||||
if len(list) == 0 || list[0] == "" {
|
if len(list) == 0 || list[0] == "" {
|
||||||
base.Fatalf("missing $GOPATH")
|
base.Fatalf("missing $GOPATH")
|
||||||
|
@ -209,8 +213,6 @@ func Init() {
|
||||||
base.Fatalf("$GOPATH/go.mod exists but should not")
|
base.Fatalf("$GOPATH/go.mod exists but should not")
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg.ModulesEnabled = true
|
|
||||||
|
|
||||||
if modRoot == "" {
|
if modRoot == "" {
|
||||||
// We're in module mode, but not inside a module.
|
// We're in module mode, but not inside a module.
|
||||||
//
|
//
|
||||||
|
@ -346,8 +348,8 @@ func die() {
|
||||||
// ensuring requirements are consistent. WriteGoMod should be called later to
|
// ensuring requirements are consistent. WriteGoMod should be called later to
|
||||||
// write changes out to disk or report errors in readonly mode.
|
// write changes out to disk or report errors in readonly mode.
|
||||||
//
|
//
|
||||||
// As a side-effect, LoadModFile sets a default for cfg.BuildMod if it does not
|
// As a side-effect, LoadModFile may change cfg.BuildMod to "vendor" if
|
||||||
// already have an explicit value.
|
// -mod wasn't set explicitly and automatic vendoring should be enabled.
|
||||||
func LoadModFile(ctx context.Context) {
|
func LoadModFile(ctx context.Context) {
|
||||||
if len(buildList) > 0 {
|
if len(buildList) > 0 {
|
||||||
return
|
return
|
||||||
|
@ -378,14 +380,14 @@ func LoadModFile(ctx context.Context) {
|
||||||
|
|
||||||
if f.Module == nil {
|
if f.Module == nil {
|
||||||
// No module declaration. Must add module path.
|
// No module declaration. Must add module path.
|
||||||
base.Fatalf("go: no module declaration in go.mod.\n\tRun 'go mod edit -module=example.com/mod' to specify the module path.")
|
base.Fatalf("go: no module declaration in go.mod. To specify the module path:\n\tgo mod edit -module=example.com/mod")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := checkModulePathLax(f.Module.Mod.Path); err != nil {
|
if err := checkModulePathLax(f.Module.Mod.Path); err != nil {
|
||||||
base.Fatalf("go: %v", err)
|
base.Fatalf("go: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
setDefaultBuildMod()
|
setDefaultBuildMod() // possibly enable automatic vendoring
|
||||||
modFileToBuildList()
|
modFileToBuildList()
|
||||||
if cfg.BuildMod == "vendor" {
|
if cfg.BuildMod == "vendor" {
|
||||||
readVendorList()
|
readVendorList()
|
||||||
|
@ -456,7 +458,7 @@ func CreateModFile(ctx context.Context, modPath string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !empty {
|
if !empty {
|
||||||
fmt.Fprintf(os.Stderr, "go: run 'go mod tidy' to add module requirements and sums\n")
|
fmt.Fprintf(os.Stderr, "go: to add module requirements and sums:\n\tgo mod tidy\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -584,8 +586,8 @@ func modFileToBuildList() {
|
||||||
buildList = list
|
buildList = list
|
||||||
}
|
}
|
||||||
|
|
||||||
// setDefaultBuildMod sets a default value for cfg.BuildMod
|
// setDefaultBuildMod sets a default value for cfg.BuildMod if the -mod flag
|
||||||
// if it is currently empty.
|
// wasn't provided. setDefaultBuildMod may be called multiple times.
|
||||||
func setDefaultBuildMod() {
|
func setDefaultBuildMod() {
|
||||||
if cfg.BuildModExplicit {
|
if cfg.BuildModExplicit {
|
||||||
// Don't override an explicit '-mod=' argument.
|
// Don't override an explicit '-mod=' argument.
|
||||||
|
@ -606,7 +608,7 @@ func setDefaultBuildMod() {
|
||||||
|
|
||||||
if fi, err := fsys.Stat(filepath.Join(modRoot, "vendor")); err == nil && fi.IsDir() {
|
if fi, err := fsys.Stat(filepath.Join(modRoot, "vendor")); err == nil && fi.IsDir() {
|
||||||
modGo := "unspecified"
|
modGo := "unspecified"
|
||||||
if index.goVersionV != "" {
|
if index != nil && index.goVersionV != "" {
|
||||||
if semver.Compare(index.goVersionV, "v1.14") >= 0 {
|
if semver.Compare(index.goVersionV, "v1.14") >= 0 {
|
||||||
// The Go version is at least 1.14, and a vendor directory exists.
|
// The Go version is at least 1.14, and a vendor directory exists.
|
||||||
// Set -mod=vendor by default.
|
// Set -mod=vendor by default.
|
||||||
|
@ -845,13 +847,15 @@ func AllowWriteGoMod() {
|
||||||
// MinReqs returns a Reqs with minimal additional dependencies of Target,
|
// MinReqs returns a Reqs with minimal additional dependencies of Target,
|
||||||
// as will be written to go.mod.
|
// as will be written to go.mod.
|
||||||
func MinReqs() mvs.Reqs {
|
func MinReqs() mvs.Reqs {
|
||||||
var retain []string
|
retain := append([]string{}, additionalExplicitRequirements...)
|
||||||
for _, m := range buildList[1:] {
|
for _, m := range buildList[1:] {
|
||||||
_, explicit := index.require[m]
|
_, explicit := index.require[m]
|
||||||
if explicit || loaded.direct[m.Path] {
|
if explicit || loaded.direct[m.Path] {
|
||||||
retain = append(retain, m.Path)
|
retain = append(retain, m.Path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sort.Strings(retain)
|
||||||
|
str.Uniq(&retain)
|
||||||
min, err := mvs.Req(Target, retain, &mvsReqs{buildList: buildList})
|
min, err := mvs.Req(Target, retain, &mvsReqs{buildList: buildList})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf("go: %v", err)
|
base.Fatalf("go: %v", err)
|
||||||
|
@ -903,7 +907,7 @@ func WriteGoMod() {
|
||||||
} else if cfg.BuildModReason != "" {
|
} else if cfg.BuildModReason != "" {
|
||||||
base.Fatalf("go: updates to go.mod needed, disabled by -mod=readonly\n\t(%s)", cfg.BuildModReason)
|
base.Fatalf("go: updates to go.mod needed, disabled by -mod=readonly\n\t(%s)", cfg.BuildModReason)
|
||||||
} else {
|
} else {
|
||||||
base.Fatalf("go: updates to go.mod needed; try 'go mod tidy' first")
|
base.Fatalf("go: updates to go.mod needed; to update it:\n\tgo mod tidy")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -972,9 +976,12 @@ func WriteGoMod() {
|
||||||
// It also contains entries for go.mod files needed for MVS (the version
|
// It also contains entries for go.mod files needed for MVS (the version
|
||||||
// of these entries ends with "/go.mod").
|
// of these entries ends with "/go.mod").
|
||||||
//
|
//
|
||||||
// If addDirect is true, the set also includes sums for modules directly
|
// If keepBuildListZips is true, the set also includes sums for zip files for
|
||||||
// required by go.mod, as represented by the index, with replacements applied.
|
// all modules in the build list with replacements applied. 'go get' and
|
||||||
func keepSums(addDirect bool) map[module.Version]bool {
|
// 'go mod download' may add sums to this set when adding a requirement on a
|
||||||
|
// module without a root package or when downloading a direct or indirect
|
||||||
|
// dependency.
|
||||||
|
func keepSums(keepBuildListZips bool) map[module.Version]bool {
|
||||||
// Re-derive the build list using the current list of direct requirements.
|
// Re-derive the build list using the current list of direct requirements.
|
||||||
// Keep the sum for the go.mod of each visited module version (or its
|
// Keep the sum for the go.mod of each visited module version (or its
|
||||||
// replacement).
|
// replacement).
|
||||||
|
@ -1003,19 +1010,20 @@ func keepSums(addDirect bool) map[module.Version]bool {
|
||||||
panic(fmt.Sprintf("unexpected error reloading build list: %v", err))
|
panic(fmt.Sprintf("unexpected error reloading build list: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
actualMods := make(map[string]module.Version)
|
||||||
|
for _, m := range buildList[1:] {
|
||||||
|
if r := Replacement(m); r.Path != "" {
|
||||||
|
actualMods[m.Path] = r
|
||||||
|
} else {
|
||||||
|
actualMods[m.Path] = m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Add entries for modules in the build list with paths that are prefixes of
|
// Add entries for modules in the build list with paths that are prefixes of
|
||||||
// paths of loaded packages. We need to retain sums for modules needed to
|
// paths of loaded packages. We need to retain sums for modules needed to
|
||||||
// report ambiguous import errors. We use our re-derived build list,
|
// report ambiguous import errors. We use our re-derived build list,
|
||||||
// since the global build list may have been tidied.
|
// since the global build list may have been tidied.
|
||||||
if loaded != nil {
|
if loaded != nil {
|
||||||
actualMods := make(map[string]module.Version)
|
|
||||||
for _, m := range buildList[1:] {
|
|
||||||
if r := Replacement(m); r.Path != "" {
|
|
||||||
actualMods[m.Path] = r
|
|
||||||
} else {
|
|
||||||
actualMods[m.Path] = m
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, pkg := range loaded.pkgs {
|
for _, pkg := range loaded.pkgs {
|
||||||
if pkg.testOf != nil || pkg.inStd || module.CheckImportPath(pkg.path) != nil {
|
if pkg.testOf != nil || pkg.inStd || module.CheckImportPath(pkg.path) != nil {
|
||||||
continue
|
continue
|
||||||
|
@ -1028,17 +1036,13 @@ func keepSums(addDirect bool) map[module.Version]bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add entries for modules directly required by go.mod.
|
// Add entries for the zip of each module in the build list.
|
||||||
if addDirect {
|
// We might not need all of these (tidy does not add them), but they may be
|
||||||
for m := range index.require {
|
// added by a specific 'go get' or 'go mod download' command to resolve
|
||||||
var kept module.Version
|
// missing import sum errors.
|
||||||
if r := Replacement(m); r.Path != "" {
|
if keepBuildListZips {
|
||||||
kept = r
|
for _, m := range actualMods {
|
||||||
} else {
|
keep[m] = true
|
||||||
kept = m
|
|
||||||
}
|
|
||||||
keep[kept] = true
|
|
||||||
keep[module.Version{Path: kept.Path, Version: kept.Version + "/go.mod"}] = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1058,9 +1062,8 @@ func (r *keepSumReqs) Required(m module.Version) ([]module.Version, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TrimGoSum() {
|
func TrimGoSum() {
|
||||||
// Don't retain sums for direct requirements in go.mod. When TrimGoSum is
|
// Don't retain sums for the zip file of every module in the build list.
|
||||||
// called, go.mod has not been updated, and it may contain requirements on
|
// We may not need them all to build the main module's packages.
|
||||||
// modules deleted from the build list.
|
keepBuildListZips := false
|
||||||
addDirect := false
|
modfetch.TrimGoSum(keepSums(keepBuildListZips))
|
||||||
modfetch.TrimGoSum(keepSums(addDirect))
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -280,11 +280,11 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
|
||||||
checkMultiplePaths()
|
checkMultiplePaths()
|
||||||
for _, pkg := range loaded.pkgs {
|
for _, pkg := range loaded.pkgs {
|
||||||
if pkg.err != nil {
|
if pkg.err != nil {
|
||||||
if pkg.flags.has(pkgInAll) {
|
if sumErr := (*ImportMissingSumError)(nil); errors.As(pkg.err, &sumErr) {
|
||||||
if imErr := (*ImportMissingError)(nil); errors.As(pkg.err, &imErr) {
|
if importer := pkg.stack; importer != nil {
|
||||||
imErr.inAll = true
|
sumErr.importer = importer.path
|
||||||
} else if sumErr := (*ImportMissingSumError)(nil); errors.As(pkg.err, &sumErr) {
|
sumErr.importerVersion = importer.mod.Version
|
||||||
sumErr.inAll = true
|
sumErr.importerIsTest = importer.testOf != nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -863,12 +863,21 @@ func loadFromRoots(params loaderParams) *loader {
|
||||||
for _, pkg := range ld.pkgs {
|
for _, pkg := range ld.pkgs {
|
||||||
if pkg.mod == Target {
|
if pkg.mod == Target {
|
||||||
for _, dep := range pkg.imports {
|
for _, dep := range pkg.imports {
|
||||||
if dep.mod.Path != "" {
|
if dep.mod.Path != "" && dep.mod.Path != Target.Path && index != nil {
|
||||||
|
_, explicit := index.require[dep.mod]
|
||||||
|
if allowWriteGoMod && cfg.BuildMod == "readonly" && !explicit {
|
||||||
|
// TODO(#40775): attach error to package instead of using
|
||||||
|
// base.Errorf. Ideally, 'go list' should not fail because of this,
|
||||||
|
// but today, LoadPackages calls WriteGoMod unconditionally, which
|
||||||
|
// would fail with a less clear message.
|
||||||
|
base.Errorf("go: %[1]s: package %[2]s imported from implicitly required module; to add missing requirements, run:\n\tgo get %[2]s@%[3]s", pkg.path, dep.path, dep.mod.Version)
|
||||||
|
}
|
||||||
ld.direct[dep.mod.Path] = true
|
ld.direct[dep.mod.Path] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
base.ExitIfErrors()
|
||||||
|
|
||||||
// If we didn't scan all of the imports from the main module, or didn't use
|
// If we didn't scan all of the imports from the main module, or didn't use
|
||||||
// imports.AnyTags, then we didn't necessarily load every package that
|
// imports.AnyTags, then we didn't necessarily load every package that
|
||||||
|
|
|
@ -446,10 +446,10 @@ func goModSummary(m module.Version) (*modFileSummary, error) {
|
||||||
if actual.Path == "" {
|
if actual.Path == "" {
|
||||||
actual = m
|
actual = m
|
||||||
}
|
}
|
||||||
if cfg.BuildMod == "readonly" && actual.Version != "" {
|
if HasModRoot() && cfg.BuildMod == "readonly" && actual.Version != "" {
|
||||||
key := module.Version{Path: actual.Path, Version: actual.Version + "/go.mod"}
|
key := module.Version{Path: actual.Path, Version: actual.Version + "/go.mod"}
|
||||||
if !modfetch.HaveSum(key) {
|
if !modfetch.HaveSum(key) {
|
||||||
suggestion := fmt.Sprintf("; try 'go mod download %s' to add it", m.Path)
|
suggestion := fmt.Sprintf("; to add it:\n\tgo mod download %s", m.Path)
|
||||||
return nil, module.VersionError(actual, &sumMissingError{suggestion: suggestion})
|
return nil, module.VersionError(actual, &sumMissingError{suggestion: suggestion})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,19 +111,3 @@ func (*mvsReqs) Previous(m module.Version) (module.Version, error) {
|
||||||
}
|
}
|
||||||
return module.Version{Path: m.Path, Version: "none"}, nil
|
return module.Version{Path: m.Path, Version: "none"}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// next returns the next version of m.Path after m.Version.
|
|
||||||
// It is only used by the exclusion processing in the Required method,
|
|
||||||
// not called directly by MVS.
|
|
||||||
func (*mvsReqs) next(m module.Version) (module.Version, error) {
|
|
||||||
// TODO(golang.org/issue/38714): thread tracing context through MVS.
|
|
||||||
list, err := versions(context.TODO(), m.Path, CheckAllowed)
|
|
||||||
if err != nil {
|
|
||||||
return module.Version{}, err
|
|
||||||
}
|
|
||||||
i := sort.Search(len(list), func(i int) bool { return semver.Compare(list[i], m.Version) > 0 })
|
|
||||||
if i < len(list) {
|
|
||||||
return module.Version{Path: m.Path, Version: list[i]}, nil
|
|
||||||
}
|
|
||||||
return module.Version{Path: m.Path, Version: "none"}, nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"cmd/go/internal/imports"
|
"cmd/go/internal/imports"
|
||||||
"cmd/go/internal/modfetch"
|
"cmd/go/internal/modfetch"
|
||||||
"cmd/go/internal/search"
|
"cmd/go/internal/search"
|
||||||
|
"cmd/go/internal/str"
|
||||||
"cmd/go/internal/trace"
|
"cmd/go/internal/trace"
|
||||||
|
|
||||||
"golang.org/x/mod/module"
|
"golang.org/x/mod/module"
|
||||||
|
@ -1005,13 +1006,8 @@ func (rr *replacementRepo) Versions(prefix string) ([]string, error) {
|
||||||
sort.Slice(versions, func(i, j int) bool {
|
sort.Slice(versions, func(i, j int) bool {
|
||||||
return semver.Compare(versions[i], versions[j]) < 0
|
return semver.Compare(versions[i], versions[j]) < 0
|
||||||
})
|
})
|
||||||
uniq := versions[:1]
|
str.Uniq(&versions)
|
||||||
for _, v := range versions {
|
return versions, nil
|
||||||
if v != uniq[len(uniq)-1] {
|
|
||||||
uniq = append(uniq, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return uniq, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *replacementRepo) Stat(rev string) (*modfetch.RevInfo, error) {
|
func (rr *replacementRepo) Stat(rev string) (*modfetch.RevInfo, error) {
|
||||||
|
|
|
@ -214,6 +214,6 @@ func checkVendorConsistency() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if vendErrors.Len() > 0 {
|
if vendErrors.Len() > 0 {
|
||||||
base.Fatalf("go: inconsistent vendoring in %s:%s\n\nrun 'go mod vendor' to sync, or use -mod=mod or -mod=readonly to ignore the vendor directory", modRoot, vendErrors)
|
base.Fatalf("go: inconsistent vendoring in %s:%s\n\n\tTo ignore the vendor directory, use -mod=readonly or -mod=mod.\n\tTo sync the vendor directory, run:\n\t\tgo mod vendor", modRoot, vendErrors)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,6 +96,20 @@ func Contains(x []string, s string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Uniq removes consecutive duplicate strings from ss.
|
||||||
|
func Uniq(ss *[]string) {
|
||||||
|
if len(*ss) <= 1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
uniq := (*ss)[:1]
|
||||||
|
for _, s := range *ss {
|
||||||
|
if s != uniq[len(uniq)-1] {
|
||||||
|
uniq = append(uniq, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*ss = uniq
|
||||||
|
}
|
||||||
|
|
||||||
func isSpaceByte(c byte) bool {
|
func isSpaceByte(c byte) bool {
|
||||||
return c == ' ' || c == '\t' || c == '\n' || c == '\r'
|
return c == ' ' || c == '\t' || c == '\n' || c == '\r'
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,9 @@ package main
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"flag"
|
"flag"
|
||||||
|
exec "internal/execabs"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
|
@ -11,10 +11,10 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/build"
|
"go/build"
|
||||||
|
exec "internal/execabs"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
|
@ -325,7 +325,7 @@ func testFlags(args []string) (packageNames, passToTest []string) {
|
||||||
if !testC {
|
if !testC {
|
||||||
buildFlag = "-i"
|
buildFlag = "-i"
|
||||||
}
|
}
|
||||||
fmt.Fprintf(os.Stderr, "flag %s is not a 'go test' flag (unknown flags cannot be used with %s)\n", firstUnknownFlag, buildFlag)
|
fmt.Fprintf(os.Stderr, "go test: unknown flag %s cannot be used with %s\n", firstUnknownFlag, buildFlag)
|
||||||
exitWithUsage()
|
exitWithUsage()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,9 @@ package tool
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
exec "internal/execabs"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/signal"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -85,7 +86,19 @@ func runTool(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
Stdout: os.Stdout,
|
Stdout: os.Stdout,
|
||||||
Stderr: os.Stderr,
|
Stderr: os.Stderr,
|
||||||
}
|
}
|
||||||
err := toolCmd.Run()
|
err := toolCmd.Start()
|
||||||
|
if err == nil {
|
||||||
|
c := make(chan os.Signal, 100)
|
||||||
|
signal.Notify(c)
|
||||||
|
go func() {
|
||||||
|
for sig := range c {
|
||||||
|
toolCmd.Process.Signal(sig)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
err = toolCmd.Wait()
|
||||||
|
signal.Stop(c)
|
||||||
|
close(c)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Only print about the exit status if the command
|
// Only print about the exit status if the command
|
||||||
// didn't even run (not an ExitError) or it didn't exit cleanly
|
// didn't even run (not an ExitError) or it didn't exit cleanly
|
||||||
|
|
|
@ -8,13 +8,13 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
exec "internal/execabs"
|
||||||
"internal/lazyregexp"
|
"internal/lazyregexp"
|
||||||
"internal/singleflight"
|
"internal/singleflight"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
urlpkg "net/url"
|
urlpkg "net/url"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -729,7 +729,7 @@ func checkGOVCS(vcs *Cmd, root string) error {
|
||||||
if private {
|
if private {
|
||||||
what = "private"
|
what = "private"
|
||||||
}
|
}
|
||||||
return fmt.Errorf("GOVCS disallows using %s for %s %s", vcs.Cmd, what, root)
|
return fmt.Errorf("GOVCS disallows using %s for %s %s; see 'go help vcs'", vcs.Cmd, what, root)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -10,9 +10,9 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
exec "internal/execabs"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,9 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/build"
|
"go/build"
|
||||||
|
exec "internal/execabs"
|
||||||
"internal/goroot"
|
"internal/goroot"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -113,7 +113,10 @@ and test commands:
|
||||||
created with -buildmode=shared.
|
created with -buildmode=shared.
|
||||||
-mod mode
|
-mod mode
|
||||||
module download mode to use: readonly, vendor, or mod.
|
module download mode to use: readonly, vendor, or mod.
|
||||||
See 'go help modules' for more.
|
By default, if a vendor directory is present and the go version in go.mod
|
||||||
|
is 1.14 or higher, the go command acts as if -mod=vendor were set.
|
||||||
|
Otherwise, the go command acts as if -mod=readonly were set.
|
||||||
|
See https://golang.org/ref/mod#build-commands for details.
|
||||||
-modcacherw
|
-modcacherw
|
||||||
leave newly-created directories in the module cache read-write
|
leave newly-created directories in the module cache read-write
|
||||||
instead of making them read-only.
|
instead of making them read-only.
|
||||||
|
|
|
@ -7,8 +7,8 @@ package work
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
exec "internal/execabs"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"cmd/go/internal/base"
|
"cmd/go/internal/base"
|
||||||
|
|
|
@ -13,13 +13,13 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
exec "internal/execabs"
|
||||||
"internal/lazyregexp"
|
"internal/lazyregexp"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -1166,6 +1166,7 @@ func (b *Builder) vet(ctx context.Context, a *Action) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(rsc): Why do we pass $GCCGO to go vet?
|
||||||
env := b.cCompilerEnv()
|
env := b.cCompilerEnv()
|
||||||
if cfg.BuildToolchainName == "gccgo" {
|
if cfg.BuildToolchainName == "gccgo" {
|
||||||
env = append(env, "GCCGO="+BuildToolchain.compiler())
|
env = append(env, "GCCGO="+BuildToolchain.compiler())
|
||||||
|
@ -2046,6 +2047,9 @@ func (b *Builder) runOut(a *Action, dir string, env []string, cmdargs ...interfa
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
cmd := exec.Command(cmdline[0], cmdline[1:]...)
|
cmd := exec.Command(cmdline[0], cmdline[1:]...)
|
||||||
|
if cmd.Path != "" {
|
||||||
|
cmd.Args[0] = cmd.Path
|
||||||
|
}
|
||||||
cmd.Stdout = &buf
|
cmd.Stdout = &buf
|
||||||
cmd.Stderr = &buf
|
cmd.Stderr = &buf
|
||||||
cleanup := passLongArgsInResponseFiles(cmd)
|
cleanup := passLongArgsInResponseFiles(cmd)
|
||||||
|
@ -2437,7 +2441,7 @@ func (b *Builder) fcExe() []string {
|
||||||
func (b *Builder) compilerExe(envValue string, def string) []string {
|
func (b *Builder) compilerExe(envValue string, def string) []string {
|
||||||
compiler := strings.Fields(envValue)
|
compiler := strings.Fields(envValue)
|
||||||
if len(compiler) == 0 {
|
if len(compiler) == 0 {
|
||||||
compiler = []string{def}
|
compiler = strings.Fields(def)
|
||||||
}
|
}
|
||||||
return compiler
|
return compiler
|
||||||
}
|
}
|
||||||
|
@ -2589,7 +2593,14 @@ func (b *Builder) gccArchArgs() []string {
|
||||||
case "386":
|
case "386":
|
||||||
return []string{"-m32"}
|
return []string{"-m32"}
|
||||||
case "amd64":
|
case "amd64":
|
||||||
|
if cfg.Goos == "darwin" {
|
||||||
|
return []string{"-arch", "x86_64", "-m64"}
|
||||||
|
}
|
||||||
return []string{"-m64"}
|
return []string{"-m64"}
|
||||||
|
case "arm64":
|
||||||
|
if cfg.Goos == "darwin" {
|
||||||
|
return []string{"-arch", "arm64"}
|
||||||
|
}
|
||||||
case "arm":
|
case "arm":
|
||||||
return []string{"-marm"} // not thumb
|
return []string{"-marm"} // not thumb
|
||||||
case "s390x":
|
case "s390x":
|
||||||
|
@ -2721,7 +2732,7 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgo
|
||||||
for i, f := range cgoLDFLAGS {
|
for i, f := range cgoLDFLAGS {
|
||||||
flags[i] = strconv.Quote(f)
|
flags[i] = strconv.Quote(f)
|
||||||
}
|
}
|
||||||
cgoenv = []string{"CGO_LDFLAGS=" + strings.Join(flags, " ")}
|
cgoenv = append(cgoenv, "CGO_LDFLAGS="+strings.Join(flags, " "))
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.BuildToolchainName == "gccgo" {
|
if cfg.BuildToolchainName == "gccgo" {
|
||||||
|
|
|
@ -6,8 +6,8 @@ package work
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
exec "internal/execabs"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -93,6 +93,12 @@ func (tools gccgoToolchain) gc(b *Builder, a *Action, archive string, importcfg,
|
||||||
args = append(args, "-I", root)
|
args = append(args, "-I", root)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if embedcfg != nil && b.gccSupportsFlag(args[:1], "-fgo-embedcfg=/dev/null") {
|
||||||
|
if err := b.writeFile(objdir+"embedcfg", embedcfg); err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
args = append(args, "-fgo-embedcfg="+objdir+"embedcfg")
|
||||||
|
}
|
||||||
|
|
||||||
if b.gccSupportsFlag(args[:1], "-ffile-prefix-map=a=b") {
|
if b.gccSupportsFlag(args[:1], "-ffile-prefix-map=a=b") {
|
||||||
if cfg.BuildTrimpath {
|
if cfg.BuildTrimpath {
|
||||||
|
|
|
@ -25,7 +25,7 @@ import (
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
exec "internal/execabs"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# embedded in a package, that is referenced by a Go assembly function.
|
# embedded in a package, that is referenced by a Go assembly function.
|
||||||
# See issue 33139.
|
# See issue 33139.
|
||||||
[!gc] skip
|
[!gc] skip
|
||||||
[!exec:cc] skip
|
[!cgo] skip
|
||||||
|
|
||||||
# External linking is not supported on linux/ppc64.
|
# External linking is not supported on linux/ppc64.
|
||||||
# See: https://github.com/golang/go/issues/8912
|
# See: https://github.com/golang/go/issues/8912
|
||||||
|
|
|
@ -19,7 +19,7 @@ stderr 'malformed module path "x/y.z": missing dot in first path element'
|
||||||
! go build ./useappengine
|
! go build ./useappengine
|
||||||
stderr '^useappengine[/\\]x.go:2:8: cannot find package$'
|
stderr '^useappengine[/\\]x.go:2:8: cannot find package$'
|
||||||
! go build ./usenonexistent
|
! go build ./usenonexistent
|
||||||
stderr '^usenonexistent[/\\]x.go:2:8: no required module provides package nonexistent.rsc.io; try ''go mod tidy'' to add it$'
|
stderr '^usenonexistent[/\\]x.go:2:8: no required module provides package nonexistent.rsc.io; to add it:\n\tgo get nonexistent.rsc.io$'
|
||||||
|
|
||||||
|
|
||||||
# 'get -d' should be similarly definitive
|
# 'get -d' should be similarly definitive
|
||||||
|
|
|
@ -21,6 +21,12 @@ cmpenv go.mod $WORK/go.mod.edit1
|
||||||
go mod edit -droprequire=x.1 -dropexclude=x.1@v1.2.1 -dropreplace=x.1@v1.3.0 -require=x.3@v1.99.0 -dropretract=v1.0.0 -dropretract=[v1.1.0,v1.2.0]
|
go mod edit -droprequire=x.1 -dropexclude=x.1@v1.2.1 -dropreplace=x.1@v1.3.0 -require=x.3@v1.99.0 -dropretract=v1.0.0 -dropretract=[v1.1.0,v1.2.0]
|
||||||
cmpenv go.mod $WORK/go.mod.edit2
|
cmpenv go.mod $WORK/go.mod.edit2
|
||||||
|
|
||||||
|
# -exclude and -retract reject invalid versions.
|
||||||
|
! go mod edit -exclude=example.com/m@bad
|
||||||
|
stderr '^go mod: -exclude=example.com/m@bad: version "bad" invalid: must be of the form v1.2.3$'
|
||||||
|
! go mod edit -retract=bad
|
||||||
|
stderr '^go mod: -retract=bad: version "bad" invalid: must be of the form v1.2.3$'
|
||||||
|
|
||||||
# go mod edit -json
|
# go mod edit -json
|
||||||
go mod edit -json
|
go mod edit -json
|
||||||
cmpenv stdout $WORK/go.mod.json
|
cmpenv stdout $WORK/go.mod.json
|
||||||
|
|
|
@ -6,5 +6,5 @@ env GOPROXY=https://proxy.golang.org,direct
|
||||||
env GOSUMDB=off
|
env GOSUMDB=off
|
||||||
|
|
||||||
go get -x -v -d golang.org/x/tools/cmd/goimports
|
go get -x -v -d golang.org/x/tools/cmd/goimports
|
||||||
stderr '# get https://proxy.golang.org/golang.org/x/tools/@latest'
|
stderr '# get https://proxy.golang.org/golang.org/x/tools/@v/list'
|
||||||
! stderr '# get https://golang.org'
|
! stderr '# get https://golang.org'
|
||||||
|
|
|
@ -19,7 +19,7 @@ exec $WORK/testimport$GOEXE other/x/y/z/w .
|
||||||
stdout w2.go
|
stdout w2.go
|
||||||
|
|
||||||
! exec $WORK/testimport$GOEXE gobuild.example.com/x/y/z/w .
|
! exec $WORK/testimport$GOEXE gobuild.example.com/x/y/z/w .
|
||||||
stderr 'no required module provides package gobuild.example.com/x/y/z/w; try ''go get -d gobuild.example.com/x/y/z/w'' to add it'
|
stderr 'no required module provides package gobuild.example.com/x/y/z/w; to add it:\n\tgo get gobuild.example.com/x/y/z/w'
|
||||||
|
|
||||||
cd z
|
cd z
|
||||||
exec $WORK/testimport$GOEXE other/x/y/z/w .
|
exec $WORK/testimport$GOEXE other/x/y/z/w .
|
||||||
|
|
|
@ -39,7 +39,7 @@ stdout example.com/notfound
|
||||||
|
|
||||||
# Listing the missing dependency directly should fail outright...
|
# Listing the missing dependency directly should fail outright...
|
||||||
! go list -f '{{if .Error}}error{{end}} {{if .Incomplete}}incomplete{{end}}' example.com/notfound
|
! go list -f '{{if .Error}}error{{end}} {{if .Incomplete}}incomplete{{end}}' example.com/notfound
|
||||||
stderr 'no required module provides package example.com/notfound; try ''go get -d example.com/notfound'' to add it'
|
stderr 'no required module provides package example.com/notfound; to add it:\n\tgo get example.com/notfound'
|
||||||
! stdout error
|
! stdout error
|
||||||
! stdout incomplete
|
! stdout incomplete
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ cmp go.mod go.mod.empty
|
||||||
# -mod=readonly should be set by default.
|
# -mod=readonly should be set by default.
|
||||||
env GOFLAGS=
|
env GOFLAGS=
|
||||||
! go list all
|
! go list all
|
||||||
stderr '^x.go:2:8: no required module provides package rsc\.io/quote; try ''go mod tidy'' to add it$'
|
stderr '^x.go:2:8: no required module provides package rsc\.io/quote; to add it:\n\tgo get rsc\.io/quote$'
|
||||||
cmp go.mod go.mod.empty
|
cmp go.mod go.mod.empty
|
||||||
|
|
||||||
env GOFLAGS=-mod=readonly
|
env GOFLAGS=-mod=readonly
|
||||||
|
@ -51,7 +51,7 @@ cmp go.mod go.mod.inconsistent
|
||||||
# We get a different message when -mod=readonly is used by default.
|
# We get a different message when -mod=readonly is used by default.
|
||||||
env GOFLAGS=
|
env GOFLAGS=
|
||||||
! go list
|
! go list
|
||||||
stderr '^go: updates to go.mod needed; try ''go mod tidy'' first$'
|
stderr '^go: updates to go.mod needed; to update it:\n\tgo mod tidy'
|
||||||
|
|
||||||
# However, it should not reject files missing a 'go' directive,
|
# However, it should not reject files missing a 'go' directive,
|
||||||
# since that was not always required.
|
# since that was not always required.
|
||||||
|
@ -75,15 +75,15 @@ cmp go.mod go.mod.indirect
|
||||||
|
|
||||||
cp go.mod.untidy go.mod
|
cp go.mod.untidy go.mod
|
||||||
! go list all
|
! go list all
|
||||||
stderr '^x.go:2:8: no required module provides package rsc.io/quote; try ''go mod tidy'' to add it$'
|
stderr '^x.go:2:8: no required module provides package rsc.io/quote; to add it:\n\tgo get rsc.io/quote$'
|
||||||
|
|
||||||
! go list -deps .
|
! go list -deps .
|
||||||
stderr '^x.go:2:8: no required module provides package rsc.io/quote; try ''go mod tidy'' to add it$'
|
stderr '^x.go:2:8: no required module provides package rsc.io/quote; to add it:\n\tgo get rsc.io/quote$'
|
||||||
|
|
||||||
# However, if we didn't see an import from the main module, we should suggest
|
# However, if we didn't see an import from the main module, we should suggest
|
||||||
# 'go get -d' instead, because we don't know whether 'go mod tidy' would add it.
|
# 'go get -d' instead, because we don't know whether 'go mod tidy' would add it.
|
||||||
! go list rsc.io/quote
|
! go list rsc.io/quote
|
||||||
stderr '^no required module provides package rsc.io/quote; try ''go get -d rsc.io/quote'' to add it$'
|
stderr '^no required module provides package rsc.io/quote; to add it:\n\tgo get rsc.io/quote$'
|
||||||
|
|
||||||
|
|
||||||
-- go.mod --
|
-- go.mod --
|
||||||
|
|
|
@ -66,7 +66,7 @@ stderr '^go: inconsistent vendoring in '$WORK[/\\]auto':$'
|
||||||
stderr '^\texample.com/printversion@v1.0.0: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt'
|
stderr '^\texample.com/printversion@v1.0.0: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt'
|
||||||
stderr '^\texample.com/unused: is replaced in go.mod, but not marked as replaced in vendor/modules.txt'
|
stderr '^\texample.com/unused: is replaced in go.mod, but not marked as replaced in vendor/modules.txt'
|
||||||
stderr '^\texample.com/version@v1.2.0: is replaced in go.mod, but not marked as replaced in vendor/modules.txt'
|
stderr '^\texample.com/version@v1.2.0: is replaced in go.mod, but not marked as replaced in vendor/modules.txt'
|
||||||
stderr '\n\nrun .go mod vendor. to sync, or use -mod=mod or -mod=readonly to ignore the vendor directory$'
|
stderr '^\tTo ignore the vendor directory, use -mod=readonly or -mod=mod.\n\tTo sync the vendor directory, run:\n\t\tgo mod vendor$'
|
||||||
|
|
||||||
# Module-specific subcommands should continue to load the full module graph.
|
# Module-specific subcommands should continue to load the full module graph.
|
||||||
go mod graph
|
go mod graph
|
||||||
|
@ -135,7 +135,7 @@ stderr '^go: inconsistent vendoring in '$WORK[/\\]auto':$'
|
||||||
stderr '^\texample.com/printversion@v1.0.0: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt'
|
stderr '^\texample.com/printversion@v1.0.0: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt'
|
||||||
stderr '^\texample.com/unused: is replaced in go.mod, but not marked as replaced in vendor/modules.txt'
|
stderr '^\texample.com/unused: is replaced in go.mod, but not marked as replaced in vendor/modules.txt'
|
||||||
stderr '^\texample.com/version@v1.2.0: is replaced in go.mod, but not marked as replaced in vendor/modules.txt'
|
stderr '^\texample.com/version@v1.2.0: is replaced in go.mod, but not marked as replaced in vendor/modules.txt'
|
||||||
stderr '\n\nrun .go mod vendor. to sync, or use -mod=mod or -mod=readonly to ignore the vendor directory$'
|
stderr '^\tTo ignore the vendor directory, use -mod=readonly or -mod=mod.\n\tTo sync the vendor directory, run:\n\t\tgo mod vendor$'
|
||||||
|
|
||||||
# If -mod=vendor is set, limited consistency checks should apply even when
|
# If -mod=vendor is set, limited consistency checks should apply even when
|
||||||
# the go version is 1.13 or earlier.
|
# the go version is 1.13 or earlier.
|
||||||
|
@ -151,7 +151,7 @@ cp $WORK/modules-bad-1.13.txt vendor/modules.txt
|
||||||
! go list -mod=vendor -f {{.Dir}} -tags tools all
|
! go list -mod=vendor -f {{.Dir}} -tags tools all
|
||||||
stderr '^go: inconsistent vendoring in '$WORK[/\\]auto':$'
|
stderr '^go: inconsistent vendoring in '$WORK[/\\]auto':$'
|
||||||
stderr '^\texample.com/printversion@v1.0.0: is explicitly required in go.mod, but vendor/modules.txt indicates example.com/printversion@v1.1.0$'
|
stderr '^\texample.com/printversion@v1.0.0: is explicitly required in go.mod, but vendor/modules.txt indicates example.com/printversion@v1.1.0$'
|
||||||
stderr '\n\nrun .go mod vendor. to sync, or use -mod=mod or -mod=readonly to ignore the vendor directory$'
|
stderr '^\tTo ignore the vendor directory, use -mod=readonly or -mod=mod.\n\tTo sync the vendor directory, run:\n\t\tgo mod vendor$'
|
||||||
|
|
||||||
# If the go version is still 1.13, 'go mod vendor' should write a
|
# If the go version is still 1.13, 'go mod vendor' should write a
|
||||||
# matching vendor/modules.txt containing the corrected 1.13 data.
|
# matching vendor/modules.txt containing the corrected 1.13 data.
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
# Test rejection of pkg@version in GOPATH mode.
|
# Test rejection of pkg@version in GOPATH mode.
|
||||||
env GO111MODULE=off
|
env GO111MODULE=off
|
||||||
! go get rsc.io/quote@v1.5.1
|
! go get rsc.io/quote@v1.5.1
|
||||||
stderr 'cannot use path@version syntax in GOPATH mode'
|
stderr '^go: can only use path@version syntax with ''go get'' and ''go install'' in module-aware mode$'
|
||||||
! go build rsc.io/quote@v1.5.1
|
! go build rsc.io/quote@v1.5.1
|
||||||
stderr 'cannot use path@version syntax in GOPATH mode'
|
stderr '^package rsc.io/quote@v1.5.1: can only use path@version syntax with ''go get'' and ''go install'' in module-aware mode$'
|
||||||
|
|
||||||
env GO111MODULE=on
|
env GO111MODULE=on
|
||||||
cd x
|
cd x
|
||||||
! go build rsc.io/quote@v1.5.1
|
! go build rsc.io/quote@v1.5.1
|
||||||
stderr 'can only use path@version syntax with ''go get'''
|
stderr '^package rsc.io/quote@v1.5.1: can only use path@version syntax with ''go get'' and ''go install'' in module-aware mode$'
|
||||||
|
|
||||||
-- x/go.mod --
|
-- x/go.mod --
|
||||||
module x
|
module x
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
package browser
|
package browser
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
exec "internal/execabs"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
//
|
//
|
||||||
// go tool test2json [-p pkg] [-t] [./pkg.test -test.v]
|
// go tool test2json [-p pkg] [-t] [./pkg.test -test.v [-test.paniconexit0]]
|
||||||
//
|
//
|
||||||
// Test2json runs the given test command and converts its output to JSON;
|
// Test2json runs the given test command and converts its output to JSON;
|
||||||
// with no command specified, test2json expects test output on standard input.
|
// with no command specified, test2json expects test output on standard input.
|
||||||
|
@ -18,6 +18,10 @@
|
||||||
//
|
//
|
||||||
// The -t flag requests that time stamps be added to each test event.
|
// The -t flag requests that time stamps be added to each test event.
|
||||||
//
|
//
|
||||||
|
// The test must be invoked with -test.v. Additionally passing
|
||||||
|
// -test.paniconexit0 will cause test2json to exit with a non-zero
|
||||||
|
// status if one of the tests being run calls os.Exit(0).
|
||||||
|
//
|
||||||
// Note that test2json is only intended for converting a single test
|
// Note that test2json is only intended for converting a single test
|
||||||
// binary's output. To convert the output of a "go test" command,
|
// binary's output. To convert the output of a "go test" command,
|
||||||
// use "go test -json" instead of invoking test2json directly.
|
// use "go test -json" instead of invoking test2json directly.
|
||||||
|
@ -82,9 +86,9 @@ package main
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
exec "internal/execabs"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
|
|
||||||
"cmd/internal/test2json"
|
"cmd/internal/test2json"
|
||||||
)
|
)
|
||||||
|
|
|
@ -28,7 +28,7 @@ golang.org/x/arch/x86/x86asm
|
||||||
golang.org/x/crypto/ed25519
|
golang.org/x/crypto/ed25519
|
||||||
golang.org/x/crypto/ed25519/internal/edwards25519
|
golang.org/x/crypto/ed25519/internal/edwards25519
|
||||||
golang.org/x/crypto/ssh/terminal
|
golang.org/x/crypto/ssh/terminal
|
||||||
# golang.org/x/mod v0.4.0
|
# golang.org/x/mod v0.4.1
|
||||||
## explicit
|
## explicit
|
||||||
golang.org/x/mod/internal/lazyregexp
|
golang.org/x/mod/internal/lazyregexp
|
||||||
golang.org/x/mod/modfile
|
golang.org/x/mod/modfile
|
||||||
|
@ -44,7 +44,7 @@ golang.org/x/mod/zip
|
||||||
golang.org/x/sys/internal/unsafeheader
|
golang.org/x/sys/internal/unsafeheader
|
||||||
golang.org/x/sys/unix
|
golang.org/x/sys/unix
|
||||||
golang.org/x/sys/windows
|
golang.org/x/sys/windows
|
||||||
# golang.org/x/tools v0.0.0-20201211025543-abf6a1d87e11
|
# golang.org/x/tools v0.0.0-20210107193943-4ed967dd8eff
|
||||||
## explicit
|
## explicit
|
||||||
golang.org/x/tools/go/analysis
|
golang.org/x/tools/go/analysis
|
||||||
golang.org/x/tools/go/analysis/internal/analysisflags
|
golang.org/x/tools/go/analysis/internal/analysisflags
|
||||||
|
|
|
@ -386,10 +386,11 @@ func p224Invert(out, in *p224FieldElement) {
|
||||||
// p224Contract converts a FieldElement to its unique, minimal form.
|
// p224Contract converts a FieldElement to its unique, minimal form.
|
||||||
//
|
//
|
||||||
// On entry, in[i] < 2**29
|
// On entry, in[i] < 2**29
|
||||||
// On exit, in[i] < 2**28
|
// On exit, out[i] < 2**28 and out < p
|
||||||
func p224Contract(out, in *p224FieldElement) {
|
func p224Contract(out, in *p224FieldElement) {
|
||||||
copy(out[:], in[:])
|
copy(out[:], in[:])
|
||||||
|
|
||||||
|
// First, carry the bits above 28 to the higher limb.
|
||||||
for i := 0; i < 7; i++ {
|
for i := 0; i < 7; i++ {
|
||||||
out[i+1] += out[i] >> 28
|
out[i+1] += out[i] >> 28
|
||||||
out[i] &= bottom28Bits
|
out[i] &= bottom28Bits
|
||||||
|
@ -397,10 +398,13 @@ func p224Contract(out, in *p224FieldElement) {
|
||||||
top := out[7] >> 28
|
top := out[7] >> 28
|
||||||
out[7] &= bottom28Bits
|
out[7] &= bottom28Bits
|
||||||
|
|
||||||
|
// Use the reduction identity to carry the overflow.
|
||||||
|
//
|
||||||
|
// a + top * 2²²⁴ = a + top * 2⁹⁶ - top
|
||||||
out[0] -= top
|
out[0] -= top
|
||||||
out[3] += top << 12
|
out[3] += top << 12
|
||||||
|
|
||||||
// We may just have made out[i] negative. So we carry down. If we made
|
// We may just have made out[0] negative. So we carry down. If we made
|
||||||
// out[0] negative then we know that out[3] is sufficiently positive
|
// out[0] negative then we know that out[3] is sufficiently positive
|
||||||
// because we just added to it.
|
// because we just added to it.
|
||||||
for i := 0; i < 3; i++ {
|
for i := 0; i < 3; i++ {
|
||||||
|
@ -425,13 +429,12 @@ func p224Contract(out, in *p224FieldElement) {
|
||||||
// There are two cases to consider for out[3]:
|
// There are two cases to consider for out[3]:
|
||||||
// 1) The first time that we eliminated top, we didn't push out[3] over
|
// 1) The first time that we eliminated top, we didn't push out[3] over
|
||||||
// 2**28. In this case, the partial carry chain didn't change any values
|
// 2**28. In this case, the partial carry chain didn't change any values
|
||||||
// and top is zero.
|
// and top is now zero.
|
||||||
// 2) We did push out[3] over 2**28 the first time that we eliminated top.
|
// 2) We did push out[3] over 2**28 the first time that we eliminated top.
|
||||||
// The first value of top was in [0..16), therefore, prior to eliminating
|
// The first value of top was in [0..2], therefore, after overflowing
|
||||||
// the first top, 0xfff1000 <= out[3] <= 0xfffffff. Therefore, after
|
// and being reduced by the second carry chain, out[3] <= 2<<12 - 1.
|
||||||
// overflowing and being reduced by the second carry chain, out[3] <=
|
// In both cases, out[3] cannot have overflowed when we eliminated top for
|
||||||
// 0xf000. Thus it cannot have overflowed when we eliminated top for the
|
// the second time.
|
||||||
// second time.
|
|
||||||
|
|
||||||
// Again, we may just have made out[0] negative, so do the same carry down.
|
// Again, we may just have made out[0] negative, so do the same carry down.
|
||||||
// As before, if we made out[0] negative then we know that out[3] is
|
// As before, if we made out[0] negative then we know that out[3] is
|
||||||
|
@ -470,12 +473,11 @@ func p224Contract(out, in *p224FieldElement) {
|
||||||
bottom3NonZero |= bottom3NonZero >> 1
|
bottom3NonZero |= bottom3NonZero >> 1
|
||||||
bottom3NonZero = uint32(int32(bottom3NonZero<<31) >> 31)
|
bottom3NonZero = uint32(int32(bottom3NonZero<<31) >> 31)
|
||||||
|
|
||||||
// Everything depends on the value of out[3].
|
// Assuming top4AllOnes != 0, everything depends on the value of out[3].
|
||||||
// If it's > 0xffff000 and top4AllOnes != 0 then the whole value is >= p
|
// If it's > 0xffff000 then the whole value is > p
|
||||||
// If it's = 0xffff000 and top4AllOnes != 0 and bottom3NonZero != 0,
|
// If it's = 0xffff000 and bottom3NonZero != 0, then the whole value is >= p
|
||||||
// then the whole value is >= p
|
|
||||||
// If it's < 0xffff000, then the whole value is < p
|
// If it's < 0xffff000, then the whole value is < p
|
||||||
n := out[3] - 0xffff000
|
n := 0xffff000 - out[3]
|
||||||
out3Equal := n
|
out3Equal := n
|
||||||
out3Equal |= out3Equal >> 16
|
out3Equal |= out3Equal >> 16
|
||||||
out3Equal |= out3Equal >> 8
|
out3Equal |= out3Equal >> 8
|
||||||
|
@ -484,8 +486,8 @@ func p224Contract(out, in *p224FieldElement) {
|
||||||
out3Equal |= out3Equal >> 1
|
out3Equal |= out3Equal >> 1
|
||||||
out3Equal = ^uint32(int32(out3Equal<<31) >> 31)
|
out3Equal = ^uint32(int32(out3Equal<<31) >> 31)
|
||||||
|
|
||||||
// If out[3] > 0xffff000 then n's MSB will be zero.
|
// If out[3] > 0xffff000 then n's MSB will be one.
|
||||||
out3GT := ^uint32(int32(n) >> 31)
|
out3GT := uint32(int32(n) >> 31)
|
||||||
|
|
||||||
mask := top4AllOnes & ((out3Equal & bottom3NonZero) | out3GT)
|
mask := top4AllOnes & ((out3Equal & bottom3NonZero) | out3GT)
|
||||||
out[0] -= 1 & mask
|
out[0] -= 1 & mask
|
||||||
|
@ -494,6 +496,15 @@ func p224Contract(out, in *p224FieldElement) {
|
||||||
out[5] -= 0xfffffff & mask
|
out[5] -= 0xfffffff & mask
|
||||||
out[6] -= 0xfffffff & mask
|
out[6] -= 0xfffffff & mask
|
||||||
out[7] -= 0xfffffff & mask
|
out[7] -= 0xfffffff & mask
|
||||||
|
|
||||||
|
// Do one final carry down, in case we made out[0] negative. One of
|
||||||
|
// out[0..3] needs to be positive and able to absorb the -1 or the value
|
||||||
|
// would have been < p, and the subtraction wouldn't have happened.
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
mask := uint32(int32(out[i]) >> 31)
|
||||||
|
out[i] += (1 << 28) & mask
|
||||||
|
out[i+1] -= 1 & mask
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Group element functions.
|
// Group element functions.
|
||||||
|
|
|
@ -6,7 +6,11 @@ package elliptic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"math/bits"
|
||||||
|
"math/rand"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
"testing/quick"
|
||||||
)
|
)
|
||||||
|
|
||||||
var toFromBigTests = []string{
|
var toFromBigTests = []string{
|
||||||
|
@ -21,16 +25,16 @@ func p224AlternativeToBig(in *p224FieldElement) *big.Int {
|
||||||
ret := new(big.Int)
|
ret := new(big.Int)
|
||||||
tmp := new(big.Int)
|
tmp := new(big.Int)
|
||||||
|
|
||||||
for i := uint(0); i < 8; i++ {
|
for i := len(in) - 1; i >= 0; i-- {
|
||||||
|
ret.Lsh(ret, 28)
|
||||||
tmp.SetInt64(int64(in[i]))
|
tmp.SetInt64(int64(in[i]))
|
||||||
tmp.Lsh(tmp, 28*i)
|
|
||||||
ret.Add(ret, tmp)
|
ret.Add(ret, tmp)
|
||||||
}
|
}
|
||||||
ret.Mod(ret, p224.P)
|
ret.Mod(ret, P224().Params().P)
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestToFromBig(t *testing.T) {
|
func TestP224ToFromBig(t *testing.T) {
|
||||||
for i, test := range toFromBigTests {
|
for i, test := range toFromBigTests {
|
||||||
n, _ := new(big.Int).SetString(test, 16)
|
n, _ := new(big.Int).SetString(test, 16)
|
||||||
var x p224FieldElement
|
var x p224FieldElement
|
||||||
|
@ -41,7 +45,270 @@ func TestToFromBig(t *testing.T) {
|
||||||
}
|
}
|
||||||
q := p224AlternativeToBig(&x)
|
q := p224AlternativeToBig(&x)
|
||||||
if n.Cmp(q) != 0 {
|
if n.Cmp(q) != 0 {
|
||||||
t.Errorf("#%d: %x != %x (alternative)", i, n, m)
|
t.Errorf("#%d: %x != %x (alternative)", i, n, q)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// quickCheckConfig32 will make each quickcheck test run (32 * -quickchecks)
|
||||||
|
// times. The default value of -quickchecks is 100.
|
||||||
|
var quickCheckConfig32 = &quick.Config{MaxCountScale: 32}
|
||||||
|
|
||||||
|
// weirdLimbs can be combined to generate a range of edge-case field elements.
|
||||||
|
var weirdLimbs = [...]uint32{
|
||||||
|
0, 1, (1 << 29) - 1,
|
||||||
|
(1 << 12), (1 << 12) - 1,
|
||||||
|
(1 << 28), (1 << 28) - 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateLimb(rand *rand.Rand) uint32 {
|
||||||
|
const bottom29Bits = 0x1fffffff
|
||||||
|
n := rand.Intn(len(weirdLimbs) + 3)
|
||||||
|
switch n {
|
||||||
|
case len(weirdLimbs):
|
||||||
|
// Random value.
|
||||||
|
return uint32(rand.Int31n(1 << 29))
|
||||||
|
case len(weirdLimbs) + 1:
|
||||||
|
// Sum of two values.
|
||||||
|
k := generateLimb(rand) + generateLimb(rand)
|
||||||
|
return k & bottom29Bits
|
||||||
|
case len(weirdLimbs) + 2:
|
||||||
|
// Difference of two values.
|
||||||
|
k := generateLimb(rand) - generateLimb(rand)
|
||||||
|
return k & bottom29Bits
|
||||||
|
default:
|
||||||
|
return weirdLimbs[n]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p224FieldElement) Generate(rand *rand.Rand, size int) reflect.Value {
|
||||||
|
return reflect.ValueOf(p224FieldElement{
|
||||||
|
generateLimb(rand),
|
||||||
|
generateLimb(rand),
|
||||||
|
generateLimb(rand),
|
||||||
|
generateLimb(rand),
|
||||||
|
generateLimb(rand),
|
||||||
|
generateLimb(rand),
|
||||||
|
generateLimb(rand),
|
||||||
|
generateLimb(rand),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func isInBounds(x *p224FieldElement) bool {
|
||||||
|
return bits.Len32(x[0]) <= 29 &&
|
||||||
|
bits.Len32(x[1]) <= 29 &&
|
||||||
|
bits.Len32(x[2]) <= 29 &&
|
||||||
|
bits.Len32(x[3]) <= 29 &&
|
||||||
|
bits.Len32(x[4]) <= 29 &&
|
||||||
|
bits.Len32(x[5]) <= 29 &&
|
||||||
|
bits.Len32(x[6]) <= 29 &&
|
||||||
|
bits.Len32(x[7]) <= 29
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestP224Mul(t *testing.T) {
|
||||||
|
mulMatchesBigInt := func(a, b, out p224FieldElement) bool {
|
||||||
|
var tmp p224LargeFieldElement
|
||||||
|
p224Mul(&out, &a, &b, &tmp)
|
||||||
|
|
||||||
|
exp := new(big.Int).Mul(p224AlternativeToBig(&a), p224AlternativeToBig(&b))
|
||||||
|
exp.Mod(exp, P224().Params().P)
|
||||||
|
got := p224AlternativeToBig(&out)
|
||||||
|
if exp.Cmp(got) != 0 || !isInBounds(&out) {
|
||||||
|
t.Logf("a = %x", a)
|
||||||
|
t.Logf("b = %x", b)
|
||||||
|
t.Logf("p224Mul(a, b) = %x = %v", out, got)
|
||||||
|
t.Logf("a * b = %v", exp)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
a := p224FieldElement{0xfffffff, 0xfffffff, 0xf00ffff, 0x20f, 0x0, 0x0, 0x0, 0x0}
|
||||||
|
b := p224FieldElement{1, 0, 0, 0, 0, 0, 0, 0}
|
||||||
|
if !mulMatchesBigInt(a, b, p224FieldElement{}) {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := quick.Check(mulMatchesBigInt, quickCheckConfig32); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestP224Square(t *testing.T) {
|
||||||
|
squareMatchesBigInt := func(a, out p224FieldElement) bool {
|
||||||
|
var tmp p224LargeFieldElement
|
||||||
|
p224Square(&out, &a, &tmp)
|
||||||
|
|
||||||
|
exp := p224AlternativeToBig(&a)
|
||||||
|
exp.Mul(exp, exp)
|
||||||
|
exp.Mod(exp, P224().Params().P)
|
||||||
|
got := p224AlternativeToBig(&out)
|
||||||
|
if exp.Cmp(got) != 0 || !isInBounds(&out) {
|
||||||
|
t.Logf("a = %x", a)
|
||||||
|
t.Logf("p224Square(a, b) = %x = %v", out, got)
|
||||||
|
t.Logf("a * a = %v", exp)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := quick.Check(squareMatchesBigInt, quickCheckConfig32); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestP224Add(t *testing.T) {
|
||||||
|
addMatchesBigInt := func(a, b, out p224FieldElement) bool {
|
||||||
|
p224Add(&out, &a, &b)
|
||||||
|
|
||||||
|
exp := new(big.Int).Add(p224AlternativeToBig(&a), p224AlternativeToBig(&b))
|
||||||
|
exp.Mod(exp, P224().Params().P)
|
||||||
|
got := p224AlternativeToBig(&out)
|
||||||
|
if exp.Cmp(got) != 0 {
|
||||||
|
t.Logf("a = %x", a)
|
||||||
|
t.Logf("b = %x", b)
|
||||||
|
t.Logf("p224Add(a, b) = %x = %v", out, got)
|
||||||
|
t.Logf("a + b = %v", exp)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := quick.Check(addMatchesBigInt, quickCheckConfig32); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestP224Reduce(t *testing.T) {
|
||||||
|
reduceMatchesBigInt := func(a p224FieldElement) bool {
|
||||||
|
out := a
|
||||||
|
// TODO: generate higher values for functions like p224Reduce that are
|
||||||
|
// expected to work with higher input bounds.
|
||||||
|
p224Reduce(&out)
|
||||||
|
|
||||||
|
exp := p224AlternativeToBig(&a)
|
||||||
|
got := p224AlternativeToBig(&out)
|
||||||
|
if exp.Cmp(got) != 0 || !isInBounds(&out) {
|
||||||
|
t.Logf("a = %x = %v", a, exp)
|
||||||
|
t.Logf("p224Reduce(a) = %x = %v", out, got)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := quick.Check(reduceMatchesBigInt, quickCheckConfig32); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestP224Contract(t *testing.T) {
|
||||||
|
contractMatchesBigInt := func(a, out p224FieldElement) bool {
|
||||||
|
p224Contract(&out, &a)
|
||||||
|
|
||||||
|
exp := p224AlternativeToBig(&a)
|
||||||
|
got := p224AlternativeToBig(&out)
|
||||||
|
if exp.Cmp(got) != 0 {
|
||||||
|
t.Logf("a = %x = %v", a, exp)
|
||||||
|
t.Logf("p224Contract(a) = %x = %v", out, got)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that out < P.
|
||||||
|
for i := range p224P {
|
||||||
|
k := 8 - i - 1
|
||||||
|
if out[k] > p224P[k] {
|
||||||
|
t.Logf("p224Contract(a) = %x", out)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if out[k] < p224P[k] {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.Logf("p224Contract(a) = %x", out)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !contractMatchesBigInt(p224P, p224FieldElement{}) {
|
||||||
|
t.Error("p224Contract(p) is broken")
|
||||||
|
}
|
||||||
|
pMinus1 := p224FieldElement{0, 0, 0, 0xffff000, 0xfffffff, 0xfffffff, 0xfffffff, 0xfffffff}
|
||||||
|
if !contractMatchesBigInt(pMinus1, p224FieldElement{}) {
|
||||||
|
t.Error("p224Contract(p - 1) is broken")
|
||||||
|
}
|
||||||
|
// Check that we can handle input above p, but lowest limb zero.
|
||||||
|
a := p224FieldElement{0, 1, 0, 0xffff000, 0xfffffff, 0xfffffff, 0xfffffff, 0xfffffff}
|
||||||
|
if !contractMatchesBigInt(a, p224FieldElement{}) {
|
||||||
|
t.Error("p224Contract(p + 2²⁸) is broken")
|
||||||
|
}
|
||||||
|
// Check that we can handle input above p, but lowest three limbs zero.
|
||||||
|
b := p224FieldElement{0, 0, 0, 0xffff001, 0xfffffff, 0xfffffff, 0xfffffff, 0xfffffff}
|
||||||
|
if !contractMatchesBigInt(b, p224FieldElement{}) {
|
||||||
|
t.Error("p224Contract(p + 2⁸⁴) is broken")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := quick.Check(contractMatchesBigInt, quickCheckConfig32); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestP224IsZero(t *testing.T) {
|
||||||
|
if got := p224IsZero(&p224FieldElement{}); got != 1 {
|
||||||
|
t.Errorf("p224IsZero(0) = %d, expected 1", got)
|
||||||
|
}
|
||||||
|
if got := p224IsZero((*p224FieldElement)(&p224P)); got != 1 {
|
||||||
|
t.Errorf("p224IsZero(p) = %d, expected 1", got)
|
||||||
|
}
|
||||||
|
if got := p224IsZero(&p224FieldElement{1}); got != 0 {
|
||||||
|
t.Errorf("p224IsZero(1) = %d, expected 0", got)
|
||||||
|
}
|
||||||
|
|
||||||
|
isZeroMatchesBigInt := func(a p224FieldElement) bool {
|
||||||
|
isZero := p224IsZero(&a)
|
||||||
|
|
||||||
|
big := p224AlternativeToBig(&a)
|
||||||
|
if big.Sign() == 0 && isZero != 1 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if big.Sign() != 0 && isZero != 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := quick.Check(isZeroMatchesBigInt, quickCheckConfig32); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestP224Invert(t *testing.T) {
|
||||||
|
var out p224FieldElement
|
||||||
|
|
||||||
|
p224Invert(&out, &p224FieldElement{})
|
||||||
|
if got := p224IsZero(&out); got != 1 {
|
||||||
|
t.Errorf("p224Invert(0) = %x, expected 0", out)
|
||||||
|
}
|
||||||
|
|
||||||
|
p224Invert(&out, (*p224FieldElement)(&p224P))
|
||||||
|
if got := p224IsZero(&out); got != 1 {
|
||||||
|
t.Errorf("p224Invert(p) = %x, expected 0", out)
|
||||||
|
}
|
||||||
|
|
||||||
|
p224Invert(&out, &p224FieldElement{1})
|
||||||
|
p224Contract(&out, &out)
|
||||||
|
if out != (p224FieldElement{1}) {
|
||||||
|
t.Errorf("p224Invert(1) = %x, expected 1", out)
|
||||||
|
}
|
||||||
|
|
||||||
|
var tmp p224LargeFieldElement
|
||||||
|
a := p224FieldElement{1, 2, 3, 4, 5, 6, 7, 8}
|
||||||
|
p224Invert(&out, &a)
|
||||||
|
p224Mul(&out, &out, &a, &tmp)
|
||||||
|
p224Contract(&out, &out)
|
||||||
|
if out != (p224FieldElement{1}) {
|
||||||
|
t.Errorf("p224Invert(a) * a = %x, expected 1", out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
package rand
|
package rand
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"internal/syscall/windows"
|
||||||
"os"
|
"os"
|
||||||
"syscall"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() { Reader = &rngReader{} }
|
func init() { Reader = &rngReader{} }
|
||||||
|
@ -24,7 +24,7 @@ func (r *rngReader) Read(b []byte) (n int, err error) {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err = syscall.RtlGenRandom(&b[0], inputLen)
|
err = windows.RtlGenRandom(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, os.NewSyscallError("RtlGenRandom", err)
|
return 0, os.NewSyscallError("RtlGenRandom", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ package tls
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"container/list"
|
"container/list"
|
||||||
"context"
|
|
||||||
"crypto"
|
"crypto"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/ed25519"
|
"crypto/ed25519"
|
||||||
|
@ -444,16 +443,6 @@ type ClientHelloInfo struct {
|
||||||
// config is embedded by the GetCertificate or GetConfigForClient caller,
|
// config is embedded by the GetCertificate or GetConfigForClient caller,
|
||||||
// for use with SupportsCertificate.
|
// for use with SupportsCertificate.
|
||||||
config *Config
|
config *Config
|
||||||
|
|
||||||
// ctx is the context of the handshake that is in progress.
|
|
||||||
ctx context.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
// Context returns the context of the handshake that is in progress.
|
|
||||||
// This context is a child of the context passed to HandshakeContext,
|
|
||||||
// if any, and is canceled when the handshake concludes.
|
|
||||||
func (c *ClientHelloInfo) Context() context.Context {
|
|
||||||
return c.ctx
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CertificateRequestInfo contains information from a server's
|
// CertificateRequestInfo contains information from a server's
|
||||||
|
@ -472,16 +461,6 @@ type CertificateRequestInfo struct {
|
||||||
|
|
||||||
// Version is the TLS version that was negotiated for this connection.
|
// Version is the TLS version that was negotiated for this connection.
|
||||||
Version uint16
|
Version uint16
|
||||||
|
|
||||||
// ctx is the context of the handshake that is in progress.
|
|
||||||
ctx context.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
// Context returns the context of the handshake that is in progress.
|
|
||||||
// This context is a child of the context passed to HandshakeContext,
|
|
||||||
// if any, and is canceled when the handshake concludes.
|
|
||||||
func (c *CertificateRequestInfo) Context() context.Context {
|
|
||||||
return c.ctx
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RenegotiationSupport enumerates the different levels of support for TLS
|
// RenegotiationSupport enumerates the different levels of support for TLS
|
||||||
|
|
|
@ -8,7 +8,6 @@ package tls
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
|
||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
"crypto/subtle"
|
"crypto/subtle"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
@ -28,7 +27,7 @@ type Conn struct {
|
||||||
// constant
|
// constant
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
isClient bool
|
isClient bool
|
||||||
handshakeFn func(context.Context) error // (*Conn).clientHandshake or serverHandshake
|
handshakeFn func() error // (*Conn).clientHandshake or serverHandshake
|
||||||
|
|
||||||
// handshakeStatus is 1 if the connection is currently transferring
|
// handshakeStatus is 1 if the connection is currently transferring
|
||||||
// application data (i.e. is not currently processing a handshake).
|
// application data (i.e. is not currently processing a handshake).
|
||||||
|
@ -1191,7 +1190,7 @@ func (c *Conn) handleRenegotiation() error {
|
||||||
defer c.handshakeMutex.Unlock()
|
defer c.handshakeMutex.Unlock()
|
||||||
|
|
||||||
atomic.StoreUint32(&c.handshakeStatus, 0)
|
atomic.StoreUint32(&c.handshakeStatus, 0)
|
||||||
if c.handshakeErr = c.clientHandshake(context.Background()); c.handshakeErr == nil {
|
if c.handshakeErr = c.clientHandshake(); c.handshakeErr == nil {
|
||||||
c.handshakes++
|
c.handshakes++
|
||||||
}
|
}
|
||||||
return c.handshakeErr
|
return c.handshakeErr
|
||||||
|
@ -1374,61 +1373,8 @@ func (c *Conn) closeNotify() error {
|
||||||
// first Read or Write will call it automatically.
|
// first Read or Write will call it automatically.
|
||||||
//
|
//
|
||||||
// For control over canceling or setting a timeout on a handshake, use
|
// For control over canceling or setting a timeout on a handshake, use
|
||||||
// HandshakeContext or the Dialer's DialContext method instead.
|
// the Dialer's DialContext method.
|
||||||
func (c *Conn) Handshake() error {
|
func (c *Conn) Handshake() error {
|
||||||
return c.HandshakeContext(context.Background())
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandshakeContext runs the client or server handshake
|
|
||||||
// protocol if it has not yet been run.
|
|
||||||
//
|
|
||||||
// The provided Context must be non-nil. If the context is canceled before
|
|
||||||
// the handshake is complete, the handshake is interrupted and an error is returned.
|
|
||||||
// Once the handshake has completed, cancellation of the context will not affect the
|
|
||||||
// connection.
|
|
||||||
//
|
|
||||||
// Most uses of this package need not call HandshakeContext explicitly: the
|
|
||||||
// first Read or Write will call it automatically.
|
|
||||||
func (c *Conn) HandshakeContext(ctx context.Context) error {
|
|
||||||
// Delegate to unexported method for named return
|
|
||||||
// without confusing documented signature.
|
|
||||||
return c.handshakeContext(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conn) handshakeContext(ctx context.Context) (ret error) {
|
|
||||||
handshakeCtx, cancel := context.WithCancel(ctx)
|
|
||||||
// Note: defer this before starting the "interrupter" goroutine
|
|
||||||
// so that we can tell the difference between the input being canceled and
|
|
||||||
// this cancellation. In the former case, we need to close the connection.
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
// Start the "interrupter" goroutine, if this context might be canceled.
|
|
||||||
// (The background context cannot).
|
|
||||||
//
|
|
||||||
// The interrupter goroutine waits for the input context to be done and
|
|
||||||
// closes the connection if this happens before the function returns.
|
|
||||||
if ctx.Done() != nil {
|
|
||||||
done := make(chan struct{})
|
|
||||||
interruptRes := make(chan error, 1)
|
|
||||||
defer func() {
|
|
||||||
close(done)
|
|
||||||
if ctxErr := <-interruptRes; ctxErr != nil {
|
|
||||||
// Return context error to user.
|
|
||||||
ret = ctxErr
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
go func() {
|
|
||||||
select {
|
|
||||||
case <-handshakeCtx.Done():
|
|
||||||
// Close the connection, discarding the error
|
|
||||||
_ = c.conn.Close()
|
|
||||||
interruptRes <- handshakeCtx.Err()
|
|
||||||
case <-done:
|
|
||||||
interruptRes <- nil
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
c.handshakeMutex.Lock()
|
c.handshakeMutex.Lock()
|
||||||
defer c.handshakeMutex.Unlock()
|
defer c.handshakeMutex.Unlock()
|
||||||
|
|
||||||
|
@ -1442,7 +1388,7 @@ func (c *Conn) handshakeContext(ctx context.Context) (ret error) {
|
||||||
c.in.Lock()
|
c.in.Lock()
|
||||||
defer c.in.Unlock()
|
defer c.in.Unlock()
|
||||||
|
|
||||||
c.handshakeErr = c.handshakeFn(handshakeCtx)
|
c.handshakeErr = c.handshakeFn()
|
||||||
if c.handshakeErr == nil {
|
if c.handshakeErr == nil {
|
||||||
c.handshakes++
|
c.handshakes++
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -6,7 +6,6 @@ package tls
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
|
||||||
"crypto"
|
"crypto"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/ed25519"
|
"crypto/ed25519"
|
||||||
|
@ -25,7 +24,6 @@ import (
|
||||||
|
|
||||||
type clientHandshakeState struct {
|
type clientHandshakeState struct {
|
||||||
c *Conn
|
c *Conn
|
||||||
ctx context.Context
|
|
||||||
serverHello *serverHelloMsg
|
serverHello *serverHelloMsg
|
||||||
hello *clientHelloMsg
|
hello *clientHelloMsg
|
||||||
suite *cipherSuite
|
suite *cipherSuite
|
||||||
|
@ -136,7 +134,7 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, ecdheParameters, error) {
|
||||||
return hello, params, nil
|
return hello, params, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) clientHandshake(ctx context.Context) (err error) {
|
func (c *Conn) clientHandshake() (err error) {
|
||||||
if c.config == nil {
|
if c.config == nil {
|
||||||
c.config = defaultConfig()
|
c.config = defaultConfig()
|
||||||
}
|
}
|
||||||
|
@ -200,7 +198,6 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) {
|
||||||
if c.vers == VersionTLS13 {
|
if c.vers == VersionTLS13 {
|
||||||
hs := &clientHandshakeStateTLS13{
|
hs := &clientHandshakeStateTLS13{
|
||||||
c: c,
|
c: c,
|
||||||
ctx: ctx,
|
|
||||||
serverHello: serverHello,
|
serverHello: serverHello,
|
||||||
hello: hello,
|
hello: hello,
|
||||||
ecdheParams: ecdheParams,
|
ecdheParams: ecdheParams,
|
||||||
|
@ -215,7 +212,6 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) {
|
||||||
|
|
||||||
hs := &clientHandshakeState{
|
hs := &clientHandshakeState{
|
||||||
c: c,
|
c: c,
|
||||||
ctx: ctx,
|
|
||||||
serverHello: serverHello,
|
serverHello: serverHello,
|
||||||
hello: hello,
|
hello: hello,
|
||||||
session: session,
|
session: session,
|
||||||
|
@ -544,7 +540,7 @@ func (hs *clientHandshakeState) doFullHandshake() error {
|
||||||
certRequested = true
|
certRequested = true
|
||||||
hs.finishedHash.Write(certReq.marshal())
|
hs.finishedHash.Write(certReq.marshal())
|
||||||
|
|
||||||
cri := certificateRequestInfoFromMsg(hs.ctx, c.vers, certReq)
|
cri := certificateRequestInfoFromMsg(c.vers, certReq)
|
||||||
if chainToSend, err = c.getClientCertificate(cri); err != nil {
|
if chainToSend, err = c.getClientCertificate(cri); err != nil {
|
||||||
c.sendAlert(alertInternalError)
|
c.sendAlert(alertInternalError)
|
||||||
return err
|
return err
|
||||||
|
@ -884,11 +880,10 @@ func (c *Conn) verifyServerCertificate(certificates [][]byte) error {
|
||||||
|
|
||||||
// certificateRequestInfoFromMsg generates a CertificateRequestInfo from a TLS
|
// certificateRequestInfoFromMsg generates a CertificateRequestInfo from a TLS
|
||||||
// <= 1.2 CertificateRequest, making an effort to fill in missing information.
|
// <= 1.2 CertificateRequest, making an effort to fill in missing information.
|
||||||
func certificateRequestInfoFromMsg(ctx context.Context, vers uint16, certReq *certificateRequestMsg) *CertificateRequestInfo {
|
func certificateRequestInfoFromMsg(vers uint16, certReq *certificateRequestMsg) *CertificateRequestInfo {
|
||||||
cri := &CertificateRequestInfo{
|
cri := &CertificateRequestInfo{
|
||||||
AcceptableCAs: certReq.certificateAuthorities,
|
AcceptableCAs: certReq.certificateAuthorities,
|
||||||
Version: vers,
|
Version: vers,
|
||||||
ctx: ctx,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var rsaAvail, ecAvail bool
|
var rsaAvail, ecAvail bool
|
||||||
|
|
|
@ -6,7 +6,6 @@ package tls
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
@ -21,7 +20,6 @@ import (
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -2513,37 +2511,3 @@ func testResumptionKeepsOCSPAndSCT(t *testing.T, ver uint16) {
|
||||||
serverConfig.Certificates[0].SignedCertificateTimestamps, ccs.SignedCertificateTimestamps)
|
serverConfig.Certificates[0].SignedCertificateTimestamps, ccs.SignedCertificateTimestamps)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestClientHandshakeContextCancellation(t *testing.T) {
|
|
||||||
c, s := localPipe(t)
|
|
||||||
serverConfig := testConfig.Clone()
|
|
||||||
serverErr := make(chan error, 1)
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
|
||||||
defer cancel()
|
|
||||||
go func() {
|
|
||||||
defer close(serverErr)
|
|
||||||
defer s.Close()
|
|
||||||
conn := Server(s, serverConfig)
|
|
||||||
_, err := conn.readClientHello(ctx)
|
|
||||||
cancel()
|
|
||||||
serverErr <- err
|
|
||||||
}()
|
|
||||||
cli := Client(c, testConfig)
|
|
||||||
err := cli.HandshakeContext(ctx)
|
|
||||||
if err == nil {
|
|
||||||
t.Fatal("Client handshake did not error when the context was canceled")
|
|
||||||
}
|
|
||||||
if err != context.Canceled {
|
|
||||||
t.Errorf("Unexpected client handshake error: %v", err)
|
|
||||||
}
|
|
||||||
if err := <-serverErr; err != nil {
|
|
||||||
t.Errorf("Unexpected server error: %v", err)
|
|
||||||
}
|
|
||||||
if runtime.GOARCH == "wasm" {
|
|
||||||
t.Skip("conn.Close does not error as expected when called multiple times on WASM")
|
|
||||||
}
|
|
||||||
err = cli.Close()
|
|
||||||
if err == nil {
|
|
||||||
t.Error("Client connection was not closed when the context was canceled")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ package tls
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
|
||||||
"crypto"
|
"crypto"
|
||||||
"crypto/hmac"
|
"crypto/hmac"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
|
@ -18,7 +17,6 @@ import (
|
||||||
|
|
||||||
type clientHandshakeStateTLS13 struct {
|
type clientHandshakeStateTLS13 struct {
|
||||||
c *Conn
|
c *Conn
|
||||||
ctx context.Context
|
|
||||||
serverHello *serverHelloMsg
|
serverHello *serverHelloMsg
|
||||||
hello *clientHelloMsg
|
hello *clientHelloMsg
|
||||||
ecdheParams ecdheParameters
|
ecdheParams ecdheParameters
|
||||||
|
@ -557,7 +555,6 @@ func (hs *clientHandshakeStateTLS13) sendClientCertificate() error {
|
||||||
AcceptableCAs: hs.certReq.certificateAuthorities,
|
AcceptableCAs: hs.certReq.certificateAuthorities,
|
||||||
SignatureSchemes: hs.certReq.supportedSignatureAlgorithms,
|
SignatureSchemes: hs.certReq.supportedSignatureAlgorithms,
|
||||||
Version: c.vers,
|
Version: c.vers,
|
||||||
ctx: hs.ctx,
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
package tls
|
package tls
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"crypto"
|
"crypto"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/ed25519"
|
"crypto/ed25519"
|
||||||
|
@ -24,7 +23,6 @@ import (
|
||||||
// It's discarded once the handshake has completed.
|
// It's discarded once the handshake has completed.
|
||||||
type serverHandshakeState struct {
|
type serverHandshakeState struct {
|
||||||
c *Conn
|
c *Conn
|
||||||
ctx context.Context
|
|
||||||
clientHello *clientHelloMsg
|
clientHello *clientHelloMsg
|
||||||
hello *serverHelloMsg
|
hello *serverHelloMsg
|
||||||
suite *cipherSuite
|
suite *cipherSuite
|
||||||
|
@ -39,8 +37,8 @@ type serverHandshakeState struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// serverHandshake performs a TLS handshake as a server.
|
// serverHandshake performs a TLS handshake as a server.
|
||||||
func (c *Conn) serverHandshake(ctx context.Context) error {
|
func (c *Conn) serverHandshake() error {
|
||||||
clientHello, err := c.readClientHello(ctx)
|
clientHello, err := c.readClientHello()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -48,7 +46,6 @@ func (c *Conn) serverHandshake(ctx context.Context) error {
|
||||||
if c.vers == VersionTLS13 {
|
if c.vers == VersionTLS13 {
|
||||||
hs := serverHandshakeStateTLS13{
|
hs := serverHandshakeStateTLS13{
|
||||||
c: c,
|
c: c,
|
||||||
ctx: ctx,
|
|
||||||
clientHello: clientHello,
|
clientHello: clientHello,
|
||||||
}
|
}
|
||||||
return hs.handshake()
|
return hs.handshake()
|
||||||
|
@ -56,7 +53,6 @@ func (c *Conn) serverHandshake(ctx context.Context) error {
|
||||||
|
|
||||||
hs := serverHandshakeState{
|
hs := serverHandshakeState{
|
||||||
c: c,
|
c: c,
|
||||||
ctx: ctx,
|
|
||||||
clientHello: clientHello,
|
clientHello: clientHello,
|
||||||
}
|
}
|
||||||
return hs.handshake()
|
return hs.handshake()
|
||||||
|
@ -128,7 +124,7 @@ func (hs *serverHandshakeState) handshake() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// readClientHello reads a ClientHello message and selects the protocol version.
|
// readClientHello reads a ClientHello message and selects the protocol version.
|
||||||
func (c *Conn) readClientHello(ctx context.Context) (*clientHelloMsg, error) {
|
func (c *Conn) readClientHello() (*clientHelloMsg, error) {
|
||||||
msg, err := c.readHandshake()
|
msg, err := c.readHandshake()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -142,7 +138,7 @@ func (c *Conn) readClientHello(ctx context.Context) (*clientHelloMsg, error) {
|
||||||
var configForClient *Config
|
var configForClient *Config
|
||||||
originalConfig := c.config
|
originalConfig := c.config
|
||||||
if c.config.GetConfigForClient != nil {
|
if c.config.GetConfigForClient != nil {
|
||||||
chi := clientHelloInfo(ctx, c, clientHello)
|
chi := clientHelloInfo(c, clientHello)
|
||||||
if configForClient, err = c.config.GetConfigForClient(chi); err != nil {
|
if configForClient, err = c.config.GetConfigForClient(chi); err != nil {
|
||||||
c.sendAlert(alertInternalError)
|
c.sendAlert(alertInternalError)
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -224,7 +220,7 @@ func (hs *serverHandshakeState) processClientHello() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hs.cert, err = c.config.getCertificate(clientHelloInfo(hs.ctx, c, hs.clientHello))
|
hs.cert, err = c.config.getCertificate(clientHelloInfo(c, hs.clientHello))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == errNoCertificates {
|
if err == errNoCertificates {
|
||||||
c.sendAlert(alertUnrecognizedName)
|
c.sendAlert(alertUnrecognizedName)
|
||||||
|
@ -832,7 +828,7 @@ func (c *Conn) processCertsFromClient(certificate Certificate) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func clientHelloInfo(ctx context.Context, c *Conn, clientHello *clientHelloMsg) *ClientHelloInfo {
|
func clientHelloInfo(c *Conn, clientHello *clientHelloMsg) *ClientHelloInfo {
|
||||||
supportedVersions := clientHello.supportedVersions
|
supportedVersions := clientHello.supportedVersions
|
||||||
if len(clientHello.supportedVersions) == 0 {
|
if len(clientHello.supportedVersions) == 0 {
|
||||||
supportedVersions = supportedVersionsFromMax(clientHello.vers)
|
supportedVersions = supportedVersionsFromMax(clientHello.vers)
|
||||||
|
@ -848,6 +844,5 @@ func clientHelloInfo(ctx context.Context, c *Conn, clientHello *clientHelloMsg)
|
||||||
SupportedVersions: supportedVersions,
|
SupportedVersions: supportedVersions,
|
||||||
Conn: c.conn,
|
Conn: c.conn,
|
||||||
config: c.config,
|
config: c.config,
|
||||||
ctx: ctx,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ package tls
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
|
||||||
"crypto"
|
"crypto"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
@ -18,7 +17,6 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
@ -40,12 +38,10 @@ func testClientHelloFailure(t *testing.T, serverConfig *Config, m handshakeMessa
|
||||||
cli.writeRecord(recordTypeHandshake, m.marshal())
|
cli.writeRecord(recordTypeHandshake, m.marshal())
|
||||||
c.Close()
|
c.Close()
|
||||||
}()
|
}()
|
||||||
ctx := context.Background()
|
|
||||||
conn := Server(s, serverConfig)
|
conn := Server(s, serverConfig)
|
||||||
ch, err := conn.readClientHello(ctx)
|
ch, err := conn.readClientHello()
|
||||||
hs := serverHandshakeState{
|
hs := serverHandshakeState{
|
||||||
c: conn,
|
c: conn,
|
||||||
ctx: ctx,
|
|
||||||
clientHello: ch,
|
clientHello: ch,
|
||||||
}
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -1425,11 +1421,9 @@ func TestSNIGivenOnFailure(t *testing.T) {
|
||||||
c.Close()
|
c.Close()
|
||||||
}()
|
}()
|
||||||
conn := Server(s, serverConfig)
|
conn := Server(s, serverConfig)
|
||||||
ctx := context.Background()
|
ch, err := conn.readClientHello()
|
||||||
ch, err := conn.readClientHello(ctx)
|
|
||||||
hs := serverHandshakeState{
|
hs := serverHandshakeState{
|
||||||
c: conn,
|
c: conn,
|
||||||
ctx: ctx,
|
|
||||||
clientHello: ch,
|
clientHello: ch,
|
||||||
}
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -1683,46 +1677,6 @@ func TestMultipleCertificates(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServerHandshakeContextCancellation(t *testing.T) {
|
|
||||||
c, s := localPipe(t)
|
|
||||||
clientConfig := testConfig.Clone()
|
|
||||||
clientErr := make(chan error, 1)
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
|
||||||
defer cancel()
|
|
||||||
go func() {
|
|
||||||
defer close(clientErr)
|
|
||||||
defer c.Close()
|
|
||||||
clientHello := &clientHelloMsg{
|
|
||||||
vers: VersionTLS10,
|
|
||||||
random: make([]byte, 32),
|
|
||||||
cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
|
|
||||||
compressionMethods: []uint8{compressionNone},
|
|
||||||
}
|
|
||||||
cli := Client(c, clientConfig)
|
|
||||||
_, err := cli.writeRecord(recordTypeHandshake, clientHello.marshal())
|
|
||||||
cancel()
|
|
||||||
clientErr <- err
|
|
||||||
}()
|
|
||||||
conn := Server(s, testConfig)
|
|
||||||
err := conn.HandshakeContext(ctx)
|
|
||||||
if err == nil {
|
|
||||||
t.Fatal("Server handshake did not error when the context was canceled")
|
|
||||||
}
|
|
||||||
if err != context.Canceled {
|
|
||||||
t.Errorf("Unexpected server handshake error: %v", err)
|
|
||||||
}
|
|
||||||
if err := <-clientErr; err != nil {
|
|
||||||
t.Errorf("Unexpected client error: %v", err)
|
|
||||||
}
|
|
||||||
if runtime.GOARCH == "wasm" {
|
|
||||||
t.Skip("conn.Close does not error as expected when called multiple times on WASM")
|
|
||||||
}
|
|
||||||
err = conn.Close()
|
|
||||||
if err == nil {
|
|
||||||
t.Error("Server connection was not closed when the context was canceled")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAESCipherReordering(t *testing.T) {
|
func TestAESCipherReordering(t *testing.T) {
|
||||||
currentAESSupport := hasAESGCMHardwareSupport
|
currentAESSupport := hasAESGCMHardwareSupport
|
||||||
defer func() { hasAESGCMHardwareSupport = currentAESSupport; initDefaultCipherSuites() }()
|
defer func() { hasAESGCMHardwareSupport = currentAESSupport; initDefaultCipherSuites() }()
|
||||||
|
|
|
@ -6,7 +6,6 @@ package tls
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
|
||||||
"crypto"
|
"crypto"
|
||||||
"crypto/hmac"
|
"crypto/hmac"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
|
@ -24,7 +23,6 @@ const maxClientPSKIdentities = 5
|
||||||
|
|
||||||
type serverHandshakeStateTLS13 struct {
|
type serverHandshakeStateTLS13 struct {
|
||||||
c *Conn
|
c *Conn
|
||||||
ctx context.Context
|
|
||||||
clientHello *clientHelloMsg
|
clientHello *clientHelloMsg
|
||||||
hello *serverHelloMsg
|
hello *serverHelloMsg
|
||||||
sentDummyCCS bool
|
sentDummyCCS bool
|
||||||
|
@ -376,7 +374,7 @@ func (hs *serverHandshakeStateTLS13) pickCertificate() error {
|
||||||
return c.sendAlert(alertMissingExtension)
|
return c.sendAlert(alertMissingExtension)
|
||||||
}
|
}
|
||||||
|
|
||||||
certificate, err := c.config.getCertificate(clientHelloInfo(hs.ctx, c, hs.clientHello))
|
certificate, err := c.config.getCertificate(clientHelloInfo(c, hs.clientHello))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == errNoCertificates {
|
if err == errNoCertificates {
|
||||||
c.sendAlert(alertUnrecognizedName)
|
c.sendAlert(alertUnrecognizedName)
|
||||||
|
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Server returns a new TLS server side connection
|
// Server returns a new TLS server side connection
|
||||||
|
@ -115,16 +116,28 @@ func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*
|
||||||
}
|
}
|
||||||
|
|
||||||
func dial(ctx context.Context, netDialer *net.Dialer, network, addr string, config *Config) (*Conn, error) {
|
func dial(ctx context.Context, netDialer *net.Dialer, network, addr string, config *Config) (*Conn, error) {
|
||||||
if netDialer.Timeout != 0 {
|
// We want the Timeout and Deadline values from dialer to cover the
|
||||||
var cancel context.CancelFunc
|
// whole process: TCP connection and TLS handshake. This means that we
|
||||||
ctx, cancel = context.WithTimeout(ctx, netDialer.Timeout)
|
// also need to start our own timers now.
|
||||||
defer cancel()
|
timeout := netDialer.Timeout
|
||||||
}
|
|
||||||
|
|
||||||
if !netDialer.Deadline.IsZero() {
|
if !netDialer.Deadline.IsZero() {
|
||||||
var cancel context.CancelFunc
|
deadlineTimeout := time.Until(netDialer.Deadline)
|
||||||
ctx, cancel = context.WithDeadline(ctx, netDialer.Deadline)
|
if timeout == 0 || deadlineTimeout < timeout {
|
||||||
defer cancel()
|
timeout = deadlineTimeout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// hsErrCh is non-nil if we might not wait for Handshake to complete.
|
||||||
|
var hsErrCh chan error
|
||||||
|
if timeout != 0 || ctx.Done() != nil {
|
||||||
|
hsErrCh = make(chan error, 2)
|
||||||
|
}
|
||||||
|
if timeout != 0 {
|
||||||
|
timer := time.AfterFunc(timeout, func() {
|
||||||
|
hsErrCh <- timeoutError{}
|
||||||
|
})
|
||||||
|
defer timer.Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
rawConn, err := netDialer.DialContext(ctx, network, addr)
|
rawConn, err := netDialer.DialContext(ctx, network, addr)
|
||||||
|
@ -151,10 +164,34 @@ func dial(ctx context.Context, netDialer *net.Dialer, network, addr string, conf
|
||||||
}
|
}
|
||||||
|
|
||||||
conn := Client(rawConn, config)
|
conn := Client(rawConn, config)
|
||||||
if err := conn.HandshakeContext(ctx); err != nil {
|
|
||||||
|
if hsErrCh == nil {
|
||||||
|
err = conn.Handshake()
|
||||||
|
} else {
|
||||||
|
go func() {
|
||||||
|
hsErrCh <- conn.Handshake()
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
err = ctx.Err()
|
||||||
|
case err = <-hsErrCh:
|
||||||
|
if err != nil {
|
||||||
|
// If the error was due to the context
|
||||||
|
// closing, prefer the context's error, rather
|
||||||
|
// than some random network teardown error.
|
||||||
|
if e := ctx.Err(); e != nil {
|
||||||
|
err = e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
rawConn.Close()
|
rawConn.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return conn, nil
|
return conn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,11 @@
|
||||||
|
|
||||||
package x509
|
package x509
|
||||||
|
|
||||||
//go:generate go run root_ios_gen.go -version 55161.140.3
|
// To update the embedded iOS root store, update the -version
|
||||||
|
// argument to the latest security_certificates version from
|
||||||
|
// https://opensource.apple.com/source/security_certificates/
|
||||||
|
// and run "go generate". See https://golang.org/issue/38843.
|
||||||
|
//go:generate go run root_ios_gen.go -version 55188.40.9
|
||||||
|
|
||||||
import "sync"
|
import "sync"
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Code generated by root_ios_gen.go -version 55161.140.3; DO NOT EDIT.
|
// Code generated by root_ios_gen.go -version 55188.40.9; DO NOT EDIT.
|
||||||
// Update the version in root.go and regenerate with "go generate".
|
// Update the version in root.go and regenerate with "go generate".
|
||||||
|
|
||||||
// +build ios
|
// +build ios
|
||||||
|
@ -116,61 +116,6 @@ ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU
|
||||||
LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT
|
LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT
|
||||||
LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg==
|
LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg==
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
# "AddTrust Class 1 CA Root"
|
|
||||||
# 8C 72 09 27 9A C0 4E 27 5E 16 D0 7F D3 B7 75 E8
|
|
||||||
# 01 54 B5 96 80 46 E3 1F 52 DD 25 76 63 24 E9 A7
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEU
|
|
||||||
MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
|
|
||||||
b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMw
|
|
||||||
MTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
|
|
||||||
QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYD
|
|
||||||
VQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA
|
|
||||||
A4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ul
|
|
||||||
CDtbKRY654eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6n
|
|
||||||
tGO0/7Gcrjyvd7ZWxbWroulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyl
|
|
||||||
dI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJch
|
|
||||||
PXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC
|
|
||||||
+Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0O
|
|
||||||
BBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8E
|
|
||||||
BTADAQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBl
|
|
||||||
MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk
|
|
||||||
ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENB
|
|
||||||
IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0MkhHma6X
|
|
||||||
7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0PhiVYrqW9yTkkz
|
|
||||||
43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY
|
|
||||||
eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJl
|
|
||||||
pz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOA
|
|
||||||
WiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk=
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
# "AddTrust External CA Root"
|
|
||||||
# 68 7F A4 51 38 22 78 FF F0 C8 B1 1F 8D 43 D5 76
|
|
||||||
# 67 1C 6E B2 BC EA B4 13 FB 83 D9 65 D0 6D 2F F2
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
|
|
||||||
MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
|
|
||||||
IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290
|
|
||||||
MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux
|
|
||||||
FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h
|
|
||||||
bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v
|
|
||||||
dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt
|
|
||||||
H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9
|
|
||||||
uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX
|
|
||||||
mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX
|
|
||||||
a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN
|
|
||||||
E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0
|
|
||||||
WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD
|
|
||||||
VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0
|
|
||||||
Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU
|
|
||||||
cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx
|
|
||||||
IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN
|
|
||||||
AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH
|
|
||||||
YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
|
|
||||||
6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC
|
|
||||||
Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
|
|
||||||
c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
|
|
||||||
mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
# "Admin-Root-CA"
|
# "Admin-Root-CA"
|
||||||
# A3 1F 09 30 53 BD 12 C1 F5 C3 C6 EF D4 98 02 3F
|
# A3 1F 09 30 53 BD 12 C1 F5 C3 C6 EF D4 98 02 3F
|
||||||
# D2 91 4D 77 58 D0 5D 69 8C E0 84 B5 06 26 E0 E5
|
# D2 91 4D 77 58 D0 5D 69 8C E0 84 B5 06 26 E0 E5
|
||||||
|
@ -1249,31 +1194,6 @@ Bvt9YAretIpjsJyp8qS5UwGH0GikJ3+r/+n6yUA4iGe0OcaEb1fJU9u6ju7AQ7L4
|
||||||
CYNu/2bPPu8Xs1gYJQk0XuPL1hS27PKSb3TkL4Eq1ZKR4OCXPDJoBYVL0fdX4lId
|
CYNu/2bPPu8Xs1gYJQk0XuPL1hS27PKSb3TkL4Eq1ZKR4OCXPDJoBYVL0fdX4lId
|
||||||
kxpUnwVwwEpxYB5DC2Ae/qPOgRnhCzU=
|
kxpUnwVwwEpxYB5DC2Ae/qPOgRnhCzU=
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
# "Class 2 Primary CA"
|
|
||||||
# 0F 99 3C 8A EF 97 BA AF 56 87 14 0E D5 9A D1 82
|
|
||||||
# 1B B4 AF AC F0 AA 9A 58 B5 D5 7A 33 8A 3A FB CB
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAw
|
|
||||||
PTELMAkGA1UEBhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFz
|
|
||||||
cyAyIFByaW1hcnkgQ0EwHhcNOTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9
|
|
||||||
MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2VydHBsdXMxGzAZBgNVBAMTEkNsYXNz
|
|
||||||
IDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANxQ
|
|
||||||
ltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR5aiR
|
|
||||||
VhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyL
|
|
||||||
kcAbmXuZVg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCd
|
|
||||||
EgETjdyAYveVqUSISnFOYFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yas
|
|
||||||
H7WLO7dDWWuwJKZtkIvEcupdM5i3y95ee++U8Rs+yskhwcWYAqqi9lt3m/V+llU0
|
|
||||||
HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRMECDAGAQH/AgEKMAsGA1Ud
|
|
||||||
DwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJYIZIAYb4
|
|
||||||
QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMu
|
|
||||||
Y29tL0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/
|
|
||||||
AN9WM2K191EBkOvDP9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8
|
|
||||||
yfFC82x/xXp8HVGIutIKPidd3i1RTtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMR
|
|
||||||
FcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+7UCmnYR0ObncHoUW2ikbhiMA
|
|
||||||
ybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW//1IMwrh3KWB
|
|
||||||
kJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7
|
|
||||||
l7+ijrRU
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
# "COMODO Certification Authority"
|
# "COMODO Certification Authority"
|
||||||
# 0C 2C D6 3D F7 80 6F A3 99 ED E8 09 11 6B 57 5B
|
# 0C 2C D6 3D F7 80 6F A3 99 ED E8 09 11 6B 57 5B
|
||||||
# F8 79 89 F0 65 18 F9 80 8C 86 05 03 17 8B AF 66
|
# F8 79 89 F0 65 18 F9 80 8C 86 05 03 17 8B AF 66
|
||||||
|
@ -1529,31 +1449,6 @@ CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na
|
||||||
xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX
|
xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX
|
||||||
KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1
|
KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
# "Deutsche Telekom Root CA 2"
|
|
||||||
# B6 19 1A 50 D0 C3 97 7F 7D A9 9B CD AA C8 6A 22
|
|
||||||
# 7D AE B9 67 9E C7 0B A3 B0 C9 D9 22 71 C1 70 D3
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEc
|
|
||||||
MBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2Vj
|
|
||||||
IFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENB
|
|
||||||
IDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5MjM1OTAwWjBxMQswCQYDVQQGEwJE
|
|
||||||
RTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxl
|
|
||||||
U2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290
|
|
||||||
IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEU
|
|
||||||
ha88EOQ5bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhC
|
|
||||||
QN/Po7qCWWqSG6wcmtoIKyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1Mjwr
|
|
||||||
rFDa1sPeg5TKqAyZMg4ISFZbavva4VhYAUlfckE8FQYBjl2tqriTtM2e66foai1S
|
|
||||||
NNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aKSe5TBY8ZTNXeWHmb0moc
|
|
||||||
QqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTVjlsB9WoH
|
|
||||||
txa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAP
|
|
||||||
BgNVHRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOC
|
|
||||||
AQEAlGRZrTlk5ynrE/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756Abrsp
|
|
||||||
tJh6sTtU6zkXR34ajgv8HzFZMQSyzhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpa
|
|
||||||
IzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8rZ7/gFnkm0W09juwzTkZmDLl
|
|
||||||
6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4Gdyd1Lx+4ivn+
|
|
||||||
xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU
|
|
||||||
Cm26OWMohpLzGITY+9HPBVZkVw==
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
# "Developer ID Certification Authority"
|
# "Developer ID Certification Authority"
|
||||||
# 7A FC 9D 01 A6 2F 03 A2 DE 96 37 93 6D 4A FE 68
|
# 7A FC 9D 01 A6 2F 03 A2 DE 96 37 93 6D 4A FE 68
|
||||||
# 09 0D 2D E1 8D 03 F2 9C 88 CF B0 B1 BA 63 58 7F
|
# 09 0D 2D E1 8D 03 F2 9C 88 CF B0 B1 BA 63 58 7F
|
||||||
|
@ -1801,29 +1696,6 @@ R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5
|
||||||
JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
|
JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
|
||||||
Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
|
Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
# "DST Root CA X4"
|
|
||||||
# 9A 73 92 9A 50 0F 1A 0B F4 9D CB 04 6E 80 39 16
|
|
||||||
# 96 96 55 73 45 E9 F8 13 F1 0F F9 38 0D B2 26 95
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDOzCCAiOgAwIBAgIRANAeRlAAACmMAAAAAgAAAAIwDQYJKoZIhvcNAQEFBQAw
|
|
||||||
PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
|
|
||||||
Ew5EU1QgUm9vdCBDQSBYNDAeFw0wMDA5MTMwNjIyNTBaFw0yMDA5MTMwNjIyNTBa
|
|
||||||
MD8xJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjEXMBUGA1UE
|
|
||||||
AxMORFNUIFJvb3QgQ0EgWDQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
|
|
||||||
AQCthX3OFEYY8gSeIYur0O4ypOT68HnDrjLfIutL5PZHRwQGjzCPb9PFo/ihboJ8
|
|
||||||
RvfGhBAqpQCo47zwYEhpWm1jB+L/OE/dBBiyn98krfU2NiBKSom2J58RBeAwHGEy
|
|
||||||
cO+lewyjVvbDDLUy4CheY059vfMjPAftCRXjqSZIolQb9FdPcAoa90mFwB7rKniE
|
|
||||||
J7vppdrUScSS0+eBrHSUPLdvwyn4RGp+lSwbWYcbg5EpSpE0GRJdchic0YDjvIoC
|
|
||||||
YHpe7Rkj93PYRTQyU4bhC88ck8tMqbvRYqMRqR+vobbkrj5LLCOQCHV5WEoxWh+0
|
|
||||||
E2SpIFe7RkV++MmpIAc0h1tZAgMBAAGjMjAwMA8GA1UdEwEB/wQFMAMBAf8wHQYD
|
|
||||||
VR0OBBYEFPCD6nPIP1ubWzdf9UyPWvf0hki9MA0GCSqGSIb3DQEBBQUAA4IBAQCE
|
|
||||||
G85wl5eEWd7adH6XW/ikGN5salvpq/Fix6yVTzE6CrhlP5LBdkf6kx1bSPL18M45
|
|
||||||
g0rw2zA/MWOhJ3+S6U+BE0zPGCuu8YQaZibR7snm3HiHUaZNMu5c8D0x0bcMxDjY
|
|
||||||
AVVcHCoNiL53Q4PLW27nbY6wwG0ffFKmgV3blxrYWfuUDgGpyPwHwkfVFvz9qjaV
|
|
||||||
mf12VJffL6W8omBPtgteb6UaT/k1oJ7YI0ldGf+ngpVbRhD+LC3cUtT6GO/BEPZu
|
|
||||||
8YTV/hbiDH5v3khVqMIeKT6o8IuXGG7F6a6vKwP1F1FwTXf4UC/ivhme7vdUH7B/
|
|
||||||
Vv4AEbT8dNfEeFxrkDbh
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
# "E-Tugra Certification Authority"
|
# "E-Tugra Certification Authority"
|
||||||
# B0 BF D5 2B B0 D7 D9 BD 92 BF 5D 4D C1 3D A2 55
|
# B0 BF D5 2B B0 D7 D9 BD 92 BF 5D 4D C1 3D A2 55
|
||||||
# C0 2C 54 2F 37 83 65 EA 89 39 11 F5 5E 55 F2 3C
|
# C0 2C 54 2F 37 83 65 EA 89 39 11 F5 5E 55 F2 3C
|
||||||
|
@ -2671,39 +2543,6 @@ EhTkYY2sEJCehFC78JZvRZ+K88psT/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpO
|
||||||
fMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilTc4afU9hDDl3WY4JxHYB0yvbi
|
fMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilTc4afU9hDDl3WY4JxHYB0yvbi
|
||||||
AmvZWg==
|
AmvZWg==
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
# "I.CA - Qualified Certification Authority, 09/2009"
|
|
||||||
# C0 C0 5A 8D 8D A5 5E AF 27 AA 9B 91 0B 0A 6E F0
|
|
||||||
# D8 BB DE D3 46 92 8D B8 72 E1 82 C2 07 3E 98 02
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIFHjCCBAagAwIBAgIEAKA3oDANBgkqhkiG9w0BAQsFADCBtzELMAkGA1UEBhMC
|
|
||||||
Q1oxOjA4BgNVBAMMMUkuQ0EgLSBRdWFsaWZpZWQgQ2VydGlmaWNhdGlvbiBBdXRo
|
|
||||||
b3JpdHksIDA5LzIwMDkxLTArBgNVBAoMJFBydm7DrSBjZXJ0aWZpa2HEjW7DrSBh
|
|
||||||
dXRvcml0YSwgYS5zLjE9MDsGA1UECww0SS5DQSAtIEFjY3JlZGl0ZWQgUHJvdmlk
|
|
||||||
ZXIgb2YgQ2VydGlmaWNhdGlvbiBTZXJ2aWNlczAeFw0wOTA5MDEwMDAwMDBaFw0x
|
|
||||||
OTA5MDEwMDAwMDBaMIG3MQswCQYDVQQGEwJDWjE6MDgGA1UEAwwxSS5DQSAtIFF1
|
|
||||||
YWxpZmllZCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSwgMDkvMjAwOTEtMCsGA1UE
|
|
||||||
CgwkUHJ2bsOtIGNlcnRpZmlrYcSNbsOtIGF1dG9yaXRhLCBhLnMuMT0wOwYDVQQL
|
|
||||||
DDRJLkNBIC0gQWNjcmVkaXRlZCBQcm92aWRlciBvZiBDZXJ0aWZpY2F0aW9uIFNl
|
|
||||||
cnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtTaEy0KC8M9l
|
|
||||||
4lSaWHMs4+sVV1LwzyJYiIQNeCrv1HHm/YpGIdY/Z640ceankjQvIX7m23BK4OSC
|
|
||||||
6KO8kZYA3zopOz6GFCOKV2PvLukbc+c2imF6kLHEv6qNA8WxhPbR3xKwlHDwB2yh
|
|
||||||
Wzo7V3QVgDRG83sugqQntKYC3LnlTGbJpNP+Az72gpO9AHUn/IBhFk4ksc8lYS2L
|
|
||||||
9GCy9CsmdKSBP78p9w8Lx7vDLqkDgt1/zBrcUWmSSb7AE/BPEeMryQV1IdI6nlGn
|
|
||||||
BhWkXOYf6GSdayJw86btuxC7viDKNrbp44HjQRaSxnp6O3eto1x4DfiYdw/YbJFe
|
|
||||||
7EjkxSQBywIDAQABo4IBLjCCASowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E
|
|
||||||
BAMCAQYwgecGA1UdIASB3zCB3DCB2QYEVR0gADCB0DCBzQYIKwYBBQUHAgIwgcAa
|
|
||||||
gb1UZW50byBjZXJ0aWZpa2F0IGplIHZ5ZGFuIGpha28ga3ZhbGlmaWtvdmFueSBz
|
|
||||||
eXN0ZW1vdnkgY2VydGlmaWthdCBwb2RsZSB6YWtvbmEgYy4gMjI3LzIwMDAgU2Iu
|
|
||||||
IHYgcGxhdG5lbSB6bmVuaS9UaGlzIGlzIHF1YWxpZmllZCBzeXN0ZW0gY2VydGlm
|
|
||||||
aWNhdGUgYWNjb3JkaW5nIHRvIEN6ZWNoIEFjdCBOby4gMjI3LzIwMDAgQ29sbC4w
|
|
||||||
HQYDVR0OBBYEFHnL0CPpOmdwkXRP01Hi4CD94Sj7MA0GCSqGSIb3DQEBCwUAA4IB
|
|
||||||
AQB9laU214hYaBHPZftbDS/2dIGLWdmdSbj1OZbJ8LIPBMxYjPoEMqzAR74tw96T
|
|
||||||
i6aWRa5WdOWaS6I/qibEKFZhJAVXX5mkx2ewGFLJ+0Go+eTxnjLOnhVF2V2s+57b
|
|
||||||
m8c8j6/bS6Ij6DspcHEYpfjjh64hE2r0aSpZDjGzKFM6YpqsCJN8qYe2X1qmGMLQ
|
|
||||||
wvNdjG+nPzCJOOuUEypIWt555ZDLXqS5F7ZjBjlfyDZjEfS2Es9Idok8alf563Mi
|
|
||||||
9/o+Ba46wMYOkk3P1IlU0RqCajdbliioACKDztAqubONU1guZVzV8tuMASVzbJeL
|
|
||||||
/GAB7ECTwe1RuKrLYtglMKI9
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
# "IdenTrust Commercial Root CA 1"
|
# "IdenTrust Commercial Root CA 1"
|
||||||
# 5D 56 49 9B E4 D2 E0 8B CF CA D0 8A 3E 38 72 3D
|
# 5D 56 49 9B E4 D2 E0 8B CF CA D0 8A 3E 38 72 3D
|
||||||
# 50 50 3B DE 70 69 48 E4 2F 55 60 30 19 E5 28 AE
|
# 50 50 3B DE 70 69 48 E4 2F 55 60 30 19 E5 28 AE
|
||||||
|
@ -4722,123 +4561,6 @@ VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB
|
||||||
L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG
|
L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG
|
||||||
jjxDah2nGN59PRbxYvnKkKj9
|
jjxDah2nGN59PRbxYvnKkKj9
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
# "UTN - DATACorp SGC"
|
|
||||||
# 85 FB 2F 91 DD 12 27 5A 01 45 B6 36 53 4F 84 02
|
|
||||||
# 4A D6 8B 69 B8 EE 88 68 4F F7 11 37 58 05 B3 48
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB
|
|
||||||
kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
|
|
||||||
Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
|
|
||||||
dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw
|
|
||||||
IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG
|
|
||||||
EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD
|
|
||||||
VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu
|
|
||||||
dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN
|
|
||||||
BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6
|
|
||||||
E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ
|
|
||||||
D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK
|
|
||||||
4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq
|
|
||||||
lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW
|
|
||||||
bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB
|
|
||||||
o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT
|
|
||||||
MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js
|
|
||||||
LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr
|
|
||||||
BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB
|
|
||||||
AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft
|
|
||||||
Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj
|
|
||||||
j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH
|
|
||||||
KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv
|
|
||||||
2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3
|
|
||||||
mfnGV/TJVTl4uix5yaaIK/QI
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
# "UTN-USERFirst-Client Authentication and Email"
|
|
||||||
# 43 F2 57 41 2D 44 0D 62 74 76 97 4F 87 7D A8 F1
|
|
||||||
# FC 24 44 56 5A 36 7A E6 0E DD C2 7A 41 25 31 AE
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIEojCCA4qgAwIBAgIQRL4Mi1AAJLQR0zYlJWfJiTANBgkqhkiG9w0BAQUFADCB
|
|
||||||
rjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
|
|
||||||
Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
|
|
||||||
dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xNjA0BgNVBAMTLVVUTi1VU0VSRmlyc3Qt
|
|
||||||
Q2xpZW50IEF1dGhlbnRpY2F0aW9uIGFuZCBFbWFpbDAeFw05OTA3MDkxNzI4NTBa
|
|
||||||
Fw0xOTA3MDkxNzM2NThaMIGuMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAV
|
|
||||||
BgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5l
|
|
||||||
dHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTE2MDQGA1UE
|
|
||||||
AxMtVVROLVVTRVJGaXJzdC1DbGllbnQgQXV0aGVudGljYXRpb24gYW5kIEVtYWls
|
|
||||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsjmFpPJ9q0E7YkY3rs3B
|
|
||||||
YHW8OWX5ShpHornMSMxqmNVNNRm5pELlzkniii8efNIxB8dOtINknS4p1aJkxIW9
|
|
||||||
hVE1eaROaJB7HHqkkqgX8pgV8pPMyaQylbsMTzC9mKALi+VuG6JG+ni8om+rWV6l
|
|
||||||
L8/K2m2qL+usobNqqrcuZzWLeeEeaYji5kbNoKXqvgvOdjp6Dpvq/NonWz1zHyLm
|
|
||||||
SGHGTPNpsaguG7bUMSAsvIKKjqQOpdeJQ/wWWq8dcdcRWdq6hw2v+vPhwvCkxWeM
|
|
||||||
1tZUOt4KpLoDd7NlyP0e03RiqhjKaJMeoYV+9Udly/hNVyh00jT/MLbu9mIwFIws
|
|
||||||
6wIDAQABo4G5MIG2MAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
|
|
||||||
DgQWBBSJgmd9xJ0mcABLtFBIfN49rgRufTBYBgNVHR8EUTBPME2gS6BJhkdodHRw
|
|
||||||
Oi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLVVTRVJGaXJzdC1DbGllbnRBdXRoZW50
|
|
||||||
aWNhdGlvbmFuZEVtYWlsLmNybDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH
|
|
||||||
AwQwDQYJKoZIhvcNAQEFBQADggEBALFtYV2mGn98q0rkMPxTbyUkxsrt4jFcKw7u
|
|
||||||
7mFVbwQ+zznexRtJlOTrIEy05p5QLnLZjfWqo7NK2lYcYJeA3IKirUq9iiv/Cwm0
|
|
||||||
xtcgBEXkzYABurorbs6q15L+5K/r9CYdFip/bDCVNy8zEqx/3cfREYxRmLLQo5HQ
|
|
||||||
rfafnoOTHh1CuEava2bwm3/q4wMC5QJRwarVNZ1yQAOJujEdxRBoUp7fooXFXAim
|
|
||||||
eOZTT7Hot9MUnpOmw2TjrH5xzbyf6QMbzPvprDHBr3wVdAKZw7JHpsIyYdfHb0gk
|
|
||||||
USeh1YdV8nuPmD0Wnu51tvjQjvLzxq4oW6fw8zYX/MMF08oDSlQ=
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
# "UTN-USERFirst-Hardware"
|
|
||||||
# 6E A5 47 41 D0 04 66 7E ED 1B 48 16 63 4A A3 A7
|
|
||||||
# 9E 6E 4B 96 95 0F 82 79 DA FC 8D 9B D8 81 21 37
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB
|
|
||||||
lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
|
|
||||||
Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
|
|
||||||
dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt
|
|
||||||
SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG
|
|
||||||
A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe
|
|
||||||
MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v
|
|
||||||
d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh
|
|
||||||
cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn
|
|
||||||
0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ
|
|
||||||
M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a
|
|
||||||
MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd
|
|
||||||
oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI
|
|
||||||
DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy
|
|
||||||
oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD
|
|
||||||
VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0
|
|
||||||
dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy
|
|
||||||
bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF
|
|
||||||
BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM
|
|
||||||
//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli
|
|
||||||
CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE
|
|
||||||
CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t
|
|
||||||
3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS
|
|
||||||
KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA==
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
# "UTN-USERFirst-Object"
|
|
||||||
# 6F FF 78 E4 00 A7 0C 11 01 1C D8 59 77 C4 59 FB
|
|
||||||
# 5A F9 6A 3D F0 54 08 20 D0 F4 B8 60 78 75 E5 8F
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIEZjCCA06gAwIBAgIQRL4Mi1AAJLQR0zYt4LNfGzANBgkqhkiG9w0BAQUFADCB
|
|
||||||
lTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
|
|
||||||
Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
|
|
||||||
dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHTAbBgNVBAMTFFVUTi1VU0VSRmlyc3Qt
|
|
||||||
T2JqZWN0MB4XDTk5MDcwOTE4MzEyMFoXDTE5MDcwOTE4NDAzNlowgZUxCzAJBgNV
|
|
||||||
BAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxHjAc
|
|
||||||
BgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEhMB8GA1UECxMYaHR0cDovL3d3
|
|
||||||
dy51c2VydHJ1c3QuY29tMR0wGwYDVQQDExRVVE4tVVNFUkZpcnN0LU9iamVjdDCC
|
|
||||||
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6qgT+jo2F4qjEAVZURnicP
|
|
||||||
HxzfOpuCaDDASmEd8S8O+r5596Uj71VRloTN2+O5bj4x2AogZ8f02b+U60cEPgLO
|
|
||||||
KqJdhwQJ9jCdGIqXsqoc/EHSoTbL+z2RuufZcDX65OeQw5ujm9M89RKZd7G3CeBo
|
|
||||||
5hy485RjiGpq/gt2yb70IuRnuasaXnfBhQfdDWy/7gbHd2pBnqcP1/vulBe3/IW+
|
|
||||||
pKvEHDHd17bR5PDv3xaPslKT16HUiaEHLr/hARJCHhrh2JU022R5KP+6LhHC5ehb
|
|
||||||
kkj7RwvCbNqtMoNB86XlQXD9ZZBt+vpRxPm9lisZBCzTbafc8H9vg2XiaquHhnUC
|
|
||||||
AwEAAaOBrzCBrDALBgNVHQ8EBAMCAcYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
|
|
||||||
FgQU2u1kdBScFDyr3ZmpvVsoTYs8ydgwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDov
|
|
||||||
L2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmlyc3QtT2JqZWN0LmNybDApBgNV
|
|
||||||
HSUEIjAgBggrBgEFBQcDAwYIKwYBBQUHAwgGCisGAQQBgjcKAwQwDQYJKoZIhvcN
|
|
||||||
AQEFBQADggEBAAgfUrE3RHjb/c652pWWmKpVZIC1WkDdIaXFwfNfLEzIR1pp6ujw
|
|
||||||
NTX00CXzyKakh0q9G7FzCL3Uw8q2NbtZhncxzaeAFK4T7/yxSPlrJSUtUbYsbUXB
|
|
||||||
mMiKVl0+7kNOPmsnjtA6S4ULX9Ptaqd1y9Fahy85dRNacrACgZ++8A+EVCBibGnU
|
|
||||||
4U3GDZlDAQ0Slox4nb9QorFEqmrPF3rPbw/U+CRVX/A0FklmPlBGyWNxODFiuGK5
|
|
||||||
81OtbLUrohKqGU8J2l7nk8aOFAj+8DCAGKCGhU3IfdeLA/5u1fedFqySLKAj5ZyR
|
|
||||||
Uh+U3xeUc8OzwcFxBSAAeL0TUh2oPs0AH8g=
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
# "VeriSign Class 1 Public Primary Certification Authority - G3"
|
# "VeriSign Class 1 Public Primary Certification Authority - G3"
|
||||||
# CB B5 AF 18 5E 94 2A 24 02 F9 EA CB C0 ED 5B B8
|
# CB B5 AF 18 5E 94 2A 24 02 F9 EA CB C0 ED 5B B8
|
||||||
# 76 EE A3 C1 22 36 23 D0 04 47 E4 F3 BA 55 4B 65
|
# 76 EE A3 C1 22 36 23 D0 04 47 E4 F3 BA 55 4B 65
|
||||||
|
|
|
@ -1997,49 +1997,6 @@ func buildCSRExtensions(template *CertificateRequest) ([]pkix.Extension, error)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if template.KeyUsage != 0 &&
|
|
||||||
!oidInExtensions(oidExtensionKeyUsage, template.ExtraExtensions) {
|
|
||||||
ext, err := marshalKeyUsage(template.KeyUsage)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ret = append(ret, ext)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len(template.ExtKeyUsage) > 0 || len(template.UnknownExtKeyUsage) > 0) &&
|
|
||||||
!oidInExtensions(oidExtensionExtendedKeyUsage, template.ExtraExtensions) {
|
|
||||||
ext, err := marshalExtKeyUsage(template.ExtKeyUsage, template.UnknownExtKeyUsage)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ret = append(ret, ext)
|
|
||||||
}
|
|
||||||
|
|
||||||
if template.BasicConstraintsValid && !oidInExtensions(oidExtensionBasicConstraints, template.ExtraExtensions) {
|
|
||||||
ext, err := marshalBasicConstraints(template.IsCA, template.MaxPathLen, template.MaxPathLenZero)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ret = append(ret, ext)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(template.SubjectKeyId) > 0 && !oidInExtensions(oidExtensionSubjectKeyId, template.ExtraExtensions) {
|
|
||||||
skidBytes, err := asn1.Marshal(template.SubjectKeyId)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ret = append(ret, pkix.Extension{Id: oidExtensionSubjectKeyId, Value: skidBytes})
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(template.PolicyIdentifiers) > 0 &&
|
|
||||||
!oidInExtensions(oidExtensionCertificatePolicies, template.ExtraExtensions) {
|
|
||||||
ext, err := marshalCertificatePolicies(template.PolicyIdentifiers)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ret = append(ret, ext)
|
|
||||||
}
|
|
||||||
|
|
||||||
return append(ret, template.ExtraExtensions...), nil
|
return append(ret, template.ExtraExtensions...), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2405,7 +2362,6 @@ type CertificateRequest struct {
|
||||||
Version int
|
Version int
|
||||||
Signature []byte
|
Signature []byte
|
||||||
SignatureAlgorithm SignatureAlgorithm
|
SignatureAlgorithm SignatureAlgorithm
|
||||||
KeyUsage KeyUsage
|
|
||||||
|
|
||||||
PublicKeyAlgorithm PublicKeyAlgorithm
|
PublicKeyAlgorithm PublicKeyAlgorithm
|
||||||
PublicKey interface{}
|
PublicKey interface{}
|
||||||
|
@ -2438,37 +2394,6 @@ type CertificateRequest struct {
|
||||||
EmailAddresses []string
|
EmailAddresses []string
|
||||||
IPAddresses []net.IP
|
IPAddresses []net.IP
|
||||||
URIs []*url.URL
|
URIs []*url.URL
|
||||||
|
|
||||||
ExtKeyUsage []ExtKeyUsage // Sequence of extended key usages.
|
|
||||||
UnknownExtKeyUsage []asn1.ObjectIdentifier // Encountered extended key usages unknown to this package.
|
|
||||||
|
|
||||||
// BasicConstraintsValid indicates whether IsCA, MaxPathLen,
|
|
||||||
// and MaxPathLenZero are valid.
|
|
||||||
BasicConstraintsValid bool
|
|
||||||
IsCA bool
|
|
||||||
|
|
||||||
// MaxPathLen and MaxPathLenZero indicate the presence and
|
|
||||||
// value of the BasicConstraints' "pathLenConstraint".
|
|
||||||
//
|
|
||||||
// When parsing a certificate, a positive non-zero MaxPathLen
|
|
||||||
// means that the field was specified, -1 means it was unset,
|
|
||||||
// and MaxPathLenZero being true mean that the field was
|
|
||||||
// explicitly set to zero. The case of MaxPathLen==0 with MaxPathLenZero==false
|
|
||||||
// should be treated equivalent to -1 (unset).
|
|
||||||
//
|
|
||||||
// When generating a certificate, an unset pathLenConstraint
|
|
||||||
// can be requested with either MaxPathLen == -1 or using the
|
|
||||||
// zero value for both MaxPathLen and MaxPathLenZero.
|
|
||||||
MaxPathLen int
|
|
||||||
// MaxPathLenZero indicates that BasicConstraintsValid==true
|
|
||||||
// and MaxPathLen==0 should be interpreted as an actual
|
|
||||||
// maximum path length of zero. Otherwise, that combination is
|
|
||||||
// interpreted as MaxPathLen not being set.
|
|
||||||
MaxPathLenZero bool
|
|
||||||
|
|
||||||
SubjectKeyId []byte
|
|
||||||
|
|
||||||
PolicyIdentifiers []asn1.ObjectIdentifier
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// These structures reflect the ASN.1 structure of X.509 certificate
|
// These structures reflect the ASN.1 structure of X.509 certificate
|
||||||
|
@ -2566,15 +2491,6 @@ func parseCSRExtensions(rawAttributes []asn1.RawValue) ([]pkix.Extension, error)
|
||||||
// - EmailAddresses
|
// - EmailAddresses
|
||||||
// - IPAddresses
|
// - IPAddresses
|
||||||
// - URIs
|
// - URIs
|
||||||
// - KeyUsage
|
|
||||||
// - ExtKeyUsage
|
|
||||||
// - UnknownExtKeyUsage
|
|
||||||
// - BasicConstraintsValid
|
|
||||||
// - IsCA
|
|
||||||
// - MaxPathLen
|
|
||||||
// - MaxPathLenZero
|
|
||||||
// - SubjectKeyId
|
|
||||||
// - PolicyIdentifiers
|
|
||||||
// - ExtraExtensions
|
// - ExtraExtensions
|
||||||
// - Attributes (deprecated)
|
// - Attributes (deprecated)
|
||||||
//
|
//
|
||||||
|
@ -2799,30 +2715,6 @@ func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
case extension.Id.Equal(oidExtensionKeyUsage):
|
|
||||||
out.KeyUsage, err = parseKeyUsageExtension(extension.Value)
|
|
||||||
case extension.Id.Equal(oidExtensionExtendedKeyUsage):
|
|
||||||
out.ExtKeyUsage, out.UnknownExtKeyUsage, err = parseExtKeyUsageExtension(extension.Value)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
case extension.Id.Equal(oidExtensionBasicConstraints):
|
|
||||||
out.IsCA, out.MaxPathLen, err = parseBasicConstraintsExtension(extension.Value)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
out.BasicConstraintsValid = true
|
|
||||||
out.MaxPathLenZero = out.MaxPathLen == 0
|
|
||||||
case extension.Id.Equal(oidExtensionSubjectKeyId):
|
|
||||||
out.SubjectKeyId, err = parseSubjectKeyIdExtension(extension.Value)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
case extension.Id.Equal(oidExtensionCertificatePolicies):
|
|
||||||
out.PolicyIdentifiers, err = parseCertificatePoliciesExtension(extension.Value)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2964,44 +2964,34 @@ func certPoolEqual(a, b *CertPool) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCertificateRequestRoundtripFields(t *testing.T) {
|
func TestCertificateRequestRoundtripFields(t *testing.T) {
|
||||||
|
urlA, err := url.Parse("https://example.com/_")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
urlB, err := url.Parse("https://example.org/_")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
in := &CertificateRequest{
|
in := &CertificateRequest{
|
||||||
KeyUsage: KeyUsageCertSign,
|
DNSNames: []string{"example.com", "example.org"},
|
||||||
ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageAny},
|
EmailAddresses: []string{"a@example.com", "b@example.com"},
|
||||||
UnknownExtKeyUsage: []asn1.ObjectIdentifier{{1, 2, 3}},
|
IPAddresses: []net.IP{net.IPv4(192, 0, 2, 0), net.IPv6loopback},
|
||||||
BasicConstraintsValid: true,
|
URIs: []*url.URL{urlA, urlB},
|
||||||
IsCA: true,
|
|
||||||
MaxPathLen: 0,
|
|
||||||
MaxPathLenZero: true,
|
|
||||||
SubjectKeyId: []byte{1, 2, 3},
|
|
||||||
PolicyIdentifiers: []asn1.ObjectIdentifier{{1, 2, 3}},
|
|
||||||
}
|
}
|
||||||
out := marshalAndParseCSR(t, in)
|
out := marshalAndParseCSR(t, in)
|
||||||
|
|
||||||
if in.KeyUsage != out.KeyUsage {
|
if !reflect.DeepEqual(in.DNSNames, out.DNSNames) {
|
||||||
t.Fatalf("Unexpected KeyUsage: got %v, want %v", out.KeyUsage, in.KeyUsage)
|
t.Fatalf("Unexpected DNSNames: got %v, want %v", out.DNSNames, in.DNSNames)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(in.ExtKeyUsage, out.ExtKeyUsage) {
|
if !reflect.DeepEqual(in.EmailAddresses, out.EmailAddresses) {
|
||||||
t.Fatalf("Unexpected ExtKeyUsage: got %v, want %v", out.ExtKeyUsage, in.ExtKeyUsage)
|
t.Fatalf("Unexpected EmailAddresses: got %v, want %v", out.EmailAddresses, in.EmailAddresses)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(in.UnknownExtKeyUsage, out.UnknownExtKeyUsage) {
|
if len(in.IPAddresses) != len(out.IPAddresses) ||
|
||||||
t.Fatalf("Unexpected UnknownExtKeyUsage: got %v, want %v", out.UnknownExtKeyUsage, in.UnknownExtKeyUsage)
|
!in.IPAddresses[0].Equal(out.IPAddresses[0]) ||
|
||||||
|
!in.IPAddresses[1].Equal(out.IPAddresses[1]) {
|
||||||
|
t.Fatalf("Unexpected IPAddresses: got %v, want %v", out.IPAddresses, in.IPAddresses)
|
||||||
}
|
}
|
||||||
if in.BasicConstraintsValid != out.BasicConstraintsValid {
|
if !reflect.DeepEqual(in.URIs, out.URIs) {
|
||||||
t.Fatalf("Unexpected BasicConstraintsValid: got %v, want %v", out.BasicConstraintsValid, in.BasicConstraintsValid)
|
t.Fatalf("Unexpected URIs: got %v, want %v", out.URIs, in.URIs)
|
||||||
}
|
|
||||||
if in.IsCA != out.IsCA {
|
|
||||||
t.Fatalf("Unexpected IsCA: got %v, want %v", out.IsCA, in.IsCA)
|
|
||||||
}
|
|
||||||
if in.MaxPathLen != out.MaxPathLen {
|
|
||||||
t.Fatalf("Unexpected MaxPathLen: got %v, want %v", out.MaxPathLen, in.MaxPathLen)
|
|
||||||
}
|
|
||||||
if in.MaxPathLenZero != out.MaxPathLenZero {
|
|
||||||
t.Fatalf("Unexpected MaxPathLenZero: got %v, want %v", out.MaxPathLenZero, in.MaxPathLenZero)
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(in.SubjectKeyId, out.SubjectKeyId) {
|
|
||||||
t.Fatalf("Unexpected SubjectKeyId: got %v, want %v", out.SubjectKeyId, in.SubjectKeyId)
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(in.PolicyIdentifiers, out.PolicyIdentifiers) {
|
|
||||||
t.Fatalf("Unexpected PolicyIdentifiers: got %v, want %v", out.PolicyIdentifiers, in.PolicyIdentifiers)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -244,6 +244,9 @@ func (f FS) lookup(name string) *file {
|
||||||
if name == "." {
|
if name == "." {
|
||||||
return dotFile
|
return dotFile
|
||||||
}
|
}
|
||||||
|
if f.files == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Binary search to find where name would be in the list,
|
// Binary search to find where name would be in the list,
|
||||||
// and then check if name is at that position.
|
// and then check if name is at that position.
|
||||||
|
@ -261,6 +264,9 @@ func (f FS) lookup(name string) *file {
|
||||||
|
|
||||||
// readDir returns the list of files corresponding to the directory dir.
|
// readDir returns the list of files corresponding to the directory dir.
|
||||||
func (f FS) readDir(dir string) []file {
|
func (f FS) readDir(dir string) []file {
|
||||||
|
if f.files == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
// Binary search to find where dir starts and ends in the list
|
// Binary search to find where dir starts and ends in the list
|
||||||
// and then return that slice of the list.
|
// and then return that slice of the list.
|
||||||
files := *f.files
|
files := *f.files
|
||||||
|
|
|
@ -73,24 +73,11 @@ func TestGlobal(t *testing.T) {
|
||||||
testString(t, string(glass), "glass", "I can eat glass and it doesn't hurt me.\n")
|
testString(t, string(glass), "glass", "I can eat glass and it doesn't hurt me.\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLocal(t *testing.T) {
|
//go:embed testdata
|
||||||
//go:embed testdata/k*.txt
|
var testDirAll embed.FS
|
||||||
var local embed.FS
|
|
||||||
testFiles(t, local, "testdata/ken.txt", "If a program is too slow, it must have a loop.\n")
|
|
||||||
|
|
||||||
//go:embed testdata/k*.txt
|
|
||||||
var s string
|
|
||||||
testString(t, s, "local variable s", "If a program is too slow, it must have a loop.\n")
|
|
||||||
|
|
||||||
//go:embed testdata/h*.txt
|
|
||||||
var b []byte
|
|
||||||
testString(t, string(b), "local variable b", "hello, world\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDir(t *testing.T) {
|
func TestDir(t *testing.T) {
|
||||||
//go:embed testdata
|
all := testDirAll
|
||||||
var all embed.FS
|
|
||||||
|
|
||||||
testFiles(t, all, "testdata/hello.txt", "hello, world\n")
|
testFiles(t, all, "testdata/hello.txt", "hello, world\n")
|
||||||
testFiles(t, all, "testdata/i/i18n.txt", "internationalization\n")
|
testFiles(t, all, "testdata/i/i18n.txt", "internationalization\n")
|
||||||
testFiles(t, all, "testdata/i/j/k/k8s.txt", "kubernetes\n")
|
testFiles(t, all, "testdata/i/j/k/k8s.txt", "kubernetes\n")
|
||||||
|
@ -102,12 +89,15 @@ func TestDir(t *testing.T) {
|
||||||
testDir(t, all, "testdata/i/j/k", "k8s.txt")
|
testDir(t, all, "testdata/i/j/k", "k8s.txt")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHidden(t *testing.T) {
|
//go:embed testdata
|
||||||
//go:embed testdata
|
var testHiddenDir embed.FS
|
||||||
var dir embed.FS
|
|
||||||
|
|
||||||
//go:embed testdata/*
|
//go:embed testdata/*
|
||||||
var star embed.FS
|
var testHiddenStar embed.FS
|
||||||
|
|
||||||
|
func TestHidden(t *testing.T) {
|
||||||
|
dir := testHiddenDir
|
||||||
|
star := testHiddenStar
|
||||||
|
|
||||||
t.Logf("//go:embed testdata")
|
t.Logf("//go:embed testdata")
|
||||||
|
|
||||||
|
@ -122,3 +112,20 @@ func TestHidden(t *testing.T) {
|
||||||
testDir(t, star, "testdata/.hidden",
|
testDir(t, star, "testdata/.hidden",
|
||||||
"fortune.txt", "more/") // but not .more or _more
|
"fortune.txt", "more/") // but not .more or _more
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUninitialized(t *testing.T) {
|
||||||
|
var uninitialized embed.FS
|
||||||
|
testDir(t, uninitialized, ".")
|
||||||
|
f, err := uninitialized.Open(".")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
fi, err := f.Stat()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !fi.IsDir() {
|
||||||
|
t.Errorf("in uninitialized embed.FS, . is not a directory")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -90,17 +90,3 @@ func TestXGlobal(t *testing.T) {
|
||||||
}
|
}
|
||||||
bbig[0] = old
|
bbig[0] = old
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestXLocal(t *testing.T) {
|
|
||||||
//go:embed testdata/*o.txt
|
|
||||||
var local embed.FS
|
|
||||||
testFiles(t, local, "testdata/hello.txt", "hello, world\n")
|
|
||||||
|
|
||||||
//go:embed testdata/k*.txt
|
|
||||||
var s string
|
|
||||||
testString(t, s, "local variable s", "If a program is too slow, it must have a loop.\n")
|
|
||||||
|
|
||||||
//go:embed testdata/h*.txt
|
|
||||||
var b []byte
|
|
||||||
testString(t, string(b), "local variable b", "hello, world\n")
|
|
||||||
}
|
|
||||||
|
|
|
@ -1067,6 +1067,15 @@ func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
|
||||||
// set causes a SET, rather than a SEQUENCE type to be expected
|
// set causes a SET, rather than a SEQUENCE type to be expected
|
||||||
// tag:x specifies the ASN.1 tag number; implies ASN.1 CONTEXT SPECIFIC
|
// tag:x specifies the ASN.1 tag number; implies ASN.1 CONTEXT SPECIFIC
|
||||||
//
|
//
|
||||||
|
// When decoding an ASN.1 value with an IMPLICIT tag into a string field,
|
||||||
|
// Unmarshal will default to a PrintableString, which doesn't support
|
||||||
|
// characters such as '@' and '&'. To force other encodings, use the following
|
||||||
|
// tags:
|
||||||
|
//
|
||||||
|
// ia5 causes strings to be unmarshaled as ASN.1 IA5String values
|
||||||
|
// numeric causes strings to be unmarshaled as ASN.1 NumericString values
|
||||||
|
// utf8 causes strings to be unmarshaled as ASN.1 UTF8String values
|
||||||
|
//
|
||||||
// If the type of the first field of a structure is RawContent then the raw
|
// If the type of the first field of a structure is RawContent then the raw
|
||||||
// ASN1 contents of the struct will be stored in it.
|
// ASN1 contents of the struct will be stored in it.
|
||||||
//
|
//
|
||||||
|
|
|
@ -11,13 +11,13 @@ import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/doc"
|
"go/doc"
|
||||||
"go/token"
|
"go/token"
|
||||||
|
exec "internal/execabs"
|
||||||
"internal/goroot"
|
"internal/goroot"
|
||||||
"internal/goversion"
|
"internal/goversion"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
pathpkg "path"
|
pathpkg "path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -451,9 +451,12 @@ type Package struct {
|
||||||
// //go:embed a* b.c
|
// //go:embed a* b.c
|
||||||
// then the list will contain those two strings as separate entries.
|
// then the list will contain those two strings as separate entries.
|
||||||
// (See package embed for more details about //go:embed.)
|
// (See package embed for more details about //go:embed.)
|
||||||
EmbedPatterns []string // patterns from GoFiles, CgoFiles
|
EmbedPatterns []string // patterns from GoFiles, CgoFiles
|
||||||
TestEmbedPatterns []string // patterns from TestGoFiles
|
EmbedPatternPos map[string][]token.Position // line information for EmbedPatterns
|
||||||
XTestEmbedPatterns []string // patterns from XTestGoFiles
|
TestEmbedPatterns []string // patterns from TestGoFiles
|
||||||
|
TestEmbedPatternPos map[string][]token.Position // line information for TestEmbedPatterns
|
||||||
|
XTestEmbedPatterns []string // patterns from XTestGoFiles
|
||||||
|
XTestEmbedPatternPos map[string][]token.Position // line information for XTestEmbedPatternPos
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsCommand reports whether the package is considered a
|
// IsCommand reports whether the package is considered a
|
||||||
|
@ -796,10 +799,12 @@ Found:
|
||||||
var badGoError error
|
var badGoError error
|
||||||
var Sfiles []string // files with ".S"(capital S)/.sx(capital s equivalent for case insensitive filesystems)
|
var Sfiles []string // files with ".S"(capital S)/.sx(capital s equivalent for case insensitive filesystems)
|
||||||
var firstFile, firstCommentFile string
|
var firstFile, firstCommentFile string
|
||||||
var embeds, testEmbeds, xTestEmbeds []string
|
embedPos := make(map[string][]token.Position)
|
||||||
imported := make(map[string][]token.Position)
|
testEmbedPos := make(map[string][]token.Position)
|
||||||
testImported := make(map[string][]token.Position)
|
xTestEmbedPos := make(map[string][]token.Position)
|
||||||
xTestImported := make(map[string][]token.Position)
|
importPos := make(map[string][]token.Position)
|
||||||
|
testImportPos := make(map[string][]token.Position)
|
||||||
|
xTestImportPos := make(map[string][]token.Position)
|
||||||
allTags := make(map[string]bool)
|
allTags := make(map[string]bool)
|
||||||
fset := token.NewFileSet()
|
fset := token.NewFileSet()
|
||||||
for _, d := range dirs {
|
for _, d := range dirs {
|
||||||
|
@ -922,31 +927,31 @@ Found:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileList, embedList *[]string
|
var fileList *[]string
|
||||||
var importMap map[string][]token.Position
|
var importMap, embedMap map[string][]token.Position
|
||||||
switch {
|
switch {
|
||||||
case isCgo:
|
case isCgo:
|
||||||
allTags["cgo"] = true
|
allTags["cgo"] = true
|
||||||
if ctxt.CgoEnabled {
|
if ctxt.CgoEnabled {
|
||||||
fileList = &p.CgoFiles
|
fileList = &p.CgoFiles
|
||||||
importMap = imported
|
importMap = importPos
|
||||||
embedList = &embeds
|
embedMap = embedPos
|
||||||
} else {
|
} else {
|
||||||
// Ignore imports from cgo files if cgo is disabled.
|
// Ignore imports and embeds from cgo files if cgo is disabled.
|
||||||
fileList = &p.IgnoredGoFiles
|
fileList = &p.IgnoredGoFiles
|
||||||
}
|
}
|
||||||
case isXTest:
|
case isXTest:
|
||||||
fileList = &p.XTestGoFiles
|
fileList = &p.XTestGoFiles
|
||||||
importMap = xTestImported
|
importMap = xTestImportPos
|
||||||
embedList = &xTestEmbeds
|
embedMap = xTestEmbedPos
|
||||||
case isTest:
|
case isTest:
|
||||||
fileList = &p.TestGoFiles
|
fileList = &p.TestGoFiles
|
||||||
importMap = testImported
|
importMap = testImportPos
|
||||||
embedList = &testEmbeds
|
embedMap = testEmbedPos
|
||||||
default:
|
default:
|
||||||
fileList = &p.GoFiles
|
fileList = &p.GoFiles
|
||||||
importMap = imported
|
importMap = importPos
|
||||||
embedList = &embeds
|
embedMap = embedPos
|
||||||
}
|
}
|
||||||
*fileList = append(*fileList, name)
|
*fileList = append(*fileList, name)
|
||||||
if importMap != nil {
|
if importMap != nil {
|
||||||
|
@ -954,8 +959,10 @@ Found:
|
||||||
importMap[imp.path] = append(importMap[imp.path], fset.Position(imp.pos))
|
importMap[imp.path] = append(importMap[imp.path], fset.Position(imp.pos))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if embedList != nil {
|
if embedMap != nil {
|
||||||
*embedList = append(*embedList, info.embeds...)
|
for _, emb := range info.embeds {
|
||||||
|
embedMap[emb.pattern] = append(embedMap[emb.pattern], emb.pos)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -964,13 +971,13 @@ Found:
|
||||||
}
|
}
|
||||||
sort.Strings(p.AllTags)
|
sort.Strings(p.AllTags)
|
||||||
|
|
||||||
p.EmbedPatterns = uniq(embeds)
|
p.EmbedPatterns, p.EmbedPatternPos = cleanDecls(embedPos)
|
||||||
p.TestEmbedPatterns = uniq(testEmbeds)
|
p.TestEmbedPatterns, p.TestEmbedPatternPos = cleanDecls(testEmbedPos)
|
||||||
p.XTestEmbedPatterns = uniq(xTestEmbeds)
|
p.XTestEmbedPatterns, p.XTestEmbedPatternPos = cleanDecls(xTestEmbedPos)
|
||||||
|
|
||||||
p.Imports, p.ImportPos = cleanImports(imported)
|
p.Imports, p.ImportPos = cleanDecls(importPos)
|
||||||
p.TestImports, p.TestImportPos = cleanImports(testImported)
|
p.TestImports, p.TestImportPos = cleanDecls(testImportPos)
|
||||||
p.XTestImports, p.XTestImportPos = cleanImports(xTestImported)
|
p.XTestImports, p.XTestImportPos = cleanDecls(xTestImportPos)
|
||||||
|
|
||||||
// add the .S/.sx files only if we are using cgo
|
// add the .S/.sx files only if we are using cgo
|
||||||
// (which means gcc will compile them).
|
// (which means gcc will compile them).
|
||||||
|
@ -1342,7 +1349,7 @@ type fileInfo struct {
|
||||||
parsed *ast.File
|
parsed *ast.File
|
||||||
parseErr error
|
parseErr error
|
||||||
imports []fileImport
|
imports []fileImport
|
||||||
embeds []string
|
embeds []fileEmbed
|
||||||
embedErr error
|
embedErr error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1352,6 +1359,11 @@ type fileImport struct {
|
||||||
doc *ast.CommentGroup
|
doc *ast.CommentGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type fileEmbed struct {
|
||||||
|
pattern string
|
||||||
|
pos token.Position
|
||||||
|
}
|
||||||
|
|
||||||
// matchFile determines whether the file with the given name in the given directory
|
// matchFile determines whether the file with the given name in the given directory
|
||||||
// should be included in the package being constructed.
|
// should be included in the package being constructed.
|
||||||
// If the file should be included, matchFile returns a non-nil *fileInfo (and a nil error).
|
// If the file should be included, matchFile returns a non-nil *fileInfo (and a nil error).
|
||||||
|
@ -1426,7 +1438,7 @@ func (ctxt *Context) matchFile(dir, name string, allTags map[string]bool, binary
|
||||||
return info, nil
|
return info, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func cleanImports(m map[string][]token.Position) ([]string, map[string][]token.Position) {
|
func cleanDecls(m map[string][]token.Position) ([]string, map[string][]token.Position) {
|
||||||
all := make([]string, 0, len(m))
|
all := make([]string, 0, len(m))
|
||||||
for path := range m {
|
for path := range m {
|
||||||
all = append(all, path)
|
all = append(all, path)
|
||||||
|
|
|
@ -28,6 +28,7 @@ func TestMatch(t *testing.T) {
|
||||||
ctxt := Default
|
ctxt := Default
|
||||||
what := "default"
|
what := "default"
|
||||||
match := func(tag string, want map[string]bool) {
|
match := func(tag string, want map[string]bool) {
|
||||||
|
t.Helper()
|
||||||
m := make(map[string]bool)
|
m := make(map[string]bool)
|
||||||
if !ctxt.match(tag, m) {
|
if !ctxt.match(tag, m) {
|
||||||
t.Errorf("%s context should match %s, does not", what, tag)
|
t.Errorf("%s context should match %s, does not", what, tag)
|
||||||
|
@ -37,6 +38,7 @@ func TestMatch(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nomatch := func(tag string, want map[string]bool) {
|
nomatch := func(tag string, want map[string]bool) {
|
||||||
|
t.Helper()
|
||||||
m := make(map[string]bool)
|
m := make(map[string]bool)
|
||||||
if ctxt.match(tag, m) {
|
if ctxt.match(tag, m) {
|
||||||
t.Errorf("%s context should NOT match %s, does", what, tag)
|
t.Errorf("%s context should NOT match %s, does", what, tag)
|
||||||
|
@ -57,7 +59,6 @@ func TestMatch(t *testing.T) {
|
||||||
nomatch(runtime.GOOS+","+runtime.GOARCH+",!foo", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "foo": true})
|
nomatch(runtime.GOOS+","+runtime.GOARCH+",!foo", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "foo": true})
|
||||||
match(runtime.GOOS+","+runtime.GOARCH+",!bar", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "bar": true})
|
match(runtime.GOOS+","+runtime.GOARCH+",!bar", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "bar": true})
|
||||||
nomatch(runtime.GOOS+","+runtime.GOARCH+",bar", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "bar": true})
|
nomatch(runtime.GOOS+","+runtime.GOARCH+",bar", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "bar": true})
|
||||||
nomatch("!", map[string]bool{})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDotSlashImport(t *testing.T) {
|
func TestDotSlashImport(t *testing.T) {
|
||||||
|
|
|
@ -0,0 +1,574 @@
|
||||||
|
// 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 constraint implements parsing and evaluation of build constraint lines.
|
||||||
|
// See https://golang.org/cmd/go/#hdr-Build_constraints for documentation about build constraints themselves.
|
||||||
|
//
|
||||||
|
// This package parses both the original “// +build” syntax and the “//go:build” syntax that will be added in Go 1.17.
|
||||||
|
// The parser is being included in Go 1.16 to allow tools that need to process Go 1.17 source code
|
||||||
|
// to still be built against the Go 1.16 release.
|
||||||
|
// See https://golang.org/design/draft-gobuild for details about the “//go:build” syntax.
|
||||||
|
package constraint
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
// An Expr is a build tag constraint expression.
|
||||||
|
// The underlying concrete type is *AndExpr, *OrExpr, *NotExpr, or *TagExpr.
|
||||||
|
type Expr interface {
|
||||||
|
// String returns the string form of the expression,
|
||||||
|
// using the boolean syntax used in //go:build lines.
|
||||||
|
String() string
|
||||||
|
|
||||||
|
// Eval reports whether the expression evaluates to true.
|
||||||
|
// It calls ok(tag) as needed to find out whether a given build tag
|
||||||
|
// is satisfied by the current build configuration.
|
||||||
|
Eval(ok func(tag string) bool) bool
|
||||||
|
|
||||||
|
// The presence of an isExpr method explicitly marks the type as an Expr.
|
||||||
|
// Only implementations in this package should be used as Exprs.
|
||||||
|
isExpr()
|
||||||
|
}
|
||||||
|
|
||||||
|
// A TagExpr is an Expr for the single tag Tag.
|
||||||
|
type TagExpr struct {
|
||||||
|
Tag string // for example, “linux” or “cgo”
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *TagExpr) isExpr() {}
|
||||||
|
|
||||||
|
func (x *TagExpr) Eval(ok func(tag string) bool) bool {
|
||||||
|
return ok(x.Tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *TagExpr) String() string {
|
||||||
|
return x.Tag
|
||||||
|
}
|
||||||
|
|
||||||
|
func tag(tag string) Expr { return &TagExpr{tag} }
|
||||||
|
|
||||||
|
// A NotExpr represents the expression !X (the negation of X).
|
||||||
|
type NotExpr struct {
|
||||||
|
X Expr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotExpr) isExpr() {}
|
||||||
|
|
||||||
|
func (x *NotExpr) Eval(ok func(tag string) bool) bool {
|
||||||
|
return !x.X.Eval(ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *NotExpr) String() string {
|
||||||
|
s := x.X.String()
|
||||||
|
switch x.X.(type) {
|
||||||
|
case *AndExpr, *OrExpr:
|
||||||
|
s = "(" + s + ")"
|
||||||
|
}
|
||||||
|
return "!" + s
|
||||||
|
}
|
||||||
|
|
||||||
|
func not(x Expr) Expr { return &NotExpr{x} }
|
||||||
|
|
||||||
|
// An AndExpr represents the expression X && Y.
|
||||||
|
type AndExpr struct {
|
||||||
|
X, Y Expr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AndExpr) isExpr() {}
|
||||||
|
|
||||||
|
func (x *AndExpr) Eval(ok func(tag string) bool) bool {
|
||||||
|
// Note: Eval both, to make sure ok func observes all tags.
|
||||||
|
xok := x.X.Eval(ok)
|
||||||
|
yok := x.Y.Eval(ok)
|
||||||
|
return xok && yok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AndExpr) String() string {
|
||||||
|
return andArg(x.X) + " && " + andArg(x.Y)
|
||||||
|
}
|
||||||
|
|
||||||
|
func andArg(x Expr) string {
|
||||||
|
s := x.String()
|
||||||
|
if _, ok := x.(*OrExpr); ok {
|
||||||
|
s = "(" + s + ")"
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func and(x, y Expr) Expr {
|
||||||
|
return &AndExpr{x, y}
|
||||||
|
}
|
||||||
|
|
||||||
|
// An OrExpr represents the expression X || Y.
|
||||||
|
type OrExpr struct {
|
||||||
|
X, Y Expr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *OrExpr) isExpr() {}
|
||||||
|
|
||||||
|
func (x *OrExpr) Eval(ok func(tag string) bool) bool {
|
||||||
|
// Note: Eval both, to make sure ok func observes all tags.
|
||||||
|
xok := x.X.Eval(ok)
|
||||||
|
yok := x.Y.Eval(ok)
|
||||||
|
return xok || yok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *OrExpr) String() string {
|
||||||
|
return orArg(x.X) + " || " + orArg(x.Y)
|
||||||
|
}
|
||||||
|
|
||||||
|
func orArg(x Expr) string {
|
||||||
|
s := x.String()
|
||||||
|
if _, ok := x.(*AndExpr); ok {
|
||||||
|
s = "(" + s + ")"
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func or(x, y Expr) Expr {
|
||||||
|
return &OrExpr{x, y}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A SyntaxError reports a syntax error in a parsed build expression.
|
||||||
|
type SyntaxError struct {
|
||||||
|
Offset int // byte offset in input where error was detected
|
||||||
|
Err string // description of error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *SyntaxError) Error() string {
|
||||||
|
return e.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
var errNotConstraint = errors.New("not a build constraint")
|
||||||
|
|
||||||
|
// Parse parses a single build constraint line of the form “//go:build ...” or “// +build ...”
|
||||||
|
// and returns the corresponding boolean expression.
|
||||||
|
func Parse(line string) (Expr, error) {
|
||||||
|
if text, ok := splitGoBuild(line); ok {
|
||||||
|
return parseExpr(text)
|
||||||
|
}
|
||||||
|
if text, ok := splitPlusBuild(line); ok {
|
||||||
|
return parsePlusBuildExpr(text), nil
|
||||||
|
}
|
||||||
|
return nil, errNotConstraint
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsGoBuild reports whether the line of text is a “//go:build” constraint.
|
||||||
|
// It only checks the prefix of the text, not that the expression itself parses.
|
||||||
|
func IsGoBuild(line string) bool {
|
||||||
|
_, ok := splitGoBuild(line)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// splitGoBuild splits apart the leading //go:build prefix in line from the build expression itself.
|
||||||
|
// It returns "", false if the input is not a //go:build line or if the input contains multiple lines.
|
||||||
|
func splitGoBuild(line string) (expr string, ok bool) {
|
||||||
|
// A single trailing newline is OK; otherwise multiple lines are not.
|
||||||
|
if len(line) > 0 && line[len(line)-1] == '\n' {
|
||||||
|
line = line[:len(line)-1]
|
||||||
|
}
|
||||||
|
if strings.Contains(line, "\n") {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.HasPrefix(line, "//go:build") {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
line = line[len("//go:build"):]
|
||||||
|
|
||||||
|
// If strings.TrimSpace finds more to trim after removing the //go:build prefix,
|
||||||
|
// it means that the prefix was followed by a space, making this a //go:build line
|
||||||
|
// (as opposed to a //go:buildsomethingelse line).
|
||||||
|
// If line is empty, we had "//go:build" by itself, which also counts.
|
||||||
|
trim := strings.TrimSpace(line)
|
||||||
|
if len(line) == len(trim) && line != "" {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
return trim, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// An exprParser holds state for parsing a build expression.
|
||||||
|
type exprParser struct {
|
||||||
|
s string // input string
|
||||||
|
i int // next read location in s
|
||||||
|
|
||||||
|
tok string // last token read
|
||||||
|
isTag bool
|
||||||
|
pos int // position (start) of last token
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseExpr parses a boolean build tag expression.
|
||||||
|
func parseExpr(text string) (x Expr, err error) {
|
||||||
|
defer func() {
|
||||||
|
if e := recover(); e != nil {
|
||||||
|
if e, ok := e.(*SyntaxError); ok {
|
||||||
|
err = e
|
||||||
|
return
|
||||||
|
}
|
||||||
|
panic(e) // unreachable unless parser has a bug
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
p := &exprParser{s: text}
|
||||||
|
x = p.or()
|
||||||
|
if p.tok != "" {
|
||||||
|
panic(&SyntaxError{Offset: p.pos, Err: "unexpected token " + p.tok})
|
||||||
|
}
|
||||||
|
return x, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// or parses a sequence of || expressions.
|
||||||
|
// On entry, the next input token has not yet been lexed.
|
||||||
|
// On exit, the next input token has been lexed and is in p.tok.
|
||||||
|
func (p *exprParser) or() Expr {
|
||||||
|
x := p.and()
|
||||||
|
for p.tok == "||" {
|
||||||
|
x = or(x, p.and())
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// and parses a sequence of && expressions.
|
||||||
|
// On entry, the next input token has not yet been lexed.
|
||||||
|
// On exit, the next input token has been lexed and is in p.tok.
|
||||||
|
func (p *exprParser) and() Expr {
|
||||||
|
x := p.not()
|
||||||
|
for p.tok == "&&" {
|
||||||
|
x = and(x, p.not())
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// not parses a ! expression.
|
||||||
|
// On entry, the next input token has not yet been lexed.
|
||||||
|
// On exit, the next input token has been lexed and is in p.tok.
|
||||||
|
func (p *exprParser) not() Expr {
|
||||||
|
p.lex()
|
||||||
|
if p.tok == "!" {
|
||||||
|
p.lex()
|
||||||
|
if p.tok == "!" {
|
||||||
|
panic(&SyntaxError{Offset: p.pos, Err: "double negation not allowed"})
|
||||||
|
}
|
||||||
|
return not(p.atom())
|
||||||
|
}
|
||||||
|
return p.atom()
|
||||||
|
}
|
||||||
|
|
||||||
|
// atom parses a tag or a parenthesized expression.
|
||||||
|
// On entry, the next input token HAS been lexed.
|
||||||
|
// On exit, the next input token has been lexed and is in p.tok.
|
||||||
|
func (p *exprParser) atom() Expr {
|
||||||
|
// first token already in p.tok
|
||||||
|
if p.tok == "(" {
|
||||||
|
pos := p.pos
|
||||||
|
defer func() {
|
||||||
|
if e := recover(); e != nil {
|
||||||
|
if e, ok := e.(*SyntaxError); ok && e.Err == "unexpected end of expression" {
|
||||||
|
e.Err = "missing close paren"
|
||||||
|
}
|
||||||
|
panic(e)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
x := p.or()
|
||||||
|
if p.tok != ")" {
|
||||||
|
panic(&SyntaxError{Offset: pos, Err: "missing close paren"})
|
||||||
|
}
|
||||||
|
p.lex()
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
if !p.isTag {
|
||||||
|
if p.tok == "" {
|
||||||
|
panic(&SyntaxError{Offset: p.pos, Err: "unexpected end of expression"})
|
||||||
|
}
|
||||||
|
panic(&SyntaxError{Offset: p.pos, Err: "unexpected token " + p.tok})
|
||||||
|
}
|
||||||
|
tok := p.tok
|
||||||
|
p.lex()
|
||||||
|
return tag(tok)
|
||||||
|
}
|
||||||
|
|
||||||
|
// lex finds and consumes the next token in the input stream.
|
||||||
|
// On return, p.tok is set to the token text,
|
||||||
|
// p.isTag reports whether the token was a tag,
|
||||||
|
// and p.pos records the byte offset of the start of the token in the input stream.
|
||||||
|
// If lex reaches the end of the input, p.tok is set to the empty string.
|
||||||
|
// For any other syntax error, lex panics with a SyntaxError.
|
||||||
|
func (p *exprParser) lex() {
|
||||||
|
p.isTag = false
|
||||||
|
for p.i < len(p.s) && (p.s[p.i] == ' ' || p.s[p.i] == '\t') {
|
||||||
|
p.i++
|
||||||
|
}
|
||||||
|
if p.i >= len(p.s) {
|
||||||
|
p.tok = ""
|
||||||
|
p.pos = p.i
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch p.s[p.i] {
|
||||||
|
case '(', ')', '!':
|
||||||
|
p.pos = p.i
|
||||||
|
p.i++
|
||||||
|
p.tok = p.s[p.pos:p.i]
|
||||||
|
return
|
||||||
|
|
||||||
|
case '&', '|':
|
||||||
|
if p.i+1 >= len(p.s) || p.s[p.i+1] != p.s[p.i] {
|
||||||
|
panic(&SyntaxError{Offset: p.i, Err: "invalid syntax at " + string(rune(p.s[p.i]))})
|
||||||
|
}
|
||||||
|
p.pos = p.i
|
||||||
|
p.i += 2
|
||||||
|
p.tok = p.s[p.pos:p.i]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tag := p.s[p.i:]
|
||||||
|
for i, c := range tag {
|
||||||
|
if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' && c != '.' {
|
||||||
|
tag = tag[:i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if tag == "" {
|
||||||
|
c, _ := utf8.DecodeRuneInString(p.s[p.i:])
|
||||||
|
panic(&SyntaxError{Offset: p.i, Err: "invalid syntax at " + string(c)})
|
||||||
|
}
|
||||||
|
|
||||||
|
p.pos = p.i
|
||||||
|
p.i += len(tag)
|
||||||
|
p.tok = p.s[p.pos:p.i]
|
||||||
|
p.isTag = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsPlusBuild reports whether the line of text is a “// +build” constraint.
|
||||||
|
// It only checks the prefix of the text, not that the expression itself parses.
|
||||||
|
func IsPlusBuild(line string) bool {
|
||||||
|
_, ok := splitPlusBuild(line)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// splitGoBuild splits apart the leading //go:build prefix in line from the build expression itself.
|
||||||
|
// It returns "", false if the input is not a //go:build line or if the input contains multiple lines.
|
||||||
|
func splitPlusBuild(line string) (expr string, ok bool) {
|
||||||
|
// A single trailing newline is OK; otherwise multiple lines are not.
|
||||||
|
if len(line) > 0 && line[len(line)-1] == '\n' {
|
||||||
|
line = line[:len(line)-1]
|
||||||
|
}
|
||||||
|
if strings.Contains(line, "\n") {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.HasPrefix(line, "//") {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
line = line[len("//"):]
|
||||||
|
// Note the space is optional; "//+build" is recognized too.
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
|
||||||
|
if !strings.HasPrefix(line, "+build") {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
line = line[len("+build"):]
|
||||||
|
|
||||||
|
// If strings.TrimSpace finds more to trim after removing the +build prefix,
|
||||||
|
// it means that the prefix was followed by a space, making this a +build line
|
||||||
|
// (as opposed to a +buildsomethingelse line).
|
||||||
|
// If line is empty, we had "// +build" by itself, which also counts.
|
||||||
|
trim := strings.TrimSpace(line)
|
||||||
|
if len(line) == len(trim) && line != "" {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
return trim, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// parsePlusBuildExpr parses a legacy build tag expression (as used with “// +build”).
|
||||||
|
func parsePlusBuildExpr(text string) Expr {
|
||||||
|
var x Expr
|
||||||
|
for _, clause := range strings.Fields(text) {
|
||||||
|
var y Expr
|
||||||
|
for _, lit := range strings.Split(clause, ",") {
|
||||||
|
var z Expr
|
||||||
|
var neg bool
|
||||||
|
if strings.HasPrefix(lit, "!!") || lit == "!" {
|
||||||
|
z = tag("ignore")
|
||||||
|
} else {
|
||||||
|
if strings.HasPrefix(lit, "!") {
|
||||||
|
neg = true
|
||||||
|
lit = lit[len("!"):]
|
||||||
|
}
|
||||||
|
if isValidTag(lit) {
|
||||||
|
z = tag(lit)
|
||||||
|
} else {
|
||||||
|
z = tag("ignore")
|
||||||
|
}
|
||||||
|
if neg {
|
||||||
|
z = not(z)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if y == nil {
|
||||||
|
y = z
|
||||||
|
} else {
|
||||||
|
y = and(y, z)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if x == nil {
|
||||||
|
x = y
|
||||||
|
} else {
|
||||||
|
x = or(x, y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// isValidTag reports whether the word is a valid build tag.
|
||||||
|
// Tags must be letters, digits, underscores or dots.
|
||||||
|
// Unlike in Go identifiers, all digits are fine (e.g., "386").
|
||||||
|
func isValidTag(word string) bool {
|
||||||
|
if word == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, c := range word {
|
||||||
|
if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' && c != '.' {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
var errComplex = errors.New("expression too complex for // +build lines")
|
||||||
|
|
||||||
|
// PlusBuildLines returns a sequence of “// +build” lines that evaluate to the build expression x.
|
||||||
|
// If the expression is too complex to convert directly to “// +build” lines, PlusBuildLines returns an error.
|
||||||
|
func PlusBuildLines(x Expr) ([]string, error) {
|
||||||
|
// Push all NOTs to the expression leaves, so that //go:build !(x && y) can be treated as !x || !y.
|
||||||
|
// This rewrite is both efficient and commonly needed, so it's worth doing.
|
||||||
|
// Essentially all other possible rewrites are too expensive and too rarely needed.
|
||||||
|
x = pushNot(x, false)
|
||||||
|
|
||||||
|
// Split into AND of ORs of ANDs of literals (tag or NOT tag).
|
||||||
|
var split [][][]Expr
|
||||||
|
for _, or := range appendSplitAnd(nil, x) {
|
||||||
|
var ands [][]Expr
|
||||||
|
for _, and := range appendSplitOr(nil, or) {
|
||||||
|
var lits []Expr
|
||||||
|
for _, lit := range appendSplitAnd(nil, and) {
|
||||||
|
switch lit.(type) {
|
||||||
|
case *TagExpr, *NotExpr:
|
||||||
|
lits = append(lits, lit)
|
||||||
|
default:
|
||||||
|
return nil, errComplex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ands = append(ands, lits)
|
||||||
|
}
|
||||||
|
split = append(split, ands)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If all the ORs have length 1 (no actual OR'ing going on),
|
||||||
|
// push the top-level ANDs to the bottom level, so that we get
|
||||||
|
// one // +build line instead of many.
|
||||||
|
maxOr := 0
|
||||||
|
for _, or := range split {
|
||||||
|
if maxOr < len(or) {
|
||||||
|
maxOr = len(or)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if maxOr == 1 {
|
||||||
|
var lits []Expr
|
||||||
|
for _, or := range split {
|
||||||
|
lits = append(lits, or[0]...)
|
||||||
|
}
|
||||||
|
split = [][][]Expr{{lits}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare the +build lines.
|
||||||
|
var lines []string
|
||||||
|
for _, or := range split {
|
||||||
|
line := "// +build"
|
||||||
|
for _, and := range or {
|
||||||
|
clause := ""
|
||||||
|
for i, lit := range and {
|
||||||
|
if i > 0 {
|
||||||
|
clause += ","
|
||||||
|
}
|
||||||
|
clause += lit.String()
|
||||||
|
}
|
||||||
|
line += " " + clause
|
||||||
|
}
|
||||||
|
lines = append(lines, line)
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// pushNot applies DeMorgan's law to push negations down the expression,
|
||||||
|
// so that only tags are negated in the result.
|
||||||
|
// (It applies the rewrites !(X && Y) => (!X || !Y) and !(X || Y) => (!X && !Y).)
|
||||||
|
func pushNot(x Expr, not bool) Expr {
|
||||||
|
switch x := x.(type) {
|
||||||
|
default:
|
||||||
|
// unreachable
|
||||||
|
return x
|
||||||
|
case *NotExpr:
|
||||||
|
if _, ok := x.X.(*TagExpr); ok && !not {
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
return pushNot(x.X, !not)
|
||||||
|
case *TagExpr:
|
||||||
|
if not {
|
||||||
|
return &NotExpr{X: x}
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
case *AndExpr:
|
||||||
|
x1 := pushNot(x.X, not)
|
||||||
|
y1 := pushNot(x.Y, not)
|
||||||
|
if not {
|
||||||
|
return or(x1, y1)
|
||||||
|
}
|
||||||
|
if x1 == x.X && y1 == x.Y {
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
return and(x1, y1)
|
||||||
|
case *OrExpr:
|
||||||
|
x1 := pushNot(x.X, not)
|
||||||
|
y1 := pushNot(x.Y, not)
|
||||||
|
if not {
|
||||||
|
return and(x1, y1)
|
||||||
|
}
|
||||||
|
if x1 == x.X && y1 == x.Y {
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
return or(x1, y1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// appendSplitAnd appends x to list while splitting apart any top-level && expressions.
|
||||||
|
// For example, appendSplitAnd({W}, X && Y && Z) = {W, X, Y, Z}.
|
||||||
|
func appendSplitAnd(list []Expr, x Expr) []Expr {
|
||||||
|
if x, ok := x.(*AndExpr); ok {
|
||||||
|
list = appendSplitAnd(list, x.X)
|
||||||
|
list = appendSplitAnd(list, x.Y)
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
return append(list, x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// appendSplitOr appends x to list while splitting apart any top-level || expressions.
|
||||||
|
// For example, appendSplitOr({W}, X || Y || Z) = {W, X, Y, Z}.
|
||||||
|
func appendSplitOr(list []Expr, x Expr) []Expr {
|
||||||
|
if x, ok := x.(*OrExpr); ok {
|
||||||
|
list = appendSplitOr(list, x.X)
|
||||||
|
list = appendSplitOr(list, x.Y)
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
return append(list, x)
|
||||||
|
}
|
|
@ -0,0 +1,317 @@
|
||||||
|
// 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 constraint
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var exprStringTests = []struct {
|
||||||
|
x Expr
|
||||||
|
out string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
x: tag("abc"),
|
||||||
|
out: "abc",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: not(tag("abc")),
|
||||||
|
out: "!abc",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: not(and(tag("abc"), tag("def"))),
|
||||||
|
out: "!(abc && def)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: and(tag("abc"), or(tag("def"), tag("ghi"))),
|
||||||
|
out: "abc && (def || ghi)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: or(and(tag("abc"), tag("def")), tag("ghi")),
|
||||||
|
out: "(abc && def) || ghi",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExprString(t *testing.T) {
|
||||||
|
for i, tt := range exprStringTests {
|
||||||
|
t.Run(fmt.Sprint(i), func(t *testing.T) {
|
||||||
|
s := tt.x.String()
|
||||||
|
if s != tt.out {
|
||||||
|
t.Errorf("String() mismatch:\nhave %s\nwant %s", s, tt.out)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var lexTests = []struct {
|
||||||
|
in string
|
||||||
|
out string
|
||||||
|
}{
|
||||||
|
{"", ""},
|
||||||
|
{"x", "x"},
|
||||||
|
{"x.y", "x.y"},
|
||||||
|
{"x_y", "x_y"},
|
||||||
|
{"αx", "αx"},
|
||||||
|
{"αx²", "αx err: invalid syntax at ²"},
|
||||||
|
{"go1.2", "go1.2"},
|
||||||
|
{"x y", "x y"},
|
||||||
|
{"x!y", "x ! y"},
|
||||||
|
{"&&||!()xy yx ", "&& || ! ( ) xy yx"},
|
||||||
|
{"x~", "x err: invalid syntax at ~"},
|
||||||
|
{"x ~", "x err: invalid syntax at ~"},
|
||||||
|
{"x &", "x err: invalid syntax at &"},
|
||||||
|
{"x &y", "x err: invalid syntax at &"},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLex(t *testing.T) {
|
||||||
|
for i, tt := range lexTests {
|
||||||
|
t.Run(fmt.Sprint(i), func(t *testing.T) {
|
||||||
|
p := &exprParser{s: tt.in}
|
||||||
|
out := ""
|
||||||
|
for {
|
||||||
|
tok, err := lexHelp(p)
|
||||||
|
if tok == "" && err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if out != "" {
|
||||||
|
out += " "
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
out += "err: " + err.Error()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
out += tok
|
||||||
|
}
|
||||||
|
if out != tt.out {
|
||||||
|
t.Errorf("lex(%q):\nhave %s\nwant %s", tt.in, out, tt.out)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func lexHelp(p *exprParser) (tok string, err error) {
|
||||||
|
defer func() {
|
||||||
|
if e := recover(); e != nil {
|
||||||
|
if e, ok := e.(*SyntaxError); ok {
|
||||||
|
err = e
|
||||||
|
return
|
||||||
|
}
|
||||||
|
panic(e)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
p.lex()
|
||||||
|
return p.tok, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var parseExprTests = []struct {
|
||||||
|
in string
|
||||||
|
x Expr
|
||||||
|
}{
|
||||||
|
{"x", tag("x")},
|
||||||
|
{"x&&y", and(tag("x"), tag("y"))},
|
||||||
|
{"x||y", or(tag("x"), tag("y"))},
|
||||||
|
{"(x)", tag("x")},
|
||||||
|
{"x||y&&z", or(tag("x"), and(tag("y"), tag("z")))},
|
||||||
|
{"x&&y||z", or(and(tag("x"), tag("y")), tag("z"))},
|
||||||
|
{"x&&(y||z)", and(tag("x"), or(tag("y"), tag("z")))},
|
||||||
|
{"(x||y)&&z", and(or(tag("x"), tag("y")), tag("z"))},
|
||||||
|
{"!(x&&y)", not(and(tag("x"), tag("y")))},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseExpr(t *testing.T) {
|
||||||
|
for i, tt := range parseExprTests {
|
||||||
|
t.Run(fmt.Sprint(i), func(t *testing.T) {
|
||||||
|
x, err := parseExpr(tt.in)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if x.String() != tt.x.String() {
|
||||||
|
t.Errorf("parseExpr(%q):\nhave %s\nwant %s", tt.in, x, tt.x)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var parseExprErrorTests = []struct {
|
||||||
|
in string
|
||||||
|
err error
|
||||||
|
}{
|
||||||
|
{"x && ", &SyntaxError{Offset: 5, Err: "unexpected end of expression"}},
|
||||||
|
{"x && (", &SyntaxError{Offset: 6, Err: "missing close paren"}},
|
||||||
|
{"x && ||", &SyntaxError{Offset: 5, Err: "unexpected token ||"}},
|
||||||
|
{"x && !", &SyntaxError{Offset: 6, Err: "unexpected end of expression"}},
|
||||||
|
{"x && !!", &SyntaxError{Offset: 6, Err: "double negation not allowed"}},
|
||||||
|
{"x !", &SyntaxError{Offset: 2, Err: "unexpected token !"}},
|
||||||
|
{"x && (y", &SyntaxError{Offset: 5, Err: "missing close paren"}},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseError(t *testing.T) {
|
||||||
|
for i, tt := range parseExprErrorTests {
|
||||||
|
t.Run(fmt.Sprint(i), func(t *testing.T) {
|
||||||
|
x, err := parseExpr(tt.in)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("parseExpr(%q) = %v, want error", tt.in, x)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(err, tt.err) {
|
||||||
|
t.Fatalf("parseExpr(%q): wrong error:\nhave %#v\nwant %#v", tt.in, err, tt.err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var exprEvalTests = []struct {
|
||||||
|
in string
|
||||||
|
ok bool
|
||||||
|
tags string
|
||||||
|
}{
|
||||||
|
{"x", false, "x"},
|
||||||
|
{"x && y", false, "x y"},
|
||||||
|
{"x || y", false, "x y"},
|
||||||
|
{"!x && yes", true, "x yes"},
|
||||||
|
{"yes || y", true, "y yes"},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExprEval(t *testing.T) {
|
||||||
|
for i, tt := range exprEvalTests {
|
||||||
|
t.Run(fmt.Sprint(i), func(t *testing.T) {
|
||||||
|
x, err := parseExpr(tt.in)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
tags := make(map[string]bool)
|
||||||
|
wantTags := make(map[string]bool)
|
||||||
|
for _, tag := range strings.Fields(tt.tags) {
|
||||||
|
wantTags[tag] = true
|
||||||
|
}
|
||||||
|
hasTag := func(tag string) bool {
|
||||||
|
tags[tag] = true
|
||||||
|
return tag == "yes"
|
||||||
|
}
|
||||||
|
ok := x.Eval(hasTag)
|
||||||
|
if ok != tt.ok || !reflect.DeepEqual(tags, wantTags) {
|
||||||
|
t.Errorf("Eval(%#q):\nhave ok=%v, tags=%v\nwant ok=%v, tags=%v",
|
||||||
|
tt.in, ok, tags, tt.ok, wantTags)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var parsePlusBuildExprTests = []struct {
|
||||||
|
in string
|
||||||
|
x Expr
|
||||||
|
}{
|
||||||
|
{"x", tag("x")},
|
||||||
|
{"x,y", and(tag("x"), tag("y"))},
|
||||||
|
{"x y", or(tag("x"), tag("y"))},
|
||||||
|
{"x y,z", or(tag("x"), and(tag("y"), tag("z")))},
|
||||||
|
{"x,y z", or(and(tag("x"), tag("y")), tag("z"))},
|
||||||
|
{"x,!y !z", or(and(tag("x"), not(tag("y"))), not(tag("z")))},
|
||||||
|
{"!! x", or(tag("ignore"), tag("x"))},
|
||||||
|
{"!!x", tag("ignore")},
|
||||||
|
{"!x", not(tag("x"))},
|
||||||
|
{"!", tag("ignore")},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParsePlusBuildExpr(t *testing.T) {
|
||||||
|
for i, tt := range parsePlusBuildExprTests {
|
||||||
|
t.Run(fmt.Sprint(i), func(t *testing.T) {
|
||||||
|
x := parsePlusBuildExpr(tt.in)
|
||||||
|
if x.String() != tt.x.String() {
|
||||||
|
t.Errorf("parsePlusBuildExpr(%q):\nhave %v\nwant %v", tt.in, x, tt.x)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var constraintTests = []struct {
|
||||||
|
in string
|
||||||
|
x Expr
|
||||||
|
err error
|
||||||
|
}{
|
||||||
|
{"//+build x y", or(tag("x"), tag("y")), nil},
|
||||||
|
{"// +build x y \n", or(tag("x"), tag("y")), nil},
|
||||||
|
{"// +build x y \n ", nil, errNotConstraint},
|
||||||
|
{"// +build x y \nmore", nil, errNotConstraint},
|
||||||
|
{" //+build x y", nil, errNotConstraint},
|
||||||
|
|
||||||
|
{"//go:build x && y", and(tag("x"), tag("y")), nil},
|
||||||
|
{"//go:build x && y\n", and(tag("x"), tag("y")), nil},
|
||||||
|
{"//go:build x && y\n ", nil, errNotConstraint},
|
||||||
|
{"//go:build x && y\nmore", nil, errNotConstraint},
|
||||||
|
{" //go:build x && y", nil, errNotConstraint},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParse(t *testing.T) {
|
||||||
|
for i, tt := range constraintTests {
|
||||||
|
t.Run(fmt.Sprint(i), func(t *testing.T) {
|
||||||
|
x, err := Parse(tt.in)
|
||||||
|
if err != nil {
|
||||||
|
if tt.err == nil {
|
||||||
|
t.Errorf("Constraint(%q): unexpected error: %v", tt.in, err)
|
||||||
|
} else if tt.err != err {
|
||||||
|
t.Errorf("Constraint(%q): error %v, want %v", tt.in, err, tt.err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if tt.err != nil {
|
||||||
|
t.Errorf("Constraint(%q) = %v, want error %v", tt.in, x, tt.err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if x.String() != tt.x.String() {
|
||||||
|
t.Errorf("Constraint(%q):\nhave %v\nwant %v", tt.in, x, tt.x)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var plusBuildLinesTests = []struct {
|
||||||
|
in string
|
||||||
|
out []string
|
||||||
|
err error
|
||||||
|
}{
|
||||||
|
{"x", []string{"x"}, nil},
|
||||||
|
{"x && !y", []string{"x,!y"}, nil},
|
||||||
|
{"x || y", []string{"x y"}, nil},
|
||||||
|
{"x && (y || z)", []string{"x", "y z"}, nil},
|
||||||
|
{"!(x && y)", []string{"!x !y"}, nil},
|
||||||
|
{"x || (y && z)", []string{"x y,z"}, nil},
|
||||||
|
{"w && (x || (y && z))", []string{"w", "x y,z"}, nil},
|
||||||
|
{"v || (w && (x || (y && z)))", nil, errComplex},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPlusBuildLines(t *testing.T) {
|
||||||
|
for i, tt := range plusBuildLinesTests {
|
||||||
|
t.Run(fmt.Sprint(i), func(t *testing.T) {
|
||||||
|
x, err := parseExpr(tt.in)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
lines, err := PlusBuildLines(x)
|
||||||
|
if err != nil {
|
||||||
|
if tt.err == nil {
|
||||||
|
t.Errorf("PlusBuildLines(%q): unexpected error: %v", tt.in, err)
|
||||||
|
} else if tt.err != err {
|
||||||
|
t.Errorf("PlusBuildLines(%q): error %v, want %v", tt.in, err, tt.err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if tt.err != nil {
|
||||||
|
t.Errorf("PlusBuildLines(%q) = %v, want error %v", tt.in, lines, tt.err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var want []string
|
||||||
|
for _, line := range tt.out {
|
||||||
|
want = append(want, "// +build "+line)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(lines, want) {
|
||||||
|
t.Errorf("PlusBuildLines(%q):\nhave %q\nwant %q", tt.in, lines, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ package build
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"go/token"
|
||||||
"internal/testenv"
|
"internal/testenv"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
|
@ -162,6 +163,9 @@ var depsRules = `
|
||||||
< os
|
< os
|
||||||
< os/signal;
|
< os/signal;
|
||||||
|
|
||||||
|
io/fs
|
||||||
|
< embed;
|
||||||
|
|
||||||
unicode, fmt !< os, os/signal;
|
unicode, fmt !< os, os/signal;
|
||||||
|
|
||||||
os/signal, STR
|
os/signal, STR
|
||||||
|
@ -174,7 +178,7 @@ var depsRules = `
|
||||||
reflect !< OS;
|
reflect !< OS;
|
||||||
|
|
||||||
OS
|
OS
|
||||||
< golang.org/x/sys/cpu, internal/goroot;
|
< golang.org/x/sys/cpu;
|
||||||
|
|
||||||
# FMT is OS (which includes string routines) plus reflect and fmt.
|
# FMT is OS (which includes string routines) plus reflect and fmt.
|
||||||
# It does not include package log, which should be avoided in core packages.
|
# It does not include package log, which should be avoided in core packages.
|
||||||
|
@ -190,6 +194,12 @@ var depsRules = `
|
||||||
|
|
||||||
log !< FMT;
|
log !< FMT;
|
||||||
|
|
||||||
|
OS, FMT
|
||||||
|
< internal/execabs;
|
||||||
|
|
||||||
|
OS, internal/execabs
|
||||||
|
< internal/goroot;
|
||||||
|
|
||||||
# Misc packages needing only FMT.
|
# Misc packages needing only FMT.
|
||||||
FMT
|
FMT
|
||||||
< flag,
|
< flag,
|
||||||
|
@ -278,6 +288,9 @@ var depsRules = `
|
||||||
container/heap, go/constant, go/parser
|
container/heap, go/constant, go/parser
|
||||||
< go/types;
|
< go/types;
|
||||||
|
|
||||||
|
FMT
|
||||||
|
< go/build/constraint;
|
||||||
|
|
||||||
go/doc, go/parser, internal/goroot, internal/goversion
|
go/doc, go/parser, internal/goroot, internal/goversion
|
||||||
< go/build;
|
< go/build;
|
||||||
|
|
||||||
|
@ -602,6 +615,7 @@ func findImports(pkg string) ([]string, error) {
|
||||||
}
|
}
|
||||||
var imports []string
|
var imports []string
|
||||||
var haveImport = map[string]bool{}
|
var haveImport = map[string]bool{}
|
||||||
|
fset := token.NewFileSet()
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
name := file.Name()
|
name := file.Name()
|
||||||
if name == "slice_go14.go" || name == "slice_go18.go" {
|
if name == "slice_go14.go" || name == "slice_go18.go" {
|
||||||
|
@ -611,8 +625,10 @@ func findImports(pkg string) ([]string, error) {
|
||||||
if !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") {
|
if !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var info fileInfo
|
info := fileInfo{
|
||||||
info.name = filepath.Join(dir, name)
|
name: filepath.Join(dir, name),
|
||||||
|
fset: fset,
|
||||||
|
}
|
||||||
f, err := os.Open(info.name)
|
f, err := os.Open(info.name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -840,3 +856,28 @@ func TestStdlibLowercase(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestFindImports tests that findImports works. See #43249.
|
||||||
|
func TestFindImports(t *testing.T) {
|
||||||
|
if !testenv.HasSrc() {
|
||||||
|
// Tests run in a limited file system and we do not
|
||||||
|
// provide access to every source file.
|
||||||
|
t.Skipf("skipping on %s/%s, missing full GOROOT", runtime.GOOS, runtime.GOARCH)
|
||||||
|
}
|
||||||
|
|
||||||
|
imports, err := findImports("go/build")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Logf("go/build imports %q", imports)
|
||||||
|
want := []string{"bytes", "os", "path/filepath", "strings"}
|
||||||
|
wantLoop:
|
||||||
|
for _, w := range want {
|
||||||
|
for _, imp := range imports {
|
||||||
|
if imp == w {
|
||||||
|
continue wantLoop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.Errorf("expected to find %q in import list", w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/parser"
|
"go/parser"
|
||||||
|
"go/token"
|
||||||
"io"
|
"io"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -24,6 +25,18 @@ type importReader struct {
|
||||||
err error
|
err error
|
||||||
eof bool
|
eof bool
|
||||||
nerr int
|
nerr int
|
||||||
|
pos token.Position
|
||||||
|
}
|
||||||
|
|
||||||
|
func newImportReader(name string, r io.Reader) *importReader {
|
||||||
|
return &importReader{
|
||||||
|
b: bufio.NewReader(r),
|
||||||
|
pos: token.Position{
|
||||||
|
Filename: name,
|
||||||
|
Line: 1,
|
||||||
|
Column: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func isIdent(c byte) bool {
|
func isIdent(c byte) bool {
|
||||||
|
@ -66,22 +79,32 @@ func (r *importReader) readByte() byte {
|
||||||
// readByteNoBuf is like readByte but doesn't buffer the byte.
|
// readByteNoBuf is like readByte but doesn't buffer the byte.
|
||||||
// It exhausts r.buf before reading from r.b.
|
// It exhausts r.buf before reading from r.b.
|
||||||
func (r *importReader) readByteNoBuf() byte {
|
func (r *importReader) readByteNoBuf() byte {
|
||||||
|
var c byte
|
||||||
|
var err error
|
||||||
if len(r.buf) > 0 {
|
if len(r.buf) > 0 {
|
||||||
c := r.buf[0]
|
c = r.buf[0]
|
||||||
r.buf = r.buf[1:]
|
r.buf = r.buf[1:]
|
||||||
return c
|
} else {
|
||||||
}
|
c, err = r.b.ReadByte()
|
||||||
c, err := r.b.ReadByte()
|
if err == nil && c == 0 {
|
||||||
if err == nil && c == 0 {
|
err = errNUL
|
||||||
err = errNUL
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
r.eof = true
|
r.eof = true
|
||||||
} else if r.err == nil {
|
} else if r.err == nil {
|
||||||
r.err = err
|
r.err = err
|
||||||
}
|
}
|
||||||
c = 0
|
return 0
|
||||||
|
}
|
||||||
|
r.pos.Offset++
|
||||||
|
if c == '\n' {
|
||||||
|
r.pos.Line++
|
||||||
|
r.pos.Column = 1
|
||||||
|
} else {
|
||||||
|
r.pos.Column++
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
@ -171,6 +194,41 @@ func (r *importReader) findEmbed(first bool) bool {
|
||||||
case ' ', '\t':
|
case ' ', '\t':
|
||||||
// leave startLine alone
|
// leave startLine alone
|
||||||
|
|
||||||
|
case '"':
|
||||||
|
startLine = false
|
||||||
|
for r.err == nil {
|
||||||
|
if r.eof {
|
||||||
|
r.syntaxError()
|
||||||
|
}
|
||||||
|
c = r.readByteNoBuf()
|
||||||
|
if c == '\\' {
|
||||||
|
r.readByteNoBuf()
|
||||||
|
if r.err != nil {
|
||||||
|
r.syntaxError()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if c == '"' {
|
||||||
|
c = r.readByteNoBuf()
|
||||||
|
goto Reswitch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
goto Reswitch
|
||||||
|
|
||||||
|
case '`':
|
||||||
|
startLine = false
|
||||||
|
for r.err == nil {
|
||||||
|
if r.eof {
|
||||||
|
r.syntaxError()
|
||||||
|
}
|
||||||
|
c = r.readByteNoBuf()
|
||||||
|
if c == '`' {
|
||||||
|
c = r.readByteNoBuf()
|
||||||
|
goto Reswitch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case '/':
|
case '/':
|
||||||
c = r.readByteNoBuf()
|
c = r.readByteNoBuf()
|
||||||
switch c {
|
switch c {
|
||||||
|
@ -288,7 +346,7 @@ func (r *importReader) readImport() {
|
||||||
// readComments is like io.ReadAll, except that it only reads the leading
|
// readComments is like io.ReadAll, except that it only reads the leading
|
||||||
// block of comments in the file.
|
// block of comments in the file.
|
||||||
func readComments(f io.Reader) ([]byte, error) {
|
func readComments(f io.Reader) ([]byte, error) {
|
||||||
r := &importReader{b: bufio.NewReader(f)}
|
r := newImportReader("", f)
|
||||||
r.peekByte(true)
|
r.peekByte(true)
|
||||||
if r.err == nil && !r.eof {
|
if r.err == nil && !r.eof {
|
||||||
// Didn't reach EOF, so must have found a non-space byte. Remove it.
|
// Didn't reach EOF, so must have found a non-space byte. Remove it.
|
||||||
|
@ -305,7 +363,7 @@ func readComments(f io.Reader) ([]byte, error) {
|
||||||
// It only returns an error if there are problems reading the file,
|
// It only returns an error if there are problems reading the file,
|
||||||
// not for syntax errors in the file itself.
|
// not for syntax errors in the file itself.
|
||||||
func readGoInfo(f io.Reader, info *fileInfo) error {
|
func readGoInfo(f io.Reader, info *fileInfo) error {
|
||||||
r := &importReader{b: bufio.NewReader(f)}
|
r := newImportReader(info.name, f)
|
||||||
|
|
||||||
r.readKeyword("package")
|
r.readKeyword("package")
|
||||||
r.readIdent()
|
r.readIdent()
|
||||||
|
@ -393,6 +451,7 @@ func readGoInfo(f io.Reader, info *fileInfo) error {
|
||||||
var line []byte
|
var line []byte
|
||||||
for first := true; r.findEmbed(first); first = false {
|
for first := true; r.findEmbed(first); first = false {
|
||||||
line = line[:0]
|
line = line[:0]
|
||||||
|
pos := r.pos
|
||||||
for {
|
for {
|
||||||
c := r.readByteNoBuf()
|
c := r.readByteNoBuf()
|
||||||
if c == '\n' || r.err != nil || r.eof {
|
if c == '\n' || r.err != nil || r.eof {
|
||||||
|
@ -403,9 +462,9 @@ func readGoInfo(f io.Reader, info *fileInfo) error {
|
||||||
// Add args if line is well-formed.
|
// Add args if line is well-formed.
|
||||||
// Ignore badly-formed lines - the compiler will report them when it finds them,
|
// Ignore badly-formed lines - the compiler will report them when it finds them,
|
||||||
// and we can pretend they are not there to help go list succeed with what it knows.
|
// and we can pretend they are not there to help go list succeed with what it knows.
|
||||||
args, err := parseGoEmbed(string(line))
|
embs, err := parseGoEmbed(string(line), pos)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
info.embeds = append(info.embeds, args...)
|
info.embeds = append(info.embeds, embs...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -415,11 +474,23 @@ func readGoInfo(f io.Reader, info *fileInfo) error {
|
||||||
|
|
||||||
// parseGoEmbed parses the text following "//go:embed" to extract the glob patterns.
|
// parseGoEmbed parses the text following "//go:embed" to extract the glob patterns.
|
||||||
// It accepts unquoted space-separated patterns as well as double-quoted and back-quoted Go strings.
|
// It accepts unquoted space-separated patterns as well as double-quoted and back-quoted Go strings.
|
||||||
// There is a copy of this code in cmd/compile/internal/gc/noder.go as well.
|
// This is based on a similar function in cmd/compile/internal/gc/noder.go;
|
||||||
func parseGoEmbed(args string) ([]string, error) {
|
// this version calculates position information as well.
|
||||||
var list []string
|
func parseGoEmbed(args string, pos token.Position) ([]fileEmbed, error) {
|
||||||
for args = strings.TrimSpace(args); args != ""; args = strings.TrimSpace(args) {
|
trimBytes := func(n int) {
|
||||||
|
pos.Offset += n
|
||||||
|
pos.Column += utf8.RuneCountInString(args[:n])
|
||||||
|
args = args[n:]
|
||||||
|
}
|
||||||
|
trimSpace := func() {
|
||||||
|
trim := strings.TrimLeftFunc(args, unicode.IsSpace)
|
||||||
|
trimBytes(len(args) - len(trim))
|
||||||
|
}
|
||||||
|
|
||||||
|
var list []fileEmbed
|
||||||
|
for trimSpace(); args != ""; trimSpace() {
|
||||||
var path string
|
var path string
|
||||||
|
pathPos := pos
|
||||||
Switch:
|
Switch:
|
||||||
switch args[0] {
|
switch args[0] {
|
||||||
default:
|
default:
|
||||||
|
@ -431,7 +502,7 @@ func parseGoEmbed(args string) ([]string, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
path = args[:i]
|
path = args[:i]
|
||||||
args = args[i:]
|
trimBytes(i)
|
||||||
|
|
||||||
case '`':
|
case '`':
|
||||||
i := strings.Index(args[1:], "`")
|
i := strings.Index(args[1:], "`")
|
||||||
|
@ -439,7 +510,7 @@ func parseGoEmbed(args string) ([]string, error) {
|
||||||
return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args)
|
return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args)
|
||||||
}
|
}
|
||||||
path = args[1 : 1+i]
|
path = args[1 : 1+i]
|
||||||
args = args[1+i+1:]
|
trimBytes(1 + i + 1)
|
||||||
|
|
||||||
case '"':
|
case '"':
|
||||||
i := 1
|
i := 1
|
||||||
|
@ -454,7 +525,7 @@ func parseGoEmbed(args string) ([]string, error) {
|
||||||
return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args[:i+1])
|
return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args[:i+1])
|
||||||
}
|
}
|
||||||
path = q
|
path = q
|
||||||
args = args[i+1:]
|
trimBytes(i + 1)
|
||||||
break Switch
|
break Switch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -469,7 +540,7 @@ func parseGoEmbed(args string) ([]string, error) {
|
||||||
return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args)
|
return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
list = append(list, path)
|
list = append(list, fileEmbed{path, pathPos})
|
||||||
}
|
}
|
||||||
return list, nil
|
return list, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,9 @@
|
||||||
package build
|
package build
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"go/token"
|
"go/token"
|
||||||
"io"
|
"io"
|
||||||
"reflect"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
@ -228,55 +228,94 @@ func TestReadFailuresIgnored(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var readEmbedTests = []struct {
|
var readEmbedTests = []struct {
|
||||||
in string
|
in, out string
|
||||||
out []string
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"package p\n",
|
"package p\n",
|
||||||
nil,
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"package p\nimport \"embed\"\nvar i int\n//go:embed x y z\nvar files embed.FS",
|
"package p\nimport \"embed\"\nvar i int\n//go:embed x y z\nvar files embed.FS",
|
||||||
[]string{"x", "y", "z"},
|
`test:4:12:x
|
||||||
|
test:4:14:y
|
||||||
|
test:4:16:z`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"package p\nimport \"embed\"\nvar i int\n//go:embed x \"\\x79\" `z`\nvar files embed.FS",
|
"package p\nimport \"embed\"\nvar i int\n//go:embed x \"\\x79\" `z`\nvar files embed.FS",
|
||||||
[]string{"x", "y", "z"},
|
`test:4:12:x
|
||||||
|
test:4:14:y
|
||||||
|
test:4:21:z`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"package p\nimport \"embed\"\nvar i int\n//go:embed x y\n//go:embed z\nvar files embed.FS",
|
"package p\nimport \"embed\"\nvar i int\n//go:embed x y\n//go:embed z\nvar files embed.FS",
|
||||||
[]string{"x", "y", "z"},
|
`test:4:12:x
|
||||||
|
test:4:14:y
|
||||||
|
test:5:12:z`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"package p\nimport \"embed\"\nvar i int\n\t //go:embed x y\n\t //go:embed z\n\t var files embed.FS",
|
"package p\nimport \"embed\"\nvar i int\n\t //go:embed x y\n\t //go:embed z\n\t var files embed.FS",
|
||||||
[]string{"x", "y", "z"},
|
`test:4:14:x
|
||||||
|
test:4:16:y
|
||||||
|
test:5:14:z`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"package p\nimport \"embed\"\n//go:embed x y z\nvar files embed.FS",
|
"package p\nimport \"embed\"\n//go:embed x y z\nvar files embed.FS",
|
||||||
[]string{"x", "y", "z"},
|
`test:3:12:x
|
||||||
|
test:3:14:y
|
||||||
|
test:3:16:z`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"package p\nimport \"embed\"\nvar s = \"/*\"\n//go:embed x\nvar files embed.FS",
|
||||||
|
`test:4:12:x`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`package p
|
||||||
|
import "embed"
|
||||||
|
var s = "\"\\\\"
|
||||||
|
//go:embed x
|
||||||
|
var files embed.FS`,
|
||||||
|
`test:4:15:x`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"package p\nimport \"embed\"\nvar s = `/*`\n//go:embed x\nvar files embed.FS",
|
||||||
|
`test:4:12:x`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"package p\nimport \"embed\"\nvar s = z/ *y\n//go:embed pointer\nvar pointer embed.FS",
|
||||||
|
"test:4:12:pointer",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"package p\n//go:embed x y z\n", // no import, no scan
|
"package p\n//go:embed x y z\n", // no import, no scan
|
||||||
nil,
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"package p\n//go:embed x y z\nvar files embed.FS", // no import, no scan
|
"package p\n//go:embed x y z\nvar files embed.FS", // no import, no scan
|
||||||
nil,
|
"",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReadEmbed(t *testing.T) {
|
func TestReadEmbed(t *testing.T) {
|
||||||
fset := token.NewFileSet()
|
fset := token.NewFileSet()
|
||||||
for i, tt := range readEmbedTests {
|
for i, tt := range readEmbedTests {
|
||||||
var info fileInfo
|
info := fileInfo{
|
||||||
info.fset = fset
|
name: "test",
|
||||||
|
fset: fset,
|
||||||
|
}
|
||||||
err := readGoInfo(strings.NewReader(tt.in), &info)
|
err := readGoInfo(strings.NewReader(tt.in), &info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("#%d: %v", i, err)
|
t.Errorf("#%d: %v", i, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(info.embeds, tt.out) {
|
b := &strings.Builder{}
|
||||||
t.Errorf("#%d: embeds=%v, want %v", i, info.embeds, tt.out)
|
sep := ""
|
||||||
|
for _, emb := range info.embeds {
|
||||||
|
fmt.Fprintf(b, "%s%v:%s", sep, emb.pos, emb.pattern)
|
||||||
|
sep = "\n"
|
||||||
|
}
|
||||||
|
got := b.String()
|
||||||
|
want := strings.Join(strings.Fields(tt.out), "\n")
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("#%d: embeds:\n%s\nwant:\n%s", i, got, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,8 @@ package gccgoimporter
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"go/types"
|
"go/types"
|
||||||
|
exec "internal/execabs"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
|
@ -13,9 +13,9 @@ import (
|
||||||
"go/parser"
|
"go/parser"
|
||||||
"go/token"
|
"go/token"
|
||||||
"go/types"
|
"go/types"
|
||||||
|
exec "internal/execabs"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue