mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-11-23 19:03:59 +08:00
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
|
||||
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
|
||||
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
|
||||
zstdpkglist.go: s-zstdpkglist; @true
|
||||
s-zstdpkglist: Makefile
|
||||
s-zstdpkglist: Makefile libgo-packages.txt
|
||||
rm -f zstdpkglist.go.tmp
|
||||
echo 'package goroot' > 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
|
||||
zstdpkglist.go: s-zstdpkglist; @true
|
||||
s-zstdpkglist: Makefile
|
||||
s-zstdpkglist: Makefile libgo-packages.txt
|
||||
rm -f zstdpkglist.go.tmp
|
||||
echo 'package goroot' > zstdpkglist.go.tmp
|
||||
echo "" >> zstdpkglist.go.tmp
|
||||
|
@ -1 +1 @@
|
||||
go1.16beta1
|
||||
go1.16rc1
|
||||
|
@ -80,6 +80,7 @@ flag
|
||||
fmt
|
||||
go/ast
|
||||
go/build
|
||||
go/build/constraint
|
||||
go/constant
|
||||
go/doc
|
||||
go/format
|
||||
@ -107,6 +108,7 @@ image/jpeg
|
||||
image/png
|
||||
index/suffixarray
|
||||
internal/cpu
|
||||
internal/execabs
|
||||
internal/fmtsort
|
||||
internal/poll
|
||||
internal/profile
|
||||
|
@ -28,7 +28,7 @@ func isASCII(s string) bool {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
if isASCII(s) {
|
||||
return s
|
||||
|
@ -1567,7 +1567,14 @@ func (p *Package) gccBaseCmd() []string {
|
||||
func (p *Package) gccMachine() []string {
|
||||
switch goarch {
|
||||
case "amd64":
|
||||
if goos == "darwin" {
|
||||
return []string{"-arch", "x86_64", "-m64"}
|
||||
}
|
||||
return []string{"-m64"}
|
||||
case "arm64":
|
||||
if goos == "darwin" {
|
||||
return []string{"-arch", "arm64"}
|
||||
}
|
||||
case "386":
|
||||
return []string{"-m32"}
|
||||
case "arm":
|
||||
|
@ -14,10 +14,10 @@ import (
|
||||
"go/ast"
|
||||
"go/printer"
|
||||
"go/token"
|
||||
exec "internal/execabs"
|
||||
"internal/xcoff"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
@ -958,9 +958,9 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||
// Build the wrapper function compiled by gcc.
|
||||
gccExport := ""
|
||||
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 {
|
||||
s += p.cgoType(fn.Recv.List[0].Type).C.String()
|
||||
s += " recv"
|
||||
|
@ -8,9 +8,9 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/token"
|
||||
exec "internal/execabs"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
// 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")
|
||||
err := p.Run()
|
||||
if _, ok := err.(*exec.ExitError); err != nil && !ok {
|
||||
fatalf("%s", err)
|
||||
fatalf("exec %s: %s", argv[0], err)
|
||||
}
|
||||
ok = p.ProcessState.Success()
|
||||
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
|
||||
// caused the fatal condition. Assume they're enough.
|
||||
if nerrors == 0 {
|
||||
fmt.Fprintf(os.Stderr, msg+"\n", args...)
|
||||
fmt.Fprintf(os.Stderr, "cgo: "+msg+"\n", args...)
|
||||
}
|
||||
os.Exit(2)
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ require (
|
||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2
|
||||
golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff
|
||||
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/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.
|
||||
os.Setenv("GOENV", "off")
|
||||
os.Unsetenv("GOFLAGS")
|
||||
os.Unsetenv("GOBIN")
|
||||
os.Unsetenv("GOPATH")
|
||||
os.Unsetenv("GIT_ALLOW_PROTOCOL")
|
||||
@ -2655,12 +2656,12 @@ func TestBadCommandLines(t *testing.T) {
|
||||
tg.tempFile("src/@x/x.go", "package x\n")
|
||||
tg.setenv("GOPATH", tg.path("."))
|
||||
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.setenv("GOPATH", tg.path("."))
|
||||
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.setenv("GOPATH", tg.path("."))
|
||||
|
@ -10,9 +10,9 @@ import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
exec "internal/execabs"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
|
@ -9,10 +9,10 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
exec "internal/execabs"
|
||||
"io"
|
||||
urlpkg "net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
|
@ -75,7 +75,8 @@ func runFmt(ctx context.Context, cmd *base.Command, args []string) {
|
||||
}
|
||||
if pkg.Error != nil {
|
||||
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
|
||||
// all files regardless.
|
||||
} else {
|
||||
|
@ -12,10 +12,10 @@ import (
|
||||
"fmt"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
exec "internal/execabs"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"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
|
||||
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
|
||||
like directives in comments or multiline strings will be treated
|
||||
as directives.
|
||||
@ -72,6 +63,15 @@ arguments when it is run.
|
||||
Quoted strings use Go syntax and are evaluated before execution; a
|
||||
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:
|
||||
|
||||
$GOARCH
|
||||
|
@ -202,7 +202,7 @@ func runGet(ctx context.Context, cmd *base.Command, args []string) {
|
||||
func downloadPaths(patterns []string) []string {
|
||||
for _, arg := range patterns {
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -266,7 +266,7 @@ listed in the GOPATH environment variable.
|
||||
(See 'go help gopath-get' and 'go help gopath'.)
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
|
||||
@ -483,6 +484,10 @@ See 'go help env' for details.
|
||||
|
||||
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
|
||||
The gccgo command to run for 'go build -compiler=gccgo'.
|
||||
GOARCH
|
||||
@ -521,20 +526,24 @@ General-purpose environment variables:
|
||||
GOPATH
|
||||
For more details see: 'go help gopath'.
|
||||
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
|
||||
Comma-separated list of glob patterns (in the syntax of Go's path.Match)
|
||||
of module path prefixes that should always be fetched directly
|
||||
or that should not be compared against the checksum database.
|
||||
See 'go help private'.
|
||||
See https://golang.org/ref/mod#private-modules.
|
||||
GOROOT
|
||||
The root of the go tree.
|
||||
GOSUMDB
|
||||
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
|
||||
The directory where the go command will write
|
||||
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:
|
||||
|
||||
|
@ -89,6 +89,14 @@ to -f '{{.ImportPath}}'. The struct being passed to the template is:
|
||||
TestGoFiles []string // _test.go files in 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
|
||||
CgoCFLAGS []string // cgo: flags for C compiler
|
||||
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 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
|
||||
p.TestImports = p.Resolve(p.TestImports)
|
||||
p.XTestImports = p.Resolve(p.XTestImports)
|
||||
p.TestEmbedFiles = p.ResolveEmbed(p.TestEmbedPatterns)
|
||||
p.XTestEmbedFiles = p.ResolveEmbed(p.XTestEmbedPatterns)
|
||||
p.DepOnly = !cmdline[p]
|
||||
|
||||
if *listCompiled {
|
||||
|
@ -96,7 +96,7 @@ type PackagePublic struct {
|
||||
|
||||
// Embedded files
|
||||
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
|
||||
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
|
||||
TestImports []string `json:",omitempty"` // imports from TestGoFiles
|
||||
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
|
||||
XTestImports []string `json:",omitempty"` // imports from XTestGoFiles
|
||||
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.
|
||||
@ -304,7 +304,7 @@ func (p *Package) setLoadPackageDataError(err error, path string, stk *ImportSta
|
||||
}
|
||||
|
||||
if path != stk.Top() {
|
||||
p = setErrorPos(p, importPos)
|
||||
p.Error.setPos(importPos)
|
||||
}
|
||||
}
|
||||
|
||||
@ -412,6 +412,9 @@ type PackageError struct {
|
||||
}
|
||||
|
||||
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) {
|
||||
// Omit import stack. The full path to the file where the error
|
||||
// is the most important thing.
|
||||
@ -447,6 +450,15 @@ func (p *PackageError) MarshalJSON() ([]byte, error) {
|
||||
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
|
||||
// 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
|
||||
@ -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)),
|
||||
}
|
||||
p.Incomplete = true
|
||||
setErrorPos(p, importPos)
|
||||
p.Error.setPos(importPos)
|
||||
}
|
||||
}
|
||||
|
||||
// Checked on every import because the rules depend on the code doing the importing.
|
||||
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 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(),
|
||||
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 {
|
||||
@ -730,21 +745,13 @@ func loadImport(ctx context.Context, pre *preload, path, srcDir string, parent *
|
||||
ImportStack: stk.Copy(),
|
||||
Err: err,
|
||||
}
|
||||
return setErrorPos(&perr, importPos)
|
||||
perr.Error.setPos(importPos)
|
||||
return &perr
|
||||
}
|
||||
|
||||
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
|
||||
// is cached, and later calls to loadPackageData for the same package will return
|
||||
// the same data.
|
||||
@ -769,11 +776,7 @@ func loadPackageData(path, parentPath, parentDir, parentRoot string, parentIsStd
|
||||
}
|
||||
|
||||
if strings.Contains(path, "@") {
|
||||
if cfg.ModulesEnabled {
|
||||
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")
|
||||
}
|
||||
return nil, false, errors.New("can only use path@version syntax with 'go get' and 'go install' in module-aware mode")
|
||||
}
|
||||
|
||||
// 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,
|
||||
// or on the importer side (indicated by a non-empty importPos).
|
||||
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.EmbedFiles, p.Internal.Embed, err = p.resolveEmbed(p.EmbedPatterns)
|
||||
if err != nil {
|
||||
setError(err)
|
||||
}
|
||||
|
||||
useBindir := p.Name == "main"
|
||||
if !p.Standard {
|
||||
switch cfg.BuildBuildmode {
|
||||
@ -1809,9 +1807,20 @@ func (p *Package) load(ctx context.Context, path string, stk *ImportStack, impor
|
||||
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)
|
||||
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.
|
||||
// To avoid problems on case-insensitive files, we reject any package
|
||||
// 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.
|
||||
// For use by go list to compute p.TestEmbedFiles and p.XTestEmbedFiles.
|
||||
func (p *Package) ResolveEmbed(patterns []string) []string {
|
||||
files, _, _ := p.resolveEmbed(patterns)
|
||||
return files
|
||||
// For use by go mod vendor to find embedded files it should copy into the
|
||||
// vendor directory.
|
||||
// TODO(#42504): Once go mod vendor uses load.PackagesAndErrors, just
|
||||
// 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.
|
||||
// It sets files to the list of unique files matched (for go list),
|
||||
// and it sets pmap to the more precise mapping from
|
||||
// patterns to files.
|
||||
// TODO(rsc): All these messages need position information for better error reports.
|
||||
func (p *Package) resolveEmbed(patterns []string) (files []string, pmap map[string][]string, err error) {
|
||||
func resolveEmbed(pkgdir string, 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)
|
||||
have := make(map[string]int)
|
||||
dirOK := make(map[string]bool)
|
||||
pid := 0 // pattern ID, to allow reuse of have map
|
||||
for _, pattern := range patterns {
|
||||
for _, pattern = range patterns {
|
||||
pid++
|
||||
|
||||
// Check pattern is valid for //go:embed.
|
||||
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.
|
||||
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 {
|
||||
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
|
||||
@ -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.)
|
||||
var list []string
|
||||
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"
|
||||
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
|
||||
// (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 {
|
||||
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 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
|
||||
if elem := filepath.Base(dir); isBadEmbedName(elem) {
|
||||
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 {
|
||||
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 {
|
||||
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():
|
||||
if have[rel] != pid {
|
||||
@ -2002,7 +2038,7 @@ func (p *Package) resolveEmbed(patterns []string) (files []string, pmap map[stri
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rel := filepath.ToSlash(path[len(p.Dir)+1:])
|
||||
rel := filepath.ToSlash(path[len(pkgdir)+1:])
|
||||
name := info.Name()
|
||||
if path != file && (isBadEmbedName(name) || name[0] == '.' || name[0] == '_') {
|
||||
// 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
|
||||
}
|
||||
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 {
|
||||
return nil, nil, fmt.Errorf("pattern %s: no matching files found", pattern)
|
||||
return nil, nil, fmt.Errorf("no matching files found")
|
||||
}
|
||||
sort.Strings(list)
|
||||
pmap[pattern] = list
|
||||
|
@ -124,12 +124,14 @@ func TestPackagesAndErrors(ctx context.Context, p *Package, cover *TestCover) (p
|
||||
imports = append(imports, p1)
|
||||
}
|
||||
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 {
|
||||
ptestErr = &PackageError{
|
||||
ImportStack: stk.Copy(),
|
||||
Err: err,
|
||||
}
|
||||
embedErr := err.(*EmbedError)
|
||||
ptestErr.setPos(p.Internal.Build.TestEmbedPatternPos[embedErr.Pattern])
|
||||
}
|
||||
stk.Pop()
|
||||
|
||||
@ -145,12 +147,14 @@ func TestPackagesAndErrors(ctx context.Context, p *Package, cover *TestCover) (p
|
||||
}
|
||||
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 {
|
||||
pxtestErr = &PackageError{
|
||||
ImportStack: stk.Copy(),
|
||||
Err: err,
|
||||
}
|
||||
embedErr := err.(*EmbedError)
|
||||
pxtestErr.setPos(p.Internal.Build.XTestEmbedPatternPos[embedErr.Pattern])
|
||||
}
|
||||
stk.Pop()
|
||||
|
||||
|
@ -52,7 +52,9 @@ corresponding to this Go struct:
|
||||
|
||||
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
|
||||
Exclude []Module
|
||||
Replace []Replace
|
||||
Retract []Retract
|
||||
}
|
||||
|
||||
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,
|
||||
use 'go list -m -json all'.
|
||||
|
||||
For example, a tool can obtain the go.mod as a data structure by
|
||||
parsing the output of 'go mod edit -json' and can then make changes
|
||||
by invoking 'go mod edit' with -require, -exclude, and so on.
|
||||
See https://golang.org/ref/mod#go-mod-edit for more about 'go mod edit'.
|
||||
`,
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
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.
|
||||
|
||||
See https://golang.org/ref/mod#go-mod-graph for more about 'go mod graph'.
|
||||
`,
|
||||
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
|
||||
import module requirements from it.
|
||||
|
||||
See https://golang.org/ref/mod#go-mod-init for more about 'go mod init'.
|
||||
`,
|
||||
Run: runInit,
|
||||
}
|
||||
|
@ -29,6 +29,8 @@ to standard error.
|
||||
|
||||
The -e flag causes tidy to attempt to proceed despite errors
|
||||
encountered while loading packages.
|
||||
|
||||
See https://golang.org/ref/mod#go-mod-tidy for more about 'go mod tidy'.
|
||||
`,
|
||||
Run: runTidy,
|
||||
}
|
||||
|
@ -7,7 +7,9 @@ package modcmd
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
@ -19,7 +21,9 @@ import (
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/fsys"
|
||||
"cmd/go/internal/imports"
|
||||
"cmd/go/internal/load"
|
||||
"cmd/go/internal/modload"
|
||||
"cmd/go/internal/str"
|
||||
|
||||
"golang.org/x/mod/module"
|
||||
"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
|
||||
encountered while loading packages.
|
||||
|
||||
See https://golang.org/ref/mod#go-mod-vendor for more about 'go mod vendor'.
|
||||
`,
|
||||
Run: runVendor,
|
||||
}
|
||||
@ -180,19 +186,76 @@ func moduleLine(m, r module.Version) 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)
|
||||
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)
|
||||
}
|
||||
|
||||
copiedFiles := make(map[string]bool)
|
||||
dst := filepath.Join(vdir, pkg)
|
||||
src := modload.PackageDir(realPath)
|
||||
if src == "" {
|
||||
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 != "" {
|
||||
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,
|
||||
// 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++ {
|
||||
if copiedMetadata[metakey{modPath, dst}] {
|
||||
break
|
||||
}
|
||||
copiedMetadata[metakey{modPath, dst}] = true
|
||||
if parent > 0 {
|
||||
copyDir(dst, src, matchMetadata)
|
||||
copyDir(dst, src, matchMetadata, copiedFiles)
|
||||
}
|
||||
if modPath == pkg {
|
||||
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.
|
||||
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)
|
||||
if err != nil {
|
||||
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) {
|
||||
continue
|
||||
}
|
||||
copiedFiles[file.Name()] = true
|
||||
r, err := os.Open(filepath.Join(src, file.Name()))
|
||||
if err != nil {
|
||||
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 {
|
||||
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
|
||||
modules have been changed and causes 'go mod' to exit with a
|
||||
non-zero status.
|
||||
|
||||
See https://golang.org/ref/mod#go-mod-verify for more about 'go mod verify'.
|
||||
`,
|
||||
Run: runVerify,
|
||||
}
|
||||
|
@ -48,6 +48,8 @@ For example:
|
||||
# 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"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
exec "internal/execabs"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
@ -8,11 +8,11 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
exec "internal/execabs"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
@ -768,90 +768,14 @@ var HelpModuleAuth = &base.Command{
|
||||
UsageLine: "module-auth",
|
||||
Short: "module authentication using go.sum",
|
||||
Long: `
|
||||
The go command tries to authenticate every downloaded module,
|
||||
checking that the bits downloaded for a specific module version today
|
||||
match bits downloaded yesterday. This ensures repeatable builds
|
||||
and detects introduction of unexpected changes, malicious or not.
|
||||
When the go command downloads a module zip file or go.mod file into the
|
||||
module cache, it computes a cryptographic hash and compares it with a known
|
||||
value to verify the file hasn't changed since it was first downloaded. Known
|
||||
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
|
||||
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.
|
||||
For details, see https://golang.org/ref/mod#authenticating.
|
||||
`,
|
||||
}
|
||||
|
||||
@ -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.
|
||||
|
||||
The GOPRIVATE environment variable controls which modules the go command
|
||||
considers to be private (not available publicly) and should therefore not use the
|
||||
proxy or checksum database. The variable is a comma-separated list of
|
||||
considers to be private (not available publicly) and should therefore not use
|
||||
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.
|
||||
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,
|
||||
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
|
||||
and GONOSUMDB environment variables accept the same kind of glob list
|
||||
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
|
||||
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"
|
||||
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
|
||||
@ -905,5 +819,7 @@ instead of module paths.
|
||||
|
||||
The 'go env -w' command (see 'go help env') can be used to set these variables
|
||||
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)
|
||||
can be a module proxy.
|
||||
|
||||
The GET requests sent to a Go module proxy are:
|
||||
|
||||
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.
|
||||
For details on the GOPROXY protocol, see
|
||||
https://golang.org/ref/mod#goproxy-protocol.
|
||||
`,
|
||||
}
|
||||
|
||||
|
@ -56,85 +56,49 @@ var CmdGet = &base.Command{
|
||||
UsageLine: "go get [-d] [-t] [-u] [-v] [-insecure] [build flags] [packages]",
|
||||
Short: "add dependencies to current module and install them",
|
||||
Long: `
|
||||
Get resolves and adds dependencies to the current development module
|
||||
and then builds and installs them.
|
||||
Get resolves its command-line arguments to packages at specific module versions,
|
||||
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
|
||||
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.
|
||||
go get example.com/pkg
|
||||
|
||||
This default version selection can be overridden by adding an @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.
|
||||
To upgrade or downgrade a package to a specific version:
|
||||
|
||||
For modules stored in source control repositories, the version suffix can
|
||||
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.
|
||||
go get example.com/pkg@v1.2.3
|
||||
|
||||
If a module under consideration is already a dependency of the current
|
||||
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.
|
||||
To remove a dependency on a module and downgrade modules that require it:
|
||||
|
||||
The version suffix @latest explicitly requests the latest minor release of
|
||||
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.
|
||||
go get example.com/mod@none
|
||||
|
||||
Although get defaults to using the latest version of the module containing
|
||||
a named package, it does not use the latest version of that module's
|
||||
dependencies. Instead it prefers to use the specific dependency versions
|
||||
requested by that module. For example, if the latest A requires module
|
||||
B v1.2.3, while B v1.2.4 and v1.3.1 are also available, then 'go get A'
|
||||
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
|
||||
those requirements by taking the maximum requested version.)
|
||||
See https://golang.org/ref/mod#go-get for details.
|
||||
|
||||
The 'go install' command may be used to build and install packages. When a
|
||||
version is specified, 'go install' runs in module-aware mode and ignores
|
||||
the go.mod file in the current directory. For example:
|
||||
|
||||
go install example.com/pkg@v1.2.3
|
||||
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
|
||||
packages specified on the command line.
|
||||
|
||||
The -u flag instructs get to update modules providing dependencies
|
||||
of packages named on the command line to use newer minor or patch
|
||||
releases when available. Continuing the previous example, 'go get -u A'
|
||||
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.
|
||||
releases when available.
|
||||
|
||||
The -u=patch flag (not -u patch) also instructs get to update dependencies,
|
||||
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
|
||||
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
|
||||
custom domains using insecure schemes such as HTTP, and also bypassess
|
||||
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
|
||||
GONOSUMDB. See 'go help environment' for details.
|
||||
|
||||
The second step is to download (if needed), build, and install
|
||||
the named 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.
|
||||
The -d flag instructs get not to build or install packages. get will only
|
||||
update go.mod and download source code needed to build packages.
|
||||
|
||||
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
|
||||
@ -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
|
||||
"@latest" after each argument.
|
||||
|
||||
If an argument names a module but not a package (because there is no
|
||||
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 modules, see https://golang.org/ref/mod.
|
||||
|
||||
For more about specifying packages, see 'go help packages'.
|
||||
|
||||
This text describes the behavior of get using modules to manage source
|
||||
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'.
|
||||
See 'go help modules' and 'go help gopath-get'.
|
||||
See 'go help gopath-get'.
|
||||
|
||||
See also: go build, go install, go clean, go mod.
|
||||
`,
|
||||
@ -1558,7 +1501,7 @@ func (r *resolver) checkPackagesAndRetractions(ctx context.Context, pkgPatterns
|
||||
}
|
||||
}
|
||||
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
|
||||
// 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 q.rawVersion == "" {
|
||||
base.Errorf("go get: %s", errStr)
|
||||
return
|
||||
}
|
||||
|
||||
versionRE := regexp.MustCompile("(?m)(?:[ @(\"`]|^)" + regexp.QuoteMeta(q.version) + "(?:[ :)\"`]|$)")
|
||||
versionRE := regexp.MustCompile("(?m)(?:[ @(\"`]|^)" + regexp.QuoteMeta(q.version) + "(?:[ :;)\"`]|$)")
|
||||
if versionRE.MatchString(errStr) {
|
||||
base.Errorf("go get: %s", errStr)
|
||||
return
|
||||
|
@ -28,6 +28,11 @@ import (
|
||||
//
|
||||
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.
|
||||
func capVersionSlice(s []module.Version) []module.Version {
|
||||
return s[:len(s):len(s)]
|
||||
@ -121,6 +126,12 @@ func EditBuildList(ctx context.Context, add, mustSelect []module.Version) error
|
||||
|
||||
if !inconsistent {
|
||||
buildList = final
|
||||
additionalExplicitRequirements = make([]string, 0, len(mustSelect))
|
||||
for _, m := range mustSelect {
|
||||
if m.Version != "none" {
|
||||
additionalExplicitRequirements = append(additionalExplicitRequirements, m.Path)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -12,395 +12,16 @@ var HelpModules = &base.Command{
|
||||
UsageLine: "modules",
|
||||
Short: "modules, module versions, and more",
|
||||
Long: `
|
||||
A module is a collection of related Go packages.
|
||||
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.
|
||||
Modules are how Go manages dependencies.
|
||||
|
||||
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
|
||||
by default whenever a go.mod file is found in the current directory or in
|
||||
any parent directory.
|
||||
For a series of tutorials on modules, see
|
||||
https://golang.org/doc/tutorial/create-module.
|
||||
|
||||
The quickest way to take advantage of module support is to check out your
|
||||
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.
|
||||
For a detailed reference on modules, see https://golang.org/ref/mod.
|
||||
`,
|
||||
}
|
||||
|
||||
@ -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
|
||||
marking the root of the main (current) module.
|
||||
|
||||
The go.mod file itself is line-oriented, with // comments but
|
||||
no /* */ comments. Each line holds a single directive, made up of a
|
||||
verb followed by arguments. For example:
|
||||
The go.mod file format is described in detail at
|
||||
https://golang.org/ref/mod#go-mod-file.
|
||||
|
||||
module my/thing
|
||||
go 1.12
|
||||
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
|
||||
To create a new go.mod file, use 'go help init'. For details see
|
||||
'go help mod init' or https://golang.org/ref/mod#go-mod-init.
|
||||
|
||||
The verbs are
|
||||
module, to define the module path;
|
||||
go, to set the expected language version;
|
||||
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.
|
||||
To add missing module requirements or remove unneeded requirements,
|
||||
use 'go mod tidy'. For details, see 'go help mod tidy' or
|
||||
https://golang.org/ref/mod#go-mod-tidy.
|
||||
|
||||
The leading verb can be factored out of adjacent lines to create a block,
|
||||
like in Go imports:
|
||||
To add, upgrade, downgrade, or remove a specific module requirement, use
|
||||
'go get'. For details, see 'go help module-get' or
|
||||
https://golang.org/ref/mod#go-get.
|
||||
|
||||
require (
|
||||
new/thing/v2 v2.3.4
|
||||
old/thing v1.2.3
|
||||
)
|
||||
|
||||
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.
|
||||
To make other changes or to parse go.mod as JSON for use by other tools,
|
||||
use 'go mod edit'. See 'go help mod edit' or
|
||||
https://golang.org/ref/mod#go-mod-edit.
|
||||
`,
|
||||
}
|
||||
|
@ -31,10 +31,6 @@ type ImportMissingError struct {
|
||||
Module module.Version
|
||||
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
|
||||
// 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
|
||||
@ -58,7 +54,7 @@ func (e *ImportMissingError) Error() string {
|
||||
if e.QueryErr != nil {
|
||||
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
|
||||
}
|
||||
|
||||
@ -67,16 +63,14 @@ func (e *ImportMissingError) Error() string {
|
||||
if !modfetch.IsZeroPseudoVersion(e.replaced.Version) {
|
||||
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 := ""
|
||||
if !HasModRoot() {
|
||||
suggestion = ": working directory is not part of a module"
|
||||
} else if e.inAll {
|
||||
suggestion = "; try 'go mod tidy' to add it"
|
||||
} 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)
|
||||
}
|
||||
@ -136,24 +130,57 @@ func (e *AmbiguousImportError) Error() string {
|
||||
}
|
||||
|
||||
// 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
|
||||
// for its .zip file.
|
||||
// if a module contains a package, but we don't have a sum 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 {
|
||||
importPath string
|
||||
found, inAll bool
|
||||
importPath string
|
||||
found bool
|
||||
mods []module.Version
|
||||
importer, importerVersion string // optional, but used for additional context
|
||||
importerIsTest bool
|
||||
}
|
||||
|
||||
func (e *ImportMissingSumError) Error() string {
|
||||
var importParen string
|
||||
if e.importer != "" {
|
||||
importParen = fmt.Sprintf(" (imported by %s)", e.importer)
|
||||
}
|
||||
var message string
|
||||
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 {
|
||||
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 {
|
||||
return message + "; try 'go mod tidy' to add it"
|
||||
var hint string
|
||||
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 {
|
||||
@ -244,7 +271,7 @@ func importFromBuildList(ctx context.Context, path string, buildList []module.Ve
|
||||
// Check each module on the build list.
|
||||
var dirs []string
|
||||
var mods []module.Version
|
||||
haveSumErr := false
|
||||
var sumErrMods []module.Version
|
||||
for _, m := range buildList {
|
||||
if !maybeInModule(path, m.Path) {
|
||||
// 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 can't verify that the package is unique, and we may not find
|
||||
// the package at all. Keep checking other modules to decide which
|
||||
// error to report.
|
||||
haveSumErr = true
|
||||
// error to report. Multiple sums may be missing if we need to look in
|
||||
// multiple nested modules to resolve the import.
|
||||
sumErrMods = append(sumErrMods, m)
|
||||
continue
|
||||
}
|
||||
// Report fetch error.
|
||||
@ -279,8 +307,12 @@ func importFromBuildList(ctx context.Context, path string, buildList []module.Ve
|
||||
if len(mods) > 1 {
|
||||
return module.Version{}, "", &AmbiguousImportError{importPath: path, Dirs: dirs, Modules: mods}
|
||||
}
|
||||
if haveSumErr {
|
||||
return module.Version{}, "", &ImportMissingSumError{importPath: path, found: len(mods) > 0}
|
||||
if len(sumErrMods) > 0 {
|
||||
return module.Version{}, "", &ImportMissingSumError{
|
||||
importPath: path,
|
||||
mods: sumErrMods,
|
||||
found: len(mods) > 0,
|
||||
}
|
||||
}
|
||||
if len(mods) == 1 {
|
||||
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}
|
||||
}
|
||||
|
||||
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
|
||||
// the module. If readonly mode was enabled explicitly, include that in
|
||||
// the error message.
|
||||
@ -547,7 +579,7 @@ func fetch(ctx context.Context, mod module.Version, needSum bool) (dir string, i
|
||||
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{})
|
||||
}
|
||||
|
||||
|
@ -58,10 +58,15 @@ var importTests = []struct {
|
||||
func TestQueryImport(t *testing.T) {
|
||||
testenv.MustHaveExternalNetwork(t)
|
||||
testenv.MustHaveExecPath(t, "git")
|
||||
defer func(old bool) {
|
||||
allowMissingModuleImports = old
|
||||
}(allowMissingModuleImports)
|
||||
AllowMissingModuleImports()
|
||||
|
||||
oldAllowMissingModuleImports := allowMissingModuleImports
|
||||
oldRootMode := RootMode
|
||||
defer func() {
|
||||
allowMissingModuleImports = oldAllowMissingModuleImports
|
||||
RootMode = oldRootMode
|
||||
}()
|
||||
allowMissingModuleImports = true
|
||||
RootMode = NoRoot
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@ -27,6 +28,7 @@ import (
|
||||
"cmd/go/internal/modfetch"
|
||||
"cmd/go/internal/mvs"
|
||||
"cmd/go/internal/search"
|
||||
"cmd/go/internal/str"
|
||||
|
||||
"golang.org/x/mod/modfile"
|
||||
"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.
|
||||
cfg.ModulesEnabled = true
|
||||
setDefaultBuildMod()
|
||||
list := filepath.SplitList(cfg.BuildContext.GOPATH)
|
||||
if len(list) == 0 || list[0] == "" {
|
||||
base.Fatalf("missing $GOPATH")
|
||||
@ -209,8 +213,6 @@ func Init() {
|
||||
base.Fatalf("$GOPATH/go.mod exists but should not")
|
||||
}
|
||||
|
||||
cfg.ModulesEnabled = true
|
||||
|
||||
if modRoot == "" {
|
||||
// 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
|
||||
// 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
|
||||
// already have an explicit value.
|
||||
// As a side-effect, LoadModFile may change cfg.BuildMod to "vendor" if
|
||||
// -mod wasn't set explicitly and automatic vendoring should be enabled.
|
||||
func LoadModFile(ctx context.Context) {
|
||||
if len(buildList) > 0 {
|
||||
return
|
||||
@ -378,14 +380,14 @@ func LoadModFile(ctx context.Context) {
|
||||
|
||||
if f.Module == nil {
|
||||
// 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 {
|
||||
base.Fatalf("go: %v", err)
|
||||
}
|
||||
|
||||
setDefaultBuildMod()
|
||||
setDefaultBuildMod() // possibly enable automatic vendoring
|
||||
modFileToBuildList()
|
||||
if cfg.BuildMod == "vendor" {
|
||||
readVendorList()
|
||||
@ -456,7 +458,7 @@ func CreateModFile(ctx context.Context, modPath string) {
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// setDefaultBuildMod sets a default value for cfg.BuildMod
|
||||
// if it is currently empty.
|
||||
// setDefaultBuildMod sets a default value for cfg.BuildMod if the -mod flag
|
||||
// wasn't provided. setDefaultBuildMod may be called multiple times.
|
||||
func setDefaultBuildMod() {
|
||||
if cfg.BuildModExplicit {
|
||||
// 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() {
|
||||
modGo := "unspecified"
|
||||
if index.goVersionV != "" {
|
||||
if index != nil && index.goVersionV != "" {
|
||||
if semver.Compare(index.goVersionV, "v1.14") >= 0 {
|
||||
// The Go version is at least 1.14, and a vendor directory exists.
|
||||
// Set -mod=vendor by default.
|
||||
@ -845,13 +847,15 @@ func AllowWriteGoMod() {
|
||||
// MinReqs returns a Reqs with minimal additional dependencies of Target,
|
||||
// as will be written to go.mod.
|
||||
func MinReqs() mvs.Reqs {
|
||||
var retain []string
|
||||
retain := append([]string{}, additionalExplicitRequirements...)
|
||||
for _, m := range buildList[1:] {
|
||||
_, explicit := index.require[m]
|
||||
if explicit || loaded.direct[m.Path] {
|
||||
retain = append(retain, m.Path)
|
||||
}
|
||||
}
|
||||
sort.Strings(retain)
|
||||
str.Uniq(&retain)
|
||||
min, err := mvs.Req(Target, retain, &mvsReqs{buildList: buildList})
|
||||
if err != nil {
|
||||
base.Fatalf("go: %v", err)
|
||||
@ -903,7 +907,7 @@ func WriteGoMod() {
|
||||
} else if cfg.BuildModReason != "" {
|
||||
base.Fatalf("go: updates to go.mod needed, disabled by -mod=readonly\n\t(%s)", cfg.BuildModReason)
|
||||
} 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
|
||||
// of these entries ends with "/go.mod").
|
||||
//
|
||||
// If addDirect is true, the set also includes sums for modules directly
|
||||
// required by go.mod, as represented by the index, with replacements applied.
|
||||
func keepSums(addDirect bool) map[module.Version]bool {
|
||||
// If keepBuildListZips is true, the set also includes sums for zip files for
|
||||
// all modules in the build list with replacements applied. 'go get' and
|
||||
// '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.
|
||||
// Keep the sum for the go.mod of each visited module version (or its
|
||||
// replacement).
|
||||
@ -1003,19 +1010,20 @@ func keepSums(addDirect bool) map[module.Version]bool {
|
||||
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
|
||||
// paths of loaded packages. We need to retain sums for modules needed to
|
||||
// report ambiguous import errors. We use our re-derived build list,
|
||||
// since the global build list may have been tidied.
|
||||
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 {
|
||||
if pkg.testOf != nil || pkg.inStd || module.CheckImportPath(pkg.path) != nil {
|
||||
continue
|
||||
@ -1028,17 +1036,13 @@ func keepSums(addDirect bool) map[module.Version]bool {
|
||||
}
|
||||
}
|
||||
|
||||
// Add entries for modules directly required by go.mod.
|
||||
if addDirect {
|
||||
for m := range index.require {
|
||||
var kept module.Version
|
||||
if r := Replacement(m); r.Path != "" {
|
||||
kept = r
|
||||
} else {
|
||||
kept = m
|
||||
}
|
||||
keep[kept] = true
|
||||
keep[module.Version{Path: kept.Path, Version: kept.Version + "/go.mod"}] = true
|
||||
// Add entries for the zip of each module in the build list.
|
||||
// We might not need all of these (tidy does not add them), but they may be
|
||||
// added by a specific 'go get' or 'go mod download' command to resolve
|
||||
// missing import sum errors.
|
||||
if keepBuildListZips {
|
||||
for _, m := range actualMods {
|
||||
keep[m] = true
|
||||
}
|
||||
}
|
||||
|
||||
@ -1058,9 +1062,8 @@ func (r *keepSumReqs) Required(m module.Version) ([]module.Version, error) {
|
||||
}
|
||||
|
||||
func TrimGoSum() {
|
||||
// Don't retain sums for direct requirements in go.mod. When TrimGoSum is
|
||||
// called, go.mod has not been updated, and it may contain requirements on
|
||||
// modules deleted from the build list.
|
||||
addDirect := false
|
||||
modfetch.TrimGoSum(keepSums(addDirect))
|
||||
// Don't retain sums for the zip file of every module in the build list.
|
||||
// We may not need them all to build the main module's packages.
|
||||
keepBuildListZips := false
|
||||
modfetch.TrimGoSum(keepSums(keepBuildListZips))
|
||||
}
|
||||
|
@ -280,11 +280,11 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
|
||||
checkMultiplePaths()
|
||||
for _, pkg := range loaded.pkgs {
|
||||
if pkg.err != nil {
|
||||
if pkg.flags.has(pkgInAll) {
|
||||
if imErr := (*ImportMissingError)(nil); errors.As(pkg.err, &imErr) {
|
||||
imErr.inAll = true
|
||||
} else if sumErr := (*ImportMissingSumError)(nil); errors.As(pkg.err, &sumErr) {
|
||||
sumErr.inAll = true
|
||||
if sumErr := (*ImportMissingSumError)(nil); errors.As(pkg.err, &sumErr) {
|
||||
if importer := pkg.stack; importer != nil {
|
||||
sumErr.importer = importer.path
|
||||
sumErr.importerVersion = importer.mod.Version
|
||||
sumErr.importerIsTest = importer.testOf != nil
|
||||
}
|
||||
}
|
||||
|
||||
@ -863,12 +863,21 @@ func loadFromRoots(params loaderParams) *loader {
|
||||
for _, pkg := range ld.pkgs {
|
||||
if pkg.mod == Target {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
base.ExitIfErrors()
|
||||
|
||||
// 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
|
||||
|
@ -446,10 +446,10 @@ func goModSummary(m module.Version) (*modFileSummary, error) {
|
||||
if actual.Path == "" {
|
||||
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"}
|
||||
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})
|
||||
}
|
||||
}
|
||||
|
@ -111,19 +111,3 @@ func (*mvsReqs) Previous(m module.Version) (module.Version, error) {
|
||||
}
|
||||
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/modfetch"
|
||||
"cmd/go/internal/search"
|
||||
"cmd/go/internal/str"
|
||||
"cmd/go/internal/trace"
|
||||
|
||||
"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 {
|
||||
return semver.Compare(versions[i], versions[j]) < 0
|
||||
})
|
||||
uniq := versions[:1]
|
||||
for _, v := range versions {
|
||||
if v != uniq[len(uniq)-1] {
|
||||
uniq = append(uniq, v)
|
||||
}
|
||||
}
|
||||
return uniq, nil
|
||||
str.Uniq(&versions)
|
||||
return versions, nil
|
||||
}
|
||||
|
||||
func (rr *replacementRepo) Stat(rev string) (*modfetch.RevInfo, error) {
|
||||
|
@ -214,6 +214,6 @@ func checkVendorConsistency() {
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return c == ' ' || c == '\t' || c == '\n' || c == '\r'
|
||||
}
|
||||
|
@ -9,9 +9,9 @@ package main
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
exec "internal/execabs"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
"text/template"
|
||||
|
@ -11,10 +11,10 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/build"
|
||||
exec "internal/execabs"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
|
@ -325,7 +325,7 @@ func testFlags(args []string) (packageNames, passToTest []string) {
|
||||
if !testC {
|
||||
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()
|
||||
}
|
||||
|
||||
|
@ -8,8 +8,9 @@ package tool
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
exec "internal/execabs"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
@ -85,7 +86,19 @@ func runTool(ctx context.Context, cmd *base.Command, args []string) {
|
||||
Stdout: os.Stdout,
|
||||
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 {
|
||||
// Only print about the exit status if the command
|
||||
// didn't even run (not an ExitError) or it didn't exit cleanly
|
||||
|
@ -8,13 +8,13 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
exec "internal/execabs"
|
||||
"internal/lazyregexp"
|
||||
"internal/singleflight"
|
||||
"io/fs"
|
||||
"log"
|
||||
urlpkg "net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
@ -729,7 +729,7 @@ func checkGOVCS(vcs *Cmd, root string) error {
|
||||
if 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
|
||||
|
@ -10,9 +10,9 @@ import (
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
exec "internal/execabs"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
|
@ -9,9 +9,9 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/build"
|
||||
exec "internal/execabs"
|
||||
"internal/goroot"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
@ -113,7 +113,10 @@ and test commands:
|
||||
created with -buildmode=shared.
|
||||
-mod mode
|
||||
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
|
||||
leave newly-created directories in the module cache read-write
|
||||
instead of making them read-only.
|
||||
|
@ -7,8 +7,8 @@ package work
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
exec "internal/execabs"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"cmd/go/internal/base"
|
||||
|
@ -13,13 +13,13 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
exec "internal/execabs"
|
||||
"internal/lazyregexp"
|
||||
"io"
|
||||
"io/fs"
|
||||
"log"
|
||||
"math/rand"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
@ -1166,6 +1166,7 @@ func (b *Builder) vet(ctx context.Context, a *Action) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO(rsc): Why do we pass $GCCGO to go vet?
|
||||
env := b.cCompilerEnv()
|
||||
if cfg.BuildToolchainName == "gccgo" {
|
||||
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
|
||||
cmd := exec.Command(cmdline[0], cmdline[1:]...)
|
||||
if cmd.Path != "" {
|
||||
cmd.Args[0] = cmd.Path
|
||||
}
|
||||
cmd.Stdout = &buf
|
||||
cmd.Stderr = &buf
|
||||
cleanup := passLongArgsInResponseFiles(cmd)
|
||||
@ -2437,7 +2441,7 @@ func (b *Builder) fcExe() []string {
|
||||
func (b *Builder) compilerExe(envValue string, def string) []string {
|
||||
compiler := strings.Fields(envValue)
|
||||
if len(compiler) == 0 {
|
||||
compiler = []string{def}
|
||||
compiler = strings.Fields(def)
|
||||
}
|
||||
return compiler
|
||||
}
|
||||
@ -2589,7 +2593,14 @@ func (b *Builder) gccArchArgs() []string {
|
||||
case "386":
|
||||
return []string{"-m32"}
|
||||
case "amd64":
|
||||
if cfg.Goos == "darwin" {
|
||||
return []string{"-arch", "x86_64", "-m64"}
|
||||
}
|
||||
return []string{"-m64"}
|
||||
case "arm64":
|
||||
if cfg.Goos == "darwin" {
|
||||
return []string{"-arch", "arm64"}
|
||||
}
|
||||
case "arm":
|
||||
return []string{"-marm"} // not thumb
|
||||
case "s390x":
|
||||
@ -2721,7 +2732,7 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgo
|
||||
for i, f := range cgoLDFLAGS {
|
||||
flags[i] = strconv.Quote(f)
|
||||
}
|
||||
cgoenv = []string{"CGO_LDFLAGS=" + strings.Join(flags, " ")}
|
||||
cgoenv = append(cgoenv, "CGO_LDFLAGS="+strings.Join(flags, " "))
|
||||
}
|
||||
|
||||
if cfg.BuildToolchainName == "gccgo" {
|
||||
|
@ -6,8 +6,8 @@ package work
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
exec "internal/execabs"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
@ -93,6 +93,12 @@ func (tools gccgoToolchain) gc(b *Builder, a *Action, archive string, importcfg,
|
||||
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 cfg.BuildTrimpath {
|
||||
|
2
libgo/go/cmd/go/testdata/addmod.go
vendored
2
libgo/go/cmd/go/testdata/addmod.go
vendored
@ -25,7 +25,7 @@ import (
|
||||
"io/fs"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
exec "internal/execabs"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
# embedded in a package, that is referenced by a Go assembly function.
|
||||
# See issue 33139.
|
||||
[!gc] skip
|
||||
[!exec:cc] skip
|
||||
[!cgo] skip
|
||||
|
||||
# External linking is not supported on linux/ppc64.
|
||||
# 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
|
||||
stderr '^useappengine[/\\]x.go:2:8: cannot find package$'
|
||||
! 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
|
||||
|
6
libgo/go/cmd/go/testdata/script/mod_edit.txt
vendored
6
libgo/go/cmd/go/testdata/script/mod_edit.txt
vendored
@ -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]
|
||||
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
|
||||
cmpenv stdout $WORK/go.mod.json
|
||||
|
@ -6,5 +6,5 @@ env GOPROXY=https://proxy.golang.org,direct
|
||||
env GOSUMDB=off
|
||||
|
||||
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'
|
||||
|
@ -19,7 +19,7 @@ exec $WORK/testimport$GOEXE other/x/y/z/w .
|
||||
stdout w2.go
|
||||
|
||||
! 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
|
||||
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...
|
||||
! 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 incomplete
|
||||
|
||||
|
10
libgo/go/cmd/go/testdata/script/mod_readonly.txt
vendored
10
libgo/go/cmd/go/testdata/script/mod_readonly.txt
vendored
@ -13,7 +13,7 @@ cmp go.mod go.mod.empty
|
||||
# -mod=readonly should be set by default.
|
||||
env GOFLAGS=
|
||||
! 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
|
||||
|
||||
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.
|
||||
env GOFLAGS=
|
||||
! 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,
|
||||
# since that was not always required.
|
||||
@ -75,15 +75,15 @@ cmp go.mod go.mod.indirect
|
||||
|
||||
cp go.mod.untidy go.mod
|
||||
! 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 .
|
||||
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
|
||||
# 'go get -d' instead, because we don't know whether 'go mod tidy' would add it.
|
||||
! 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 --
|
||||
|
@ -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/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 '\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.
|
||||
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/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 '\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
|
||||
# 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
|
||||
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 '\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
|
||||
# matching vendor/modules.txt containing the corrected 1.13 data.
|
||||
|
@ -1,14 +1,14 @@
|
||||
# Test rejection of pkg@version in GOPATH mode.
|
||||
env GO111MODULE=off
|
||||
! 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
|
||||
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
|
||||
cd x
|
||||
! 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 --
|
||||
module x
|
||||
|
@ -6,8 +6,8 @@
|
||||
package browser
|
||||
|
||||
import (
|
||||
exec "internal/execabs"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"time"
|
||||
)
|
||||
|
@ -6,7 +6,7 @@
|
||||
//
|
||||
// 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;
|
||||
// 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 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
|
||||
// binary's output. To convert the output of a "go test" command,
|
||||
// use "go test -json" instead of invoking test2json directly.
|
||||
@ -82,9 +86,9 @@ package main
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
exec "internal/execabs"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"cmd/internal/test2json"
|
||||
)
|
||||
|
4
libgo/go/cmd/vendor/modules.txt
vendored
4
libgo/go/cmd/vendor/modules.txt
vendored
@ -28,7 +28,7 @@ golang.org/x/arch/x86/x86asm
|
||||
golang.org/x/crypto/ed25519
|
||||
golang.org/x/crypto/ed25519/internal/edwards25519
|
||||
golang.org/x/crypto/ssh/terminal
|
||||
# golang.org/x/mod v0.4.0
|
||||
# golang.org/x/mod v0.4.1
|
||||
## explicit
|
||||
golang.org/x/mod/internal/lazyregexp
|
||||
golang.org/x/mod/modfile
|
||||
@ -44,7 +44,7 @@ golang.org/x/mod/zip
|
||||
golang.org/x/sys/internal/unsafeheader
|
||||
golang.org/x/sys/unix
|
||||
golang.org/x/sys/windows
|
||||
# golang.org/x/tools v0.0.0-20201211025543-abf6a1d87e11
|
||||
# golang.org/x/tools v0.0.0-20210107193943-4ed967dd8eff
|
||||
## explicit
|
||||
golang.org/x/tools/go/analysis
|
||||
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.
|
||||
//
|
||||
// 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) {
|
||||
copy(out[:], in[:])
|
||||
|
||||
// First, carry the bits above 28 to the higher limb.
|
||||
for i := 0; i < 7; i++ {
|
||||
out[i+1] += out[i] >> 28
|
||||
out[i] &= bottom28Bits
|
||||
@ -397,10 +398,13 @@ func p224Contract(out, in *p224FieldElement) {
|
||||
top := out[7] >> 28
|
||||
out[7] &= bottom28Bits
|
||||
|
||||
// Use the reduction identity to carry the overflow.
|
||||
//
|
||||
// a + top * 2²²⁴ = a + top * 2⁹⁶ - top
|
||||
out[0] -= top
|
||||
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
|
||||
// because we just added to it.
|
||||
for i := 0; i < 3; i++ {
|
||||
@ -425,13 +429,12 @@ func p224Contract(out, in *p224FieldElement) {
|
||||
// There are two cases to consider for out[3]:
|
||||
// 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
|
||||
// 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.
|
||||
// The first value of top was in [0..16), therefore, prior to eliminating
|
||||
// the first top, 0xfff1000 <= out[3] <= 0xfffffff. Therefore, after
|
||||
// overflowing and being reduced by the second carry chain, out[3] <=
|
||||
// 0xf000. Thus it cannot have overflowed when we eliminated top for the
|
||||
// second time.
|
||||
// The first value of top was in [0..2], therefore, after overflowing
|
||||
// and being reduced by the second carry chain, out[3] <= 2<<12 - 1.
|
||||
// In both cases, out[3] cannot have overflowed when we eliminated top for
|
||||
// the second time.
|
||||
|
||||
// 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
|
||||
@ -470,12 +473,11 @@ func p224Contract(out, in *p224FieldElement) {
|
||||
bottom3NonZero |= bottom3NonZero >> 1
|
||||
bottom3NonZero = uint32(int32(bottom3NonZero<<31) >> 31)
|
||||
|
||||
// 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 and top4AllOnes != 0 and bottom3NonZero != 0,
|
||||
// then the whole value is >= p
|
||||
// Assuming top4AllOnes != 0, everything depends on the value of out[3].
|
||||
// If it's > 0xffff000 then the whole value is > p
|
||||
// If it's = 0xffff000 and bottom3NonZero != 0, 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 |= out3Equal >> 16
|
||||
out3Equal |= out3Equal >> 8
|
||||
@ -484,8 +486,8 @@ func p224Contract(out, in *p224FieldElement) {
|
||||
out3Equal |= out3Equal >> 1
|
||||
out3Equal = ^uint32(int32(out3Equal<<31) >> 31)
|
||||
|
||||
// If out[3] > 0xffff000 then n's MSB will be zero.
|
||||
out3GT := ^uint32(int32(n) >> 31)
|
||||
// If out[3] > 0xffff000 then n's MSB will be one.
|
||||
out3GT := uint32(int32(n) >> 31)
|
||||
|
||||
mask := top4AllOnes & ((out3Equal & bottom3NonZero) | out3GT)
|
||||
out[0] -= 1 & mask
|
||||
@ -494,6 +496,15 @@ func p224Contract(out, in *p224FieldElement) {
|
||||
out[5] -= 0xfffffff & mask
|
||||
out[6] -= 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.
|
||||
|
@ -6,7 +6,11 @@ package elliptic
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"math/bits"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"testing"
|
||||
"testing/quick"
|
||||
)
|
||||
|
||||
var toFromBigTests = []string{
|
||||
@ -21,16 +25,16 @@ func p224AlternativeToBig(in *p224FieldElement) *big.Int {
|
||||
ret := 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.Lsh(tmp, 28*i)
|
||||
ret.Add(ret, tmp)
|
||||
}
|
||||
ret.Mod(ret, p224.P)
|
||||
ret.Mod(ret, P224().Params().P)
|
||||
return ret
|
||||
}
|
||||
|
||||
func TestToFromBig(t *testing.T) {
|
||||
func TestP224ToFromBig(t *testing.T) {
|
||||
for i, test := range toFromBigTests {
|
||||
n, _ := new(big.Int).SetString(test, 16)
|
||||
var x p224FieldElement
|
||||
@ -41,7 +45,270 @@ func TestToFromBig(t *testing.T) {
|
||||
}
|
||||
q := p224AlternativeToBig(&x)
|
||||
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
|
||||
|
||||
import (
|
||||
"internal/syscall/windows"
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func init() { Reader = &rngReader{} }
|
||||
@ -24,7 +24,7 @@ func (r *rngReader) Read(b []byte) (n int, err error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
err = syscall.RtlGenRandom(&b[0], inputLen)
|
||||
err = windows.RtlGenRandom(b)
|
||||
if err != nil {
|
||||
return 0, os.NewSyscallError("RtlGenRandom", err)
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ package tls
|
||||
import (
|
||||
"bytes"
|
||||
"container/list"
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/ed25519"
|
||||
@ -444,16 +443,6 @@ type ClientHelloInfo struct {
|
||||
// config is embedded by the GetCertificate or GetConfigForClient caller,
|
||||
// for use with SupportsCertificate.
|
||||
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
|
||||
@ -472,16 +461,6 @@ type CertificateRequestInfo struct {
|
||||
|
||||
// Version is the TLS version that was negotiated for this connection.
|
||||
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
|
||||
|
@ -8,7 +8,6 @@ package tls
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/cipher"
|
||||
"crypto/subtle"
|
||||
"crypto/x509"
|
||||
@ -28,7 +27,7 @@ type Conn struct {
|
||||
// constant
|
||||
conn net.Conn
|
||||
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
|
||||
// application data (i.e. is not currently processing a handshake).
|
||||
@ -1191,7 +1190,7 @@ func (c *Conn) handleRenegotiation() error {
|
||||
defer c.handshakeMutex.Unlock()
|
||||
|
||||
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++
|
||||
}
|
||||
return c.handshakeErr
|
||||
@ -1374,61 +1373,8 @@ func (c *Conn) closeNotify() error {
|
||||
// first Read or Write will call it automatically.
|
||||
//
|
||||
// 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 {
|
||||
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()
|
||||
defer c.handshakeMutex.Unlock()
|
||||
|
||||
@ -1442,7 +1388,7 @@ func (c *Conn) handshakeContext(ctx context.Context) (ret error) {
|
||||
c.in.Lock()
|
||||
defer c.in.Unlock()
|
||||
|
||||
c.handshakeErr = c.handshakeFn(handshakeCtx)
|
||||
c.handshakeErr = c.handshakeFn()
|
||||
if c.handshakeErr == nil {
|
||||
c.handshakes++
|
||||
} else {
|
||||
|
@ -6,7 +6,6 @@ package tls
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/ed25519"
|
||||
@ -25,7 +24,6 @@ import (
|
||||
|
||||
type clientHandshakeState struct {
|
||||
c *Conn
|
||||
ctx context.Context
|
||||
serverHello *serverHelloMsg
|
||||
hello *clientHelloMsg
|
||||
suite *cipherSuite
|
||||
@ -136,7 +134,7 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, ecdheParameters, error) {
|
||||
return hello, params, nil
|
||||
}
|
||||
|
||||
func (c *Conn) clientHandshake(ctx context.Context) (err error) {
|
||||
func (c *Conn) clientHandshake() (err error) {
|
||||
if c.config == nil {
|
||||
c.config = defaultConfig()
|
||||
}
|
||||
@ -200,7 +198,6 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) {
|
||||
if c.vers == VersionTLS13 {
|
||||
hs := &clientHandshakeStateTLS13{
|
||||
c: c,
|
||||
ctx: ctx,
|
||||
serverHello: serverHello,
|
||||
hello: hello,
|
||||
ecdheParams: ecdheParams,
|
||||
@ -215,7 +212,6 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) {
|
||||
|
||||
hs := &clientHandshakeState{
|
||||
c: c,
|
||||
ctx: ctx,
|
||||
serverHello: serverHello,
|
||||
hello: hello,
|
||||
session: session,
|
||||
@ -544,7 +540,7 @@ func (hs *clientHandshakeState) doFullHandshake() error {
|
||||
certRequested = true
|
||||
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 {
|
||||
c.sendAlert(alertInternalError)
|
||||
return err
|
||||
@ -884,11 +880,10 @@ func (c *Conn) verifyServerCertificate(certificates [][]byte) error {
|
||||
|
||||
// certificateRequestInfoFromMsg generates a CertificateRequestInfo from a TLS
|
||||
// <= 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{
|
||||
AcceptableCAs: certReq.certificateAuthorities,
|
||||
Version: vers,
|
||||
ctx: ctx,
|
||||
}
|
||||
|
||||
var rsaAvail, ecAvail bool
|
||||
|
@ -6,7 +6,6 @@ package tls
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
@ -21,7 +20,6 @@ import (
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
@ -2513,37 +2511,3 @@ func testResumptionKeepsOCSPAndSCT(t *testing.T, ver uint16) {
|
||||
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 (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/hmac"
|
||||
"crypto/rsa"
|
||||
@ -18,7 +17,6 @@ import (
|
||||
|
||||
type clientHandshakeStateTLS13 struct {
|
||||
c *Conn
|
||||
ctx context.Context
|
||||
serverHello *serverHelloMsg
|
||||
hello *clientHelloMsg
|
||||
ecdheParams ecdheParameters
|
||||
@ -557,7 +555,6 @@ func (hs *clientHandshakeStateTLS13) sendClientCertificate() error {
|
||||
AcceptableCAs: hs.certReq.certificateAuthorities,
|
||||
SignatureSchemes: hs.certReq.supportedSignatureAlgorithms,
|
||||
Version: c.vers,
|
||||
ctx: hs.ctx,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -5,7 +5,6 @@
|
||||
package tls
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/ed25519"
|
||||
@ -24,7 +23,6 @@ import (
|
||||
// It's discarded once the handshake has completed.
|
||||
type serverHandshakeState struct {
|
||||
c *Conn
|
||||
ctx context.Context
|
||||
clientHello *clientHelloMsg
|
||||
hello *serverHelloMsg
|
||||
suite *cipherSuite
|
||||
@ -39,8 +37,8 @@ type serverHandshakeState struct {
|
||||
}
|
||||
|
||||
// serverHandshake performs a TLS handshake as a server.
|
||||
func (c *Conn) serverHandshake(ctx context.Context) error {
|
||||
clientHello, err := c.readClientHello(ctx)
|
||||
func (c *Conn) serverHandshake() error {
|
||||
clientHello, err := c.readClientHello()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -48,7 +46,6 @@ func (c *Conn) serverHandshake(ctx context.Context) error {
|
||||
if c.vers == VersionTLS13 {
|
||||
hs := serverHandshakeStateTLS13{
|
||||
c: c,
|
||||
ctx: ctx,
|
||||
clientHello: clientHello,
|
||||
}
|
||||
return hs.handshake()
|
||||
@ -56,7 +53,6 @@ func (c *Conn) serverHandshake(ctx context.Context) error {
|
||||
|
||||
hs := serverHandshakeState{
|
||||
c: c,
|
||||
ctx: ctx,
|
||||
clientHello: clientHello,
|
||||
}
|
||||
return hs.handshake()
|
||||
@ -128,7 +124,7 @@ func (hs *serverHandshakeState) handshake() error {
|
||||
}
|
||||
|
||||
// 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()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -142,7 +138,7 @@ func (c *Conn) readClientHello(ctx context.Context) (*clientHelloMsg, error) {
|
||||
var configForClient *Config
|
||||
originalConfig := c.config
|
||||
if c.config.GetConfigForClient != nil {
|
||||
chi := clientHelloInfo(ctx, c, clientHello)
|
||||
chi := clientHelloInfo(c, clientHello)
|
||||
if configForClient, err = c.config.GetConfigForClient(chi); err != nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
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 == errNoCertificates {
|
||||
c.sendAlert(alertUnrecognizedName)
|
||||
@ -832,7 +828,7 @@ func (c *Conn) processCertsFromClient(certificate Certificate) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func clientHelloInfo(ctx context.Context, c *Conn, clientHello *clientHelloMsg) *ClientHelloInfo {
|
||||
func clientHelloInfo(c *Conn, clientHello *clientHelloMsg) *ClientHelloInfo {
|
||||
supportedVersions := clientHello.supportedVersions
|
||||
if len(clientHello.supportedVersions) == 0 {
|
||||
supportedVersions = supportedVersionsFromMax(clientHello.vers)
|
||||
@ -848,6 +844,5 @@ func clientHelloInfo(ctx context.Context, c *Conn, clientHello *clientHelloMsg)
|
||||
SupportedVersions: supportedVersions,
|
||||
Conn: c.conn,
|
||||
config: c.config,
|
||||
ctx: ctx,
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ package tls
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/elliptic"
|
||||
"crypto/x509"
|
||||
@ -18,7 +17,6 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@ -40,12 +38,10 @@ func testClientHelloFailure(t *testing.T, serverConfig *Config, m handshakeMessa
|
||||
cli.writeRecord(recordTypeHandshake, m.marshal())
|
||||
c.Close()
|
||||
}()
|
||||
ctx := context.Background()
|
||||
conn := Server(s, serverConfig)
|
||||
ch, err := conn.readClientHello(ctx)
|
||||
ch, err := conn.readClientHello()
|
||||
hs := serverHandshakeState{
|
||||
c: conn,
|
||||
ctx: ctx,
|
||||
clientHello: ch,
|
||||
}
|
||||
if err == nil {
|
||||
@ -1425,11 +1421,9 @@ func TestSNIGivenOnFailure(t *testing.T) {
|
||||
c.Close()
|
||||
}()
|
||||
conn := Server(s, serverConfig)
|
||||
ctx := context.Background()
|
||||
ch, err := conn.readClientHello(ctx)
|
||||
ch, err := conn.readClientHello()
|
||||
hs := serverHandshakeState{
|
||||
c: conn,
|
||||
ctx: ctx,
|
||||
clientHello: ch,
|
||||
}
|
||||
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) {
|
||||
currentAESSupport := hasAESGCMHardwareSupport
|
||||
defer func() { hasAESGCMHardwareSupport = currentAESSupport; initDefaultCipherSuites() }()
|
||||
|
@ -6,7 +6,6 @@ package tls
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/hmac"
|
||||
"crypto/rsa"
|
||||
@ -24,7 +23,6 @@ const maxClientPSKIdentities = 5
|
||||
|
||||
type serverHandshakeStateTLS13 struct {
|
||||
c *Conn
|
||||
ctx context.Context
|
||||
clientHello *clientHelloMsg
|
||||
hello *serverHelloMsg
|
||||
sentDummyCCS bool
|
||||
@ -376,7 +374,7 @@ func (hs *serverHandshakeStateTLS13) pickCertificate() error {
|
||||
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 == errNoCertificates {
|
||||
c.sendAlert(alertUnrecognizedName)
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 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) {
|
||||
if netDialer.Timeout != 0 {
|
||||
var cancel context.CancelFunc
|
||||
ctx, cancel = context.WithTimeout(ctx, netDialer.Timeout)
|
||||
defer cancel()
|
||||
}
|
||||
// We want the Timeout and Deadline values from dialer to cover the
|
||||
// whole process: TCP connection and TLS handshake. This means that we
|
||||
// also need to start our own timers now.
|
||||
timeout := netDialer.Timeout
|
||||
|
||||
if !netDialer.Deadline.IsZero() {
|
||||
var cancel context.CancelFunc
|
||||
ctx, cancel = context.WithDeadline(ctx, netDialer.Deadline)
|
||||
defer cancel()
|
||||
deadlineTimeout := time.Until(netDialer.Deadline)
|
||||
if timeout == 0 || deadlineTimeout < timeout {
|
||||
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)
|
||||
@ -151,10 +164,34 @@ func dial(ctx context.Context, netDialer *net.Dialer, network, addr string, conf
|
||||
}
|
||||
|
||||
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()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,11 @@
|
||||
|
||||
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"
|
||||
|
||||
|
@ -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".
|
||||
|
||||
// +build ios
|
||||
@ -116,61 +116,6 @@ ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU
|
||||
LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT
|
||||
LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg==
|
||||
-----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"
|
||||
# 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
|
||||
@ -1249,31 +1194,6 @@ Bvt9YAretIpjsJyp8qS5UwGH0GikJ3+r/+n6yUA4iGe0OcaEb1fJU9u6ju7AQ7L4
|
||||
CYNu/2bPPu8Xs1gYJQk0XuPL1hS27PKSb3TkL4Eq1ZKR4OCXPDJoBYVL0fdX4lId
|
||||
kxpUnwVwwEpxYB5DC2Ae/qPOgRnhCzU=
|
||||
-----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"
|
||||
# 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
|
||||
@ -1529,31 +1449,6 @@ CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na
|
||||
xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX
|
||||
KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1
|
||||
-----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"
|
||||
# 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
|
||||
@ -1801,29 +1696,6 @@ R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5
|
||||
JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
|
||||
Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
|
||||
-----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"
|
||||
# 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
|
||||
@ -2671,39 +2543,6 @@ EhTkYY2sEJCehFC78JZvRZ+K88psT/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpO
|
||||
fMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilTc4afU9hDDl3WY4JxHYB0yvbi
|
||||
AmvZWg==
|
||||
-----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"
|
||||
# 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
|
||||
@ -4722,123 +4561,6 @@ VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB
|
||||
L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG
|
||||
jjxDah2nGN59PRbxYvnKkKj9
|
||||
-----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"
|
||||
# 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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
@ -2405,7 +2362,6 @@ type CertificateRequest struct {
|
||||
Version int
|
||||
Signature []byte
|
||||
SignatureAlgorithm SignatureAlgorithm
|
||||
KeyUsage KeyUsage
|
||||
|
||||
PublicKeyAlgorithm PublicKeyAlgorithm
|
||||
PublicKey interface{}
|
||||
@ -2438,37 +2394,6 @@ type CertificateRequest struct {
|
||||
EmailAddresses []string
|
||||
IPAddresses []net.IP
|
||||
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
|
||||
@ -2566,15 +2491,6 @@ func parseCSRExtensions(rawAttributes []asn1.RawValue) ([]pkix.Extension, error)
|
||||
// - EmailAddresses
|
||||
// - IPAddresses
|
||||
// - URIs
|
||||
// - KeyUsage
|
||||
// - ExtKeyUsage
|
||||
// - UnknownExtKeyUsage
|
||||
// - BasicConstraintsValid
|
||||
// - IsCA
|
||||
// - MaxPathLen
|
||||
// - MaxPathLenZero
|
||||
// - SubjectKeyId
|
||||
// - PolicyIdentifiers
|
||||
// - ExtraExtensions
|
||||
// - Attributes (deprecated)
|
||||
//
|
||||
@ -2799,30 +2715,6 @@ func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error
|
||||
if err != nil {
|
||||
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) {
|
||||
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{
|
||||
KeyUsage: KeyUsageCertSign,
|
||||
ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageAny},
|
||||
UnknownExtKeyUsage: []asn1.ObjectIdentifier{{1, 2, 3}},
|
||||
BasicConstraintsValid: true,
|
||||
IsCA: true,
|
||||
MaxPathLen: 0,
|
||||
MaxPathLenZero: true,
|
||||
SubjectKeyId: []byte{1, 2, 3},
|
||||
PolicyIdentifiers: []asn1.ObjectIdentifier{{1, 2, 3}},
|
||||
DNSNames: []string{"example.com", "example.org"},
|
||||
EmailAddresses: []string{"a@example.com", "b@example.com"},
|
||||
IPAddresses: []net.IP{net.IPv4(192, 0, 2, 0), net.IPv6loopback},
|
||||
URIs: []*url.URL{urlA, urlB},
|
||||
}
|
||||
out := marshalAndParseCSR(t, in)
|
||||
|
||||
if in.KeyUsage != out.KeyUsage {
|
||||
t.Fatalf("Unexpected KeyUsage: got %v, want %v", out.KeyUsage, in.KeyUsage)
|
||||
if !reflect.DeepEqual(in.DNSNames, out.DNSNames) {
|
||||
t.Fatalf("Unexpected DNSNames: got %v, want %v", out.DNSNames, in.DNSNames)
|
||||
}
|
||||
if !reflect.DeepEqual(in.ExtKeyUsage, out.ExtKeyUsage) {
|
||||
t.Fatalf("Unexpected ExtKeyUsage: got %v, want %v", out.ExtKeyUsage, in.ExtKeyUsage)
|
||||
if !reflect.DeepEqual(in.EmailAddresses, out.EmailAddresses) {
|
||||
t.Fatalf("Unexpected EmailAddresses: got %v, want %v", out.EmailAddresses, in.EmailAddresses)
|
||||
}
|
||||
if !reflect.DeepEqual(in.UnknownExtKeyUsage, out.UnknownExtKeyUsage) {
|
||||
t.Fatalf("Unexpected UnknownExtKeyUsage: got %v, want %v", out.UnknownExtKeyUsage, in.UnknownExtKeyUsage)
|
||||
if len(in.IPAddresses) != len(out.IPAddresses) ||
|
||||
!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 {
|
||||
t.Fatalf("Unexpected BasicConstraintsValid: got %v, want %v", out.BasicConstraintsValid, in.BasicConstraintsValid)
|
||||
}
|
||||
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)
|
||||
if !reflect.DeepEqual(in.URIs, out.URIs) {
|
||||
t.Fatalf("Unexpected URIs: got %v, want %v", out.URIs, in.URIs)
|
||||
}
|
||||
}
|
||||
|
@ -244,6 +244,9 @@ func (f FS) lookup(name string) *file {
|
||||
if name == "." {
|
||||
return dotFile
|
||||
}
|
||||
if f.files == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Binary search to find where name would be in the list,
|
||||
// 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.
|
||||
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
|
||||
// and then return that slice of the list.
|
||||
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")
|
||||
}
|
||||
|
||||
func TestLocal(t *testing.T) {
|
||||
//go:embed testdata/k*.txt
|
||||
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")
|
||||
}
|
||||
//go:embed testdata
|
||||
var testDirAll embed.FS
|
||||
|
||||
func TestDir(t *testing.T) {
|
||||
//go:embed testdata
|
||||
var all embed.FS
|
||||
|
||||
all := testDirAll
|
||||
testFiles(t, all, "testdata/hello.txt", "hello, world\n")
|
||||
testFiles(t, all, "testdata/i/i18n.txt", "internationalization\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")
|
||||
}
|
||||
|
||||
func TestHidden(t *testing.T) {
|
||||
//go:embed testdata
|
||||
var dir embed.FS
|
||||
//go:embed testdata
|
||||
var testHiddenDir embed.FS
|
||||
|
||||
//go:embed testdata/*
|
||||
var star embed.FS
|
||||
//go:embed testdata/*
|
||||
var testHiddenStar embed.FS
|
||||
|
||||
func TestHidden(t *testing.T) {
|
||||
dir := testHiddenDir
|
||||
star := testHiddenStar
|
||||
|
||||
t.Logf("//go:embed testdata")
|
||||
|
||||
@ -122,3 +112,20 @@ func TestHidden(t *testing.T) {
|
||||
testDir(t, star, "testdata/.hidden",
|
||||
"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
|
||||
}
|
||||
|
||||
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
|
||||
// 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
|
||||
// ASN1 contents of the struct will be stored in it.
|
||||
//
|
||||
|
@ -11,13 +11,13 @@ import (
|
||||
"go/ast"
|
||||
"go/doc"
|
||||
"go/token"
|
||||
exec "internal/execabs"
|
||||
"internal/goroot"
|
||||
"internal/goversion"
|
||||
"io"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
pathpkg "path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
@ -451,9 +451,12 @@ type Package struct {
|
||||
// //go:embed a* b.c
|
||||
// then the list will contain those two strings as separate entries.
|
||||
// (See package embed for more details about //go:embed.)
|
||||
EmbedPatterns []string // patterns from GoFiles, CgoFiles
|
||||
TestEmbedPatterns []string // patterns from TestGoFiles
|
||||
XTestEmbedPatterns []string // patterns from XTestGoFiles
|
||||
EmbedPatterns []string // patterns from GoFiles, CgoFiles
|
||||
EmbedPatternPos map[string][]token.Position // line information for EmbedPatterns
|
||||
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
|
||||
@ -796,10 +799,12 @@ Found:
|
||||
var badGoError error
|
||||
var Sfiles []string // files with ".S"(capital S)/.sx(capital s equivalent for case insensitive filesystems)
|
||||
var firstFile, firstCommentFile string
|
||||
var embeds, testEmbeds, xTestEmbeds []string
|
||||
imported := make(map[string][]token.Position)
|
||||
testImported := make(map[string][]token.Position)
|
||||
xTestImported := make(map[string][]token.Position)
|
||||
embedPos := make(map[string][]token.Position)
|
||||
testEmbedPos := make(map[string][]token.Position)
|
||||
xTestEmbedPos := 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)
|
||||
fset := token.NewFileSet()
|
||||
for _, d := range dirs {
|
||||
@ -922,31 +927,31 @@ Found:
|
||||
}
|
||||
}
|
||||
|
||||
var fileList, embedList *[]string
|
||||
var importMap map[string][]token.Position
|
||||
var fileList *[]string
|
||||
var importMap, embedMap map[string][]token.Position
|
||||
switch {
|
||||
case isCgo:
|
||||
allTags["cgo"] = true
|
||||
if ctxt.CgoEnabled {
|
||||
fileList = &p.CgoFiles
|
||||
importMap = imported
|
||||
embedList = &embeds
|
||||
importMap = importPos
|
||||
embedMap = embedPos
|
||||
} else {
|
||||
// Ignore imports from cgo files if cgo is disabled.
|
||||
// Ignore imports and embeds from cgo files if cgo is disabled.
|
||||
fileList = &p.IgnoredGoFiles
|
||||
}
|
||||
case isXTest:
|
||||
fileList = &p.XTestGoFiles
|
||||
importMap = xTestImported
|
||||
embedList = &xTestEmbeds
|
||||
importMap = xTestImportPos
|
||||
embedMap = xTestEmbedPos
|
||||
case isTest:
|
||||
fileList = &p.TestGoFiles
|
||||
importMap = testImported
|
||||
embedList = &testEmbeds
|
||||
importMap = testImportPos
|
||||
embedMap = testEmbedPos
|
||||
default:
|
||||
fileList = &p.GoFiles
|
||||
importMap = imported
|
||||
embedList = &embeds
|
||||
importMap = importPos
|
||||
embedMap = embedPos
|
||||
}
|
||||
*fileList = append(*fileList, name)
|
||||
if importMap != nil {
|
||||
@ -954,8 +959,10 @@ Found:
|
||||
importMap[imp.path] = append(importMap[imp.path], fset.Position(imp.pos))
|
||||
}
|
||||
}
|
||||
if embedList != nil {
|
||||
*embedList = append(*embedList, info.embeds...)
|
||||
if embedMap != nil {
|
||||
for _, emb := range info.embeds {
|
||||
embedMap[emb.pattern] = append(embedMap[emb.pattern], emb.pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -964,13 +971,13 @@ Found:
|
||||
}
|
||||
sort.Strings(p.AllTags)
|
||||
|
||||
p.EmbedPatterns = uniq(embeds)
|
||||
p.TestEmbedPatterns = uniq(testEmbeds)
|
||||
p.XTestEmbedPatterns = uniq(xTestEmbeds)
|
||||
p.EmbedPatterns, p.EmbedPatternPos = cleanDecls(embedPos)
|
||||
p.TestEmbedPatterns, p.TestEmbedPatternPos = cleanDecls(testEmbedPos)
|
||||
p.XTestEmbedPatterns, p.XTestEmbedPatternPos = cleanDecls(xTestEmbedPos)
|
||||
|
||||
p.Imports, p.ImportPos = cleanImports(imported)
|
||||
p.TestImports, p.TestImportPos = cleanImports(testImported)
|
||||
p.XTestImports, p.XTestImportPos = cleanImports(xTestImported)
|
||||
p.Imports, p.ImportPos = cleanDecls(importPos)
|
||||
p.TestImports, p.TestImportPos = cleanDecls(testImportPos)
|
||||
p.XTestImports, p.XTestImportPos = cleanDecls(xTestImportPos)
|
||||
|
||||
// add the .S/.sx files only if we are using cgo
|
||||
// (which means gcc will compile them).
|
||||
@ -1342,7 +1349,7 @@ type fileInfo struct {
|
||||
parsed *ast.File
|
||||
parseErr error
|
||||
imports []fileImport
|
||||
embeds []string
|
||||
embeds []fileEmbed
|
||||
embedErr error
|
||||
}
|
||||
|
||||
@ -1352,6 +1359,11 @@ type fileImport struct {
|
||||
doc *ast.CommentGroup
|
||||
}
|
||||
|
||||
type fileEmbed struct {
|
||||
pattern string
|
||||
pos token.Position
|
||||
}
|
||||
|
||||
// matchFile determines whether the file with the given name in the given directory
|
||||
// should be included in the package being constructed.
|
||||
// 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
|
||||
}
|
||||
|
||||
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))
|
||||
for path := range m {
|
||||
all = append(all, path)
|
||||
|
@ -28,6 +28,7 @@ func TestMatch(t *testing.T) {
|
||||
ctxt := Default
|
||||
what := "default"
|
||||
match := func(tag string, want map[string]bool) {
|
||||
t.Helper()
|
||||
m := make(map[string]bool)
|
||||
if !ctxt.match(tag, m) {
|
||||
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) {
|
||||
t.Helper()
|
||||
m := make(map[string]bool)
|
||||
if ctxt.match(tag, m) {
|
||||
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})
|
||||
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("!", map[string]bool{})
|
||||
}
|
||||
|
||||
func TestDotSlashImport(t *testing.T) {
|
||||
|
574
libgo/go/go/build/constraint/expr.go
Normal file
574
libgo/go/go/build/constraint/expr.go
Normal file
@ -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)
|
||||
}
|
317
libgo/go/go/build/constraint/expr_test.go
Normal file
317
libgo/go/go/build/constraint/expr_test.go
Normal file
@ -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 (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/token"
|
||||
"internal/testenv"
|
||||
"io/fs"
|
||||
"os"
|
||||
@ -162,6 +163,9 @@ var depsRules = `
|
||||
< os
|
||||
< os/signal;
|
||||
|
||||
io/fs
|
||||
< embed;
|
||||
|
||||
unicode, fmt !< os, os/signal;
|
||||
|
||||
os/signal, STR
|
||||
@ -174,7 +178,7 @@ var depsRules = `
|
||||
reflect !< 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.
|
||||
# It does not include package log, which should be avoided in core packages.
|
||||
@ -190,6 +194,12 @@ var depsRules = `
|
||||
|
||||
log !< FMT;
|
||||
|
||||
OS, FMT
|
||||
< internal/execabs;
|
||||
|
||||
OS, internal/execabs
|
||||
< internal/goroot;
|
||||
|
||||
# Misc packages needing only FMT.
|
||||
FMT
|
||||
< flag,
|
||||
@ -278,6 +288,9 @@ var depsRules = `
|
||||
container/heap, go/constant, go/parser
|
||||
< go/types;
|
||||
|
||||
FMT
|
||||
< go/build/constraint;
|
||||
|
||||
go/doc, go/parser, internal/goroot, internal/goversion
|
||||
< go/build;
|
||||
|
||||
@ -602,6 +615,7 @@ func findImports(pkg string) ([]string, error) {
|
||||
}
|
||||
var imports []string
|
||||
var haveImport = map[string]bool{}
|
||||
fset := token.NewFileSet()
|
||||
for _, file := range files {
|
||||
name := file.Name()
|
||||
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") {
|
||||
continue
|
||||
}
|
||||
var info fileInfo
|
||||
info.name = filepath.Join(dir, name)
|
||||
info := fileInfo{
|
||||
name: filepath.Join(dir, name),
|
||||
fset: fset,
|
||||
}
|
||||
f, err := os.Open(info.name)
|
||||
if err != nil {
|
||||
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"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -24,6 +25,18 @@ type importReader struct {
|
||||
err error
|
||||
eof bool
|
||||
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 {
|
||||
@ -66,22 +79,32 @@ func (r *importReader) readByte() byte {
|
||||
// readByteNoBuf is like readByte but doesn't buffer the byte.
|
||||
// It exhausts r.buf before reading from r.b.
|
||||
func (r *importReader) readByteNoBuf() byte {
|
||||
var c byte
|
||||
var err error
|
||||
if len(r.buf) > 0 {
|
||||
c := r.buf[0]
|
||||
c = r.buf[0]
|
||||
r.buf = r.buf[1:]
|
||||
return c
|
||||
}
|
||||
c, err := r.b.ReadByte()
|
||||
if err == nil && c == 0 {
|
||||
err = errNUL
|
||||
} else {
|
||||
c, err = r.b.ReadByte()
|
||||
if err == nil && c == 0 {
|
||||
err = errNUL
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
r.eof = true
|
||||
} else if r.err == nil {
|
||||
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
|
||||
}
|
||||
@ -171,6 +194,41 @@ func (r *importReader) findEmbed(first bool) bool {
|
||||
case ' ', '\t':
|
||||
// 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 '/':
|
||||
c = r.readByteNoBuf()
|
||||
switch c {
|
||||
@ -288,7 +346,7 @@ func (r *importReader) readImport() {
|
||||
// readComments is like io.ReadAll, except that it only reads the leading
|
||||
// block of comments in the file.
|
||||
func readComments(f io.Reader) ([]byte, error) {
|
||||
r := &importReader{b: bufio.NewReader(f)}
|
||||
r := newImportReader("", f)
|
||||
r.peekByte(true)
|
||||
if r.err == nil && !r.eof {
|
||||
// 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,
|
||||
// not for syntax errors in the file itself.
|
||||
func readGoInfo(f io.Reader, info *fileInfo) error {
|
||||
r := &importReader{b: bufio.NewReader(f)}
|
||||
r := newImportReader(info.name, f)
|
||||
|
||||
r.readKeyword("package")
|
||||
r.readIdent()
|
||||
@ -393,6 +451,7 @@ func readGoInfo(f io.Reader, info *fileInfo) error {
|
||||
var line []byte
|
||||
for first := true; r.findEmbed(first); first = false {
|
||||
line = line[:0]
|
||||
pos := r.pos
|
||||
for {
|
||||
c := r.readByteNoBuf()
|
||||
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.
|
||||
// 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.
|
||||
args, err := parseGoEmbed(string(line))
|
||||
embs, err := parseGoEmbed(string(line), pos)
|
||||
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.
|
||||
// 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.
|
||||
func parseGoEmbed(args string) ([]string, error) {
|
||||
var list []string
|
||||
for args = strings.TrimSpace(args); args != ""; args = strings.TrimSpace(args) {
|
||||
// This is based on a similar function in cmd/compile/internal/gc/noder.go;
|
||||
// this version calculates position information as well.
|
||||
func parseGoEmbed(args string, pos token.Position) ([]fileEmbed, error) {
|
||||
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
|
||||
pathPos := pos
|
||||
Switch:
|
||||
switch args[0] {
|
||||
default:
|
||||
@ -431,7 +502,7 @@ func parseGoEmbed(args string) ([]string, error) {
|
||||
}
|
||||
}
|
||||
path = args[:i]
|
||||
args = args[i:]
|
||||
trimBytes(i)
|
||||
|
||||
case '`':
|
||||
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)
|
||||
}
|
||||
path = args[1 : 1+i]
|
||||
args = args[1+i+1:]
|
||||
trimBytes(1 + i + 1)
|
||||
|
||||
case '"':
|
||||
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])
|
||||
}
|
||||
path = q
|
||||
args = args[i+1:]
|
||||
trimBytes(i + 1)
|
||||
break Switch
|
||||
}
|
||||
}
|
||||
@ -469,7 +540,7 @@ func parseGoEmbed(args string) ([]string, error) {
|
||||
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
|
||||
}
|
||||
|
@ -5,9 +5,9 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/token"
|
||||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
@ -228,55 +228,94 @@ func TestReadFailuresIgnored(t *testing.T) {
|
||||
}
|
||||
|
||||
var readEmbedTests = []struct {
|
||||
in string
|
||||
out []string
|
||||
in, out string
|
||||
}{
|
||||
{
|
||||
"package p\n",
|
||||
nil,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"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",
|
||||
[]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",
|
||||
[]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",
|
||||
[]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",
|
||||
[]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
|
||||
nil,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"package p\n//go:embed x y z\nvar files embed.FS", // no import, no scan
|
||||
nil,
|
||||
"",
|
||||
},
|
||||
}
|
||||
|
||||
func TestReadEmbed(t *testing.T) {
|
||||
fset := token.NewFileSet()
|
||||
for i, tt := range readEmbedTests {
|
||||
var info fileInfo
|
||||
info.fset = fset
|
||||
info := fileInfo{
|
||||
name: "test",
|
||||
fset: fset,
|
||||
}
|
||||
err := readGoInfo(strings.NewReader(tt.in), &info)
|
||||
if err != nil {
|
||||
t.Errorf("#%d: %v", i, err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(info.embeds, tt.out) {
|
||||
t.Errorf("#%d: embeds=%v, want %v", i, info.embeds, tt.out)
|
||||
b := &strings.Builder{}
|
||||
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 (
|
||||
"bufio"
|
||||
"go/types"
|
||||
exec "internal/execabs"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
@ -13,9 +13,9 @@ import (
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"go/types"
|
||||
exec "internal/execabs"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user