mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-11-27 05:44:15 +08:00
libgo: update to go1.9
Reviewed-on: https://go-review.googlesource.com/63753 From-SVN: r252767
This commit is contained in:
parent
a41a6142df
commit
bc998d034f
@ -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.
|
||||
|
@ -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")
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -1 +1 @@
|
||||
go1.8.3
|
||||
go1.9
|
||||
|
2
libgo/configure
vendored
2
libgo/configure
vendored
@ -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
|
||||
|
@ -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(, ..)
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -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}
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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 = '☺'
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -7,3 +7,4 @@ package bytes
|
||||
// Export func for testing
|
||||
var IndexBytePortable = indexBytePortable
|
||||
var EqualPortable = equalPortable
|
||||
var CountGeneric = countGeneric
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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]¬SignedIntConst != 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)
|
||||
|
@ -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.
|
||||
|
@ -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))
|
||||
|
@ -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.
|
||||
//
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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"))
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
173
libgo/go/cmd/go/internal/base/base.go
Normal file
173
libgo/go/cmd/go/internal/base/base.go
Normal 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
|
||||
}
|
37
libgo/go/cmd/go/internal/base/env.go
Normal file
37
libgo/go/cmd/go/internal/base/env.go
Normal 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
|
||||
}
|
35
libgo/go/cmd/go/internal/base/flag.go
Normal file
35
libgo/go/cmd/go/internal/base/flag.go
Normal 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, "")
|
||||
}
|
74
libgo/go/cmd/go/internal/base/path.go
Normal file
74
libgo/go/cmd/go/internal/base/path.go
Normal 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")
|
||||
}
|
@ -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)
|
||||
}
|
@ -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
|
@ -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
|
53
libgo/go/cmd/go/internal/base/tool.go
Normal file
53
libgo/go/cmd/go/internal/base/tool.go
Normal 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
|
||||
}
|
@ -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
|
201
libgo/go/cmd/go/internal/buildid/buildid.go
Normal file
201
libgo/go/cmd/go/internal/buildid/buildid.go
Normal 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
|
||||
}
|
@ -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
|
134
libgo/go/cmd/go/internal/cfg/cfg.go
Normal file
134
libgo/go/cmd/go/internal/cfg/cfg.go
Normal 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()
|
||||
}
|
@ -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)
|
||||
}
|
123
libgo/go/cmd/go/internal/cmdflag/flag.go
Normal file
123
libgo/go/cmd/go/internal/cmdflag/flag.go
Normal 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
|
||||
}
|
@ -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)
|
||||
}
|
178
libgo/go/cmd/go/internal/envcmd/env.go
Normal file
178
libgo/go/cmd/go/internal/envcmd/env.go
Normal 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)
|
||||
}
|
||||
}
|
@ -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))
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
@ -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)
|
@ -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"
|
@ -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"
|
@ -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
|
||||
}
|
83
libgo/go/cmd/go/internal/get/pkg_test.go
Normal file
83
libgo/go/cmd/go/internal/get/pkg_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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"
|
||||
|
@ -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}")
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
178
libgo/go/cmd/go/internal/help/help.go
Normal file
178
libgo/go/cmd/go/internal/help/help.go
Normal 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()
|
||||
}
|
@ -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
|
@ -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"
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
165
libgo/go/cmd/go/internal/load/match_test.go
Normal file
165
libgo/go/cmd/go/internal/load/match_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
80
libgo/go/cmd/go/internal/load/path.go
Normal file
80
libgo/go/cmd/go/internal/load/path.go
Normal 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
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
338
libgo/go/cmd/go/internal/load/search.go
Normal file
338
libgo/go/cmd/go/internal/load/search.go
Normal 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"
|
||||
}
|
@ -10,7 +10,7 @@
|
||||
|
||||
// +build testgo
|
||||
|
||||
package main
|
||||
package load
|
||||
|
||||
import "os"
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
141
libgo/go/cmd/go/internal/str/str.go
Normal file
141
libgo/go/cmd/go/internal/str/str.go
Normal 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
|
||||
}
|
File diff suppressed because it is too large
Load Diff
211
libgo/go/cmd/go/internal/test/testflag.go
Normal file
211
libgo/go/cmd/go/internal/test/testflag.go
Normal 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
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
56
libgo/go/cmd/go/internal/vet/vet.go
Normal file
56
libgo/go/cmd/go/internal/vet/vet.go
Normal 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))
|
||||
}
|
99
libgo/go/cmd/go/internal/vet/vetflag.go
Normal file
99
libgo/go/cmd/go/internal/vet/vetflag.go
Normal 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
|
||||
}
|
@ -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") }
|
@ -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) }
|
16
libgo/go/cmd/go/internal/web/security.go
Normal file
16
libgo/go/cmd/go/internal/web/security.go
Normal 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
|
||||
)
|
File diff suppressed because it is too large
Load Diff
227
libgo/go/cmd/go/internal/work/build_test.go
Normal file
227
libgo/go/cmd/go/internal/work/build_test.go
Normal 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)
|
||||
}
|
||||
}
|
17
libgo/go/cmd/go/internal/work/testgo.go
Normal file
17
libgo/go/cmd/go/internal/work/testgo.go
Normal 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
|
||||
}
|
||||
}
|
@ -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 "", ""
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
@ -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
|
@ -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.
|
||||
---
|
||||
|
@ -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
|
6
libgo/go/cmd/go/testdata/src/bench/x_test.go
vendored
Normal file
6
libgo/go/cmd/go/testdata/src/bench/x_test.go
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
package bench
|
||||
|
||||
import "testing"
|
||||
|
||||
func Benchmark(b *testing.B) {
|
||||
}
|
8
libgo/go/cmd/go/testdata/src/cgoasm/p.go
vendored
Normal file
8
libgo/go/cmd/go/testdata/src/cgoasm/p.go
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
package p
|
||||
|
||||
/*
|
||||
// hi
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func F() {}
|
2
libgo/go/cmd/go/testdata/src/cgoasm/p.s
vendored
Normal file
2
libgo/go/cmd/go/testdata/src/cgoasm/p.s
vendored
Normal 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
Loading…
Reference in New Issue
Block a user