libgo: update to go1.9

Reviewed-on: https://go-review.googlesource.com/63753

From-SVN: r252767
This commit is contained in:
Ian Lance Taylor 2017-09-14 17:11:35 +00:00 committed by Ian Lance Taylor
parent a41a6142df
commit bc998d034f
985 changed files with 56892 additions and 20449 deletions

View File

@ -1,4 +1,4 @@
199f175f4239d1ca6d7e80d08639955d41c3b09f
4e063a8eee636cce17aea48c7183e78431174de3
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.

View File

@ -1,10 +1,10 @@
// run
// Copyright 2010 The Go Authors. All rights reserved.
// Copyright 2010 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.
// http://code.google.com/p/go/issues/detail?id=589
// https://golang.org/issue/589
package main
@ -48,15 +48,6 @@ func bigcap() {
g1 = make([]block, 10, big)
}
var g3 map[block]block
func badmapcap() {
g3 = make(map[block]block, minus1)
}
func bigmapcap() {
g3 = make(map[block]block, big)
}
type cblock [1<<16-1]byte
var g4 chan cblock
@ -78,8 +69,6 @@ func main() {
shouldfail(badcap, "badcap")
shouldfail(badcap1, "badcap1")
shouldfail(bigcap, "bigcap")
shouldfail(badmapcap, "badmapcap")
shouldfail(bigmapcap, "bigmapcap")
shouldfail(badchancap, "badchancap")
shouldfail(bigchancap, "bigchancap")
shouldfail(overflowchan, "overflowchan")

View File

@ -1,3 +1,15 @@
2017-09-14 Ian Lance Taylor <iant@golang.org>
* Makefile.am (LIBGOTOOL): Define.
(go_cmd_go_files): Update for Go 1.9 release.
(go$(EXEEXT)): Depend on and link against $(LIBGOTOOL).
(CHECK_ENV): Add definition of shell variable fl.
(check-go-tool): Update for rearrangement of cmd/go sources in Go
1.9 release. Echo failure message if test fails.
(check-runtime): Echo failure message if test fails.
(check-cgo-test, check-carchive-test): Likewise.
* Makefile.in: Rebuild.
2017-08-30 Ian Lance Taylor <iant@golang.org>
* configure.ac: Substitute GOC_FOR_TARGET and GCC_FOR_TARGET.

View File

@ -28,6 +28,8 @@ STAMP = echo timestamp >
libgodir = ../$(target_noncanonical)/libgo
LIBGODEP = $(libgodir)/libgo.la
LIBGOTOOL = $(libgodir)/libgotool.a
if NATIVE
# Use the compiler we just built.
GOCOMPILER = $(GOC_FOR_TARGET) $(XGCC_FLAGS_FOR_TARGET)
@ -48,34 +50,8 @@ libgomiscdir = $(srcdir)/../libgo/misc
go_cmd_go_files = \
$(cmdsrcdir)/go/alldocs.go \
$(cmdsrcdir)/go/bug.go \
$(cmdsrcdir)/go/build.go \
$(cmdsrcdir)/go/clean.go \
$(cmdsrcdir)/go/context.go \
$(cmdsrcdir)/go/discovery.go \
$(cmdsrcdir)/go/doc.go \
$(cmdsrcdir)/go/env.go \
$(cmdsrcdir)/go/fix.go \
$(cmdsrcdir)/go/fmt.go \
$(cmdsrcdir)/go/generate.go \
$(cmdsrcdir)/go/get.go \
$(cmdsrcdir)/go/go11.go \
$(cmdsrcdir)/go/help.go \
$(cmdsrcdir)/go/http.go \
$(cmdsrcdir)/go/list.go \
$(cmdsrcdir)/go/main.go \
$(cmdsrcdir)/go/note.go \
$(cmdsrcdir)/go/pkg.go \
$(cmdsrcdir)/go/run.go \
$(cmdsrcdir)/go/signal.go \
$(cmdsrcdir)/go/signal_unix.go \
$(cmdsrcdir)/go/test.go \
$(cmdsrcdir)/go/testflag.go \
$(cmdsrcdir)/go/tool.go \
$(cmdsrcdir)/go/vcs.go \
$(cmdsrcdir)/go/version.go \
$(cmdsrcdir)/go/vet.go \
$(libgodir)/zstdpkglist.go
$(cmdsrcdir)/go/main.go
go_cmd_gofmt_files = \
$(cmdsrcdir)/gofmt/doc.go \
@ -124,8 +100,8 @@ bin_PROGRAMS = go$(EXEEXT) gofmt$(EXEEXT)
noinst_PROGRAMS = cgo$(EXEEXT)
man_MANS = go.1 gofmt.1
go$(EXEEXT): $(go_cmd_go_files) zdefaultcc.go $(LIBGODEP)
$(GOLINK) $(go_cmd_go_files) zdefaultcc.go $(LIBS) $(NET_LIBS)
go$(EXEEXT): $(go_cmd_go_files) $(LIBGOTOOL) $(LIBGODEP)
$(GOLINK) $(go_cmd_go_files) $(LIBGOTOOL) $(LIBS) $(NET_LIBS)
gofmt$(EXEEXT): $(go_cmd_gofmt_files) $(LIBGODEP)
$(GOLINK) $(go_cmd_gofmt_files) $(LIBS) $(NET_LIBS)
cgo$(EXEEXT): $(go_cmd_cgo_files) zdefaultcc.go $(LIBGODEP)
@ -175,6 +151,8 @@ check-gcc: Makefile
# CHECK_ENV sets up the environment to run the newly built go tool.
# If you change this, change ECHO_ENV, below.
# The fl shell variable is used to avoid having FAIL appear
# in the log unnecessarily.
CHECK_ENV = \
PATH=`echo $(abs_builddir):$${PATH} | sed 's,::*,:,g;s,^:*,,;s,:*$$,,'`; \
export PATH; \
@ -190,7 +168,8 @@ CHECK_ENV = \
LD_LIBRARY_PATH=`echo $${abs_libgodir}/.libs:$${LD_LIBRARY_PATH} | sed 's,::*,:,g;s,^:*,,;s,:*$$,,'`; \
export LD_LIBRARY_PATH; \
GOROOT=$${abs_libgodir}; \
export GOROOT;
export GOROOT; \
fl1="FA"; fl2="IL"; fl="$${fl1}$${fl2}";
# ECHO_ENV is a variant of CHECK_ENV to put into a testlog file.
# It assumes that abs_libgodir is set.
@ -201,16 +180,18 @@ check-go-tool: go$(EXEEXT) cgo$(EXEEXT) check-head check-gccgo check-gcc
rm -rf check-go-dir cmd_go-testlog
$(MKDIR_P) check-go-dir/src/cmd/go
cp $(cmdsrcdir)/go/*.go check-go-dir/src/cmd/go/
cp $(libgodir)/zstdpkglist.go check-go-dir/src/cmd/go/
cp zdefaultcc.go check-go-dir/src/cmd/go/
cp -r $(cmdsrcdir)/go/internal check-go-dir/src/cmd/go/
cp $(libgodir)/zstdpkglist.go check-go-dir/src/cmd/go/internal/load/
cp $(libgodir)/zdefaultcc.go check-go-dir/src/cmd/go/internal/cfg/
cp -r $(cmdsrcdir)/go/testdata check-go-dir/src/cmd/go/
cp -r $(cmdsrcdir)/internal check-go-dir/src/cmd/
@abs_libgodir=`cd $(libgodir) && $(PWD_COMMAND)`; \
abs_checkdir=`cd check-go-dir && $(PWD_COMMAND)`; \
echo "cd check-go-dir/src/cmd/go && $(ECHO_ENV) GOPATH=$${abs_checkdir} $(abs_builddir)/go$(EXEEXT) test -test.short -test.v" > cmd_go-testlog
$(CHECK_ENV) \
GOPATH=`cd check-go-dir && $(PWD_COMMAND)`; \
export GOPATH; \
(cd check-go-dir/src/cmd/go && $(abs_builddir)/go$(EXEEXT) test -test.short -test.v) > cmd_go-testlog 2>&1 || true
(cd check-go-dir/src/cmd/go && $(abs_builddir)/go$(EXEEXT) test -test.short -test.v) >> cmd_go-testlog 2>&1 || echo "--- $${fl} go test cmd/go (0.00s)" >> cmd_go-testlog
grep '^--- ' cmd_go-testlog | sed -e 's/^--- \(.*\) ([^)]*)$$/\1/'
# check-runtime runs `go test runtime` in our environment.
@ -232,7 +213,7 @@ check-runtime: go$(EXEEXT) cgo$(EXEEXT) check-head check-gccgo check-gcc
GOARCH=`$(abs_builddir)/go$(EXEEXT) env GOARCH`; \
GOOS=`$(abs_builddir)/go$(EXEEXT) env GOOS`; \
files=`$(SHELL) $(libgosrcdir)/../match.sh --goarch=$${GOARCH} --goos=$${GOOS} --srcdir=$(libgosrcdir)/runtime --extrafiles="$(libgodir)/runtime_sysinfo.go $(libgodir)/sigtab.go" --tag=libffi`; \
$(SHELL) $(libgosrcdir)/../testsuite/gotest --goarch=$${GOARCH} --goos=$${GOOS} --basedir=$(libgosrcdir)/.. --srcdir=$(libgosrcdir)/runtime --pkgpath=runtime --pkgfiles="$${files}" -test.v >> runtime-testlog 2>&1 || true
$(SHELL) $(libgosrcdir)/../testsuite/gotest --goarch=$${GOARCH} --goos=$${GOOS} --basedir=$(libgosrcdir)/.. --srcdir=$(libgosrcdir)/runtime --pkgpath=runtime --pkgfiles="$${files}" -test.v >> runtime-testlog 2>&1 || echo "--- $${fl} go test runtime (0.00s)" >> runtime-testlog
grep '^--- ' runtime-testlog | sed -e 's/^--- \(.*\) ([^)]*)$$/\1/'
# check-cgo-test runs `go test misc/cgo/test` in our environment.
@ -245,7 +226,7 @@ check-cgo-test: go$(EXEEXT) cgo$(EXEEXT) check-head check-gccgo check-gcc
$(CHECK_ENV) \
GOTRACEBACK=2; \
export GOTRACEBACK; \
(cd cgo-test-dir/misc/cgo/test && $(abs_builddir)/go$(EXEEXT) test -test.short -test.v) >> cgo-testlog 2>&1 || true
(cd cgo-test-dir/misc/cgo/test && $(abs_builddir)/go$(EXEEXT) test -test.short -test.v) >> cgo-testlog 2>&1 || echo "--- $${fl} go test misc/cgo/test (0.00s)" >> cgo-testlog
grep '^--- ' cgo-testlog | sed -e 's/^--- \(.*\) ([^)]*)$$/\1/'
# check-carchive-test runs `go test misc/cgo/testcarchive/carchive_test.go`
@ -259,7 +240,7 @@ check-carchive-test: go$(EXEEXT) cgo$(EXEEXT) check-head check-gccgo check-gcc
$(CHECK_ENV) \
LIBRARY_PATH=`echo $${abs_libgodir}/.libs:$${LIBRARY_PATH} | sed 's,::*,:,g;s,^:*,,;s,:*$$,,'`; \
export LIBRARY_PATH; \
(cd carchive-test-dir/misc/cgo/testcarchive && $(abs_builddir)/go$(EXEEXT) test -test.v carchive_test.go) >> carchive-testlog 2>&1 || true
(cd carchive-test-dir/misc/cgo/testcarchive && $(abs_builddir)/go$(EXEEXT) test -test.v carchive_test.go) >> carchive-testlog 2>&1 || echo "--- $${fl} go test misc/cgo/testcarchive (0.00s)" >> carchive-testlog
grep '^--- ' carchive-testlog | sed -e 's/^--- \(.*\) ([^)]*)$$/\1/'
# The check targets runs the tests and assembles the output files.

View File

@ -255,6 +255,7 @@ PWD_COMMAND = $${PWDCMD-pwd}
STAMP = echo timestamp >
libgodir = ../$(target_noncanonical)/libgo
LIBGODEP = $(libgodir)/libgo.la
LIBGOTOOL = $(libgodir)/libgotool.a
@NATIVE_FALSE@GOCOMPILER = $(GOC)
# Use the compiler we just built.
@ -268,34 +269,8 @@ cmdsrcdir = $(libgosrcdir)/cmd
libgomiscdir = $(srcdir)/../libgo/misc
go_cmd_go_files = \
$(cmdsrcdir)/go/alldocs.go \
$(cmdsrcdir)/go/bug.go \
$(cmdsrcdir)/go/build.go \
$(cmdsrcdir)/go/clean.go \
$(cmdsrcdir)/go/context.go \
$(cmdsrcdir)/go/discovery.go \
$(cmdsrcdir)/go/doc.go \
$(cmdsrcdir)/go/env.go \
$(cmdsrcdir)/go/fix.go \
$(cmdsrcdir)/go/fmt.go \
$(cmdsrcdir)/go/generate.go \
$(cmdsrcdir)/go/get.go \
$(cmdsrcdir)/go/go11.go \
$(cmdsrcdir)/go/help.go \
$(cmdsrcdir)/go/http.go \
$(cmdsrcdir)/go/list.go \
$(cmdsrcdir)/go/main.go \
$(cmdsrcdir)/go/note.go \
$(cmdsrcdir)/go/pkg.go \
$(cmdsrcdir)/go/run.go \
$(cmdsrcdir)/go/signal.go \
$(cmdsrcdir)/go/signal_unix.go \
$(cmdsrcdir)/go/test.go \
$(cmdsrcdir)/go/testflag.go \
$(cmdsrcdir)/go/tool.go \
$(cmdsrcdir)/go/vcs.go \
$(cmdsrcdir)/go/version.go \
$(cmdsrcdir)/go/vet.go \
$(libgodir)/zstdpkglist.go
$(cmdsrcdir)/go/main.go
go_cmd_gofmt_files = \
$(cmdsrcdir)/gofmt/doc.go \
@ -330,6 +305,8 @@ MOSTLYCLEANFILES = \
# CHECK_ENV sets up the environment to run the newly built go tool.
# If you change this, change ECHO_ENV, below.
# The fl shell variable is used to avoid having FAIL appear
# in the log unnecessarily.
@NATIVE_TRUE@CHECK_ENV = \
@NATIVE_TRUE@ PATH=`echo $(abs_builddir):$${PATH} | sed 's,::*,:,g;s,^:*,,;s,:*$$,,'`; \
@NATIVE_TRUE@ export PATH; \
@ -345,7 +322,8 @@ MOSTLYCLEANFILES = \
@NATIVE_TRUE@ LD_LIBRARY_PATH=`echo $${abs_libgodir}/.libs:$${LD_LIBRARY_PATH} | sed 's,::*,:,g;s,^:*,,;s,:*$$,,'`; \
@NATIVE_TRUE@ export LD_LIBRARY_PATH; \
@NATIVE_TRUE@ GOROOT=$${abs_libgodir}; \
@NATIVE_TRUE@ export GOROOT;
@NATIVE_TRUE@ export GOROOT; \
@NATIVE_TRUE@ fl1="FA"; fl2="IL"; fl="$${fl1}$${fl2}";
# ECHO_ENV is a variant of CHECK_ENV to put into a testlog file.
@ -598,8 +576,8 @@ distclean-generic:
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
@NATIVE_FALSE@uninstall-local:
@NATIVE_FALSE@install-exec-local:
@NATIVE_FALSE@uninstall-local:
clean: clean-am
clean-am: clean-binPROGRAMS clean-generic clean-noinstPROGRAMS \
@ -707,8 +685,8 @@ s-zdefaultcc: Makefile
mostlyclean-local:
rm -rf check-go-dir check-runtime-dir cgo-test-dir carchive-test-dir
@NATIVE_TRUE@go$(EXEEXT): $(go_cmd_go_files) zdefaultcc.go $(LIBGODEP)
@NATIVE_TRUE@ $(GOLINK) $(go_cmd_go_files) zdefaultcc.go $(LIBS) $(NET_LIBS)
@NATIVE_TRUE@go$(EXEEXT): $(go_cmd_go_files) $(LIBGOTOOL) $(LIBGODEP)
@NATIVE_TRUE@ $(GOLINK) $(go_cmd_go_files) $(LIBGOTOOL) $(LIBS) $(NET_LIBS)
@NATIVE_TRUE@gofmt$(EXEEXT): $(go_cmd_gofmt_files) $(LIBGODEP)
@NATIVE_TRUE@ $(GOLINK) $(go_cmd_gofmt_files) $(LIBS) $(NET_LIBS)
@NATIVE_TRUE@cgo$(EXEEXT): $(go_cmd_cgo_files) zdefaultcc.go $(LIBGODEP)
@ -761,16 +739,18 @@ mostlyclean-local:
@NATIVE_TRUE@ rm -rf check-go-dir cmd_go-testlog
@NATIVE_TRUE@ $(MKDIR_P) check-go-dir/src/cmd/go
@NATIVE_TRUE@ cp $(cmdsrcdir)/go/*.go check-go-dir/src/cmd/go/
@NATIVE_TRUE@ cp $(libgodir)/zstdpkglist.go check-go-dir/src/cmd/go/
@NATIVE_TRUE@ cp zdefaultcc.go check-go-dir/src/cmd/go/
@NATIVE_TRUE@ cp -r $(cmdsrcdir)/go/internal check-go-dir/src/cmd/go/
@NATIVE_TRUE@ cp $(libgodir)/zstdpkglist.go check-go-dir/src/cmd/go/internal/load/
@NATIVE_TRUE@ cp $(libgodir)/zdefaultcc.go check-go-dir/src/cmd/go/internal/cfg/
@NATIVE_TRUE@ cp -r $(cmdsrcdir)/go/testdata check-go-dir/src/cmd/go/
@NATIVE_TRUE@ cp -r $(cmdsrcdir)/internal check-go-dir/src/cmd/
@NATIVE_TRUE@ @abs_libgodir=`cd $(libgodir) && $(PWD_COMMAND)`; \
@NATIVE_TRUE@ abs_checkdir=`cd check-go-dir && $(PWD_COMMAND)`; \
@NATIVE_TRUE@ echo "cd check-go-dir/src/cmd/go && $(ECHO_ENV) GOPATH=$${abs_checkdir} $(abs_builddir)/go$(EXEEXT) test -test.short -test.v" > cmd_go-testlog
@NATIVE_TRUE@ $(CHECK_ENV) \
@NATIVE_TRUE@ GOPATH=`cd check-go-dir && $(PWD_COMMAND)`; \
@NATIVE_TRUE@ export GOPATH; \
@NATIVE_TRUE@ (cd check-go-dir/src/cmd/go && $(abs_builddir)/go$(EXEEXT) test -test.short -test.v) > cmd_go-testlog 2>&1 || true
@NATIVE_TRUE@ (cd check-go-dir/src/cmd/go && $(abs_builddir)/go$(EXEEXT) test -test.short -test.v) >> cmd_go-testlog 2>&1 || echo "--- $${fl} go test cmd/go (0.00s)" >> cmd_go-testlog
@NATIVE_TRUE@ grep '^--- ' cmd_go-testlog | sed -e 's/^--- \(.*\) ([^)]*)$$/\1/'
# check-runtime runs `go test runtime` in our environment.
@ -792,7 +772,7 @@ mostlyclean-local:
@NATIVE_TRUE@ GOARCH=`$(abs_builddir)/go$(EXEEXT) env GOARCH`; \
@NATIVE_TRUE@ GOOS=`$(abs_builddir)/go$(EXEEXT) env GOOS`; \
@NATIVE_TRUE@ files=`$(SHELL) $(libgosrcdir)/../match.sh --goarch=$${GOARCH} --goos=$${GOOS} --srcdir=$(libgosrcdir)/runtime --extrafiles="$(libgodir)/runtime_sysinfo.go $(libgodir)/sigtab.go" --tag=libffi`; \
@NATIVE_TRUE@ $(SHELL) $(libgosrcdir)/../testsuite/gotest --goarch=$${GOARCH} --goos=$${GOOS} --basedir=$(libgosrcdir)/.. --srcdir=$(libgosrcdir)/runtime --pkgpath=runtime --pkgfiles="$${files}" -test.v >> runtime-testlog 2>&1 || true
@NATIVE_TRUE@ $(SHELL) $(libgosrcdir)/../testsuite/gotest --goarch=$${GOARCH} --goos=$${GOOS} --basedir=$(libgosrcdir)/.. --srcdir=$(libgosrcdir)/runtime --pkgpath=runtime --pkgfiles="$${files}" -test.v >> runtime-testlog 2>&1 || echo "--- $${fl} go test runtime (0.00s)" >> runtime-testlog
@NATIVE_TRUE@ grep '^--- ' runtime-testlog | sed -e 's/^--- \(.*\) ([^)]*)$$/\1/'
# check-cgo-test runs `go test misc/cgo/test` in our environment.
@ -805,7 +785,7 @@ mostlyclean-local:
@NATIVE_TRUE@ $(CHECK_ENV) \
@NATIVE_TRUE@ GOTRACEBACK=2; \
@NATIVE_TRUE@ export GOTRACEBACK; \
@NATIVE_TRUE@ (cd cgo-test-dir/misc/cgo/test && $(abs_builddir)/go$(EXEEXT) test -test.short -test.v) >> cgo-testlog 2>&1 || true
@NATIVE_TRUE@ (cd cgo-test-dir/misc/cgo/test && $(abs_builddir)/go$(EXEEXT) test -test.short -test.v) >> cgo-testlog 2>&1 || echo "--- $${fl} go test misc/cgo/test (0.00s)" >> cgo-testlog
@NATIVE_TRUE@ grep '^--- ' cgo-testlog | sed -e 's/^--- \(.*\) ([^)]*)$$/\1/'
# check-carchive-test runs `go test misc/cgo/testcarchive/carchive_test.go`
@ -819,7 +799,7 @@ mostlyclean-local:
@NATIVE_TRUE@ $(CHECK_ENV) \
@NATIVE_TRUE@ LIBRARY_PATH=`echo $${abs_libgodir}/.libs:$${LIBRARY_PATH} | sed 's,::*,:,g;s,^:*,,;s,:*$$,,'`; \
@NATIVE_TRUE@ export LIBRARY_PATH; \
@NATIVE_TRUE@ (cd carchive-test-dir/misc/cgo/testcarchive && $(abs_builddir)/go$(EXEEXT) test -test.v carchive_test.go) >> carchive-testlog 2>&1 || true
@NATIVE_TRUE@ (cd carchive-test-dir/misc/cgo/testcarchive && $(abs_builddir)/go$(EXEEXT) test -test.v carchive_test.go) >> carchive-testlog 2>&1 || echo "--- $${fl} go test misc/cgo/testcarchive (0.00s)" >> carchive-testlog
@NATIVE_TRUE@ grep '^--- ' carchive-testlog | sed -e 's/^--- \(.*\) ([^)]*)$$/\1/'
# The check targets runs the tests and assembles the output files.

View File

@ -1,4 +1,4 @@
352996a381701cfa0c16e8de29cbde8f3922182f
c8aec4095e089ff6ac50d18e97c3f46561f14f48
The first line of this file holds the git revision number of the
last merge done from the master library sources.

View File

@ -117,6 +117,8 @@ toolexeclib_LTLIBRARIES = libgo.la
toolexeclib_LIBRARIES = libgobegin.a libgolibbegin.a
endif
noinst_LIBRARIES = libgotool.a
toolexeclibgo_DATA = \
bufio.gox \
bytes.gox \
@ -299,6 +301,7 @@ toolexeclibgomathdir = $(toolexeclibgodir)/math
toolexeclibgomath_DATA = \
math/big.gox \
math/bits.gox \
math/cmplx.gox \
math/rand.gox
@ -534,6 +537,21 @@ s-sigtab: $(srcdir)/mksigtab.sh gen-sysinfo.go
$(SHELL) $(srcdir)/mvifdiff.sh tmp-sigtab.go sigtab.go
$(STAMP) $@
GCCGO_INSTALL_NAME := $(shell echo gccgo|sed '$(program_transform_name)')
GCC_INSTALL_NAME := $(shell echo gcc|sed '$(program_transform_name)')
GXX_INSTALL_NAME := $(shell echo g++|sed '$(program_transform_name)')
zdefaultcc.go: s-zdefaultcc; @true
s-zdefaultcc: Makefile
echo 'package cfg' > zdefaultcc.go.tmp
echo >> zdefaultcc.go.tmp
echo 'const DefaultGCCGO = "$(bindir)/$(GCCGO_INSTALL_NAME)"' >> zdefaultcc.go.tmp
echo 'const DefaultCC = "$(GCC_INSTALL_NAME)"' >> zdefaultcc.go.tmp
echo 'const DefaultCXX = "$(GXX_INSTALL_NAME)"' >> zdefaultcc.go.tmp
echo 'const DefaultPkgConfig = "pkg-config"' >> zdefaultcc.go.tmp
$(SHELL) $(srcdir)/../move-if-change zdefaultcc.go.tmp zdefaultcc.go
$(STAMP) $@
# _Complex_lock and _Reader_lock are Go translations of some AIX system
# types and should not be exported back to C
# semt is a Go translation of the C type sem_t; it fails to convert on
@ -555,13 +573,13 @@ s-runtime-inc: runtime.lo Makefile
rm -f runtime.inc.tmp2 runtime.inc.tmp3
$(STAMP) $@
noinst_DATA = zstdpkglist.go
noinst_DATA = zstdpkglist.go zdefaultcc.go
# Generate the list of go std packages that were included in libgo
zstdpkglist.go: s-zstdpkglist; @true
s-zstdpkglist: Makefile
rm -f zstdpkglist.go.tmp
echo 'package main' > zstdpkglist.go.tmp
echo 'package load' > zstdpkglist.go.tmp
echo "" >> zstdpkglist.go.tmp
echo 'var stdpkg = map[string]bool{' >> zstdpkglist.go.tmp
echo $(libgo_go_objs) 'unsafe.lo' 'runtime/cgo.lo' | sed 's|[a-z0-9_/]*_c\.lo||g' | sed 's|\([a-z0-9_/]*\)\.lo|"\1": true,|g' >> zstdpkglist.go.tmp
@ -660,7 +678,6 @@ PACKAGES = \
archive/zip \
bufio \
bytes \
cmd/internal/browser \
compress/bzip2 \
compress/flate \
compress/gzip \
@ -724,6 +741,7 @@ PACKAGES = \
go/importer \
go/internal/gccgoimporter \
go/internal/gcimporter \
go/internal/srcimporter \
go/parser \
go/printer \
go/scanner \
@ -736,7 +754,10 @@ PACKAGES = \
golang_org/x/net/http2/hpack \
golang_org/x/net/idna \
golang_org/x/net/lex/httplex \
golang_org/x/net/proxy \
golang_org/x/text/secure/bidirule \
golang_org/x/text/transform \
golang_org/x/text/unicode/bidi \
golang_org/x/text/unicode/norm \
golang_org/x/text/width \
hash \
@ -756,7 +777,7 @@ PACKAGES = \
image/png \
index/suffixarray \
internal/nettrace \
internal/pprof/profile \
internal/poll \
internal/race \
internal/singleflight \
internal/syscall/unix \
@ -768,6 +789,7 @@ PACKAGES = \
log/syslog \
math \
math/big \
math/bits \
math/cmplx \
math/rand \
mime \
@ -804,7 +826,7 @@ PACKAGES = \
runtime/internal/atomic \
runtime/internal/sys \
runtime/pprof \
runtime/pprof/internal/protopprof \
runtime/pprof/internal/profile \
runtime/trace \
sort \
strconv \
@ -871,6 +893,37 @@ libgolibbegin_a_SOURCES = \
libgolibbegin_a_CFLAGS = $(AM_CFLAGS) -fPIC
GOTOOL_PACKAGES = \
cmd/go/internal/base \
cmd/go/internal/bug \
cmd/go/internal/buildid \
cmd/go/internal/cfg \
cmd/go/internal/clean \
cmd/go/internal/cmdflag \
cmd/go/internal/doc \
cmd/go/internal/envcmd \
cmd/go/internal/fix \
cmd/go/internal/fmtcmd \
cmd/go/internal/generate \
cmd/go/internal/get \
cmd/go/internal/help \
cmd/go/internal/list \
cmd/go/internal/load \
cmd/go/internal/run \
cmd/go/internal/str \
cmd/go/internal/test \
cmd/go/internal/tool \
cmd/go/internal/version \
cmd/go/internal/vet \
cmd/go/internal/web \
cmd/go/internal/work \
cmd/internal/browser \
cmd/internal/objabi
libgotool_a_SOURCES =
libgotool_a_DEPENDENCIES = $(addsuffix .lo,$(GOTOOL_PACKAGES))
libgotool_a_LIBADD = $(addsuffix .o,$(GOTOOL_PACKAGES))
# Make sure runtime.inc is built before compiling any .c file.
$(libgo_la_OBJECTS): runtime.inc
$(libgo_llgo_la_OBJECTS): runtime.inc
@ -925,7 +978,7 @@ GOBENCH =
CHECK = \
GC="$(GOC) $(GOCFLAGS) $($(subst /,_,$@)_GOCFLAGS) -L `${PWD_COMMAND}` -L `${PWD_COMMAND}`/.libs"; \
export GC; \
GOLIBS="$(MATH_LIBS) $(NET_LIBS) $(LIBS)"; \
GOLIBS="$(extra_check_libs_$(subst /,_,$(@D))) $(MATH_LIBS) $(NET_LIBS) $(LIBS)"; \
export GOLIBS; \
RUNTESTFLAGS="$(RUNTESTFLAGS)"; \
export RUNTESTFLAGS; \
@ -985,7 +1038,8 @@ CHECK_DEPS = \
$(toolexeclibgotesting_DATA) \
$(toolexeclibgotext_DATA) \
$(toolexeclibgotexttemplate_DATA) \
$(toolexeclibgounicode_DATA)
$(toolexeclibgounicode_DATA) \
$(noinst_LIBRARIES)
if GOC_IS_LLGO
CHECK_DEPS += libgo-llgo.la libgobegin-llgo.a
@ -1025,6 +1079,7 @@ endef
# This line expands PACKAGE_template once for each package name listed
# in $(PACKAGES).
$(foreach package,$(PACKAGES),$(eval $(call PACKAGE_template,$(package))))
$(foreach package,$(GOTOOL_PACKAGES),$(eval $(call PACKAGE_template,$(package))))
# Pass -ffp-contract=off, or 386-specific options, when building the
# math package. MATH_FLAG is defined in configure.ac.
@ -1066,6 +1121,17 @@ runtime_pprof_check_GOCFLAGS = -static-libgo -fno-inline
extra_go_files_runtime_internal_sys = version.go
runtime/internal/sys.lo.dep: $(extra_go_files_runtime_internal_sys)
extra_go_files_cmd_go_internal_cfg = zdefaultcc.go
cmd/go/internal/cfg.lo.dep: $(extra_go_files_cmd_go_internal_cfg)
extra_go_files_cmd_go_internal_load = zstdpkglist.go
cmd/go/internal/load.lo.dep: $(extra_go_files_cmd_go_internal_load)
extra_check_libs_cmd_go_internal_generate = $(abs_builddir)/libgotool.a
extra_check_libs_cmd_go_internal_get = $(abs_builddir)/libgotool.a
extra_check_libs_cmd_go_internal_load = $(abs_builddir)/libgotool.a
extra_check_libs_cmd_go_internal_work = $(abs_builddir)/libgotool.a
# FIXME: The following C files may as well move to the runtime
# directory and be treated like other C files.
@ -1177,6 +1243,11 @@ TEST_PACKAGES = \
unicode/check \
archive/tar/check \
archive/zip/check \
cmd/go/internal/generate/check \
cmd/go/internal/get/check \
cmd/go/internal/load/check \
cmd/go/internal/work/check \
cmd/internal/objabi/check \
compress/bzip2/check \
compress/flate/check \
compress/gzip/check \
@ -1230,6 +1301,7 @@ TEST_PACKAGES = \
go/format/check \
go/internal/gcimporter/check \
go/internal/gccgoimporter/check \
go/internal/srcimporter/check \
go/parser/check \
go/printer/check \
go/scanner/check \
@ -1243,6 +1315,7 @@ TEST_PACKAGES = \
golang_org/x/net/idna/check \
golang_org/x/net/lex/httplex/check \
$(golang_org_x_net_lif_check) \
golang_org/x/net/proxy/check \
$(golang_org_x_net_route_check) \
hash/adler32/check \
hash/crc32/check \
@ -1253,12 +1326,13 @@ TEST_PACKAGES = \
image/jpeg/check \
image/png/check \
index/suffixarray/check \
internal/pprof/profile/check \
internal/poll/check \
internal/singleflight/check \
internal/trace/check \
io/ioutil/check \
log/syslog/check \
math/big/check \
math/bits/check \
math/cmplx/check \
math/rand/check \
mime/multipart/check \
@ -1287,7 +1361,7 @@ TEST_PACKAGES = \
runtime/internal/atomic/check \
runtime/internal/sys/check \
runtime/pprof/check \
runtime/pprof/internal/protopprof/check \
runtime/pprof/internal/profile/check \
runtime/trace/check \
sync/atomic/check \
text/scanner/check \
@ -1413,7 +1487,7 @@ mostlyclean-local:
find . -name '*-testsum' -print | xargs rm -f
find . -name '*-testlog' -print | xargs rm -f
CLEANFILES = *.go *.c s-version libgo.sum libgo.log runtime.inc
CLEANFILES = *.go *.c s-* libgo.sum libgo.log runtime.inc
clean-local:
find . -name '*.la' -print | xargs $(LIBTOOL) --mode=clean rm -f

View File

@ -155,7 +155,7 @@ am__installdirs = "$(DESTDIR)$(toolexeclibdir)" \
"$(DESTDIR)$(toolexeclibgotextdir)" \
"$(DESTDIR)$(toolexeclibgotexttemplatedir)" \
"$(DESTDIR)$(toolexeclibgounicodedir)"
LIBRARIES = $(toolexeclib_LIBRARIES)
LIBRARIES = $(noinst_LIBRARIES) $(toolexeclib_LIBRARIES)
ARFLAGS = cru
libgobegin_llgo_a_AR = $(AR) $(ARFLAGS)
libgobegin_llgo_a_LIBADD =
@ -169,6 +169,9 @@ libgolibbegin_a_AR = $(AR) $(ARFLAGS)
libgolibbegin_a_LIBADD =
am_libgolibbegin_a_OBJECTS = libgolibbegin_a-go-libmain.$(OBJEXT)
libgolibbegin_a_OBJECTS = $(am_libgolibbegin_a_OBJECTS)
libgotool_a_AR = $(AR) $(ARFLAGS)
am_libgotool_a_OBJECTS =
libgotool_a_OBJECTS = $(am_libgotool_a_OBJECTS)
LTLIBRARIES = $(toolexeclib_LTLIBRARIES)
@LIBGO_IS_LINUX_TRUE@am__DEPENDENCIES_1 = syscall/clone_linux.lo
am__DEPENDENCIES_2 = $(addsuffix .lo,$(PACKAGES)) bytes/index.lo \
@ -229,8 +232,8 @@ LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
$(LDFLAGS) -o $@
SOURCES = $(libgobegin_llgo_a_SOURCES) $(libgobegin_a_SOURCES) \
$(libgolibbegin_a_SOURCES) $(libgo_llgo_la_SOURCES) \
$(libgo_la_SOURCES)
$(libgolibbegin_a_SOURCES) $(libgotool_a_SOURCES) \
$(libgo_llgo_la_SOURCES) $(libgo_la_SOURCES)
MULTISRCTOP =
MULTIBUILDTOP =
MULTIDIRS =
@ -518,6 +521,7 @@ FLAGS_TO_PASS = $(AM_MAKEFLAGS)
@GOC_IS_LLGO_TRUE@toolexeclib_LTLIBRARIES = libgo-llgo.la
@GOC_IS_LLGO_FALSE@toolexeclib_LIBRARIES = libgobegin.a libgolibbegin.a
@GOC_IS_LLGO_TRUE@toolexeclib_LIBRARIES = libgobegin-llgo.a
noinst_LIBRARIES = libgotool.a
toolexeclibgo_DATA = \
bufio.gox \
bytes.gox \
@ -681,6 +685,7 @@ toolexeclibgolog_DATA = \
toolexeclibgomathdir = $(toolexeclibgodir)/math
toolexeclibgomath_DATA = \
math/big.gox \
math/bits.gox \
math/cmplx.gox \
math/rand.gox
@ -809,7 +814,10 @@ runtime_files = \
$(rtems_task_variable_add_file) \
$(runtime_getncpu_file)
noinst_DATA = zstdpkglist.go
GCCGO_INSTALL_NAME := $(shell echo gccgo|sed '$(program_transform_name)')
GCC_INSTALL_NAME := $(shell echo gcc|sed '$(program_transform_name)')
GXX_INSTALL_NAME := $(shell echo g++|sed '$(program_transform_name)')
noinst_DATA = zstdpkglist.go zdefaultcc.go
@LIBGO_IS_LINUX_FALSE@syscall_epoll_file =
@LIBGO_IS_LINUX_TRUE@syscall_epoll_file = epoll.go
SYSINFO_FLAGS = \
@ -823,7 +831,6 @@ PACKAGES = \
archive/zip \
bufio \
bytes \
cmd/internal/browser \
compress/bzip2 \
compress/flate \
compress/gzip \
@ -887,6 +894,7 @@ PACKAGES = \
go/importer \
go/internal/gccgoimporter \
go/internal/gcimporter \
go/internal/srcimporter \
go/parser \
go/printer \
go/scanner \
@ -899,7 +907,10 @@ PACKAGES = \
golang_org/x/net/http2/hpack \
golang_org/x/net/idna \
golang_org/x/net/lex/httplex \
golang_org/x/net/proxy \
golang_org/x/text/secure/bidirule \
golang_org/x/text/transform \
golang_org/x/text/unicode/bidi \
golang_org/x/text/unicode/norm \
golang_org/x/text/width \
hash \
@ -919,7 +930,7 @@ PACKAGES = \
image/png \
index/suffixarray \
internal/nettrace \
internal/pprof/profile \
internal/poll \
internal/race \
internal/singleflight \
internal/syscall/unix \
@ -931,6 +942,7 @@ PACKAGES = \
log/syslog \
math \
math/big \
math/bits \
math/cmplx \
math/rand \
mime \
@ -967,7 +979,7 @@ PACKAGES = \
runtime/internal/atomic \
runtime/internal/sys \
runtime/pprof \
runtime/pprof/internal/protopprof \
runtime/pprof/internal/profile \
runtime/trace \
sort \
strconv \
@ -1031,6 +1043,36 @@ libgolibbegin_a_SOURCES = \
runtime/go-libmain.c
libgolibbegin_a_CFLAGS = $(AM_CFLAGS) -fPIC
GOTOOL_PACKAGES = \
cmd/go/internal/base \
cmd/go/internal/bug \
cmd/go/internal/buildid \
cmd/go/internal/cfg \
cmd/go/internal/clean \
cmd/go/internal/cmdflag \
cmd/go/internal/doc \
cmd/go/internal/envcmd \
cmd/go/internal/fix \
cmd/go/internal/fmtcmd \
cmd/go/internal/generate \
cmd/go/internal/get \
cmd/go/internal/help \
cmd/go/internal/list \
cmd/go/internal/load \
cmd/go/internal/run \
cmd/go/internal/str \
cmd/go/internal/test \
cmd/go/internal/tool \
cmd/go/internal/version \
cmd/go/internal/vet \
cmd/go/internal/web \
cmd/go/internal/work \
cmd/internal/browser \
cmd/internal/objabi
libgotool_a_SOURCES =
libgotool_a_DEPENDENCIES = $(addsuffix .lo,$(GOTOOL_PACKAGES))
libgotool_a_LIBADD = $(addsuffix .o,$(GOTOOL_PACKAGES))
LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS))
AM_GOCFLAGS = $(STRINGOPS_FLAG) $(GO_SPLIT_STACK)
GOCOMPILE = $(GOC) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_GOCFLAGS) $(GOCFLAGS)
@ -1078,7 +1120,7 @@ GOBENCH =
CHECK = \
GC="$(GOC) $(GOCFLAGS) $($(subst /,_,$@)_GOCFLAGS) -L `${PWD_COMMAND}` -L `${PWD_COMMAND}`/.libs"; \
export GC; \
GOLIBS="$(MATH_LIBS) $(NET_LIBS) $(LIBS)"; \
GOLIBS="$(extra_check_libs_$(subst /,_,$(@D))) $(MATH_LIBS) $(NET_LIBS) $(LIBS)"; \
export GOLIBS; \
RUNTESTFLAGS="$(RUNTESTFLAGS)"; \
export RUNTESTFLAGS; \
@ -1125,7 +1167,8 @@ CHECK_DEPS = $(toolexeclibgo_DATA) $(toolexeclibgoarchive_DATA) \
$(toolexeclibgorpc_DATA) $(toolexeclibgoruntime_DATA) \
$(toolexeclibgosync_DATA) $(toolexeclibgotesting_DATA) \
$(toolexeclibgotext_DATA) $(toolexeclibgotexttemplate_DATA) \
$(toolexeclibgounicode_DATA) $(am__append_3) $(am__append_4)
$(toolexeclibgounicode_DATA) $(noinst_LIBRARIES) \
$(am__append_3) $(am__append_4)
# Pass -ffp-contract=off, or 386-specific options, when building the
# math package. MATH_FLAG is defined in configure.ac.
@ -1160,6 +1203,12 @@ runtime_internal_sys_lo_check_GOCFLAGS = -fgo-compiling-runtime
# Also use -fno-inline to get better results from the memory profiler.
runtime_pprof_check_GOCFLAGS = -static-libgo -fno-inline
extra_go_files_runtime_internal_sys = version.go
extra_go_files_cmd_go_internal_cfg = zdefaultcc.go
extra_go_files_cmd_go_internal_load = zstdpkglist.go
extra_check_libs_cmd_go_internal_generate = $(abs_builddir)/libgotool.a
extra_check_libs_cmd_go_internal_get = $(abs_builddir)/libgotool.a
extra_check_libs_cmd_go_internal_load = $(abs_builddir)/libgotool.a
extra_check_libs_cmd_go_internal_work = $(abs_builddir)/libgotool.a
@HAVE_STAT_TIMESPEC_FALSE@@LIBGO_IS_SOLARIS_TRUE@matchargs_os =
# Solaris 12 changed the type of fields in struct stat.
@ -1207,6 +1256,11 @@ TEST_PACKAGES = \
unicode/check \
archive/tar/check \
archive/zip/check \
cmd/go/internal/generate/check \
cmd/go/internal/get/check \
cmd/go/internal/load/check \
cmd/go/internal/work/check \
cmd/internal/objabi/check \
compress/bzip2/check \
compress/flate/check \
compress/gzip/check \
@ -1260,6 +1314,7 @@ TEST_PACKAGES = \
go/format/check \
go/internal/gcimporter/check \
go/internal/gccgoimporter/check \
go/internal/srcimporter/check \
go/parser/check \
go/printer/check \
go/scanner/check \
@ -1273,6 +1328,7 @@ TEST_PACKAGES = \
golang_org/x/net/idna/check \
golang_org/x/net/lex/httplex/check \
$(golang_org_x_net_lif_check) \
golang_org/x/net/proxy/check \
$(golang_org_x_net_route_check) \
hash/adler32/check \
hash/crc32/check \
@ -1283,12 +1339,13 @@ TEST_PACKAGES = \
image/jpeg/check \
image/png/check \
index/suffixarray/check \
internal/pprof/profile/check \
internal/poll/check \
internal/singleflight/check \
internal/trace/check \
io/ioutil/check \
log/syslog/check \
math/big/check \
math/bits/check \
math/cmplx/check \
math/rand/check \
mime/multipart/check \
@ -1317,7 +1374,7 @@ TEST_PACKAGES = \
runtime/internal/atomic/check \
runtime/internal/sys/check \
runtime/pprof/check \
runtime/pprof/internal/protopprof/check \
runtime/pprof/internal/profile/check \
runtime/trace/check \
sync/atomic/check \
text/scanner/check \
@ -1335,7 +1392,7 @@ MOSTLYCLEANFILES = \
libgo.head libgo.sum.sep libgo.log.sep libgo.var \
libcalls-list runtime.inc runtime.inc.tmp2 runtime.inc.tmp3
CLEANFILES = *.go *.c s-version libgo.sum libgo.log runtime.inc
CLEANFILES = *.go *.c s-* libgo.sum libgo.log runtime.inc
all: config.h
$(MAKE) $(AM_MAKEFLAGS) all-recursive
@ -1390,6 +1447,9 @@ $(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
distclean-hdr:
-rm -f config.h stamp-h1
clean-noinstLIBRARIES:
-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
install-toolexeclibLIBRARIES: $(toolexeclib_LIBRARIES)
@$(NORMAL_INSTALL)
@list='$(toolexeclib_LIBRARIES)'; test -n "$(toolexeclibdir)" || list=; \
@ -1433,6 +1493,10 @@ libgolibbegin.a: $(libgolibbegin_a_OBJECTS) $(libgolibbegin_a_DEPENDENCIES) $(EX
-rm -f libgolibbegin.a
$(libgolibbegin_a_AR) libgolibbegin.a $(libgolibbegin_a_OBJECTS) $(libgolibbegin_a_LIBADD)
$(RANLIB) libgolibbegin.a
libgotool.a: $(libgotool_a_OBJECTS) $(libgotool_a_DEPENDENCIES) $(EXTRA_libgotool_a_DEPENDENCIES)
-rm -f libgotool.a
$(libgotool_a_AR) libgotool.a $(libgotool_a_OBJECTS) $(libgotool_a_LIBADD)
$(RANLIB) libgotool.a
install-toolexeclibLTLIBRARIES: $(toolexeclib_LTLIBRARIES)
@$(NORMAL_INSTALL)
@list='$(toolexeclib_LTLIBRARIES)'; test -n "$(toolexeclibdir)" || list=; \
@ -2797,8 +2861,8 @@ maintainer-clean-generic:
clean: clean-multi clean-recursive
clean-am: clean-generic clean-libtool clean-local \
clean-toolexeclibLIBRARIES clean-toolexeclibLTLIBRARIES \
mostlyclean-am
clean-noinstLIBRARIES clean-toolexeclibLIBRARIES \
clean-toolexeclibLTLIBRARIES mostlyclean-am
distclean: distclean-multi distclean-recursive
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
@ -2931,17 +2995,18 @@ uninstall-am: uninstall-toolexeclibLIBRARIES \
.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
all all-am all-multi am--refresh check check-am clean \
clean-generic clean-libtool clean-local clean-multi \
clean-toolexeclibLIBRARIES clean-toolexeclibLTLIBRARIES ctags \
ctags-recursive distclean distclean-compile distclean-generic \
distclean-hdr distclean-libtool distclean-local \
distclean-multi distclean-tags dvi dvi-am html html-am info \
info-am install install-am install-data install-data-am \
install-dvi install-dvi-am install-exec install-exec-am \
install-html install-html-am install-info install-info-am \
install-man install-multi install-pdf install-pdf-am \
install-ps install-ps-am install-strip \
install-toolexeclibLIBRARIES install-toolexeclibLTLIBRARIES \
install-toolexeclibgoDATA install-toolexeclibgoarchiveDATA \
clean-noinstLIBRARIES clean-toolexeclibLIBRARIES \
clean-toolexeclibLTLIBRARIES ctags ctags-recursive distclean \
distclean-compile distclean-generic distclean-hdr \
distclean-libtool distclean-local distclean-multi \
distclean-tags dvi dvi-am html html-am info info-am install \
install-am install-data install-data-am install-dvi \
install-dvi-am install-exec install-exec-am install-html \
install-html-am install-info install-info-am install-man \
install-multi install-pdf install-pdf-am install-ps \
install-ps-am install-strip install-toolexeclibLIBRARIES \
install-toolexeclibLTLIBRARIES install-toolexeclibgoDATA \
install-toolexeclibgoarchiveDATA \
install-toolexeclibgocompressDATA \
install-toolexeclibgocontainerDATA \
install-toolexeclibgocryptoDATA \
@ -3069,6 +3134,17 @@ s-sigtab: $(srcdir)/mksigtab.sh gen-sysinfo.go
$(SHELL) $(srcdir)/mvifdiff.sh tmp-sigtab.go sigtab.go
$(STAMP) $@
zdefaultcc.go: s-zdefaultcc; @true
s-zdefaultcc: Makefile
echo 'package cfg' > zdefaultcc.go.tmp
echo >> zdefaultcc.go.tmp
echo 'const DefaultGCCGO = "$(bindir)/$(GCCGO_INSTALL_NAME)"' >> zdefaultcc.go.tmp
echo 'const DefaultCC = "$(GCC_INSTALL_NAME)"' >> zdefaultcc.go.tmp
echo 'const DefaultCXX = "$(GXX_INSTALL_NAME)"' >> zdefaultcc.go.tmp
echo 'const DefaultPkgConfig = "pkg-config"' >> zdefaultcc.go.tmp
$(SHELL) $(srcdir)/../move-if-change zdefaultcc.go.tmp zdefaultcc.go
$(STAMP) $@
# _Complex_lock and _Reader_lock are Go translations of some AIX system
# types and should not be exported back to C
# semt is a Go translation of the C type sem_t; it fails to convert on
@ -3094,7 +3170,7 @@ s-runtime-inc: runtime.lo Makefile
zstdpkglist.go: s-zstdpkglist; @true
s-zstdpkglist: Makefile
rm -f zstdpkglist.go.tmp
echo 'package main' > zstdpkglist.go.tmp
echo 'package load' > zstdpkglist.go.tmp
echo "" >> zstdpkglist.go.tmp
echo 'var stdpkg = map[string]bool{' >> zstdpkglist.go.tmp
echo $(libgo_go_objs) 'unsafe.lo' 'runtime/cgo.lo' | sed 's|[a-z0-9_/]*_c\.lo||g' | sed 's|\([a-z0-9_/]*\)\.lo|"\1": true,|g' >> zstdpkglist.go.tmp
@ -3211,9 +3287,12 @@ endef
# This line expands PACKAGE_template once for each package name listed
# in $(PACKAGES).
$(foreach package,$(PACKAGES),$(eval $(call PACKAGE_template,$(package))))
$(foreach package,$(GOTOOL_PACKAGES),$(eval $(call PACKAGE_template,$(package))))
runtime.lo.dep: $(extra_go_files_runtime)
syscall.lo.dep: $(extra_go_files_syscall)
runtime/internal/sys.lo.dep: $(extra_go_files_runtime_internal_sys)
cmd/go/internal/cfg.lo.dep: $(extra_go_files_cmd_go_internal_cfg)
cmd/go/internal/load.lo.dep: $(extra_go_files_cmd_go_internal_load)
# FIXME: The following C files may as well move to the runtime
# directory and be treated like other C files.

View File

@ -1 +1 @@
go1.8.3
go1.9

2
libgo/configure vendored
View File

@ -2494,7 +2494,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
ac_config_headers="$ac_config_headers config.h"
libtool_VERSION=11:0:0
libtool_VERSION=12:0:0
# Default to --enable-multilib

View File

@ -11,7 +11,7 @@ AC_INIT(package-unused, version-unused,, libgo)
AC_CONFIG_SRCDIR(Makefile.am)
AC_CONFIG_HEADER(config.h)
libtool_VERSION=11:0:0
libtool_VERSION=12:0:0
AC_SUBST(libtool_VERSION)
AM_ENABLE_MULTILIB(, ..)

View File

@ -158,11 +158,15 @@ func (fi headerFileInfo) Mode() (mode os.FileMode) {
// sysStat, if non-nil, populates h from system-dependent fields of fi.
var sysStat func(fi os.FileInfo, h *Header) error
// Mode constants from the tar spec.
const (
c_ISUID = 04000 // Set uid
c_ISGID = 02000 // Set gid
c_ISVTX = 01000 // Save text (sticky bit)
// Mode constants from the USTAR spec:
// See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13_06
c_ISUID = 04000 // Set uid
c_ISGID = 02000 // Set gid
c_ISVTX = 01000 // Save text (sticky bit)
// Common Unix mode constants; these are not defined in any common tar standard.
// Header.FileInfo understands these, but FileInfoHeader will never produce these.
c_ISDIR = 040000 // Directory
c_ISFIFO = 010000 // FIFO
c_ISREG = 0100000 // Regular file
@ -208,30 +212,24 @@ func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) {
}
switch {
case fm.IsRegular():
h.Mode |= c_ISREG
h.Typeflag = TypeReg
h.Size = fi.Size()
case fi.IsDir():
h.Typeflag = TypeDir
h.Mode |= c_ISDIR
h.Name += "/"
case fm&os.ModeSymlink != 0:
h.Typeflag = TypeSymlink
h.Mode |= c_ISLNK
h.Linkname = link
case fm&os.ModeDevice != 0:
if fm&os.ModeCharDevice != 0 {
h.Mode |= c_ISCHR
h.Typeflag = TypeChar
} else {
h.Mode |= c_ISBLK
h.Typeflag = TypeBlock
}
case fm&os.ModeNamedPipe != 0:
h.Typeflag = TypeFifo
h.Mode |= c_ISFIFO
case fm&os.ModeSocket != 0:
h.Mode |= c_ISSOCK
return nil, fmt.Errorf("archive/tar: sockets not supported")
default:
return nil, fmt.Errorf("archive/tar: unknown file mode %v", fm)
}

View File

@ -6,9 +6,11 @@ package tar
import (
"bytes"
"internal/testenv"
"io/ioutil"
"os"
"path"
"path/filepath"
"reflect"
"strings"
"testing"
@ -27,7 +29,7 @@ func TestFileInfoHeader(t *testing.T) {
if g, e := h.Name, "small.txt"; g != e {
t.Errorf("Name = %q; want %q", g, e)
}
if g, e := h.Mode, int64(fi.Mode().Perm())|c_ISREG; g != e {
if g, e := h.Mode, int64(fi.Mode().Perm()); g != e {
t.Errorf("Mode = %#o; want %#o", g, e)
}
if g, e := h.Size, int64(5); g != e {
@ -55,7 +57,7 @@ func TestFileInfoHeaderDir(t *testing.T) {
t.Errorf("Name = %q; want %q", g, e)
}
// Ignoring c_ISGID for golang.org/issue/4867
if g, e := h.Mode&^c_ISGID, int64(fi.Mode().Perm())|c_ISDIR; g != e {
if g, e := h.Mode&^c_ISGID, int64(fi.Mode().Perm()); g != e {
t.Errorf("Mode = %#o; want %#o", g, e)
}
if g, e := h.Size, int64(0); g != e {
@ -67,40 +69,56 @@ func TestFileInfoHeaderDir(t *testing.T) {
}
func TestFileInfoHeaderSymlink(t *testing.T) {
h, err := FileInfoHeader(symlink{}, "some-target")
testenv.MustHaveSymlink(t)
tmpdir, err := ioutil.TempDir("", "TestFileInfoHeaderSymlink")
if err != nil {
t.Fatal(err)
}
if g, e := h.Name, "some-symlink"; g != e {
defer os.RemoveAll(tmpdir)
link := filepath.Join(tmpdir, "link")
target := tmpdir
err = os.Symlink(target, link)
if err != nil {
t.Fatal(err)
}
fi, err := os.Lstat(link)
if err != nil {
t.Fatal(err)
}
h, err := FileInfoHeader(fi, target)
if err != nil {
t.Fatal(err)
}
if g, e := h.Name, fi.Name(); g != e {
t.Errorf("Name = %q; want %q", g, e)
}
if g, e := h.Linkname, "some-target"; g != e {
if g, e := h.Linkname, target; g != e {
t.Errorf("Linkname = %q; want %q", g, e)
}
if g, e := h.Typeflag, byte(TypeSymlink); g != e {
t.Errorf("Typeflag = %v; want %v", g, e)
}
}
type symlink struct{}
func (symlink) Name() string { return "some-symlink" }
func (symlink) Size() int64 { return 0 }
func (symlink) Mode() os.FileMode { return os.ModeSymlink }
func (symlink) ModTime() time.Time { return time.Time{} }
func (symlink) IsDir() bool { return false }
func (symlink) Sys() interface{} { return nil }
func TestRoundTrip(t *testing.T) {
data := []byte("some file contents")
var b bytes.Buffer
tw := NewWriter(&b)
hdr := &Header{
Name: "file.txt",
Uid: 1 << 21, // too big for 8 octal digits
Size: int64(len(data)),
ModTime: time.Now(),
Name: "file.txt",
Uid: 1 << 21, // too big for 8 octal digits
Size: int64(len(data)),
// AddDate to strip monotonic clock reading,
// and Round to discard sub-second precision,
// both of which are not included in the tar header
// and would otherwise break the round-trip check
// below.
ModTime: time.Now().AddDate(0, 0, 0).Round(1 * time.Second),
}
// tar only supports second precision.
hdr.ModTime = hdr.ModTime.Add(-time.Duration(hdr.ModTime.Nanosecond()) * time.Nanosecond)
if err := tw.WriteHeader(hdr); err != nil {
t.Fatalf("tw.WriteHeader: %v", err)
}
@ -139,7 +157,7 @@ func TestHeaderRoundTrip(t *testing.T) {
// regular file.
h: &Header{
Name: "test.txt",
Mode: 0644 | c_ISREG,
Mode: 0644,
Size: 12,
ModTime: time.Unix(1360600916, 0),
Typeflag: TypeReg,
@ -149,7 +167,7 @@ func TestHeaderRoundTrip(t *testing.T) {
// symbolic link.
h: &Header{
Name: "link.txt",
Mode: 0777 | c_ISLNK,
Mode: 0777,
Size: 0,
ModTime: time.Unix(1360600852, 0),
Typeflag: TypeSymlink,
@ -159,7 +177,7 @@ func TestHeaderRoundTrip(t *testing.T) {
// character device node.
h: &Header{
Name: "dev/null",
Mode: 0666 | c_ISCHR,
Mode: 0666,
Size: 0,
ModTime: time.Unix(1360578951, 0),
Typeflag: TypeChar,
@ -169,7 +187,7 @@ func TestHeaderRoundTrip(t *testing.T) {
// block device node.
h: &Header{
Name: "dev/sda",
Mode: 0660 | c_ISBLK,
Mode: 0660,
Size: 0,
ModTime: time.Unix(1360578954, 0),
Typeflag: TypeBlock,
@ -179,7 +197,7 @@ func TestHeaderRoundTrip(t *testing.T) {
// directory.
h: &Header{
Name: "dir/",
Mode: 0755 | c_ISDIR,
Mode: 0755,
Size: 0,
ModTime: time.Unix(1360601116, 0),
Typeflag: TypeDir,
@ -189,7 +207,7 @@ func TestHeaderRoundTrip(t *testing.T) {
// fifo node.
h: &Header{
Name: "dev/initctl",
Mode: 0600 | c_ISFIFO,
Mode: 0600,
Size: 0,
ModTime: time.Unix(1360578949, 0),
Typeflag: TypeFifo,
@ -199,7 +217,7 @@ func TestHeaderRoundTrip(t *testing.T) {
// setuid.
h: &Header{
Name: "bin/su",
Mode: 0755 | c_ISREG | c_ISUID,
Mode: 0755 | c_ISUID,
Size: 23232,
ModTime: time.Unix(1355405093, 0),
Typeflag: TypeReg,
@ -209,7 +227,7 @@ func TestHeaderRoundTrip(t *testing.T) {
// setguid.
h: &Header{
Name: "group.txt",
Mode: 0750 | c_ISREG | c_ISGID,
Mode: 0750 | c_ISGID,
Size: 0,
ModTime: time.Unix(1360602346, 0),
Typeflag: TypeReg,
@ -219,7 +237,7 @@ func TestHeaderRoundTrip(t *testing.T) {
// sticky.
h: &Header{
Name: "sticky.txt",
Mode: 0600 | c_ISREG | c_ISVTX,
Mode: 0600 | c_ISVTX,
Size: 7,
ModTime: time.Unix(1360602540, 0),
Typeflag: TypeReg,
@ -229,7 +247,7 @@ func TestHeaderRoundTrip(t *testing.T) {
// hard link.
h: &Header{
Name: "hard.txt",
Mode: 0644 | c_ISREG,
Mode: 0644,
Size: 0,
Linkname: "file.txt",
ModTime: time.Unix(1360600916, 0),
@ -240,7 +258,7 @@ func TestHeaderRoundTrip(t *testing.T) {
// More information.
h: &Header{
Name: "info.txt",
Mode: 0600 | c_ISREG,
Mode: 0600,
Size: 0,
Uid: 1000,
Gid: 1000,

View File

@ -121,9 +121,15 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
needsPaxHeader := paxKeyword != paxNone && len(s) > len(b) || !isASCII(s)
if needsPaxHeader {
paxHeaders[paxKeyword] = s
return
}
f.formatString(b, s)
// Write string in a best-effort manner to satisfy readers that expect
// the field to be non-empty.
s = toASCII(s)
if len(s) > len(b) {
s = s[:len(b)]
}
f.formatString(b, s) // Should never error
}
var formatNumeric = func(b []byte, x int64, paxKeyword string) {
// Try octal first.

View File

@ -103,51 +103,46 @@ func (r *pooledFlateReader) Close() error {
}
var (
mu sync.RWMutex // guards compressor and decompressor maps
compressors = map[uint16]Compressor{
Store: func(w io.Writer) (io.WriteCloser, error) { return &nopCloser{w}, nil },
Deflate: func(w io.Writer) (io.WriteCloser, error) { return newFlateWriter(w), nil },
}
decompressors = map[uint16]Decompressor{
Store: ioutil.NopCloser,
Deflate: newFlateReader,
}
compressors sync.Map // map[uint16]Compressor
decompressors sync.Map // map[uint16]Decompressor
)
func init() {
compressors.Store(Store, Compressor(func(w io.Writer) (io.WriteCloser, error) { return &nopCloser{w}, nil }))
compressors.Store(Deflate, Compressor(func(w io.Writer) (io.WriteCloser, error) { return newFlateWriter(w), nil }))
decompressors.Store(Store, Decompressor(ioutil.NopCloser))
decompressors.Store(Deflate, Decompressor(newFlateReader))
}
// RegisterDecompressor allows custom decompressors for a specified method ID.
// The common methods Store and Deflate are built in.
func RegisterDecompressor(method uint16, dcomp Decompressor) {
mu.Lock()
defer mu.Unlock()
if _, ok := decompressors[method]; ok {
if _, dup := decompressors.LoadOrStore(method, dcomp); dup {
panic("decompressor already registered")
}
decompressors[method] = dcomp
}
// RegisterCompressor registers custom compressors for a specified method ID.
// The common methods Store and Deflate are built in.
func RegisterCompressor(method uint16, comp Compressor) {
mu.Lock()
defer mu.Unlock()
if _, ok := compressors[method]; ok {
if _, dup := compressors.LoadOrStore(method, comp); dup {
panic("compressor already registered")
}
compressors[method] = comp
}
func compressor(method uint16) Compressor {
mu.RLock()
defer mu.RUnlock()
return compressors[method]
ci, ok := compressors.Load(method)
if !ok {
return nil
}
return ci.(Compressor)
}
func decompressor(method uint16) Decompressor {
mu.RLock()
defer mu.RUnlock()
return decompressors[method]
di, ok := decompressors.Load(method)
if !ok {
return nil
}
return di.(Decompressor)
}

View File

@ -5,7 +5,7 @@
/*
Package zip provides support for reading and writing ZIP archives.
See: https://www.pkware.com/documents/casestudies/APPNOTE.TXT
See: https://www.pkware.com/appnote
This package does not support disk spanning.

View File

@ -11,10 +11,9 @@ import (
"hash"
"hash/crc32"
"io"
"unicode/utf8"
)
// TODO(adg): support zip file comments
// Writer implements a zip file writer.
type Writer struct {
cw *countWriter
@ -201,6 +200,20 @@ func (w *Writer) Create(name string) (io.Writer, error) {
return w.CreateHeader(header)
}
func hasValidUTF8(s string) bool {
n := 0
for _, r := range s {
// By default, ZIP uses CP437, which is only identical to ASCII for the printable characters.
if r < 0x20 || r >= 0x7f {
if !utf8.ValidRune(r) {
return false
}
n++
}
}
return n > 0
}
// CreateHeader adds a file to the zip file using the provided FileHeader
// for the file metadata.
// It returns a Writer to which the file contents should be written.
@ -221,6 +234,10 @@ func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) {
fh.Flags |= 0x8 // we will write a data descriptor
if hasValidUTF8(fh.Name) || hasValidUTF8(fh.Comment) {
fh.Flags |= 0x800 // filename or comment have valid utf-8 string
}
fh.CreatorVersion = fh.CreatorVersion&0xff00 | zipVersion20 // preserve compatibility byte
fh.ReaderVersion = zipVersion20

View File

@ -87,6 +87,69 @@ func TestWriter(t *testing.T) {
}
}
func TestWriterUTF8(t *testing.T) {
var utf8Tests = []struct {
name string
comment string
expect uint16
}{
{
name: "hi, hello",
comment: "in the world",
expect: 0x8,
},
{
name: "hi, こんにちわ",
comment: "in the world",
expect: 0x808,
},
{
name: "hi, hello",
comment: "in the 世界",
expect: 0x808,
},
{
name: "hi, こんにちわ",
comment: "in the 世界",
expect: 0x808,
},
}
// write a zip file
buf := new(bytes.Buffer)
w := NewWriter(buf)
for _, test := range utf8Tests {
h := &FileHeader{
Name: test.name,
Comment: test.comment,
Method: Deflate,
}
w, err := w.CreateHeader(h)
if err != nil {
t.Fatal(err)
}
w.Write([]byte{})
}
if err := w.Close(); err != nil {
t.Fatal(err)
}
// read it back
r, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
if err != nil {
t.Fatal(err)
}
for i, test := range utf8Tests {
got := r.File[i].Flags
t.Logf("name %v, comment %v", test.name, test.comment)
if got != test.expect {
t.Fatalf("Flags: got %v, want %v", got, test.expect)
}
}
}
func TestWriterOffset(t *testing.T) {
largeData := make([]byte, 1<<17)
for i := range largeData {
@ -181,12 +244,11 @@ func testReadFile(t *testing.T, f *File, wt *WriteTest) {
}
func BenchmarkCompressedZipGarbage(b *testing.B) {
b.ReportAllocs()
var buf bytes.Buffer
bigBuf := bytes.Repeat([]byte("a"), 1<<20)
for i := 0; i <= b.N; i++ {
runOnce := func(buf *bytes.Buffer) {
buf.Reset()
zw := NewWriter(&buf)
zw := NewWriter(buf)
for j := 0; j < 3; j++ {
w, _ := zw.CreateHeader(&FileHeader{
Name: "foo",
@ -195,11 +257,19 @@ func BenchmarkCompressedZipGarbage(b *testing.B) {
w.Write(bigBuf)
}
zw.Close()
if i == 0 {
// Reset the timer after the first time through.
// This effectively discards the very large initial flate setup cost,
// as well as the initialization of bigBuf.
b.ResetTimer()
}
}
b.ReportAllocs()
// Run once and then reset the timer.
// This effectively discards the very large initial flate setup cost,
// as well as the initialization of bigBuf.
runOnce(&bytes.Buffer{})
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
var buf bytes.Buffer
for pb.Next() {
runOnce(&buf)
}
})
}

View File

@ -255,7 +255,7 @@ func TestZip64EdgeCase(t *testing.T) {
testZip64DirectoryRecordLength(buf, t)
}
// Tests that we generate a zip64 file if the the directory at offset
// Tests that we generate a zip64 file if the directory at offset
// 0xFFFFFFFF, but not before.
func TestZip64DirectoryOffset(t *testing.T) {
if testing.Short() && race.Enabled {
@ -681,6 +681,18 @@ func BenchmarkZip64Test(b *testing.B) {
}
}
func BenchmarkZip64TestSizes(b *testing.B) {
for _, size := range []int64{1 << 12, 1 << 20, 1 << 26} {
b.Run(fmt.Sprint(size), func(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
testZip64(b, size)
}
})
})
}
}
func TestSuffixSaver(t *testing.T) {
const keep = 10
ss := &suffixSaver{keep: keep}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package bufio implements buffered I/O. It wraps an io.Reader or io.Writer
// Package bufio implements buffered I/O. It wraps an io.Reader or io.Writer
// object, creating another object (Reader or Writer) that also implements
// the interface but provides buffering and some help for textual I/O.
package bufio
@ -458,6 +458,7 @@ func (b *Reader) ReadString(delim byte) (string, error) {
}
// WriteTo implements io.WriterTo.
// This may make multiple calls to the Read method of the underlying Reader.
func (b *Reader) WriteTo(w io.Writer) (n int64, err error) {
n, err = b.writeBuf(w)
if err != nil {
@ -513,7 +514,7 @@ func (b *Reader) writeBuf(w io.Writer) (int64, error) {
// Writer implements buffering for an io.Writer object.
// If an error occurs writing to a Writer, no more data will be
// accepted and all subsequent writes will return the error.
// accepted and all subsequent writes, and Flush, will return the error.
// After all data has been written, the client should call the
// Flush method to guarantee all data has been forwarded to
// the underlying io.Writer.

View File

@ -169,7 +169,6 @@ func genLine(buf *bytes.Buffer, lineNum, n int, addNewline bool) {
}
buf.WriteByte('\n')
}
return
}
// Test the line splitter, including some carriage returns but no long lines.

View File

@ -85,11 +85,11 @@ type uintptr uintptr
// byte is an alias for uint8 and is equivalent to uint8 in all ways. It is
// used, by convention, to distinguish byte values from 8-bit unsigned
// integer values.
type byte byte
type byte = uint8
// rune is an alias for int32 and is equivalent to int32 in all ways. It is
// used, by convention, to distinguish character values from integer values.
type rune rune
type rune = int32
// iota is a predeclared identifier representing the untyped integer ordinal
// number of the current const specification in a (usually parenthesized)
@ -179,7 +179,7 @@ func cap(v Type) int
// Channel: The channel's buffer is initialized with the specified
// buffer capacity. If zero, or the size is omitted, the channel is
// unbuffered.
func make(Type, size IntegerType) Type
func make(t Type, size ...IntegerType) Type
// The new built-in function allocates memory. The first argument is a type,
// not a value, and the value returned is a pointer to a newly

View File

@ -15,10 +15,15 @@ import (
// A Buffer is a variable-sized buffer of bytes with Read and Write methods.
// The zero value for Buffer is an empty buffer ready to use.
type Buffer struct {
buf []byte // contents are the bytes buf[off : len(buf)]
off int // read at &buf[off], write at &buf[len(buf)]
bootstrap [64]byte // memory to hold first slice; helps small buffers avoid allocation.
lastRead readOp // last read operation, so that Unread* can work correctly.
buf []byte // contents are the bytes buf[off : len(buf)]
off int // read at &buf[off], write at &buf[len(buf)]
lastRead readOp // last read operation, so that Unread* can work correctly.
// FIXME: lastRead can fit in a single byte
// memory to hold first slice; helps small buffers avoid allocation.
// FIXME: it would be advisable to align Buffer to cachelines to avoid false
// sharing.
bootstrap [64]byte
}
// The readOp constants describe the last action performed on
@ -68,13 +73,13 @@ func (b *Buffer) Cap() int { return cap(b.buf) }
// but continues to use the same allocated storage.
// It panics if n is negative or greater than the length of the buffer.
func (b *Buffer) Truncate(n int) {
if n == 0 {
b.Reset()
return
}
b.lastRead = opInvalid
switch {
case n < 0 || n > b.Len():
if n < 0 || n > b.Len() {
panic("bytes.Buffer: truncation out of range")
case n == 0:
// Reuse buffer space.
b.off = 0
}
b.buf = b.buf[0 : b.off+n]
}
@ -82,7 +87,22 @@ func (b *Buffer) Truncate(n int) {
// Reset resets the buffer to be empty,
// but it retains the underlying storage for use by future writes.
// Reset is the same as Truncate(0).
func (b *Buffer) Reset() { b.Truncate(0) }
func (b *Buffer) Reset() {
b.buf = b.buf[:0]
b.off = 0
b.lastRead = opInvalid
}
// tryGrowByReslice is a inlineable version of grow for the fast-case where the
// internal buffer only needs to be resliced.
// It returns the index where bytes should be written and whether it succeeded.
func (b *Buffer) tryGrowByReslice(n int) (int, bool) {
if l := len(b.buf); l+n <= cap(b.buf) {
b.buf = b.buf[:l+n]
return l, true
}
return 0, false
}
// grow grows the buffer to guarantee space for n more bytes.
// It returns the index where bytes should be written.
@ -91,29 +111,33 @@ func (b *Buffer) grow(n int) int {
m := b.Len()
// If buffer is empty, reset to recover space.
if m == 0 && b.off != 0 {
b.Truncate(0)
b.Reset()
}
if len(b.buf)+n > cap(b.buf) {
var buf []byte
if b.buf == nil && n <= len(b.bootstrap) {
buf = b.bootstrap[0:]
} else if m+n <= cap(b.buf)/2 {
// We can slide things down instead of allocating a new
// slice. We only need m+n <= cap(b.buf) to slide, but
// we instead let capacity get twice as large so we
// don't spend all our time copying.
copy(b.buf[:], b.buf[b.off:])
buf = b.buf[:m]
} else {
// not enough space anywhere
buf = makeSlice(2*cap(b.buf) + n)
copy(buf, b.buf[b.off:])
}
// Try to grow by means of a reslice.
if i, ok := b.tryGrowByReslice(n); ok {
return i
}
// Check if we can make use of bootstrap array.
if b.buf == nil && n <= len(b.bootstrap) {
b.buf = b.bootstrap[:n]
return 0
}
if m+n <= cap(b.buf)/2 {
// We can slide things down instead of allocating a new
// slice. We only need m+n <= cap(b.buf) to slide, but
// we instead let capacity get twice as large so we
// don't spend all our time copying.
copy(b.buf[:], b.buf[b.off:])
} else {
// Not enough space anywhere, we need to allocate.
buf := makeSlice(2*cap(b.buf) + n)
copy(buf, b.buf[b.off:])
b.buf = buf
b.off = 0
}
b.buf = b.buf[0 : b.off+m+n]
return b.off + m
// Restore b.off and len(b.buf).
b.off = 0
b.buf = b.buf[:m+n]
return m
}
// Grow grows the buffer's capacity, if necessary, to guarantee space for
@ -134,7 +158,10 @@ func (b *Buffer) Grow(n int) {
// buffer becomes too large, Write will panic with ErrTooLarge.
func (b *Buffer) Write(p []byte) (n int, err error) {
b.lastRead = opInvalid
m := b.grow(len(p))
m, ok := b.tryGrowByReslice(len(p))
if !ok {
m = b.grow(len(p))
}
return copy(b.buf[m:], p), nil
}
@ -143,7 +170,10 @@ func (b *Buffer) Write(p []byte) (n int, err error) {
// buffer becomes too large, WriteString will panic with ErrTooLarge.
func (b *Buffer) WriteString(s string) (n int, err error) {
b.lastRead = opInvalid
m := b.grow(len(s))
m, ok := b.tryGrowByReslice(len(s))
if !ok {
m = b.grow(len(s))
}
return copy(b.buf[m:], s), nil
}
@ -161,7 +191,7 @@ func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) {
b.lastRead = opInvalid
// If buffer is empty, reset to recover space.
if b.off >= len(b.buf) {
b.Truncate(0)
b.Reset()
}
for {
if free := cap(b.buf) - len(b.buf); free < MinRead {
@ -225,7 +255,7 @@ func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) {
}
}
// Buffer is now empty; reset.
b.Truncate(0)
b.Reset()
return
}
@ -235,7 +265,10 @@ func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) {
// ErrTooLarge.
func (b *Buffer) WriteByte(c byte) error {
b.lastRead = opInvalid
m := b.grow(1)
m, ok := b.tryGrowByReslice(1)
if !ok {
m = b.grow(1)
}
b.buf[m] = c
return nil
}
@ -250,7 +283,10 @@ func (b *Buffer) WriteRune(r rune) (n int, err error) {
return 1, nil
}
b.lastRead = opInvalid
m := b.grow(utf8.UTFMax)
m, ok := b.tryGrowByReslice(utf8.UTFMax)
if !ok {
m = b.grow(utf8.UTFMax)
}
n = utf8.EncodeRune(b.buf[m:m+utf8.UTFMax], r)
b.buf = b.buf[:m+n]
return n, nil
@ -264,7 +300,7 @@ func (b *Buffer) Read(p []byte) (n int, err error) {
b.lastRead = opInvalid
if b.off >= len(b.buf) {
// Buffer is empty, reset to recover space.
b.Truncate(0)
b.Reset()
if len(p) == 0 {
return
}
@ -302,7 +338,7 @@ func (b *Buffer) ReadByte() (byte, error) {
b.lastRead = opInvalid
if b.off >= len(b.buf) {
// Buffer is empty, reset to recover space.
b.Truncate(0)
b.Reset()
return 0, io.EOF
}
c := b.buf[b.off]
@ -320,7 +356,7 @@ func (b *Buffer) ReadRune() (r rune, size int, err error) {
b.lastRead = opInvalid
if b.off >= len(b.buf) {
// Buffer is empty, reset to recover space.
b.Truncate(0)
b.Reset()
return 0, 0, io.EOF
}
c := b.buf[b.off]
@ -337,12 +373,12 @@ func (b *Buffer) ReadRune() (r rune, size int, err error) {
// UnreadRune unreads the last rune returned by ReadRune.
// If the most recent read or write operation on the buffer was
// not a ReadRune, UnreadRune returns an error. (In this regard
// not a successful ReadRune, UnreadRune returns an error. (In this regard
// it is stricter than UnreadByte, which will unread the last byte
// from any read operation.)
func (b *Buffer) UnreadRune() error {
if b.lastRead <= opInvalid {
return errors.New("bytes.Buffer: UnreadRune: previous operation was not ReadRune")
return errors.New("bytes.Buffer: UnreadRune: previous operation was not a successful ReadRune")
}
if b.off >= int(b.lastRead) {
b.off -= int(b.lastRead)
@ -351,12 +387,13 @@ func (b *Buffer) UnreadRune() error {
return nil
}
// UnreadByte unreads the last byte returned by the most recent
// read operation. If write has happened since the last read, UnreadByte
// returns an error.
// UnreadByte unreads the last byte returned by the most recent successful
// read operation that read at least one byte. If a write has happened since
// the last read, if the last read returned an error, or if the read read zero
// bytes, UnreadByte returns an error.
func (b *Buffer) UnreadByte() error {
if b.lastRead == opInvalid {
return errors.New("bytes.Buffer: UnreadByte: previous operation was not a read")
return errors.New("bytes.Buffer: UnreadByte: previous operation was not a successful read")
}
b.lastRead = opInvalid
if b.off > 0 {
@ -404,10 +441,12 @@ func (b *Buffer) ReadString(delim byte) (line string, err error) {
return string(slice), err
}
// NewBuffer creates and initializes a new Buffer using buf as its initial
// contents. It is intended to prepare a Buffer to read existing data. It
// can also be used to size the internal buffer for writing. To do that,
// buf should have the desired capacity but a length of zero.
// NewBuffer creates and initializes a new Buffer using buf as its
// initial contents. The new Buffer takes ownership of buf, and the
// caller should not use buf after this call. NewBuffer is intended to
// prepare a Buffer to read existing data. It can also be used to size
// the internal buffer for writing. To do that, buf should have the
// desired capacity but a length of zero.
//
// In most cases, new(Buffer) (or just declaring a Buffer variable) is
// sufficient to initialize a Buffer.

View File

@ -6,8 +6,10 @@ package bytes_test
import (
. "bytes"
"internal/testenv"
"io"
"math/rand"
"os/exec"
"runtime"
"testing"
"unicode/utf8"
@ -311,6 +313,19 @@ func TestRuneIO(t *testing.T) {
// Check that UnreadRune works
buf.Reset()
// check at EOF
if err := buf.UnreadRune(); err == nil {
t.Fatal("UnreadRune at EOF: got no error")
}
if _, _, err := buf.ReadRune(); err == nil {
t.Fatal("ReadRune at EOF: got no error")
}
if err := buf.UnreadRune(); err == nil {
t.Fatal("UnreadRune after ReadRune at EOF: got no error")
}
// check not at EOF
buf.Write(b)
for r := rune(0); r < NRune; r++ {
r1, size, _ := buf.ReadRune()
@ -473,15 +488,34 @@ func TestReadEmptyAtEOF(t *testing.T) {
func TestUnreadByte(t *testing.T) {
b := new(Buffer)
b.WriteString("abcdefghijklmnopqrstuvwxyz")
_, err := b.ReadBytes('m')
if err != nil {
t.Fatalf("ReadBytes: %v", err)
// check at EOF
if err := b.UnreadByte(); err == nil {
t.Fatal("UnreadByte at EOF: got no error")
}
if _, err := b.ReadByte(); err == nil {
t.Fatal("ReadByte at EOF: got no error")
}
if err := b.UnreadByte(); err == nil {
t.Fatal("UnreadByte after ReadByte at EOF: got no error")
}
err = b.UnreadByte()
if err != nil {
// check not at EOF
b.WriteString("abcdefghijklmnopqrstuvwxyz")
// after unsuccessful read
if n, err := b.Read(nil); n != 0 || err != nil {
t.Fatalf("Read(nil) = %d,%v; want 0,nil", n, err)
}
if err := b.UnreadByte(); err == nil {
t.Fatal("UnreadByte after Read(nil): got no error")
}
// after successful read
if _, err := b.ReadBytes('m'); err != nil {
t.Fatalf("ReadBytes: %v", err)
}
if err := b.UnreadByte(); err != nil {
t.Fatalf("UnreadByte: %v", err)
}
c, err := b.ReadByte()
@ -514,6 +548,38 @@ func TestBufferGrowth(t *testing.T) {
}
}
// Test that tryGrowByReslice is inlined.
// Only execute on "linux-amd64" builder in order to avoid breakage.
func TestTryGrowByResliceInlined(t *testing.T) {
targetBuilder := "linux-amd64"
if testenv.Builder() != targetBuilder {
t.Skipf("%q gets executed on %q builder only", t.Name(), targetBuilder)
}
t.Parallel()
goBin := testenv.GoToolPath(t)
out, err := exec.Command(goBin, "tool", "nm", goBin).CombinedOutput()
if err != nil {
t.Fatalf("go tool nm: %v: %s", err, out)
}
// Verify this doesn't exist:
sym := "bytes.(*Buffer).tryGrowByReslice"
if Contains(out, []byte(sym)) {
t.Errorf("found symbol %q in cmd/go, but should be inlined", sym)
}
}
func BenchmarkWriteByte(b *testing.B) {
const n = 4 << 10
b.SetBytes(n)
buf := NewBuffer(make([]byte, n))
for i := 0; i < b.N; i++ {
buf.Reset()
for i := 0; i < n; i++ {
buf.WriteByte('x')
}
}
}
func BenchmarkWriteRune(b *testing.B) {
const n = 4 << 10
const r = '☺'

View File

@ -46,36 +46,21 @@ func explode(s []byte, n int) [][]byte {
return a[0:na]
}
// Count counts the number of non-overlapping instances of sep in s.
// If sep is an empty slice, Count returns 1 + the number of Unicode code points in s.
func Count(s, sep []byte) int {
n := len(sep)
if n == 0 {
// countGeneric actually implements Count
func countGeneric(s, sep []byte) int {
// special case
if len(sep) == 0 {
return utf8.RuneCount(s) + 1
}
if n > len(s) {
return 0
}
count := 0
c := sep[0]
i := 0
t := s[:len(s)-n+1]
for i < len(t) {
if t[i] != c {
o := IndexByte(t[i:], c)
if o < 0 {
break
}
i += o
n := 0
for {
i := Index(s, sep)
if i == -1 {
return n
}
if n == 1 || Equal(s[i:i+n], sep) {
count++
i += n
continue
}
i++
n++
s = s[i+len(sep):]
}
return count
}
// Contains reports whether subslice is within b.
@ -229,20 +214,21 @@ func genSplit(s, sep []byte, sepSave, n int) [][]byte {
if n < 0 {
n = Count(s, sep) + 1
}
c := sep[0]
start := 0
a := make([][]byte, n)
na := 0
for i := 0; i+len(sep) <= len(s) && na+1 < n; i++ {
if s[i] == c && (len(sep) == 1 || Equal(s[i:i+len(sep)], sep)) {
a[na] = s[start : i+sepSave]
na++
start = i + len(sep)
i += len(sep) - 1
n--
i := 0
for i < n {
m := Index(s, sep)
if m < 0 {
break
}
a[i] = s[:m+sepSave]
s = s[m+len(sep):]
i++
}
a[na] = s[start:]
return a[0 : na+1]
a[i] = s
return a[:i+1]
}
// SplitN slices s into subslices separated by sep and returns a slice of

View File

@ -6,17 +6,19 @@
package bytes
import "internal/cpu"
//go:noescape
// indexShortStr returns the index of the first instance of c in s, or -1 if c is not present in s.
// indexShortStr requires 2 <= len(c) <= shortStringLen
func indexShortStr(s, c []byte) int // ../runtime/asm_$GOARCH.s
func supportAVX2() bool // ../runtime/asm_$GOARCH.s
func indexShortStr(s, c []byte) int // ../runtime/asm_amd64.s
func countByte(s []byte, c byte) int // ../runtime/asm_amd64.s
var shortStringLen int
func init() {
if supportAVX2() {
if cpu.X86.HasAVX2 {
shortStringLen = 63
} else {
shortStringLen = 31
@ -96,6 +98,15 @@ func Index(s, sep []byte) int {
return -1
}
// Count counts the number of non-overlapping instances of sep in s.
// If sep is an empty slice, Count returns 1 + the number of Unicode code points in s.
func Count(s, sep []byte) int {
if len(sep) == 1 && cpu.X86.HasPOPCNT {
return countByte(s, sep[0])
}
return countGeneric(s, sep)
}
// primeRK is the prime base used in Rabin-Karp algorithm.
const primeRK = 16777619

View File

@ -39,3 +39,9 @@ func Index(s, sep []byte) int {
}
return -1
}
// Count counts the number of non-overlapping instances of sep in s.
// If sep is an empty slice, Count returns 1 + the number of Unicode code points in s.
func Count(s, sep []byte) int {
return countGeneric(s, sep)
}

View File

@ -99,6 +99,12 @@ func Index(s, sep []byte) int {
return -1
}
// Count counts the number of non-overlapping instances of sep in s.
// If sep is an empty slice, Count returns 1 + the number of Unicode code points in s.
func Count(s, sep []byte) int {
return countGeneric(s, sep)
}
// primeRK is the prime base used in Rabin-Karp algorithm.
const primeRK = 16777619

View File

@ -401,6 +401,79 @@ func TestIndexRune(t *testing.T) {
}
}
// test count of a single byte across page offsets
func TestCountByte(t *testing.T) {
b := make([]byte, 5015) // bigger than a page
windows := []int{1, 2, 3, 4, 15, 16, 17, 31, 32, 33, 63, 64, 65, 128}
testCountWindow := func(i, window int) {
for j := 0; j < window; j++ {
b[i+j] = byte(100)
p := Count(b[i:i+window], []byte{100})
if p != j+1 {
t.Errorf("TestCountByte.Count(%q, 100) = %d", b[i:i+window], p)
}
pGeneric := CountGeneric(b[i:i+window], []byte{100})
if pGeneric != j+1 {
t.Errorf("TestCountByte.CountGeneric(%q, 100) = %d", b[i:i+window], p)
}
}
}
maxWnd := windows[len(windows)-1]
for i := 0; i <= 2*maxWnd; i++ {
for _, window := range windows {
if window > len(b[i:]) {
window = len(b[i:])
}
testCountWindow(i, window)
for j := 0; j < window; j++ {
b[i+j] = byte(0)
}
}
}
for i := 4096 - (maxWnd + 1); i < len(b); i++ {
for _, window := range windows {
if window > len(b[i:]) {
window = len(b[i:])
}
testCountWindow(i, window)
for j := 0; j < window; j++ {
b[i+j] = byte(0)
}
}
}
}
// Make sure we don't count bytes outside our window
func TestCountByteNoMatch(t *testing.T) {
b := make([]byte, 5015)
windows := []int{1, 2, 3, 4, 15, 16, 17, 31, 32, 33, 63, 64, 65, 128}
for i := 0; i <= len(b); i++ {
for _, window := range windows {
if window > len(b[i:]) {
window = len(b[i:])
}
// Fill the window with non-match
for j := 0; j < window; j++ {
b[i+j] = byte(100)
}
// Try to find something that doesn't exist
p := Count(b[i:i+window], []byte{0})
if p != 0 {
t.Errorf("TestCountByteNoMatch(%q, 0) = %d", b[i:i+window], p)
}
pGeneric := CountGeneric(b[i:i+window], []byte{0})
if pGeneric != 0 {
t.Errorf("TestCountByteNoMatch.CountGeneric(%q, 100) = %d", b[i:i+window], p)
}
for j := 0; j < window; j++ {
b[i+j] = byte(0)
}
}
}
}
var bmbuf []byte
func valName(x int) string {
@ -594,6 +667,26 @@ func BenchmarkCountEasy(b *testing.B) {
})
}
func BenchmarkCountSingle(b *testing.B) {
benchBytes(b, indexSizes, func(b *testing.B, n int) {
buf := bmbuf[0:n]
step := 8
for i := 0; i < len(buf); i += step {
buf[i] = 1
}
expect := (len(buf) + (step - 1)) / step
for i := 0; i < b.N; i++ {
j := Count(buf, []byte{1})
if j != expect {
b.Fatal("bad count", j, expect)
}
}
for i := 0; i < len(buf); i++ {
buf[i] = 0
}
})
}
type ExplodeTest struct {
s string
n int
@ -1437,6 +1530,59 @@ func BenchmarkTrimSpace(b *testing.B) {
}
}
func makeBenchInputHard() []byte {
tokens := [...]string{
"<a>", "<p>", "<b>", "<strong>",
"</a>", "</p>", "</b>", "</strong>",
"hello", "world",
}
x := make([]byte, 0, 1<<20)
for {
i := rand.Intn(len(tokens))
if len(x)+len(tokens[i]) >= 1<<20 {
break
}
x = append(x, tokens[i]...)
}
return x
}
var benchInputHard = makeBenchInputHard()
func BenchmarkSplitEmptySeparator(b *testing.B) {
for i := 0; i < b.N; i++ {
Split(benchInputHard, nil)
}
}
func BenchmarkSplitSingleByteSeparator(b *testing.B) {
sep := []byte("/")
for i := 0; i < b.N; i++ {
Split(benchInputHard, sep)
}
}
func BenchmarkSplitMultiByteSeparator(b *testing.B) {
sep := []byte("hello")
for i := 0; i < b.N; i++ {
Split(benchInputHard, sep)
}
}
func BenchmarkSplitNSingleByteSeparator(b *testing.B) {
sep := []byte("/")
for i := 0; i < b.N; i++ {
SplitN(benchInputHard, sep, 10)
}
}
func BenchmarkSplitNMultiByteSeparator(b *testing.B) {
sep := []byte("hello")
for i := 0; i < b.N; i++ {
SplitN(benchInputHard, sep, 10)
}
}
func BenchmarkRepeat(b *testing.B) {
for i := 0; i < b.N; i++ {
Repeat([]byte("-"), 80)

View File

@ -30,6 +30,15 @@ func ExampleBuffer_reader() {
// Output: Gophers rule!
}
func ExampleBuffer_Grow() {
var b bytes.Buffer
b.Grow(64)
bb := b.Bytes()
b.Write([]byte("64 bytes or fewer"))
fmt.Printf("%q", bb[:b.Len()])
// Output: "64 bytes or fewer"
}
func ExampleCompare() {
// Interpret Compare's result by comparing it to zero.
var a, b []byte

View File

@ -7,3 +7,4 @@ package bytes
// Export func for testing
var IndexBytePortable = indexBytePortable
var EqualPortable = equalPortable
var CountGeneric = countGeneric

View File

@ -17,8 +17,8 @@ import (
"strings"
)
func parse(name string, flags parser.Mode) *ast.File {
ast1, err := parser.ParseFile(fset, name, nil, flags)
func parse(name string, src []byte, flags parser.Mode) *ast.File {
ast1, err := parser.ParseFile(fset, name, src, flags)
if err != nil {
if list, ok := err.(scanner.ErrorList); ok {
// If err is a scanner.ErrorList, its String will print just
@ -39,12 +39,12 @@ func sourceLine(n ast.Node) int {
return fset.Position(n.Pos()).Line
}
// ReadGo populates f with information learned from reading the
// Go source file with the given file name. It gathers the C preamble
// ParseGo populates f with information learned from the Go source code
// which was read from the named file. It gathers the C preamble
// attached to the import "C" comment, a list of references to C.xxx,
// a list of exported functions, and the actual AST, to be rewritten and
// printed.
func (f *File) ReadGo(name string) {
func (f *File) ParseGo(name string, src []byte) {
// Create absolute path for file, so that it will be used in error
// messages and recorded in debug line number information.
// This matches the rest of the toolchain. See golang.org/issue/5122.
@ -58,8 +58,8 @@ func (f *File) ReadGo(name string) {
// so we use ast1 to look for the doc comments on import "C"
// and on exported functions, and we use ast2 for translating
// and reprinting.
ast1 := parse(name, parser.ParseComments)
ast2 := parse(name, 0)
ast1 := parse(name, src, parser.ParseComments)
ast2 := parse(name, src, 0)
f.Package = ast1.Name.Name
f.Name = make(map[string]*Name)

View File

@ -14,27 +14,27 @@ as C.stdout, or functions such as C.putchar.
If the import of "C" is immediately preceded by a comment, that
comment, called the preamble, is used as a header when compiling
the C parts of the package. For example:
the C parts of the package. For example:
// #include <stdio.h>
// #include <errno.h>
import "C"
The preamble may contain any C code, including function and variable
declarations and definitions. These may then be referred to from Go
code as though they were defined in the package "C". All names
declarations and definitions. These may then be referred to from Go
code as though they were defined in the package "C". All names
declared in the preamble may be used, even if they start with a
lower-case letter. Exception: static variables in the preamble may
lower-case letter. Exception: static variables in the preamble may
not be referenced from Go code; static functions are permitted.
See $GOROOT/misc/cgo/stdio and $GOROOT/misc/cgo/gmp for examples. See
See $GOROOT/misc/cgo/stdio and $GOROOT/misc/cgo/gmp for examples. See
"C? Go? Cgo!" for an introduction to using cgo:
https://golang.org/doc/articles/c_go_cgo.html.
CFLAGS, CPPFLAGS, CXXFLAGS, FFLAGS and LDFLAGS may be defined with pseudo
#cgo directives within these comments to tweak the behavior of the C, C++
or Fortran compiler. Values defined in multiple directives are concatenated
together. The directive can include a list of build constraints limiting its
or Fortran compiler. Values defined in multiple directives are concatenated
together. The directive can include a list of build constraints limiting its
effect to systems satisfying one of the constraints
(see https://golang.org/pkg/go/build/#hdr-Build_Constraints for details about the constraint syntax).
For example:
@ -57,16 +57,16 @@ The default pkg-config tool may be changed by setting the PKG_CONFIG environment
When building, the CGO_CFLAGS, CGO_CPPFLAGS, CGO_CXXFLAGS, CGO_FFLAGS and
CGO_LDFLAGS environment variables are added to the flags derived from
these directives. Package-specific flags should be set using the
these directives. Package-specific flags should be set using the
directives, not the environment variables, so that builds work in
unmodified environments.
All the cgo CPPFLAGS and CFLAGS directives in a package are concatenated and
used to compile C files in that package. All the CPPFLAGS and CXXFLAGS
used to compile C files in that package. All the CPPFLAGS and CXXFLAGS
directives in a package are concatenated and used to compile C++ files in that
package. All the CPPFLAGS and FFLAGS directives in a package are concatenated
and used to compile Fortran files in that package. All the LDFLAGS directives
in any package in the program are concatenated and used at link time. All the
package. All the CPPFLAGS and FFLAGS directives in a package are concatenated
and used to compile Fortran files in that package. All the LDFLAGS directives
in any package in the program are concatenated and used at link time. All the
pkg-config directives are concatenated and sent to pkg-config simultaneously
to add to each appropriate set of command-line flags.
@ -84,27 +84,27 @@ Will be expanded to:
When the Go tool sees that one or more Go files use the special import
"C", it will look for other non-Go files in the directory and compile
them as part of the Go package. Any .c, .s, or .S files will be
compiled with the C compiler. Any .cc, .cpp, or .cxx files will be
compiled with the C++ compiler. Any .f, .F, .for or .f90 files will be
them as part of the Go package. Any .c, .s, or .S files will be
compiled with the C compiler. Any .cc, .cpp, or .cxx files will be
compiled with the C++ compiler. Any .f, .F, .for or .f90 files will be
compiled with the fortran compiler. Any .h, .hh, .hpp, or .hxx files will
not be compiled separately, but, if these header files are changed,
the C and C++ files will be recompiled. The default C and C++
the C and C++ files will be recompiled. The default C and C++
compilers may be changed by the CC and CXX environment variables,
respectively; those environment variables may include command line
options.
The cgo tool is enabled by default for native builds on systems where
it is expected to work. It is disabled by default when
cross-compiling. You can control this by setting the CGO_ENABLED
it is expected to work. It is disabled by default when
cross-compiling. You can control this by setting the CGO_ENABLED
environment variable when running the go tool: set it to 1 to enable
the use of cgo, and to 0 to disable it. The go tool will set the
the use of cgo, and to 0 to disable it. The go tool will set the
build constraint "cgo" if cgo is enabled.
When cross-compiling, you must specify a C cross-compiler for cgo to
use. You can do this by setting the CC_FOR_TARGET environment
use. You can do this by setting the CC_FOR_TARGET environment
variable when building the toolchain using make.bash, or by setting
the CC environment variable any time you run the go tool. The
the CC environment variable any time you run the go tool. The
CXX_FOR_TARGET and CXX environment variables work in a similar way for
C++ code.
@ -138,7 +138,7 @@ C's union types are represented as a Go byte array with the same length.
Go structs cannot embed fields with C types.
Go code cannot refer to zero-sized fields that occur at the end of
non-empty C structs. To get the address of such a field (which is the
non-empty C structs. To get the address of such a field (which is the
only operation you can do with a zero-sized field) you must take the
address of the struct and add the size of the struct.
@ -150,7 +150,7 @@ is different from the same C type used in another.
Any C function (even void functions) may be called in a multiple
assignment context to retrieve both the return value (if any) and the
C errno variable as an error (use _ to skip the result value if the
function returns void). For example:
function returns void). For example:
n, err = C.sqrt(-1)
_, err := C.voidFunc()
@ -187,11 +187,11 @@ received from Go. For example:
In C, a function argument written as a fixed size array
actually requires a pointer to the first element of the array.
C compilers are aware of this calling convention and adjust
the call accordingly, but Go cannot. In Go, you must pass
the call accordingly, but Go cannot. In Go, you must pass
the pointer to the first element explicitly: C.f(&C.x[0]).
A few special functions convert between Go and C types
by making copies of the data. In pseudo-Go definitions:
by making copies of the data. In pseudo-Go definitions:
// Go string to C string
// The C string is allocated in the C heap using malloc.
@ -253,50 +253,50 @@ must be placed in preambles in other files, or in C source files.
Passing pointers
Go is a garbage collected language, and the garbage collector needs to
know the location of every pointer to Go memory. Because of this,
know the location of every pointer to Go memory. Because of this,
there are restrictions on passing pointers between Go and C.
In this section the term Go pointer means a pointer to memory
allocated by Go (such as by using the & operator or calling the
predefined new function) and the term C pointer means a pointer to
memory allocated by C (such as by a call to C.malloc). Whether a
memory allocated by C (such as by a call to C.malloc). Whether a
pointer is a Go pointer or a C pointer is a dynamic property
determined by how the memory was allocated; it has nothing to do with
the type of the pointer.
Go code may pass a Go pointer to C provided the Go memory to which it
points does not contain any Go pointers. The C code must preserve
points does not contain any Go pointers. The C code must preserve
this property: it must not store any Go pointers in Go memory, even
temporarily. When passing a pointer to a field in a struct, the Go
temporarily. When passing a pointer to a field in a struct, the Go
memory in question is the memory occupied by the field, not the entire
struct. When passing a pointer to an element in an array or slice,
struct. When passing a pointer to an element in an array or slice,
the Go memory in question is the entire array or the entire backing
array of the slice.
C code may not keep a copy of a Go pointer after the call returns.
A Go function called by C code may not return a Go pointer. A Go
A Go function called by C code may not return a Go pointer. A Go
function called by C code may take C pointers as arguments, and it may
store non-pointer or C pointer data through those pointers, but it may
not store a Go pointer in memory pointed to by a C pointer. A Go
not store a Go pointer in memory pointed to by a C pointer. A Go
function called by C code may take a Go pointer as an argument, but it
must preserve the property that the Go memory to which it points does
not contain any Go pointers.
Go code may not store a Go pointer in C memory. C code may store Go
Go code may not store a Go pointer in C memory. C code may store Go
pointers in C memory, subject to the rule above: it must stop storing
the Go pointer when the C function returns.
These rules are checked dynamically at runtime. The checking is
These rules are checked dynamically at runtime. The checking is
controlled by the cgocheck setting of the GODEBUG environment
variable. The default setting is GODEBUG=cgocheck=1, which implements
reasonably cheap dynamic checks. These checks may be disabled
entirely using GODEBUG=cgocheck=0. Complete checking of pointer
variable. The default setting is GODEBUG=cgocheck=1, which implements
reasonably cheap dynamic checks. These checks may be disabled
entirely using GODEBUG=cgocheck=0. Complete checking of pointer
handling, at some cost in run time, is available via GODEBUG=cgocheck=2.
It is possible to defeat this enforcement by using the unsafe package,
and of course there is nothing stopping the C code from doing anything
it likes. However, programs that break these rules are likely to fail
it likes. However, programs that break these rules are likely to fail
in unexpected and unpredictable ways.
Using cgo directly
@ -499,7 +499,7 @@ Here is a _cgo_gotypes.go containing definitions for needed C types:
type _Ctype_void [0]byte
The _cgo_gotypes.go file also contains the definitions of the
functions. They all have similar bodies that invoke runtime·cgocall
functions. They all have similar bodies that invoke runtime·cgocall
to make a switch from the Go runtime world to the system C (GCC-based)
world.
@ -835,7 +835,7 @@ to avoid conflicts), write the go.o file to that directory, and invoke
the host linker. The default value for the host linker is $CC, split
into fields, or else "gcc". The specific host linker command line can
be overridden using command line flags: cmd/link -extld=clang
-extldflags='-ggdb -O3'. If any package in a build includes a .cc or
-extldflags='-ggdb -O3'. If any package in a build includes a .cc or
other file compiled by the C++ compiler, the go tool will use the
-extld option to set the host linker to the C++ compiler.

View File

@ -20,6 +20,7 @@ import (
"go/ast"
"go/parser"
"go/token"
"math"
"os"
"strconv"
"strings"
@ -259,26 +260,26 @@ func (p *Package) guessKinds(f *File) []*Name {
// If we've already found this name as a #define
// and we can translate it as a constant value, do so.
if n.Define != "" {
isConst := false
if _, err := strconv.Atoi(n.Define); err == nil {
isConst = true
} else if n.Define[0] == '"' || n.Define[0] == '\'' {
if _, err := parser.ParseExpr(n.Define); err == nil {
isConst = true
}
}
if isConst {
n.Kind = "const"
if i, err := strconv.ParseInt(n.Define, 0, 64); err == nil {
n.Kind = "iconst"
// Turn decimal into hex, just for consistency
// with enum-derived constants. Otherwise
// in the cgo -godefs output half the constants
// are in hex and half are in whatever the #define used.
i, err := strconv.ParseInt(n.Define, 0, 64)
if err == nil {
n.Const = fmt.Sprintf("%#x", i)
} else {
n.Const = fmt.Sprintf("%#x", i)
} else if n.Define[0] == '\'' {
if _, err := parser.ParseExpr(n.Define); err == nil {
n.Kind = "iconst"
n.Const = n.Define
}
} else if n.Define[0] == '"' {
if _, err := parser.ParseExpr(n.Define); err == nil {
n.Kind = "sconst"
n.Const = n.Define
}
}
if n.IsConst() {
continue
}
@ -287,11 +288,10 @@ func (p *Package) guessKinds(f *File) []*Name {
}
}
needType = append(needType, n)
// If this is a struct, union, or enum type name, no need to guess the kind.
if strings.HasPrefix(n.C, "struct ") || strings.HasPrefix(n.C, "union ") || strings.HasPrefix(n.C, "enum ") {
n.Kind = "type"
needType = append(needType, n)
continue
}
@ -317,14 +317,24 @@ func (p *Package) guessKinds(f *File) []*Name {
// void __cgo_f_xxx_1(void) { __typeof__(name) *__cgo_undefined__; }
// #line xxx "not-type"
// void __cgo_f_xxx_2(void) { name *__cgo_undefined__; }
// #line xxx "not-const"
// #line xxx "not-int-const"
// void __cgo_f_xxx_3(void) { enum { __cgo_undefined__ = (name)*1 }; }
// #line xxx "not-num-const"
// void __cgo_f_xxx_4(void) { static const double x = (name); }
// #line xxx "not-str-lit"
// void __cgo_f_xxx_5(void) { static const char x[] = (name); }
// #line xxx "not-signed-int-const"
// #if 0 < -(name)
// #line xxx "not-signed-int-const"
// #error found unsigned int
// #endif
//
// If we see an error at not-declared:xxx, the corresponding name is not declared.
// If we see an error at not-type:xxx, the corresponding name is a type.
// If we see an error at not-const:xxx, the corresponding name is not an integer constant.
// If we see no errors, we assume the name is an expression but not a constant
// (so a variable or a function).
// If we see an error at not-int-const:xxx, the corresponding name is not an integer constant.
// If we see an error at not-num-const:xxx, the corresponding name is not a number constant.
// If we see an error at not-str-lit:xxx, the corresponding name is not a string literal.
// If we see an error at not-signed-int-const:xxx, the corresponding name is not a signed integer literal.
//
// The specific input forms are chosen so that they are valid C syntax regardless of
// whether name denotes a type or an expression.
@ -338,11 +348,24 @@ func (p *Package) guessKinds(f *File) []*Name {
"void __cgo_f_%d_1(void) { __typeof__(%s) *__cgo_undefined__; }\n"+
"#line %d \"not-type\"\n"+
"void __cgo_f_%d_2(void) { %s *__cgo_undefined__; }\n"+
"#line %d \"not-const\"\n"+
"void __cgo_f_%d_3(void) { enum { __cgo__undefined__ = (%s)*1 }; }\n",
"#line %d \"not-int-const\"\n"+
"void __cgo_f_%d_3(void) { enum { __cgo_undefined__ = (%s)*1 }; }\n"+
"#line %d \"not-num-const\"\n"+
"void __cgo_f_%d_4(void) { static const double x = (%s); }\n"+
"#line %d \"not-str-lit\"\n"+
"void __cgo_f_%d_5(void) { static const char s[] = (%s); }\n"+
"#line %d \"not-signed-int-const\"\n"+
"#if 0 < (%s)\n"+
"#line %d \"not-signed-int-const\"\n"+
"#error found unsigned int\n"+
"#endif\n",
i+1, i+1, n.C,
i+1, i+1, n.C,
i+1, i+1, n.C)
i+1, i+1, n.C,
i+1, i+1, n.C,
i+1, i+1, n.C,
i+1, n.C, i+1,
)
}
fmt.Fprintf(&b, "#line 1 \"completed\"\n"+
"int __cgo__1 = __cgo__2;\n")
@ -356,13 +379,23 @@ func (p *Package) guessKinds(f *File) []*Name {
sniff := make([]int, len(names))
const (
notType = 1 << iota
notConst
notIntConst
notNumConst
notStrLiteral
notDeclared
notSignedIntConst
)
sawUnmatchedErrors := false
for _, line := range strings.Split(stderr, "\n") {
if !strings.Contains(line, ": error:") {
// we only care about errors.
// we tried to turn off warnings on the command line, but one never knows.
// Ignore warnings and random comments, with one
// exception: newer GCC versions will sometimes emit
// an error on a macro #define with a note referring
// to where the expansion occurs. We care about where
// the expansion occurs, so in that case treat the note
// as an error.
isError := strings.Contains(line, ": error:")
isErrorNote := strings.Contains(line, ": note:") && sawUnmatchedErrors
if !isError && !isErrorNote {
continue
}
@ -380,6 +413,9 @@ func (p *Package) guessKinds(f *File) []*Name {
i, _ := strconv.Atoi(line[c1+1 : c2])
i--
if i < 0 || i >= len(names) {
if isError {
sawUnmatchedErrors = true
}
continue
}
@ -395,9 +431,22 @@ func (p *Package) guessKinds(f *File) []*Name {
sniff[i] |= notDeclared
case "not-type":
sniff[i] |= notType
case "not-const":
sniff[i] |= notConst
case "not-int-const":
sniff[i] |= notIntConst
case "not-num-const":
sniff[i] |= notNumConst
case "not-str-lit":
sniff[i] |= notStrLiteral
case "not-signed-int-const":
sniff[i] |= notSignedIntConst
default:
if isError {
sawUnmatchedErrors = true
}
continue
}
sawUnmatchedErrors = false
}
if !completed {
@ -405,14 +454,29 @@ func (p *Package) guessKinds(f *File) []*Name {
}
for i, n := range names {
switch sniff[i] {
switch sniff[i] &^ notSignedIntConst {
default:
error_(token.NoPos, "could not determine kind of name for C.%s", fixGo(n.Go))
case notType:
n.Kind = "const"
case notConst:
var tpos token.Pos
for _, ref := range f.Ref {
if ref.Name == n {
tpos = ref.Pos()
break
}
}
error_(tpos, "could not determine kind of name for C.%s", fixGo(n.Go))
case notStrLiteral | notType:
if sniff[i]&notSignedIntConst != 0 {
n.Kind = "uconst"
} else {
n.Kind = "iconst"
}
case notIntConst | notStrLiteral | notType:
n.Kind = "fconst"
case notIntConst | notNumConst | notType:
n.Kind = "sconst"
case notIntConst | notNumConst | notStrLiteral:
n.Kind = "type"
case notConst | notType:
case notIntConst | notNumConst | notStrLiteral | notType:
n.Kind = "not-type"
}
}
@ -450,18 +514,16 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
b.WriteString("#line 1 \"cgo-dwarf-inference\"\n")
for i, n := range names {
fmt.Fprintf(&b, "__typeof__(%s) *__cgo__%d;\n", n.C, i)
if n.Kind == "const" {
if n.Kind == "iconst" || n.Kind == "uconst" {
fmt.Fprintf(&b, "enum { __cgo_enum__%d = %s };\n", i, n.C)
}
}
// Apple's LLVM-based gcc does not include the enumeration
// names and values in its DWARF debug output. In case we're
// using such a gcc, create a data block initialized with the values.
// We can read them out of the object file.
fmt.Fprintf(&b, "long long __cgodebug_data[] = {\n")
// We create a data block initialized with the values,
// so we can read them out of the object file.
fmt.Fprintf(&b, "long long __cgodebug_ints[] = {\n")
for _, n := range names {
if n.Kind == "const" {
if n.Kind == "iconst" || n.Kind == "uconst" {
fmt.Fprintf(&b, "\t%s,\n", n.C)
} else {
fmt.Fprintf(&b, "\t0,\n")
@ -475,15 +537,30 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
fmt.Fprintf(&b, "\t1\n")
fmt.Fprintf(&b, "};\n")
d, bo, debugData := p.gccDebug(b.Bytes())
enumVal := make([]int64, len(debugData)/8)
for i := range enumVal {
enumVal[i] = int64(bo.Uint64(debugData[i*8:]))
// do the same work for floats.
fmt.Fprintf(&b, "double __cgodebug_floats[] = {\n")
for _, n := range names {
if n.Kind == "fconst" {
fmt.Fprintf(&b, "\t%s,\n", n.C)
} else {
fmt.Fprintf(&b, "\t0,\n")
}
}
fmt.Fprintf(&b, "\t1\n")
fmt.Fprintf(&b, "};\n")
// do the same work for strings.
for i, n := range names {
if n.Kind == "sconst" {
fmt.Fprintf(&b, "const char __cgodebug_str__%d[] = %s;\n", i, n.C)
fmt.Fprintf(&b, "const unsigned long long __cgodebug_strlen__%d = sizeof(%s)-1;\n", i, n.C)
}
}
d, ints, floats, strs := p.gccDebug(b.Bytes(), len(names))
// Scan DWARF info for top-level TagVariable entries with AttrName __cgo__i.
types := make([]dwarf.Type, len(names))
enums := make([]dwarf.Offset, len(names))
nameToIndex := make(map[*Name]int)
for i, n := range names {
nameToIndex[n] = i
@ -502,26 +579,6 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
break
}
switch e.Tag {
case dwarf.TagEnumerationType:
offset := e.Offset
for {
e, err := r.Next()
if err != nil {
fatalf("reading DWARF entry: %s", err)
}
if e.Tag == 0 {
break
}
if e.Tag == dwarf.TagEnumerator {
entryName := e.Val(dwarf.AttrName).(string)
if strings.HasPrefix(entryName, "__cgo_enum__") {
n, _ := strconv.Atoi(entryName[len("__cgo_enum__"):])
if 0 <= n && n < len(names) {
enums[n] = offset
}
}
}
}
case dwarf.TagVariable:
name, _ := e.Val(dwarf.AttrName).(string)
typOff, _ := e.Val(dwarf.AttrType).(dwarf.Offset)
@ -548,15 +605,7 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
if err != nil {
fatalf("malformed __cgo__ name: %s", name)
}
if enums[i] != 0 {
t, err := d.Type(enums[i])
if err != nil {
fatalf("loading DWARF type: %s", err)
}
types[i] = t
} else {
types[i] = t.Type
}
types[i] = t.Type
}
if e.Tag != dwarf.TagCompileUnit {
r.SkipChildren()
@ -580,17 +629,23 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
n.FuncType = conv.FuncType(f, pos)
} else {
n.Type = conv.Type(types[i], pos)
if enums[i] != 0 && n.Type.EnumValues != nil {
k := fmt.Sprintf("__cgo_enum__%d", i)
n.Kind = "const"
n.Const = fmt.Sprintf("%#x", n.Type.EnumValues[k])
// Remove injected enum to ensure the value will deep-compare
// equally in future loads of the same constant.
delete(n.Type.EnumValues, k)
}
// Prefer debug data over DWARF debug output, if we have it.
if n.Kind == "const" && i < len(enumVal) {
n.Const = fmt.Sprintf("%#x", enumVal[i])
switch n.Kind {
case "iconst":
if i < len(ints) {
n.Const = fmt.Sprintf("%#x", ints[i])
}
case "uconst":
if i < len(ints) {
n.Const = fmt.Sprintf("%#x", uint64(ints[i]))
}
case "fconst":
if i < len(floats) {
n.Const = fmt.Sprintf("%f", floats[i])
}
case "sconst":
if i < len(strs) {
n.Const = fmt.Sprintf("%q", strs[i])
}
}
}
conv.FinishType(pos)
@ -1069,7 +1124,7 @@ func (p *Package) rewriteRef(f *File) {
// are trying to do a ,err call. Also check that
// functions are only used in calls.
for _, r := range f.Ref {
if r.Name.Kind == "const" && r.Name.Const == "" {
if r.Name.IsConst() && r.Name.Const == "" {
error_(r.Pos(), "unable to find value of constant C.%s", fixGo(r.Name.Go))
}
var expr ast.Expr = ast.NewIdent(r.Name.Mangle) // default
@ -1109,6 +1164,10 @@ func (p *Package) rewriteRef(f *File) {
}
case "expr":
if r.Name.Kind == "func" {
if builtinDefs[r.Name.C] != "" {
error_(r.Pos(), "use of builtin '%s' not in function call", fixGo(r.Name.C))
}
// Function is being used in an expression, to e.g. pass around a C function pointer.
// Create a new Name for this Ref which causes the variable to be declared in Go land.
fpName := "fp_" + r.Name.Go
@ -1277,12 +1336,55 @@ func (p *Package) gccCmd() []string {
// gccDebug runs gcc -gdwarf-2 over the C program stdin and
// returns the corresponding DWARF data and, if present, debug data block.
func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte) {
func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int64, floats []float64, strs []string) {
runGcc(stdin, p.gccCmd())
isDebugData := func(s string) bool {
isDebugInts := func(s string) bool {
// Some systems use leading _ to denote non-assembly symbols.
return s == "__cgodebug_data" || s == "___cgodebug_data"
return s == "__cgodebug_ints" || s == "___cgodebug_ints"
}
isDebugFloats := func(s string) bool {
// Some systems use leading _ to denote non-assembly symbols.
return s == "__cgodebug_floats" || s == "___cgodebug_floats"
}
indexOfDebugStr := func(s string) int {
// Some systems use leading _ to denote non-assembly symbols.
if strings.HasPrefix(s, "___") {
s = s[1:]
}
if strings.HasPrefix(s, "__cgodebug_str__") {
if n, err := strconv.Atoi(s[len("__cgodebug_str__"):]); err == nil {
return n
}
}
return -1
}
indexOfDebugStrlen := func(s string) int {
// Some systems use leading _ to denote non-assembly symbols.
if strings.HasPrefix(s, "___") {
s = s[1:]
}
if strings.HasPrefix(s, "__cgodebug_strlen__") {
if n, err := strconv.Atoi(s[len("__cgodebug_strlen__"):]); err == nil {
return n
}
}
return -1
}
strs = make([]string, nnames)
strdata := make(map[int]string, nnames)
strlens := make(map[int]int, nnames)
buildStrings := func() {
for n, strlen := range strlens {
data := strdata[n]
if len(data) <= strlen {
fatalf("invalid string literal")
}
strs[n] = string(data[:strlen])
}
}
if f, err := macho.Open(gccTmp()); err == nil {
@ -1291,24 +1393,76 @@ func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte)
if err != nil {
fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
}
var data []byte
bo := f.ByteOrder
if f.Symtab != nil {
for i := range f.Symtab.Syms {
s := &f.Symtab.Syms[i]
if isDebugData(s.Name) {
switch {
case isDebugInts(s.Name):
// Found it. Now find data section.
if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) {
sect := f.Sections[i]
if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
if sdat, err := sect.Data(); err == nil {
data = sdat[s.Value-sect.Addr:]
data := sdat[s.Value-sect.Addr:]
ints = make([]int64, len(data)/8)
for i := range ints {
ints[i] = int64(bo.Uint64(data[i*8:]))
}
}
}
}
case isDebugFloats(s.Name):
// Found it. Now find data section.
if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) {
sect := f.Sections[i]
if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
if sdat, err := sect.Data(); err == nil {
data := sdat[s.Value-sect.Addr:]
floats = make([]float64, len(data)/8)
for i := range floats {
floats[i] = math.Float64frombits(bo.Uint64(data[i*8:]))
}
}
}
}
default:
if n := indexOfDebugStr(s.Name); n != -1 {
// Found it. Now find data section.
if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) {
sect := f.Sections[i]
if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
if sdat, err := sect.Data(); err == nil {
data := sdat[s.Value-sect.Addr:]
strdata[n] = string(data)
}
}
}
break
}
if n := indexOfDebugStrlen(s.Name); n != -1 {
// Found it. Now find data section.
if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) {
sect := f.Sections[i]
if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
if sdat, err := sect.Data(); err == nil {
data := sdat[s.Value-sect.Addr:]
strlen := bo.Uint64(data[:8])
if strlen > (1<<(uint(p.IntSize*8)-1) - 1) { // greater than MaxInt?
fatalf("string literal too big")
}
strlens[n] = int(strlen)
}
}
}
break
}
}
}
buildStrings()
}
return d, f.ByteOrder, data
return d, ints, floats, strs
}
if f, err := elf.Open(gccTmp()); err == nil {
@ -1317,25 +1471,77 @@ func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte)
if err != nil {
fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
}
var data []byte
bo := f.ByteOrder
symtab, err := f.Symbols()
if err == nil {
for i := range symtab {
s := &symtab[i]
if isDebugData(s.Name) {
switch {
case isDebugInts(s.Name):
// Found it. Now find data section.
if i := int(s.Section); 0 <= i && i < len(f.Sections) {
sect := f.Sections[i]
if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
if sdat, err := sect.Data(); err == nil {
data = sdat[s.Value-sect.Addr:]
data := sdat[s.Value-sect.Addr:]
ints = make([]int64, len(data)/8)
for i := range ints {
ints[i] = int64(bo.Uint64(data[i*8:]))
}
}
}
}
case isDebugFloats(s.Name):
// Found it. Now find data section.
if i := int(s.Section); 0 <= i && i < len(f.Sections) {
sect := f.Sections[i]
if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
if sdat, err := sect.Data(); err == nil {
data := sdat[s.Value-sect.Addr:]
floats = make([]float64, len(data)/8)
for i := range floats {
floats[i] = math.Float64frombits(bo.Uint64(data[i*8:]))
}
}
}
}
default:
if n := indexOfDebugStr(s.Name); n != -1 {
// Found it. Now find data section.
if i := int(s.Section); 0 <= i && i < len(f.Sections) {
sect := f.Sections[i]
if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
if sdat, err := sect.Data(); err == nil {
data := sdat[s.Value-sect.Addr:]
strdata[n] = string(data)
}
}
}
break
}
if n := indexOfDebugStrlen(s.Name); n != -1 {
// Found it. Now find data section.
if i := int(s.Section); 0 <= i && i < len(f.Sections) {
sect := f.Sections[i]
if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
if sdat, err := sect.Data(); err == nil {
data := sdat[s.Value-sect.Addr:]
strlen := bo.Uint64(data[:8])
if strlen > (1<<(uint(p.IntSize*8)-1) - 1) { // greater than MaxInt?
fatalf("string literal too big")
}
strlens[n] = int(strlen)
}
}
}
break
}
}
}
buildStrings()
}
return d, f.ByteOrder, data
return d, ints, floats, strs
}
if f, err := pe.Open(gccTmp()); err == nil {
@ -1344,20 +1550,70 @@ func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte)
if err != nil {
fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
}
var data []byte
bo := binary.LittleEndian
for _, s := range f.Symbols {
if isDebugData(s.Name) {
switch {
case isDebugInts(s.Name):
if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
sect := f.Sections[i]
if s.Value < sect.Size {
if sdat, err := sect.Data(); err == nil {
data = sdat[s.Value:]
data := sdat[s.Value:]
ints = make([]int64, len(data)/8)
for i := range ints {
ints[i] = int64(bo.Uint64(data[i*8:]))
}
}
}
}
case isDebugFloats(s.Name):
if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
sect := f.Sections[i]
if s.Value < sect.Size {
if sdat, err := sect.Data(); err == nil {
data := sdat[s.Value:]
floats = make([]float64, len(data)/8)
for i := range floats {
floats[i] = math.Float64frombits(bo.Uint64(data[i*8:]))
}
}
}
}
default:
if n := indexOfDebugStr(s.Name); n != -1 {
if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
sect := f.Sections[i]
if s.Value < sect.Size {
if sdat, err := sect.Data(); err == nil {
data := sdat[s.Value:]
strdata[n] = string(data)
}
}
}
break
}
if n := indexOfDebugStrlen(s.Name); n != -1 {
if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
sect := f.Sections[i]
if s.Value < sect.Size {
if sdat, err := sect.Data(); err == nil {
data := sdat[s.Value:]
strlen := bo.Uint64(data[:8])
if strlen > (1<<(uint(p.IntSize*8)-1) - 1) { // greater than MaxInt?
fatalf("string literal too big")
}
strlens[n] = int(strlen)
}
}
}
break
}
}
}
return d, binary.LittleEndian, data
buildStrings()
return d, ints, floats, strs
}
fatalf("cannot parse gcc output %s as ELF, Mach-O, PE object", gccTmp())
@ -2048,7 +2304,7 @@ func (c *typeConv) FuncType(dtype *dwarf.FuncType, pos token.Pos) *FuncType {
}
var r *Type
var gr []*ast.Field
if _, ok := dtype.ReturnType.(*dwarf.VoidType); ok {
if _, ok := base(dtype.ReturnType).(*dwarf.VoidType); ok {
gr = []*ast.Field{{Type: c.goVoid}}
} else if dtype.ReturnType != nil {
r = c.Type(unqual(dtype.ReturnType), pos)

View File

@ -17,7 +17,7 @@ import (
"go/ast"
"go/printer"
"go/token"
"io"
"io/ioutil"
"os"
"path/filepath"
"reflect"
@ -88,7 +88,7 @@ type Name struct {
Mangle string // name used in generated Go
C string // name used in C
Define string // #define expansion
Kind string // "const", "type", "var", "fpvar", "func", "not-type"
Kind string // "iconst", "uconst", "fconst", "sconst", "type", "var", "fpvar", "func", "not-type"
Type *Type // the type of xxx
FuncType *FuncType
AddError bool
@ -100,6 +100,11 @@ func (n *Name) IsVar() bool {
return n.Kind == "var" || n.Kind == "fpvar"
}
// IsConst reports whether Kind is either "iconst", "uconst", "fconst" or "sconst"
func (n *Name) IsConst() bool {
return strings.HasSuffix(n.Kind, "const")
}
// A ExpFunc is an exported function, callable from C.
// Such functions are identified in the Go input file
// by doc comments containing the line //export ExpName
@ -274,30 +279,28 @@ func main() {
// concern is other cgo wrappers for the same functions.
// Use the beginning of the md5 of the input to disambiguate.
h := md5.New()
for _, input := range goFiles {
if *srcDir != "" {
input = filepath.Join(*srcDir, input)
}
f, err := os.Open(input)
if err != nil {
fatalf("%s", err)
}
io.Copy(h, f)
f.Close()
}
cPrefix = fmt.Sprintf("_%x", h.Sum(nil)[0:6])
fs := make([]*File, len(goFiles))
for i, input := range goFiles {
if *srcDir != "" {
input = filepath.Join(*srcDir, input)
}
b, err := ioutil.ReadFile(input)
if err != nil {
fatalf("%s", err)
}
if _, err = h.Write(b); err != nil {
fatalf("%s", err)
}
f := new(File)
f.ReadGo(input)
f.ParseGo(input, b)
f.DiscardCgoDirectives()
fs[i] = f
}
cPrefix = fmt.Sprintf("_%x", h.Sum(nil)[0:6])
if *objDir == "" {
// make sure that _obj directory exists, so that we can write
// all the output files there.

View File

@ -190,7 +190,7 @@ func (p *Package) writeDefs() {
for _, key := range nameKeys(p.Name) {
n := p.Name[key]
if n.Const != "" {
fmt.Fprintf(fgo2, "const _Cconst_%s = %s\n", n.Go, n.Const)
fmt.Fprintf(fgo2, "const %s = %s\n", n.Mangle, n.Const)
}
}
fmt.Fprintf(fgo2, "\n")
@ -1303,7 +1303,7 @@ const gccProlog = `
*/
#define __cgo_compile_assert_eq(x, y, name) typedef char name[(x-y)*(x-y)*-2+1];
// Check at compile time that the sizes we use match our expectations.
/* Check at compile time that the sizes we use match our expectations. */
#define __cgo_size_assert(t, n) __cgo_compile_assert_eq(sizeof(t), n, _cgo_sizeof_##t##_is_not_##n)
__cgo_size_assert(char, 1)
@ -1328,6 +1328,27 @@ const noTsanProlog = `
`
// This must match the TSAN code in runtime/cgo/libcgo.h.
// This is used when the code is built with the C/C++ Thread SANitizer,
// which is not the same as the Go race detector.
// __tsan_acquire tells TSAN that we are acquiring a lock on a variable,
// in this case _cgo_sync. __tsan_release releases the lock.
// (There is no actual lock, we are just telling TSAN that there is.)
//
// When we call from Go to C we call _cgo_tsan_acquire.
// When the C function returns we call _cgo_tsan_release.
// Similarly, when C calls back into Go we call _cgo_tsan_release
// and then call _cgo_tsan_acquire when we return to C.
// These calls tell TSAN that there is a serialization point at the C call.
//
// This is necessary because TSAN, which is a C/C++ tool, can not see
// the synchronization in the Go code. Without these calls, when
// multiple goroutines call into C code, TSAN does not understand
// that the calls are properly synchronized on the Go side.
//
// To be clear, if the calls are not properly synchronized on the Go side,
// we will be hiding races. But when using TSAN on mixed Go C/C++ code
// it is more important to avoid false positives, which reduce confidence
// in the tool, than to avoid false negatives.
const yesTsanProlog = `
#line 1 "cgo-tsan-prolog"
#define CGO_NO_SANITIZE_THREAD __attribute__ ((no_sanitize_thread))

View File

@ -118,8 +118,8 @@
// a suffix to use in the name of the package installation directory,
// in order to keep output separate from default builds.
// If using the -race flag, the install suffix is automatically set to race
// or, if set explicitly, has _race appended to it. Likewise for the -msan
// flag. Using a -buildmode option that requires non-default compile flags
// or, if set explicitly, has _race appended to it. Likewise for the -msan
// flag. Using a -buildmode option that requires non-default compile flags
// has a similar effect.
// -ldflags 'flag list'
// arguments to pass on each go tool link invocation.
@ -131,16 +131,17 @@
// For example, when building with a non-standard configuration,
// use -pkgdir to keep generated packages in a separate location.
// -tags 'tag list'
// a list of build tags to consider satisfied during the build.
// For more information about build tags, see the description of
// a space-separated list of build tags to consider satisfied during the
// build. For more information about build tags, see the description of
// build constraints in the documentation for the go/build package.
// -toolexec 'cmd args'
// a program to use to invoke toolchain programs like vet and asm.
// For example, instead of running asm, the go command will run
// 'cmd args /path/to/asm <arguments for asm>'.
//
// The list flags accept a space-separated list of strings. To embed spaces
// in an element in the list, surround it with either single or double quotes.
// All the flags that take a list of arguments accept a space-separated
// list of strings. To embed spaces in an element in the list, surround
// it with either single or double quotes.
//
// For more about specifying packages, see 'go help packages'.
// For more about where packages and binaries are installed,
@ -208,12 +209,13 @@
//
// Usage:
//
// go doc [-u] [-c] [package|[package.]symbol[.method]]
// go doc [-u] [-c] [package|[package.]symbol[.methodOrField]]
//
// Doc prints the documentation comments associated with the item identified by its
// arguments (a package, const, func, type, var, or method) followed by a one-line
// summary of each of the first-level items "under" that item (package-level
// declarations for a package, methods for a type, etc.).
// arguments (a package, const, func, type, var, method, or struct field)
// followed by a one-line summary of each of the first-level items "under"
// that item (package-level declarations for a package, methods for a type,
// etc.).
//
// Doc accepts zero, one, or two arguments.
//
@ -231,9 +233,9 @@
// which is schematically one of these:
//
// go doc <pkg>
// go doc <sym>[.<method>]
// go doc [<pkg>.]<sym>[.<method>]
// go doc [<pkg>.][<sym>.]<method>
// go doc <sym>[.<methodOrField>]
// go doc [<pkg>.]<sym>[.<methodOrField>]
// go doc [<pkg>.][<sym>.]<methodOrField>
//
// The first item in this list matched by the argument is the one whose documentation
// is printed. (See the examples below.) However, if the argument starts with a capital
@ -241,7 +243,7 @@
//
// For packages, the order of scanning is determined lexically in breadth-first order.
// That is, the package presented is the one that matches the search and is nearest
// the root and lexically first at its level of the hierarchy. The GOROOT tree is
// the root and lexically first at its level of the hierarchy. The GOROOT tree is
// always scanned in its entirety before GOPATH.
//
// If there is no package specified or matched, the package in the current
@ -253,10 +255,10 @@
// elements like . and ... are not implemented by go doc.
//
// When run with two arguments, the first must be a full package path (not just a
// suffix), and the second is a symbol or symbol and method; this is similar to the
// syntax accepted by godoc:
// suffix), and the second is a symbol, or symbol with method or struct field.
// This is similar to the syntax accepted by godoc:
//
// go doc <pkg> <sym>[.<method>]
// go doc <pkg> <sym>[.<methodOrField>]
//
// In all forms, when matching symbols, lower-case letters in the argument match
// either case but upper-case letters match exactly. This means that there may be
@ -307,22 +309,25 @@
// when showing the package's top-level documentation.
// -u
// Show documentation for unexported as well as exported
// symbols and methods.
// symbols, methods, and fields.
//
//
// Print Go environment information
//
// Usage:
//
// go env [var ...]
// go env [-json] [var ...]
//
// Env prints Go environment information.
//
// By default env prints information as a shell script
// (on Windows, a batch file). If one or more variable
// names is given as arguments, env prints the value of
// (on Windows, a batch file). If one or more variable
// names is given as arguments, env prints the value of
// each named variable on its own line.
//
// The -json flag prints the environment in JSON format
// instead of as a shell script.
//
//
// Start a bug report
//
@ -357,7 +362,7 @@
// go fmt [-n] [-x] [packages]
//
// Fmt runs the command 'gofmt -l -w' on the packages named
// by the import paths. It prints the names of the files that are modified.
// by the import paths. It prints the names of the files that are modified.
//
// For more about gofmt, see 'go doc cmd/gofmt'.
// For more about specifying packages, see 'go help packages'.
@ -427,7 +432,7 @@
// As a last step before running the command, any invocations of any
// environment variables with alphanumeric names, such as $GOFILE or
// $HOME, are expanded throughout the command line. The syntax for
// variable expansion is $NAME on all operating systems. Due to the
// variable expansion is $NAME on all operating systems. Due to the
// order of evaluation, variables are expanded even inside quoted
// strings. If the variable NAME is not set, $NAME expands to the
// empty string.
@ -504,7 +509,7 @@
// the tests for the specified packages.
//
// The -u flag instructs get to use the network to update the named packages
// and their dependencies. By default, get uses the network to check out
// and their dependencies. By default, get uses the network to check out
// missing packages but does not use it to look for updates to existing packages.
//
// The -v flag enables verbose progress and debug output.
@ -518,8 +523,8 @@
// When checking out or updating a package, get looks for a branch or tag
// that matches the locally installed version of Go. The most important
// rule is that if the local installation is running version "go1", get
// searches for a branch or tag named "go1". If no such version exists it
// retrieves the most recent version of the package.
// searches for a branch or tag named "go1". If no such version exists
// it retrieves the default branch of the package.
//
// When go get checks out or updates a Git repository,
// it also updates any git submodules referenced by the repository.
@ -565,7 +570,7 @@
// golang.org/x/net/html
//
// The -f flag specifies an alternate format for the list, using the
// syntax of package template. The default output is equivalent to -f
// syntax of package template. The default output is equivalent to -f
// '{{.ImportPath}}'. The struct being passed to the template is:
//
// type Package struct {
@ -658,12 +663,12 @@
// instead of using the template format.
//
// The -e flag changes the handling of erroneous packages, those that
// cannot be found or are malformed. By default, the list command
// cannot be found or are malformed. By default, the list command
// prints an error to standard error for each erroneous package and
// omits the packages from consideration during the usual printing.
// With the -e flag, the list command never prints errors to standard
// error and instead processes the erroneous packages with the usual
// printing. Erroneous packages will have a non-empty ImportPath and
// printing. Erroneous packages will have a non-empty ImportPath and
// a non-nil Error field; other information may or may not be missing
// (zeroed).
//
@ -716,7 +721,7 @@
// the file pattern "*_test.go".
// Files whose names begin with "_" (including "_test.go") or "." are ignored.
// These additional files can contain test functions, benchmark functions, and
// example functions. See 'go help testfunc' for more.
// example functions. See 'go help testfunc' for more.
// Each listed package causes the execution of a separate test binary.
//
// Test files that declare a package with the suffix "_test" will be compiled as a
@ -725,7 +730,7 @@
// The go tool will ignore a directory named "testdata", making it available
// to hold ancillary data needed by the tests.
//
// By default, go test needs no arguments. It compiles and tests the package
// By default, go test needs no arguments. It compiles and tests the package
// with source in the current directory, including tests, and runs the tests.
//
// The package is built in a temporary directory so it does not interfere with the
@ -793,15 +798,13 @@
//
// Usage:
//
// go vet [-n] [-x] [build flags] [packages]
// go vet [-n] [-x] [build flags] [vet flags] [packages]
//
// Vet runs the Go vet command on the packages named by the import paths.
//
// For more about vet, see 'go doc cmd/vet'.
// For more about vet and its flags, see 'go doc cmd/vet'.
// For more about specifying packages, see 'go help packages'.
//
// To run the vet tool with specific options, run 'go tool vet'.
//
// The -n flag prints commands that would be executed.
// The -x flag prints commands as they are executed.
//
@ -814,18 +817,18 @@
//
// There are two different ways to call between Go and C/C++ code.
//
// The first is the cgo tool, which is part of the Go distribution. For
// The first is the cgo tool, which is part of the Go distribution. For
// information on how to use it see the cgo documentation (go doc cmd/cgo).
//
// The second is the SWIG program, which is a general tool for
// interfacing between languages. For information on SWIG see
// http://swig.org/. When running go build, any file with a .swig
// extension will be passed to SWIG. Any file with a .swigcxx extension
// interfacing between languages. For information on SWIG see
// http://swig.org/. When running go build, any file with a .swig
// extension will be passed to SWIG. Any file with a .swigcxx extension
// will be passed to SWIG with the -c++ option.
//
// When either cgo or SWIG is used, go build will pass any .c, .m, .s,
// or .S files to the C compiler, and any .cc, .cpp, .cxx files to the C++
// compiler. The CC or CXX environment variables may be set to determine
// compiler. The CC or CXX environment variables may be set to determine
// the C or C++ compiler, respectively, to use.
//
//
@ -846,10 +849,10 @@
// exactly one main package to be listed.
//
// -buildmode=c-shared
// Build the listed main packages, plus all packages that they
// import, into C shared libraries. The only callable symbols will
// Build the listed main package, plus all packages it imports,
// into a C shared library. The only callable symbols will
// be those functions exported using a cgo //export comment.
// Non-main packages are ignored.
// Requires exactly one main package to be listed.
//
// -buildmode=default
// Listed main packages are built into executables and listed
@ -938,7 +941,7 @@
//
// Each directory listed in GOPATH must have a prescribed structure:
//
// The src directory holds source code. The path below src
// The src directory holds source code. The path below src
// determines the import path or executable name.
//
// The pkg directory holds installed package objects.
@ -952,11 +955,11 @@
//
// The bin directory holds compiled commands.
// Each command is named for its source directory, but only
// the final element, not the entire path. That is, the
// the final element, not the entire path. That is, the
// command with source in DIR/src/foo/quux is installed into
// DIR/bin/quux, not DIR/bin/foo/quux. The "foo/" prefix is stripped
// DIR/bin/quux, not DIR/bin/foo/quux. The "foo/" prefix is stripped
// so that you can add DIR/bin to your PATH to get at the
// installed commands. If the GOBIN environment variable is
// installed commands. If the GOBIN environment variable is
// set, commands are installed to the directory it names instead
// of DIR/bin. GOBIN must be an absolute path.
//
@ -1099,7 +1102,7 @@
// CC
// The command to use to compile C code.
// CGO_ENABLED
// Whether the cgo command is supported. Either 0 or 1.
// Whether the cgo command is supported. Either 0 or 1.
// CGO_CFLAGS
// Flags that cgo will pass to the compiler when compiling
// C code.
@ -1151,7 +1154,7 @@
// Import path syntax
//
// An import path (see 'go help packages') denotes a package stored in the local
// file system. In general, an import path denotes either a standard package (such
// file system. In general, an import path denotes either a standard package (such
// as "unicode/utf8") or a package found in one of the work spaces (For more
// details see: 'go help gopath').
//
@ -1222,7 +1225,7 @@
//
// specifies the given repository, with or without the .vcs suffix,
// using the named version control system, and then the path inside
// that repository. The supported version control systems are:
// that repository. The supported version control systems are:
//
// Bazaar .bzr
// Git .git
@ -1242,7 +1245,7 @@
// example.org/repo or repo.git.
//
// When a version control system supports multiple protocols,
// each is tried in turn when downloading. For example, a Git
// each is tried in turn when downloading. For example, a Git
// download tries https://, then git+ssh://.
//
// By default, downloads are restricted to known secure protocols
@ -1360,17 +1363,28 @@
//
// An import path is a pattern if it includes one or more "..." wildcards,
// each of which can match any string, including the empty string and
// strings containing slashes. Such a pattern expands to all package
// strings containing slashes. Such a pattern expands to all package
// directories found in the GOPATH trees with names matching the
// patterns. As a special case, x/... matches x as well as x's subdirectories.
// For example, net/... expands to net and packages in its subdirectories.
// patterns.
//
// To make common patterns more convenient, there are two special cases.
// First, /... at the end of the pattern can match an empty string,
// so that net/... matches both net and packages in its subdirectories, like net/http.
// Second, any slash-separated pattern element containing a wildcard never
// participates in a match of the "vendor" element in the path of a vendored
// package, so that ./... does not match packages in subdirectories of
// ./vendor or ./mycode/vendor, but ./vendor/... and ./mycode/vendor/... do.
// Note, however, that a directory named vendor that itself contains code
// is not a vendored package: cmd/vendor would be a command named vendor,
// and the pattern cmd/... matches it.
// See golang.org/s/go15vendor for more about vendoring.
//
// An import path can also name a package to be downloaded from
// a remote repository. Run 'go help importpath' for details.
// a remote repository. Run 'go help importpath' for details.
//
// Every package in a program must have a unique import path.
// By convention, this is arranged by starting each path with a
// unique prefix that belongs to you. For example, paths used
// unique prefix that belongs to you. For example, paths used
// internally at Google all begin with 'google', and paths
// denoting remote repositories begin with the path to the code,
// such as 'github.com/user/repo'.
@ -1399,19 +1413,24 @@
//
// Several of the flags control profiling and write an execution profile
// suitable for "go tool pprof"; run "go tool pprof -h" for more
// information. The --alloc_space, --alloc_objects, and --show_bytes
// information. The --alloc_space, --alloc_objects, and --show_bytes
// options of pprof control how the information is presented.
//
// The following flags are recognized by the 'go test' command and
// control the execution of any test:
//
// -bench regexp
// Run (sub)benchmarks matching a regular expression.
// The given regular expression is split into smaller ones by
// top-level '/', where each must match the corresponding part of a
// benchmark's identifier.
// By default, no benchmarks run. To run all benchmarks,
// use '-bench .' or '-bench=.'.
// Run only those benchmarks matching a regular expression.
// By default, no benchmarks are run.
// To run all benchmarks, use '-bench .' or '-bench=.'.
// The regular expression is split by unbracketed slash (/)
// characters into a sequence of regular expressions, and each
// part of a benchmark's identifier must match the corresponding
// element in the sequence, if any. Possible parents of matches
// are run with b.N=1 to identify sub-benchmarks. For example,
// given -bench=X/Y, top-level benchmarks matching X are run
// with b.N=1 to find any sub-benchmarks matching Y, which are
// then run in full.
//
// -benchtime t
// Run enough iterations of each benchmark to take t, specified
@ -1425,6 +1444,10 @@
//
// -cover
// Enable coverage analysis.
// Note that because coverage works by annotating the source
// code before compilation, compilation and test failures with
// coverage enabled may report line numbers that don't correspond
// to the original sources.
//
// -covermode set,count,atomic
// Set the mode for coverage analysis for the package[s]
@ -1445,9 +1468,14 @@
//
// -cpu 1,2,4
// Specify a list of GOMAXPROCS values for which the tests or
// benchmarks should be executed. The default is the current value
// benchmarks should be executed. The default is the current value
// of GOMAXPROCS.
//
// -list regexp
// List tests, benchmarks, or examples matching the regular expression.
// No tests, benchmarks or examples will be run. This will only
// list top-level tests. No subtest or subbenchmarks will be shown.
//
// -parallel n
// Allow parallel execution of test functions that call t.Parallel.
// The value of this flag is the maximum number of tests to run
@ -1459,9 +1487,13 @@
//
// -run regexp
// Run only those tests and examples matching the regular expression.
// For tests the regular expression is split into smaller ones by
// top-level '/', where each must match the corresponding part of a
// test's identifier.
// For tests, the regular expression is split by unbracketed slash (/)
// characters into a sequence of regular expressions, and each part
// of a test's identifier must match the corresponding element in
// the sequence, if any. Note that possible parents of matches are
// run too, so that -run=X/Y matches and runs and reports the result
// of all tests matching X, even those without sub-tests matching Y,
// because it must run them to look for those sub-tests.
//
// -short
// Tell long-running tests to shorten their run time.
@ -1469,8 +1501,8 @@
// the Go tree can run a sanity check but not spend time running
// exhaustive tests.
//
// -timeout t
// If a test runs longer than t, panic.
// -timeout d
// If a test binary runs longer than duration d, panic.
// The default is 10 minutes (10m).
//
// -v
@ -1493,7 +1525,7 @@
// calling runtime.SetBlockProfileRate with n.
// See 'go doc runtime.SetBlockProfileRate'.
// The profiler aims to sample, on average, one blocking event every
// n nanoseconds the program spends blocked. By default,
// n nanoseconds the program spends blocked. By default,
// if -test.blockprofile is set without this flag, all blocking events
// are recorded, equivalent to -test.blockprofilerate=1.
//
@ -1511,7 +1543,7 @@
//
// -memprofilerate n
// Enable more precise (and expensive) memory profiles by setting
// runtime.MemProfileRate. See 'go doc runtime.MemProfileRate'.
// runtime.MemProfileRate. See 'go doc runtime.MemProfileRate'.
// To profile all memory allocations, use -test.memprofilerate=1
// and pass --alloc_space flag to the pprof tool.
//
@ -1614,8 +1646,8 @@
// "Output:" is compiled, executed, and expected to produce no output.
//
// Godoc displays the body of ExampleXXX to demonstrate the use
// of the function, constant, or variable XXX. An example of a method M with
// receiver type T or *T is named ExampleT_M. There may be multiple examples
// of the function, constant, or variable XXX. An example of a method M with
// receiver type T or *T is named ExampleT_M. There may be multiple examples
// for a given function, constant, or variable, distinguished by a trailing _xxx,
// where xxx is a suffix not beginning with an upper case letter.
//

View File

@ -1,44 +0,0 @@
// Copyright 2016 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 main
import (
"os"
"reflect"
"testing"
)
func TestRemoveDevNull(t *testing.T) {
fi, err := os.Lstat(os.DevNull)
if err != nil {
t.Skip(err)
}
if fi.Mode().IsRegular() {
t.Errorf("Lstat(%s).Mode().IsRegular() = true; expected false", os.DevNull)
}
mayberemovefile(os.DevNull)
_, err = os.Lstat(os.DevNull)
if err != nil {
t.Errorf("mayberemovefile(%s) did remove it; oops", os.DevNull)
}
}
func TestSplitPkgConfigOutput(t *testing.T) {
for _, test := range []struct {
in []byte
want []string
}{
{[]byte(`-r:foo -L/usr/white\ space/lib -lfoo\ bar -lbar\ baz`), []string{"-r:foo", "-L/usr/white space/lib", "-lfoo bar", "-lbar baz"}},
{[]byte(`-lextra\ fun\ arg\\`), []string{`-lextra fun arg\`}},
{[]byte(`broken flag\`), []string{"broken", "flag"}},
{[]byte("\textra whitespace\r\n"), []string{"extra", "whitespace"}},
{[]byte(" \r\n "), nil},
} {
got := splitPkgConfigOutput(test.in)
if !reflect.DeepEqual(got, test.want) {
t.Errorf("splitPkgConfigOutput(%v) = %v; want %v", test.in, got, test.want)
}
}
}

View File

@ -1,138 +0,0 @@
// 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.
package main
import (
"fmt"
"os"
"runtime"
"strings"
)
var cmdEnv = &Command{
Run: runEnv,
UsageLine: "env [var ...]",
Short: "print Go environment information",
Long: `
Env prints Go environment information.
By default env prints information as a shell script
(on Windows, a batch file). If one or more variable
names is given as arguments, env prints the value of
each named variable on its own line.
`,
}
type envVar struct {
name, value string
}
func mkEnv() []envVar {
var b builder
b.init()
env := []envVar{
{"GOARCH", goarch},
{"GOBIN", gobin},
{"GOEXE", exeSuffix},
{"GOHOSTARCH", runtime.GOARCH},
{"GOHOSTOS", runtime.GOOS},
{"GOOS", goos},
{"GOPATH", buildContext.GOPATH},
{"GORACE", os.Getenv("GORACE")},
{"GOROOT", goroot},
{"GOTOOLDIR", toolDir},
// disable escape codes in clang errors
{"TERM", "dumb"},
}
if gccgoBin != "" {
env = append(env, envVar{"GCCGO", gccgoBin})
} else {
env = append(env, envVar{"GCCGO", gccgoName})
}
switch goarch {
case "arm":
env = append(env, envVar{"GOARM", os.Getenv("GOARM")})
case "386":
env = append(env, envVar{"GO386", os.Getenv("GO386")})
}
cmd := b.gccCmd(".")
env = append(env, envVar{"CC", cmd[0]})
env = append(env, envVar{"GOGCCFLAGS", strings.Join(cmd[3:], " ")})
cmd = b.gxxCmd(".")
env = append(env, envVar{"CXX", cmd[0]})
if buildContext.CgoEnabled {
env = append(env, envVar{"CGO_ENABLED", "1"})
} else {
env = append(env, envVar{"CGO_ENABLED", "0"})
}
return env
}
func findEnv(env []envVar, name string) string {
for _, e := range env {
if e.name == name {
return e.value
}
}
return ""
}
// extraEnvVars returns environment variables that should not leak into child processes.
func extraEnvVars() []envVar {
var b builder
b.init()
cppflags, cflags, cxxflags, fflags, ldflags := b.cflags(&Package{})
return []envVar{
{"PKG_CONFIG", b.pkgconfigCmd()},
{"CGO_CFLAGS", strings.Join(cflags, " ")},
{"CGO_CPPFLAGS", strings.Join(cppflags, " ")},
{"CGO_CXXFLAGS", strings.Join(cxxflags, " ")},
{"CGO_FFLAGS", strings.Join(fflags, " ")},
{"CGO_LDFLAGS", strings.Join(ldflags, " ")},
}
}
func runEnv(cmd *Command, args []string) {
env := newEnv
env = append(env, extraEnvVars()...)
if len(args) > 0 {
for _, name := range args {
fmt.Printf("%s\n", findEnv(env, name))
}
return
}
for _, e := range env {
if e.name != "TERM" {
switch runtime.GOOS {
default:
fmt.Printf("%s=\"%s\"\n", e.name, e.value)
case "plan9":
if strings.IndexByte(e.value, '\x00') < 0 {
fmt.Printf("%s='%s'\n", e.name, strings.Replace(e.value, "'", "''", -1))
} else {
v := strings.Split(e.value, "\x00")
fmt.Printf("%s=(", e.name)
for x, s := range v {
if x > 0 {
fmt.Printf(" ")
}
fmt.Printf("%s", s)
}
fmt.Printf(")\n")
}
case "windows":
fmt.Printf("set %s=%s\n", e.name, e.value)
}
}
}
}

View File

@ -7,7 +7,6 @@ package main_test
import (
"bytes"
"fmt"
"go/build"
"go/format"
"internal/race"
"internal/testenv"
@ -74,6 +73,13 @@ func init() {
}
}
// testGOROOT is the GOROOT to use when running testgo, a cmd/go binary
// build from this process's current GOROOT, but run from a different
// (temp) directory.
var testGOROOT string
var testCC string
// The TestMain function creates a go command for testing purposes and
// deletes it after the tests have been run.
func TestMain(m *testing.M) {
@ -88,6 +94,20 @@ func TestMain(m *testing.M) {
os.Exit(2)
}
out, err = exec.Command("go", "env", "GOROOT").CombinedOutput()
if err != nil {
fmt.Fprintf(os.Stderr, "could not find testing GOROOT: %v\n%s", err, out)
os.Exit(2)
}
testGOROOT = strings.TrimSpace(string(out))
out, err = exec.Command("go", "env", "CC").CombinedOutput()
if err != nil {
fmt.Fprintf(os.Stderr, "could not find testing CC: %v\n%s", err, out)
os.Exit(2)
}
testCC = strings.TrimSpace(string(out))
if out, err := exec.Command("./testgo"+exeSuffix, "env", "CGO_ENABLED").Output(); err != nil {
fmt.Fprintf(os.Stderr, "running testgo failed: %v\n", err)
canRun = false
@ -100,7 +120,9 @@ func TestMain(m *testing.M) {
switch runtime.GOOS {
case "linux", "darwin", "freebsd", "windows":
canRace = canCgo && runtime.GOARCH == "amd64" && runtime.Compiler != "gccgo"
// The race detector doesn't work on Alpine Linux:
// golang.org/issue/14481
canRace = canCgo && runtime.GOARCH == "amd64" && !isAlpineLinux() && runtime.Compiler != "gccgo"
}
}
@ -111,7 +133,7 @@ func TestMain(m *testing.M) {
if home, ccacheDir := os.Getenv("HOME"), os.Getenv("CCACHE_DIR"); home != "" && ccacheDir == "" {
// On some systems the default C compiler is ccache.
// Setting HOME to a non-existent directory will break
// those systems. Set CCACHE_DIR to cope. Issue 17668.
// those systems. Set CCACHE_DIR to cope. Issue 17668.
os.Setenv("CCACHE_DIR", filepath.Join(home, ".ccache"))
}
os.Setenv("HOME", "/test-go-home-does-not-exist")
@ -125,6 +147,14 @@ func TestMain(m *testing.M) {
os.Exit(r)
}
func isAlpineLinux() bool {
if runtime.GOOS != "linux" {
return false
}
fi, err := os.Lstat("/etc/alpine-release")
return err == nil && fi.Mode().IsRegular()
}
// The length of an mtime tick on this system. This is an estimate of
// how long we need to sleep to ensure that the mtime of two files is
// different.
@ -251,6 +281,13 @@ func (tg *testgoData) unsetenv(name string) {
}
}
func (tg *testgoData) goTool() string {
if tg.wd == "" {
return "./testgo" + exeSuffix
}
return filepath.Join(tg.wd, "testgo"+exeSuffix)
}
// doRun runs the test go command, recording stdout and stderr and
// returning exit status.
func (tg *testgoData) doRun(args []string) error {
@ -264,13 +301,20 @@ func (tg *testgoData) doRun(args []string) error {
}
}
}
tg.t.Logf("running testgo %v", args)
var prog string
if tg.wd == "" {
prog = "./testgo" + exeSuffix
} else {
prog = filepath.Join(tg.wd, "testgo"+exeSuffix)
hasGoroot := false
for _, v := range tg.env {
if strings.HasPrefix(v, "GOROOT=") {
hasGoroot = true
break
}
}
prog := tg.goTool()
if !hasGoroot {
tg.setenv("GOROOT", testGOROOT)
}
tg.t.Logf("running testgo %v", args)
cmd := exec.Command(prog, args...)
tg.stdout.Reset()
tg.stderr.Reset()
@ -365,7 +409,7 @@ func (tg *testgoData) doGrepMatch(match string, b *bytes.Buffer) bool {
// doGrep looks for a regular expression in a buffer and fails if it
// is not found. The name argument is the name of the output we are
// searching, "output" or "error". The msg argument is logged on
// searching, "output" or "error". The msg argument is logged on
// failure.
func (tg *testgoData) doGrep(match string, b *bytes.Buffer, name, msg string) {
if !tg.doGrepMatch(match, b) {
@ -1354,7 +1398,7 @@ func TestInstallFailsWithNoBuildableFiles(t *testing.T) {
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.setenv("CGO_ENABLED", "0")
tg.runFail("install", "cgotest")
tg.grepStderr("no buildable Go source files", "go install cgotest did not report 'no buildable Go Source files'")
tg.grepStderr("build constraints exclude all Go files", "go install cgotest did not report 'build constraints exclude all Go files'")
}
func TestRelativeGOBINFail(t *testing.T) {
@ -1483,11 +1527,11 @@ func TestGoGetNonPkg(t *testing.T) {
tg.setenv("GOPATH", tg.path("."))
tg.setenv("GOBIN", tg.path("gobin"))
tg.runFail("get", "-d", "golang.org/x/tools")
tg.grepStderr("golang.org/x/tools: no buildable Go source files", "missing error")
tg.grepStderr("golang.org/x/tools: no Go files", "missing error")
tg.runFail("get", "-d", "-u", "golang.org/x/tools")
tg.grepStderr("golang.org/x/tools: no buildable Go source files", "missing error")
tg.grepStderr("golang.org/x/tools: no Go files", "missing error")
tg.runFail("get", "-d", "golang.org/x/tools")
tg.grepStderr("golang.org/x/tools: no buildable Go source files", "missing error")
tg.grepStderr("golang.org/x/tools: no Go files", "missing error")
}
func TestGoGetTestOnlyPkg(t *testing.T) {
@ -1753,7 +1797,7 @@ func TestDefaultGOPATHPrintedSearchList(t *testing.T) {
tg.grepStderr(regexp.QuoteMeta(tg.path("home/go/src/github.com/golang/example/hello"))+`.*from \$GOPATH`, "expected default GOPATH")
}
// Issue 4186. go get cannot be used to download packages to $GOROOT.
// Issue 4186. go get cannot be used to download packages to $GOROOT.
// Test that without GOPATH set, go get should fail.
func TestGoGetIntoGOROOT(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
@ -1895,10 +1939,7 @@ func TestGoTestDashIDashOWritesBinary(t *testing.T) {
// Issue 4568.
func TestSymlinksList(t *testing.T) {
switch runtime.GOOS {
case "plan9", "windows":
t.Skipf("skipping symlink test on %s", runtime.GOOS)
}
testenv.MustHaveSymlink(t)
tg := testgo(t)
defer tg.cleanup()
@ -1916,10 +1957,7 @@ func TestSymlinksList(t *testing.T) {
// Issue 14054.
func TestSymlinksVendor(t *testing.T) {
switch runtime.GOOS {
case "plan9", "windows":
t.Skipf("skipping symlink test on %s", runtime.GOOS)
}
testenv.MustHaveSymlink(t)
tg := testgo(t)
defer tg.cleanup()
@ -1943,10 +1981,7 @@ func TestSymlinksVendor(t *testing.T) {
// Issue 15201.
func TestSymlinksVendor15201(t *testing.T) {
switch runtime.GOOS {
case "plan9", "windows":
t.Skipf("skipping symlink test on %s", runtime.GOOS)
}
testenv.MustHaveSymlink(t)
tg := testgo(t)
defer tg.cleanup()
@ -1963,10 +1998,7 @@ func TestSymlinksVendor15201(t *testing.T) {
}
func TestSymlinksInternal(t *testing.T) {
switch runtime.GOOS {
case "plan9", "windows":
t.Skipf("skipping symlink test on %s", runtime.GOOS)
}
testenv.MustHaveSymlink(t)
tg := testgo(t)
defer tg.cleanup()
@ -2030,8 +2062,10 @@ func TestCaseCollisions(t *testing.T) {
)`)
tg.tempFile("src/example/a/pkg/pkg.go", `package pkg`)
tg.tempFile("src/example/a/Pkg/pkg.go", `package pkg`)
tg.runFail("list", "example/a")
tg.grepStderr("case-insensitive import collision", "go list example/a did not report import collision")
tg.run("list", "-json", "example/a")
tg.grepStdout("case-insensitive import collision", "go list -json example/a did not report import collision")
tg.runFail("build", "example/a")
tg.grepStderr("case-insensitive import collision", "go build example/a did not report import collision")
tg.tempFile("src/example/b/file.go", `package b`)
tg.tempFile("src/example/b/FILE.go", `package b`)
f, err := os.Open(tg.path("src/example/b"))
@ -2049,6 +2083,38 @@ func TestCaseCollisions(t *testing.T) {
}
tg.runFail(args...)
tg.grepStderr("case-insensitive file name collision", "go list example/b did not report file name collision")
tg.runFail("list", "example/a/pkg", "example/a/Pkg")
tg.grepStderr("case-insensitive import collision", "go list example/a/pkg example/a/Pkg did not report import collision")
tg.run("list", "-json", "-e", "example/a/pkg", "example/a/Pkg")
tg.grepStdout("case-insensitive import collision", "go list -json -e example/a/pkg example/a/Pkg did not report import collision")
tg.runFail("build", "example/a/pkg", "example/a/Pkg")
tg.grepStderr("case-insensitive import collision", "go build example/a/pkg example/a/Pkg did not report import collision")
}
// Issue 17451, 17662.
func TestSymlinkWarning(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.parallel()
tg.makeTempdir()
tg.setenv("GOPATH", tg.path("."))
tg.tempDir("src/example/xx")
tg.tempDir("yy/zz")
tg.tempFile("yy/zz/zz.go", "package zz\n")
if err := os.Symlink(tg.path("yy"), tg.path("src/example/xx/yy")); err != nil {
t.Skip("symlink failed: %v", err)
}
tg.run("list", "example/xx/z...")
tg.grepStdoutNot(".", "list should not have matched anything")
tg.grepStderr("matched no packages", "list should have reported that pattern matched no packages")
tg.grepStderrNot("symlink", "list should not have reported symlink")
tg.run("list", "example/xx/...")
tg.grepStdoutNot(".", "list should not have matched anything")
tg.grepStderr("matched no packages", "list should have reported that pattern matched no packages")
tg.grepStderr("ignoring symlink", "list should have reported symlink")
}
// Issue 8181.
@ -2195,29 +2261,6 @@ func TestCoverageUsesAtomicModeForRace(t *testing.T) {
checkCoverage(tg, data)
}
func TestCoverageUsesActualSettingToOverrideEvenForRace(t *testing.T) {
if testing.Short() {
t.Skip("don't build libraries for coverage in short mode")
}
if !canRace {
t.Skip("skipping because race detector not supported")
}
tg := testgo(t)
defer tg.cleanup()
tg.creatingTemp("testdata/cover.out")
tg.run("test", "-short", "-race", "-cover", "encoding/binary", "-covermode=count", "-coverprofile=testdata/cover.out")
data := tg.getStdout() + tg.getStderr()
if out, err := ioutil.ReadFile("testdata/cover.out"); err != nil {
t.Error(err)
} else {
if !bytes.Contains(out, []byte("mode: count")) {
t.Error("missing mode: count")
}
}
checkCoverage(tg, data)
}
func TestCoverageImportMainLoop(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
@ -2228,6 +2271,20 @@ func TestCoverageImportMainLoop(t *testing.T) {
tg.grepStderr("not an importable package", "did not detect import main")
}
func TestPluginNonMain(t *testing.T) {
wd, err := os.Getwd()
if err != nil {
t.Fatal(err)
}
pkg := filepath.Join(wd, "testdata", "testdep", "p2")
tg := testgo(t)
defer tg.cleanup()
tg.runFail("build", "-buildmode=plugin", pkg)
}
func TestTestEmpty(t *testing.T) {
if !canRace {
t.Skip("no race detector")
@ -2235,7 +2292,6 @@ func TestTestEmpty(t *testing.T) {
wd, _ := os.Getwd()
testdata := filepath.Join(wd, "testdata")
for _, dir := range []string{"pkg", "test", "xtest", "pkgtest", "pkgxtest", "pkgtestxtest", "testxtest"} {
t.Run(dir, func(t *testing.T) {
tg := testgo(t)
@ -2250,10 +2306,36 @@ func TestTestEmpty(t *testing.T) {
}
}
func TestNoGoError(t *testing.T) {
wd, _ := os.Getwd()
testdata := filepath.Join(wd, "testdata")
for _, dir := range []string{"empty/test", "empty/xtest", "empty/testxtest", "exclude", "exclude/ignore", "exclude/empty"} {
t.Run(dir, func(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", testdata)
tg.cd(filepath.Join(testdata, "src"))
tg.runFail("build", "./"+dir)
var want string
if strings.Contains(dir, "test") {
want = "no non-test Go files in "
} else if dir == "exclude" {
want = "build constraints exclude all Go files in "
} else {
want = "no Go files in "
}
tg.grepStderr(want, "wrong reason for failure")
})
}
}
func TestTestRaceInstall(t *testing.T) {
if !canRace {
t.Skip("no race detector")
}
if testing.Short() && testenv.Builder() == "" {
t.Skip("don't rebuild the standard library in short mode")
}
tg := testgo(t)
defer tg.cleanup()
@ -2308,6 +2390,19 @@ func TestCoverageWithCgo(t *testing.T) {
}
}
func TestCgoAsmError(t *testing.T) {
if !canCgo {
t.Skip("skipping because cgo not enabled")
}
tg := testgo(t)
tg.parallel()
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.runFail("build", "cgoasm")
tg.grepBoth("package using cgo has Go assembly file", "did not detect Go assembly file")
}
func TestCgoDependsOnSyscall(t *testing.T) {
if testing.Short() {
t.Skip("skipping test that removes $GOROOT/pkg/*_race in short mode")
@ -2445,7 +2540,7 @@ import "C"
func main() { C.f() }`)
tg.setenv("GOPATH", tg.path("."))
tg.run("build", "-n", "-compiler", "gccgo", "cgoref")
tg.grepStderr(`gccgo.*\-L alibpath \-lalib`, `no Go-inline "#cgo LDFLAGS:" ("-L alibpath -lalib") passed to gccgo linking stage`)
tg.grepStderr(`gccgo.*\-L [^ ]*alibpath \-lalib`, `no Go-inline "#cgo LDFLAGS:" ("-L alibpath -lalib") passed to gccgo linking stage`)
}
func TestListTemplateContextFunction(t *testing.T) {
@ -2535,7 +2630,7 @@ func TestGoBuildInTestOnlyDirectoryFailsWithAGoodError(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.runFail("build", "./testdata/testonly")
tg.grepStderr("no buildable Go", "go build ./testdata/testonly produced unexpected error")
tg.grepStderr("no non-test Go files in", "go build ./testdata/testonly produced unexpected error")
}
func TestGoTestDetectsTestOnlyImportCycles(t *testing.T) {
@ -2674,8 +2769,7 @@ func TestGoGetInternalWildcard(t *testing.T) {
}
func TestGoVetWithExternalTests(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
skipIfGccgo(t, "gccgo does not have vet")
tg := testgo(t)
defer tg.cleanup()
tg.makeTempdir()
@ -2686,19 +2780,39 @@ func TestGoVetWithExternalTests(t *testing.T) {
}
func TestGoVetWithTags(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
skipIfGccgo(t, "gccgo does not have vet")
tg := testgo(t)
defer tg.cleanup()
tg.makeTempdir()
tg.run("install", "cmd/vet")
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.runFail("vet", "-tags", "tagtest", "vetpkg")
tg.grepBoth(`c\.go.*wrong number of args for format`, "go get vetpkg did not run scan tagged file")
tg.grepBoth(`c\.go.*wrong number of args for format`, "go vet vetpkg did not run scan tagged file")
}
// Issue 9767.
func TestGoGetRscIoToolstash(t *testing.T) {
func TestGoVetWithFlagsOn(t *testing.T) {
skipIfGccgo(t, "gccgo does not have vet")
tg := testgo(t)
defer tg.cleanup()
tg.makeTempdir()
tg.run("install", "cmd/vet")
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.runFail("vet", "-printf", "vetpkg")
tg.grepBoth("missing argument for Printf", "go vet -printf vetpkg did not find missing argument for Printf")
}
func TestGoVetWithFlagsOff(t *testing.T) {
skipIfGccgo(t, "gccgo does not have vet")
tg := testgo(t)
defer tg.cleanup()
tg.makeTempdir()
tg.run("install", "cmd/vet")
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.run("vet", "-printf=false", "vetpkg")
}
// Issue 9767, 19769.
func TestGoGetDotSlashDownload(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
tg := testgo(t)
@ -2706,7 +2820,7 @@ func TestGoGetRscIoToolstash(t *testing.T) {
tg.tempDir("src/rsc.io")
tg.setenv("GOPATH", tg.path("."))
tg.cd(tg.path("src/rsc.io"))
tg.run("get", "./toolstash")
tg.run("get", "./pprof_mac_fix")
}
// Issue 13037: Was not parsing <meta> tags in 404 served over HTTPS
@ -3047,17 +3161,8 @@ func TestGoInstallPkgdir(t *testing.T) {
}
func TestGoTestRaceInstallCgo(t *testing.T) {
skipIfGccgo(t, "gccgo has no race detector")
switch sys := runtime.GOOS + "/" + runtime.GOARCH; sys {
case "darwin/amd64", "freebsd/amd64", "linux/amd64", "windows/amd64":
// ok
default:
t.Skip("no race detector on %s", sys)
}
if !build.Default.CgoEnabled {
t.Skip("no race detector without cgo")
if !canRace {
t.Skip("skipping because race detector not supported")
}
// golang.org/issue/10500.
@ -3071,7 +3176,7 @@ func TestGoTestRaceInstallCgo(t *testing.T) {
tg.run("test", "-race", "-i", "runtime/race")
new, err := os.Stat(cgo)
tg.must(err)
if new.ModTime() != old.ModTime() {
if !new.ModTime().Equal(old.ModTime()) {
t.Fatalf("go test -i runtime/race reinstalled cmd/cgo")
}
}
@ -3100,7 +3205,7 @@ func TestGoTestRaceFailures(t *testing.T) {
func TestGoTestImportErrorStack(t *testing.T) {
const out = `package testdep/p1 (test)
imports testdep/p2
imports testdep/p3: no buildable Go source files`
imports testdep/p3: build constraints exclude all Go files `
tg := testgo(t)
defer tg.cleanup()
@ -3141,6 +3246,20 @@ func TestGoGetUpdate(t *testing.T) {
tg.run("get", "-d", "-u", "github.com/rsc/go-get-issue-9224-cmd")
}
// Issue #20512.
func TestGoGetRace(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
if !canRace {
t.Skip("skipping because race detector not supported")
}
tg := testgo(t)
defer tg.cleanup()
tg.makeTempdir()
tg.setenv("GOPATH", tg.path("."))
tg.run("get", "-race", "github.com/rsc/go-get-issue-9224-cmd")
}
func TestGoGetDomainRoot(t *testing.T) {
// golang.org/issue/9357.
// go get foo.io (not foo.io/subdir) was not working consistently.
@ -3477,7 +3596,7 @@ func TestBinaryOnlyPackages(t *testing.T) {
func F() { p1.F(true) }
`)
tg.runFail("install", "p2")
tg.grepStderr("no buildable Go source files", "did not complain about missing sources")
tg.grepStderr("no Go files", "did not complain about missing sources")
tg.tempFile("src/p1/missing.go", `//go:binary-only-package
@ -3675,6 +3794,28 @@ func TestMatchesOnlyBenchmarkIsOK(t *testing.T) {
tg.grepBoth(okPattern, "go test did not say ok")
}
func TestBenchmarkLabels(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
// TODO: tg.parallel()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.run("test", "-run", "^$", "-bench", ".", "bench")
tg.grepStdout(`(?m)^goos: `+runtime.GOOS, "go test did not print goos")
tg.grepStdout(`(?m)^goarch: `+runtime.GOARCH, "go test did not print goarch")
tg.grepStdout(`(?m)^pkg: bench`, "go test did not say pkg: bench")
tg.grepBothNot(`(?s)pkg:.*pkg:`, "go test said pkg multiple times")
}
func TestBenchmarkLabelsOutsideGOPATH(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
// TODO: tg.parallel()
tg.run("test", "-run", "^$", "-bench", ".", "testdata/standalone_benchmark_test.go")
tg.grepStdout(`(?m)^goos: `+runtime.GOOS, "go test did not print goos")
tg.grepStdout(`(?m)^goarch: `+runtime.GOARCH, "go test did not print goarch")
tg.grepBothNot(`(?m)^pkg:`, "go test did say pkg:")
}
func TestMatchesOnlyTestIsOK(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
@ -3804,3 +3945,431 @@ func TestA(t *testing.T) {}`)
tg.grepStdout("pkgs$", "expected package not listed")
tg.grepStdout("pkgs/a", "expected package not listed")
}
// Issue 18975.
func TestFFLAGS(t *testing.T) {
if !canCgo {
t.Skip("skipping because cgo not enabled")
}
tg := testgo(t)
defer tg.cleanup()
tg.parallel()
tg.tempFile("p/src/p/main.go", `package main
// #cgo FFLAGS: -no-such-fortran-flag
import "C"
func main() {}
`)
tg.tempFile("p/src/p/a.f", `! comment`)
tg.setenv("GOPATH", tg.path("p"))
// This should normally fail because we are passing an unknown flag,
// but issue #19080 points to Fortran compilers that succeed anyhow.
// To work either way we call doRun directly rather than run or runFail.
tg.doRun([]string{"build", "-x", "p"})
tg.grepStderr("no-such-fortran-flag", `missing expected "-no-such-fortran-flag"`)
}
// Issue 19198.
// This is really a cmd/link issue but this is a convenient place to test it.
func TestDuplicateGlobalAsmSymbols(t *testing.T) {
skipIfGccgo(t, "gccgo does not use cmd/asm")
if runtime.GOARCH != "386" && runtime.GOARCH != "amd64" {
t.Skipf("skipping test on %s", runtime.GOARCH)
}
if !canCgo {
t.Skip("skipping because cgo not enabled")
}
tg := testgo(t)
defer tg.cleanup()
tg.parallel()
asm := `
#include "textflag.h"
DATA sym<>+0x0(SB)/8,$0
GLOBL sym<>(SB),(NOPTR+RODATA),$8
TEXT ·Data(SB),NOSPLIT,$0
MOVB sym<>(SB), AX
MOVB AX, ret+0(FP)
RET
`
tg.tempFile("go/src/a/a.s", asm)
tg.tempFile("go/src/a/a.go", `package a; func Data() uint8`)
tg.tempFile("go/src/b/b.s", asm)
tg.tempFile("go/src/b/b.go", `package b; func Data() uint8`)
tg.tempFile("go/src/p/p.go", `
package main
import "a"
import "b"
import "C"
func main() {
_ = a.Data() + b.Data()
}
`)
tg.setenv("GOPATH", tg.path("go"))
exe := filepath.Join(tg.tempdir, "p.exe")
tg.creatingTemp(exe)
tg.run("build", "-o", exe, "p")
}
func TestBuildTagsNoComma(t *testing.T) {
skipIfGccgo(t, "gccgo has no standard packages")
tg := testgo(t)
defer tg.cleanup()
tg.makeTempdir()
tg.setenv("GOPATH", tg.path("go"))
tg.run("install", "-tags", "tag1 tag2", "math")
tg.runFail("install", "-tags", "tag1,tag2", "math")
tg.grepBoth("space-separated list contains comma", "-tags with a comma-separated list didn't error")
tg.runFail("build", "-tags", "tag1,tag2", "math")
tg.grepBoth("space-separated list contains comma", "-tags with a comma-separated list didn't error")
}
func copyFile(src, dst string, perm os.FileMode) error {
sf, err := os.Open(src)
if err != nil {
return err
}
defer sf.Close()
df, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
if err != nil {
return err
}
_, err = io.Copy(df, sf)
err2 := df.Close()
if err != nil {
return err
}
return err2
}
func TestExecutableGOROOT(t *testing.T) {
skipIfGccgo(t, "gccgo has no GOROOT")
if runtime.GOOS == "openbsd" {
t.Skipf("test case does not work on %s, missing os.Executable", runtime.GOOS)
}
// Env with no GOROOT.
var env []string
for _, e := range os.Environ() {
if !strings.HasPrefix(e, "GOROOT=") {
env = append(env, e)
}
}
check := func(t *testing.T, exe, want string) {
cmd := exec.Command(exe, "env", "GOROOT")
cmd.Env = env
out, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("%s env GOROOT: %v, %s", exe, err, out)
}
goroot, err := filepath.EvalSymlinks(strings.TrimSpace(string(out)))
if err != nil {
t.Fatal(err)
}
want, err = filepath.EvalSymlinks(want)
if err != nil {
t.Fatal(err)
}
if !strings.EqualFold(goroot, want) {
t.Errorf("go env GOROOT:\nhave %s\nwant %s", goroot, want)
} else {
t.Logf("go env GOROOT: %s", goroot)
}
}
// Note: Must not call tg methods inside subtests: tg is attached to outer t.
tg := testgo(t)
defer tg.cleanup()
tg.makeTempdir()
tg.tempDir("new/bin")
newGoTool := tg.path("new/bin/go" + exeSuffix)
tg.must(copyFile(tg.goTool(), newGoTool, 0775))
newRoot := tg.path("new")
t.Run("RelocatedExe", func(t *testing.T) {
t.Skip("TODO: skipping known broken test; see golang.org/issue/20284")
// Should fall back to default location in binary.
// No way to dig out other than look at source code.
data, err := ioutil.ReadFile("../../runtime/internal/sys/zversion.go")
if err != nil {
t.Fatal(err)
}
m := regexp.MustCompile("const DefaultGoroot = `([^`]+)`").FindStringSubmatch(string(data))
if m == nil {
t.Fatal("cannot find DefaultGoroot in ../../runtime/internal/sys/zversion.go")
}
check(t, newGoTool, m[1])
})
// If the binary is sitting in a bin dir next to ../pkg/tool, that counts as a GOROOT,
// so it should find the new tree.
tg.tempDir("new/pkg/tool")
t.Run("RelocatedTree", func(t *testing.T) {
check(t, newGoTool, newRoot)
})
tg.tempDir("other/bin")
symGoTool := tg.path("other/bin/go" + exeSuffix)
// Symlink into go tree should still find go tree.
t.Run("SymlinkedExe", func(t *testing.T) {
testenv.MustHaveSymlink(t)
if err := os.Symlink(newGoTool, symGoTool); err != nil {
t.Fatal(err)
}
check(t, symGoTool, newRoot)
})
}
func TestNeedVersion(t *testing.T) {
skipIfGccgo(t, "gccgo does not use cmd/compile")
tg := testgo(t)
defer tg.cleanup()
tg.parallel()
tg.tempFile("goversion.go", `package main; func main() {}`)
path := tg.path("goversion.go")
tg.setenv("TESTGO_VERSION", "go1.testgo")
tg.runFail("run", path)
tg.grepStderr("compile", "does not match go tool version")
}
// Test that user can override default code generation flags.
func TestUserOverrideFlags(t *testing.T) {
skipIfGccgo(t, "gccgo does not use -gcflags")
if !canCgo {
t.Skip("skipping because cgo not enabled")
}
if runtime.GOOS != "linux" {
// We are testing platform-independent code, so it's
// OK to skip cases that work differently.
t.Skipf("skipping on %s because test only works if c-archive implies -shared", runtime.GOOS)
}
tg := testgo(t)
defer tg.cleanup()
tg.parallel()
tg.tempFile("override.go", `package main
import "C"
//export GoFunc
func GoFunc() {}
func main() {}`)
tg.creatingTemp("override.a")
tg.creatingTemp("override.h")
tg.run("build", "-x", "-buildmode=c-archive", "-gcflags=-shared=false", tg.path("override.go"))
tg.grepStderr("compile .*-shared .*-shared=false", "user can not override code generation flag")
}
func TestCgoFlagContainsSpace(t *testing.T) {
if !canCgo {
t.Skip("skipping because cgo not enabled")
}
tg := testgo(t)
defer tg.cleanup()
ccName := filepath.Base(testCC)
tg.tempFile(fmt.Sprintf("src/%s/main.go", ccName), fmt.Sprintf(`package main
import (
"os"
"os/exec"
"path/filepath"
"strings"
)
func main() {
cmd := exec.Command(%q, os.Args[1:]...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil {
panic(err)
}
if os.Args[len(os.Args)-1] == "trivial.c" {
return
}
if filepath.Base(os.Args[len(os.Args)-1]) == "_cgo_defun.c" {
return
}
var success bool
for _, arg := range os.Args {
switch {
case strings.Contains(arg, "c flags"):
if success {
panic("duplicate CFLAGS")
}
success = true
case strings.Contains(arg, "ld flags"):
if success {
panic("duplicate LDFLAGS")
}
success = true
}
}
if !success {
panic("args should contains '-Ic flags' or '-Lld flags'")
}
}
`, testCC))
tg.cd(tg.path(fmt.Sprintf("src/%s", ccName)))
tg.run("build")
tg.setenv("CC", tg.path(fmt.Sprintf("src/%s/%s", ccName, ccName)))
tg.tempFile("src/cgo/main.go", `package main
// #cgo CFLAGS: -I"c flags"
// #cgo LDFLAGS: -L"ld flags"
import "C"
func main() {}
`)
tg.cd(tg.path("src/cgo"))
tg.run("run", "main.go")
}
// Issue #20435.
func TestGoTestRaceCoverModeFailures(t *testing.T) {
if !canRace {
t.Skip("skipping because race detector not supported")
}
tg := testgo(t)
tg.parallel()
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.run("test", "testrace")
tg.runFail("test", "-race", "-covermode=set", "testrace")
tg.grepStderr(`-covermode must be "atomic", not "set", when -race is enabled`, "-race -covermode=set was allowed")
tg.grepBothNot("PASS", "something passed")
}
// Issue 9737: verify that GOARM and GO386 affect the computed build ID.
func TestBuildIDContainsArchModeEnv(t *testing.T) {
if testing.Short() {
t.Skip("skipping in short mode")
}
var tg *testgoData
testWith := func(before, after func()) func(*testing.T) {
return func(t *testing.T) {
tg = testgo(t)
defer tg.cleanup()
tg.tempFile("src/mycmd/x.go", `package main
func main() {}`)
tg.setenv("GOPATH", tg.path("."))
tg.cd(tg.path("src/mycmd"))
tg.setenv("GOOS", "linux")
before()
tg.run("install", "mycmd")
after()
tg.wantStale("mycmd", "build ID mismatch", "should be stale after environment variable change")
}
}
t.Run("386", testWith(func() {
tg.setenv("GOARCH", "386")
tg.setenv("GO386", "387")
}, func() {
tg.setenv("GO386", "sse2")
}))
t.Run("arm", testWith(func() {
tg.setenv("GOARCH", "arm")
tg.setenv("GOARM", "5")
}, func() {
tg.setenv("GOARM", "7")
}))
}
func TestTestRegexps(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.run("test", "-cpu=1", "-run=X/Y", "-bench=X/Y", "-count=2", "-v", "testregexp")
var lines []string
for _, line := range strings.SplitAfter(tg.getStdout(), "\n") {
if strings.Contains(line, "=== RUN") || strings.Contains(line, "--- BENCH") || strings.Contains(line, "LOG") {
lines = append(lines, line)
}
}
// Important parts:
// TestX is run, twice
// TestX/Y is run, twice
// TestXX is run, twice
// TestZ is not run
// BenchmarkX is run but only with N=1, once
// BenchmarkXX is run but only with N=1, once
// BenchmarkX/Y is run in full, twice
want := `=== RUN TestX
=== RUN TestX/Y
x_test.go:6: LOG: X running
x_test.go:8: LOG: Y running
=== RUN TestXX
z_test.go:10: LOG: XX running
=== RUN TestX
=== RUN TestX/Y
x_test.go:6: LOG: X running
x_test.go:8: LOG: Y running
=== RUN TestXX
z_test.go:10: LOG: XX running
--- BENCH: BenchmarkX/Y
x_test.go:15: LOG: Y running N=1
x_test.go:15: LOG: Y running N=100
x_test.go:15: LOG: Y running N=10000
x_test.go:15: LOG: Y running N=1000000
x_test.go:15: LOG: Y running N=100000000
x_test.go:15: LOG: Y running N=2000000000
--- BENCH: BenchmarkX/Y
x_test.go:15: LOG: Y running N=1
x_test.go:15: LOG: Y running N=100
x_test.go:15: LOG: Y running N=10000
x_test.go:15: LOG: Y running N=1000000
x_test.go:15: LOG: Y running N=100000000
x_test.go:15: LOG: Y running N=2000000000
--- BENCH: BenchmarkX
x_test.go:13: LOG: X running N=1
--- BENCH: BenchmarkXX
z_test.go:18: LOG: XX running N=1
`
have := strings.Join(lines, "")
if have != want {
t.Errorf("reduced output:<<<\n%s>>> want:<<<\n%s>>>", have, want)
}
}
func TestListTests(t *testing.T) {
var tg *testgoData
testWith := func(listName, expected string) func(*testing.T) {
return func(t *testing.T) {
tg = testgo(t)
defer tg.cleanup()
tg.run("test", "./testdata/src/testlist/...", fmt.Sprintf("-list=%s", listName))
tg.grepStdout(expected, fmt.Sprintf("-test.list=%s returned %q, expected %s", listName, tg.getStdout(), expected))
}
}
t.Run("Test", testWith("Test", "TestSimple"))
t.Run("Bench", testWith("Benchmark", "BenchmarkSimple"))
t.Run("Example1", testWith("Example", "ExampleSimple"))
t.Run("Example2", testWith("Example", "ExampleWithEmptyOutput"))
}

View File

@ -19,9 +19,13 @@ func TestGoBuildUmask(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.tempFile("x.go", `package main; func main() {}`)
tg.creatingTemp("x")
tg.run("build", tg.path("x.go"))
fi, err := os.Stat("x")
// Make sure artifact will be output to /tmp/... in case the user
// has POSIX acl's on their go source tree.
// See issue 17909.
exe := tg.path("x")
tg.creatingTemp(exe)
tg.run("build", "-o", exe, tg.path("x.go"))
fi, err := os.Stat(exe)
if err != nil {
t.Fatal(err)
}

View File

@ -0,0 +1,173 @@
// Copyright 2017 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 base defines shared basic pieces of the go command,
// in particular logging and the Command structure.
package base
import (
"bytes"
"errors"
"flag"
"fmt"
"go/scanner"
"log"
"os"
"os/exec"
"strings"
"sync"
"cmd/go/internal/cfg"
"cmd/go/internal/str"
)
// A Command is an implementation of a go command
// like go build or go fix.
type Command struct {
// Run runs the command.
// The args are the arguments after the command name.
Run func(cmd *Command, args []string)
// UsageLine is the one-line usage message.
// The first word in the line is taken to be the command name.
UsageLine string
// Short is the short description shown in the 'go help' output.
Short string
// Long is the long message shown in the 'go help <this-command>' output.
Long string
// Flag is a set of flags specific to this command.
Flag flag.FlagSet
// CustomFlags indicates that the command will do its own
// flag parsing.
CustomFlags bool
}
// Commands lists the available commands and help topics.
// The order here is the order in which they are printed by 'go help'.
var Commands []*Command
// Name returns the command's name: the first word in the usage line.
func (c *Command) Name() string {
name := c.UsageLine
i := strings.Index(name, " ")
if i >= 0 {
name = name[:i]
}
return name
}
func (c *Command) Usage() {
fmt.Fprintf(os.Stderr, "usage: %s\n\n", c.UsageLine)
fmt.Fprintf(os.Stderr, "%s\n", strings.TrimSpace(c.Long))
os.Exit(2)
}
// Runnable reports whether the command can be run; otherwise
// it is a documentation pseudo-command such as importpath.
func (c *Command) Runnable() bool {
return c.Run != nil
}
var atExitFuncs []func()
func AtExit(f func()) {
atExitFuncs = append(atExitFuncs, f)
}
func Exit() {
for _, f := range atExitFuncs {
f()
}
os.Exit(exitStatus)
}
func Fatalf(format string, args ...interface{}) {
Errorf(format, args...)
Exit()
}
func Errorf(format string, args ...interface{}) {
log.Printf(format, args...)
SetExitStatus(1)
}
func ExitIfErrors() {
if exitStatus != 0 {
Exit()
}
}
var exitStatus = 0
var exitMu sync.Mutex
func SetExitStatus(n int) {
exitMu.Lock()
if exitStatus < n {
exitStatus = n
}
exitMu.Unlock()
}
// Run runs the command, with stdout and stderr
// connected to the go command's own stdout and stderr.
// If the command fails, Run reports the error using Errorf.
func Run(cmdargs ...interface{}) {
cmdline := str.StringList(cmdargs...)
if cfg.BuildN || cfg.BuildX {
fmt.Printf("%s\n", strings.Join(cmdline, " "))
if cfg.BuildN {
return
}
}
cmd := exec.Command(cmdline[0], cmdline[1:]...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
Errorf("%v", err)
}
}
// RunStdin is like run but connects Stdin.
func RunStdin(cmdline []string) {
cmd := exec.Command(cmdline[0], cmdline[1:]...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Env = cfg.OrigEnv
StartSigHandlers()
if err := cmd.Run(); err != nil {
Errorf("%v", err)
}
}
// Usage is the usage-reporting function, filled in by package main
// but here for reference by other packages.
var Usage func()
// ExpandScanner expands a scanner.List error into all the errors in the list.
// The default Error method only shows the first error
// and does not shorten paths.
func ExpandScanner(err error) error {
// Look for parser errors.
if err, ok := err.(scanner.ErrorList); ok {
// Prepare error with \n before each message.
// When printed in something like context: %v
// this will put the leading file positions each on
// its own line. It will also show all the errors
// instead of just the first, as err.Error does.
var buf bytes.Buffer
for _, e := range err {
e.Pos.Filename = ShortPath(e.Pos.Filename)
buf.WriteString("\n")
buf.WriteString(e.Error())
}
return errors.New(buf.String())
}
return err
}

View File

@ -0,0 +1,37 @@
// Copyright 2017 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 base
import "strings"
// EnvForDir returns a copy of the environment
// suitable for running in the given directory.
// The environment is the current process's environment
// but with an updated $PWD, so that an os.Getwd in the
// child will be faster.
func EnvForDir(dir string, base []string) []string {
// Internally we only use rooted paths, so dir is rooted.
// Even if dir is not rooted, no harm done.
return MergeEnvLists([]string{"PWD=" + dir}, base)
}
// MergeEnvLists merges the two environment lists such that
// variables with the same name in "in" replace those in "out".
// This always returns a newly allocated slice.
func MergeEnvLists(in, out []string) []string {
out = append([]string(nil), out...)
NextVar:
for _, inkv := range in {
k := strings.SplitAfterN(inkv, "=", 2)[0]
for i, outkv := range out {
if strings.HasPrefix(outkv, k) {
out[i] = inkv
continue NextVar
}
}
out = append(out, inkv)
}
return out
}

View File

@ -0,0 +1,35 @@
// Copyright 2017 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 base
import (
"flag"
"cmd/go/internal/cfg"
"cmd/go/internal/str"
)
// A StringsFlag is a command-line flag that interprets its argument
// as a space-separated list of possibly-quoted strings.
type StringsFlag []string
func (v *StringsFlag) Set(s string) error {
var err error
*v, err = str.SplitQuotedFields(s)
if *v == nil {
*v = []string{}
}
return err
}
func (v *StringsFlag) String() string {
return "<StringsFlag>"
}
// AddBuildFlagsNX adds the -n and -x build flags to the flag set.
func AddBuildFlagsNX(flags *flag.FlagSet) {
flags.BoolVar(&cfg.BuildN, "n", false, "")
flags.BoolVar(&cfg.BuildX, "x", false, "")
}

View File

@ -0,0 +1,74 @@
// Copyright 2017 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 base
import (
"os"
"path/filepath"
"strings"
)
func getwd() string {
wd, err := os.Getwd()
if err != nil {
Fatalf("cannot determine current directory: %v", err)
}
return wd
}
var Cwd = getwd()
// ShortPath returns an absolute or relative name for path, whatever is shorter.
func ShortPath(path string) string {
if rel, err := filepath.Rel(Cwd, path); err == nil && len(rel) < len(path) {
return rel
}
return path
}
// RelPaths returns a copy of paths with absolute paths
// made relative to the current directory if they would be shorter.
func RelPaths(paths []string) []string {
var out []string
// TODO(rsc): Can this use Cwd from above?
pwd, _ := os.Getwd()
for _, p := range paths {
rel, err := filepath.Rel(pwd, p)
if err == nil && len(rel) < len(p) {
p = rel
}
out = append(out, p)
}
return out
}
// FilterDotUnderscoreFiles returns a slice containing all elements
// of path whose base name doesn't begin with "." or "_".
func FilterDotUnderscoreFiles(path []string) []string {
var out []string // lazily initialized
for i, p := range path {
base := filepath.Base(p)
if strings.HasPrefix(base, ".") || strings.HasPrefix(base, "_") {
if out == nil {
out = append(make([]string, 0, len(path)), path[:i]...)
}
continue
}
if out != nil {
out = append(out, p)
}
}
if out == nil {
return path
}
return out
}
// IsTestFile reports whether the source file is a set of tests and should therefore
// be excluded from coverage analysis.
func IsTestFile(file string) bool {
// We don't cover tests, only the code they test.
return strings.HasSuffix(file, "_test.go")
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
package base
import (
"os"
@ -10,8 +10,8 @@ import (
"sync"
)
// interrupted is closed, if go process is interrupted.
var interrupted = make(chan struct{})
// Interrupted is closed when the go command receives an interrupt signal.
var Interrupted = make(chan struct{})
// processSignals setups signal handler.
func processSignals() {
@ -19,13 +19,13 @@ func processSignals() {
signal.Notify(sig, signalsToIgnore...)
go func() {
<-sig
close(interrupted)
close(Interrupted)
}()
}
var onceProcessSignals sync.Once
// startSigHandlers start signal handlers.
func startSigHandlers() {
// StartSigHandlers starts the signal handlers.
func StartSigHandlers() {
onceProcessSignals.Do(processSignals)
}

View File

@ -4,7 +4,7 @@
// +build plan9 windows
package main
package base
import (
"os"
@ -12,6 +12,6 @@ import (
var signalsToIgnore = []os.Signal{os.Interrupt}
// signalTrace is the signal to send to make a Go program
// crash with a stack trace.
var signalTrace os.Signal = nil
// SignalTrace is the signal to send to make a Go program
// crash with a stack trace (no such signal in this case).
var SignalTrace os.Signal = nil

View File

@ -4,7 +4,7 @@
// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package main
package base
import (
"os"
@ -13,6 +13,6 @@ import (
var signalsToIgnore = []os.Signal{os.Interrupt, syscall.SIGQUIT}
// signalTrace is the signal to send to make a Go program
// SignalTrace is the signal to send to make a Go program
// crash with a stack trace.
var signalTrace os.Signal = syscall.SIGQUIT
var SignalTrace os.Signal = syscall.SIGQUIT

View File

@ -0,0 +1,53 @@
// Copyright 2017 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 base
import (
"fmt"
"go/build"
"os"
"path/filepath"
"runtime"
"cmd/go/internal/cfg"
)
// Configuration for finding tool binaries.
var (
ToolGOOS = runtime.GOOS
ToolGOARCH = runtime.GOARCH
ToolIsWindows = ToolGOOS == "windows"
ToolDir = build.ToolDir
)
const ToolWindowsExtension = ".exe"
// Tool returns the path to the named tool (for example, "vet").
// If the tool cannot be found, Tool exits the process.
func Tool(toolName string) string {
toolPath := filepath.Join(ToolDir, toolName)
if ToolIsWindows {
toolPath += ToolWindowsExtension
}
if len(cfg.BuildToolexec) > 0 {
return toolPath
}
// Give a nice message if there is no tool with that name.
if _, err := os.Stat(toolPath); err != nil {
if isInGoToolsRepo(toolName) {
fmt.Fprintf(os.Stderr, "go tool: no such tool %q; to install:\n\tgo get golang.org/x/tools/cmd/%s\n", toolName, toolName)
} else {
fmt.Fprintf(os.Stderr, "go tool: no such tool %q\n", toolName)
}
SetExitStatus(2)
Exit()
}
return toolPath
}
// TODO: Delete.
func isInGoToolsRepo(toolName string) bool {
return false
}

View File

@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
// Package bug implements the ``go bug'' command.
package bug
import (
"bytes"
@ -15,9 +16,14 @@ import (
"regexp"
"runtime"
"strings"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/envcmd"
"cmd/go/internal/web"
)
var cmdBug = &Command{
var CmdBug = &base.Command{
Run: runBug,
UsageLine: "bug",
Short: "start a bug report",
@ -28,23 +34,23 @@ The report includes useful system information.
}
func init() {
cmdBug.Flag.BoolVar(&buildV, "v", false, "")
CmdBug.Flag.BoolVar(&cfg.BuildV, "v", false, "")
}
func runBug(cmd *Command, args []string) {
func runBug(cmd *base.Command, args []string) {
var buf bytes.Buffer
buf.WriteString(bugHeader)
inspectGoVersion(&buf)
fmt.Fprint(&buf, "#### System details\n\n")
fmt.Fprintln(&buf, "```")
fmt.Fprintf(&buf, "go version %s %s/%s\n", runtime.Version(), runtime.GOOS, runtime.GOARCH)
env := newEnv
env = append(env, extraEnvVars()...)
env := cfg.CmdEnv
env = append(env, envcmd.ExtraEnvVars()...)
for _, e := range env {
// Hide the TERM environment variable from "go bug".
// See issue #18128
if e.name != "TERM" {
fmt.Fprintf(&buf, "%s=\"%s\"\n", e.name, e.value)
if e.Name != "TERM" {
fmt.Fprintf(&buf, "%s=\"%s\"\n", e.Name, e.Value)
}
}
printGoDetails(&buf)
@ -53,8 +59,8 @@ func runBug(cmd *Command, args []string) {
fmt.Fprintln(&buf, "```")
body := buf.String()
url := "https://github.com/golang/go/issues/new?body=" + queryEscape(body)
if !openBrowser(url) {
url := "https://github.com/golang/go/issues/new?body=" + web.QueryEscape(body)
if !web.OpenBrowser(url) {
fmt.Print("Please file a new issue at golang.org/issue/new using this template:\n\n")
fmt.Print(body)
}
@ -97,7 +103,7 @@ func printOSDetails(w io.Writer) {
if err == nil {
fmt.Fprintf(w, "/etc/release: %s\n", out)
} else {
if buildV {
if cfg.BuildV {
fmt.Printf("failed to read /etc/release: %v\n", err)
}
}
@ -114,16 +120,16 @@ func printCDetails(w io.Writer) {
// Print up to the first newline.
fmt.Fprintf(w, "gdb --version: %s\n", firstLine(out))
} else {
if buildV {
if cfg.BuildV {
fmt.Printf("failed to run gdb --version: %v\n", err)
}
}
}
func inspectGoVersion(w io.Writer) {
data, err := httpGET("https://golang.org/VERSION?m=text")
data, err := web.Get("https://golang.org/VERSION?m=text")
if err != nil {
if buildV {
if cfg.BuildV {
fmt.Printf("failed to read from golang.org/VERSION: %v\n", err)
}
return
@ -150,7 +156,7 @@ func printCmdOut(w io.Writer, prefix, path string, args ...string) {
cmd := exec.Command(path, args...)
out, err := cmd.Output()
if err != nil {
if buildV {
if cfg.BuildV {
fmt.Printf("%s %s: %v\n", path, strings.Join(args, " "), err)
}
return

View File

@ -0,0 +1,201 @@
// Copyright 2017 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 buildid
import (
"bytes"
"cmd/go/internal/cfg"
"fmt"
"io"
"os"
"strconv"
"strings"
)
var (
errBuildIDToolchain = fmt.Errorf("build ID only supported in gc toolchain")
errBuildIDMalformed = fmt.Errorf("malformed object file")
errBuildIDUnknown = fmt.Errorf("lost build ID")
)
var (
bangArch = []byte("!<arch>")
pkgdef = []byte("__.PKGDEF")
goobject = []byte("go object ")
buildid = []byte("build id ")
)
// ReadBuildID reads the build ID from an archive or binary.
// It only supports the gc toolchain.
// Other toolchain maintainers should adjust this function.
func ReadBuildID(name, target string) (id string, err error) {
if cfg.BuildToolchainName != "gc" {
return "", errBuildIDToolchain
}
// For commands, read build ID directly from binary.
if name == "main" {
return ReadBuildIDFromBinary(target)
}
// Otherwise, we expect to have an archive (.a) file,
// and we can read the build ID from the Go export data.
if !strings.HasSuffix(target, ".a") {
return "", &os.PathError{Op: "parse", Path: target, Err: errBuildIDUnknown}
}
// Read just enough of the target to fetch the build ID.
// The archive is expected to look like:
//
// !<arch>
// __.PKGDEF 0 0 0 644 7955 `
// go object darwin amd64 devel X:none
// build id "b41e5c45250e25c9fd5e9f9a1de7857ea0d41224"
//
// The variable-sized strings are GOOS, GOARCH, and the experiment list (X:none).
// Reading the first 1024 bytes should be plenty.
f, err := os.Open(target)
if err != nil {
return "", err
}
data := make([]byte, 1024)
n, err := io.ReadFull(f, data)
f.Close()
if err != nil && n == 0 {
return "", err
}
bad := func() (string, error) {
return "", &os.PathError{Op: "parse", Path: target, Err: errBuildIDMalformed}
}
// Archive header.
for i := 0; ; i++ { // returns during i==3
j := bytes.IndexByte(data, '\n')
if j < 0 {
return bad()
}
line := data[:j]
data = data[j+1:]
switch i {
case 0:
if !bytes.Equal(line, bangArch) {
return bad()
}
case 1:
if !bytes.HasPrefix(line, pkgdef) {
return bad()
}
case 2:
if !bytes.HasPrefix(line, goobject) {
return bad()
}
case 3:
if !bytes.HasPrefix(line, buildid) {
// Found the object header, just doesn't have a build id line.
// Treat as successful, with empty build id.
return "", nil
}
id, err := strconv.Unquote(string(line[len(buildid):]))
if err != nil {
return bad()
}
return id, nil
}
}
}
var (
goBuildPrefix = []byte("\xff Go build ID: \"")
goBuildEnd = []byte("\"\n \xff")
elfPrefix = []byte("\x7fELF")
machoPrefixes = [][]byte{
{0xfe, 0xed, 0xfa, 0xce},
{0xfe, 0xed, 0xfa, 0xcf},
{0xce, 0xfa, 0xed, 0xfe},
{0xcf, 0xfa, 0xed, 0xfe},
}
)
var BuildIDReadSize = 32 * 1024 // changed for testing
// ReadBuildIDFromBinary reads the build ID from a binary.
//
// ELF binaries store the build ID in a proper PT_NOTE section.
//
// Other binary formats are not so flexible. For those, the linker
// stores the build ID as non-instruction bytes at the very beginning
// of the text segment, which should appear near the beginning
// of the file. This is clumsy but fairly portable. Custom locations
// can be added for other binary types as needed, like we did for ELF.
func ReadBuildIDFromBinary(filename string) (id string, err error) {
if filename == "" {
return "", &os.PathError{Op: "parse", Path: filename, Err: errBuildIDUnknown}
}
// Read the first 32 kB of the binary file.
// That should be enough to find the build ID.
// In ELF files, the build ID is in the leading headers,
// which are typically less than 4 kB, not to mention 32 kB.
// In Mach-O files, there's no limit, so we have to parse the file.
// On other systems, we're trying to read enough that
// we get the beginning of the text segment in the read.
// The offset where the text segment begins in a hello
// world compiled for each different object format today:
//
// Plan 9: 0x20
// Windows: 0x600
//
f, err := os.Open(filename)
if err != nil {
return "", err
}
defer f.Close()
data := make([]byte, BuildIDReadSize)
_, err = io.ReadFull(f, data)
if err == io.ErrUnexpectedEOF {
err = nil
}
if err != nil {
return "", err
}
if bytes.HasPrefix(data, elfPrefix) {
return readELFGoBuildID(filename, f, data)
}
for _, m := range machoPrefixes {
if bytes.HasPrefix(data, m) {
return readMachoGoBuildID(filename, f, data)
}
}
return readRawGoBuildID(filename, data)
}
// readRawGoBuildID finds the raw build ID stored in text segment data.
func readRawGoBuildID(filename string, data []byte) (id string, err error) {
i := bytes.Index(data, goBuildPrefix)
if i < 0 {
// Missing. Treat as successful but build ID empty.
return "", nil
}
j := bytes.Index(data[i+len(goBuildPrefix):], goBuildEnd)
if j < 0 {
return "", &os.PathError{Op: "parse", Path: filename, Err: errBuildIDMalformed}
}
quoted := data[i+len(goBuildPrefix)-1 : i+len(goBuildPrefix)+j+1]
id, err = strconv.Unquote(string(quoted))
if err != nil {
return "", &os.PathError{Op: "parse", Path: filename, Err: errBuildIDMalformed}
}
return id, nil
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
package buildid
import (
"bytes"
@ -25,7 +25,7 @@ func readAligned4(r io.Reader, sz int32) ([]byte, error) {
return data, nil
}
func readELFNote(filename, name string, typ int32) ([]byte, error) {
func ReadELFNote(filename, name string, typ int32) ([]byte, error) {
f, err := elf.Open(filename)
if err != nil {
return nil, err

View File

@ -0,0 +1,134 @@
// Copyright 2017 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 cfg holds configuration shared by multiple parts
// of the go command.
package cfg
import (
"fmt"
"go/build"
"os"
"path/filepath"
"runtime"
"cmd/internal/objabi"
)
// These are general "build flags" used by build and other commands.
var (
BuildA bool // -a flag
BuildBuildmode string // -buildmode flag
BuildContext = build.Default
BuildI bool // -i flag
BuildLdflags []string // -ldflags flag
BuildLinkshared bool // -linkshared flag
BuildMSan bool // -msan flag
BuildN bool // -n flag
BuildO string // -o flag
BuildP = runtime.NumCPU() // -p flag
BuildPkgdir string // -pkgdir flag
BuildRace bool // -race flag
BuildToolexec []string // -toolexec flag
BuildToolchainName string
BuildToolchainCompiler func() string
BuildToolchainLinker func() string
BuildV bool // -v flag
BuildWork bool // -work flag
BuildX bool // -x flag
)
func init() {
BuildToolchainCompiler = func() string { return "missing-compiler" }
BuildToolchainLinker = func() string { return "missing-linker" }
}
// An EnvVar is an environment variable Name=Value.
type EnvVar struct {
Name string
Value string
}
// OrigEnv is the original environment of the program at startup.
var OrigEnv []string
// CmdEnv is the new environment for running go tool commands.
// User binaries (during go test or go run) are run with OrigEnv,
// not CmdEnv.
var CmdEnv []EnvVar
// Global build parameters (used during package load)
var (
Goarch = BuildContext.GOARCH
Goos = BuildContext.GOOS
ExeSuffix string
Gopath = filepath.SplitList(BuildContext.GOPATH)
)
func init() {
if Goos == "windows" {
ExeSuffix = ".exe"
}
}
var (
GOROOT = findGOROOT()
GOBIN = os.Getenv("GOBIN")
GOROOTbin = filepath.Join(GOROOT, "bin")
GOROOTpkg = filepath.Join(GOROOT, "pkg")
GOROOTsrc = filepath.Join(GOROOT, "src")
// Used in envcmd.MkEnv and build ID computations.
GOARM = fmt.Sprint(objabi.GOARM)
GO386 = objabi.GO386
)
// Update build context to use our computed GOROOT.
func init() {
BuildContext.GOROOT = GOROOT
// Note that we must use runtime.GOOS and runtime.GOARCH here,
// as the tool directory does not move based on environment variables.
// This matches the initialization of ToolDir in go/build,
// except for using GOROOT rather than runtime.GOROOT().
if runtime.Compiler != "gccgo" {
build.ToolDir = filepath.Join(GOROOT, "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH)
}
}
func findGOROOT() string {
if env := os.Getenv("GOROOT"); env != "" {
return filepath.Clean(env)
}
if runtime.Compiler != "gccgo" {
exe, err := os.Executable()
if err == nil {
exe, err = filepath.Abs(exe)
if err == nil {
if dir := filepath.Join(exe, "../.."); isGOROOT(dir) {
return dir
}
exe, err = filepath.EvalSymlinks(exe)
if err == nil {
if dir := filepath.Join(exe, "../.."); isGOROOT(dir) {
return dir
}
}
}
}
}
return filepath.Clean(runtime.GOROOT())
}
// isGOROOT reports whether path looks like a GOROOT.
//
// It does this by looking for the path/pkg/tool directory,
// which is necessary for useful operation of the cmd/go tool,
// and is not typically present in a GOPATH.
func isGOROOT(path string) bool {
stat, err := os.Stat(filepath.Join(path, "pkg", "tool"))
if err != nil {
return false
}
return stat.IsDir()
}

View File

@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
// Package clean implements the ``go clean'' command.
package clean
import (
"fmt"
@ -10,9 +11,14 @@ import (
"os"
"path/filepath"
"strings"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/work"
)
var cmdClean = &Command{
var CmdClean = &base.Command{
UsageLine: "clean [-i] [-r] [-n] [-x] [build flags] [packages]",
Short: "remove object files",
Long: `
@ -63,24 +69,24 @@ var cleanR bool // clean -r flag
func init() {
// break init cycle
cmdClean.Run = runClean
CmdClean.Run = runClean
cmdClean.Flag.BoolVar(&cleanI, "i", false, "")
cmdClean.Flag.BoolVar(&cleanR, "r", false, "")
CmdClean.Flag.BoolVar(&cleanI, "i", false, "")
CmdClean.Flag.BoolVar(&cleanR, "r", false, "")
// -n and -x are important enough to be
// mentioned explicitly in the docs but they
// are part of the build flags.
addBuildFlags(cmdClean)
work.AddBuildFlags(CmdClean)
}
func runClean(cmd *Command, args []string) {
for _, pkg := range packagesAndErrors(args) {
func runClean(cmd *base.Command, args []string) {
for _, pkg := range load.PackagesAndErrors(args) {
clean(pkg)
}
}
var cleaned = map[*Package]bool{}
var cleaned = map[*load.Package]bool{}
// TODO: These are dregs left by Makefile-based builds.
// Eventually, can stop deleting these.
@ -105,24 +111,24 @@ var cleanExt = map[string]bool{
".so": true,
}
func clean(p *Package) {
func clean(p *load.Package) {
if cleaned[p] {
return
}
cleaned[p] = true
if p.Dir == "" {
errorf("can't load package: %v", p.Error)
base.Errorf("can't load package: %v", p.Error)
return
}
dirs, err := ioutil.ReadDir(p.Dir)
if err != nil {
errorf("go clean %s: %v", p.Dir, err)
base.Errorf("go clean %s: %v", p.Dir, err)
return
}
var b builder
b.print = fmt.Print
var b work.Builder
b.Print = fmt.Print
packageFile := map[string]bool{}
if p.Name != "main" {
@ -172,8 +178,8 @@ func clean(p *Package) {
}
}
if buildN || buildX {
b.showcmd(p.Dir, "rm -f %s", strings.Join(allRemove, " "))
if cfg.BuildN || cfg.BuildX {
b.Showcmd(p.Dir, "rm -f %s", strings.Join(allRemove, " "))
}
toRemove := map[string]bool{}
@ -185,20 +191,20 @@ func clean(p *Package) {
if dir.IsDir() {
// TODO: Remove once Makefiles are forgotten.
if cleanDir[name] {
if buildN || buildX {
b.showcmd(p.Dir, "rm -r %s", name)
if buildN {
if cfg.BuildN || cfg.BuildX {
b.Showcmd(p.Dir, "rm -r %s", name)
if cfg.BuildN {
continue
}
}
if err := os.RemoveAll(filepath.Join(p.Dir, name)); err != nil {
errorf("go clean: %v", err)
base.Errorf("go clean: %v", err)
}
}
continue
}
if buildN {
if cfg.BuildN {
continue
}
@ -207,17 +213,17 @@ func clean(p *Package) {
}
}
if cleanI && p.target != "" {
if buildN || buildX {
b.showcmd("", "rm -f %s", p.target)
if cleanI && p.Internal.Target != "" {
if cfg.BuildN || cfg.BuildX {
b.Showcmd("", "rm -f %s", p.Internal.Target)
}
if !buildN {
removeFile(p.target)
if !cfg.BuildN {
removeFile(p.Internal.Target)
}
}
if cleanR {
for _, p1 := range p.imports {
for _, p1 := range p.Internal.Imports {
clean(p1)
}
}
@ -231,7 +237,7 @@ func removeFile(f string) {
return
}
// Windows does not allow deletion of a binary file while it is executing.
if toolIsWindows {
if base.ToolIsWindows {
// Remove lingering ~ file from last attempt.
if _, err2 := os.Stat(f + "~"); err2 == nil {
os.Remove(f + "~")
@ -244,5 +250,5 @@ func removeFile(f string) {
return
}
}
errorf("go clean: %v", err)
base.Errorf("go clean: %v", err)
}

View File

@ -0,0 +1,123 @@
// Copyright 2017 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 cmdflag handles flag processing common to several go tools.
package cmdflag
import (
"flag"
"fmt"
"os"
"strconv"
"strings"
"cmd/go/internal/base"
)
// The flag handling part of go commands such as test is large and distracting.
// We can't use the standard flag package because some of the flags from
// our command line are for us, and some are for the binary we're running,
// and some are for both.
// Defn defines a flag we know about.
type Defn struct {
Name string // Name on command line.
BoolVar *bool // If it's a boolean flag, this points to it.
Value flag.Value // The flag.Value represented.
PassToTest bool // Pass to the test binary? Used only by go test.
Present bool // Flag has been seen.
}
// IsBool reports whether v is a bool flag.
func IsBool(v flag.Value) bool {
vv, ok := v.(interface {
IsBoolFlag() bool
})
if ok {
return vv.IsBoolFlag()
}
return false
}
// SetBool sets the addressed boolean to the value.
func SetBool(cmd string, flag *bool, value string) {
x, err := strconv.ParseBool(value)
if err != nil {
SyntaxError(cmd, "illegal bool flag value "+value)
}
*flag = x
}
// SetInt sets the addressed integer to the value.
func SetInt(cmd string, flag *int, value string) {
x, err := strconv.Atoi(value)
if err != nil {
SyntaxError(cmd, "illegal int flag value "+value)
}
*flag = x
}
// SyntaxError reports an argument syntax error and exits the program.
func SyntaxError(cmd, msg string) {
fmt.Fprintf(os.Stderr, "go %s: %s\n", cmd, msg)
if cmd == "test" {
fmt.Fprintf(os.Stderr, `run "go help %s" or "go help testflag" for more information`+"\n", cmd)
} else {
fmt.Fprintf(os.Stderr, `run "go help %s" for more information`+"\n", cmd)
}
os.Exit(2)
}
// Parse sees if argument i is present in the definitions and if so,
// returns its definition, value, and whether it consumed an extra word.
// If the flag begins (cmd+".") it is ignored for the purpose of this function.
func Parse(cmd string, defns []*Defn, args []string, i int) (f *Defn, value string, extra bool) {
arg := args[i]
if strings.HasPrefix(arg, "--") { // reduce two minuses to one
arg = arg[1:]
}
switch arg {
case "-?", "-h", "-help":
base.Usage()
}
if arg == "" || arg[0] != '-' {
return
}
name := arg[1:]
// If there's already a prefix such as "test.", drop it for now.
name = strings.TrimPrefix(name, cmd+".")
equals := strings.Index(name, "=")
if equals >= 0 {
value = name[equals+1:]
name = name[:equals]
}
for _, f = range defns {
if name == f.Name {
// Booleans are special because they have modes -x, -x=true, -x=false.
if f.BoolVar != nil || IsBool(f.Value) {
if equals < 0 { // Otherwise, it's been set and will be verified in SetBool.
value = "true"
} else {
// verify it parses
SetBool(cmd, new(bool), value)
}
} else { // Non-booleans must have a value.
extra = equals < 0
if extra {
if i+1 >= len(args) {
SyntaxError(cmd, "missing argument for flag "+f.Name)
}
value = args[i+1]
}
}
if f.Present {
SyntaxError(cmd, f.Name+" flag may be set only once")
}
f.Present = true
return
}
}
f = nil
return
}

View File

@ -2,20 +2,25 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:generate ./mkalldocs.sh
// Package doc implements the ``go doc'' command.
package doc
package main
import (
"cmd/go/internal/base"
"cmd/go/internal/cfg"
)
var cmdDoc = &Command{
var CmdDoc = &base.Command{
Run: runDoc,
UsageLine: "doc [-u] [-c] [package|[package.]symbol[.method]]",
UsageLine: "doc [-u] [-c] [package|[package.]symbol[.methodOrField]]",
CustomFlags: true,
Short: "show documentation for package or symbol",
Long: `
Doc prints the documentation comments associated with the item identified by its
arguments (a package, const, func, type, var, or method) followed by a one-line
summary of each of the first-level items "under" that item (package-level
declarations for a package, methods for a type, etc.).
arguments (a package, const, func, type, var, method, or struct field)
followed by a one-line summary of each of the first-level items "under"
that item (package-level declarations for a package, methods for a type,
etc.).
Doc accepts zero, one, or two arguments.
@ -33,9 +38,9 @@ on what is installed in GOROOT and GOPATH, as well as the form of the argument,
which is schematically one of these:
go doc <pkg>
go doc <sym>[.<method>]
go doc [<pkg>.]<sym>[.<method>]
go doc [<pkg>.][<sym>.]<method>
go doc <sym>[.<methodOrField>]
go doc [<pkg>.]<sym>[.<methodOrField>]
go doc [<pkg>.][<sym>.]<methodOrField>
The first item in this list matched by the argument is the one whose documentation
is printed. (See the examples below.) However, if the argument starts with a capital
@ -43,7 +48,7 @@ letter it is assumed to identify a symbol or method in the current directory.
For packages, the order of scanning is determined lexically in breadth-first order.
That is, the package presented is the one that matches the search and is nearest
the root and lexically first at its level of the hierarchy. The GOROOT tree is
the root and lexically first at its level of the hierarchy. The GOROOT tree is
always scanned in its entirety before GOPATH.
If there is no package specified or matched, the package in the current
@ -55,10 +60,10 @@ path. The go tool's usual package mechanism does not apply: package path
elements like . and ... are not implemented by go doc.
When run with two arguments, the first must be a full package path (not just a
suffix), and the second is a symbol or symbol and method; this is similar to the
syntax accepted by godoc:
suffix), and the second is a symbol, or symbol with method or struct field.
This is similar to the syntax accepted by godoc:
go doc <pkg> <sym>[.<method>]
go doc <pkg> <sym>[.<methodOrField>]
In all forms, when matching symbols, lower-case letters in the argument match
either case but upper-case letters match exactly. This means that there may be
@ -109,10 +114,10 @@ Flags:
when showing the package's top-level documentation.
-u
Show documentation for unexported as well as exported
symbols and methods.
symbols, methods, and fields.
`,
}
func runDoc(cmd *Command, args []string) {
run(buildToolExec, tool("doc"), args)
func runDoc(cmd *base.Command, args []string) {
base.Run(cfg.BuildToolexec, base.Tool("doc"), args)
}

View File

@ -0,0 +1,178 @@
// 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.
// Package envcmd implements the ``go env'' command.
package envcmd
import (
"encoding/json"
"fmt"
"os"
"runtime"
"strings"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/work"
)
var CmdEnv = &base.Command{
UsageLine: "env [-json] [var ...]",
Short: "print Go environment information",
Long: `
Env prints Go environment information.
By default env prints information as a shell script
(on Windows, a batch file). If one or more variable
names is given as arguments, env prints the value of
each named variable on its own line.
The -json flag prints the environment in JSON format
instead of as a shell script.
`,
}
func init() {
CmdEnv.Run = runEnv // break init cycle
}
var envJson = CmdEnv.Flag.Bool("json", false, "")
func MkEnv() []cfg.EnvVar {
var b work.Builder
b.Init()
env := []cfg.EnvVar{
{Name: "GOARCH", Value: cfg.Goarch},
{Name: "GOBIN", Value: cfg.GOBIN},
{Name: "GOEXE", Value: cfg.ExeSuffix},
{Name: "GOHOSTARCH", Value: runtime.GOARCH},
{Name: "GOHOSTOS", Value: runtime.GOOS},
{Name: "GOOS", Value: cfg.Goos},
{Name: "GOPATH", Value: cfg.BuildContext.GOPATH},
{Name: "GORACE", Value: os.Getenv("GORACE")},
{Name: "GOROOT", Value: cfg.GOROOT},
{Name: "GOTOOLDIR", Value: base.ToolDir},
// disable escape codes in clang errors
{Name: "TERM", Value: "dumb"},
}
if work.GccgoBin != "" {
env = append(env, cfg.EnvVar{Name: "GCCGO", Value: work.GccgoBin})
} else {
env = append(env, cfg.EnvVar{Name: "GCCGO", Value: work.GccgoName})
}
switch cfg.Goarch {
case "arm":
env = append(env, cfg.EnvVar{Name: "GOARM", Value: cfg.GOARM})
case "386":
env = append(env, cfg.EnvVar{Name: "GO386", Value: cfg.GO386})
}
cmd := b.GccCmd(".")
env = append(env, cfg.EnvVar{Name: "CC", Value: cmd[0]})
env = append(env, cfg.EnvVar{Name: "GOGCCFLAGS", Value: strings.Join(cmd[3:], " ")})
cmd = b.GxxCmd(".")
env = append(env, cfg.EnvVar{Name: "CXX", Value: cmd[0]})
if cfg.BuildContext.CgoEnabled {
env = append(env, cfg.EnvVar{Name: "CGO_ENABLED", Value: "1"})
} else {
env = append(env, cfg.EnvVar{Name: "CGO_ENABLED", Value: "0"})
}
return env
}
func findEnv(env []cfg.EnvVar, name string) string {
for _, e := range env {
if e.Name == name {
return e.Value
}
}
return ""
}
// ExtraEnvVars returns environment variables that should not leak into child processes.
func ExtraEnvVars() []cfg.EnvVar {
var b work.Builder
b.Init()
cppflags, cflags, cxxflags, fflags, ldflags := b.CFlags(&load.Package{})
return []cfg.EnvVar{
{Name: "CGO_CFLAGS", Value: strings.Join(cflags, " ")},
{Name: "CGO_CPPFLAGS", Value: strings.Join(cppflags, " ")},
{Name: "CGO_CXXFLAGS", Value: strings.Join(cxxflags, " ")},
{Name: "CGO_FFLAGS", Value: strings.Join(fflags, " ")},
{Name: "CGO_LDFLAGS", Value: strings.Join(ldflags, " ")},
{Name: "PKG_CONFIG", Value: b.PkgconfigCmd()},
}
}
func runEnv(cmd *base.Command, args []string) {
env := cfg.CmdEnv
env = append(env, ExtraEnvVars()...)
if len(args) > 0 {
if *envJson {
var es []cfg.EnvVar
for _, name := range args {
e := cfg.EnvVar{Name: name, Value: findEnv(env, name)}
es = append(es, e)
}
printEnvAsJSON(es)
} else {
for _, name := range args {
fmt.Printf("%s\n", findEnv(env, name))
}
}
return
}
if *envJson {
printEnvAsJSON(env)
return
}
for _, e := range env {
if e.Name != "TERM" {
switch runtime.GOOS {
default:
fmt.Printf("%s=\"%s\"\n", e.Name, e.Value)
case "plan9":
if strings.IndexByte(e.Value, '\x00') < 0 {
fmt.Printf("%s='%s'\n", e.Name, strings.Replace(e.Value, "'", "''", -1))
} else {
v := strings.Split(e.Value, "\x00")
fmt.Printf("%s=(", e.Name)
for x, s := range v {
if x > 0 {
fmt.Printf(" ")
}
fmt.Printf("%s", s)
}
fmt.Printf(")\n")
}
case "windows":
fmt.Printf("set %s=%s\n", e.Name, e.Value)
}
}
}
}
func printEnvAsJSON(env []cfg.EnvVar) {
m := make(map[string]string)
for _, e := range env {
if e.Name == "TERM" {
continue
}
m[e.Name] = e.Value
}
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", "\t")
if err := enc.Encode(m); err != nil {
base.Fatalf("%s", err)
}
}

View File

@ -2,9 +2,17 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
// Package fix implements the ``go fix'' command.
package fix
var cmdFix = &Command{
import (
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/str"
)
var CmdFix = &base.Command{
Run: runFix,
UsageLine: "fix [packages]",
Short: "run go tool fix on packages",
@ -20,11 +28,12 @@ See also: go fmt, go vet.
`,
}
func runFix(cmd *Command, args []string) {
for _, pkg := range packages(args) {
func runFix(cmd *base.Command, args []string) {
for _, pkg := range load.Packages(args) {
// Use pkg.gofiles instead of pkg.Dir so that
// the command only applies to this package,
// not to packages in subdirectories.
run(stringList(buildToolExec, tool("fix"), relPaths(pkg.allgofiles)))
files := base.FilterDotUnderscoreFiles(base.RelPaths(pkg.Internal.AllGoFiles))
base.Run(str.StringList(cfg.BuildToolexec, base.Tool("fix"), files))
}
}

View File

@ -2,24 +2,30 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
// Package fmtcmd implements the ``go fmt'' command.
package fmtcmd
import (
"os"
"path/filepath"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/str"
)
func init() {
addBuildFlagsNX(cmdFmt)
base.AddBuildFlagsNX(&CmdFmt.Flag)
}
var cmdFmt = &Command{
var CmdFmt = &base.Command{
Run: runFmt,
UsageLine: "fmt [-n] [-x] [packages]",
Short: "run gofmt on package sources",
Long: `
Fmt runs the command 'gofmt -l -w' on the packages named
by the import paths. It prints the names of the files that are modified.
by the import paths. It prints the names of the files that are modified.
For more about gofmt, see 'go doc cmd/gofmt'.
For more about specifying packages, see 'go help packages'.
@ -33,28 +39,29 @@ See also: go fix, go vet.
`,
}
func runFmt(cmd *Command, args []string) {
func runFmt(cmd *base.Command, args []string) {
gofmt := gofmtPath()
for _, pkg := range packages(args) {
for _, pkg := range load.Packages(args) {
// Use pkg.gofiles instead of pkg.Dir so that
// the command only applies to this package,
// not to packages in subdirectories.
run(stringList(gofmt, "-l", "-w", relPaths(pkg.allgofiles)))
files := base.FilterDotUnderscoreFiles(base.RelPaths(pkg.Internal.AllGoFiles))
base.Run(str.StringList(gofmt, "-l", "-w", files))
}
}
func gofmtPath() string {
gofmt := "gofmt"
if toolIsWindows {
gofmt += toolWindowsExtension
if base.ToolIsWindows {
gofmt += base.ToolWindowsExtension
}
gofmtPath := filepath.Join(gobin, gofmt)
gofmtPath := filepath.Join(cfg.GOBIN, gofmt)
if _, err := os.Stat(gofmtPath); err == nil {
return gofmtPath
}
gofmtPath = filepath.Join(goroot, "bin", gofmt)
gofmtPath = filepath.Join(cfg.GOROOT, "bin", gofmt)
if _, err := os.Stat(gofmtPath); err == nil {
return gofmtPath
}

View File

@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
// Package generate implements the ``go generate'' command.
package generate
import (
"bufio"
@ -16,9 +17,14 @@ import (
"regexp"
"strconv"
"strings"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/work"
)
var cmdGenerate = &Command{
var CmdGenerate = &base.Command{
Run: runGenerate,
UsageLine: "generate [-run regexp] [-n] [-v] [-x] [build flags] [file.go... | packages]",
Short: "generate Go files by processing source",
@ -74,7 +80,7 @@ line.
As a last step before running the command, any invocations of any
environment variables with alphanumeric names, such as $GOFILE or
$HOME, are expanded throughout the command line. The syntax for
variable expansion is $NAME on all operating systems. Due to the
variable expansion is $NAME on all operating systems. Due to the
order of evaluation, variables are expanded even inside quoted
strings. If the variable NAME is not set, $NAME expands to the
empty string.
@ -131,12 +137,12 @@ var (
)
func init() {
addBuildFlags(cmdGenerate)
cmdGenerate.Flag.StringVar(&generateRunFlag, "run", "", "")
work.AddBuildFlags(CmdGenerate)
CmdGenerate.Flag.StringVar(&generateRunFlag, "run", "", "")
}
func runGenerate(cmd *Command, args []string) {
ignoreImports = true
func runGenerate(cmd *base.Command, args []string) {
load.IgnoreImports = true
if generateRunFlag != "" {
var err error
@ -146,8 +152,8 @@ func runGenerate(cmd *Command, args []string) {
}
}
// Even if the arguments are .go files, this loop suffices.
for _, pkg := range packages(args) {
for _, file := range pkg.gofiles {
for _, pkg := range load.Packages(args) {
for _, file := range pkg.Internal.GoFiles {
if !generate(pkg.Name, file) {
break
}
@ -195,13 +201,13 @@ func (g *Generator) run() (ok bool) {
if e != stop {
panic(e)
}
setExitStatus(1)
base.SetExitStatus(1)
}
}()
g.dir, g.file = filepath.Split(g.path)
g.dir = filepath.Clean(g.dir) // No final separator please.
if buildV {
fmt.Fprintf(os.Stderr, "%s\n", shortPath(g.path))
if cfg.BuildV {
fmt.Fprintf(os.Stderr, "%s\n", base.ShortPath(g.path))
}
// Scan for lines that start "//go:generate".
@ -255,16 +261,16 @@ func (g *Generator) run() (ok bool) {
continue
}
// Run the command line.
if buildN || buildX {
if cfg.BuildN || cfg.BuildX {
fmt.Fprintf(os.Stderr, "%s\n", strings.Join(words, " "))
}
if buildN {
if cfg.BuildN {
continue
}
g.exec(words)
}
if err != nil && err != io.EOF {
g.errorf("error reading %s: %s", shortPath(g.path), err)
g.errorf("error reading %s: %s", base.ShortPath(g.path), err)
}
return true
}
@ -277,8 +283,8 @@ func isGoGenerate(buf []byte) bool {
// single go:generate command.
func (g *Generator) setEnv() {
g.env = []string{
"GOARCH=" + buildContext.GOARCH,
"GOOS=" + buildContext.GOOS,
"GOARCH=" + cfg.BuildContext.GOARCH,
"GOOS=" + cfg.BuildContext.GOOS,
"GOFILE=" + g.file,
"GOLINE=" + strconv.Itoa(g.lineNum),
"GOPACKAGE=" + g.pkg,
@ -354,7 +360,7 @@ var stop = fmt.Errorf("error in generation")
// It then exits the program (with exit status 1) because generation stops
// at the first error.
func (g *Generator) errorf(format string, args ...interface{}) {
fmt.Fprintf(os.Stderr, "%s:%d: %s\n", shortPath(g.path), g.lineNum,
fmt.Fprintf(os.Stderr, "%s:%d: %s\n", base.ShortPath(g.path), g.lineNum,
fmt.Sprintf(format, args...))
panic(stop)
}
@ -393,7 +399,7 @@ func (g *Generator) exec(words []string) {
cmd.Stderr = os.Stderr
// Run the command in the package directory.
cmd.Dir = g.dir
cmd.Env = mergeEnvLists(g.env, origEnv)
cmd.Env = base.MergeEnvLists(g.env, cfg.OrigEnv)
err := cmd.Run()
if err != nil {
g.errorf("running %q: %s", words[0], err)

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
package generate
import (
"reflect"

View File

@ -2,14 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !cmd_go_bootstrap
// This code is compiled into the real 'go' binary, but it is not
// compiled into the binary that is built during all.bash, so as
// to avoid needing to build net (and thus use cgo) during the
// bootstrap process.
package main
package get
import (
"encoding/xml"

View File

@ -2,20 +2,26 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
// Package get implements the ``go get'' command.
package get
import (
"fmt"
"go/build"
"os"
"path/filepath"
"regexp"
"runtime"
"strconv"
"strings"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/str"
"cmd/go/internal/web"
"cmd/go/internal/work"
)
var cmdGet = &Command{
var CmdGet = &base.Command{
UsageLine: "get [-d] [-f] [-fix] [-insecure] [-t] [-u] [build flags] [packages]",
Short: "download and install packages and dependencies",
Long: `
@ -40,7 +46,7 @@ The -t flag instructs get to also download the packages required to build
the tests for the specified packages.
The -u flag instructs get to use the network to update the named packages
and their dependencies. By default, get uses the network to check out
and their dependencies. By default, get uses the network to check out
missing packages but does not use it to look for updates to existing packages.
The -v flag enables verbose progress and debug output.
@ -54,8 +60,8 @@ get uses the first one. For more details see: 'go help gopath'.
When checking out or updating a package, get looks for a branch or tag
that matches the locally installed version of Go. The most important
rule is that if the local installation is running version "go1", get
searches for a branch or tag named "go1". If no such version exists it
retrieves the most recent version of the package.
searches for a branch or tag named "go1". If no such version exists
it retrieves the default branch of the package.
When go get checks out or updates a Git repository,
it also updates any git submodules referenced by the repository.
@ -71,21 +77,24 @@ See also: go build, go install, go clean.
`,
}
var getD = cmdGet.Flag.Bool("d", false, "")
var getF = cmdGet.Flag.Bool("f", false, "")
var getT = cmdGet.Flag.Bool("t", false, "")
var getU = cmdGet.Flag.Bool("u", false, "")
var getFix = cmdGet.Flag.Bool("fix", false, "")
var getInsecure = cmdGet.Flag.Bool("insecure", false, "")
var getD = CmdGet.Flag.Bool("d", false, "")
var getF = CmdGet.Flag.Bool("f", false, "")
var getT = CmdGet.Flag.Bool("t", false, "")
var getU = CmdGet.Flag.Bool("u", false, "")
var getFix = CmdGet.Flag.Bool("fix", false, "")
var getInsecure = CmdGet.Flag.Bool("insecure", false, "")
func init() {
addBuildFlags(cmdGet)
cmdGet.Run = runGet // break init loop
work.AddBuildFlags(CmdGet)
CmdGet.Run = runGet // break init loop
}
func runGet(cmd *Command, args []string) {
func runGet(cmd *base.Command, args []string) {
work.InstrumentInit()
work.BuildModeInit()
if *getF && !*getU {
fatalf("go get: cannot use -f flag without -u")
base.Fatalf("go get: cannot use -f flag without -u")
}
// Disable any prompting for passwords by Git.
@ -115,17 +124,17 @@ func runGet(cmd *Command, args []string) {
os.Setenv("GIT_SSH_COMMAND", "ssh -o ControlMaster=no")
}
// Phase 1. Download/update.
var stk importStack
// Phase 1. Download/update.
var stk load.ImportStack
mode := 0
if *getT {
mode |= getTestDeps
mode |= load.GetTestDeps
}
args = downloadPaths(args)
for _, arg := range args {
download(arg, nil, &stk, mode)
}
exitIfErrors()
base.ExitIfErrors()
// Phase 2. Rescan packages and re-evaluate args list.
@ -134,22 +143,18 @@ func runGet(cmd *Command, args []string) {
// the information will be recomputed. Instead of keeping
// track of the reverse dependency information, evict
// everything.
for name := range packageCache {
delete(packageCache, name)
}
load.ClearPackageCache()
// In order to rebuild packages information completely,
// we need to clear commands cache. Command packages are
// referring to evicted packages from the package cache.
// This leads to duplicated loads of the standard packages.
for name := range cmdCache {
delete(cmdCache, name)
}
load.ClearCmdCache()
args = importPaths(args)
packagesForBuild(args)
args = load.ImportPaths(args)
load.PackagesForBuild(args)
// Phase 3. Install.
// Phase 3. Install.
if *getD {
// Download only.
// Check delayed until now so that importPaths
@ -157,7 +162,7 @@ func runGet(cmd *Command, args []string) {
return
}
installPackages(args, true)
work.InstallPackages(args, true)
}
// downloadPaths prepares the list of paths to pass to download.
@ -166,7 +171,7 @@ func runGet(cmd *Command, args []string) {
// in the hope that we can figure out the repository from the
// initial ...-free prefix.
func downloadPaths(args []string) []string {
args = importPathsNoDotExpansion(args)
args = load.ImportPathsNoDotExpansion(args)
var out []string
for _, a := range args {
if strings.Contains(a, "...") {
@ -175,9 +180,9 @@ func downloadPaths(args []string) []string {
// warnings. They will be printed by the
// eventual call to importPaths instead.
if build.IsLocalImport(a) {
expand = matchPackagesInFS(a)
expand = load.MatchPackagesInFS(a)
} else {
expand = matchPackages(a)
expand = load.MatchPackages(a)
}
if len(expand) > 0 {
out = append(out, expand...)
@ -204,21 +209,21 @@ var downloadRootCache = map[string]bool{}
// download runs the download half of the get command
// for the package named by the argument.
func download(arg string, parent *Package, stk *importStack, mode int) {
if mode&useVendor != 0 {
func download(arg string, parent *load.Package, stk *load.ImportStack, mode int) {
if mode&load.UseVendor != 0 {
// Caller is responsible for expanding vendor paths.
panic("internal error: download mode has useVendor set")
}
load := func(path string, mode int) *Package {
load1 := func(path string, mode int) *load.Package {
if parent == nil {
return loadPackage(path, stk)
return load.LoadPackage(path, stk)
}
return loadImport(path, parent.Dir, parent, stk, nil, mode)
return load.LoadImport(path, parent.Dir, parent, stk, nil, mode)
}
p := load(arg, mode)
if p.Error != nil && p.Error.hard {
errorf("%s", p.Error)
p := load1(arg, mode)
if p.Error != nil && p.Error.Hard {
base.Errorf("%s", p.Error)
return
}
@ -240,26 +245,26 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
// Only process each package once.
// (Unless we're fetching test dependencies for this package,
// in which case we want to process it again.)
if downloadCache[arg] && mode&getTestDeps == 0 {
if downloadCache[arg] && mode&load.GetTestDeps == 0 {
return
}
downloadCache[arg] = true
pkgs := []*Package{p}
pkgs := []*load.Package{p}
wildcardOkay := len(*stk) == 0
isWildcard := false
// Download if the package is missing, or update if we're using -u.
if p.Dir == "" || *getU {
// The actual download.
stk.push(arg)
stk.Push(arg)
err := downloadPackage(p)
if err != nil {
errorf("%s", &PackageError{ImportStack: stk.copy(), Err: err.Error()})
stk.pop()
base.Errorf("%s", &load.PackageError{ImportStack: stk.Copy(), Err: err.Error()})
stk.Pop()
return
}
stk.pop()
stk.Pop()
args := []string{arg}
// If the argument has a wildcard in it, re-evaluate the wildcard.
@ -267,31 +272,25 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
// for p has been replaced in the package cache.
if wildcardOkay && strings.Contains(arg, "...") {
if build.IsLocalImport(arg) {
args = matchPackagesInFS(arg)
args = load.MatchPackagesInFS(arg)
} else {
args = matchPackages(arg)
args = load.MatchPackages(arg)
}
isWildcard = true
}
// Clear all relevant package cache entries before
// doing any new loads.
for _, arg := range args {
p := packageCache[arg]
if p != nil {
delete(packageCache, p.Dir)
delete(packageCache, p.ImportPath)
}
}
load.ClearPackageCachePartial(args)
pkgs = pkgs[:0]
for _, arg := range args {
// Note: load calls loadPackage or loadImport,
// which push arg onto stk already.
// Do not push here too, or else stk will say arg imports arg.
p := load(arg, mode)
p := load1(arg, mode)
if p.Error != nil {
errorf("%s", p.Error)
base.Errorf("%s", p.Error)
continue
}
pkgs = append(pkgs, p)
@ -302,12 +301,13 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
// due to wildcard expansion.
for _, p := range pkgs {
if *getFix {
run(buildToolExec, stringList(tool("fix"), relPaths(p.allgofiles)))
files := base.FilterDotUnderscoreFiles(base.RelPaths(p.Internal.AllGoFiles))
base.Run(cfg.BuildToolexec, str.StringList(base.Tool("fix"), files))
// The imports might have changed, so reload again.
p = reloadPackage(arg, stk)
p = load.ReloadPackage(arg, stk)
if p.Error != nil {
errorf("%s", p.Error)
base.Errorf("%s", p.Error)
return
}
}
@ -315,16 +315,16 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
if isWildcard {
// Report both the real package and the
// wildcard in any error message.
stk.push(p.ImportPath)
stk.Push(p.ImportPath)
}
// Process dependencies, now that we know what they are.
imports := p.Imports
if mode&getTestDeps != 0 {
if mode&load.GetTestDeps != 0 {
// Process test dependencies when -t is specified.
// (But don't get test dependencies for test dependencies:
// we always pass mode 0 to the recursive calls below.)
imports = stringList(imports, p.TestImports, p.XTestImports)
imports = str.StringList(imports, p.TestImports, p.XTestImports)
}
for i, path := range imports {
if path == "C" {
@ -332,19 +332,19 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
}
// Fail fast on import naming full vendor path.
// Otherwise expand path as needed for test imports.
// Note that p.Imports can have additional entries beyond p.build.Imports.
// Note that p.Imports can have additional entries beyond p.Internal.Build.Imports.
orig := path
if i < len(p.build.Imports) {
orig = p.build.Imports[i]
if i < len(p.Internal.Build.Imports) {
orig = p.Internal.Build.Imports[i]
}
if j, ok := findVendor(orig); ok {
stk.push(path)
err := &PackageError{
ImportStack: stk.copy(),
if j, ok := load.FindVendor(orig); ok {
stk.Push(path)
err := &load.PackageError{
ImportStack: stk.Copy(),
Err: "must be imported as " + path[j+len("vendor/"):],
}
stk.pop()
errorf("%s", err)
stk.Pop()
base.Errorf("%s", err)
continue
}
// If this is a test import, apply vendor lookup now.
@ -352,34 +352,34 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
// download does caching based on the value of path,
// so it must be the fully qualified path already.
if i >= len(p.Imports) {
path = vendoredImportPath(p, path)
path = load.VendoredImportPath(p, path)
}
download(path, p, stk, 0)
}
if isWildcard {
stk.pop()
stk.Pop()
}
}
}
// downloadPackage runs the create or download command
// to make the first copy of or update a copy of the given package.
func downloadPackage(p *Package) error {
func downloadPackage(p *load.Package) error {
var (
vcs *vcsCmd
repo, rootPath string
err error
)
security := secure
security := web.Secure
if *getInsecure {
security = insecure
security = web.Insecure
}
if p.build.SrcRoot != "" {
if p.Internal.Build.SrcRoot != "" {
// Directory exists. Look for checkout along path to src.
vcs, rootPath, err = vcsFromDir(p.Dir, p.build.SrcRoot)
vcs, rootPath, err = vcsFromDir(p.Dir, p.Internal.Build.SrcRoot)
if err != nil {
return err
}
@ -387,7 +387,7 @@ func downloadPackage(p *Package) error {
// Double-check where it came from.
if *getU && vcs.remoteRepo != nil {
dir := filepath.Join(p.build.SrcRoot, filepath.FromSlash(rootPath))
dir := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath))
remote, err := vcs.remoteRepo(vcs, dir)
if err != nil {
return err
@ -421,31 +421,31 @@ func downloadPackage(p *Package) error {
return fmt.Errorf("cannot download, %v uses insecure protocol", repo)
}
if p.build.SrcRoot == "" {
if p.Internal.Build.SrcRoot == "" {
// Package not found. Put in first directory of $GOPATH.
list := filepath.SplitList(buildContext.GOPATH)
list := filepath.SplitList(cfg.BuildContext.GOPATH)
if len(list) == 0 {
return fmt.Errorf("cannot download, $GOPATH not set. For more details see: 'go help gopath'")
}
// Guard against people setting GOPATH=$GOROOT.
if filepath.Clean(list[0]) == filepath.Clean(goroot) {
if filepath.Clean(list[0]) == filepath.Clean(cfg.GOROOT) {
return fmt.Errorf("cannot download, $GOPATH must not be set to $GOROOT. For more details see: 'go help gopath'")
}
if _, err := os.Stat(filepath.Join(list[0], "src/cmd/go/alldocs.go")); err == nil {
return fmt.Errorf("cannot download, %s is a GOROOT, not a GOPATH. For more details see: 'go help gopath'", list[0])
}
p.build.Root = list[0]
p.build.SrcRoot = filepath.Join(list[0], "src")
p.build.PkgRoot = filepath.Join(list[0], "pkg")
p.Internal.Build.Root = list[0]
p.Internal.Build.SrcRoot = filepath.Join(list[0], "src")
p.Internal.Build.PkgRoot = filepath.Join(list[0], "pkg")
}
root := filepath.Join(p.build.SrcRoot, filepath.FromSlash(rootPath))
root := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath))
// If we've considered this repository already, don't do it again.
if downloadRootCache[root] {
return nil
}
downloadRootCache[root] = true
if buildV {
if cfg.BuildV {
fmt.Fprintf(os.Stderr, "%s (download)\n", rootPath)
}
@ -464,7 +464,7 @@ func downloadPackage(p *Package) error {
return fmt.Errorf("%s exists but %s does not - stale checkout?", root, meta)
}
_, err := os.Stat(p.build.Root)
_, err := os.Stat(p.Internal.Build.Root)
gopathExisted := err == nil
// Some version control tools require the parent of the target to exist.
@ -472,8 +472,8 @@ func downloadPackage(p *Package) error {
if err = os.MkdirAll(parent, 0777); err != nil {
return err
}
if buildV && !gopathExisted && p.build.Root == buildContext.GOPATH {
fmt.Fprintf(os.Stderr, "created GOPATH=%s; see 'go help gopath'\n", p.build.Root)
if cfg.BuildV && !gopathExisted && p.Internal.Build.Root == cfg.BuildContext.GOPATH {
fmt.Fprintf(os.Stderr, "created GOPATH=%s; see 'go help gopath'\n", p.Internal.Build.Root)
}
if err = vcs.create(root, repo); err != nil {
@ -486,7 +486,7 @@ func downloadPackage(p *Package) error {
}
}
if buildN {
if cfg.BuildN {
// Do not show tag sync in -n; it's noise more than anything,
// and since we're not running commands, no tag will be found.
// But avoid printing nothing.
@ -510,14 +510,6 @@ func downloadPackage(p *Package) error {
return nil
}
// goTag matches go release tags such as go1 and go1.2.3.
// The numbers involved must be small (at most 4 digits),
// have no unnecessary leading zeros, and the version cannot
// end in .0 - it is go1, not go1.0 or go1.0.0.
var goTag = regexp.MustCompile(
`^go((0|[1-9][0-9]{0,3})\.)*([1-9][0-9]{0,3})$`,
)
// selectTag returns the closest matching tag for a given version.
// Closest means the latest one that is not after the current release.
// Version "goX" (or "goX.Y" or "goX.Y.Z") matches tags of the same form.
@ -525,7 +517,7 @@ var goTag = regexp.MustCompile(
// Version "weekly.YYYY-MM-DD" matches tags like "go.weekly.YYYY-MM-DD".
//
// NOTE(rsc): Eventually we will need to decide on some logic here.
// For now, there is only "go1". This matches the docs in go help get.
// For now, there is only "go1". This matches the docs in go help get.
func selectTag(goVersion string, tags []string) (match string) {
for _, t := range tags {
if t == "go1" {
@ -533,56 +525,4 @@ func selectTag(goVersion string, tags []string) (match string) {
}
}
return ""
/*
if goTag.MatchString(goVersion) {
v := goVersion
for _, t := range tags {
if !goTag.MatchString(t) {
continue
}
if cmpGoVersion(match, t) < 0 && cmpGoVersion(t, v) <= 0 {
match = t
}
}
}
return match
*/
}
// cmpGoVersion returns -1, 0, +1 reporting whether
// x < y, x == y, or x > y.
func cmpGoVersion(x, y string) int {
// Malformed strings compare less than well-formed strings.
if !goTag.MatchString(x) {
return -1
}
if !goTag.MatchString(y) {
return +1
}
// Compare numbers in sequence.
xx := strings.Split(x[len("go"):], ".")
yy := strings.Split(y[len("go"):], ".")
for i := 0; i < len(xx) && i < len(yy); i++ {
// The Atoi are guaranteed to succeed
// because the versions match goTag.
xi, _ := strconv.Atoi(xx[i])
yi, _ := strconv.Atoi(yy[i])
if xi < yi {
return -1
} else if xi > yi {
return +1
}
}
if len(xx) < len(yy) {
return -1
}
if len(xx) > len(yy) {
return +1
}
return 0
}

View File

@ -0,0 +1,83 @@
// Copyright 2014 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 get
import (
"cmd/go/internal/str"
"reflect"
"strings"
"testing"
)
var foldDupTests = []struct {
list []string
f1, f2 string
}{
{str.StringList("math/rand", "math/big"), "", ""},
{str.StringList("math", "strings"), "", ""},
{str.StringList("strings"), "", ""},
{str.StringList("strings", "strings"), "strings", "strings"},
{str.StringList("Rand", "rand", "math", "math/rand", "math/Rand"), "Rand", "rand"},
}
func TestFoldDup(t *testing.T) {
for _, tt := range foldDupTests {
f1, f2 := str.FoldDup(tt.list)
if f1 != tt.f1 || f2 != tt.f2 {
t.Errorf("foldDup(%q) = %q, %q, want %q, %q", tt.list, f1, f2, tt.f1, tt.f2)
}
}
}
var parseMetaGoImportsTests = []struct {
in string
out []metaImport
}{
{
`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">`,
[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
},
{
`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
<meta name="go-import" content="baz/quux git http://github.com/rsc/baz/quux">`,
[]metaImport{
{"foo/bar", "git", "https://github.com/rsc/foo/bar"},
{"baz/quux", "git", "http://github.com/rsc/baz/quux"},
},
},
{
`<head>
<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
</head>`,
[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
},
{
`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
<body>`,
[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
},
{
`<!doctype html><meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">`,
[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
},
{
// XML doesn't like <div style=position:relative>.
`<!doctype html><title>Page Not Found</title><meta name=go-import content="chitin.io/chitin git https://github.com/chitin-io/chitin"><div style=position:relative>DRAFT</div>`,
[]metaImport{{"chitin.io/chitin", "git", "https://github.com/chitin-io/chitin"}},
},
}
func TestParseMetaGoImports(t *testing.T) {
for i, tt := range parseMetaGoImportsTests {
out, err := parseMetaGoImports(strings.NewReader(tt.in))
if err != nil {
t.Errorf("test#%d: %v", i, err)
continue
}
if !reflect.DeepEqual(out, tt.out) {
t.Errorf("test#%d:\n\thave %q\n\twant %q", i, out, tt.out)
}
}
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
package get
import "testing"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
package get
import (
"bytes"
@ -18,6 +18,10 @@ import (
"regexp"
"strings"
"sync"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/web"
)
// A vcsCmd describes how to use a version control system
@ -298,15 +302,20 @@ func svnRemoteRepo(vcsSvn *vcsCmd, rootDir string) (remoteRepo string, err error
out := string(outb)
// Expect:
// ...
// Repository Root: <URL>
// ...
i := strings.Index(out, "\nRepository Root: ")
//
// ...
// URL: <URL>
// ...
//
// Note that we're not using the Repository Root line,
// because svn allows checking out subtrees.
// The URL will be the URL of the subtree (what we used with 'svn co')
// while the Repository Root may be a much higher parent.
i := strings.Index(out, "\nURL: ")
if i < 0 {
return "", fmt.Errorf("unable to parse output of svn info")
}
out = out[i+len("\nRepository Root: "):]
out = out[i+len("\nURL: "):]
i = strings.Index(out, "\n")
if i < 0 {
return "", fmt.Errorf("unable to parse output of svn info")
@ -320,7 +329,7 @@ func (v *vcsCmd) String() string {
}
// run runs the command line cmd in the given directory.
// keyval is a list of key, value pairs. run expands
// keyval is a list of key, value pairs. run expands
// instances of {key} in cmd into value, but only after
// splitting cmd into individual arguments.
// If an error occurs, run prints the command line and the
@ -372,8 +381,8 @@ func (v *vcsCmd) run1(dir string, cmdline string, keyval []string, verbose bool)
cmd := exec.Command(v.cmd, args...)
cmd.Dir = dir
cmd.Env = envForDir(cmd.Dir, os.Environ())
if buildX {
cmd.Env = base.EnvForDir(cmd.Dir, os.Environ())
if cfg.BuildX {
fmt.Printf("cd %s\n", dir)
fmt.Printf("%s %s\n", v.cmd, strings.Join(args, " "))
}
@ -383,7 +392,7 @@ func (v *vcsCmd) run1(dir string, cmdline string, keyval []string, verbose bool)
err = cmd.Run()
out := buf.Bytes()
if err != nil {
if verbose || buildV {
if verbose || cfg.BuildV {
fmt.Fprintf(os.Stderr, "# cd %s; %s %s\n", dir, v.cmd, strings.Join(args, " "))
os.Stderr.Write(out)
}
@ -535,19 +544,9 @@ type repoRoot struct {
var httpPrefixRE = regexp.MustCompile(`^https?:`)
// securityMode specifies whether a function should make network
// calls using insecure transports (eg, plain text HTTP).
// The zero value is "secure".
type securityMode int
const (
secure securityMode = iota
insecure
)
// repoRootForImportPath analyzes importPath to determine the
// version control system, and code repository to use.
func repoRootForImportPath(importPath string, security securityMode) (*repoRoot, error) {
func repoRootForImportPath(importPath string, security web.SecurityMode) (*repoRoot, error) {
rr, err := repoRootFromVCSPaths(importPath, "", security, vcsPaths)
if err == errUnknownSite {
// If there are wildcards, look up the thing before the wildcard,
@ -583,7 +582,7 @@ var errUnknownSite = errors.New("dynamic lookup required to find mapping")
// repoRootFromVCSPaths attempts to map importPath to a repoRoot
// using the mappings defined in vcsPaths.
// If scheme is non-empty, that scheme is forced.
func repoRootFromVCSPaths(importPath, scheme string, security securityMode, vcsPaths []*vcsPath) (*repoRoot, error) {
func repoRootFromVCSPaths(importPath, scheme string, security web.SecurityMode, vcsPaths []*vcsPath) (*repoRoot, error) {
// A common error is to use https://packagepath because that's what
// hg and git require. Diagnose this helpfully.
if loc := httpPrefixRE.FindStringIndex(importPath); loc != nil {
@ -633,7 +632,7 @@ func repoRootFromVCSPaths(importPath, scheme string, security securityMode, vcsP
match["repo"] = scheme + "://" + match["repo"]
} else {
for _, scheme := range vcs.scheme {
if security == secure && !vcs.isSecureScheme(scheme) {
if security == web.Secure && !vcs.isSecureScheme(scheme) {
continue
}
if vcs.ping(scheme, match["repo"]) == nil {
@ -657,7 +656,7 @@ func repoRootFromVCSPaths(importPath, scheme string, security securityMode, vcsP
// statically known by repoRootForImportPathStatic.
//
// This handles custom import paths like "name.tld/pkg/foo" or just "name.tld".
func repoRootForImportDynamic(importPath string, security securityMode) (*repoRoot, error) {
func repoRootForImportDynamic(importPath string, security web.SecurityMode) (*repoRoot, error) {
slash := strings.Index(importPath, "/")
if slash < 0 {
slash = len(importPath)
@ -666,10 +665,10 @@ func repoRootForImportDynamic(importPath string, security securityMode) (*repoRo
if !strings.Contains(host, ".") {
return nil, errors.New("import path does not begin with hostname")
}
urlStr, body, err := httpsOrHTTP(importPath, security)
urlStr, body, err := web.GetMaybeInsecure(importPath, security)
if err != nil {
msg := "https fetch: %v"
if security == insecure {
if security == web.Insecure {
msg = "http/" + msg
}
return nil, fmt.Errorf(msg, err)
@ -687,17 +686,17 @@ func repoRootForImportDynamic(importPath string, security securityMode) (*repoRo
}
return nil, fmt.Errorf("parse %s: no go-import meta tags (%s)", urlStr, err)
}
if buildV {
if cfg.BuildV {
log.Printf("get %q: found meta tag %#v at %s", importPath, mmi, urlStr)
}
// If the import was "uni.edu/bob/project", which said the
// prefix was "uni.edu" and the RepoRoot was "evilroot.com",
// make sure we don't trust Bob and check out evilroot.com to
// "uni.edu" yet (possibly overwriting/preempting another
// non-evil student). Instead, first verify the root and see
// non-evil student). Instead, first verify the root and see
// if it matches Bob's claim.
if mmi.Prefix != importPath {
if buildV {
if cfg.BuildV {
log.Printf("get %q: verifying non-authoritative meta tag", importPath)
}
urlStr0 := urlStr
@ -741,7 +740,7 @@ var (
// It is an error if no imports are found.
// urlStr will still be valid if err != nil.
// The returned urlStr will be of the form "https://golang.org/x/tools?go-get=1"
func metaImportsForPrefix(importPrefix string, security securityMode) (urlStr string, imports []metaImport, err error) {
func metaImportsForPrefix(importPrefix string, security web.SecurityMode) (urlStr string, imports []metaImport, err error) {
setCache := func(res fetchResult) (fetchResult, error) {
fetchCacheMu.Lock()
defer fetchCacheMu.Unlock()
@ -757,7 +756,7 @@ func metaImportsForPrefix(importPrefix string, security securityMode) (urlStr st
}
fetchCacheMu.Unlock()
urlStr, body, err := httpsOrHTTP(importPrefix, security)
urlStr, body, err := web.GetMaybeInsecure(importPrefix, security)
if err != nil {
return setCache(fetchResult{urlStr: urlStr, err: fmt.Errorf("fetch %s: %v", urlStr, err)})
}
@ -857,7 +856,7 @@ var vcsPaths = []*vcsPath{
// Github
{
prefix: "github.com/",
re: `^(?P<root>github\.com/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`,
re: `^(?P<root>github\.com/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(/[\p{L}0-9_.\-]+)*$`,
vcs: "git",
repo: "https://{root}",
check: noVCSSuffix,
@ -954,10 +953,10 @@ func bitbucketVCS(match map[string]string) error {
var resp struct {
SCM string `json:"scm"`
}
url := expand(match, "https://api.bitbucket.org/1.0/repositories/{bitname}")
data, err := httpGET(url)
url := expand(match, "https://api.bitbucket.org/2.0/repositories/{bitname}?fields=scm")
data, err := web.Get(url)
if err != nil {
if httpErr, ok := err.(*httpError); ok && httpErr.statusCode == 403 {
if httpErr, ok := err.(*web.HTTPError); ok && httpErr.StatusCode == 403 {
// this may be a private repository. If so, attempt to determine which
// VCS it uses. See issue 5375.
root := match["root"]
@ -997,7 +996,7 @@ func launchpadVCS(match map[string]string) error {
if match["project"] == "" || match["series"] == "" {
return nil
}
_, err := httpGET(expand(match, "https://code.launchpad.net/{project}{series}/.bzr/branch-format"))
_, err := web.Get(expand(match, "https://code.launchpad.net/{project}{series}/.bzr/branch-format"))
if err != nil {
match["root"] = expand(match, "launchpad.net/{project}")
match["repo"] = expand(match, "https://{root}")

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
package get
import (
"errors"
@ -12,6 +12,8 @@ import (
"path"
"path/filepath"
"testing"
"cmd/go/internal/web"
)
// Test that RepoRootForImportPath creates the correct RepoRoot for a given importPath.
@ -30,6 +32,14 @@ func TestRepoRootForImportPath(t *testing.T) {
repo: "https://github.com/golang/groupcache",
},
},
// Unicode letters in directories (issue 18660).
{
"github.com/user/unicode/испытание",
&repoRoot{
vcs: vcsGit,
repo: "https://github.com/user/unicode",
},
},
// IBM DevOps Services tests
{
"hub.jazz.net/git/user1/pkgname",
@ -147,21 +157,21 @@ func TestRepoRootForImportPath(t *testing.T) {
}
for _, test := range tests {
got, err := repoRootForImportPath(test.path, secure)
got, err := repoRootForImportPath(test.path, web.Secure)
want := test.want
if want == nil {
if err == nil {
t.Errorf("RepoRootForImport(%q): Error expected but not received", test.path)
t.Errorf("repoRootForImportPath(%q): Error expected but not received", test.path)
}
continue
}
if err != nil {
t.Errorf("RepoRootForImport(%q): %v", test.path, err)
t.Errorf("repoRootForImportPath(%q): %v", test.path, err)
continue
}
if got.vcs.name != want.vcs.name || got.repo != want.repo {
t.Errorf("RepoRootForImport(%q) = VCS(%s) Repo(%s), want VCS(%s) Repo(%s)", test.path, got.vcs, got.repo, want.vcs, want.repo)
t.Errorf("repoRootForImportPath(%q) = VCS(%s) Repo(%s), want VCS(%s) Repo(%s)", test.path, got.vcs, got.repo, want.vcs, want.repo)
}
}
}

View File

@ -0,0 +1,178 @@
// Copyright 2017 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 help implements the ``go help'' command.
package help
import (
"bufio"
"bytes"
"fmt"
"io"
"os"
"strings"
"text/template"
"unicode"
"unicode/utf8"
"cmd/go/internal/base"
)
// Help implements the 'help' command.
func Help(args []string) {
if len(args) == 0 {
PrintUsage(os.Stdout)
// not exit 2: succeeded at 'go help'.
return
}
if len(args) != 1 {
fmt.Fprintf(os.Stderr, "usage: go help command\n\nToo many arguments given.\n")
os.Exit(2) // failed at 'go help'
}
arg := args[0]
// 'go help documentation' generates doc.go.
if arg == "documentation" {
fmt.Println("// Copyright 2011 The Go Authors. All rights reserved.")
fmt.Println("// Use of this source code is governed by a BSD-style")
fmt.Println("// license that can be found in the LICENSE file.")
fmt.Println()
fmt.Println("// DO NOT EDIT THIS FILE. GENERATED BY mkalldocs.sh.")
fmt.Println("// Edit the documentation in other files and rerun mkalldocs.sh to generate this one.")
fmt.Println()
buf := new(bytes.Buffer)
PrintUsage(buf)
usage := &base.Command{Long: buf.String()}
tmpl(&commentWriter{W: os.Stdout}, documentationTemplate, append([]*base.Command{usage}, base.Commands...))
fmt.Println("package main")
return
}
for _, cmd := range base.Commands {
if cmd.Name() == arg {
tmpl(os.Stdout, helpTemplate, cmd)
// not exit 2: succeeded at 'go help cmd'.
return
}
}
fmt.Fprintf(os.Stderr, "Unknown help topic %#q. Run 'go help'.\n", arg)
os.Exit(2) // failed at 'go help cmd'
}
var usageTemplate = `Go is a tool for managing Go source code.
Usage:
go command [arguments]
The commands are:
{{range .}}{{if .Runnable}}
{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
Use "go help [command]" for more information about a command.
Additional help topics:
{{range .}}{{if not .Runnable}}
{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
Use "go help [topic]" for more information about that topic.
`
var helpTemplate = `{{if .Runnable}}usage: go {{.UsageLine}}
{{end}}{{.Long | trim}}
`
var documentationTemplate = `{{range .}}{{if .Short}}{{.Short | capitalize}}
{{end}}{{if .Runnable}}Usage:
go {{.UsageLine}}
{{end}}{{.Long | trim}}
{{end}}`
// commentWriter writes a Go comment to the underlying io.Writer,
// using line comment form (//).
type commentWriter struct {
W io.Writer
wroteSlashes bool // Wrote "//" at the beginning of the current line.
}
func (c *commentWriter) Write(p []byte) (int, error) {
var n int
for i, b := range p {
if !c.wroteSlashes {
s := "//"
if b != '\n' {
s = "// "
}
if _, err := io.WriteString(c.W, s); err != nil {
return n, err
}
c.wroteSlashes = true
}
n0, err := c.W.Write(p[i : i+1])
n += n0
if err != nil {
return n, err
}
if b == '\n' {
c.wroteSlashes = false
}
}
return len(p), nil
}
// An errWriter wraps a writer, recording whether a write error occurred.
type errWriter struct {
w io.Writer
err error
}
func (w *errWriter) Write(b []byte) (int, error) {
n, err := w.w.Write(b)
if err != nil {
w.err = err
}
return n, err
}
// tmpl executes the given template text on data, writing the result to w.
func tmpl(w io.Writer, text string, data interface{}) {
t := template.New("top")
t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize})
template.Must(t.Parse(text))
ew := &errWriter{w: w}
err := t.Execute(ew, data)
if ew.err != nil {
// I/O error writing. Ignore write on closed pipe.
if strings.Contains(ew.err.Error(), "pipe") {
os.Exit(1)
}
base.Fatalf("writing output: %v", ew.err)
}
if err != nil {
panic(err)
}
}
func capitalize(s string) string {
if s == "" {
return s
}
r, n := utf8.DecodeRuneInString(s)
return string(unicode.ToTitle(r)) + s[n:]
}
func PrintUsage(w io.Writer) {
bw := bufio.NewWriter(w)
tmpl(bw, usageTemplate, base.Commands)
bw.Flush()
}

View File

@ -2,31 +2,33 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
package help
var helpC = &Command{
import "cmd/go/internal/base"
var HelpC = &base.Command{
UsageLine: "c",
Short: "calling between Go and C",
Long: `
There are two different ways to call between Go and C/C++ code.
The first is the cgo tool, which is part of the Go distribution. For
The first is the cgo tool, which is part of the Go distribution. For
information on how to use it see the cgo documentation (go doc cmd/cgo).
The second is the SWIG program, which is a general tool for
interfacing between languages. For information on SWIG see
http://swig.org/. When running go build, any file with a .swig
extension will be passed to SWIG. Any file with a .swigcxx extension
interfacing between languages. For information on SWIG see
http://swig.org/. When running go build, any file with a .swig
extension will be passed to SWIG. Any file with a .swigcxx extension
will be passed to SWIG with the -c++ option.
When either cgo or SWIG is used, go build will pass any .c, .m, .s,
or .S files to the C compiler, and any .cc, .cpp, .cxx files to the C++
compiler. The CC or CXX environment variables may be set to determine
compiler. The CC or CXX environment variables may be set to determine
the C or C++ compiler, respectively, to use.
`,
}
var helpPackages = &Command{
var HelpPackages = &base.Command{
UsageLine: "packages",
Short: "description of package lists",
Long: `
@ -67,17 +69,28 @@ the Go repository.
An import path is a pattern if it includes one or more "..." wildcards,
each of which can match any string, including the empty string and
strings containing slashes. Such a pattern expands to all package
strings containing slashes. Such a pattern expands to all package
directories found in the GOPATH trees with names matching the
patterns. As a special case, x/... matches x as well as x's subdirectories.
For example, net/... expands to net and packages in its subdirectories.
patterns.
To make common patterns more convenient, there are two special cases.
First, /... at the end of the pattern can match an empty string,
so that net/... matches both net and packages in its subdirectories, like net/http.
Second, any slash-separated pattern element containing a wildcard never
participates in a match of the "vendor" element in the path of a vendored
package, so that ./... does not match packages in subdirectories of
./vendor or ./mycode/vendor, but ./vendor/... and ./mycode/vendor/... do.
Note, however, that a directory named vendor that itself contains code
is not a vendored package: cmd/vendor would be a command named vendor,
and the pattern cmd/... matches it.
See golang.org/s/go15vendor for more about vendoring.
An import path can also name a package to be downloaded from
a remote repository. Run 'go help importpath' for details.
a remote repository. Run 'go help importpath' for details.
Every package in a program must have a unique import path.
By convention, this is arranged by starting each path with a
unique prefix that belongs to you. For example, paths used
unique prefix that belongs to you. For example, paths used
internally at Google all begin with 'google', and paths
denoting remote repositories begin with the path to the code,
such as 'github.com/user/repo'.
@ -100,13 +113,13 @@ by the go tool, as are directories named "testdata".
`,
}
var helpImportPath = &Command{
var HelpImportPath = &base.Command{
UsageLine: "importpath",
Short: "import path syntax",
Long: `
An import path (see 'go help packages') denotes a package stored in the local
file system. In general, an import path denotes either a standard package (such
file system. In general, an import path denotes either a standard package (such
as "unicode/utf8") or a package found in one of the work spaces (For more
details see: 'go help gopath').
@ -177,7 +190,7 @@ To declare the code location, an import path of the form
specifies the given repository, with or without the .vcs suffix,
using the named version control system, and then the path inside
that repository. The supported version control systems are:
that repository. The supported version control systems are:
Bazaar .bzr
Git .git
@ -197,7 +210,7 @@ denotes the foo/bar directory of the Git repository at
example.org/repo or repo.git.
When a version control system supports multiple protocols,
each is tried in turn when downloading. For example, a Git
each is tried in turn when downloading. For example, a Git
download tries https://, then git+ssh://.
By default, downloads are restricted to known secure protocols
@ -277,7 +290,7 @@ See https://golang.org/s/go14customimport for details.
`,
}
var helpGopath = &Command{
var HelpGopath = &base.Command{
UsageLine: "gopath",
Short: "GOPATH environment variable",
Long: `
@ -299,7 +312,7 @@ See https://golang.org/wiki/SettingGOPATH to set a custom GOPATH.
Each directory listed in GOPATH must have a prescribed structure:
The src directory holds source code. The path below src
The src directory holds source code. The path below src
determines the import path or executable name.
The pkg directory holds installed package objects.
@ -313,11 +326,11 @@ has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a".
The bin directory holds compiled commands.
Each command is named for its source directory, but only
the final element, not the entire path. That is, the
the final element, not the entire path. That is, the
command with source in DIR/src/foo/quux is installed into
DIR/bin/quux, not DIR/bin/foo/quux. The "foo/" prefix is stripped
DIR/bin/quux, not DIR/bin/foo/quux. The "foo/" prefix is stripped
so that you can add DIR/bin to your PATH to get at the
installed commands. If the GOBIN environment variable is
installed commands. If the GOBIN environment variable is
set, commands are installed to the directory it names instead
of DIR/bin. GOBIN must be an absolute path.
@ -429,7 +442,7 @@ See https://golang.org/s/go15vendor for details.
`,
}
var helpEnvironment = &Command{
var HelpEnvironment = &base.Command{
UsageLine: "environment",
Short: "environment variables",
Long: `
@ -464,7 +477,7 @@ Environment variables for use with cgo:
CC
The command to use to compile C code.
CGO_ENABLED
Whether the cgo command is supported. Either 0 or 1.
Whether the cgo command is supported. Either 0 or 1.
CGO_CFLAGS
Flags that cgo will pass to the compiler when compiling
C code.
@ -514,7 +527,7 @@ Special-purpose environment variables:
`,
}
var helpFileType = &Command{
var HelpFileType = &base.Command{
UsageLine: "filetype",
Short: "file types",
Long: `
@ -560,7 +573,7 @@ for more details.
`,
}
var helpBuildmode = &Command{
var HelpBuildmode = &base.Command{
UsageLine: "buildmode",
Short: "description of build modes",
Long: `
@ -579,10 +592,10 @@ are:
exactly one main package to be listed.
-buildmode=c-shared
Build the listed main packages, plus all packages that they
import, into C shared libraries. The only callable symbols will
Build the listed main package, plus all packages it imports,
into a C shared library. The only callable symbols will
be those functions exported using a cgo //export comment.
Non-main packages are ignored.
Requires exactly one main package to be listed.
-buildmode=default
Listed main packages are built into executables and listed

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
package list
import (
"go/build"

View File

@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
// Package list implements the ``go list'' command.
package list
import (
"bufio"
@ -11,9 +12,14 @@ import (
"os"
"strings"
"text/template"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/work"
)
var cmdList = &Command{
var CmdList = &base.Command{
UsageLine: "list [-e] [-f format] [-json] [build flags] [packages]",
Short: "list packages",
Long: `
@ -27,7 +33,7 @@ The default output shows the package import path:
golang.org/x/net/html
The -f flag specifies an alternate format for the list, using the
syntax of package template. The default output is equivalent to -f
syntax of package template. The default output is equivalent to -f
'{{.ImportPath}}'. The struct being passed to the template is:
type Package struct {
@ -120,12 +126,12 @@ The -json flag causes the package data to be printed in JSON format
instead of using the template format.
The -e flag changes the handling of erroneous packages, those that
cannot be found or are malformed. By default, the list command
cannot be found or are malformed. By default, the list command
prints an error to standard error for each erroneous package and
omits the packages from consideration during the usual printing.
With the -e flag, the list command never prints errors to standard
error and instead processes the erroneous packages with the usual
printing. Erroneous packages will have a non-empty ImportPath and
printing. Erroneous packages will have a non-empty ImportPath and
a non-nil Error field; other information may or may not be missing
(zeroed).
@ -136,27 +142,27 @@ For more about specifying packages, see 'go help packages'.
}
func init() {
cmdList.Run = runList // break init cycle
addBuildFlags(cmdList)
CmdList.Run = runList // break init cycle
work.AddBuildFlags(CmdList)
}
var listE = cmdList.Flag.Bool("e", false, "")
var listFmt = cmdList.Flag.String("f", "{{.ImportPath}}", "")
var listJson = cmdList.Flag.Bool("json", false, "")
var listE = CmdList.Flag.Bool("e", false, "")
var listFmt = CmdList.Flag.String("f", "{{.ImportPath}}", "")
var listJson = CmdList.Flag.Bool("json", false, "")
var nl = []byte{'\n'}
func runList(cmd *Command, args []string) {
buildModeInit()
func runList(cmd *base.Command, args []string) {
work.BuildModeInit()
out := newTrackingWriter(os.Stdout)
defer out.w.Flush()
var do func(*Package)
var do func(*load.PackagePublic)
if *listJson {
do = func(p *Package) {
do = func(p *load.PackagePublic) {
b, err := json.MarshalIndent(p, "", "\t")
if err != nil {
out.Flush()
fatalf("%s", err)
base.Fatalf("%s", err)
}
out.Write(b)
out.Write(nl)
@ -165,7 +171,7 @@ func runList(cmd *Command, args []string) {
var cachedCtxt *Context
context := func() *Context {
if cachedCtxt == nil {
cachedCtxt = newContext(&buildContext)
cachedCtxt = newContext(&cfg.BuildContext)
}
return cachedCtxt
}
@ -175,12 +181,12 @@ func runList(cmd *Command, args []string) {
}
tmpl, err := template.New("main").Funcs(fm).Parse(*listFmt)
if err != nil {
fatalf("%s", err)
base.Fatalf("%s", err)
}
do = func(p *Package) {
do = func(p *load.PackagePublic) {
if err := tmpl.Execute(out, p); err != nil {
out.Flush()
fatalf("%s", err)
base.Fatalf("%s", err)
}
if out.NeedNL() {
out.Write(nl)
@ -188,17 +194,17 @@ func runList(cmd *Command, args []string) {
}
}
load := packages
loadpkgs := load.Packages
if *listE {
load = packagesAndErrors
loadpkgs = load.PackagesAndErrors
}
for _, pkg := range load(args) {
for _, pkg := range loadpkgs(args) {
// Show vendor-expanded paths in listing
pkg.TestImports = pkg.vendored(pkg.TestImports)
pkg.XTestImports = pkg.vendored(pkg.XTestImports)
pkg.TestImports = pkg.Vendored(pkg.TestImports)
pkg.XTestImports = pkg.Vendored(pkg.XTestImports)
do(pkg)
do(&pkg.PackagePublic)
}
}

View File

@ -0,0 +1,165 @@
// 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.
package load
import (
"strings"
"testing"
)
var matchPatternTests = `
pattern ...
match foo
pattern net
match net
not net/http
pattern net/http
match net/http
not net
pattern net...
match net net/http netchan
not not/http not/net/http
# Special cases. Quoting docs:
# First, /... at the end of the pattern can match an empty string,
# so that net/... matches both net and packages in its subdirectories, like net/http.
pattern net/...
match net net/http
not not/http not/net/http netchan
# Second, any slash-separted pattern element containing a wildcard never
# participates in a match of the "vendor" element in the path of a vendored
# package, so that ./... does not match packages in subdirectories of
# ./vendor or ./mycode/vendor, but ./vendor/... and ./mycode/vendor/... do.
# Note, however, that a directory named vendor that itself contains code
# is not a vendored package: cmd/vendor would be a command named vendor,
# and the pattern cmd/... matches it.
pattern ./...
match ./vendor ./mycode/vendor
not ./vendor/foo ./mycode/vendor/foo
pattern ./vendor/...
match ./vendor/foo ./vendor/foo/vendor
not ./vendor/foo/vendor/bar
pattern mycode/vendor/...
match mycode/vendor mycode/vendor/foo mycode/vendor/foo/vendor
not mycode/vendor/foo/vendor/bar
pattern x/vendor/y
match x/vendor/y
not x/vendor
pattern x/vendor/y/...
match x/vendor/y x/vendor/y/z x/vendor/y/vendor x/vendor/y/z/vendor
not x/vendor/y/vendor/z
pattern .../vendor/...
match x/vendor/y x/vendor/y/z x/vendor/y/vendor x/vendor/y/z/vendor
`
func TestMatchPattern(t *testing.T) {
testPatterns(t, "matchPattern", matchPatternTests, func(pattern, name string) bool {
return matchPattern(pattern)(name)
})
}
var treeCanMatchPatternTests = `
pattern ...
match foo
pattern net
match net
not net/http
pattern net/http
match net net/http
pattern net...
match net netchan net/http
not not/http not/net/http
pattern net/...
match net net/http
not not/http netchan
pattern abc.../def
match abcxyz
not xyzabc
pattern x/y/z/...
match x x/y x/y/z x/y/z/w
pattern x/y/z
match x x/y x/y/z
not x/y/z/w
pattern x/.../y/z
match x/a/b/c
not y/x/a/b/c
`
func TestTreeCanMatchPattern(t *testing.T) {
testPatterns(t, "treeCanMatchPattern", treeCanMatchPatternTests, func(pattern, name string) bool {
return treeCanMatchPattern(pattern)(name)
})
}
var hasPathPrefixTests = []stringPairTest{
{"abc", "a", false},
{"a/bc", "a", true},
{"a", "a", true},
{"a/bc", "a/", true},
}
func TestHasPathPrefix(t *testing.T) {
testStringPairs(t, "hasPathPrefix", hasPathPrefixTests, hasPathPrefix)
}
type stringPairTest struct {
in1 string
in2 string
out bool
}
func testStringPairs(t *testing.T, name string, tests []stringPairTest, f func(string, string) bool) {
for _, tt := range tests {
if out := f(tt.in1, tt.in2); out != tt.out {
t.Errorf("%s(%q, %q) = %v, want %v", name, tt.in1, tt.in2, out, tt.out)
}
}
}
func testPatterns(t *testing.T, name, tests string, fn func(string, string) bool) {
var patterns []string
for _, line := range strings.Split(tests, "\n") {
if i := strings.Index(line, "#"); i >= 0 {
line = line[:i]
}
f := strings.Fields(line)
if len(f) == 0 {
continue
}
switch f[0] {
default:
t.Fatalf("unknown directive %q", f[0])
case "pattern":
patterns = f[1:]
case "match", "not":
want := f[0] == "match"
for _, pattern := range patterns {
for _, in := range f[1:] {
if fn(pattern, in) != want {
t.Errorf("%s(%q, %q) = %v, want %v", name, pattern, in, !want, want)
}
}
}
}
}
}

View File

@ -0,0 +1,80 @@
// Copyright 2017 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 load
import (
"path/filepath"
"strings"
)
// hasSubdir reports whether dir is a subdirectory of
// (possibly multiple levels below) root.
// If so, it sets rel to the path fragment that must be
// appended to root to reach dir.
func hasSubdir(root, dir string) (rel string, ok bool) {
if p, err := filepath.EvalSymlinks(root); err == nil {
root = p
}
if p, err := filepath.EvalSymlinks(dir); err == nil {
dir = p
}
const sep = string(filepath.Separator)
root = filepath.Clean(root)
if !strings.HasSuffix(root, sep) {
root += sep
}
dir = filepath.Clean(dir)
if !strings.HasPrefix(dir, root) {
return "", false
}
return filepath.ToSlash(dir[len(root):]), true
}
// hasPathPrefix reports whether the path s begins with the
// elements in prefix.
func hasPathPrefix(s, prefix string) bool {
switch {
default:
return false
case len(s) == len(prefix):
return s == prefix
case len(s) > len(prefix):
if prefix != "" && prefix[len(prefix)-1] == '/' {
return strings.HasPrefix(s, prefix)
}
return s[len(prefix)] == '/' && s[:len(prefix)] == prefix
}
}
// expandPath returns the symlink-expanded form of path.
func expandPath(p string) string {
x, err := filepath.EvalSymlinks(p)
if err == nil {
return x
}
return p
}
// hasFilePathPrefix reports whether the filesystem path s begins with the
// elements in prefix.
func hasFilePathPrefix(s, prefix string) bool {
sv := strings.ToUpper(filepath.VolumeName(s))
pv := strings.ToUpper(filepath.VolumeName(prefix))
s = s[len(sv):]
prefix = prefix[len(pv):]
switch {
default:
return false
case sv != pv:
return false
case len(s) == len(prefix):
return s == prefix
case len(s) > len(prefix):
if prefix != "" && prefix[len(prefix)-1] == filepath.Separator {
return strings.HasPrefix(s, prefix)
}
return s[len(prefix)] == filepath.Separator && s[:len(prefix)] == prefix
}
}

View File

@ -0,0 +1,338 @@
// Copyright 2017 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 load
import (
"cmd/go/internal/cfg"
"fmt"
"go/build"
"log"
"os"
"path"
"path/filepath"
"regexp"
"strings"
)
// allPackages returns all the packages that can be found
// under the $GOPATH directories and $GOROOT matching pattern.
// The pattern is either "all" (all packages), "std" (standard packages),
// "cmd" (standard commands), or a path including "...".
func allPackages(pattern string) []string {
pkgs := MatchPackages(pattern)
if len(pkgs) == 0 {
fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
}
return pkgs
}
// allPackagesInFS is like allPackages but is passed a pattern
// beginning ./ or ../, meaning it should scan the tree rooted
// at the given directory. There are ... in the pattern too.
func allPackagesInFS(pattern string) []string {
pkgs := MatchPackagesInFS(pattern)
if len(pkgs) == 0 {
fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
}
return pkgs
}
// MatchPackages returns a list of package paths matching pattern
// (see go help packages for pattern syntax).
func MatchPackages(pattern string) []string {
match := func(string) bool { return true }
treeCanMatch := func(string) bool { return true }
if !IsMetaPackage(pattern) {
match = matchPattern(pattern)
treeCanMatch = treeCanMatchPattern(pattern)
}
have := map[string]bool{
"builtin": true, // ignore pseudo-package that exists only for documentation
}
if !cfg.BuildContext.CgoEnabled {
have["runtime/cgo"] = true // ignore during walk
}
var pkgs []string
for _, src := range cfg.BuildContext.SrcDirs() {
if (pattern == "std" || pattern == "cmd") && src != cfg.GOROOTsrc {
continue
}
src = filepath.Clean(src) + string(filepath.Separator)
root := src
if pattern == "cmd" {
root += "cmd" + string(filepath.Separator)
}
filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
if err != nil || path == src {
return nil
}
want := true
// Avoid .foo, _foo, and testdata directory trees.
_, elem := filepath.Split(path)
if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
want = false
}
name := filepath.ToSlash(path[len(src):])
if pattern == "std" && (!isStandardImportPath(name) || name == "cmd") {
// The name "std" is only the standard library.
// If the name is cmd, it's the root of the command tree.
want = false
}
if !treeCanMatch(name) {
want = false
}
if !fi.IsDir() {
if fi.Mode()&os.ModeSymlink != 0 && want {
if target, err := os.Stat(path); err == nil && target.IsDir() {
fmt.Fprintf(os.Stderr, "warning: ignoring symlink %s\n", path)
}
}
return nil
}
if !want {
return filepath.SkipDir
}
if have[name] {
return nil
}
have[name] = true
if !match(name) {
return nil
}
pkg, err := cfg.BuildContext.ImportDir(path, 0)
if err != nil {
if _, noGo := err.(*build.NoGoError); noGo {
return nil
}
}
// If we are expanding "cmd", skip main
// packages under cmd/vendor. At least as of
// March, 2017, there is one there for the
// vendored pprof tool.
if pattern == "cmd" && strings.HasPrefix(pkg.ImportPath, "cmd/vendor") && pkg.Name == "main" {
return nil
}
pkgs = append(pkgs, name)
return nil
})
}
return pkgs
}
// MatchPackagesInFS returns a list of package paths matching pattern,
// which must begin with ./ or ../
// (see go help packages for pattern syntax).
func MatchPackagesInFS(pattern string) []string {
// Find directory to begin the scan.
// Could be smarter but this one optimization
// is enough for now, since ... is usually at the
// end of a path.
i := strings.Index(pattern, "...")
dir, _ := path.Split(pattern[:i])
// pattern begins with ./ or ../.
// path.Clean will discard the ./ but not the ../.
// We need to preserve the ./ for pattern matching
// and in the returned import paths.
prefix := ""
if strings.HasPrefix(pattern, "./") {
prefix = "./"
}
match := matchPattern(pattern)
var pkgs []string
filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
if err != nil || !fi.IsDir() {
return nil
}
if path == dir {
// filepath.Walk starts at dir and recurses. For the recursive case,
// the path is the result of filepath.Join, which calls filepath.Clean.
// The initial case is not Cleaned, though, so we do this explicitly.
//
// This converts a path like "./io/" to "io". Without this step, running
// "cd $GOROOT/src; go list ./io/..." would incorrectly skip the io
// package, because prepending the prefix "./" to the unclean path would
// result in "././io", and match("././io") returns false.
path = filepath.Clean(path)
}
// Avoid .foo, _foo, and testdata directory trees, but do not avoid "." or "..".
_, elem := filepath.Split(path)
dot := strings.HasPrefix(elem, ".") && elem != "." && elem != ".."
if dot || strings.HasPrefix(elem, "_") || elem == "testdata" {
return filepath.SkipDir
}
name := prefix + filepath.ToSlash(path)
if !match(name) {
return nil
}
// We keep the directory if we can import it, or if we can't import it
// due to invalid Go source files. This means that directories containing
// parse errors will be built (and fail) instead of being silently skipped
// as not matching the pattern. Go 1.5 and earlier skipped, but that
// behavior means people miss serious mistakes.
// See golang.org/issue/11407.
if p, err := cfg.BuildContext.ImportDir(path, 0); err != nil && (p == nil || len(p.InvalidGoFiles) == 0) {
if _, noGo := err.(*build.NoGoError); !noGo {
log.Print(err)
}
return nil
}
pkgs = append(pkgs, name)
return nil
})
return pkgs
}
// treeCanMatchPattern(pattern)(name) reports whether
// name or children of name can possibly match pattern.
// Pattern is the same limited glob accepted by matchPattern.
func treeCanMatchPattern(pattern string) func(name string) bool {
wildCard := false
if i := strings.Index(pattern, "..."); i >= 0 {
wildCard = true
pattern = pattern[:i]
}
return func(name string) bool {
return len(name) <= len(pattern) && hasPathPrefix(pattern, name) ||
wildCard && strings.HasPrefix(name, pattern)
}
}
// matchPattern(pattern)(name) reports whether
// name matches pattern. Pattern is a limited glob
// pattern in which '...' means 'any string' and there
// is no other special syntax.
// Unfortunately, there are two special cases. Quoting "go help packages":
//
// First, /... at the end of the pattern can match an empty string,
// so that net/... matches both net and packages in its subdirectories, like net/http.
// Second, any slash-separted pattern element containing a wildcard never
// participates in a match of the "vendor" element in the path of a vendored
// package, so that ./... does not match packages in subdirectories of
// ./vendor or ./mycode/vendor, but ./vendor/... and ./mycode/vendor/... do.
// Note, however, that a directory named vendor that itself contains code
// is not a vendored package: cmd/vendor would be a command named vendor,
// and the pattern cmd/... matches it.
func matchPattern(pattern string) func(name string) bool {
// Convert pattern to regular expression.
// The strategy for the trailing /... is to nest it in an explicit ? expression.
// The strategy for the vendor exclusion is to change the unmatchable
// vendor strings to a disallowed code point (vendorChar) and to use
// "(anything but that codepoint)*" as the implementation of the ... wildcard.
// This is a bit complicated but the obvious alternative,
// namely a hand-written search like in most shell glob matchers,
// is too easy to make accidentally exponential.
// Using package regexp guarantees linear-time matching.
const vendorChar = "\x00"
if strings.Contains(pattern, vendorChar) {
return func(name string) bool { return false }
}
re := regexp.QuoteMeta(pattern)
re = replaceVendor(re, vendorChar)
switch {
case strings.HasSuffix(re, `/`+vendorChar+`/\.\.\.`):
re = strings.TrimSuffix(re, `/`+vendorChar+`/\.\.\.`) + `(/vendor|/` + vendorChar + `/\.\.\.)`
case re == vendorChar+`/\.\.\.`:
re = `(/vendor|/` + vendorChar + `/\.\.\.)`
case strings.HasSuffix(re, `/\.\.\.`):
re = strings.TrimSuffix(re, `/\.\.\.`) + `(/\.\.\.)?`
}
re = strings.Replace(re, `\.\.\.`, `[^`+vendorChar+`]*`, -1)
reg := regexp.MustCompile(`^` + re + `$`)
return func(name string) bool {
if strings.Contains(name, vendorChar) {
return false
}
return reg.MatchString(replaceVendor(name, vendorChar))
}
}
// replaceVendor returns the result of replacing
// non-trailing vendor path elements in x with repl.
func replaceVendor(x, repl string) string {
if !strings.Contains(x, "vendor") {
return x
}
elem := strings.Split(x, "/")
for i := 0; i < len(elem)-1; i++ {
if elem[i] == "vendor" {
elem[i] = repl
}
}
return strings.Join(elem, "/")
}
// ImportPaths returns the import paths to use for the given command line.
func ImportPaths(args []string) []string {
args = ImportPathsNoDotExpansion(args)
var out []string
for _, a := range args {
if strings.Contains(a, "...") {
if build.IsLocalImport(a) {
out = append(out, allPackagesInFS(a)...)
} else {
out = append(out, allPackages(a)...)
}
continue
}
out = append(out, a)
}
return out
}
// ImportPathsNoDotExpansion returns the import paths to use for the given
// command line, but it does no ... expansion.
func ImportPathsNoDotExpansion(args []string) []string {
if len(args) == 0 {
return []string{"."}
}
var out []string
for _, a := range args {
// Arguments are supposed to be import paths, but
// as a courtesy to Windows developers, rewrite \ to /
// in command-line arguments. Handles .\... and so on.
if filepath.Separator == '\\' {
a = strings.Replace(a, `\`, `/`, -1)
}
// Put argument in canonical form, but preserve leading ./.
if strings.HasPrefix(a, "./") {
a = "./" + path.Clean(a)
if a == "./." {
a = "."
}
} else {
a = path.Clean(a)
}
if IsMetaPackage(a) {
out = append(out, allPackages(a)...)
continue
}
out = append(out, a)
}
return out
}
// isMetaPackage checks if name is a reserved package name that expands to multiple packages.
func IsMetaPackage(name string) bool {
return name == "std" || name == "cmd" || name == "all"
}

View File

@ -10,7 +10,7 @@
// +build testgo
package main
package load
import "os"

View File

@ -2,34 +2,22 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
// Package run implements the ``go run'' command.
package run
import (
"fmt"
"os"
"os/exec"
"runtime"
"strings"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/str"
"cmd/go/internal/work"
)
var execCmd []string // -exec flag, for run and test
func findExecCmd() []string {
if execCmd != nil {
return execCmd
}
execCmd = []string{} // avoid work the second time
if goos == runtime.GOOS && goarch == runtime.GOARCH {
return execCmd
}
path, err := exec.LookPath(fmt.Sprintf("go_%s_%s_exec", goos, goarch))
if err == nil {
execCmd = []string{path}
}
return execCmd
}
var cmdRun = &Command{
var CmdRun = &base.Command{
UsageLine: "run [build flags] [-exec xprog] gofiles... [arguments...]",
Short: "compile and run Go program",
Long: `
@ -53,60 +41,60 @@ See also: go build.
}
func init() {
cmdRun.Run = runRun // break init loop
CmdRun.Run = runRun // break init loop
addBuildFlags(cmdRun)
cmdRun.Flag.Var((*stringsFlag)(&execCmd), "exec", "")
work.AddBuildFlags(CmdRun)
CmdRun.Flag.Var((*base.StringsFlag)(&work.ExecCmd), "exec", "")
}
func printStderr(args ...interface{}) (int, error) {
return fmt.Fprint(os.Stderr, args...)
}
func runRun(cmd *Command, args []string) {
instrumentInit()
buildModeInit()
var b builder
b.init()
b.print = printStderr
func runRun(cmd *base.Command, args []string) {
work.InstrumentInit()
work.BuildModeInit()
var b work.Builder
b.Init()
b.Print = printStderr
i := 0
for i < len(args) && strings.HasSuffix(args[i], ".go") {
i++
}
files, cmdArgs := args[:i], args[i:]
if len(files) == 0 {
fatalf("go run: no go files listed")
base.Fatalf("go run: no go files listed")
}
for _, file := range files {
if strings.HasSuffix(file, "_test.go") {
// goFilesPackage is going to assign this to TestGoFiles.
// GoFilesPackage is going to assign this to TestGoFiles.
// Reject since it won't be part of the build.
fatalf("go run: cannot run *_test.go files (%s)", file)
base.Fatalf("go run: cannot run *_test.go files (%s)", file)
}
}
p := goFilesPackage(files)
p := load.GoFilesPackage(files)
if p.Error != nil {
fatalf("%s", p.Error)
base.Fatalf("%s", p.Error)
}
p.omitDWARF = true
p.Internal.OmitDebug = true
if len(p.DepsErrors) > 0 {
// Since these are errors in dependencies,
// the same error might show up multiple times,
// once in each package that depends on it.
// Only print each once.
printed := map[*PackageError]bool{}
printed := map[*load.PackageError]bool{}
for _, err := range p.DepsErrors {
if !printed[err] {
printed[err] = true
errorf("%s", err)
base.Errorf("%s", err)
}
}
}
exitIfErrors()
base.ExitIfErrors()
if p.Name != "main" {
fatalf("go run: cannot run non-main package")
base.Fatalf("go run: cannot run non-main package")
}
p.target = "" // must build - not up to date
p.Internal.Target = "" // must build - not up to date
var src string
if len(p.GoFiles) > 0 {
src = p.GoFiles[0]
@ -116,41 +104,28 @@ func runRun(cmd *Command, args []string) {
// this case could only happen if the provided source uses cgo
// while cgo is disabled.
hint := ""
if !buildContext.CgoEnabled {
if !cfg.BuildContext.CgoEnabled {
hint = " (cgo is disabled)"
}
fatalf("go run: no suitable source files%s", hint)
base.Fatalf("go run: no suitable source files%s", hint)
}
p.exeName = src[:len(src)-len(".go")] // name temporary executable for first go file
a1 := b.action(modeBuild, modeBuild, p)
a := &action{f: (*builder).runProgram, args: cmdArgs, deps: []*action{a1}}
b.do(a)
p.Internal.ExeName = src[:len(src)-len(".go")] // name temporary executable for first go file
a1 := b.Action(work.ModeBuild, work.ModeBuild, p)
a := &work.Action{Func: buildRunProgram, Args: cmdArgs, Deps: []*work.Action{a1}}
b.Do(a)
}
// runProgram is the action for running a binary that has already
// buildRunProgram is the action for running a binary that has already
// been compiled. We ignore exit status.
func (b *builder) runProgram(a *action) error {
cmdline := stringList(findExecCmd(), a.deps[0].target, a.args)
if buildN || buildX {
b.showcmd("", "%s", strings.Join(cmdline, " "))
if buildN {
func buildRunProgram(b *work.Builder, a *work.Action) error {
cmdline := str.StringList(work.FindExecCmd(), a.Deps[0].Target, a.Args)
if cfg.BuildN || cfg.BuildX {
b.Showcmd("", "%s", strings.Join(cmdline, " "))
if cfg.BuildN {
return nil
}
}
runStdin(cmdline)
base.RunStdin(cmdline)
return nil
}
// runStdin is like run, but connects Stdin.
func runStdin(cmdline []string) {
cmd := exec.Command(cmdline[0], cmdline[1:]...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Env = origEnv
startSigHandlers()
if err := cmd.Run(); err != nil {
errorf("%v", err)
}
}

View File

@ -0,0 +1,141 @@
// Copyright 2017 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 str provides string manipulation utilities.
package str
import (
"bytes"
"fmt"
"unicode"
"unicode/utf8"
)
// StringList flattens its arguments into a single []string.
// Each argument in args must have type string or []string.
func StringList(args ...interface{}) []string {
var x []string
for _, arg := range args {
switch arg := arg.(type) {
case []string:
x = append(x, arg...)
case string:
x = append(x, arg)
default:
panic("stringList: invalid argument of type " + fmt.Sprintf("%T", arg))
}
}
return x
}
// ToFold returns a string with the property that
// strings.EqualFold(s, t) iff ToFold(s) == ToFold(t)
// This lets us test a large set of strings for fold-equivalent
// duplicates without making a quadratic number of calls
// to EqualFold. Note that strings.ToUpper and strings.ToLower
// do not have the desired property in some corner cases.
func ToFold(s string) string {
// Fast path: all ASCII, no upper case.
// Most paths look like this already.
for i := 0; i < len(s); i++ {
c := s[i]
if c >= utf8.RuneSelf || 'A' <= c && c <= 'Z' {
goto Slow
}
}
return s
Slow:
var buf bytes.Buffer
for _, r := range s {
// SimpleFold(x) cycles to the next equivalent rune > x
// or wraps around to smaller values. Iterate until it wraps,
// and we've found the minimum value.
for {
r0 := r
r = unicode.SimpleFold(r0)
if r <= r0 {
break
}
}
// Exception to allow fast path above: A-Z => a-z
if 'A' <= r && r <= 'Z' {
r += 'a' - 'A'
}
buf.WriteRune(r)
}
return buf.String()
}
// FoldDup reports a pair of strings from the list that are
// equal according to strings.EqualFold.
// It returns "", "" if there are no such strings.
func FoldDup(list []string) (string, string) {
clash := map[string]string{}
for _, s := range list {
fold := ToFold(s)
if t := clash[fold]; t != "" {
if s > t {
s, t = t, s
}
return s, t
}
clash[fold] = s
}
return "", ""
}
// Contains reports whether x contains s.
func Contains(x []string, s string) bool {
for _, t := range x {
if t == s {
return true
}
}
return false
}
func isSpaceByte(c byte) bool {
return c == ' ' || c == '\t' || c == '\n' || c == '\r'
}
// SplitQuotedFields splits s into a list of fields,
// allowing single or double quotes around elements.
// There is no unescaping or other processing within
// quoted fields.
func SplitQuotedFields(s string) ([]string, error) {
// Split fields allowing '' or "" around elements.
// Quotes further inside the string do not count.
var f []string
for len(s) > 0 {
for len(s) > 0 && isSpaceByte(s[0]) {
s = s[1:]
}
if len(s) == 0 {
break
}
// Accepted quoted string. No unescaping inside.
if s[0] == '"' || s[0] == '\'' {
quote := s[0]
s = s[1:]
i := 0
for i < len(s) && s[i] != quote {
i++
}
if i >= len(s) {
return nil, fmt.Errorf("unterminated %c string", quote)
}
f = append(f, s[:i])
s = s[i+1:]
continue
}
i := 0
for i < len(s) && !isSpaceByte(s[i]) {
i++
}
f = append(f, s[:i])
s = s[i:]
}
return f, nil
}

View File

@ -0,0 +1,211 @@
// Copyright 2011 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 test
import (
"flag"
"os"
"strings"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/cmdflag"
"cmd/go/internal/str"
"cmd/go/internal/work"
)
const cmd = "test"
// The flag handling part of go test is large and distracting.
// We can't use the flag package because some of the flags from
// our command line are for us, and some are for 6.out, and
// some are for both.
// testFlagDefn is the set of flags we process.
var testFlagDefn = []*cmdflag.Defn{
// local.
{Name: "c", BoolVar: &testC},
{Name: "i", BoolVar: &cfg.BuildI},
{Name: "o"},
{Name: "cover", BoolVar: &testCover},
{Name: "covermode"},
{Name: "coverpkg"},
{Name: "exec"},
// Passed to 6.out, adding a "test." prefix to the name if necessary: -v becomes -test.v.
{Name: "bench", PassToTest: true},
{Name: "benchmem", BoolVar: new(bool), PassToTest: true},
{Name: "benchtime", PassToTest: true},
{Name: "count", PassToTest: true},
{Name: "coverprofile", PassToTest: true},
{Name: "cpu", PassToTest: true},
{Name: "cpuprofile", PassToTest: true},
{Name: "list", PassToTest: true},
{Name: "memprofile", PassToTest: true},
{Name: "memprofilerate", PassToTest: true},
{Name: "blockprofile", PassToTest: true},
{Name: "blockprofilerate", PassToTest: true},
{Name: "mutexprofile", PassToTest: true},
{Name: "mutexprofilefraction", PassToTest: true},
{Name: "outputdir", PassToTest: true},
{Name: "parallel", PassToTest: true},
{Name: "run", PassToTest: true},
{Name: "short", BoolVar: new(bool), PassToTest: true},
{Name: "timeout", PassToTest: true},
{Name: "trace", PassToTest: true},
{Name: "v", BoolVar: &testV, PassToTest: true},
}
// add build flags to testFlagDefn
func init() {
var cmd base.Command
work.AddBuildFlags(&cmd)
cmd.Flag.VisitAll(func(f *flag.Flag) {
if f.Name == "v" {
// test overrides the build -v flag
return
}
testFlagDefn = append(testFlagDefn, &cmdflag.Defn{
Name: f.Name,
Value: f.Value,
})
})
}
// testFlags processes the command line, grabbing -x and -c, rewriting known flags
// to have "test" before them, and reading the command line for the 6.out.
// Unfortunately for us, we need to do our own flag processing because go test
// grabs some flags but otherwise its command line is just a holding place for
// pkg.test's arguments.
// We allow known flags both before and after the package name list,
// to allow both
// go test fmt -custom-flag-for-fmt-test
// go test -x math
func testFlags(args []string) (packageNames, passToTest []string) {
inPkg := false
outputDir := ""
var explicitArgs []string
for i := 0; i < len(args); i++ {
if !strings.HasPrefix(args[i], "-") {
if !inPkg && packageNames == nil {
// First package name we've seen.
inPkg = true
}
if inPkg {
packageNames = append(packageNames, args[i])
continue
}
}
if inPkg {
// Found an argument beginning with "-"; end of package list.
inPkg = false
}
f, value, extraWord := cmdflag.Parse(cmd, testFlagDefn, args, i)
if f == nil {
// This is a flag we do not know; we must assume
// that any args we see after this might be flag
// arguments, not package names.
inPkg = false
if packageNames == nil {
// make non-nil: we have seen the empty package list
packageNames = []string{}
}
if args[i] == "-args" || args[i] == "--args" {
// -args or --args signals that everything that follows
// should be passed to the test.
explicitArgs = args[i+1:]
break
}
passToTest = append(passToTest, args[i])
continue
}
if f.Value != nil {
if err := f.Value.Set(value); err != nil {
base.Fatalf("invalid flag argument for -%s: %v", f.Name, err)
}
} else {
// Test-only flags.
// Arguably should be handled by f.Value, but aren't.
switch f.Name {
// bool flags.
case "c", "i", "v", "cover":
cmdflag.SetBool(cmd, f.BoolVar, value)
case "o":
testO = value
testNeedBinary = true
case "exec":
xcmd, err := str.SplitQuotedFields(value)
if err != nil {
base.Fatalf("invalid flag argument for -%s: %v", f.Name, err)
}
work.ExecCmd = xcmd
case "bench":
// record that we saw the flag; don't care about the value
testBench = true
case "list":
testList = true
case "timeout":
testTimeout = value
case "blockprofile", "cpuprofile", "memprofile", "mutexprofile":
testProfile = true
testNeedBinary = true
case "trace":
testProfile = true
case "coverpkg":
testCover = true
if value == "" {
testCoverPaths = nil
} else {
testCoverPaths = strings.Split(value, ",")
}
case "coverprofile":
testCover = true
testProfile = true
case "covermode":
switch value {
case "set", "count", "atomic":
testCoverMode = value
default:
base.Fatalf("invalid flag argument for -covermode: %q", value)
}
testCover = true
case "outputdir":
outputDir = value
}
}
if extraWord {
i++
}
if f.PassToTest {
passToTest = append(passToTest, "-test."+f.Name+"="+value)
}
}
if testCoverMode == "" {
testCoverMode = "set"
if cfg.BuildRace {
// Default coverage mode is atomic when -race is set.
testCoverMode = "atomic"
}
}
if cfg.BuildRace && testCoverMode != "atomic" {
base.Fatalf(`-covermode must be "atomic", not %q, when -race is enabled`, testCoverMode)
}
// Tell the test what directory we're running in, so it can write the profiles there.
if testProfile && outputDir == "" {
dir, err := os.Getwd()
if err != nil {
base.Fatalf("error from os.Getwd: %s", err)
}
passToTest = append(passToTest, "-test.outputdir", dir)
}
passToTest = append(passToTest, explicitArgs...)
return
}

View File

@ -2,20 +2,21 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
// Package tool implements the ``go tool'' command.
package tool
import (
"fmt"
"go/build"
"os"
"os/exec"
"path/filepath"
"runtime"
"sort"
"strings"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
)
var cmdTool = &Command{
var CmdTool = &base.Command{
Run: runTool,
UsageLine: "tool [-n] command [args...]",
Short: "run specified go tool",
@ -30,53 +31,24 @@ For more about each tool command, see 'go tool command -h'.
`,
}
var (
toolGOOS = runtime.GOOS
toolGOARCH = runtime.GOARCH
toolIsWindows = toolGOOS == "windows"
toolDir = build.ToolDir
var toolN bool
toolN bool
)
// List of go tools found in the gccgo tool directory.
// Return whether tool can be expected in the gccgo tool directory.
// Other binaries could be in the same directory so don't
// show those with the 'go tool' command.
var gccgoTools = []string{"cgo", "fix", "cover", "godoc", "vet"}
func init() {
cmdTool.Flag.BoolVar(&toolN, "n", false, "")
}
const toolWindowsExtension = ".exe"
func tool(toolName string) string {
toolPath := filepath.Join(toolDir, toolName)
if toolIsWindows {
toolPath += toolWindowsExtension
func isGccgoTool(tool string) bool {
switch tool {
case "cgo", "fix", "cover", "godoc", "vet":
return true
}
if len(buildToolExec) > 0 {
return toolPath
}
// Give a nice message if there is no tool with that name.
if _, err := os.Stat(toolPath); err != nil {
if isInGoToolsRepo(toolName) {
fmt.Fprintf(os.Stderr, "go tool: no such tool %q; to install:\n\tgo get golang.org/x/tools/cmd/%s\n", toolName, toolName)
} else {
fmt.Fprintf(os.Stderr, "go tool: no such tool %q\n", toolName)
}
setExitStatus(2)
exit()
}
return toolPath
}
func isInGoToolsRepo(toolName string) bool {
return false
}
func runTool(cmd *Command, args []string) {
func init() {
CmdTool.Flag.BoolVar(&toolN, "n", false, "")
}
func runTool(cmd *base.Command, args []string) {
if len(args) == 0 {
listTools()
return
@ -88,11 +60,11 @@ func runTool(cmd *Command, args []string) {
case 'a' <= c && c <= 'z', '0' <= c && c <= '9', c == '_':
default:
fmt.Fprintf(os.Stderr, "go tool: bad tool name %q\n", toolName)
setExitStatus(2)
base.SetExitStatus(2)
return
}
}
toolPath := tool(toolName)
toolPath := base.Tool(toolName)
if toolPath == "" {
return
}
@ -112,7 +84,7 @@ func runTool(cmd *Command, args []string) {
Stdout: os.Stdout,
Stderr: os.Stderr,
// Set $GOROOT, mainly for go tool dist.
Env: mergeEnvLists([]string{"GOROOT=" + goroot}, os.Environ()),
Env: base.MergeEnvLists([]string{"GOROOT=" + cfg.GOROOT}, os.Environ()),
}
err := toolCmd.Run()
if err != nil {
@ -121,27 +93,27 @@ func runTool(cmd *Command, args []string) {
// or we're printing command lines too (-x mode).
// Assume if command exited cleanly (even with non-zero status)
// it printed any messages it wanted to print.
if e, ok := err.(*exec.ExitError); !ok || !e.Exited() || buildX {
if e, ok := err.(*exec.ExitError); !ok || !e.Exited() || cfg.BuildX {
fmt.Fprintf(os.Stderr, "go tool %s: %s\n", toolName, err)
}
setExitStatus(1)
base.SetExitStatus(1)
return
}
}
// listTools prints a list of the available tools in the tools directory.
func listTools() {
f, err := os.Open(toolDir)
f, err := os.Open(base.ToolDir)
if err != nil {
fmt.Fprintf(os.Stderr, "go tool: no tool directory: %s\n", err)
setExitStatus(2)
base.SetExitStatus(2)
return
}
defer f.Close()
names, err := f.Readdirnames(-1)
if err != nil {
fmt.Fprintf(os.Stderr, "go tool: can't read directory: %s\n", err)
setExitStatus(2)
base.SetExitStatus(2)
return
}
@ -150,24 +122,14 @@ func listTools() {
// Unify presentation by going to lower case.
name = strings.ToLower(name)
// If it's windows, don't show the .exe suffix.
if toolIsWindows && strings.HasSuffix(name, toolWindowsExtension) {
name = name[:len(name)-len(toolWindowsExtension)]
if base.ToolIsWindows && strings.HasSuffix(name, base.ToolWindowsExtension) {
name = name[:len(name)-len(base.ToolWindowsExtension)]
}
// The tool directory used by gccgo will have other binaries
// in additions to go tools. Only display go tools for this list.
if buildContext.Compiler == "gccgo" {
for _, tool := range gccgoTools {
if tool == name {
fmt.Println(name)
}
}
} else {
// Not gccgo, list all the tools found in this dir
fmt.Println(name)
// in addition to go tools. Only display go tools here.
if cfg.BuildToolchainName == "gccgo" && !isGccgoTool(name) {
continue
}
fmt.Println(name)
}
}

View File

@ -2,21 +2,24 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
// Package version implements the ``go version'' command.
package version
import (
"fmt"
"runtime"
"cmd/go/internal/base"
)
var cmdVersion = &Command{
var CmdVersion = &base.Command{
Run: runVersion,
UsageLine: "version",
Short: "print Go version",
Long: `Version prints the Go version, as reported by runtime.Version.`,
}
func runVersion(cmd *Command, args []string) {
func runVersion(cmd *base.Command, args []string) {
if len(args) != 0 {
cmd.Usage()
}

View File

@ -0,0 +1,56 @@
// Copyright 2011 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 vet implements the ``go vet'' command.
package vet
import (
"path/filepath"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/str"
)
var CmdVet = &base.Command{
Run: runVet,
CustomFlags: true,
UsageLine: "vet [-n] [-x] [build flags] [vet flags] [packages]",
Short: "run go tool vet on packages",
Long: `
Vet runs the Go vet command on the packages named by the import paths.
For more about vet and its flags, see 'go doc cmd/vet'.
For more about specifying packages, see 'go help packages'.
The -n flag prints commands that would be executed.
The -x flag prints commands as they are executed.
For more about build flags, see 'go help build'.
See also: go fmt, go fix.
`,
}
func runVet(cmd *base.Command, args []string) {
vetFlags, packages := vetFlags(args)
for _, p := range load.Packages(packages) {
// Vet expects to be given a set of files all from the same package.
// Run once for package p and once for package p_test.
if len(p.GoFiles)+len(p.CgoFiles)+len(p.TestGoFiles) > 0 {
runVetFiles(p, vetFlags, str.StringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.SFiles))
}
if len(p.XTestGoFiles) > 0 {
runVetFiles(p, vetFlags, str.StringList(p.XTestGoFiles))
}
}
}
func runVetFiles(p *load.Package, flags, files []string) {
for i := range files {
files[i] = filepath.Join(p.Dir, files[i])
}
base.Run(cfg.BuildToolexec, base.Tool("vet"), flags, base.RelPaths(files))
}

View File

@ -0,0 +1,99 @@
// Copyright 2017 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 vet
import (
"flag"
"fmt"
"os"
"strings"
"cmd/go/internal/base"
"cmd/go/internal/cmdflag"
"cmd/go/internal/work"
)
const cmd = "vet"
// vetFlagDefn is the set of flags we process.
var vetFlagDefn = []*cmdflag.Defn{
// Note: Some flags, in particular -tags and -v, are known to
// vet but also defined as build flags. This works fine, so we
// don't define them here but use AddBuildFlags to init them.
// However some, like -x, are known to the build but not
// to vet. We handle them in vetFlags.
// local.
{Name: "all", BoolVar: new(bool)},
{Name: "asmdecl", BoolVar: new(bool)},
{Name: "assign", BoolVar: new(bool)},
{Name: "atomic", BoolVar: new(bool)},
{Name: "bool", BoolVar: new(bool)},
{Name: "buildtags", BoolVar: new(bool)},
{Name: "cgocall", BoolVar: new(bool)},
{Name: "composites", BoolVar: new(bool)},
{Name: "copylocks", BoolVar: new(bool)},
{Name: "httpresponse", BoolVar: new(bool)},
{Name: "lostcancel", BoolVar: new(bool)},
{Name: "methods", BoolVar: new(bool)},
{Name: "nilfunc", BoolVar: new(bool)},
{Name: "printf", BoolVar: new(bool)},
{Name: "printfuncs"},
{Name: "rangeloops", BoolVar: new(bool)},
{Name: "shadow", BoolVar: new(bool)},
{Name: "shadowstrict", BoolVar: new(bool)},
{Name: "source", BoolVar: new(bool)},
{Name: "structtags", BoolVar: new(bool)},
{Name: "tests", BoolVar: new(bool)},
{Name: "unreachable", BoolVar: new(bool)},
{Name: "unsafeptr", BoolVar: new(bool)},
{Name: "unusedfuncs"},
{Name: "unusedresult", BoolVar: new(bool)},
{Name: "unusedstringmethods"},
}
// add build flags to vetFlagDefn.
func init() {
var cmd base.Command
work.AddBuildFlags(&cmd)
cmd.Flag.VisitAll(func(f *flag.Flag) {
vetFlagDefn = append(vetFlagDefn, &cmdflag.Defn{
Name: f.Name,
Value: f.Value,
})
})
}
// vetFlags processes the command line, splitting it at the first non-flag
// into the list of flags and list of packages.
func vetFlags(args []string) (passToVet, packageNames []string) {
for i := 0; i < len(args); i++ {
if !strings.HasPrefix(args[i], "-") {
return args[:i], args[i:]
}
f, value, extraWord := cmdflag.Parse(cmd, vetFlagDefn, args, i)
if f == nil {
fmt.Fprintf(os.Stderr, "vet: flag %q not defined\n", args[i])
fmt.Fprintf(os.Stderr, "Run \"go help vet\" for more information\n")
os.Exit(2)
}
if f.Value != nil {
if err := f.Value.Set(value); err != nil {
base.Fatalf("invalid flag argument for -%s: %v", f.Name, err)
}
switch f.Name {
// Flags known to the build but not to vet, so must be dropped.
case "x", "n":
args = append(args[:i], args[i+1:]...)
i--
}
}
if extraWord {
i++
}
}
return args, nil
}

View File

@ -8,7 +8,7 @@
// These stubs avoid importing packages with large dependency
// trees, like the use of "net/http" in vcs.go.
package main
package web
import (
"errors"
@ -17,25 +17,21 @@ import (
var errHTTP = errors.New("no http in bootstrap go command")
type httpError struct {
statusCode int
type HTTPError struct {
StatusCode int
}
func (e *httpError) Error() string {
func (e *HTTPError) Error() string {
panic("unreachable")
}
func httpGET(url string) ([]byte, error) {
func Get(url string) ([]byte, error) {
return nil, errHTTP
}
func httpsOrHTTP(importPath string, security securityMode) (string, io.ReadCloser, error) {
func GetMaybeInsecure(importPath string, security SecurityMode) (string, io.ReadCloser, error) {
return "", nil, errHTTP
}
func parseMetaGoImports(r io.Reader) ([]metaImport, error) {
panic("unreachable")
}
func queryEscape(s string) string { panic("unreachable") }
func openBrowser(url string) bool { panic("unreachable") }
func QueryEscape(s string) string { panic("unreachable") }
func OpenBrowser(url string) bool { panic("unreachable") }

View File

@ -9,10 +9,9 @@
// to avoid needing to build net (and thus use cgo) during the
// bootstrap process.
package main
package web
import (
"cmd/internal/browser"
"crypto/tls"
"fmt"
"io"
@ -21,6 +20,9 @@ import (
"net/http"
"net/url"
"time"
"cmd/go/internal/cfg"
"cmd/internal/browser"
)
// httpClient is the default HTTP client, but a variable so it can be
@ -40,25 +42,25 @@ var impatientInsecureHTTPClient = &http.Client{
},
}
type httpError struct {
type HTTPError struct {
status string
statusCode int
StatusCode int
url string
}
func (e *httpError) Error() string {
func (e *HTTPError) Error() string {
return fmt.Sprintf("%s: %s", e.url, e.status)
}
// httpGET returns the data from an HTTP GET request for the given URL.
func httpGET(url string) ([]byte, error) {
// Get returns the data from an HTTP GET request for the given URL.
func Get(url string) ([]byte, error) {
resp, err := httpClient.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
err := &httpError{status: resp.Status, statusCode: resp.StatusCode, url: url}
err := &HTTPError{status: resp.Status, StatusCode: resp.StatusCode, url: url}
return nil, err
}
@ -69,9 +71,9 @@ func httpGET(url string) ([]byte, error) {
return b, nil
}
// httpsOrHTTP returns the body of either the importPath's
// https resource or, if unavailable, the http resource.
func httpsOrHTTP(importPath string, security securityMode) (urlStr string, body io.ReadCloser, err error) {
// GetMaybeInsecure returns the body of either the importPath's
// https resource or, if unavailable and permitted by the security mode, the http resource.
func GetMaybeInsecure(importPath string, security SecurityMode) (urlStr string, body io.ReadCloser, err error) {
fetch := func(scheme string) (urlStr string, res *http.Response, err error) {
u, err := url.Parse(scheme + "://" + importPath)
if err != nil {
@ -79,10 +81,10 @@ func httpsOrHTTP(importPath string, security securityMode) (urlStr string, body
}
u.RawQuery = "go-get=1"
urlStr = u.String()
if buildV {
if cfg.BuildV {
log.Printf("Fetching %s", urlStr)
}
if security == insecure && scheme == "https" { // fail earlier
if security == Insecure && scheme == "https" { // fail earlier
res, err = impatientInsecureHTTPClient.Get(urlStr)
} else {
res, err = httpClient.Get(urlStr)
@ -96,10 +98,10 @@ func httpsOrHTTP(importPath string, security securityMode) (urlStr string, body
}
urlStr, res, err := fetch("https")
if err != nil {
if buildV {
if cfg.BuildV {
log.Printf("https fetch failed: %v", err)
}
if security == insecure {
if security == Insecure {
closeBody(res)
urlStr, res, err = fetch("http")
}
@ -110,11 +112,11 @@ func httpsOrHTTP(importPath string, security securityMode) (urlStr string, body
}
// Note: accepting a non-200 OK here, so people can serve a
// meta import in their http 404 page.
if buildV {
if cfg.BuildV {
log.Printf("Parsing meta tags from %s (status code %d)", urlStr, res.StatusCode)
}
return urlStr, res.Body, nil
}
func queryEscape(s string) string { return url.QueryEscape(s) }
func openBrowser(url string) bool { return browser.Open(url) }
func QueryEscape(s string) string { return url.QueryEscape(s) }
func OpenBrowser(url string) bool { return browser.Open(url) }

View File

@ -0,0 +1,16 @@
// Copyright 2017 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 web defines helper routines for accessing HTTP/HTTPS resources.
package web
// SecurityMode specifies whether a function should make network
// calls using insecure transports (eg, plain text HTTP).
// The zero value is "secure".
type SecurityMode int
const (
Secure SecurityMode = iota
Insecure
)

View File

@ -0,0 +1,227 @@
// Copyright 2016 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 work
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"reflect"
"runtime"
"strings"
"testing"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
)
func TestRemoveDevNull(t *testing.T) {
fi, err := os.Lstat(os.DevNull)
if err != nil {
t.Skip(err)
}
if fi.Mode().IsRegular() {
t.Errorf("Lstat(%s).Mode().IsRegular() = true; expected false", os.DevNull)
}
mayberemovefile(os.DevNull)
_, err = os.Lstat(os.DevNull)
if err != nil {
t.Errorf("mayberemovefile(%s) did remove it; oops", os.DevNull)
}
}
func TestSplitPkgConfigOutput(t *testing.T) {
for _, test := range []struct {
in []byte
want []string
}{
{[]byte(`-r:foo -L/usr/white\ space/lib -lfoo\ bar -lbar\ baz`), []string{"-r:foo", "-L/usr/white space/lib", "-lfoo bar", "-lbar baz"}},
{[]byte(`-lextra\ fun\ arg\\`), []string{`-lextra fun arg\`}},
{[]byte(`broken flag\`), []string{"broken", "flag"}},
{[]byte("\textra whitespace\r\n"), []string{"extra", "whitespace"}},
{[]byte(" \r\n "), nil},
} {
got := splitPkgConfigOutput(test.in)
if !reflect.DeepEqual(got, test.want) {
t.Errorf("splitPkgConfigOutput(%v) = %v; want %v", test.in, got, test.want)
}
}
}
func TestSharedLibName(t *testing.T) {
// TODO(avdva) - make these values platform-specific
prefix := "lib"
suffix := ".so"
testData := []struct {
args []string
pkgs []*load.Package
expected string
expectErr bool
rootedAt string
}{
{
args: []string{"std"},
pkgs: []*load.Package{},
expected: "std",
},
{
args: []string{"std", "cmd"},
pkgs: []*load.Package{},
expected: "std,cmd",
},
{
args: []string{},
pkgs: []*load.Package{pkgImportPath("gopkg.in/somelib")},
expected: "gopkg.in-somelib",
},
{
args: []string{"./..."},
pkgs: []*load.Package{pkgImportPath("somelib")},
expected: "somelib",
rootedAt: "somelib",
},
{
args: []string{"../somelib", "../somelib"},
pkgs: []*load.Package{pkgImportPath("somelib")},
expected: "somelib",
},
{
args: []string{"../lib1", "../lib2"},
pkgs: []*load.Package{pkgImportPath("gopkg.in/lib1"), pkgImportPath("gopkg.in/lib2")},
expected: "gopkg.in-lib1,gopkg.in-lib2",
},
{
args: []string{"./..."},
pkgs: []*load.Package{
pkgImportPath("gopkg.in/dir/lib1"),
pkgImportPath("gopkg.in/lib2"),
pkgImportPath("gopkg.in/lib3"),
},
expected: "gopkg.in",
rootedAt: "gopkg.in",
},
{
args: []string{"std", "../lib2"},
pkgs: []*load.Package{},
expectErr: true,
},
{
args: []string{"all", "./"},
pkgs: []*load.Package{},
expectErr: true,
},
{
args: []string{"cmd", "fmt"},
pkgs: []*load.Package{},
expectErr: true,
},
}
for _, data := range testData {
func() {
if data.rootedAt != "" {
tmpGopath, err := ioutil.TempDir("", "gopath")
if err != nil {
t.Fatal(err)
}
oldGopath := cfg.BuildContext.GOPATH
defer func() {
cfg.BuildContext.GOPATH = oldGopath
os.Chdir(base.Cwd)
err := os.RemoveAll(tmpGopath)
if err != nil {
t.Error(err)
}
}()
root := filepath.Join(tmpGopath, "src", data.rootedAt)
err = os.MkdirAll(root, 0755)
if err != nil {
t.Fatal(err)
}
cfg.BuildContext.GOPATH = tmpGopath
os.Chdir(root)
}
computed, err := libname(data.args, data.pkgs)
if err != nil {
if !data.expectErr {
t.Errorf("libname returned an error %q, expected a name", err.Error())
}
} else if data.expectErr {
t.Errorf("libname returned %q, expected an error", computed)
} else {
expected := prefix + data.expected + suffix
if expected != computed {
t.Errorf("libname returned %q, expected %q", computed, expected)
}
}
}()
}
}
func pkgImportPath(pkgpath string) *load.Package {
return &load.Package{
PackagePublic: load.PackagePublic{
ImportPath: pkgpath,
},
}
}
// When installing packages, the installed package directory should
// respect the SetGID bit and group name of the destination
// directory.
// See https://golang.org/issue/18878.
func TestRespectSetgidDir(t *testing.T) {
if runtime.GOOS == "nacl" {
t.Skip("can't set SetGID bit with chmod on nacl")
}
var b Builder
// Check that `cp` is called instead of `mv` by looking at the output
// of `(*Builder).ShowCmd` afterwards as a sanity check.
cfg.BuildX = true
var cmdBuf bytes.Buffer
b.Print = func(a ...interface{}) (int, error) {
return cmdBuf.WriteString(fmt.Sprint(a...))
}
setgiddir, err := ioutil.TempDir("", "SetGroupID")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(setgiddir)
if runtime.GOOS == "freebsd" {
err = os.Chown(setgiddir, os.Getuid(), os.Getgid())
if err != nil {
t.Fatal(err)
}
}
// Change setgiddir's permissions to include the SetGID bit.
if err := os.Chmod(setgiddir, 0755|os.ModeSetgid); err != nil {
t.Fatal(err)
}
pkgfile, err := ioutil.TempFile("", "pkgfile")
if err != nil {
t.Fatalf("ioutil.TempFile(\"\", \"pkgfile\"): %v", err)
}
defer os.Remove(pkgfile.Name())
defer pkgfile.Close()
dirGIDFile := filepath.Join(setgiddir, "setgid")
if err := b.moveOrCopyFile(nil, dirGIDFile, pkgfile.Name(), 0666, true); err != nil {
t.Fatalf("moveOrCopyFile: %v", err)
}
got := strings.TrimSpace(cmdBuf.String())
want := b.fmtcmd("", "cp %s %s", pkgfile.Name(), dirGIDFile)
if got != want {
t.Fatalf("moveOrCopyFile(%q, %q): want %q, got %q", dirGIDFile, pkgfile.Name(), want, got)
}
}

View File

@ -0,0 +1,17 @@
// Copyright 2017 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.
// This file contains extra hooks for testing the go command.
// +build testgo
package work
import "os"
func init() {
if v := os.Getenv("TESTGO_VERSION"); v != "" {
runtimeVersion = v
}
}

View File

@ -2,141 +2,90 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:generate ./mkalldocs.sh
package main
import (
"bufio"
"bytes"
"flag"
"fmt"
"go/build"
"io"
"log"
"os"
"os/exec"
"path"
"path/filepath"
"regexp"
"runtime"
"strings"
"sync"
"text/template"
"unicode"
"unicode/utf8"
"cmd/go/internal/base"
"cmd/go/internal/bug"
"cmd/go/internal/cfg"
"cmd/go/internal/clean"
"cmd/go/internal/doc"
"cmd/go/internal/envcmd"
"cmd/go/internal/fix"
"cmd/go/internal/fmtcmd"
"cmd/go/internal/generate"
"cmd/go/internal/get"
"cmd/go/internal/help"
"cmd/go/internal/list"
"cmd/go/internal/run"
"cmd/go/internal/test"
"cmd/go/internal/tool"
"cmd/go/internal/version"
"cmd/go/internal/vet"
"cmd/go/internal/work"
)
// A Command is an implementation of a go command
// like go build or go fix.
type Command struct {
// Run runs the command.
// The args are the arguments after the command name.
Run func(cmd *Command, args []string)
func init() {
base.Commands = []*base.Command{
work.CmdBuild,
clean.CmdClean,
doc.CmdDoc,
envcmd.CmdEnv,
bug.CmdBug,
fix.CmdFix,
fmtcmd.CmdFmt,
generate.CmdGenerate,
get.CmdGet,
work.CmdInstall,
list.CmdList,
run.CmdRun,
test.CmdTest,
tool.CmdTool,
version.CmdVersion,
vet.CmdVet,
// UsageLine is the one-line usage message.
// The first word in the line is taken to be the command name.
UsageLine string
// Short is the short description shown in the 'go help' output.
Short string
// Long is the long message shown in the 'go help <this-command>' output.
Long string
// Flag is a set of flags specific to this command.
Flag flag.FlagSet
// CustomFlags indicates that the command will do its own
// flag parsing.
CustomFlags bool
}
// Name returns the command's name: the first word in the usage line.
func (c *Command) Name() string {
name := c.UsageLine
i := strings.Index(name, " ")
if i >= 0 {
name = name[:i]
help.HelpC,
help.HelpBuildmode,
help.HelpFileType,
help.HelpGopath,
help.HelpEnvironment,
help.HelpImportPath,
help.HelpPackages,
test.HelpTestflag,
test.HelpTestfunc,
}
return name
}
func (c *Command) Usage() {
fmt.Fprintf(os.Stderr, "usage: %s\n\n", c.UsageLine)
fmt.Fprintf(os.Stderr, "%s\n", strings.TrimSpace(c.Long))
os.Exit(2)
}
// Runnable reports whether the command can be run; otherwise
// it is a documentation pseudo-command such as importpath.
func (c *Command) Runnable() bool {
return c.Run != nil
}
// Commands lists the available commands and help topics.
// The order here is the order in which they are printed by 'go help'.
var commands = []*Command{
cmdBuild,
cmdClean,
cmdDoc,
cmdEnv,
cmdBug,
cmdFix,
cmdFmt,
cmdGenerate,
cmdGet,
cmdInstall,
cmdList,
cmdRun,
cmdTest,
cmdTool,
cmdVersion,
cmdVet,
helpC,
helpBuildmode,
helpFileType,
helpGopath,
helpEnvironment,
helpImportPath,
helpPackages,
helpTestflag,
helpTestfunc,
}
var exitStatus = 0
var exitMu sync.Mutex
func setExitStatus(n int) {
exitMu.Lock()
if exitStatus < n {
exitStatus = n
}
exitMu.Unlock()
}
var origEnv []string
var newEnv []envVar
func main() {
_ = go11tag
flag.Usage = usage
flag.Usage = base.Usage
flag.Parse()
log.SetFlags(0)
args := flag.Args()
if len(args) < 1 {
usage()
base.Usage()
}
if args[0] == "help" {
help(args[1:])
help.Help(args[1:])
return
}
// Diagnose common mistake: GOPATH==GOROOT.
// This setting is equivalent to not setting GOPATH at all,
// which is not what most people want when they do it.
if gopath := buildContext.GOPATH; filepath.Clean(gopath) == filepath.Clean(runtime.GOROOT()) {
if gopath := cfg.BuildContext.GOPATH; filepath.Clean(gopath) == filepath.Clean(runtime.GOROOT()) {
fmt.Fprintf(os.Stderr, "warning: GOPATH set to GOROOT (%s) has no effect\n", gopath)
} else {
for _, p := range filepath.SplitList(gopath) {
@ -154,14 +103,12 @@ func main() {
}
}
if fi, err := os.Stat(goroot); err != nil || !fi.IsDir() {
// For gccgo this is fine, carry on.
// Note that this check is imperfect as we have not yet
// parsed the -compiler flag.
if runtime.Compiler != "gccgo" {
fmt.Fprintf(os.Stderr, "go: cannot find GOROOT directory: %v\n", goroot)
os.Exit(2)
}
// For gccgo this is fine, carry on.
// Note that this check is imperfect as we have not yet parsed
// the -compiler flag.
if fi, err := os.Stat(cfg.GOROOT); err != nil || !fi.IsDir() && runtime.Compiler != "gccgo" {
fmt.Fprintf(os.Stderr, "go: cannot find GOROOT directory: %v\n", cfg.GOROOT)
os.Exit(2)
}
// Set environment (GOOS, GOARCH, etc) explicitly.
@ -169,15 +116,15 @@ func main() {
// the same default computation of these as we do,
// but in practice there might be skew
// This makes sure we all agree.
origEnv = os.Environ()
newEnv = mkEnv()
for _, env := range newEnv {
if os.Getenv(env.name) != env.value {
os.Setenv(env.name, env.value)
cfg.OrigEnv = os.Environ()
cfg.CmdEnv = envcmd.MkEnv()
for _, env := range cfg.CmdEnv {
if os.Getenv(env.Name) != env.Value {
os.Setenv(env.Name, env.Value)
}
}
for _, cmd := range commands {
for _, cmd := range base.Commands {
if cmd.Name() == args[0] && cmd.Runnable() {
cmd.Flag.Usage = func() { cmd.Usage() }
if cmd.CustomFlags {
@ -187,615 +134,25 @@ func main() {
args = cmd.Flag.Args()
}
cmd.Run(cmd, args)
exit()
base.Exit()
return
}
}
fmt.Fprintf(os.Stderr, "go: unknown subcommand %q\nRun 'go help' for usage.\n", args[0])
setExitStatus(2)
exit()
base.SetExitStatus(2)
base.Exit()
}
var usageTemplate = `Go is a tool for managing Go source code.
Usage:
go command [arguments]
The commands are:
{{range .}}{{if .Runnable}}
{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
Use "go help [command]" for more information about a command.
Additional help topics:
{{range .}}{{if not .Runnable}}
{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
Use "go help [topic]" for more information about that topic.
`
var helpTemplate = `{{if .Runnable}}usage: go {{.UsageLine}}
{{end}}{{.Long | trim}}
`
var documentationTemplate = `{{range .}}{{if .Short}}{{.Short | capitalize}}
{{end}}{{if .Runnable}}Usage:
go {{.UsageLine}}
{{end}}{{.Long | trim}}
{{end}}`
// commentWriter writes a Go comment to the underlying io.Writer,
// using line comment form (//).
type commentWriter struct {
W io.Writer
wroteSlashes bool // Wrote "//" at the beginning of the current line.
func init() {
base.Usage = mainUsage
}
func (c *commentWriter) Write(p []byte) (int, error) {
var n int
for i, b := range p {
if !c.wroteSlashes {
s := "//"
if b != '\n' {
s = "// "
}
if _, err := io.WriteString(c.W, s); err != nil {
return n, err
}
c.wroteSlashes = true
}
n0, err := c.W.Write(p[i : i+1])
n += n0
if err != nil {
return n, err
}
if b == '\n' {
c.wroteSlashes = false
}
}
return len(p), nil
}
// An errWriter wraps a writer, recording whether a write error occurred.
type errWriter struct {
w io.Writer
err error
}
func (w *errWriter) Write(b []byte) (int, error) {
n, err := w.w.Write(b)
if err != nil {
w.err = err
}
return n, err
}
// tmpl executes the given template text on data, writing the result to w.
func tmpl(w io.Writer, text string, data interface{}) {
t := template.New("top")
t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize})
template.Must(t.Parse(text))
ew := &errWriter{w: w}
err := t.Execute(ew, data)
if ew.err != nil {
// I/O error writing. Ignore write on closed pipe.
if strings.Contains(ew.err.Error(), "pipe") {
os.Exit(1)
}
fatalf("writing output: %v", ew.err)
}
if err != nil {
panic(err)
}
}
func capitalize(s string) string {
if s == "" {
return s
}
r, n := utf8.DecodeRuneInString(s)
return string(unicode.ToTitle(r)) + s[n:]
}
func printUsage(w io.Writer) {
bw := bufio.NewWriter(w)
tmpl(bw, usageTemplate, commands)
bw.Flush()
}
func usage() {
func mainUsage() {
// special case "go test -h"
if len(os.Args) > 1 && os.Args[1] == "test" {
os.Stderr.WriteString(testUsage + "\n\n" +
strings.TrimSpace(testFlag1) + "\n\n\t" +
strings.TrimSpace(testFlag2) + "\n")
os.Exit(2)
test.Usage()
}
printUsage(os.Stderr)
help.PrintUsage(os.Stderr)
os.Exit(2)
}
// help implements the 'help' command.
func help(args []string) {
if len(args) == 0 {
printUsage(os.Stdout)
// not exit 2: succeeded at 'go help'.
return
}
if len(args) != 1 {
fmt.Fprintf(os.Stderr, "usage: go help command\n\nToo many arguments given.\n")
os.Exit(2) // failed at 'go help'
}
arg := args[0]
// 'go help documentation' generates doc.go.
if arg == "documentation" {
fmt.Println("// Copyright 2011 The Go Authors. All rights reserved.")
fmt.Println("// Use of this source code is governed by a BSD-style")
fmt.Println("// license that can be found in the LICENSE file.")
fmt.Println()
fmt.Println("// DO NOT EDIT THIS FILE. GENERATED BY mkalldocs.sh.")
fmt.Println("// Edit the documentation in other files and rerun mkalldocs.sh to generate this one.")
fmt.Println()
buf := new(bytes.Buffer)
printUsage(buf)
usage := &Command{Long: buf.String()}
tmpl(&commentWriter{W: os.Stdout}, documentationTemplate, append([]*Command{usage}, commands...))
fmt.Println("package main")
return
}
for _, cmd := range commands {
if cmd.Name() == arg {
tmpl(os.Stdout, helpTemplate, cmd)
// not exit 2: succeeded at 'go help cmd'.
return
}
}
fmt.Fprintf(os.Stderr, "Unknown help topic %#q. Run 'go help'.\n", arg)
os.Exit(2) // failed at 'go help cmd'
}
// importPathsNoDotExpansion returns the import paths to use for the given
// command line, but it does no ... expansion.
func importPathsNoDotExpansion(args []string) []string {
if len(args) == 0 {
return []string{"."}
}
var out []string
for _, a := range args {
// Arguments are supposed to be import paths, but
// as a courtesy to Windows developers, rewrite \ to /
// in command-line arguments. Handles .\... and so on.
if filepath.Separator == '\\' {
a = strings.Replace(a, `\`, `/`, -1)
}
// Put argument in canonical form, but preserve leading ./.
if strings.HasPrefix(a, "./") {
a = "./" + path.Clean(a)
if a == "./." {
a = "."
}
} else {
a = path.Clean(a)
}
if isMetaPackage(a) {
out = append(out, allPackages(a)...)
continue
}
out = append(out, a)
}
return out
}
// importPaths returns the import paths to use for the given command line.
func importPaths(args []string) []string {
args = importPathsNoDotExpansion(args)
var out []string
for _, a := range args {
if strings.Contains(a, "...") {
if build.IsLocalImport(a) {
out = append(out, allPackagesInFS(a)...)
} else {
out = append(out, allPackages(a)...)
}
continue
}
out = append(out, a)
}
return out
}
var atexitFuncs []func()
func atexit(f func()) {
atexitFuncs = append(atexitFuncs, f)
}
func exit() {
for _, f := range atexitFuncs {
f()
}
os.Exit(exitStatus)
}
func fatalf(format string, args ...interface{}) {
errorf(format, args...)
exit()
}
func errorf(format string, args ...interface{}) {
log.Printf(format, args...)
setExitStatus(1)
}
func exitIfErrors() {
if exitStatus != 0 {
exit()
}
}
func run(cmdargs ...interface{}) {
cmdline := stringList(cmdargs...)
if buildN || buildX {
fmt.Printf("%s\n", strings.Join(cmdline, " "))
if buildN {
return
}
}
cmd := exec.Command(cmdline[0], cmdline[1:]...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
errorf("%v", err)
}
}
// envForDir returns a copy of the environment
// suitable for running in the given directory.
// The environment is the current process's environment
// but with an updated $PWD, so that an os.Getwd in the
// child will be faster.
func envForDir(dir string, base []string) []string {
// Internally we only use rooted paths, so dir is rooted.
// Even if dir is not rooted, no harm done.
return mergeEnvLists([]string{"PWD=" + dir}, base)
}
// mergeEnvLists merges the two environment lists such that
// variables with the same name in "in" replace those in "out".
// This always returns a newly allocated slice.
func mergeEnvLists(in, out []string) []string {
out = append([]string(nil), out...)
NextVar:
for _, inkv := range in {
k := strings.SplitAfterN(inkv, "=", 2)[0]
for i, outkv := range out {
if strings.HasPrefix(outkv, k) {
out[i] = inkv
continue NextVar
}
}
out = append(out, inkv)
}
return out
}
// matchPattern(pattern)(name) reports whether
// name matches pattern. Pattern is a limited glob
// pattern in which '...' means 'any string' and there
// is no other special syntax.
func matchPattern(pattern string) func(name string) bool {
re := regexp.QuoteMeta(pattern)
re = strings.Replace(re, `\.\.\.`, `.*`, -1)
// Special case: foo/... matches foo too.
if strings.HasSuffix(re, `/.*`) {
re = re[:len(re)-len(`/.*`)] + `(/.*)?`
}
reg := regexp.MustCompile(`^` + re + `$`)
return func(name string) bool {
return reg.MatchString(name)
}
}
// hasPathPrefix reports whether the path s begins with the
// elements in prefix.
func hasPathPrefix(s, prefix string) bool {
switch {
default:
return false
case len(s) == len(prefix):
return s == prefix
case len(s) > len(prefix):
if prefix != "" && prefix[len(prefix)-1] == '/' {
return strings.HasPrefix(s, prefix)
}
return s[len(prefix)] == '/' && s[:len(prefix)] == prefix
}
}
// hasFilePathPrefix reports whether the filesystem path s begins with the
// elements in prefix.
func hasFilePathPrefix(s, prefix string) bool {
sv := strings.ToUpper(filepath.VolumeName(s))
pv := strings.ToUpper(filepath.VolumeName(prefix))
s = s[len(sv):]
prefix = prefix[len(pv):]
switch {
default:
return false
case sv != pv:
return false
case len(s) == len(prefix):
return s == prefix
case len(s) > len(prefix):
if prefix != "" && prefix[len(prefix)-1] == filepath.Separator {
return strings.HasPrefix(s, prefix)
}
return s[len(prefix)] == filepath.Separator && s[:len(prefix)] == prefix
}
}
// expandPath returns the symlink-expanded form of path.
func expandPath(p string) string {
x, err := filepath.EvalSymlinks(p)
if err == nil {
return x
}
return p
}
// treeCanMatchPattern(pattern)(name) reports whether
// name or children of name can possibly match pattern.
// Pattern is the same limited glob accepted by matchPattern.
func treeCanMatchPattern(pattern string) func(name string) bool {
wildCard := false
if i := strings.Index(pattern, "..."); i >= 0 {
wildCard = true
pattern = pattern[:i]
}
return func(name string) bool {
return len(name) <= len(pattern) && hasPathPrefix(pattern, name) ||
wildCard && strings.HasPrefix(name, pattern)
}
}
// allPackages returns all the packages that can be found
// under the $GOPATH directories and $GOROOT matching pattern.
// The pattern is either "all" (all packages), "std" (standard packages),
// "cmd" (standard commands), or a path including "...".
func allPackages(pattern string) []string {
pkgs := matchPackages(pattern)
if len(pkgs) == 0 {
fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
}
return pkgs
}
func matchPackages(pattern string) []string {
match := func(string) bool { return true }
treeCanMatch := func(string) bool { return true }
if !isMetaPackage(pattern) {
match = matchPattern(pattern)
treeCanMatch = treeCanMatchPattern(pattern)
}
have := map[string]bool{
"builtin": true, // ignore pseudo-package that exists only for documentation
}
if !buildContext.CgoEnabled {
have["runtime/cgo"] = true // ignore during walk
}
var pkgs []string
for _, src := range buildContext.SrcDirs() {
if (pattern == "std" || pattern == "cmd") && src != gorootSrc {
continue
}
src = filepath.Clean(src) + string(filepath.Separator)
root := src
if pattern == "cmd" {
root += "cmd" + string(filepath.Separator)
}
filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
if err != nil || !fi.IsDir() || path == src {
return nil
}
// Avoid .foo, _foo, and testdata directory trees.
_, elem := filepath.Split(path)
if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
return filepath.SkipDir
}
name := filepath.ToSlash(path[len(src):])
if pattern == "std" && (!isStandardImportPath(name) || name == "cmd") {
// The name "std" is only the standard library.
// If the name is cmd, it's the root of the command tree.
return filepath.SkipDir
}
if !treeCanMatch(name) {
return filepath.SkipDir
}
if have[name] {
return nil
}
have[name] = true
if !match(name) {
return nil
}
_, err = buildContext.ImportDir(path, 0)
if err != nil {
if _, noGo := err.(*build.NoGoError); noGo {
return nil
}
}
pkgs = append(pkgs, name)
return nil
})
}
return pkgs
}
// allPackagesInFS is like allPackages but is passed a pattern
// beginning ./ or ../, meaning it should scan the tree rooted
// at the given directory. There are ... in the pattern too.
func allPackagesInFS(pattern string) []string {
pkgs := matchPackagesInFS(pattern)
if len(pkgs) == 0 {
fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
}
return pkgs
}
func matchPackagesInFS(pattern string) []string {
// Find directory to begin the scan.
// Could be smarter but this one optimization
// is enough for now, since ... is usually at the
// end of a path.
i := strings.Index(pattern, "...")
dir, _ := path.Split(pattern[:i])
// pattern begins with ./ or ../.
// path.Clean will discard the ./ but not the ../.
// We need to preserve the ./ for pattern matching
// and in the returned import paths.
prefix := ""
if strings.HasPrefix(pattern, "./") {
prefix = "./"
}
match := matchPattern(pattern)
var pkgs []string
filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
if err != nil || !fi.IsDir() {
return nil
}
if path == dir {
// filepath.Walk starts at dir and recurses. For the recursive case,
// the path is the result of filepath.Join, which calls filepath.Clean.
// The initial case is not Cleaned, though, so we do this explicitly.
//
// This converts a path like "./io/" to "io". Without this step, running
// "cd $GOROOT/src; go list ./io/..." would incorrectly skip the io
// package, because prepending the prefix "./" to the unclean path would
// result in "././io", and match("././io") returns false.
path = filepath.Clean(path)
}
// Avoid .foo, _foo, and testdata directory trees, but do not avoid "." or "..".
_, elem := filepath.Split(path)
dot := strings.HasPrefix(elem, ".") && elem != "." && elem != ".."
if dot || strings.HasPrefix(elem, "_") || elem == "testdata" {
return filepath.SkipDir
}
name := prefix + filepath.ToSlash(path)
if !match(name) {
return nil
}
// We keep the directory if we can import it, or if we can't import it
// due to invalid Go source files. This means that directories containing
// parse errors will be built (and fail) instead of being silently skipped
// as not matching the pattern. Go 1.5 and earlier skipped, but that
// behavior means people miss serious mistakes.
// See golang.org/issue/11407.
if p, err := buildContext.ImportDir(path, 0); err != nil && (p == nil || len(p.InvalidGoFiles) == 0) {
if _, noGo := err.(*build.NoGoError); !noGo {
log.Print(err)
}
return nil
}
pkgs = append(pkgs, name)
return nil
})
return pkgs
}
// stringList's arguments should be a sequence of string or []string values.
// stringList flattens them into a single []string.
func stringList(args ...interface{}) []string {
var x []string
for _, arg := range args {
switch arg := arg.(type) {
case []string:
x = append(x, arg...)
case string:
x = append(x, arg)
default:
panic("stringList: invalid argument of type " + fmt.Sprintf("%T", arg))
}
}
return x
}
// toFold returns a string with the property that
// strings.EqualFold(s, t) iff toFold(s) == toFold(t)
// This lets us test a large set of strings for fold-equivalent
// duplicates without making a quadratic number of calls
// to EqualFold. Note that strings.ToUpper and strings.ToLower
// have the desired property in some corner cases.
func toFold(s string) string {
// Fast path: all ASCII, no upper case.
// Most paths look like this already.
for i := 0; i < len(s); i++ {
c := s[i]
if c >= utf8.RuneSelf || 'A' <= c && c <= 'Z' {
goto Slow
}
}
return s
Slow:
var buf bytes.Buffer
for _, r := range s {
// SimpleFold(x) cycles to the next equivalent rune > x
// or wraps around to smaller values. Iterate until it wraps,
// and we've found the minimum value.
for {
r0 := r
r = unicode.SimpleFold(r0)
if r <= r0 {
break
}
}
// Exception to allow fast path above: A-Z => a-z
if 'A' <= r && r <= 'Z' {
r += 'a' - 'A'
}
buf.WriteRune(r)
}
return buf.String()
}
// foldDup reports a pair of strings from the list that are
// equal according to strings.EqualFold.
// It returns "", "" if there are no such strings.
func foldDup(list []string) (string, string) {
clash := map[string]string{}
for _, s := range list {
fold := toFold(s)
if t := clash[fold]; t != "" {
if s > t {
s, t = t, s
}
return s, t
}
clash[fold] = s
}
return "", ""
}

View File

@ -1,88 +0,0 @@
// 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.
package main
import "testing"
var matchPatternTests = []stringPairTest{
{"...", "foo", true},
{"net", "net", true},
{"net", "net/http", false},
{"net/http", "net", false},
{"net/http", "net/http", true},
{"net...", "netchan", true},
{"net...", "net", true},
{"net...", "net/http", true},
{"net...", "not/http", false},
{"net/...", "netchan", false},
{"net/...", "net", true},
{"net/...", "net/http", true},
{"net/...", "not/http", false},
}
func TestMatchPattern(t *testing.T) {
testStringPairs(t, "matchPattern", matchPatternTests, func(pattern, name string) bool {
return matchPattern(pattern)(name)
})
}
var treeCanMatchPatternTests = []stringPairTest{
{"...", "foo", true},
{"net", "net", true},
{"net", "net/http", false},
{"net/http", "net", true},
{"net/http", "net/http", true},
{"net...", "netchan", true},
{"net...", "net", true},
{"net...", "net/http", true},
{"net...", "not/http", false},
{"net/...", "netchan", false},
{"net/...", "net", true},
{"net/...", "net/http", true},
{"net/...", "not/http", false},
{"abc.../def", "abcxyz", true},
{"abc.../def", "xyxabc", false},
{"x/y/z/...", "x", true},
{"x/y/z/...", "x/y", true},
{"x/y/z/...", "x/y/z", true},
{"x/y/z/...", "x/y/z/w", true},
{"x/y/z", "x", true},
{"x/y/z", "x/y", true},
{"x/y/z", "x/y/z", true},
{"x/y/z", "x/y/z/w", false},
{"x/.../y/z", "x/a/b/c", true},
{"x/.../y/z", "y/x/a/b/c", false},
}
func TestChildrenCanMatchPattern(t *testing.T) {
testStringPairs(t, "treeCanMatchPattern", treeCanMatchPatternTests, func(pattern, name string) bool {
return treeCanMatchPattern(pattern)(name)
})
}
var hasPathPrefixTests = []stringPairTest{
{"abc", "a", false},
{"a/bc", "a", true},
{"a", "a", true},
{"a/bc", "a/", true},
}
func TestHasPathPrefix(t *testing.T) {
testStringPairs(t, "hasPathPrefix", hasPathPrefixTests, hasPathPrefix)
}
type stringPairTest struct {
in1 string
in2 string
out bool
}
func testStringPairs(t *testing.T, name string, tests []stringPairTest, f func(string, string) bool) {
for _, tt := range tests {
if out := f(tt.in1, tt.in2); out != tt.out {
t.Errorf("%s(%q, %q) = %v, want %v", name, tt.in1, tt.in2, out, tt.out)
}
}
}

View File

@ -7,10 +7,11 @@
package main_test
import (
main "cmd/go"
"go/build"
"runtime"
"testing"
"cmd/go/internal/buildid"
)
func TestNoteReading(t *testing.T) {
@ -23,9 +24,9 @@ func TestNoteReading2K(t *testing.T) {
}
// Set BuildIDReadSize to 2kB to exercise Mach-O parsing more strictly.
defer func(old int) {
main.BuildIDReadSize = old
}(main.BuildIDReadSize)
main.BuildIDReadSize = 2 * 1024
buildid.BuildIDReadSize = old
}(buildid.BuildIDReadSize)
buildid.BuildIDReadSize = 2 * 1024
testNoteReading(t)
}
@ -36,7 +37,7 @@ func testNoteReading(t *testing.T) {
tg.tempFile("hello.go", `package main; func main() { print("hello, world\n") }`)
const buildID = "TestNoteReading-Build-ID"
tg.run("build", "-ldflags", "-buildid="+buildID, "-o", tg.path("hello.exe"), tg.path("hello.go"))
id, err := main.ReadBuildIDFromBinary(tg.path("hello.exe"))
id, err := buildid.ReadBuildIDFromBinary(tg.path("hello.exe"))
if err != nil {
t.Fatalf("reading build ID from hello binary: %v", err)
}
@ -56,7 +57,7 @@ func testNoteReading(t *testing.T) {
}
tg.run("build", "-ldflags", "-buildid="+buildID+" -linkmode=external", "-o", tg.path("hello.exe"), tg.path("hello.go"))
id, err = main.ReadBuildIDFromBinary(tg.path("hello.exe"))
id, err = buildid.ReadBuildIDFromBinary(tg.path("hello.exe"))
if err != nil {
t.Fatalf("reading build ID from hello binary (linkmode=external): %v", err)
}

View File

@ -1,194 +0,0 @@
// Copyright 2014 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 main
import (
"io/ioutil"
"os"
"path/filepath"
"reflect"
"strings"
"testing"
)
var foldDupTests = []struct {
list []string
f1, f2 string
}{
{stringList("math/rand", "math/big"), "", ""},
{stringList("math", "strings"), "", ""},
{stringList("strings"), "", ""},
{stringList("strings", "strings"), "strings", "strings"},
{stringList("Rand", "rand", "math", "math/rand", "math/Rand"), "Rand", "rand"},
}
func TestFoldDup(t *testing.T) {
for _, tt := range foldDupTests {
f1, f2 := foldDup(tt.list)
if f1 != tt.f1 || f2 != tt.f2 {
t.Errorf("foldDup(%q) = %q, %q, want %q, %q", tt.list, f1, f2, tt.f1, tt.f2)
}
}
}
var parseMetaGoImportsTests = []struct {
in string
out []metaImport
}{
{
`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">`,
[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
},
{
`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
<meta name="go-import" content="baz/quux git http://github.com/rsc/baz/quux">`,
[]metaImport{
{"foo/bar", "git", "https://github.com/rsc/foo/bar"},
{"baz/quux", "git", "http://github.com/rsc/baz/quux"},
},
},
{
`<head>
<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
</head>`,
[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
},
{
`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
<body>`,
[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
},
{
`<!doctype html><meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">`,
[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
},
{
// XML doesn't like <div style=position:relative>.
`<!doctype html><title>Page Not Found</title><meta name=go-import content="chitin.io/chitin git https://github.com/chitin-io/chitin"><div style=position:relative>DRAFT</div>`,
[]metaImport{{"chitin.io/chitin", "git", "https://github.com/chitin-io/chitin"}},
},
}
func TestParseMetaGoImports(t *testing.T) {
for i, tt := range parseMetaGoImportsTests {
out, err := parseMetaGoImports(strings.NewReader(tt.in))
if err != nil {
t.Errorf("test#%d: %v", i, err)
continue
}
if !reflect.DeepEqual(out, tt.out) {
t.Errorf("test#%d:\n\thave %q\n\twant %q", i, out, tt.out)
}
}
}
func TestSharedLibName(t *testing.T) {
// TODO(avdva) - make these values platform-specific
prefix := "lib"
suffix := ".so"
testData := []struct {
args []string
pkgs []*Package
expected string
expectErr bool
rootedAt string
}{
{
args: []string{"std"},
pkgs: []*Package{},
expected: "std",
},
{
args: []string{"std", "cmd"},
pkgs: []*Package{},
expected: "std,cmd",
},
{
args: []string{},
pkgs: []*Package{&Package{ImportPath: "gopkg.in/somelib"}},
expected: "gopkg.in-somelib",
},
{
args: []string{"./..."},
pkgs: []*Package{&Package{ImportPath: "somelib"}},
expected: "somelib",
rootedAt: "somelib",
},
{
args: []string{"../somelib", "../somelib"},
pkgs: []*Package{&Package{ImportPath: "somelib"}},
expected: "somelib",
},
{
args: []string{"../lib1", "../lib2"},
pkgs: []*Package{&Package{ImportPath: "gopkg.in/lib1"}, &Package{ImportPath: "gopkg.in/lib2"}},
expected: "gopkg.in-lib1,gopkg.in-lib2",
},
{
args: []string{"./..."},
pkgs: []*Package{
&Package{ImportPath: "gopkg.in/dir/lib1"},
&Package{ImportPath: "gopkg.in/lib2"},
&Package{ImportPath: "gopkg.in/lib3"},
},
expected: "gopkg.in",
rootedAt: "gopkg.in",
},
{
args: []string{"std", "../lib2"},
pkgs: []*Package{},
expectErr: true,
},
{
args: []string{"all", "./"},
pkgs: []*Package{},
expectErr: true,
},
{
args: []string{"cmd", "fmt"},
pkgs: []*Package{},
expectErr: true,
},
}
for _, data := range testData {
func() {
if data.rootedAt != "" {
tmpGopath, err := ioutil.TempDir("", "gopath")
if err != nil {
t.Fatal(err)
}
oldGopath := buildContext.GOPATH
defer func() {
buildContext.GOPATH = oldGopath
os.Chdir(cwd)
err := os.RemoveAll(tmpGopath)
if err != nil {
t.Error(err)
}
}()
root := filepath.Join(tmpGopath, "src", data.rootedAt)
err = os.MkdirAll(root, 0755)
if err != nil {
t.Fatal(err)
}
buildContext.GOPATH = tmpGopath
os.Chdir(root)
}
computed, err := libname(data.args, data.pkgs)
if err != nil {
if !data.expectErr {
t.Errorf("libname returned an error %q, expected a name", err.Error())
}
} else if data.expectErr {
t.Errorf("libname returned %q, expected an error", computed)
} else {
expected := prefix + data.expected + suffix
if expected != computed {
t.Errorf("libname returned %q, expected %q", computed, expected)
}
}
}()
}
}

View File

@ -1,23 +0,0 @@
#!/bin/sh
x() {
echo '--- ' "$@"
"$@"
echo '---'
echo
}
x go help
x go help build
x go help clean
x go help install
x go help fix
x go help fmt
x go help get
x go help list
x go help test
x go help version
x go help vet
x go help gopath
x go help importpath
x go help remote

View File

@ -1,352 +0,0 @@
--- go help
usage: go command [arguments]
go manages Go source code.
The commands are:
build compile and install packages and dependencies
clean remove intermediate objects
fix run gofix on packages
fmt run gofmt -w on packages
get download and install packages and dependencies
install install packages and dependencies
list list packages
test test packages
version print Go version
vet run govet on packages
Use "go help [command]" for more information about a command.
Additional help topics:
gopath GOPATH environment variable
importpath description of import paths
remote remote import path syntax
Use "go help [topic]" for more information about that topic.
---
--- go help build
usage: go build [-n] [-v] [importpath...]
Build compiles the packages named by the import paths,
along with their dependencies, but it does not install the results.
The -n flag prints the commands but does not run them.
The -v flag prints the commands.
For more about import paths, see 'go help importpath'.
See also: go install, go get, go clean.
---
--- go help clean
usage: go clean [-nuke] [importpath...]
Clean removes intermediate object files generated during
the compilation of the packages named by the import paths,
but by default it does not remove the installed package binaries.
The -nuke flag causes clean to remove the installed package binaries too.
TODO: Clean does not clean dependencies of the packages.
For more about import paths, see 'go help importpath'.
---
--- go help install
usage: go install [-n] [-v] [importpath...]
Install compiles and installs the packages named by the import paths,
along with their dependencies.
The -n flag prints the commands but does not run them.
The -v flag prints the commands.
For more about import paths, see 'go help importpath'.
See also: go build, go get, go clean.
---
--- go help fix
usage: go fix [importpath...]
Fix runs the gofix command on the packages named by the import paths.
For more about gofix, see 'godoc gofix'.
For more about import paths, see 'go help importpath'.
To run gofix with specific options, run gofix itself.
See also: go fmt, go vet.
---
--- go help fmt
usage: go fmt [importpath...]
Fmt runs the command 'gofmt -w' on the packages named by the import paths.
For more about gofmt, see 'godoc gofmt'.
For more about import paths, see 'go help importpath'.
To run gofmt with specific options, run gofmt itself.
See also: go fix, go vet.
---
--- go help get
usage: go get [importpath...]
Get downloads and installs the packages named by the import paths,
along with their dependencies.
After downloading the code, 'go get' looks for a tag beginning
with "go." that corresponds to the local Go version.
For Go "release.r58" it looks for a tag named "go.r58".
For "weekly.2011-06-03" it looks for "go.weekly.2011-06-03".
If the specific "go.X" tag is not found, it uses the latest earlier
version it can find. Otherwise, it uses the default version for
the version control system: HEAD for git, tip for Mercurial,
and so on.
TODO: Explain versions better.
For more about import paths, see 'go help importpath'.
For more about how 'go get' finds source code to
download, see 'go help remote'.
See also: go build, go install, go clean.
---
--- go help list
usage: go list [-f format] [-json] [importpath...]
List lists the packages named by the import paths.
The default output shows the package name and file system location:
books /home/you/src/google-api-go-client.googlecode.com/hg/books/v1
oauth /home/you/src/goauth2.googlecode.com/hg/oauth
sqlite /home/you/src/gosqlite.googlecode.com/hg/sqlite
The -f flag specifies an alternate format for the list,
using the syntax of package template. The default output
is equivalent to -f '{{.Name}} {{.Dir}}' The struct
being passed to the template is:
type Package struct {
Name string // package name
Doc string // package documentation string
GoFiles []string // names of Go source files in package
ImportPath string // import path denoting package
Imports []string // import paths used by this package
Deps []string // all (recursively) imported dependencies
Dir string // directory containing package sources
Version string // version of installed package
}
The -json flag causes the package data to be printed in JSON format.
For more about import paths, see 'go help importpath'.
---
--- go help test
usage: go test [importpath...]
Test runs gotest to test the packages named by the import paths.
It prints a summary of the test results in the format:
test archive/tar
FAIL archive/zip
test compress/gzip
...
followed by gotest output for each failed package.
For more about import paths, see 'go help importpath'.
See also: go build, go compile, go vet.
---
--- go help version
usage: go version
Version prints the Go version, as reported by runtime.Version.
---
--- go help vet
usage: go vet [importpath...]
Vet runs the govet command on the packages named by the import paths.
For more about govet, see 'godoc govet'.
For more about import paths, see 'go help importpath'.
To run govet with specific options, run govet itself.
See also: go fmt, go fix.
---
--- go help gopath
The GOPATH environment variable lists places to look for Go code.
On Unix, the value is a colon-separated string.
On Windows, the value is a semicolon-separated string.
On Plan 9, the value is a list.
GOPATH must be set to build and install packages outside the
standard Go tree.
Each directory listed in GOPATH must have a prescribed structure:
The src/ directory holds source code. The path below 'src'
determines the import path or executable name.
The pkg/ directory holds installed package objects.
As in the Go tree, each target operating system and
architecture pair has its own subdirectory of pkg
(pkg/GOOS_GOARCH).
If DIR is a directory listed in the GOPATH, a package with
source in DIR/src/foo/bar can be imported as "foo/bar" and
has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a".
The bin/ directory holds compiled commands.
Each command is named for its source directory, but only
the final element, not the entire path. That is, the
command with source in DIR/src/foo/quux is installed into
DIR/bin/quux, not DIR/bin/foo/quux. The foo/ is stripped
so that you can add DIR/bin to your PATH to get at the
installed commands.
Here's an example directory layout:
GOPATH=/home/user/gocode
/home/user/gocode/
src/
foo/
bar/ (go code in package bar)
x.go
quux/ (go code in package main)
y.go
bin/
quux (installed command)
pkg/
linux_amd64/
foo/
bar.a (installed package object)
Go searches each directory listed in GOPATH to find source code,
but new packages are always downloaded into the first directory
in the list.
---
--- go help importpath
Many commands apply to a set of packages named by import paths:
go action [importpath...]
An import path that is a rooted path or that begins with
a . or .. element is interpreted as a file system path and
denotes the package in that directory.
Otherwise, the import path P denotes the package found in
the directory DIR/src/P for some DIR listed in the GOPATH
environment variable (see 'go help gopath').
If no import paths are given, the action applies to the
package in the current directory.
The special import path "all" expands to all package directories
found in all the GOPATH trees. For example, 'go list all'
lists all the packages on the local system.
An import path can also name a package to be downloaded from
a remote repository. Run 'go help remote' for details.
Every package in a program must have a unique import path.
By convention, this is arranged by starting each path with a
unique prefix that belongs to you. For example, paths used
internally at Google all begin with 'google', and paths
denoting remote repositories begin with the path to the code,
such as 'project.googlecode.com/'.
---
--- go help remote
An import path (see 'go help importpath') denotes a package
stored in the local file system. Certain import paths also
describe how to obtain the source code for the package using
a revision control system.
A few common code hosting sites have special syntax:
BitBucket (Mercurial)
import "bitbucket.org/user/project"
import "bitbucket.org/user/project/sub/directory"
GitHub (Git)
import "github.com/user/project"
import "github.com/user/project/sub/directory"
Google Code Project Hosting (Git, Mercurial, Subversion)
import "project.googlecode.com/git"
import "project.googlecode.com/git/sub/directory"
import "project.googlecode.com/hg"
import "project.googlecode.com/hg/sub/directory"
import "project.googlecode.com/svn/trunk"
import "project.googlecode.com/svn/trunk/sub/directory"
Launchpad (Bazaar)
import "launchpad.net/project"
import "launchpad.net/project/series"
import "launchpad.net/project/series/sub/directory"
import "launchpad.net/~user/project/branch"
import "launchpad.net/~user/project/branch/sub/directory"
For code hosted on other servers, an import path of the form
repository.vcs/path
specifies the given repository, with or without the .vcs suffix,
using the named version control system, and then the path inside
that repository. The supported version control systems are:
Bazaar .bzr
Git .git
Mercurial .hg
Subversion .svn
For example,
import "example.org/user/foo.hg"
denotes the root directory of the Mercurial repository at
example.org/user/foo or foo.hg, and
import "example.org/repo.git/foo/bar"
denotes the foo/bar directory of the Git repository at
example.com/repo or repo.git.
When a version control system supports multiple protocols,
each is tried in turn when downloading. For example, a Git
download tries git://, then https://, then http://.
New downloaded packages are written to the first directory
listed in the GOPATH environment variable (see 'go help gopath').
The go command attempts to download the version of the
package appropriate for the Go release being used.
Run 'go help install' for more.
---

View File

@ -1,820 +0,0 @@
#!/bin/bash
# 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.
set -e
go build -o testgo
go() {
echo TEST ERROR: ran go, not testgo: go "$@" >&2
exit 2
}
started=false
TEST() {
if $started; then
stop
fi
echo TEST: "$@"
started=true
ok=true
}
stop() {
if ! $started; then
echo TEST ERROR: stop missing start >&2
exit 2
fi
started=false
if $ok; then
echo PASS
else
echo FAIL
allok=false
fi
}
ok=true
allok=true
unset GOBIN
unset GOPATH
unset GOROOT
TEST 'file:line in error messages'
# Test that error messages have file:line information at beginning of
# the line. Also test issue 4917: that the error is on stderr.
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
fn=$d/err.go
echo "package main" > $fn
echo 'import "bar"' >> $fn
./testgo run $fn 2>$d/err.out || true
if ! grep -q "^$fn:" $d/err.out; then
echo "missing file:line in error message"
cat $d/err.out
ok=false
fi
rm -r $d
# Test local (./) imports.
testlocal() {
local="$1"
TEST local imports $2 '(easy)'
./testgo build -o hello "testdata/$local/easy.go"
./hello >hello.out
if ! grep -q '^easysub\.Hello' hello.out; then
echo "testdata/$local/easy.go did not generate expected output"
cat hello.out
ok=false
fi
TEST local imports $2 '(easysub)'
./testgo build -o hello "testdata/$local/easysub/main.go"
./hello >hello.out
if ! grep -q '^easysub\.Hello' hello.out; then
echo "testdata/$local/easysub/main.go did not generate expected output"
cat hello.out
ok=false
fi
TEST local imports $2 '(hard)'
./testgo build -o hello "testdata/$local/hard.go"
./hello >hello.out
if ! grep -q '^sub\.Hello' hello.out || ! grep -q '^subsub\.Hello' hello.out ; then
echo "testdata/$local/hard.go did not generate expected output"
cat hello.out
ok=false
fi
rm -f hello.out hello
# Test that go install x.go fails.
TEST local imports $2 '(go install should fail)'
if ./testgo install "testdata/$local/easy.go" >/dev/null 2>&1; then
echo "go install testdata/$local/easy.go succeeded"
ok=false
fi
}
# Test local imports
testlocal local ''
# Test local imports again, with bad characters in the directory name.
bad='#$%:, &()*;<=>?\^{}'
rm -rf "testdata/$bad"
cp -R testdata/local "testdata/$bad"
testlocal "$bad" 'with bad characters in path'
rm -rf "testdata/$bad"
TEST error message for syntax error in test go file says FAIL
export GOPATH=$(pwd)/testdata
if ./testgo test syntaxerror 2>testdata/err; then
echo 'go test syntaxerror succeeded'
ok=false
elif ! grep FAIL testdata/err >/dev/null; then
echo 'go test did not say FAIL:'
cat testdata/err
ok=false
fi
rm -f ./testdata/err
unset GOPATH
TEST wildcards do not look in useless directories
export GOPATH=$(pwd)/testdata
if ./testgo list ... >testdata/err 2>&1; then
echo "go list ... succeeded"
ok=false
elif ! grep badpkg testdata/err >/dev/null; then
echo "go list ... failure does not mention badpkg"
cat testdata/err
ok=false
elif ! ./testgo list m... >testdata/err 2>&1; then
echo "go list m... failed"
ok=false
fi
rm -rf ./testdata/err
unset GOPATH
# Test tests with relative imports.
TEST relative imports '(go test)'
if ! ./testgo test ./testdata/testimport; then
echo "go test ./testdata/testimport failed"
ok=false
fi
# Test installation with relative imports.
TEST relative imports '(go test -i)'
if ! ./testgo test -i ./testdata/testimport; then
echo "go test -i ./testdata/testimport failed"
ok=false
fi
# Test tests with relative imports in packages synthesized
# from Go files named on the command line.
TEST relative imports in command-line package
if ! ./testgo test ./testdata/testimport/*.go; then
echo "go test ./testdata/testimport/*.go failed"
ok=false
fi
TEST version control error message includes correct directory
export GOPATH=$(pwd)/testdata/shadow/root1
if ./testgo get -u foo 2>testdata/err; then
echo "go get -u foo succeeded unexpectedly"
ok=false
elif ! grep testdata/shadow/root1/src/foo testdata/err >/dev/null; then
echo "go get -u error does not mention shadow/root1/src/foo:"
cat testdata/err
ok=false
fi
unset GOPATH
TEST go install fails with no buildable files
export GOPATH=$(pwd)/testdata
export CGO_ENABLED=0
if ./testgo install cgotest 2>testdata/err; then
echo "go install cgotest succeeded unexpectedly"
elif ! grep 'no buildable Go source files' testdata/err >/dev/null; then
echo "go install cgotest did not report 'no buildable Go source files'"
cat testdata/err
ok=false
fi
unset CGO_ENABLED
unset GOPATH
# Test that without $GOBIN set, binaries get installed
# into the GOPATH bin directory.
TEST install into GOPATH
rm -rf testdata/bin
if ! GOPATH=$(pwd)/testdata ./testgo install go-cmd-test; then
echo "go install go-cmd-test failed"
ok=false
elif ! test -x testdata/bin/go-cmd-test; then
echo "go install go-cmd-test did not write to testdata/bin/go-cmd-test"
ok=false
fi
TEST package main_test imports archive not binary
export GOBIN=$(pwd)/testdata/bin
mkdir -p $GOBIN
export GOPATH=$(pwd)/testdata
touch ./testdata/src/main_test/m.go
if ! ./testgo test main_test; then
echo "go test main_test failed without install"
ok=false
elif ! ./testgo install main_test; then
echo "go test main_test failed"
ok=false
elif [ "$(./testgo list -f '{{.Stale}}' main_test)" != false ]; then
echo "after go install, main listed as stale"
ok=false
elif ! ./testgo test main_test; then
echo "go test main_test failed after install"
ok=false
fi
rm -rf $GOBIN
unset GOBIN
# And with $GOBIN set, binaries get installed to $GOBIN.
TEST install into GOBIN
if ! GOBIN=$(pwd)/testdata/bin1 GOPATH=$(pwd)/testdata ./testgo install go-cmd-test; then
echo "go install go-cmd-test failed"
ok=false
elif ! test -x testdata/bin1/go-cmd-test; then
echo "go install go-cmd-test did not write to testdata/bin1/go-cmd-test"
ok=false
fi
# Without $GOBIN set, installing a program outside $GOPATH should fail
# (there is nowhere to install it).
TEST install without destination fails
if ./testgo install testdata/src/go-cmd-test/helloworld.go 2>testdata/err; then
echo "go install testdata/src/go-cmd-test/helloworld.go should have failed, did not"
ok=false
elif ! grep 'no install location for .go files listed on command line' testdata/err; then
echo "wrong error:"
cat testdata/err
ok=false
fi
rm -f testdata/err
# With $GOBIN set, should install there.
TEST install to GOBIN '(command-line package)'
if ! GOBIN=$(pwd)/testdata/bin1 ./testgo install testdata/src/go-cmd-test/helloworld.go; then
echo "go install testdata/src/go-cmd-test/helloworld.go failed"
ok=false
elif ! test -x testdata/bin1/helloworld; then
echo "go install testdata/src/go-cmd-test/helloworld.go did not write testdata/bin1/helloworld"
ok=false
fi
TEST godoc installs into GOBIN
d=$(mktemp -d -t testgoXXX)
export GOPATH=$d
mkdir $d/gobin
GOBIN=$d/gobin ./testgo get code.google.com/p/go.tools/cmd/godoc
if [ ! -x $d/gobin/godoc ]; then
echo did not install godoc to '$GOBIN'
GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' code.google.com/p/go.tools/cmd/godoc
ok=false
fi
TEST godoc installs into GOROOT
GOROOT=$(./testgo env GOROOT)
rm -f $GOROOT/bin/godoc
./testgo install code.google.com/p/go.tools/cmd/godoc
if [ ! -x $GOROOT/bin/godoc ]; then
echo did not install godoc to '$GOROOT/bin'
./testgo list -f 'Target: {{.Target}}' code.google.com/p/go.tools/cmd/godoc
ok=false
fi
TEST cmd/fix installs into tool
GOOS=$(./testgo env GOOS)
GOARCH=$(./testgo env GOARCH)
rm -f $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix
./testgo install cmd/fix
if [ ! -x $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix ]; then
echo 'did not install cmd/fix to $GOROOT/pkg/tool'
GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' cmd/fix
ok=false
fi
rm -f $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix
GOBIN=$d/gobin ./testgo install cmd/fix
if [ ! -x $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix ]; then
echo 'did not install cmd/fix to $GOROOT/pkg/tool with $GOBIN set'
GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' cmd/fix
ok=false
fi
TEST gopath program installs into GOBIN
mkdir $d/src/progname
echo 'package main; func main() {}' >$d/src/progname/p.go
GOBIN=$d/gobin ./testgo install progname
if [ ! -x $d/gobin/progname ]; then
echo 'did not install progname to $GOBIN/progname'
./testgo list -f 'Target: {{.Target}}' cmd/api
ok=false
fi
rm -f $d/gobin/progname $d/bin/progname
TEST gopath program installs into GOPATH/bin
./testgo install progname
if [ ! -x $d/bin/progname ]; then
echo 'did not install progname to $GOPATH/bin/progname'
./testgo list -f 'Target: {{.Target}}' progname
ok=false
fi
unset GOPATH
rm -rf $d
# Reject relative paths in GOPATH.
TEST reject relative paths in GOPATH '(command-line package)'
if GOPATH=. ./testgo build testdata/src/go-cmd-test/helloworld.go; then
echo 'GOPATH="." go build should have failed, did not'
ok=false
fi
TEST reject relative paths in GOPATH
if GOPATH=:$(pwd)/testdata:. ./testgo build go-cmd-test; then
echo 'GOPATH=":$(pwd)/testdata:." go build should have failed, did not'
ok=false
fi
# issue 4104
TEST go test with package listed multiple times
if [ $(./testgo test fmt fmt fmt fmt fmt | wc -l) -ne 1 ] ; then
echo 'go test fmt fmt fmt fmt fmt tested the same package multiple times'
ok=false
fi
# ensure that output of 'go list' is consistent between runs
TEST go list is consistent
./testgo list std > test_std.list
if ! ./testgo list std | cmp -s test_std.list - ; then
echo "go list std ordering is inconsistent"
ok=false
fi
rm -f test_std.list
# issue 4096. Validate the output of unsuccessful go install foo/quxx
TEST unsuccessful go install should mention missing package
if [ $(./testgo install 'foo/quxx' 2>&1 | grep -c 'cannot find package "foo/quxx" in any of') -ne 1 ] ; then
echo 'go install foo/quxx expected error: .*cannot find package "foo/quxx" in any of'
ok=false
fi
# test GOROOT search failure is reported
TEST GOROOT search failure reporting
if [ $(./testgo install 'foo/quxx' 2>&1 | egrep -c 'foo/quxx \(from \$GOROOT\)$') -ne 1 ] ; then
echo 'go install foo/quxx expected error: .*foo/quxx (from $GOROOT)'
ok=false
fi
# test multiple GOPATH entries are reported separately
TEST multiple GOPATH entries reported separately
if [ $(GOPATH=$(pwd)/testdata/a:$(pwd)/testdata/b ./testgo install 'foo/quxx' 2>&1 | egrep -c 'testdata/./src/foo/quxx') -ne 2 ] ; then
echo 'go install foo/quxx expected error: .*testdata/a/src/foo/quxx (from $GOPATH)\n.*testdata/b/src/foo/quxx'
ok=false
fi
# test (from $GOPATH) annotation is reported for the first GOPATH entry
TEST mention GOPATH in first GOPATH entry
if [ $(GOPATH=$(pwd)/testdata/a:$(pwd)/testdata/b ./testgo install 'foo/quxx' 2>&1 | egrep -c 'testdata/a/src/foo/quxx \(from \$GOPATH\)$') -ne 1 ] ; then
echo 'go install foo/quxx expected error: .*testdata/a/src/foo/quxx (from $GOPATH)'
ok=false
fi
# but not on the second
TEST but not the second entry
if [ $(GOPATH=$(pwd)/testdata/a:$(pwd)/testdata/b ./testgo install 'foo/quxx' 2>&1 | egrep -c 'testdata/b/src/foo/quxx$') -ne 1 ] ; then
echo 'go install foo/quxx expected error: .*testdata/b/src/foo/quxx'
ok=false
fi
# test missing GOPATH is reported
TEST missing GOPATH is reported
if [ $(GOPATH= ./testgo install 'foo/quxx' 2>&1 | egrep -c '\(\$GOPATH not set\)$') -ne 1 ] ; then
echo 'go install foo/quxx expected error: ($GOPATH not set)'
ok=false
fi
# issue 4186. go get cannot be used to download packages to $GOROOT
# Test that without GOPATH set, go get should fail
TEST without GOPATH, go get fails
d=$(mktemp -d -t testgoXXX)
mkdir -p $d/src/pkg
if GOPATH= GOROOT=$d ./testgo get -d code.google.com/p/go.codereview/cmd/hgpatch ; then
echo 'go get code.google.com/p/go.codereview/cmd/hgpatch should not succeed with $GOPATH unset'
ok=false
fi
rm -rf $d
# Test that with GOPATH=$GOROOT, go get should fail
TEST with GOPATH=GOROOT, go get fails
d=$(mktemp -d -t testgoXXX)
mkdir -p $d/src/pkg
if GOPATH=$d GOROOT=$d ./testgo get -d code.google.com/p/go.codereview/cmd/hgpatch ; then
echo 'go get code.google.com/p/go.codereview/cmd/hgpatch should not succeed with GOPATH=$GOROOT'
ok=false
fi
rm -rf $d
TEST ldflags arguments with spaces '(issue 3941)'
d=$(mktemp -d -t testgoXXX)
cat >$d/main.go<<EOF
package main
var extern string
func main() {
println(extern)
}
EOF
./testgo run -ldflags '-X main.extern "hello world"' $d/main.go 2>hello.out
if ! grep -q '^hello world' hello.out; then
echo "ldflags -X main.extern 'hello world' failed. Output:"
cat hello.out
ok=false
fi
rm -rf $d hello.out
TEST go test -cpuprofile leaves binary behind
./testgo test -cpuprofile strings.prof strings || ok=false
if [ ! -x strings.test ]; then
echo "go test -cpuprofile did not create strings.test"
ok=false
fi
rm -f strings.prof strings.test
TEST symlinks do not confuse go list '(issue 4568)'
old=$(pwd)
tmp=$(cd /tmp && pwd -P)
d=$(TMPDIR=$tmp mktemp -d -t testgoXXX)
mkdir -p $d/src
(
ln -s $d $d/src/dir1
cd $d/src
echo package p >dir1/p.go
export GOPATH=$d
if [ "$($old/testgo list -f '{{.Root}}' dir1)" != "$d" ]; then
echo Confused by symlinks.
echo "Package in current directory $(pwd) should have Root $d"
env|grep WD
$old/testgo list -json . dir1
touch $d/failed
fi
)
if [ -f $d/failed ]; then
ok=false
fi
rm -rf $d
TEST 'install with tags (issue 4515)'
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
mkdir -p $d/src/example/a $d/src/example/b $d/bin
cat >$d/src/example/a/main.go <<EOF
package main
func main() {}
EOF
cat >$d/src/example/b/main.go <<EOF
// +build mytag
package main
func main() {}
EOF
GOPATH=$d ./testgo install -tags mytag example/a example/b || ok=false
if [ ! -x $d/bin/a -o ! -x $d/bin/b ]; then
echo go install example/a example/b did not install binaries
ok=false
fi
rm -f $d/bin/*
GOPATH=$d ./testgo install -tags mytag example/... || ok=false
if [ ! -x $d/bin/a -o ! -x $d/bin/b ]; then
echo go install example/... did not install binaries
ok=false
fi
rm -f $d/bin/*go
export GOPATH=$d
if [ "$(./testgo list -tags mytag example/b...)" != "example/b" ]; then
echo go list example/b did not find example/b
ok=false
fi
unset GOPATH
rm -rf $d
TEST case collisions '(issue 4773)'
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
export GOPATH=$d
mkdir -p $d/src/example/{a/pkg,a/Pkg,b}
cat >$d/src/example/a/a.go <<EOF
package p
import (
_ "example/a/pkg"
_ "example/a/Pkg"
)
EOF
cat >$d/src/example/a/pkg/pkg.go <<EOF
package pkg
EOF
cat >$d/src/example/a/Pkg/pkg.go <<EOF
package pkg
EOF
if ./testgo list example/a 2>$d/out; then
echo go list example/a should have failed, did not.
ok=false
elif ! grep "case-insensitive import collision" $d/out >/dev/null; then
echo go list example/a did not report import collision.
ok=false
fi
cat >$d/src/example/b/file.go <<EOF
package b
EOF
cat >$d/src/example/b/FILE.go <<EOF
package b
EOF
if [ $(ls $d/src/example/b | wc -l) = 2 ]; then
# case-sensitive file system, let directory read find both files
args="example/b"
else
# case-insensitive file system, list files explicitly on command line.
args="$d/src/example/b/file.go $d/src/example/b/FILE.go"
fi
if ./testgo list $args 2>$d/out; then
echo go list example/b should have failed, did not.
ok=false
elif ! grep "case-insensitive file name collision" $d/out >/dev/null; then
echo go list example/b did not report file name collision.
ok=false
fi
TEST go get cover
./testgo get code.google.com/p/go.tools/cmd/cover || ok=false
unset GOPATH
rm -rf $d
TEST shadowing logic
export GOPATH=$(pwd)/testdata/shadow/root1:$(pwd)/testdata/shadow/root2
# The math in root1 is not "math" because the standard math is.
cdir=$(./testgo list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./testdata/shadow/root1/src/math)
if [ "$cdir" != "(_$(pwd)/testdata/shadow/root1/src/math) ($GOROOT/src/pkg/math)" ]; then
echo shadowed math is not shadowed: "$cdir"
ok=false
fi
# The foo in root1 is "foo".
cdir=$(./testgo list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./testdata/shadow/root1/src/foo)
if [ "$cdir" != "(foo) ()" ]; then
echo unshadowed foo is shadowed: "$cdir"
ok=false
fi
# The foo in root2 is not "foo" because the foo in root1 got there first.
cdir=$(./testgo list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./testdata/shadow/root2/src/foo)
if [ "$cdir" != "(_$(pwd)/testdata/shadow/root2/src/foo) ($(pwd)/testdata/shadow/root1/src/foo)" ]; then
echo shadowed foo is not shadowed: "$cdir"
ok=false
fi
# The error for go install should mention the conflicting directory.
err=$(! ./testgo install ./testdata/shadow/root2/src/foo 2>&1)
if [ "$err" != "go install: no install location for $(pwd)/testdata/shadow/root2/src/foo: hidden by $(pwd)/testdata/shadow/root1/src/foo" ]; then
echo wrong shadowed install error: "$err"
ok=false
fi
# Only succeeds if source order is preserved.
TEST source file name order preserved
./testgo test testdata/example[12]_test.go || ok=false
# Check that coverage analysis works at all.
# Don't worry about the exact numbers but require not 0.0%.
checkcoverage() {
if grep '[^0-9]0\.0%' testdata/cover.txt >/dev/null; then
echo 'some coverage results are 0.0%'
ok=false
fi
cat testdata/cover.txt
rm -f testdata/cover.txt
}
TEST coverage runs
./testgo test -short -coverpkg=strings strings regexp >testdata/cover.txt 2>&1 || ok=false
./testgo test -short -cover strings math regexp >>testdata/cover.txt 2>&1 || ok=false
checkcoverage
# Check that coverage analysis uses set mode.
TEST coverage uses set mode
if ./testgo test -short -cover encoding/binary -coverprofile=testdata/cover.out >testdata/cover.txt 2>&1; then
if ! grep -q 'mode: set' testdata/cover.out; then
ok=false
fi
checkcoverage
else
ok=false
fi
rm -f testdata/cover.out testdata/cover.txt
TEST coverage uses atomic mode for -race.
if ./testgo test -short -race -cover encoding/binary -coverprofile=testdata/cover.out >testdata/cover.txt 2>&1; then
if ! grep -q 'mode: atomic' testdata/cover.out; then
ok=false
fi
checkcoverage
else
ok=false
fi
rm -f testdata/cover.out
TEST coverage uses actual setting to override even for -race.
if ./testgo test -short -race -cover encoding/binary -covermode=count -coverprofile=testdata/cover.out >testdata/cover.txt 2>&1; then
if ! grep -q 'mode: count' testdata/cover.out; then
ok=false
fi
checkcoverage
else
ok=false
fi
rm -f testdata/cover.out
TEST coverage with cgo
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
./testgo test -short -cover ./testdata/cgocover >testdata/cover.txt 2>&1 || ok=false
checkcoverage
TEST cgo depends on syscall
rm -rf $GOROOT/pkg/*_race
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
export GOPATH=$d
mkdir -p $d/src/foo
echo '
package foo
//#include <stdio.h>
import "C"
' >$d/src/foo/foo.go
./testgo build -race foo || ok=false
rm -rf $d
unset GOPATH
TEST cgo shows full path names
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
export GOPATH=$d
mkdir -p $d/src/x/y/dirname
echo '
package foo
import "C"
func f() {
' >$d/src/x/y/dirname/foo.go
if ./testgo build x/y/dirname >$d/err 2>&1; then
echo build succeeded unexpectedly.
ok=false
elif ! grep x/y/dirname $d/err >/dev/null; then
echo error did not use full path.
cat $d/err
ok=false
fi
rm -rf $d
unset GOPATH
TEST 'cgo handles -Wl,$ORIGIN'
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
export GOPATH=$d
mkdir -p $d/src/origin
echo '
package origin
// #cgo !darwin LDFLAGS: -Wl,-rpath -Wl,$ORIGIN
// void f(void) {}
import "C"
func f() { C.f() }
' >$d/src/origin/origin.go
if ! ./testgo build origin; then
echo build failed
ok=false
fi
rm -rf $d
unset GOPATH
TEST 'Issue 6480: "go test -c -test.bench=XXX fmt" should not hang'
if ! ./testgo test -c -test.bench=XXX fmt; then
echo build test failed
ok=false
fi
rm -f fmt.test
TEST 'Issue 7573: cmd/cgo: undefined reference when linking a C-library using gccgo'
d=$(mktemp -d -t testgoXXX)
export GOPATH=$d
mkdir -p $d/src/cgoref
ldflags="-L alibpath -lalib"
echo "
package main
// #cgo LDFLAGS: $ldflags
// void f(void) {}
import \"C\"
func main() { C.f() }
" >$d/src/cgoref/cgoref.go
go_cmds="$(./testgo build -n -compiler gccgo cgoref 2>&1 1>/dev/null)"
ldflags_count="$(echo "$go_cmds" | egrep -c "^gccgo.*$(echo $ldflags | sed -e 's/-/\\-/g')" || true)"
if [ "$ldflags_count" -lt 1 ]; then
echo "No Go-inline "#cgo LDFLAGS:" (\"$ldflags\") passed to gccgo linking stage."
ok=false
fi
rm -rf $d
unset ldflags_count
unset go_cmds
unset ldflags
unset GOPATH
TEST list template can use context function
if ! ./testgo list -f "GOARCH: {{context.GOARCH}}"; then
echo unable to use context in list template
ok=false
fi
TEST 'Issue 7108: cmd/go: "go test" should fail if package does not build'
export GOPATH=$(pwd)/testdata
if ./testgo test notest >/dev/null 2>&1; then
echo 'go test notest succeeded, but should fail'
ok=false
fi
unset GOPATH
TEST 'Issue 6844: cmd/go: go test -a foo does not rebuild regexp'
if ! ./testgo test -x -a -c testdata/dep_test.go 2>deplist; then
echo "go test -x -a -c testdata/dep_test.go failed"
ok=false
elif ! grep -q regexp deplist; then
echo "go test -x -a -c testdata/dep_test.go did not rebuild regexp"
ok=false
fi
rm -f deplist
rm -f deps.test
TEST list template can use context function
if ! ./testgo list -f "GOARCH: {{context.GOARCH}}"; then
echo unable to use context in list template
ok=false
fi
TEST build -i installs dependencies
d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
export GOPATH=$d
mkdir -p $d/src/x/y/foo $d/src/x/y/bar
echo '
package foo
func F() {}
' >$d/src/x/y/foo/foo.go
echo '
package bar
import "x/y/foo"
func F() { foo.F() }
' >$d/src/x/y/bar/bar.go
if ! ./testgo build -v -i x/y/bar &> $d/err; then
echo build -i failed
cat $d/err
ok=false
elif ! grep x/y/foo $d/err >/dev/null; then
echo first build -i did not build x/y/foo
cat $d/err
ok=false
fi
if ! ./testgo build -v -i x/y/bar &> $d/err; then
echo second build -i failed
cat $d/err
ok=false
elif grep x/y/foo $d/err >/dev/null; then
echo second build -i built x/y/foo
cat $d/err
ok=false
fi
rm -rf $d
unset GOPATH
TEST 'go build in test-only directory fails with a good error'
if ./testgo build ./testdata/testonly 2>testdata/err.out; then
echo "go build ./testdata/testonly succeeded, should have failed"
ok=false
elif ! grep 'no buildable Go' testdata/err.out >/dev/null; then
echo "go build ./testdata/testonly produced unexpected error:"
cat testdata/err.out
ok=false
fi
rm -f testdata/err.out
TEST 'go test detects test-only import cycles'
export GOPATH=$(pwd)/testdata
if ./testgo test -c testcycle/p3 2>testdata/err.out; then
echo "go test testcycle/p3 succeeded, should have failed"
ok=false
elif ! grep 'import cycle not allowed in test' testdata/err.out >/dev/null; then
echo "go test testcycle/p3 produced unexpected error:"
cat testdata/err.out
ok=false
fi
rm -f testdata/err.out
unset GOPATH
TEST 'go test foo_test.go works'
if ! ./testgo test testdata/standalone_test.go; then
echo "go test testdata/standalone_test.go failed"
ok=false
fi
TEST 'go test xtestonly works'
export GOPATH=$(pwd)/testdata
./testgo clean -i xtestonly
if ! ./testgo test xtestonly >/dev/null; then
echo "go test xtestonly failed"
ok=false
fi
unset GOPATH
# clean up
if $started; then stop; fi
rm -rf testdata/bin testdata/bin1
rm -f testgo
if $allok; then
echo PASS
else
echo FAIL
exit 1
fi

View File

@ -0,0 +1,6 @@
package bench
import "testing"
func Benchmark(b *testing.B) {
}

View File

@ -0,0 +1,8 @@
package p
/*
// hi
*/
import "C"
func F() {}

View File

@ -0,0 +1,2 @@
TEXT asm(SB),$0
RET

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