Initial commit: Go 1.23 release state
This commit is contained in:
374
src/cmd/go/internal/imports/build.go
Normal file
374
src/cmd/go/internal/imports/build.go
Normal file
@@ -0,0 +1,374 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
// Copied from Go distribution src/go/build/build.go, syslist.go.
|
||||
// That package does not export the ability to process raw file data,
|
||||
// although we could fake it with an appropriate build.Context
|
||||
// and a lot of unwrapping.
|
||||
// More importantly, that package does not implement the tags["*"]
|
||||
// special case, in which both tag and !tag are considered to be true
|
||||
// for essentially all tags (except "ignore").
|
||||
//
|
||||
// If we added this API to go/build directly, we wouldn't need this
|
||||
// file anymore, but this API is not terribly general-purpose and we
|
||||
// don't really want to commit to any public form of it, nor do we
|
||||
// want to move the core parts of go/build into a top-level internal package.
|
||||
// These details change very infrequently, so the copy is fine.
|
||||
|
||||
package imports
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmd/go/internal/cfg"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/build/constraint"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
var (
|
||||
bSlashSlash = []byte("//")
|
||||
bStarSlash = []byte("*/")
|
||||
bSlashStar = []byte("/*")
|
||||
bPlusBuild = []byte("+build")
|
||||
|
||||
goBuildComment = []byte("//go:build")
|
||||
|
||||
errMultipleGoBuild = errors.New("multiple //go:build comments")
|
||||
)
|
||||
|
||||
func isGoBuildComment(line []byte) bool {
|
||||
if !bytes.HasPrefix(line, goBuildComment) {
|
||||
return false
|
||||
}
|
||||
line = bytes.TrimSpace(line)
|
||||
rest := line[len(goBuildComment):]
|
||||
return len(rest) == 0 || len(bytes.TrimSpace(rest)) < len(rest)
|
||||
}
|
||||
|
||||
// ShouldBuild reports whether it is okay to use this file,
|
||||
// The rule is that in the file's leading run of // comments
|
||||
// and blank lines, which must be followed by a blank line
|
||||
// (to avoid including a Go package clause doc comment),
|
||||
// lines beginning with '// +build' are taken as build directives.
|
||||
//
|
||||
// The file is accepted only if each such line lists something
|
||||
// matching the file. For example:
|
||||
//
|
||||
// // +build windows linux
|
||||
//
|
||||
// marks the file as applicable only on Windows and Linux.
|
||||
//
|
||||
// If tags["*"] is true, then ShouldBuild will consider every
|
||||
// build tag except "ignore" to be both true and false for
|
||||
// the purpose of satisfying build tags, in order to estimate
|
||||
// (conservatively) whether a file could ever possibly be used
|
||||
// in any build.
|
||||
func ShouldBuild(content []byte, tags map[string]bool) bool {
|
||||
// Identify leading run of // comments and blank lines,
|
||||
// which must be followed by a blank line.
|
||||
// Also identify any //go:build comments.
|
||||
content, goBuild, _, err := parseFileHeader(content)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// If //go:build line is present, it controls.
|
||||
// Otherwise fall back to +build processing.
|
||||
var shouldBuild bool
|
||||
switch {
|
||||
case goBuild != nil:
|
||||
x, err := constraint.Parse(string(goBuild))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
shouldBuild = eval(x, tags, true)
|
||||
|
||||
default:
|
||||
shouldBuild = true
|
||||
p := content
|
||||
for len(p) > 0 {
|
||||
line := p
|
||||
if i := bytes.IndexByte(line, '\n'); i >= 0 {
|
||||
line, p = line[:i], p[i+1:]
|
||||
} else {
|
||||
p = p[len(p):]
|
||||
}
|
||||
line = bytes.TrimSpace(line)
|
||||
if !bytes.HasPrefix(line, bSlashSlash) || !bytes.Contains(line, bPlusBuild) {
|
||||
continue
|
||||
}
|
||||
text := string(line)
|
||||
if !constraint.IsPlusBuild(text) {
|
||||
continue
|
||||
}
|
||||
if x, err := constraint.Parse(text); err == nil {
|
||||
if !eval(x, tags, true) {
|
||||
shouldBuild = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return shouldBuild
|
||||
}
|
||||
|
||||
func parseFileHeader(content []byte) (trimmed, goBuild []byte, sawBinaryOnly bool, err error) {
|
||||
end := 0
|
||||
p := content
|
||||
ended := false // found non-blank, non-// line, so stopped accepting // +build lines
|
||||
inSlashStar := false // in /* */ comment
|
||||
|
||||
Lines:
|
||||
for len(p) > 0 {
|
||||
line := p
|
||||
if i := bytes.IndexByte(line, '\n'); i >= 0 {
|
||||
line, p = line[:i], p[i+1:]
|
||||
} else {
|
||||
p = p[len(p):]
|
||||
}
|
||||
line = bytes.TrimSpace(line)
|
||||
if len(line) == 0 && !ended { // Blank line
|
||||
// Remember position of most recent blank line.
|
||||
// When we find the first non-blank, non-// line,
|
||||
// this "end" position marks the latest file position
|
||||
// where a // +build line can appear.
|
||||
// (It must appear _before_ a blank line before the non-blank, non-// line.
|
||||
// Yes, that's confusing, which is part of why we moved to //go:build lines.)
|
||||
// Note that ended==false here means that inSlashStar==false,
|
||||
// since seeing a /* would have set ended==true.
|
||||
end = len(content) - len(p)
|
||||
continue Lines
|
||||
}
|
||||
if !bytes.HasPrefix(line, bSlashSlash) { // Not comment line
|
||||
ended = true
|
||||
}
|
||||
|
||||
if !inSlashStar && isGoBuildComment(line) {
|
||||
if goBuild != nil {
|
||||
return nil, nil, false, errMultipleGoBuild
|
||||
}
|
||||
goBuild = line
|
||||
}
|
||||
|
||||
Comments:
|
||||
for len(line) > 0 {
|
||||
if inSlashStar {
|
||||
if i := bytes.Index(line, bStarSlash); i >= 0 {
|
||||
inSlashStar = false
|
||||
line = bytes.TrimSpace(line[i+len(bStarSlash):])
|
||||
continue Comments
|
||||
}
|
||||
continue Lines
|
||||
}
|
||||
if bytes.HasPrefix(line, bSlashSlash) {
|
||||
continue Lines
|
||||
}
|
||||
if bytes.HasPrefix(line, bSlashStar) {
|
||||
inSlashStar = true
|
||||
line = bytes.TrimSpace(line[len(bSlashStar):])
|
||||
continue Comments
|
||||
}
|
||||
// Found non-comment text.
|
||||
break Lines
|
||||
}
|
||||
}
|
||||
|
||||
return content[:end], goBuild, sawBinaryOnly, nil
|
||||
}
|
||||
|
||||
// matchTag reports whether the tag name is valid and tags[name] is true.
|
||||
// As a special case, if tags["*"] is true and name is not empty or ignore,
|
||||
// then matchTag will return prefer instead of the actual answer,
|
||||
// which allows the caller to pretend in that case that most tags are
|
||||
// both true and false.
|
||||
func matchTag(name string, tags map[string]bool, prefer bool) bool {
|
||||
// Tags must be letters, digits, underscores or dots.
|
||||
// Unlike in Go identifiers, all digits are fine (e.g., "386").
|
||||
for _, c := range name {
|
||||
if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' && c != '.' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if tags["*"] && name != "" && name != "ignore" {
|
||||
// Special case for gathering all possible imports:
|
||||
// if we put * in the tags map then all tags
|
||||
// except "ignore" are considered both present and not
|
||||
// (so we return true no matter how 'want' is set).
|
||||
return prefer
|
||||
}
|
||||
|
||||
if tags[name] {
|
||||
return true
|
||||
}
|
||||
|
||||
switch name {
|
||||
case "linux":
|
||||
return tags["android"]
|
||||
case "solaris":
|
||||
return tags["illumos"]
|
||||
case "darwin":
|
||||
return tags["ios"]
|
||||
case "unix":
|
||||
return unixOS[cfg.BuildContext.GOOS]
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// eval is like
|
||||
//
|
||||
// x.Eval(func(tag string) bool { return matchTag(tag, tags) })
|
||||
//
|
||||
// except that it implements the special case for tags["*"] meaning
|
||||
// all tags are both true and false at the same time.
|
||||
func eval(x constraint.Expr, tags map[string]bool, prefer bool) bool {
|
||||
switch x := x.(type) {
|
||||
case *constraint.TagExpr:
|
||||
return matchTag(x.Tag, tags, prefer)
|
||||
case *constraint.NotExpr:
|
||||
return !eval(x.X, tags, !prefer)
|
||||
case *constraint.AndExpr:
|
||||
return eval(x.X, tags, prefer) && eval(x.Y, tags, prefer)
|
||||
case *constraint.OrExpr:
|
||||
return eval(x.X, tags, prefer) || eval(x.Y, tags, prefer)
|
||||
}
|
||||
panic(fmt.Sprintf("unexpected constraint expression %T", x))
|
||||
}
|
||||
|
||||
// Eval is like
|
||||
//
|
||||
// x.Eval(func(tag string) bool { return matchTag(tag, tags) })
|
||||
//
|
||||
// except that it implements the special case for tags["*"] meaning
|
||||
// all tags are both true and false at the same time.
|
||||
func Eval(x constraint.Expr, tags map[string]bool, prefer bool) bool {
|
||||
return eval(x, tags, prefer)
|
||||
}
|
||||
|
||||
// MatchFile returns false if the name contains a $GOOS or $GOARCH
|
||||
// suffix which does not match the current system.
|
||||
// The recognized name formats are:
|
||||
//
|
||||
// name_$(GOOS).*
|
||||
// name_$(GOARCH).*
|
||||
// name_$(GOOS)_$(GOARCH).*
|
||||
// name_$(GOOS)_test.*
|
||||
// name_$(GOARCH)_test.*
|
||||
// name_$(GOOS)_$(GOARCH)_test.*
|
||||
//
|
||||
// Exceptions:
|
||||
//
|
||||
// if GOOS=android, then files with GOOS=linux are also matched.
|
||||
// if GOOS=illumos, then files with GOOS=solaris are also matched.
|
||||
// if GOOS=ios, then files with GOOS=darwin are also matched.
|
||||
//
|
||||
// If tags["*"] is true, then MatchFile will consider all possible
|
||||
// GOOS and GOARCH to be available and will consequently
|
||||
// always return true.
|
||||
func MatchFile(name string, tags map[string]bool) bool {
|
||||
if tags["*"] {
|
||||
return true
|
||||
}
|
||||
if dot := strings.Index(name, "."); dot != -1 {
|
||||
name = name[:dot]
|
||||
}
|
||||
|
||||
// Before Go 1.4, a file called "linux.go" would be equivalent to having a
|
||||
// build tag "linux" in that file. For Go 1.4 and beyond, we require this
|
||||
// auto-tagging to apply only to files with a non-empty prefix, so
|
||||
// "foo_linux.go" is tagged but "linux.go" is not. This allows new operating
|
||||
// systems, such as android, to arrive without breaking existing code with
|
||||
// innocuous source code in "android.go". The easiest fix: cut everything
|
||||
// in the name before the initial _.
|
||||
i := strings.Index(name, "_")
|
||||
if i < 0 {
|
||||
return true
|
||||
}
|
||||
name = name[i:] // ignore everything before first _
|
||||
|
||||
l := strings.Split(name, "_")
|
||||
if n := len(l); n > 0 && l[n-1] == "test" {
|
||||
l = l[:n-1]
|
||||
}
|
||||
n := len(l)
|
||||
if n >= 2 && KnownOS[l[n-2]] && KnownArch[l[n-1]] {
|
||||
return matchTag(l[n-2], tags, true) && matchTag(l[n-1], tags, true)
|
||||
}
|
||||
if n >= 1 && KnownOS[l[n-1]] {
|
||||
return matchTag(l[n-1], tags, true)
|
||||
}
|
||||
if n >= 1 && KnownArch[l[n-1]] {
|
||||
return matchTag(l[n-1], tags, true)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
var KnownOS = map[string]bool{
|
||||
"aix": true,
|
||||
"android": true,
|
||||
"darwin": true,
|
||||
"dragonfly": true,
|
||||
"freebsd": true,
|
||||
"hurd": true,
|
||||
"illumos": true,
|
||||
"ios": true,
|
||||
"js": true,
|
||||
"linux": true,
|
||||
"nacl": true, // legacy; don't remove
|
||||
"netbsd": true,
|
||||
"openbsd": true,
|
||||
"plan9": true,
|
||||
"solaris": true,
|
||||
"wasip1": true,
|
||||
"windows": true,
|
||||
"zos": true,
|
||||
}
|
||||
|
||||
// unixOS is the set of GOOS values matched by the "unix" build tag.
|
||||
// This is not used for filename matching.
|
||||
// This is the same list as in go/build/syslist.go and cmd/dist/build.go.
|
||||
var unixOS = map[string]bool{
|
||||
"aix": true,
|
||||
"android": true,
|
||||
"darwin": true,
|
||||
"dragonfly": true,
|
||||
"freebsd": true,
|
||||
"hurd": true,
|
||||
"illumos": true,
|
||||
"ios": true,
|
||||
"linux": true,
|
||||
"netbsd": true,
|
||||
"openbsd": true,
|
||||
"solaris": true,
|
||||
}
|
||||
|
||||
var KnownArch = map[string]bool{
|
||||
"386": true,
|
||||
"amd64": true,
|
||||
"amd64p32": true, // legacy; don't remove
|
||||
"arm": true,
|
||||
"armbe": true,
|
||||
"arm64": true,
|
||||
"arm64be": true,
|
||||
"ppc64": true,
|
||||
"ppc64le": true,
|
||||
"mips": true,
|
||||
"mipsle": true,
|
||||
"mips64": true,
|
||||
"mips64le": true,
|
||||
"mips64p32": true,
|
||||
"mips64p32le": true,
|
||||
"loong64": true,
|
||||
"ppc": true,
|
||||
"riscv": true,
|
||||
"riscv64": true,
|
||||
"s390": true,
|
||||
"s390x": true,
|
||||
"sparc": true,
|
||||
"sparc64": true,
|
||||
"wasm": true,
|
||||
}
|
||||
263
src/cmd/go/internal/imports/read.go
Normal file
263
src/cmd/go/internal/imports/read.go
Normal file
@@ -0,0 +1,263 @@
|
||||
// Copyright 2012 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.
|
||||
|
||||
// Copied from Go distribution src/go/build/read.go.
|
||||
|
||||
package imports
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
type importReader struct {
|
||||
b *bufio.Reader
|
||||
buf []byte
|
||||
peek byte
|
||||
err error
|
||||
eof bool
|
||||
nerr int
|
||||
}
|
||||
|
||||
var bom = []byte{0xef, 0xbb, 0xbf}
|
||||
|
||||
func newImportReader(b *bufio.Reader) *importReader {
|
||||
// Remove leading UTF-8 BOM.
|
||||
// Per https://golang.org/ref/spec#Source_code_representation:
|
||||
// a compiler may ignore a UTF-8-encoded byte order mark (U+FEFF)
|
||||
// if it is the first Unicode code point in the source text.
|
||||
if leadingBytes, err := b.Peek(3); err == nil && bytes.Equal(leadingBytes, bom) {
|
||||
b.Discard(3)
|
||||
}
|
||||
return &importReader{b: b}
|
||||
}
|
||||
|
||||
func isIdent(c byte) bool {
|
||||
return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '_' || c >= utf8.RuneSelf
|
||||
}
|
||||
|
||||
var (
|
||||
errSyntax = errors.New("syntax error")
|
||||
errNUL = errors.New("unexpected NUL in input")
|
||||
)
|
||||
|
||||
// syntaxError records a syntax error, but only if an I/O error has not already been recorded.
|
||||
func (r *importReader) syntaxError() {
|
||||
if r.err == nil {
|
||||
r.err = errSyntax
|
||||
}
|
||||
}
|
||||
|
||||
// readByte reads the next byte from the input, saves it in buf, and returns it.
|
||||
// If an error occurs, readByte records the error in r.err and returns 0.
|
||||
func (r *importReader) readByte() byte {
|
||||
c, err := r.b.ReadByte()
|
||||
if err == nil {
|
||||
r.buf = append(r.buf, c)
|
||||
if 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 c
|
||||
}
|
||||
|
||||
// peekByte returns the next byte from the input reader but does not advance beyond it.
|
||||
// If skipSpace is set, peekByte skips leading spaces and comments.
|
||||
func (r *importReader) peekByte(skipSpace bool) byte {
|
||||
if r.err != nil {
|
||||
if r.nerr++; r.nerr > 10000 {
|
||||
panic("go/build: import reader looping")
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Use r.peek as first input byte.
|
||||
// Don't just return r.peek here: it might have been left by peekByte(false)
|
||||
// and this might be peekByte(true).
|
||||
c := r.peek
|
||||
if c == 0 {
|
||||
c = r.readByte()
|
||||
}
|
||||
for r.err == nil && !r.eof {
|
||||
if skipSpace {
|
||||
// For the purposes of this reader, semicolons are never necessary to
|
||||
// understand the input and are treated as spaces.
|
||||
switch c {
|
||||
case ' ', '\f', '\t', '\r', '\n', ';':
|
||||
c = r.readByte()
|
||||
continue
|
||||
|
||||
case '/':
|
||||
c = r.readByte()
|
||||
if c == '/' {
|
||||
for c != '\n' && r.err == nil && !r.eof {
|
||||
c = r.readByte()
|
||||
}
|
||||
} else if c == '*' {
|
||||
var c1 byte
|
||||
for (c != '*' || c1 != '/') && r.err == nil {
|
||||
if r.eof {
|
||||
r.syntaxError()
|
||||
}
|
||||
c, c1 = c1, r.readByte()
|
||||
}
|
||||
} else {
|
||||
r.syntaxError()
|
||||
}
|
||||
c = r.readByte()
|
||||
continue
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
r.peek = c
|
||||
return r.peek
|
||||
}
|
||||
|
||||
// nextByte is like peekByte but advances beyond the returned byte.
|
||||
func (r *importReader) nextByte(skipSpace bool) byte {
|
||||
c := r.peekByte(skipSpace)
|
||||
r.peek = 0
|
||||
return c
|
||||
}
|
||||
|
||||
// readKeyword reads the given keyword from the input.
|
||||
// If the keyword is not present, readKeyword records a syntax error.
|
||||
func (r *importReader) readKeyword(kw string) {
|
||||
r.peekByte(true)
|
||||
for i := 0; i < len(kw); i++ {
|
||||
if r.nextByte(false) != kw[i] {
|
||||
r.syntaxError()
|
||||
return
|
||||
}
|
||||
}
|
||||
if isIdent(r.peekByte(false)) {
|
||||
r.syntaxError()
|
||||
}
|
||||
}
|
||||
|
||||
// readIdent reads an identifier from the input.
|
||||
// If an identifier is not present, readIdent records a syntax error.
|
||||
func (r *importReader) readIdent() {
|
||||
c := r.peekByte(true)
|
||||
if !isIdent(c) {
|
||||
r.syntaxError()
|
||||
return
|
||||
}
|
||||
for isIdent(r.peekByte(false)) {
|
||||
r.peek = 0
|
||||
}
|
||||
}
|
||||
|
||||
// readString reads a quoted string literal from the input.
|
||||
// If an identifier is not present, readString records a syntax error.
|
||||
func (r *importReader) readString(save *[]string) {
|
||||
switch r.nextByte(true) {
|
||||
case '`':
|
||||
start := len(r.buf) - 1
|
||||
for r.err == nil {
|
||||
if r.nextByte(false) == '`' {
|
||||
if save != nil {
|
||||
*save = append(*save, string(r.buf[start:]))
|
||||
}
|
||||
break
|
||||
}
|
||||
if r.eof {
|
||||
r.syntaxError()
|
||||
}
|
||||
}
|
||||
case '"':
|
||||
start := len(r.buf) - 1
|
||||
for r.err == nil {
|
||||
c := r.nextByte(false)
|
||||
if c == '"' {
|
||||
if save != nil {
|
||||
*save = append(*save, string(r.buf[start:]))
|
||||
}
|
||||
break
|
||||
}
|
||||
if r.eof || c == '\n' {
|
||||
r.syntaxError()
|
||||
}
|
||||
if c == '\\' {
|
||||
r.nextByte(false)
|
||||
}
|
||||
}
|
||||
default:
|
||||
r.syntaxError()
|
||||
}
|
||||
}
|
||||
|
||||
// readImport reads an import clause - optional identifier followed by quoted string -
|
||||
// from the input.
|
||||
func (r *importReader) readImport(imports *[]string) {
|
||||
c := r.peekByte(true)
|
||||
if c == '.' {
|
||||
r.peek = 0
|
||||
} else if isIdent(c) {
|
||||
r.readIdent()
|
||||
}
|
||||
r.readString(imports)
|
||||
}
|
||||
|
||||
// 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 := newImportReader(bufio.NewReader(f))
|
||||
r.peekByte(true)
|
||||
if r.err == nil && !r.eof {
|
||||
// Didn't reach EOF, so must have found a non-space byte. Remove it.
|
||||
r.buf = r.buf[:len(r.buf)-1]
|
||||
}
|
||||
return r.buf, r.err
|
||||
}
|
||||
|
||||
// ReadImports is like io.ReadAll, except that it expects a Go file as input
|
||||
// and stops reading the input once the imports have completed.
|
||||
func ReadImports(f io.Reader, reportSyntaxError bool, imports *[]string) ([]byte, error) {
|
||||
r := newImportReader(bufio.NewReader(f))
|
||||
|
||||
r.readKeyword("package")
|
||||
r.readIdent()
|
||||
for r.peekByte(true) == 'i' {
|
||||
r.readKeyword("import")
|
||||
if r.peekByte(true) == '(' {
|
||||
r.nextByte(false)
|
||||
for r.peekByte(true) != ')' && r.err == nil {
|
||||
r.readImport(imports)
|
||||
}
|
||||
r.nextByte(false)
|
||||
} else {
|
||||
r.readImport(imports)
|
||||
}
|
||||
}
|
||||
|
||||
// If we stopped successfully before EOF, we read a byte that told us we were done.
|
||||
// Return all but that last byte, which would cause a syntax error if we let it through.
|
||||
if r.err == nil && !r.eof {
|
||||
return r.buf[:len(r.buf)-1], nil
|
||||
}
|
||||
|
||||
// If we stopped for a syntax error, consume the whole file so that
|
||||
// we are sure we don't change the errors that go/parser returns.
|
||||
if r.err == errSyntax && !reportSyntaxError {
|
||||
r.err = nil
|
||||
for r.err == nil && !r.eof {
|
||||
r.readByte()
|
||||
}
|
||||
}
|
||||
|
||||
return r.buf, r.err
|
||||
}
|
||||
254
src/cmd/go/internal/imports/read_test.go
Normal file
254
src/cmd/go/internal/imports/read_test.go
Normal file
@@ -0,0 +1,254 @@
|
||||
// Copyright 2012 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.
|
||||
|
||||
// Copied from Go distribution src/go/build/read.go.
|
||||
|
||||
package imports
|
||||
|
||||
import (
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const quote = "`"
|
||||
|
||||
type readTest struct {
|
||||
// Test input contains ℙ where readImports should stop.
|
||||
in string
|
||||
err string
|
||||
}
|
||||
|
||||
var readImportsTests = []readTest{
|
||||
{
|
||||
`package p`,
|
||||
"",
|
||||
},
|
||||
{
|
||||
`package p; import "x"`,
|
||||
"",
|
||||
},
|
||||
{
|
||||
`package p; import . "x"`,
|
||||
"",
|
||||
},
|
||||
{
|
||||
`package p; import "x";ℙvar x = 1`,
|
||||
"",
|
||||
},
|
||||
{
|
||||
`package p
|
||||
|
||||
// comment
|
||||
|
||||
import "x"
|
||||
import _ "x"
|
||||
import a "x"
|
||||
|
||||
/* comment */
|
||||
|
||||
import (
|
||||
"x" /* comment */
|
||||
_ "x"
|
||||
a "x" // comment
|
||||
` + quote + `x` + quote + `
|
||||
_ /*comment*/ ` + quote + `x` + quote + `
|
||||
a ` + quote + `x` + quote + `
|
||||
)
|
||||
import (
|
||||
)
|
||||
import ()
|
||||
import()import()import()
|
||||
import();import();import()
|
||||
|
||||
ℙvar x = 1
|
||||
`,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"\ufeff𝔻" + `package p; import "x";ℙvar x = 1`,
|
||||
"",
|
||||
},
|
||||
}
|
||||
|
||||
var readCommentsTests = []readTest{
|
||||
{
|
||||
`ℙpackage p`,
|
||||
"",
|
||||
},
|
||||
{
|
||||
`ℙpackage p; import "x"`,
|
||||
"",
|
||||
},
|
||||
{
|
||||
`ℙpackage p; import . "x"`,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"\ufeff𝔻" + `ℙpackage p; import . "x"`,
|
||||
"",
|
||||
},
|
||||
{
|
||||
`// foo
|
||||
|
||||
/* bar */
|
||||
|
||||
/* quux */ // baz
|
||||
|
||||
/*/ zot */
|
||||
|
||||
// asdf
|
||||
ℙHello, world`,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"\ufeff𝔻" + `// foo
|
||||
|
||||
/* bar */
|
||||
|
||||
/* quux */ // baz
|
||||
|
||||
/*/ zot */
|
||||
|
||||
// asdf
|
||||
ℙHello, world`,
|
||||
"",
|
||||
},
|
||||
}
|
||||
|
||||
func testRead(t *testing.T, tests []readTest, read func(io.Reader) ([]byte, error)) {
|
||||
for i, tt := range tests {
|
||||
var in, testOut string
|
||||
j := strings.Index(tt.in, "ℙ")
|
||||
if j < 0 {
|
||||
in = tt.in
|
||||
testOut = tt.in
|
||||
} else {
|
||||
in = tt.in[:j] + tt.in[j+len("ℙ"):]
|
||||
testOut = tt.in[:j]
|
||||
}
|
||||
d := strings.Index(tt.in, "𝔻")
|
||||
if d >= 0 {
|
||||
in = in[:d] + in[d+len("𝔻"):]
|
||||
testOut = testOut[d+len("𝔻"):]
|
||||
}
|
||||
r := strings.NewReader(in)
|
||||
buf, err := read(r)
|
||||
if err != nil {
|
||||
if tt.err == "" {
|
||||
t.Errorf("#%d: err=%q, expected success (%q)", i, err, string(buf))
|
||||
continue
|
||||
}
|
||||
if !strings.Contains(err.Error(), tt.err) {
|
||||
t.Errorf("#%d: err=%q, expected %q", i, err, tt.err)
|
||||
continue
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err == nil && tt.err != "" {
|
||||
t.Errorf("#%d: success, expected %q", i, tt.err)
|
||||
continue
|
||||
}
|
||||
|
||||
out := string(buf)
|
||||
if out != testOut {
|
||||
t.Errorf("#%d: wrong output:\nhave %q\nwant %q\n", i, out, testOut)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadImports(t *testing.T) {
|
||||
testRead(t, readImportsTests, func(r io.Reader) ([]byte, error) { return ReadImports(r, true, nil) })
|
||||
}
|
||||
|
||||
func TestReadComments(t *testing.T) {
|
||||
testRead(t, readCommentsTests, ReadComments)
|
||||
}
|
||||
|
||||
var readFailuresTests = []readTest{
|
||||
{
|
||||
`package`,
|
||||
"syntax error",
|
||||
},
|
||||
{
|
||||
"package p\n\x00\nimport `math`\n",
|
||||
"unexpected NUL in input",
|
||||
},
|
||||
{
|
||||
`package p; import`,
|
||||
"syntax error",
|
||||
},
|
||||
{
|
||||
`package p; import "`,
|
||||
"syntax error",
|
||||
},
|
||||
{
|
||||
"package p; import ` \n\n",
|
||||
"syntax error",
|
||||
},
|
||||
{
|
||||
`package p; import "x`,
|
||||
"syntax error",
|
||||
},
|
||||
{
|
||||
`package p; import _`,
|
||||
"syntax error",
|
||||
},
|
||||
{
|
||||
`package p; import _ "`,
|
||||
"syntax error",
|
||||
},
|
||||
{
|
||||
`package p; import _ "x`,
|
||||
"syntax error",
|
||||
},
|
||||
{
|
||||
`package p; import .`,
|
||||
"syntax error",
|
||||
},
|
||||
{
|
||||
`package p; import . "`,
|
||||
"syntax error",
|
||||
},
|
||||
{
|
||||
`package p; import . "x`,
|
||||
"syntax error",
|
||||
},
|
||||
{
|
||||
`package p; import (`,
|
||||
"syntax error",
|
||||
},
|
||||
{
|
||||
`package p; import ("`,
|
||||
"syntax error",
|
||||
},
|
||||
{
|
||||
`package p; import ("x`,
|
||||
"syntax error",
|
||||
},
|
||||
{
|
||||
`package p; import ("x"`,
|
||||
"syntax error",
|
||||
},
|
||||
}
|
||||
|
||||
func TestReadFailures(t *testing.T) {
|
||||
// Errors should be reported (true arg to readImports).
|
||||
testRead(t, readFailuresTests, func(r io.Reader) ([]byte, error) { return ReadImports(r, true, nil) })
|
||||
}
|
||||
|
||||
func TestReadFailuresIgnored(t *testing.T) {
|
||||
// Syntax errors should not be reported (false arg to readImports).
|
||||
// Instead, entire file should be the output and no error.
|
||||
// Convert tests not to return syntax errors.
|
||||
tests := make([]readTest, len(readFailuresTests))
|
||||
copy(tests, readFailuresTests)
|
||||
for i := range tests {
|
||||
tt := &tests[i]
|
||||
if !strings.Contains(tt.err, "NUL") {
|
||||
tt.err = ""
|
||||
}
|
||||
}
|
||||
testRead(t, tests, func(r io.Reader) ([]byte, error) { return ReadImports(r, false, nil) })
|
||||
}
|
||||
107
src/cmd/go/internal/imports/scan.go
Normal file
107
src/cmd/go/internal/imports/scan.go
Normal file
@@ -0,0 +1,107 @@
|
||||
// Copyright 2018 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 imports
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"cmd/go/internal/fsys"
|
||||
)
|
||||
|
||||
func ScanDir(dir string, tags map[string]bool) ([]string, []string, error) {
|
||||
infos, err := fsys.ReadDir(dir)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
var files []string
|
||||
for _, info := range infos {
|
||||
name := info.Name()
|
||||
|
||||
// If the directory entry is a symlink, stat it to obtain the info for the
|
||||
// link target instead of the link itself.
|
||||
if info.Mode()&fs.ModeSymlink != 0 {
|
||||
info, err = fsys.Stat(filepath.Join(dir, name))
|
||||
if err != nil {
|
||||
continue // Ignore broken symlinks.
|
||||
}
|
||||
}
|
||||
|
||||
if info.Mode().IsRegular() && !strings.HasPrefix(name, "_") && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") && MatchFile(name, tags) {
|
||||
files = append(files, filepath.Join(dir, name))
|
||||
}
|
||||
}
|
||||
return scanFiles(files, tags, false)
|
||||
}
|
||||
|
||||
func ScanFiles(files []string, tags map[string]bool) ([]string, []string, error) {
|
||||
return scanFiles(files, tags, true)
|
||||
}
|
||||
|
||||
func scanFiles(files []string, tags map[string]bool, explicitFiles bool) ([]string, []string, error) {
|
||||
imports := make(map[string]bool)
|
||||
testImports := make(map[string]bool)
|
||||
numFiles := 0
|
||||
Files:
|
||||
for _, name := range files {
|
||||
r, err := fsys.Open(name)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
var list []string
|
||||
data, err := ReadImports(r, false, &list)
|
||||
r.Close()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("reading %s: %v", name, err)
|
||||
}
|
||||
|
||||
// import "C" is implicit requirement of cgo tag.
|
||||
// When listing files on the command line (explicitFiles=true)
|
||||
// we do not apply build tag filtering but we still do apply
|
||||
// cgo filtering, so no explicitFiles check here.
|
||||
// Why? Because we always have, and it's not worth breaking
|
||||
// that behavior now.
|
||||
for _, path := range list {
|
||||
if path == `"C"` && !tags["cgo"] && !tags["*"] {
|
||||
continue Files
|
||||
}
|
||||
}
|
||||
|
||||
if !explicitFiles && !ShouldBuild(data, tags) {
|
||||
continue
|
||||
}
|
||||
numFiles++
|
||||
m := imports
|
||||
if strings.HasSuffix(name, "_test.go") {
|
||||
m = testImports
|
||||
}
|
||||
for _, p := range list {
|
||||
q, err := strconv.Unquote(p)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
m[q] = true
|
||||
}
|
||||
}
|
||||
if numFiles == 0 {
|
||||
return nil, nil, ErrNoGo
|
||||
}
|
||||
return keys(imports), keys(testImports), nil
|
||||
}
|
||||
|
||||
var ErrNoGo = fmt.Errorf("no Go source files")
|
||||
|
||||
func keys(m map[string]bool) []string {
|
||||
var list []string
|
||||
for k := range m {
|
||||
list = append(list, k)
|
||||
}
|
||||
sort.Strings(list)
|
||||
return list
|
||||
}
|
||||
93
src/cmd/go/internal/imports/scan_test.go
Normal file
93
src/cmd/go/internal/imports/scan_test.go
Normal file
@@ -0,0 +1,93 @@
|
||||
// Copyright 2018 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 imports
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"internal/testenv"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestScan(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
imports, testImports, err := ScanDir(filepath.Join(testenv.GOROOT(t), "src/encoding/json"), Tags())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
foundBase64 := false
|
||||
for _, p := range imports {
|
||||
if p == "encoding/base64" {
|
||||
foundBase64 = true
|
||||
}
|
||||
if p == "encoding/binary" {
|
||||
// A dependency but not an import
|
||||
t.Errorf("json reported as importing encoding/binary but does not")
|
||||
}
|
||||
if p == "net/http" {
|
||||
// A test import but not an import
|
||||
t.Errorf("json reported as importing net/http but does not")
|
||||
}
|
||||
}
|
||||
if !foundBase64 {
|
||||
t.Errorf("json missing import encoding/base64 (%q)", imports)
|
||||
}
|
||||
|
||||
foundHTTP := false
|
||||
for _, p := range testImports {
|
||||
if p == "net/http" {
|
||||
foundHTTP = true
|
||||
}
|
||||
if p == "unicode/utf16" {
|
||||
// A package import but not a test import
|
||||
t.Errorf("json reported as test-importing unicode/utf16 but does not")
|
||||
}
|
||||
}
|
||||
if !foundHTTP {
|
||||
t.Errorf("json missing test import net/http (%q)", testImports)
|
||||
}
|
||||
}
|
||||
func TestScanDir(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
dirs, err := os.ReadDir("testdata")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, dir := range dirs {
|
||||
if !dir.IsDir() || strings.HasPrefix(dir.Name(), ".") {
|
||||
continue
|
||||
}
|
||||
t.Run(dir.Name(), func(t *testing.T) {
|
||||
tagsData, err := os.ReadFile(filepath.Join("testdata", dir.Name(), "tags.txt"))
|
||||
if err != nil {
|
||||
t.Fatalf("error reading tags: %v", err)
|
||||
}
|
||||
tags := make(map[string]bool)
|
||||
for _, t := range strings.Fields(string(tagsData)) {
|
||||
tags[t] = true
|
||||
}
|
||||
|
||||
wantData, err := os.ReadFile(filepath.Join("testdata", dir.Name(), "want.txt"))
|
||||
if err != nil {
|
||||
t.Fatalf("error reading want: %v", err)
|
||||
}
|
||||
want := string(bytes.TrimSpace(wantData))
|
||||
|
||||
imports, _, err := ScanDir(path.Join("testdata", dir.Name()), tags)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got := strings.Join(imports, "\n")
|
||||
if got != want {
|
||||
t.Errorf("ScanDir: got imports:\n%s\n\nwant:\n%s", got, want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
61
src/cmd/go/internal/imports/tags.go
Normal file
61
src/cmd/go/internal/imports/tags.go
Normal file
@@ -0,0 +1,61 @@
|
||||
// Copyright 2018 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 imports
|
||||
|
||||
import (
|
||||
"cmd/go/internal/cfg"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
tags map[string]bool
|
||||
tagsOnce sync.Once
|
||||
)
|
||||
|
||||
// Tags returns a set of build tags that are true for the target platform.
|
||||
// It includes GOOS, GOARCH, the compiler, possibly "cgo",
|
||||
// release tags like "go1.13", and user-specified build tags.
|
||||
func Tags() map[string]bool {
|
||||
tagsOnce.Do(func() {
|
||||
tags = loadTags()
|
||||
})
|
||||
return tags
|
||||
}
|
||||
|
||||
func loadTags() map[string]bool {
|
||||
tags := map[string]bool{
|
||||
cfg.BuildContext.GOOS: true,
|
||||
cfg.BuildContext.GOARCH: true,
|
||||
cfg.BuildContext.Compiler: true,
|
||||
}
|
||||
if cfg.BuildContext.CgoEnabled {
|
||||
tags["cgo"] = true
|
||||
}
|
||||
for _, tag := range cfg.BuildContext.BuildTags {
|
||||
tags[tag] = true
|
||||
}
|
||||
for _, tag := range cfg.BuildContext.ToolTags {
|
||||
tags[tag] = true
|
||||
}
|
||||
for _, tag := range cfg.BuildContext.ReleaseTags {
|
||||
tags[tag] = true
|
||||
}
|
||||
return tags
|
||||
}
|
||||
|
||||
var (
|
||||
anyTags map[string]bool
|
||||
anyTagsOnce sync.Once
|
||||
)
|
||||
|
||||
// AnyTags returns a special set of build tags that satisfy nearly all
|
||||
// build tag expressions. Only "ignore" and malformed build tag requirements
|
||||
// are considered false.
|
||||
func AnyTags() map[string]bool {
|
||||
anyTagsOnce.Do(func() {
|
||||
anyTags = map[string]bool{"*": true}
|
||||
})
|
||||
return anyTags
|
||||
}
|
||||
3
src/cmd/go/internal/imports/testdata/android/.h.go
vendored
Normal file
3
src/cmd/go/internal/imports/testdata/android/.h.go
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
package android
|
||||
|
||||
import _ "h"
|
||||
3
src/cmd/go/internal/imports/testdata/android/a_android.go
vendored
Normal file
3
src/cmd/go/internal/imports/testdata/android/a_android.go
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
package android
|
||||
|
||||
import _ "a"
|
||||
3
src/cmd/go/internal/imports/testdata/android/b_android_arm64.go
vendored
Normal file
3
src/cmd/go/internal/imports/testdata/android/b_android_arm64.go
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
package android
|
||||
|
||||
import _ "b"
|
||||
3
src/cmd/go/internal/imports/testdata/android/c_linux.go
vendored
Normal file
3
src/cmd/go/internal/imports/testdata/android/c_linux.go
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
package android
|
||||
|
||||
import _ "c"
|
||||
3
src/cmd/go/internal/imports/testdata/android/d_linux_arm64.go
vendored
Normal file
3
src/cmd/go/internal/imports/testdata/android/d_linux_arm64.go
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
package android
|
||||
|
||||
import _ "d"
|
||||
6
src/cmd/go/internal/imports/testdata/android/e.go
vendored
Normal file
6
src/cmd/go/internal/imports/testdata/android/e.go
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
//go:build android
|
||||
// +build android
|
||||
|
||||
package android
|
||||
|
||||
import _ "e"
|
||||
6
src/cmd/go/internal/imports/testdata/android/f.go
vendored
Normal file
6
src/cmd/go/internal/imports/testdata/android/f.go
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package android
|
||||
|
||||
import _ "f"
|
||||
6
src/cmd/go/internal/imports/testdata/android/g.go
vendored
Normal file
6
src/cmd/go/internal/imports/testdata/android/g.go
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
//go:build !android
|
||||
// +build !android
|
||||
|
||||
package android
|
||||
|
||||
import _ "g"
|
||||
1
src/cmd/go/internal/imports/testdata/android/tags.txt
vendored
Normal file
1
src/cmd/go/internal/imports/testdata/android/tags.txt
vendored
Normal file
@@ -0,0 +1 @@
|
||||
android arm64
|
||||
6
src/cmd/go/internal/imports/testdata/android/want.txt
vendored
Normal file
6
src/cmd/go/internal/imports/testdata/android/want.txt
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
a
|
||||
b
|
||||
c
|
||||
d
|
||||
e
|
||||
f
|
||||
3
src/cmd/go/internal/imports/testdata/illumos/.h.go
vendored
Normal file
3
src/cmd/go/internal/imports/testdata/illumos/.h.go
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
package android
|
||||
|
||||
import _ "h"
|
||||
3
src/cmd/go/internal/imports/testdata/illumos/a_illumos.go
vendored
Normal file
3
src/cmd/go/internal/imports/testdata/illumos/a_illumos.go
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
package illumos
|
||||
|
||||
import _ "a"
|
||||
3
src/cmd/go/internal/imports/testdata/illumos/b_illumos_amd64.go
vendored
Normal file
3
src/cmd/go/internal/imports/testdata/illumos/b_illumos_amd64.go
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
package illumos
|
||||
|
||||
import _ "b"
|
||||
3
src/cmd/go/internal/imports/testdata/illumos/c_solaris.go
vendored
Normal file
3
src/cmd/go/internal/imports/testdata/illumos/c_solaris.go
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
package illumos
|
||||
|
||||
import _ "c"
|
||||
3
src/cmd/go/internal/imports/testdata/illumos/d_solaris_amd64.go
vendored
Normal file
3
src/cmd/go/internal/imports/testdata/illumos/d_solaris_amd64.go
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
package illumos
|
||||
|
||||
import _ "d"
|
||||
6
src/cmd/go/internal/imports/testdata/illumos/e.go
vendored
Normal file
6
src/cmd/go/internal/imports/testdata/illumos/e.go
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
//go:build illumos
|
||||
// +build illumos
|
||||
|
||||
package illumos
|
||||
|
||||
import _ "e"
|
||||
6
src/cmd/go/internal/imports/testdata/illumos/f.go
vendored
Normal file
6
src/cmd/go/internal/imports/testdata/illumos/f.go
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
//go:build solaris
|
||||
// +build solaris
|
||||
|
||||
package illumos
|
||||
|
||||
import _ "f"
|
||||
6
src/cmd/go/internal/imports/testdata/illumos/g.go
vendored
Normal file
6
src/cmd/go/internal/imports/testdata/illumos/g.go
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
//go:build !illumos
|
||||
// +build !illumos
|
||||
|
||||
package illumos
|
||||
|
||||
import _ "g"
|
||||
1
src/cmd/go/internal/imports/testdata/illumos/tags.txt
vendored
Normal file
1
src/cmd/go/internal/imports/testdata/illumos/tags.txt
vendored
Normal file
@@ -0,0 +1 @@
|
||||
illumos amd64
|
||||
6
src/cmd/go/internal/imports/testdata/illumos/want.txt
vendored
Normal file
6
src/cmd/go/internal/imports/testdata/illumos/want.txt
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
a
|
||||
b
|
||||
c
|
||||
d
|
||||
e
|
||||
f
|
||||
1
src/cmd/go/internal/imports/testdata/star/tags.txt
vendored
Normal file
1
src/cmd/go/internal/imports/testdata/star/tags.txt
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*
|
||||
4
src/cmd/go/internal/imports/testdata/star/want.txt
vendored
Normal file
4
src/cmd/go/internal/imports/testdata/star/want.txt
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import1
|
||||
import2
|
||||
import3
|
||||
import4
|
||||
3
src/cmd/go/internal/imports/testdata/star/x.go
vendored
Normal file
3
src/cmd/go/internal/imports/testdata/star/x.go
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
package x
|
||||
|
||||
import "import1"
|
||||
6
src/cmd/go/internal/imports/testdata/star/x1.go
vendored
Normal file
6
src/cmd/go/internal/imports/testdata/star/x1.go
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
//go:build blahblh && linux && !linux && windows && darwin
|
||||
// +build blahblh,linux,!linux,windows,darwin
|
||||
|
||||
package x
|
||||
|
||||
import "import4"
|
||||
3
src/cmd/go/internal/imports/testdata/star/x_darwin.go
vendored
Normal file
3
src/cmd/go/internal/imports/testdata/star/x_darwin.go
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
package xxxx
|
||||
|
||||
import "import3"
|
||||
3
src/cmd/go/internal/imports/testdata/star/x_windows.go
vendored
Normal file
3
src/cmd/go/internal/imports/testdata/star/x_windows.go
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
package x
|
||||
|
||||
import "import2"
|
||||
Reference in New Issue
Block a user