libgo: update to Go1.18beta2

gotools/
	* Makefile.am (go_cmd_cgo_files): Add ast_go118.go
	(check-go-tool): Copy golang.org/x/tools directories.
	* Makefile.in: Regenerate.

Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/384695
devel/gccgo
Ian Lance Taylor 2022-02-11 14:53:56 -08:00
parent 9a56779dbc
commit 8dc2499aa6
1980 changed files with 84424 additions and 36492 deletions

View File

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

View File

@ -62,6 +62,7 @@ go_cmd_gofmt_files = \
go_cmd_cgo_files = \
$(cmdsrcdir)/cgo/ast.go \
$(cmdsrcdir)/cgo/ast_go118.go \
$(cmdsrcdir)/cgo/doc.go \
$(cmdsrcdir)/cgo/gcc.go \
$(cmdsrcdir)/cgo/godefs.go \
@ -224,6 +225,7 @@ check-go-tool: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc
cp -r $(libgosrcdir)/golang.org/x/mod check-go-dir/src/cmd/vendor/golang.org/x/
cp -r $(libgosrcdir)/golang.org/x/crypto check-go-dir/src/cmd/vendor/golang.org/x/
cp -r $(libgosrcdir)/golang.org/x/xerrors check-go-dir/src/cmd/vendor/golang.org/x/
cp -r $(libgosrcdir)/golang.org/x/tools check-go-dir/src/cmd/vendor/golang.org/x/
cp $(libgodir)/objabi.go check-go-dir/src/cmd/internal/objabi/
@abs_libgodir=`cd $(libgodir) && $(PWD_COMMAND)`; \
abs_checkdir=`cd check-go-dir && $(PWD_COMMAND)`; \

View File

@ -366,6 +366,7 @@ go_cmd_gofmt_files = \
go_cmd_cgo_files = \
$(cmdsrcdir)/cgo/ast.go \
$(cmdsrcdir)/cgo/ast_go118.go \
$(cmdsrcdir)/cgo/doc.go \
$(cmdsrcdir)/cgo/gcc.go \
$(cmdsrcdir)/cgo/godefs.go \
@ -896,6 +897,7 @@ mostlyclean-local:
@NATIVE_TRUE@ cp -r $(libgosrcdir)/golang.org/x/mod check-go-dir/src/cmd/vendor/golang.org/x/
@NATIVE_TRUE@ cp -r $(libgosrcdir)/golang.org/x/crypto check-go-dir/src/cmd/vendor/golang.org/x/
@NATIVE_TRUE@ cp -r $(libgosrcdir)/golang.org/x/xerrors check-go-dir/src/cmd/vendor/golang.org/x/
@NATIVE_TRUE@ cp -r $(libgosrcdir)/golang.org/x/tools check-go-dir/src/cmd/vendor/golang.org/x/
@NATIVE_TRUE@ cp $(libgodir)/objabi.go check-go-dir/src/cmd/internal/objabi/
@NATIVE_TRUE@ @abs_libgodir=`cd $(libgodir) && $(PWD_COMMAND)`; \
@NATIVE_TRUE@ abs_checkdir=`cd check-go-dir && $(PWD_COMMAND)`; \

View File

@ -1,4 +1,4 @@
21a4e67ad58e3c4a7c5254f60cda5be5c3c450ff
41f485b9a7d8fd647c415be1d11b612063dff21c
The first line of this file holds the git revision number of the
last merge done from the master library sources.

View File

@ -220,6 +220,7 @@ toolexeclibgodatabasesql_DATA = \
toolexeclibgodebugdir = $(toolexeclibgodir)/debug
toolexeclibgodebug_DATA = \
debug/buildinfo.gox \
debug/dwarf.gox \
debug/elf.gox \
debug/gosym.gox \
@ -325,6 +326,7 @@ toolexeclibgonetdir = $(toolexeclibgodir)/net
toolexeclibgonet_DATA = \
net/http.gox \
net/mail.gox \
net/netip.gox \
net/rpc.gox \
net/smtp.gox \
net/textproto.gox \
@ -429,6 +431,7 @@ noinst_DATA = \
internal/testenv.gox \
internal/trace.gox \
net/internal/socktest.gox \
os/exec/internal/fdtest.gox \
os/signal/internal/pty.gox \
reflect/internal/example1.gox \
reflect/internal/example2.gox
@ -483,53 +486,68 @@ version.go: s-version; @true
s-version: Makefile
rm -f version.go.tmp
echo "package sys" > version.go.tmp
echo 'const GOARCH = "'$(GOARCH)'"' >> version.go.tmp
echo 'const GOOS = "'$(GOOS)'"' >> version.go.tmp
echo 'const GccgoToolDir = "$(libexecsubdir)"' >> version.go.tmp
echo 'const StackGuardMultiplierDefault = 1' >> version.go.tmp
echo >> version.go.tmp
echo "const (" >> version.go.tmp
echo " UNKNOWN ArchFamilyType = iota" >> version.go.tmp
$(SHELL) $(srcdir)/mvifdiff.sh version.go.tmp version.go
$(STAMP) $@
zgoarch.go: s-zgoarch; @true
s-zgoarch: Makefile goarch.sh
rm -f zgoarch.go.tmp
echo "package goarch" > zgoarch.go.tmp
echo >> zgoarch.go.tmp
echo 'const GOARCH = "'$(GOARCH)'"' >> zgoarch.go.tmp
echo >> zgoarch.go.tmp
echo 'const (' >> zgoarch.go.tmp
echo " _ArchFamily = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) family`" >> zgoarch.go.tmp
echo " _BigEndian = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) bigendian`" >> zgoarch.go.tmp
echo " _DefaultPhysPageSize = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) defaultphyspagesize`" >> zgoarch.go.tmp
echo " _Int64Align = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) int64align`" >> zgoarch.go.tmp
echo " _MinFrameSize = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) minframesize`" >> zgoarch.go.tmp
echo " _PCQuantum = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) pcquantum`" >> zgoarch.go.tmp
echo " _StackAlign = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) stackalign`" >> zgoarch.go.tmp
echo ")" >> zgoarch.go.tmp
echo >> zgoarch.go.tmp
echo "const (" >> zgoarch.go.tmp
echo " UNKNOWN ArchFamilyType = iota" >> zgoarch.go.tmp
for a in $(ALLGOARCHFAMILY); do \
echo " $${a}" >> version.go.tmp; \
echo " $${a}" >> zgoarch.go.tmp; \
done
echo ")" >> version.go.tmp
echo >> version.go.tmp
echo ")" >> zgoarch.go.tmp
echo >> zgoarch.go.tmp
for a in $(ALLGOARCH); do \
f=`echo $${a} | sed -e 's/\(.\).*/\1/' -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`; \
n="$${f}`echo $${a} | sed -e 's/.//'`"; \
if test "$${a}" = "$(GOARCH)"; then \
echo "const Goarch$${n} = 1" >> version.go.tmp; \
echo "const Is$${n} = 1" >> zgoarch.go.tmp; \
else \
echo "const Goarch$${n} = 0" >> version.go.tmp; \
echo "const Is$${n} = 0" >> zgoarch.go.tmp; \
fi; \
done
echo >> version.go.tmp
echo "const (" >> version.go.tmp
echo " _ArchFamily = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) family`" >> version.go.tmp
echo " _BigEndian = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) bigendian`" >> version.go.tmp
echo " _DefaultPhysPageSize = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) defaultphyspagesize`" >> version.go.tmp
echo " _Int64Align = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) int64align`" >> version.go.tmp
echo " _MinFrameSize = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) minframesize`" >> version.go.tmp
echo " _PCQuantum = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) pcquantum`" >> version.go.tmp
echo " _StackAlign = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) stackalign`" >> version.go.tmp
echo ")" >> version.go.tmp
echo >> version.go.tmp
$(SHELL) $(srcdir)/mvifdiff.sh zgoarch.go.tmp zgoarch.go
$(STAMP) $@
zgoos.go: s-zgoos; @true
s-zgoos: Makefile
rm -f zgoos.go.tmp
echo "package goos" > zgoos.go.tmp
echo >> zgoos.go.tmp
echo 'const GOOS = "'$(GOOS)'"' >> zgoos.go.tmp
echo >> zgoos.go.tmp
for a in $(ALLGOOS); do \
f=`echo $${a} | sed -e 's/\(.\).*/\1/' -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`; \
n="$${f}`echo $${a} | sed -e 's/.//'`"; \
if test "$${a}" = "$(GOOS)"; then \
echo "const Goos$${n} = 1" >> version.go.tmp; \
echo "const Is$${n} = 1" >> zgoos.go.tmp; \
else \
echo "const Goos$${n} = 0" >> version.go.tmp; \
echo "const Is$${n} = 0" >> zgoos.go.tmp; \
fi; \
done
echo >> version.go.tmp
$(SHELL) $(srcdir)/mvifdiff.sh version.go.tmp version.go
$(SHELL) $(srcdir)/mvifdiff.sh zgoos.go.tmp zgoos.go
$(STAMP) $@
cpugen.go: s-cpu; @true
s-cpu: Makefile
s-cpu: Makefile goarch.sh
rm -f cpugen.go.tmp
echo "package cpu" > cpugen.go.tmp
echo "const CacheLinePadSize = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) cachelinesize`" >> cpugen.go.tmp
@ -538,7 +556,7 @@ s-cpu: Makefile
$(STAMP) $@
gcpugen.go: s-gcpu; @true
s-gcpu: Makefile
s-gcpu: Makefile goarch.sh
rm -f gcpugen.go.tmp
echo "package cpu" > gcpugen.go.tmp
echo "const cacheLineSize = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) cachelinesize`" >> gcpugen.go.tmp
@ -560,6 +578,7 @@ s-buildcfg: Makefile
echo "import \"runtime\"" >> buildcfg.go.tmp
echo 'func defaultGOROOTValue() string { return `$(prefix)` }' >> buildcfg.go.tmp
echo 'const defaultGO386 = `sse2`' >> buildcfg.go.tmp
echo 'const defaultGOAMD64 = `v1`' >> buildcfg.go.tmp
echo 'const defaultGOARM = `5`' >> buildcfg.go.tmp
echo 'const defaultGOMIPS = `hardfloat`' >> buildcfg.go.tmp
echo 'const defaultGOMIPS64 = `hardfloat`' >> buildcfg.go.tmp
@ -813,7 +832,8 @@ libgo_ldflags = \
libgo_libadd = \
$(libgo_go_objs) ../libbacktrace/libbacktrace.la \
$(LIBATOMIC) $(LIBFFI) $(PTHREAD_LIBS) $(MATH_LIBS) $(NET_LIBS)
$(LIBATOMIC) $(LIBFFI) $(PTHREAD_LIBS) $(MATH_LIBS) \
$(NET_LIBS) $(RT_LIBS)
libgo_la_SOURCES = $(runtime_files)
libgo_la_LDFLAGS = $(libgo_ldflags)
@ -904,7 +924,7 @@ GOBENCH =
CHECK = \
GC="$(GOC) $(GOCFLAGS) $($(subst /,_,$@)_GOCFLAGS) -L `${PWD_COMMAND}` -L `${PWD_COMMAND}`/.libs"; \
export GC; \
GOLIBS="$(extra_check_libs_$(subst .,_,$(subst /,_,$(@D)))) $(PTHREAD_LIBS) $(MATH_LIBS) $(NET_LIBS) $(LIBS)"; \
GOLIBS="$(extra_check_libs_$(subst .,_,$(subst /,_,$(@D)))) $(PTHREAD_LIBS) $(MATH_LIBS) $(NET_LIBS) $(RT_LIBS) $(LIBS)"; \
export GOLIBS; \
RUNTESTFLAGS="$(RUNTESTFLAGS)"; \
export RUNTESTFLAGS; \
@ -1065,6 +1085,12 @@ runtime/internal/sys.lo.dep: $(extra_go_files_runtime_internal_sys)
extra_go_files_internal_cpu = cpugen.go
internal/cpu.lo.dep: $(extra_go_files_internal_cpu)
extra_go_files_internal_goarch = zgoarch.go
internal/goarch.lo.dep: $(extra_go_files_internal_goarch)
extra_go_files_internal_goos = zgoos.go
internal/goos.lo.dep: $(extra_go_files_internal_goos)
extra_go_files_golang_org_x_sys_cpu = gcpugen.go
golang.org/x/sys/cpu.lo.dep: $(extra_go_files_golang_org_x_sys_cpu)

View File

@ -233,7 +233,8 @@ am__DEPENDENCIES_4 =
am__DEPENDENCIES_5 = $(am__DEPENDENCIES_3) \
../libbacktrace/libbacktrace.la $(am__DEPENDENCIES_4) \
$(am__DEPENDENCIES_4) $(am__DEPENDENCIES_4) \
$(am__DEPENDENCIES_4) $(am__DEPENDENCIES_4)
$(am__DEPENDENCIES_4) $(am__DEPENDENCIES_4) \
$(am__DEPENDENCIES_4)
libgo_llgo_la_DEPENDENCIES = $(am__DEPENDENCIES_5)
@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_X86_TRUE@am__objects_1 = \
@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_X86_TRUE@ runtime/go-context.lo
@ -465,6 +466,7 @@ PATH_SEPARATOR = @PATH_SEPARATOR@
PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
PTHREAD_LIBS = @PTHREAD_LIBS@
RANLIB = @RANLIB@
RT_LIBS = @RT_LIBS@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
@ -712,6 +714,7 @@ toolexeclibgodatabasesql_DATA = \
toolexeclibgodebugdir = $(toolexeclibgodir)/debug
toolexeclibgodebug_DATA = \
debug/buildinfo.gox \
debug/dwarf.gox \
debug/elf.gox \
debug/gosym.gox \
@ -804,6 +807,7 @@ toolexeclibgonetdir = $(toolexeclibgodir)/net
toolexeclibgonet_DATA = \
net/http.gox \
net/mail.gox \
net/netip.gox \
net/rpc.gox \
net/smtp.gox \
net/textproto.gox \
@ -892,9 +896,9 @@ toolexeclibgointernal_DATA = \
noinst_DATA = golang.org/x/net/nettest.gox internal/cfg.gox \
internal/obscuretestdata.gox internal/profile.gox \
internal/testenv.gox internal/trace.gox \
net/internal/socktest.gox os/signal/internal/pty.gox \
reflect/internal/example1.gox reflect/internal/example2.gox \
zdefaultcc.go
net/internal/socktest.gox os/exec/internal/fdtest.gox \
os/signal/internal/pty.gox reflect/internal/example1.gox \
reflect/internal/example2.gox zdefaultcc.go
@LIBGO_IS_RTEMS_FALSE@rtems_task_variable_add_file =
@LIBGO_IS_RTEMS_TRUE@rtems_task_variable_add_file = runtime/rtems-task-variable-add.c
runtime_context_asm_file = $(am__append_3)
@ -968,7 +972,8 @@ libgo_ldflags = \
libgo_libadd = \
$(libgo_go_objs) ../libbacktrace/libbacktrace.la \
$(LIBATOMIC) $(LIBFFI) $(PTHREAD_LIBS) $(MATH_LIBS) $(NET_LIBS)
$(LIBATOMIC) $(LIBFFI) $(PTHREAD_LIBS) $(MATH_LIBS) \
$(NET_LIBS) $(RT_LIBS)
libgo_la_SOURCES = $(runtime_files)
libgo_la_LDFLAGS = $(libgo_ldflags)
@ -1042,7 +1047,7 @@ GOBENCH =
CHECK = \
GC="$(GOC) $(GOCFLAGS) $($(subst /,_,$@)_GOCFLAGS) -L `${PWD_COMMAND}` -L `${PWD_COMMAND}`/.libs"; \
export GC; \
GOLIBS="$(extra_check_libs_$(subst .,_,$(subst /,_,$(@D)))) $(PTHREAD_LIBS) $(MATH_LIBS) $(NET_LIBS) $(LIBS)"; \
GOLIBS="$(extra_check_libs_$(subst .,_,$(subst /,_,$(@D)))) $(PTHREAD_LIBS) $(MATH_LIBS) $(NET_LIBS) $(RT_LIBS) $(LIBS)"; \
export GOLIBS; \
RUNTESTFLAGS="$(RUNTESTFLAGS)"; \
export RUNTESTFLAGS; \
@ -1138,6 +1143,8 @@ runtime_pprof_check_GOCFLAGS = -static-libgo -fno-inline
@HAVE_STATIC_LINK_TRUE@syscall_check_GOCFLAGS = -static
extra_go_files_runtime_internal_sys = version.go
extra_go_files_internal_cpu = cpugen.go
extra_go_files_internal_goarch = zgoarch.go
extra_go_files_internal_goos = zgoos.go
extra_go_files_golang_org_x_sys_cpu = gcpugen.go
extra_go_files_internal_buildcfg = buildcfg.go
extra_go_files_internal_goroot = zstdpkglist.go
@ -2692,53 +2699,68 @@ version.go: s-version; @true
s-version: Makefile
rm -f version.go.tmp
echo "package sys" > version.go.tmp
echo 'const GOARCH = "'$(GOARCH)'"' >> version.go.tmp
echo 'const GOOS = "'$(GOOS)'"' >> version.go.tmp
echo 'const GccgoToolDir = "$(libexecsubdir)"' >> version.go.tmp
echo 'const StackGuardMultiplierDefault = 1' >> version.go.tmp
echo >> version.go.tmp
echo "const (" >> version.go.tmp
echo " UNKNOWN ArchFamilyType = iota" >> version.go.tmp
$(SHELL) $(srcdir)/mvifdiff.sh version.go.tmp version.go
$(STAMP) $@
zgoarch.go: s-zgoarch; @true
s-zgoarch: Makefile goarch.sh
rm -f zgoarch.go.tmp
echo "package goarch" > zgoarch.go.tmp
echo >> zgoarch.go.tmp
echo 'const GOARCH = "'$(GOARCH)'"' >> zgoarch.go.tmp
echo >> zgoarch.go.tmp
echo 'const (' >> zgoarch.go.tmp
echo " _ArchFamily = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) family`" >> zgoarch.go.tmp
echo " _BigEndian = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) bigendian`" >> zgoarch.go.tmp
echo " _DefaultPhysPageSize = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) defaultphyspagesize`" >> zgoarch.go.tmp
echo " _Int64Align = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) int64align`" >> zgoarch.go.tmp
echo " _MinFrameSize = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) minframesize`" >> zgoarch.go.tmp
echo " _PCQuantum = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) pcquantum`" >> zgoarch.go.tmp
echo " _StackAlign = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) stackalign`" >> zgoarch.go.tmp
echo ")" >> zgoarch.go.tmp
echo >> zgoarch.go.tmp
echo "const (" >> zgoarch.go.tmp
echo " UNKNOWN ArchFamilyType = iota" >> zgoarch.go.tmp
for a in $(ALLGOARCHFAMILY); do \
echo " $${a}" >> version.go.tmp; \
echo " $${a}" >> zgoarch.go.tmp; \
done
echo ")" >> version.go.tmp
echo >> version.go.tmp
echo ")" >> zgoarch.go.tmp
echo >> zgoarch.go.tmp
for a in $(ALLGOARCH); do \
f=`echo $${a} | sed -e 's/\(.\).*/\1/' -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`; \
n="$${f}`echo $${a} | sed -e 's/.//'`"; \
if test "$${a}" = "$(GOARCH)"; then \
echo "const Goarch$${n} = 1" >> version.go.tmp; \
echo "const Is$${n} = 1" >> zgoarch.go.tmp; \
else \
echo "const Goarch$${n} = 0" >> version.go.tmp; \
echo "const Is$${n} = 0" >> zgoarch.go.tmp; \
fi; \
done
echo >> version.go.tmp
echo "const (" >> version.go.tmp
echo " _ArchFamily = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) family`" >> version.go.tmp
echo " _BigEndian = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) bigendian`" >> version.go.tmp
echo " _DefaultPhysPageSize = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) defaultphyspagesize`" >> version.go.tmp
echo " _Int64Align = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) int64align`" >> version.go.tmp
echo " _MinFrameSize = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) minframesize`" >> version.go.tmp
echo " _PCQuantum = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) pcquantum`" >> version.go.tmp
echo " _StackAlign = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) stackalign`" >> version.go.tmp
echo ")" >> version.go.tmp
echo >> version.go.tmp
$(SHELL) $(srcdir)/mvifdiff.sh zgoarch.go.tmp zgoarch.go
$(STAMP) $@
zgoos.go: s-zgoos; @true
s-zgoos: Makefile
rm -f zgoos.go.tmp
echo "package goos" > zgoos.go.tmp
echo >> zgoos.go.tmp
echo 'const GOOS = "'$(GOOS)'"' >> zgoos.go.tmp
echo >> zgoos.go.tmp
for a in $(ALLGOOS); do \
f=`echo $${a} | sed -e 's/\(.\).*/\1/' -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`; \
n="$${f}`echo $${a} | sed -e 's/.//'`"; \
if test "$${a}" = "$(GOOS)"; then \
echo "const Goos$${n} = 1" >> version.go.tmp; \
echo "const Is$${n} = 1" >> zgoos.go.tmp; \
else \
echo "const Goos$${n} = 0" >> version.go.tmp; \
echo "const Is$${n} = 0" >> zgoos.go.tmp; \
fi; \
done
echo >> version.go.tmp
$(SHELL) $(srcdir)/mvifdiff.sh version.go.tmp version.go
$(SHELL) $(srcdir)/mvifdiff.sh zgoos.go.tmp zgoos.go
$(STAMP) $@
cpugen.go: s-cpu; @true
s-cpu: Makefile
s-cpu: Makefile goarch.sh
rm -f cpugen.go.tmp
echo "package cpu" > cpugen.go.tmp
echo "const CacheLinePadSize = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) cachelinesize`" >> cpugen.go.tmp
@ -2747,7 +2769,7 @@ s-cpu: Makefile
$(STAMP) $@
gcpugen.go: s-gcpu; @true
s-gcpu: Makefile
s-gcpu: Makefile goarch.sh
rm -f gcpugen.go.tmp
echo "package cpu" > gcpugen.go.tmp
echo "const cacheLineSize = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) cachelinesize`" >> gcpugen.go.tmp
@ -2769,6 +2791,7 @@ s-buildcfg: Makefile
echo "import \"runtime\"" >> buildcfg.go.tmp
echo 'func defaultGOROOTValue() string { return `$(prefix)` }' >> buildcfg.go.tmp
echo 'const defaultGO386 = `sse2`' >> buildcfg.go.tmp
echo 'const defaultGOAMD64 = `v1`' >> buildcfg.go.tmp
echo 'const defaultGOARM = `5`' >> buildcfg.go.tmp
echo 'const defaultGOMIPS = `hardfloat`' >> buildcfg.go.tmp
echo 'const defaultGOMIPS64 = `hardfloat`' >> buildcfg.go.tmp
@ -3019,6 +3042,8 @@ 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)
internal/cpu.lo.dep: $(extra_go_files_internal_cpu)
internal/goarch.lo.dep: $(extra_go_files_internal_goarch)
internal/goos.lo.dep: $(extra_go_files_internal_goos)
golang.org/x/sys/cpu.lo.dep: $(extra_go_files_golang_org_x_sys_cpu)
cmd/internal/buildcfg.lo.dep: $(extra_go_files_internal_buildcfg)
internal/goroot.lo.dep: $(extra_go_files_internal_goroot)

View File

@ -1 +1 @@
go1.17.1
go1.18beta2

View File

@ -19,13 +19,13 @@ cmd/go/internal/par
cmd/go/internal/search
cmd/go/internal/str
cmd/go/internal/test
cmd/go/internal/txtar
cmd/go/internal/vcs
cmd/go/internal/work
cmd/internal/buildid
cmd/internal/edit
cmd/internal/objabi
cmd/internal/pkgpath
cmd/internal/quoted
cmd/internal/test2json
compress/bzip2
compress/flate
@ -46,7 +46,7 @@ crypto/ed25519
crypto/ed25519/internal/edwards25519
crypto/ed25519/internal/edwards25519/field
crypto/elliptic
crypto/elliptic/internal/fiat
crypto/elliptic/internal/nistec
crypto/hmac
crypto/internal/subtle
crypto/md5
@ -61,6 +61,7 @@ crypto/tls
crypto/x509
database/sql
database/sql/driver
debug/buildinfo
debug/dwarf
debug/elf
debug/macho
@ -110,9 +111,13 @@ image/draw
image/jpeg
image/png
index/suffixarray
internal/buildcfg
internal/cpu
internal/execabs
internal/fmtsort
internal/fuzz
internal/godebug
internal/intern
internal/itoa
internal/poll
internal/profile
@ -147,6 +152,7 @@ net/http/internal/ascii
net/http/pprof
net/internal/socktest
net/mail
net/netip
net/rpc
net/rpc/jsonrpc
net/smtp

13
libgo/configure vendored
View File

@ -649,6 +649,7 @@ HAVE_SYS_MMAN_H_FALSE
HAVE_SYS_MMAN_H_TRUE
PTHREAD_LIBS
PTHREAD_CFLAGS
RT_LIBS
NET_LIBS
MATH_LIBS
GOC_IS_LLGO_FALSE
@ -2608,7 +2609,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
ac_config_headers="$ac_config_headers config.h"
libtool_VERSION=20:0:0
libtool_VERSION=21:0:0
# Default to --enable-multilib
@ -11544,7 +11545,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
#line 11547 "configure"
#line 11548 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@ -11650,7 +11651,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
#line 11653 "configure"
#line 11654 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@ -14747,6 +14748,12 @@ $as_echo "$libgo_cv_lib_sockets" >&6; }
NET_LIBS="$libgo_cv_lib_sockets"
RT_LIBS=
case ${host} in
*-*-linux*) RT_LIBS=-lrt ;;
esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -pthread is supported" >&5
$as_echo_n "checking whether -pthread is supported... " >&6; }
if ${libgo_cv_lib_pthread+:} false; then :

View File

@ -10,7 +10,7 @@ AC_INIT(package-unused, version-unused,, libgo)
AC_CONFIG_SRCDIR(Makefile.am)
AC_CONFIG_HEADER(config.h)
libtool_VERSION=20:0:0
libtool_VERSION=21:0:0
AC_SUBST(libtool_VERSION)
AM_ENABLE_MULTILIB(, ..)
@ -549,6 +549,12 @@ AC_CACHE_CHECK([for socket libraries], libgo_cv_lib_sockets,
NET_LIBS="$libgo_cv_lib_sockets"
AC_SUBST(NET_LIBS)
RT_LIBS=
case ${host} in
*-*-linux*) RT_LIBS=-lrt ;;
esac
AC_SUBST(RT_LIBS)
dnl Test whether the compiler supports the -pthread option.
AC_CACHE_CHECK([whether -pthread is supported],
[libgo_cv_lib_pthread],

View File

@ -316,10 +316,10 @@ func invertSparseEntries(src []sparseEntry, size int64) []sparseEntry {
// fileState tracks the number of logical (includes sparse holes) and physical
// (actual in tar archive) bytes remaining for the current file.
//
// Invariant: LogicalRemaining >= PhysicalRemaining
// Invariant: logicalRemaining >= physicalRemaining
type fileState interface {
LogicalRemaining() int64
PhysicalRemaining() int64
logicalRemaining() int64
physicalRemaining() int64
}
// allowedFormats determines which formats can be used.
@ -413,22 +413,22 @@ func (h Header) allowedFormats() (format Format, paxHdrs map[string]string, err
// Check basic fields.
var blk block
v7 := blk.V7()
ustar := blk.USTAR()
gnu := blk.GNU()
verifyString(h.Name, len(v7.Name()), "Name", paxPath)
verifyString(h.Linkname, len(v7.LinkName()), "Linkname", paxLinkpath)
verifyString(h.Uname, len(ustar.UserName()), "Uname", paxUname)
verifyString(h.Gname, len(ustar.GroupName()), "Gname", paxGname)
verifyNumeric(h.Mode, len(v7.Mode()), "Mode", paxNone)
verifyNumeric(int64(h.Uid), len(v7.UID()), "Uid", paxUid)
verifyNumeric(int64(h.Gid), len(v7.GID()), "Gid", paxGid)
verifyNumeric(h.Size, len(v7.Size()), "Size", paxSize)
verifyNumeric(h.Devmajor, len(ustar.DevMajor()), "Devmajor", paxNone)
verifyNumeric(h.Devminor, len(ustar.DevMinor()), "Devminor", paxNone)
verifyTime(h.ModTime, len(v7.ModTime()), "ModTime", paxMtime)
verifyTime(h.AccessTime, len(gnu.AccessTime()), "AccessTime", paxAtime)
verifyTime(h.ChangeTime, len(gnu.ChangeTime()), "ChangeTime", paxCtime)
v7 := blk.toV7()
ustar := blk.toUSTAR()
gnu := blk.toGNU()
verifyString(h.Name, len(v7.name()), "Name", paxPath)
verifyString(h.Linkname, len(v7.linkName()), "Linkname", paxLinkpath)
verifyString(h.Uname, len(ustar.userName()), "Uname", paxUname)
verifyString(h.Gname, len(ustar.groupName()), "Gname", paxGname)
verifyNumeric(h.Mode, len(v7.mode()), "Mode", paxNone)
verifyNumeric(int64(h.Uid), len(v7.uid()), "Uid", paxUid)
verifyNumeric(int64(h.Gid), len(v7.gid()), "Gid", paxGid)
verifyNumeric(h.Size, len(v7.size()), "Size", paxSize)
verifyNumeric(h.Devmajor, len(ustar.devMajor()), "Devmajor", paxNone)
verifyNumeric(h.Devminor, len(ustar.devMinor()), "Devminor", paxNone)
verifyTime(h.ModTime, len(v7.modTime()), "ModTime", paxMtime)
verifyTime(h.AccessTime, len(gnu.accessTime()), "AccessTime", paxAtime)
verifyTime(h.ChangeTime, len(gnu.changeTime()), "ChangeTime", paxCtime)
// Check for header-only types.
var whyOnlyPAX, whyOnlyGNU string
@ -538,7 +538,7 @@ type headerFileInfo struct {
func (fi headerFileInfo) Size() int64 { return fi.h.Size }
func (fi headerFileInfo) IsDir() bool { return fi.Mode().IsDir() }
func (fi headerFileInfo) ModTime() time.Time { return fi.h.ModTime }
func (fi headerFileInfo) Sys() interface{} { return fi.h }
func (fi headerFileInfo) Sys() any { return fi.h }
// Name returns the base name of the file.
func (fi headerFileInfo) Name() string {

View File

@ -156,28 +156,28 @@ var zeroBlock block
type block [blockSize]byte
// Convert block to any number of formats.
func (b *block) V7() *headerV7 { return (*headerV7)(b) }
func (b *block) GNU() *headerGNU { return (*headerGNU)(b) }
func (b *block) STAR() *headerSTAR { return (*headerSTAR)(b) }
func (b *block) USTAR() *headerUSTAR { return (*headerUSTAR)(b) }
func (b *block) Sparse() sparseArray { return sparseArray(b[:]) }
func (b *block) toV7() *headerV7 { return (*headerV7)(b) }
func (b *block) toGNU() *headerGNU { return (*headerGNU)(b) }
func (b *block) toSTAR() *headerSTAR { return (*headerSTAR)(b) }
func (b *block) toUSTAR() *headerUSTAR { return (*headerUSTAR)(b) }
func (b *block) toSparse() sparseArray { return sparseArray(b[:]) }
// GetFormat checks that the block is a valid tar header based on the checksum.
// It then attempts to guess the specific format based on magic values.
// If the checksum fails, then FormatUnknown is returned.
func (b *block) GetFormat() Format {
func (b *block) getFormat() Format {
// Verify checksum.
var p parser
value := p.parseOctal(b.V7().Chksum())
chksum1, chksum2 := b.ComputeChecksum()
value := p.parseOctal(b.toV7().chksum())
chksum1, chksum2 := b.computeChecksum()
if p.err != nil || (value != chksum1 && value != chksum2) {
return FormatUnknown
}
// Guess the magic values.
magic := string(b.USTAR().Magic())
version := string(b.USTAR().Version())
trailer := string(b.STAR().Trailer())
magic := string(b.toUSTAR().magic())
version := string(b.toUSTAR().version())
trailer := string(b.toSTAR().trailer())
switch {
case magic == magicUSTAR && trailer == trailerSTAR:
return formatSTAR
@ -190,23 +190,23 @@ func (b *block) GetFormat() Format {
}
}
// SetFormat writes the magic values necessary for specified format
// setFormat writes the magic values necessary for specified format
// and then updates the checksum accordingly.
func (b *block) SetFormat(format Format) {
func (b *block) setFormat(format Format) {
// Set the magic values.
switch {
case format.has(formatV7):
// Do nothing.
case format.has(FormatGNU):
copy(b.GNU().Magic(), magicGNU)
copy(b.GNU().Version(), versionGNU)
copy(b.toGNU().magic(), magicGNU)
copy(b.toGNU().version(), versionGNU)
case format.has(formatSTAR):
copy(b.STAR().Magic(), magicUSTAR)
copy(b.STAR().Version(), versionUSTAR)
copy(b.STAR().Trailer(), trailerSTAR)
copy(b.toSTAR().magic(), magicUSTAR)
copy(b.toSTAR().version(), versionUSTAR)
copy(b.toSTAR().trailer(), trailerSTAR)
case format.has(FormatUSTAR | FormatPAX):
copy(b.USTAR().Magic(), magicUSTAR)
copy(b.USTAR().Version(), versionUSTAR)
copy(b.toUSTAR().magic(), magicUSTAR)
copy(b.toUSTAR().version(), versionUSTAR)
default:
panic("invalid format")
}
@ -214,17 +214,17 @@ func (b *block) SetFormat(format Format) {
// Update checksum.
// This field is special in that it is terminated by a NULL then space.
var f formatter
field := b.V7().Chksum()
chksum, _ := b.ComputeChecksum() // Possible values are 256..128776
field := b.toV7().chksum()
chksum, _ := b.computeChecksum() // Possible values are 256..128776
f.formatOctal(field[:7], chksum) // Never fails since 128776 < 262143
field[7] = ' '
}
// ComputeChecksum computes the checksum for the header block.
// computeChecksum computes the checksum for the header block.
// POSIX specifies a sum of the unsigned byte values, but the Sun tar used
// signed byte values.
// We compute and return both.
func (b *block) ComputeChecksum() (unsigned, signed int64) {
func (b *block) computeChecksum() (unsigned, signed int64) {
for i, c := range b {
if 148 <= i && i < 156 {
c = ' ' // Treat the checksum field itself as all spaces.
@ -236,68 +236,68 @@ func (b *block) ComputeChecksum() (unsigned, signed int64) {
}
// Reset clears the block with all zeros.
func (b *block) Reset() {
func (b *block) reset() {
*b = block{}
}
type headerV7 [blockSize]byte
func (h *headerV7) Name() []byte { return h[000:][:100] }
func (h *headerV7) Mode() []byte { return h[100:][:8] }
func (h *headerV7) UID() []byte { return h[108:][:8] }
func (h *headerV7) GID() []byte { return h[116:][:8] }
func (h *headerV7) Size() []byte { return h[124:][:12] }
func (h *headerV7) ModTime() []byte { return h[136:][:12] }
func (h *headerV7) Chksum() []byte { return h[148:][:8] }
func (h *headerV7) TypeFlag() []byte { return h[156:][:1] }
func (h *headerV7) LinkName() []byte { return h[157:][:100] }
func (h *headerV7) name() []byte { return h[000:][:100] }
func (h *headerV7) mode() []byte { return h[100:][:8] }
func (h *headerV7) uid() []byte { return h[108:][:8] }
func (h *headerV7) gid() []byte { return h[116:][:8] }
func (h *headerV7) size() []byte { return h[124:][:12] }
func (h *headerV7) modTime() []byte { return h[136:][:12] }
func (h *headerV7) chksum() []byte { return h[148:][:8] }
func (h *headerV7) typeFlag() []byte { return h[156:][:1] }
func (h *headerV7) linkName() []byte { return h[157:][:100] }
type headerGNU [blockSize]byte
func (h *headerGNU) V7() *headerV7 { return (*headerV7)(h) }
func (h *headerGNU) Magic() []byte { return h[257:][:6] }
func (h *headerGNU) Version() []byte { return h[263:][:2] }
func (h *headerGNU) UserName() []byte { return h[265:][:32] }
func (h *headerGNU) GroupName() []byte { return h[297:][:32] }
func (h *headerGNU) DevMajor() []byte { return h[329:][:8] }
func (h *headerGNU) DevMinor() []byte { return h[337:][:8] }
func (h *headerGNU) AccessTime() []byte { return h[345:][:12] }
func (h *headerGNU) ChangeTime() []byte { return h[357:][:12] }
func (h *headerGNU) Sparse() sparseArray { return sparseArray(h[386:][:24*4+1]) }
func (h *headerGNU) RealSize() []byte { return h[483:][:12] }
func (h *headerGNU) v7() *headerV7 { return (*headerV7)(h) }
func (h *headerGNU) magic() []byte { return h[257:][:6] }
func (h *headerGNU) version() []byte { return h[263:][:2] }
func (h *headerGNU) userName() []byte { return h[265:][:32] }
func (h *headerGNU) groupName() []byte { return h[297:][:32] }
func (h *headerGNU) devMajor() []byte { return h[329:][:8] }
func (h *headerGNU) devMinor() []byte { return h[337:][:8] }
func (h *headerGNU) accessTime() []byte { return h[345:][:12] }
func (h *headerGNU) changeTime() []byte { return h[357:][:12] }
func (h *headerGNU) sparse() sparseArray { return sparseArray(h[386:][:24*4+1]) }
func (h *headerGNU) realSize() []byte { return h[483:][:12] }
type headerSTAR [blockSize]byte
func (h *headerSTAR) V7() *headerV7 { return (*headerV7)(h) }
func (h *headerSTAR) Magic() []byte { return h[257:][:6] }
func (h *headerSTAR) Version() []byte { return h[263:][:2] }
func (h *headerSTAR) UserName() []byte { return h[265:][:32] }
func (h *headerSTAR) GroupName() []byte { return h[297:][:32] }
func (h *headerSTAR) DevMajor() []byte { return h[329:][:8] }
func (h *headerSTAR) DevMinor() []byte { return h[337:][:8] }
func (h *headerSTAR) Prefix() []byte { return h[345:][:131] }
func (h *headerSTAR) AccessTime() []byte { return h[476:][:12] }
func (h *headerSTAR) ChangeTime() []byte { return h[488:][:12] }
func (h *headerSTAR) Trailer() []byte { return h[508:][:4] }
func (h *headerSTAR) v7() *headerV7 { return (*headerV7)(h) }
func (h *headerSTAR) magic() []byte { return h[257:][:6] }
func (h *headerSTAR) version() []byte { return h[263:][:2] }
func (h *headerSTAR) userName() []byte { return h[265:][:32] }
func (h *headerSTAR) groupName() []byte { return h[297:][:32] }
func (h *headerSTAR) devMajor() []byte { return h[329:][:8] }
func (h *headerSTAR) devMinor() []byte { return h[337:][:8] }
func (h *headerSTAR) prefix() []byte { return h[345:][:131] }
func (h *headerSTAR) accessTime() []byte { return h[476:][:12] }
func (h *headerSTAR) changeTime() []byte { return h[488:][:12] }
func (h *headerSTAR) trailer() []byte { return h[508:][:4] }
type headerUSTAR [blockSize]byte
func (h *headerUSTAR) V7() *headerV7 { return (*headerV7)(h) }
func (h *headerUSTAR) Magic() []byte { return h[257:][:6] }
func (h *headerUSTAR) Version() []byte { return h[263:][:2] }
func (h *headerUSTAR) UserName() []byte { return h[265:][:32] }
func (h *headerUSTAR) GroupName() []byte { return h[297:][:32] }
func (h *headerUSTAR) DevMajor() []byte { return h[329:][:8] }
func (h *headerUSTAR) DevMinor() []byte { return h[337:][:8] }
func (h *headerUSTAR) Prefix() []byte { return h[345:][:155] }
func (h *headerUSTAR) v7() *headerV7 { return (*headerV7)(h) }
func (h *headerUSTAR) magic() []byte { return h[257:][:6] }
func (h *headerUSTAR) version() []byte { return h[263:][:2] }
func (h *headerUSTAR) userName() []byte { return h[265:][:32] }
func (h *headerUSTAR) groupName() []byte { return h[297:][:32] }
func (h *headerUSTAR) devMajor() []byte { return h[329:][:8] }
func (h *headerUSTAR) devMinor() []byte { return h[337:][:8] }
func (h *headerUSTAR) prefix() []byte { return h[345:][:155] }
type sparseArray []byte
func (s sparseArray) Entry(i int) sparseElem { return sparseElem(s[i*24:]) }
func (s sparseArray) IsExtended() []byte { return s[24*s.MaxEntries():][:1] }
func (s sparseArray) MaxEntries() int { return len(s) / 24 }
func (s sparseArray) entry(i int) sparseElem { return sparseElem(s[i*24:]) }
func (s sparseArray) isExtended() []byte { return s[24*s.maxEntries():][:1] }
func (s sparseArray) maxEntries() int { return len(s) / 24 }
type sparseElem []byte
func (s sparseElem) Offset() []byte { return s[00:][:12] }
func (s sparseElem) Length() []byte { return s[12:][:12] }
func (s sparseElem) offset() []byte { return s[00:][:12] }
func (s sparseElem) length() []byte { return s[12:][:12] }

View File

@ -0,0 +1,80 @@
// Copyright 2021 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 tar
import (
"bytes"
"io"
"testing"
)
func FuzzReader(f *testing.F) {
b := bytes.NewBuffer(nil)
w := NewWriter(b)
inp := []byte("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")
err := w.WriteHeader(&Header{
Name: "lorem.txt",
Mode: 0600,
Size: int64(len(inp)),
})
if err != nil {
f.Fatalf("failed to create writer: %s", err)
}
_, err = w.Write(inp)
if err != nil {
f.Fatalf("failed to write file to archive: %s", err)
}
if err := w.Close(); err != nil {
f.Fatalf("failed to write archive: %s", err)
}
f.Add(b.Bytes())
f.Fuzz(func(t *testing.T, b []byte) {
r := NewReader(bytes.NewReader(b))
type file struct {
header *Header
content []byte
}
files := []file{}
for {
hdr, err := r.Next()
if err == io.EOF {
break
}
if err != nil {
return
}
buf := bytes.NewBuffer(nil)
if _, err := io.Copy(buf, r); err != nil {
continue
}
files = append(files, file{header: hdr, content: buf.Bytes()})
}
// If we were unable to read anything out of the archive don't
// bother trying to roundtrip it.
if len(files) == 0 {
return
}
out := bytes.NewBuffer(nil)
w := NewWriter(out)
for _, f := range files {
if err := w.WriteHeader(f.header); err != nil {
t.Fatalf("unable to write previously parsed header: %s", err)
}
if _, err := w.Write(f.content); err != nil {
t.Fatalf("unable to write previously parsed content: %s", err)
}
}
if err := w.Close(); err != nil {
t.Fatalf("Unable to write archive: %s", err)
}
// TODO: We may want to check if the archive roundtrips. This would require
// taking into account addition of the two zero trailer blocks that Writer.Close
// appends.
})
}

View File

@ -65,7 +65,7 @@ func (tr *Reader) next() (*Header, error) {
format := FormatUSTAR | FormatPAX | FormatGNU
for {
// Discard the remainder of the file and any padding.
if err := discard(tr.r, tr.curr.PhysicalRemaining()); err != nil {
if err := discard(tr.r, tr.curr.physicalRemaining()); err != nil {
return nil, err
}
if _, err := tryReadFull(tr.r, tr.blk[:tr.pad]); err != nil {
@ -355,7 +355,7 @@ func (tr *Reader) readHeader() (*Header, *block, error) {
}
// Verify the header matches a known format.
format := tr.blk.GetFormat()
format := tr.blk.getFormat()
if format == FormatUnknown {
return nil, nil, ErrHeader
}
@ -364,30 +364,30 @@ func (tr *Reader) readHeader() (*Header, *block, error) {
hdr := new(Header)
// Unpack the V7 header.
v7 := tr.blk.V7()
hdr.Typeflag = v7.TypeFlag()[0]
hdr.Name = p.parseString(v7.Name())
hdr.Linkname = p.parseString(v7.LinkName())
hdr.Size = p.parseNumeric(v7.Size())
hdr.Mode = p.parseNumeric(v7.Mode())
hdr.Uid = int(p.parseNumeric(v7.UID()))
hdr.Gid = int(p.parseNumeric(v7.GID()))
hdr.ModTime = time.Unix(p.parseNumeric(v7.ModTime()), 0)
v7 := tr.blk.toV7()
hdr.Typeflag = v7.typeFlag()[0]
hdr.Name = p.parseString(v7.name())
hdr.Linkname = p.parseString(v7.linkName())
hdr.Size = p.parseNumeric(v7.size())
hdr.Mode = p.parseNumeric(v7.mode())
hdr.Uid = int(p.parseNumeric(v7.uid()))
hdr.Gid = int(p.parseNumeric(v7.gid()))
hdr.ModTime = time.Unix(p.parseNumeric(v7.modTime()), 0)
// Unpack format specific fields.
if format > formatV7 {
ustar := tr.blk.USTAR()
hdr.Uname = p.parseString(ustar.UserName())
hdr.Gname = p.parseString(ustar.GroupName())
hdr.Devmajor = p.parseNumeric(ustar.DevMajor())
hdr.Devminor = p.parseNumeric(ustar.DevMinor())
ustar := tr.blk.toUSTAR()
hdr.Uname = p.parseString(ustar.userName())
hdr.Gname = p.parseString(ustar.groupName())
hdr.Devmajor = p.parseNumeric(ustar.devMajor())
hdr.Devminor = p.parseNumeric(ustar.devMinor())
var prefix string
switch {
case format.has(FormatUSTAR | FormatPAX):
hdr.Format = format
ustar := tr.blk.USTAR()
prefix = p.parseString(ustar.Prefix())
ustar := tr.blk.toUSTAR()
prefix = p.parseString(ustar.prefix())
// For Format detection, check if block is properly formatted since
// the parser is more liberal than what USTAR actually permits.
@ -396,23 +396,23 @@ func (tr *Reader) readHeader() (*Header, *block, error) {
hdr.Format = FormatUnknown // Non-ASCII characters in block.
}
nul := func(b []byte) bool { return int(b[len(b)-1]) == 0 }
if !(nul(v7.Size()) && nul(v7.Mode()) && nul(v7.UID()) && nul(v7.GID()) &&
nul(v7.ModTime()) && nul(ustar.DevMajor()) && nul(ustar.DevMinor())) {
if !(nul(v7.size()) && nul(v7.mode()) && nul(v7.uid()) && nul(v7.gid()) &&
nul(v7.modTime()) && nul(ustar.devMajor()) && nul(ustar.devMinor())) {
hdr.Format = FormatUnknown // Numeric fields must end in NUL
}
case format.has(formatSTAR):
star := tr.blk.STAR()
prefix = p.parseString(star.Prefix())
hdr.AccessTime = time.Unix(p.parseNumeric(star.AccessTime()), 0)
hdr.ChangeTime = time.Unix(p.parseNumeric(star.ChangeTime()), 0)
star := tr.blk.toSTAR()
prefix = p.parseString(star.prefix())
hdr.AccessTime = time.Unix(p.parseNumeric(star.accessTime()), 0)
hdr.ChangeTime = time.Unix(p.parseNumeric(star.changeTime()), 0)
case format.has(FormatGNU):
hdr.Format = format
var p2 parser
gnu := tr.blk.GNU()
if b := gnu.AccessTime(); b[0] != 0 {
gnu := tr.blk.toGNU()
if b := gnu.accessTime(); b[0] != 0 {
hdr.AccessTime = time.Unix(p2.parseNumeric(b), 0)
}
if b := gnu.ChangeTime(); b[0] != 0 {
if b := gnu.changeTime(); b[0] != 0 {
hdr.ChangeTime = time.Unix(p2.parseNumeric(b), 0)
}
@ -439,8 +439,8 @@ func (tr *Reader) readHeader() (*Header, *block, error) {
// See https://golang.org/issues/21005
if p2.err != nil {
hdr.AccessTime, hdr.ChangeTime = time.Time{}, time.Time{}
ustar := tr.blk.USTAR()
if s := p.parseString(ustar.Prefix()); isASCII(s) {
ustar := tr.blk.toUSTAR()
if s := p.parseString(ustar.prefix()); isASCII(s) {
prefix = s
}
hdr.Format = FormatUnknown // Buggy file is not GNU
@ -465,38 +465,38 @@ func (tr *Reader) readOldGNUSparseMap(hdr *Header, blk *block) (sparseDatas, err
// Make sure that the input format is GNU.
// Unfortunately, the STAR format also has a sparse header format that uses
// the same type flag but has a completely different layout.
if blk.GetFormat() != FormatGNU {
if blk.getFormat() != FormatGNU {
return nil, ErrHeader
}
hdr.Format.mayOnlyBe(FormatGNU)
var p parser
hdr.Size = p.parseNumeric(blk.GNU().RealSize())
hdr.Size = p.parseNumeric(blk.toGNU().realSize())
if p.err != nil {
return nil, p.err
}
s := blk.GNU().Sparse()
spd := make(sparseDatas, 0, s.MaxEntries())
s := blk.toGNU().sparse()
spd := make(sparseDatas, 0, s.maxEntries())
for {
for i := 0; i < s.MaxEntries(); i++ {
for i := 0; i < s.maxEntries(); i++ {
// This termination condition is identical to GNU and BSD tar.
if s.Entry(i).Offset()[0] == 0x00 {
if s.entry(i).offset()[0] == 0x00 {
break // Don't return, need to process extended headers (even if empty)
}
offset := p.parseNumeric(s.Entry(i).Offset())
length := p.parseNumeric(s.Entry(i).Length())
offset := p.parseNumeric(s.entry(i).offset())
length := p.parseNumeric(s.entry(i).length())
if p.err != nil {
return nil, p.err
}
spd = append(spd, sparseEntry{Offset: offset, Length: length})
}
if s.IsExtended()[0] > 0 {
if s.isExtended()[0] > 0 {
// There are more entries. Read an extension header and parse its entries.
if _, err := mustReadFull(tr.r, blk[:]); err != nil {
return nil, err
}
s = blk.Sparse()
s = blk.toSparse()
continue
}
return spd, nil // Done
@ -678,11 +678,13 @@ func (fr *regFileReader) WriteTo(w io.Writer) (int64, error) {
return io.Copy(w, struct{ io.Reader }{fr})
}
func (fr regFileReader) LogicalRemaining() int64 {
// logicalRemaining implements fileState.logicalRemaining.
func (fr regFileReader) logicalRemaining() int64 {
return fr.nb
}
func (fr regFileReader) PhysicalRemaining() int64 {
// logicalRemaining implements fileState.physicalRemaining.
func (fr regFileReader) physicalRemaining() int64 {
return fr.nb
}
@ -694,9 +696,9 @@ type sparseFileReader struct {
}
func (sr *sparseFileReader) Read(b []byte) (n int, err error) {
finished := int64(len(b)) >= sr.LogicalRemaining()
finished := int64(len(b)) >= sr.logicalRemaining()
if finished {
b = b[:sr.LogicalRemaining()]
b = b[:sr.logicalRemaining()]
}
b0 := b
@ -724,7 +726,7 @@ func (sr *sparseFileReader) Read(b []byte) (n int, err error) {
return n, errMissData // Less data in dense file than sparse file
case err != nil:
return n, err
case sr.LogicalRemaining() == 0 && sr.PhysicalRemaining() > 0:
case sr.logicalRemaining() == 0 && sr.physicalRemaining() > 0:
return n, errUnrefData // More data in dense file than sparse file
case finished:
return n, io.EOF
@ -746,7 +748,7 @@ func (sr *sparseFileReader) WriteTo(w io.Writer) (n int64, err error) {
var writeLastByte bool
pos0 := sr.pos
for sr.LogicalRemaining() > 0 && !writeLastByte && err == nil {
for sr.logicalRemaining() > 0 && !writeLastByte && err == nil {
var nf int64 // Size of fragment
holeStart, holeEnd := sr.sp[0].Offset, sr.sp[0].endOffset()
if sr.pos < holeStart { // In a data fragment
@ -754,7 +756,7 @@ func (sr *sparseFileReader) WriteTo(w io.Writer) (n int64, err error) {
nf, err = io.CopyN(ws, sr.fr, nf)
} else { // In a hole fragment
nf = holeEnd - sr.pos
if sr.PhysicalRemaining() == 0 {
if sr.physicalRemaining() == 0 {
writeLastByte = true
nf--
}
@ -779,18 +781,18 @@ func (sr *sparseFileReader) WriteTo(w io.Writer) (n int64, err error) {
return n, errMissData // Less data in dense file than sparse file
case err != nil:
return n, err
case sr.LogicalRemaining() == 0 && sr.PhysicalRemaining() > 0:
case sr.logicalRemaining() == 0 && sr.physicalRemaining() > 0:
return n, errUnrefData // More data in dense file than sparse file
default:
return n, nil
}
}
func (sr sparseFileReader) LogicalRemaining() int64 {
func (sr sparseFileReader) logicalRemaining() int64 {
return sr.sp[len(sr.sp)-1].endOffset() - sr.pos
}
func (sr sparseFileReader) PhysicalRemaining() int64 {
return sr.fr.PhysicalRemaining()
func (sr sparseFileReader) physicalRemaining() int64 {
return sr.fr.physicalRemaining()
}
type zeroReader struct{}

View File

@ -1021,12 +1021,12 @@ func TestParsePAX(t *testing.T) {
func TestReadOldGNUSparseMap(t *testing.T) {
populateSparseMap := func(sa sparseArray, sps []string) []string {
for i := 0; len(sps) > 0 && i < sa.MaxEntries(); i++ {
copy(sa.Entry(i), sps[0])
for i := 0; len(sps) > 0 && i < sa.maxEntries(); i++ {
copy(sa.entry(i), sps[0])
sps = sps[1:]
}
if len(sps) > 0 {
copy(sa.IsExtended(), "\x80")
copy(sa.isExtended(), "\x80")
}
return sps
}
@ -1034,19 +1034,19 @@ func TestReadOldGNUSparseMap(t *testing.T) {
makeInput := func(format Format, size string, sps ...string) (out []byte) {
// Write the initial GNU header.
var blk block
gnu := blk.GNU()
sparse := gnu.Sparse()
copy(gnu.RealSize(), size)
gnu := blk.toGNU()
sparse := gnu.sparse()
copy(gnu.realSize(), size)
sps = populateSparseMap(sparse, sps)
if format != FormatUnknown {
blk.SetFormat(format)
blk.setFormat(format)
}
out = append(out, blk[:]...)
// Write extended sparse blocks.
for len(sps) > 0 {
var blk block
sps = populateSparseMap(blk.Sparse(), sps)
sps = populateSparseMap(blk.toSparse(), sps)
out = append(out, blk[:]...)
}
return out
@ -1359,11 +1359,11 @@ func TestFileReader(t *testing.T) {
wantCnt int64
wantErr error
}
testRemaining struct { // LogicalRemaining() == wantLCnt, PhysicalRemaining() == wantPCnt
testRemaining struct { // logicalRemaining() == wantLCnt, physicalRemaining() == wantPCnt
wantLCnt int64
wantPCnt int64
}
testFnc interface{} // testRead | testWriteTo | testRemaining
testFnc any // testRead | testWriteTo | testRemaining
)
type (
@ -1376,7 +1376,7 @@ func TestFileReader(t *testing.T) {
spd sparseDatas
size int64
}
fileMaker interface{} // makeReg | makeSparse
fileMaker any // makeReg | makeSparse
)
vectors := []struct {
@ -1596,11 +1596,11 @@ func TestFileReader(t *testing.T) {
t.Errorf("test %d.%d, expected %d more operations", i, j, len(f.ops))
}
case testRemaining:
if got := fr.LogicalRemaining(); got != tf.wantLCnt {
t.Errorf("test %d.%d, LogicalRemaining() = %d, want %d", i, j, got, tf.wantLCnt)
if got := fr.logicalRemaining(); got != tf.wantLCnt {
t.Errorf("test %d.%d, logicalRemaining() = %d, want %d", i, j, got, tf.wantLCnt)
}
if got := fr.PhysicalRemaining(); got != tf.wantPCnt {
t.Errorf("test %d.%d, PhysicalRemaining() = %d, want %d", i, j, got, tf.wantPCnt)
if got := fr.physicalRemaining(); got != tf.wantPCnt {
t.Errorf("test %d.%d, physicalRemaining() = %d, want %d", i, j, got, tf.wantPCnt)
}
default:
t.Fatalf("test %d.%d, unknown test operation: %T", i, j, tf)

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build aix || hurd || linux || dragonfly || openbsd || solaris
// +build aix hurd linux dragonfly openbsd solaris
package tar

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build darwin || freebsd || netbsd
// +build darwin freebsd netbsd
package tar

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build aix || hurd || linux || darwin || dragonfly || freebsd || openbsd || netbsd || solaris
// +build aix hurd linux darwin dragonfly freebsd openbsd netbsd solaris
package tar

View File

@ -14,7 +14,7 @@ import (
// hasNUL reports whether the NUL character exists within s.
func hasNUL(s string) bool {
return strings.IndexByte(s, 0) >= 0
return strings.Contains(s, "\x00")
}
// isASCII reports whether the input is an ASCII C-style string.
@ -201,10 +201,7 @@ func parsePAXTime(s string) (time.Time, error) {
const maxNanoSecondDigits = 9
// Split string into seconds and sub-seconds parts.
ss, sn := s, ""
if pos := strings.IndexByte(s, '.'); pos >= 0 {
ss, sn = s[:pos], s[pos+1:]
}
ss, sn, _ := strings.Cut(s, ".")
// Parse the seconds.
secs, err := strconv.ParseInt(ss, 10, 64)
@ -254,48 +251,32 @@ func formatPAXTime(ts time.Time) (s string) {
// return the remainder as r.
func parsePAXRecord(s string) (k, v, r string, err error) {
// The size field ends at the first space.
sp := strings.IndexByte(s, ' ')
if sp == -1 {
nStr, rest, ok := strings.Cut(s, " ")
if !ok {
return "", "", s, ErrHeader
}
// Parse the first token as a decimal integer.
n, perr := strconv.ParseInt(s[:sp], 10, 0) // Intentionally parse as native int
if perr != nil || n < 5 || int64(len(s)) < n {
n, perr := strconv.ParseInt(nStr, 10, 0) // Intentionally parse as native int
if perr != nil || n < 5 || n > int64(len(s)) {
return "", "", s, ErrHeader
}
afterSpace := int64(sp + 1)
beforeLastNewLine := n - 1
// In some cases, "length" was perhaps padded/malformed, and
// trying to index past where the space supposedly is goes past
// the end of the actual record.
// For example:
// "0000000000000000000000000000000030 mtime=1432668921.098285006\n30 ctime=2147483649.15163319"
// ^ ^
// | |
// | afterSpace=35
// |
// beforeLastNewLine=29
// yet indexOf(firstSpace) MUST BE before endOfRecord.
//
// See https://golang.org/issues/40196.
if afterSpace >= beforeLastNewLine {
n -= int64(len(nStr) + 1) // convert from index in s to index in rest
if n <= 0 {
return "", "", s, ErrHeader
}
// Extract everything between the space and the final newline.
rec, nl, rem := s[afterSpace:beforeLastNewLine], s[beforeLastNewLine:n], s[n:]
rec, nl, rem := rest[:n-1], rest[n-1:n], rest[n:]
if nl != "\n" {
return "", "", s, ErrHeader
}
// The first equals separates the key from the value.
eq := strings.IndexByte(rec, '=')
if eq == -1 {
k, v, ok = strings.Cut(rec, "=")
if !ok {
return "", "", s, ErrHeader
}
k, v = rec[:eq], rec[eq+1:]
if !validPAXRecord(k, v) {
return "", "", s, ErrHeader
@ -333,7 +314,7 @@ func formatPAXRecord(k, v string) (string, error) {
// for the PAX version of the USTAR string fields.
// The key must not contain an '=' character.
func validPAXRecord(k, v string) bool {
if k == "" || strings.IndexByte(k, '=') >= 0 {
if k == "" || strings.Contains(k, "=") {
return false
}
switch k {

View File

@ -23,7 +23,7 @@ import (
type testError struct{ error }
type fileOps []interface{} // []T where T is (string | int64)
type fileOps []any // []T where T is (string | int64)
// testFile is an io.ReadWriteSeeker where the IO operations performed
// on it must match the list of operations in ops.

View File

@ -50,7 +50,7 @@ func (tw *Writer) Flush() error {
if tw.err != nil {
return tw.err
}
if nb := tw.curr.LogicalRemaining(); nb > 0 {
if nb := tw.curr.logicalRemaining(); nb > 0 {
return fmt.Errorf("archive/tar: missed writing %d bytes", nb)
}
if _, tw.err = tw.w.Write(zeroBlock[:tw.pad]); tw.err != nil {
@ -117,8 +117,8 @@ func (tw *Writer) writeUSTARHeader(hdr *Header) error {
// Pack the main header.
var f formatter
blk := tw.templateV7Plus(hdr, f.formatString, f.formatOctal)
f.formatString(blk.USTAR().Prefix(), namePrefix)
blk.SetFormat(FormatUSTAR)
f.formatString(blk.toUSTAR().prefix(), namePrefix)
blk.setFormat(FormatUSTAR)
if f.err != nil {
return f.err // Should never happen since header is validated
}
@ -208,7 +208,7 @@ func (tw *Writer) writePAXHeader(hdr *Header, paxHdrs map[string]string) error {
var f formatter // Ignore errors since they are expected
fmtStr := func(b []byte, s string) { f.formatString(b, toASCII(s)) }
blk := tw.templateV7Plus(hdr, fmtStr, f.formatOctal)
blk.SetFormat(FormatPAX)
blk.setFormat(FormatPAX)
if err := tw.writeRawHeader(blk, hdr.Size, hdr.Typeflag); err != nil {
return err
}
@ -250,10 +250,10 @@ func (tw *Writer) writeGNUHeader(hdr *Header) error {
var spb []byte
blk := tw.templateV7Plus(hdr, f.formatString, f.formatNumeric)
if !hdr.AccessTime.IsZero() {
f.formatNumeric(blk.GNU().AccessTime(), hdr.AccessTime.Unix())
f.formatNumeric(blk.toGNU().accessTime(), hdr.AccessTime.Unix())
}
if !hdr.ChangeTime.IsZero() {
f.formatNumeric(blk.GNU().ChangeTime(), hdr.ChangeTime.Unix())
f.formatNumeric(blk.toGNU().changeTime(), hdr.ChangeTime.Unix())
}
// TODO(dsnet): Re-enable this when adding sparse support.
// See https://golang.org/issue/22735
@ -293,7 +293,7 @@ func (tw *Writer) writeGNUHeader(hdr *Header) error {
f.formatNumeric(blk.GNU().RealSize(), realSize)
}
*/
blk.SetFormat(FormatGNU)
blk.setFormat(FormatGNU)
if err := tw.writeRawHeader(blk, hdr.Size, hdr.Typeflag); err != nil {
return err
}
@ -321,28 +321,28 @@ type (
// The block returned is only valid until the next call to
// templateV7Plus or writeRawFile.
func (tw *Writer) templateV7Plus(hdr *Header, fmtStr stringFormatter, fmtNum numberFormatter) *block {
tw.blk.Reset()
tw.blk.reset()
modTime := hdr.ModTime
if modTime.IsZero() {
modTime = time.Unix(0, 0)
}
v7 := tw.blk.V7()
v7.TypeFlag()[0] = hdr.Typeflag
fmtStr(v7.Name(), hdr.Name)
fmtStr(v7.LinkName(), hdr.Linkname)
fmtNum(v7.Mode(), hdr.Mode)
fmtNum(v7.UID(), int64(hdr.Uid))
fmtNum(v7.GID(), int64(hdr.Gid))
fmtNum(v7.Size(), hdr.Size)
fmtNum(v7.ModTime(), modTime.Unix())
v7 := tw.blk.toV7()
v7.typeFlag()[0] = hdr.Typeflag
fmtStr(v7.name(), hdr.Name)
fmtStr(v7.linkName(), hdr.Linkname)
fmtNum(v7.mode(), hdr.Mode)
fmtNum(v7.uid(), int64(hdr.Uid))
fmtNum(v7.gid(), int64(hdr.Gid))
fmtNum(v7.size(), hdr.Size)
fmtNum(v7.modTime(), modTime.Unix())
ustar := tw.blk.USTAR()
fmtStr(ustar.UserName(), hdr.Uname)
fmtStr(ustar.GroupName(), hdr.Gname)
fmtNum(ustar.DevMajor(), hdr.Devmajor)
fmtNum(ustar.DevMinor(), hdr.Devminor)
ustar := tw.blk.toUSTAR()
fmtStr(ustar.userName(), hdr.Uname)
fmtStr(ustar.groupName(), hdr.Gname)
fmtNum(ustar.devMajor(), hdr.Devmajor)
fmtNum(ustar.devMinor(), hdr.Devminor)
return &tw.blk
}
@ -351,7 +351,7 @@ func (tw *Writer) templateV7Plus(hdr *Header, fmtStr stringFormatter, fmtNum num
// It uses format to encode the header format and will write data as the body.
// It uses default values for all of the other fields (as BSD and GNU tar does).
func (tw *Writer) writeRawFile(name, data string, flag byte, format Format) error {
tw.blk.Reset()
tw.blk.reset()
// Best effort for the filename.
name = toASCII(name)
@ -361,15 +361,15 @@ func (tw *Writer) writeRawFile(name, data string, flag byte, format Format) erro
name = strings.TrimRight(name, "/")
var f formatter
v7 := tw.blk.V7()
v7.TypeFlag()[0] = flag
f.formatString(v7.Name(), name)
f.formatOctal(v7.Mode(), 0)
f.formatOctal(v7.UID(), 0)
f.formatOctal(v7.GID(), 0)
f.formatOctal(v7.Size(), int64(len(data))) // Must be < 8GiB
f.formatOctal(v7.ModTime(), 0)
tw.blk.SetFormat(format)
v7 := tw.blk.toV7()
v7.typeFlag()[0] = flag
f.formatString(v7.name(), name)
f.formatOctal(v7.mode(), 0)
f.formatOctal(v7.uid(), 0)
f.formatOctal(v7.gid(), 0)
f.formatOctal(v7.size(), int64(len(data))) // Must be < 8GiB
f.formatOctal(v7.modTime(), 0)
tw.blk.setFormat(format)
if f.err != nil {
return f.err // Only occurs if size condition is violated
}
@ -511,10 +511,13 @@ func (fw *regFileWriter) ReadFrom(r io.Reader) (int64, error) {
return io.Copy(struct{ io.Writer }{fw}, r)
}
func (fw regFileWriter) LogicalRemaining() int64 {
// logicalRemaining implements fileState.logicalRemaining.
func (fw regFileWriter) logicalRemaining() int64 {
return fw.nb
}
func (fw regFileWriter) PhysicalRemaining() int64 {
// logicalRemaining implements fileState.physicalRemaining.
func (fw regFileWriter) physicalRemaining() int64 {
return fw.nb
}
@ -526,9 +529,9 @@ type sparseFileWriter struct {
}
func (sw *sparseFileWriter) Write(b []byte) (n int, err error) {
overwrite := int64(len(b)) > sw.LogicalRemaining()
overwrite := int64(len(b)) > sw.logicalRemaining()
if overwrite {
b = b[:sw.LogicalRemaining()]
b = b[:sw.logicalRemaining()]
}
b0 := b
@ -556,7 +559,7 @@ func (sw *sparseFileWriter) Write(b []byte) (n int, err error) {
return n, errMissData // Not possible; implies bug in validation logic
case err != nil:
return n, err
case sw.LogicalRemaining() == 0 && sw.PhysicalRemaining() > 0:
case sw.logicalRemaining() == 0 && sw.physicalRemaining() > 0:
return n, errUnrefData // Not possible; implies bug in validation logic
case overwrite:
return n, ErrWriteTooLong
@ -578,12 +581,12 @@ func (sw *sparseFileWriter) ReadFrom(r io.Reader) (n int64, err error) {
var readLastByte bool
pos0 := sw.pos
for sw.LogicalRemaining() > 0 && !readLastByte && err == nil {
for sw.logicalRemaining() > 0 && !readLastByte && err == nil {
var nf int64 // Size of fragment
dataStart, dataEnd := sw.sp[0].Offset, sw.sp[0].endOffset()
if sw.pos < dataStart { // In a hole fragment
nf = dataStart - sw.pos
if sw.PhysicalRemaining() == 0 {
if sw.physicalRemaining() == 0 {
readLastByte = true
nf--
}
@ -613,18 +616,18 @@ func (sw *sparseFileWriter) ReadFrom(r io.Reader) (n int64, err error) {
return n, errMissData // Not possible; implies bug in validation logic
case err != nil:
return n, err
case sw.LogicalRemaining() == 0 && sw.PhysicalRemaining() > 0:
case sw.logicalRemaining() == 0 && sw.physicalRemaining() > 0:
return n, errUnrefData // Not possible; implies bug in validation logic
default:
return n, ensureEOF(rs)
}
}
func (sw sparseFileWriter) LogicalRemaining() int64 {
func (sw sparseFileWriter) logicalRemaining() int64 {
return sw.sp[len(sw.sp)-1].endOffset() - sw.pos
}
func (sw sparseFileWriter) PhysicalRemaining() int64 {
return sw.fw.PhysicalRemaining()
func (sw sparseFileWriter) physicalRemaining() int64 {
return sw.fw.physicalRemaining()
}
// zeroWriter may only be written with NULs, otherwise it returns errWriteHole.

View File

@ -67,7 +67,7 @@ func TestWriter(t *testing.T) {
testClose struct { // Close() == wantErr
wantErr error
}
testFnc interface{} // testHeader | testWrite | testReadFrom | testClose
testFnc any // testHeader | testWrite | testReadFrom | testClose
)
vectors := []struct {
@ -987,11 +987,9 @@ func TestIssue12594(t *testing.T) {
// The prefix field should never appear in the GNU format.
var blk block
copy(blk[:], b.Bytes())
prefix := string(blk.USTAR().Prefix())
if i := strings.IndexByte(prefix, 0); i >= 0 {
prefix = prefix[:i] // Truncate at the NUL terminator
}
if blk.GetFormat() == FormatGNU && len(prefix) > 0 && strings.HasPrefix(name, prefix) {
prefix := string(blk.toUSTAR().prefix())
prefix, _, _ = strings.Cut(prefix, "\x00") // Truncate at the NUL terminator
if blk.getFormat() == FormatGNU && len(prefix) > 0 && strings.HasPrefix(name, prefix) {
t.Errorf("test %d, found prefix in GNU format: %s", i, prefix)
}
@ -1029,11 +1027,11 @@ func TestFileWriter(t *testing.T) {
wantCnt int64
wantErr error
}
testRemaining struct { // LogicalRemaining() == wantLCnt, PhysicalRemaining() == wantPCnt
testRemaining struct { // logicalRemaining() == wantLCnt, physicalRemaining() == wantPCnt
wantLCnt int64
wantPCnt int64
}
testFnc interface{} // testWrite | testReadFrom | testRemaining
testFnc any // testWrite | testReadFrom | testRemaining
)
type (
@ -1046,7 +1044,7 @@ func TestFileWriter(t *testing.T) {
sph sparseHoles
size int64
}
fileMaker interface{} // makeReg | makeSparse
fileMaker any // makeReg | makeSparse
)
vectors := []struct {
@ -1292,11 +1290,11 @@ func TestFileWriter(t *testing.T) {
t.Errorf("test %d.%d, expected %d more operations", i, j, len(f.ops))
}
case testRemaining:
if got := fw.LogicalRemaining(); got != tf.wantLCnt {
t.Errorf("test %d.%d, LogicalRemaining() = %d, want %d", i, j, got, tf.wantLCnt)
if got := fw.logicalRemaining(); got != tf.wantLCnt {
t.Errorf("test %d.%d, logicalRemaining() = %d, want %d", i, j, got, tf.wantLCnt)
}
if got := fw.PhysicalRemaining(); got != tf.wantPCnt {
t.Errorf("test %d.%d, PhysicalRemaining() = %d, want %d", i, j, got, tf.wantPCnt)
if got := fw.physicalRemaining(); got != tf.wantPCnt {
t.Errorf("test %d.%d, physicalRemaining() = %d, want %d", i, j, got, tf.wantPCnt)
}
default:
t.Fatalf("test %d.%d, unknown test operation: %T", i, j, tf)

View File

@ -0,0 +1,81 @@
// Copyright 2021 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 zip
import (
"bytes"
"io"
"os"
"path/filepath"
"testing"
)
func FuzzReader(f *testing.F) {
testdata, err := os.ReadDir("testdata")
if err != nil {
f.Fatalf("failed to read testdata directory: %s", err)
}
for _, de := range testdata {
if de.IsDir() {
continue
}
b, err := os.ReadFile(filepath.Join("testdata", de.Name()))
if err != nil {
f.Fatalf("failed to read testdata: %s", err)
}
f.Add(b)
}
f.Fuzz(func(t *testing.T, b []byte) {
r, err := NewReader(bytes.NewReader(b), int64(len(b)))
if err != nil {
return
}
type file struct {
header *FileHeader
content []byte
}
files := []file{}
for _, f := range r.File {
fr, err := f.Open()
if err != nil {
continue
}
content, err := io.ReadAll(fr)
if err != nil {
continue
}
files = append(files, file{header: &f.FileHeader, content: content})
if _, err := r.Open(f.Name); err != nil {
continue
}
}
// If we were unable to read anything out of the archive don't
// bother trying to roundtrip it.
if len(files) == 0 {
return
}
w := NewWriter(io.Discard)
for _, f := range files {
ww, err := w.CreateHeader(f.header)
if err != nil {
t.Fatalf("unable to write previously parsed header: %s", err)
}
if _, err := ww.Write(f.content); err != nil {
t.Fatalf("unable to write previously parsed content: %s", err)
}
}
if err := w.Close(); err != nil {
t.Fatalf("Unable to write archive: %s", err)
}
// TODO: We may want to check if the archive roundtrips.
})
}

View File

@ -125,7 +125,6 @@ func (z *Reader) init(r io.ReaderAt, size int64) error {
if err != nil {
return err
}
f.readDataDescriptor()
z.File = append(z.File, f)
}
if uint16(len(z.File)) != uint16(end.directoryRecords) { // only compare 16 bits here
@ -186,10 +185,15 @@ func (f *File) Open() (io.ReadCloser, error) {
return nil, ErrAlgorithm
}
var rc io.ReadCloser = dcomp(r)
var desr io.Reader
if f.hasDataDescriptor() {
desr = io.NewSectionReader(f.zipr, f.headerOffset+bodyOffset+size, dataDescriptorLen)
}
rc = &checksumReader{
rc: rc,
hash: crc32.NewIEEE(),
f: f,
desr: desr,
}
return rc, nil
}
@ -205,49 +209,13 @@ func (f *File) OpenRaw() (io.Reader, error) {
return r, nil
}
func (f *File) readDataDescriptor() {
if !f.hasDataDescriptor() {
return
}
bodyOffset, err := f.findBodyOffset()
if err != nil {
f.descErr = err
return
}
// In section 4.3.9.2 of the spec: "However ZIP64 format MAY be used
// regardless of the size of a file. When extracting, if the zip64
// extended information extra field is present for the file the
// compressed and uncompressed sizes will be 8 byte values."
//
// Historically, this package has used the compressed and uncompressed
// sizes from the central directory to determine if the package is
// zip64.
//
// For this case we allow either the extra field or sizes to determine
// the data descriptor length.
zip64 := f.zip64 || f.isZip64()
n := int64(dataDescriptorLen)
if zip64 {
n = dataDescriptor64Len
}
size := int64(f.CompressedSize64)
r := io.NewSectionReader(f.zipr, f.headerOffset+bodyOffset+size, n)
dd, err := readDataDescriptor(r, zip64)
if err != nil {
f.descErr = err
return
}
f.CRC32 = dd.crc32
}
type checksumReader struct {
rc io.ReadCloser
hash hash.Hash32
nread uint64 // number of bytes read so far
f *File
err error // sticky error
desr io.Reader // if non-nil, where to read the data descriptor
err error // sticky error
}
func (r *checksumReader) Stat() (fs.FileInfo, error) {
@ -268,12 +236,12 @@ func (r *checksumReader) Read(b []byte) (n int, err error) {
if r.nread != r.f.UncompressedSize64 {
return 0, io.ErrUnexpectedEOF
}
if r.f.hasDataDescriptor() {
if r.f.descErr != nil {
if r.f.descErr == io.EOF {
if r.desr != nil {
if err1 := readDataDescriptor(r.desr, r.f); err1 != nil {
if err1 == io.EOF {
err = io.ErrUnexpectedEOF
} else {
err = r.f.descErr
err = err1
}
} else if r.hash.Sum32() != r.f.CRC32 {
err = ErrChecksum
@ -485,10 +453,8 @@ parseExtras:
return nil
}
func readDataDescriptor(r io.Reader, zip64 bool) (*dataDescriptor, error) {
// Create enough space for the largest possible size
var buf [dataDescriptor64Len]byte
func readDataDescriptor(r io.Reader, f *File) error {
var buf [dataDescriptorLen]byte
// The spec says: "Although not originally assigned a
// signature, the value 0x08074b50 has commonly been adopted
// as a signature value for the data descriptor record.
@ -497,9 +463,10 @@ func readDataDescriptor(r io.Reader, zip64 bool) (*dataDescriptor, error) {
// descriptors and should account for either case when reading
// ZIP files to ensure compatibility."
//
// First read just those 4 bytes to see if the signature exists.
// dataDescriptorLen includes the size of the signature but
// first read just those 4 bytes to see if it exists.
if _, err := io.ReadFull(r, buf[:4]); err != nil {
return nil, err
return err
}
off := 0
maybeSig := readBuf(buf[:4])
@ -508,28 +475,21 @@ func readDataDescriptor(r io.Reader, zip64 bool) (*dataDescriptor, error) {
// bytes.
off += 4
}
end := dataDescriptorLen - 4
if zip64 {
end = dataDescriptor64Len - 4
if _, err := io.ReadFull(r, buf[off:12]); err != nil {
return err
}
if _, err := io.ReadFull(r, buf[off:end]); err != nil {
return nil, err
}
b := readBuf(buf[:end])
out := &dataDescriptor{
crc32: b.uint32(),
b := readBuf(buf[:12])
if b.uint32() != f.CRC32 {
return ErrChecksum
}
if zip64 {
out.compressedSize = b.uint64()
out.uncompressedSize = b.uint64()
} else {
out.compressedSize = uint64(b.uint32())
out.uncompressedSize = uint64(b.uint32())
}
return out, nil
// The two sizes that follow here can be either 32 bits or 64 bits
// but the spec is not very clear on this and different
// interpretations has been made causing incompatibilities. We
// already have the sizes from the central directory so we can
// just ignore these.
return nil
}
func readDirectoryEnd(r io.ReaderAt, size int64) (dir *directoryEnd, err error) {
@ -710,7 +670,7 @@ func (f *fileListEntry) Size() int64 { return 0 }
func (f *fileListEntry) Mode() fs.FileMode { return fs.ModeDir | 0555 }
func (f *fileListEntry) Type() fs.FileMode { return fs.ModeDir }
func (f *fileListEntry) IsDir() bool { return true }
func (f *fileListEntry) Sys() interface{} { return nil }
func (f *fileListEntry) Sys() any { return nil }
func (f *fileListEntry) ModTime() time.Time {
if f.file == nil {
@ -741,6 +701,9 @@ func (r *Reader) initFileList() {
for _, file := range r.File {
isDir := len(file.Name) > 0 && file.Name[len(file.Name)-1] == '/'
name := toValidName(file.Name)
if name == "" {
continue
}
for dir := path.Dir(name); dir != "."; dir = path.Dir(dir) {
dirs[dir] = true
}
@ -782,8 +745,11 @@ func fileEntryLess(x, y string) bool {
func (r *Reader) Open(name string) (fs.File, error) {
r.initFileList()
if !fs.ValidPath(name) {
return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrInvalid}
}
e := r.openLookup(name)
if e == nil || !fs.ValidPath(name) {
if e == nil {
return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrNotExist}
}
if e.isDir {
@ -797,7 +763,7 @@ func (r *Reader) Open(name string) (fs.File, error) {
}
func split(name string) (dir, elem string, isDir bool) {
if name[len(name)-1] == '/' {
if len(name) > 0 && name[len(name)-1] == '/' {
isDir = true
name = name[:len(name)-1]
}

View File

@ -13,6 +13,7 @@ import (
"io/fs"
"os"
"path/filepath"
"reflect"
"regexp"
"strings"
"testing"
@ -1202,127 +1203,14 @@ func TestCVE202127919(t *testing.T) {
if err != nil {
t.Errorf("Error reading file: %v", err)
}
}
func TestReadDataDescriptor(t *testing.T) {
tests := []struct {
desc string
in []byte
zip64 bool
want *dataDescriptor
wantErr error
}{{
desc: "valid 32 bit with signature",
in: []byte{
0x50, 0x4b, 0x07, 0x08, // signature
0x00, 0x01, 0x02, 0x03, // crc32
0x04, 0x05, 0x06, 0x07, // compressed size
0x08, 0x09, 0x0a, 0x0b, // uncompressed size
},
want: &dataDescriptor{
crc32: 0x03020100,
compressedSize: 0x07060504,
uncompressedSize: 0x0b0a0908,
},
}, {
desc: "valid 32 bit without signature",
in: []byte{
0x00, 0x01, 0x02, 0x03, // crc32
0x04, 0x05, 0x06, 0x07, // compressed size
0x08, 0x09, 0x0a, 0x0b, // uncompressed size
},
want: &dataDescriptor{
crc32: 0x03020100,
compressedSize: 0x07060504,
uncompressedSize: 0x0b0a0908,
},
}, {
desc: "valid 64 bit with signature",
in: []byte{
0x50, 0x4b, 0x07, 0x08, // signature
0x00, 0x01, 0x02, 0x03, // crc32
0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, // compressed size
0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, // uncompressed size
},
zip64: true,
want: &dataDescriptor{
crc32: 0x03020100,
compressedSize: 0x0b0a090807060504,
uncompressedSize: 0x131211100f0e0d0c,
},
}, {
desc: "valid 64 bit without signature",
in: []byte{
0x00, 0x01, 0x02, 0x03, // crc32
0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, // compressed size
0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, // uncompressed size
},
zip64: true,
want: &dataDescriptor{
crc32: 0x03020100,
compressedSize: 0x0b0a090807060504,
uncompressedSize: 0x131211100f0e0d0c,
},
}, {
desc: "invalid 32 bit with signature",
in: []byte{
0x50, 0x4b, 0x07, 0x08, // signature
0x00, 0x01, 0x02, 0x03, // crc32
0x04, 0x05, // unexpected end
},
wantErr: io.ErrUnexpectedEOF,
}, {
desc: "invalid 32 bit without signature",
in: []byte{
0x00, 0x01, 0x02, 0x03, // crc32
0x04, 0x05, // unexpected end
},
wantErr: io.ErrUnexpectedEOF,
}, {
desc: "invalid 64 bit with signature",
in: []byte{
0x50, 0x4b, 0x07, 0x08, // signature
0x00, 0x01, 0x02, 0x03, // crc32
0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, // compressed size
0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, // unexpected end
},
zip64: true,
wantErr: io.ErrUnexpectedEOF,
}, {
desc: "invalid 64 bit without signature",
in: []byte{
0x00, 0x01, 0x02, 0x03, // crc32
0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, // compressed size
0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, // unexpected end
},
zip64: true,
wantErr: io.ErrUnexpectedEOF,
}}
for _, test := range tests {
t.Run(test.desc, func(t *testing.T) {
r := bytes.NewReader(test.in)
desc, err := readDataDescriptor(r, test.zip64)
if err != test.wantErr {
t.Fatalf("got err %v; want nil", err)
}
if test.want == nil {
return
}
if desc == nil {
t.Fatalf("got nil DataDescriptor; want non-nil")
}
if desc.crc32 != test.want.crc32 {
t.Errorf("got CRC32 %#x; want %#x", desc.crc32, test.want.crc32)
}
if desc.compressedSize != test.want.compressedSize {
t.Errorf("got CompressedSize %#x; want %#x", desc.compressedSize, test.want.compressedSize)
}
if desc.uncompressedSize != test.want.uncompressedSize {
t.Errorf("got UncompressedSize %#x; want %#x", desc.uncompressedSize, test.want.uncompressedSize)
}
})
if len(r.File) != 1 {
t.Fatalf("No entries in the file list")
}
if r.File[0].Name != "../test.txt" {
t.Errorf("Unexpected entry name: %s", r.File[0].Name)
}
if _, err := r.File[0].Open(); err != nil {
t.Errorf("Error opening file: %v", err)
}
}
@ -1402,3 +1290,121 @@ func TestCVE202139293(t *testing.T) {
t.Fatalf("unexpected error, got: %v, want: %v", err, ErrFormat)
}
}
func TestCVE202141772(t *testing.T) {
// Archive contains a file whose name is exclusively made up of '/', '\'
// characters, or "../", "..\" paths, which would previously cause a panic.
//
// Length Method Size Cmpr Date Time CRC-32 Name
// -------- ------ ------- ---- ---------- ----- -------- ----
// 0 Stored 0 0% 08-05-2021 18:32 00000000 /
// 0 Stored 0 0% 09-14-2021 12:59 00000000 //
// 0 Stored 0 0% 09-14-2021 12:59 00000000 \
// 11 Stored 11 0% 09-14-2021 13:04 0d4a1185 /test.txt
// -------- ------- --- -------
// 11 11 0% 4 files
data := []byte{
0x50, 0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x08,
0x00, 0x00, 0x06, 0x94, 0x05, 0x53, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2f, 0x50,
0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00,
0x00, 0x78, 0x67, 0x2e, 0x53, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x02, 0x00, 0x00, 0x00, 0x2f, 0x2f, 0x50,
0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00,
0x00, 0x78, 0x67, 0x2e, 0x53, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x5c, 0x50, 0x4b,
0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
0x91, 0x68, 0x2e, 0x53, 0x85, 0x11, 0x4a, 0x0d,
0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
0x09, 0x00, 0x00, 0x00, 0x2f, 0x74, 0x65, 0x73,
0x74, 0x2e, 0x74, 0x78, 0x74, 0x68, 0x65, 0x6c,
0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64,
0x50, 0x4b, 0x01, 0x02, 0x14, 0x03, 0x0a, 0x00,
0x00, 0x08, 0x00, 0x00, 0x06, 0x94, 0x05, 0x53,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
0xed, 0x41, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x50,
0x4b, 0x01, 0x02, 0x3f, 0x00, 0x0a, 0x00, 0x00,
0x00, 0x00, 0x00, 0x78, 0x67, 0x2e, 0x53, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x02, 0x00, 0x24, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
0x00, 0x1f, 0x00, 0x00, 0x00, 0x2f, 0x2f, 0x0a,
0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x00, 0x18, 0x00, 0x93, 0x98, 0x25, 0x57, 0x25,
0xa9, 0xd7, 0x01, 0x93, 0x98, 0x25, 0x57, 0x25,
0xa9, 0xd7, 0x01, 0x93, 0x98, 0x25, 0x57, 0x25,
0xa9, 0xd7, 0x01, 0x50, 0x4b, 0x01, 0x02, 0x3f,
0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78,
0x67, 0x2e, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x20, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00,
0x00, 0x5c, 0x0a, 0x00, 0x20, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x93, 0x98,
0x25, 0x57, 0x25, 0xa9, 0xd7, 0x01, 0x93, 0x98,
0x25, 0x57, 0x25, 0xa9, 0xd7, 0x01, 0x93, 0x98,
0x25, 0x57, 0x25, 0xa9, 0xd7, 0x01, 0x50, 0x4b,
0x01, 0x02, 0x3f, 0x00, 0x0a, 0x00, 0x00, 0x00,
0x00, 0x00, 0x91, 0x68, 0x2e, 0x53, 0x85, 0x11,
0x4a, 0x0d, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00,
0x00, 0x00, 0x09, 0x00, 0x24, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x5e, 0x00, 0x00, 0x00, 0x2f, 0x74, 0x65, 0x73,
0x74, 0x2e, 0x74, 0x78, 0x74, 0x0a, 0x00, 0x20,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x18,
0x00, 0xa9, 0x80, 0x51, 0x01, 0x26, 0xa9, 0xd7,
0x01, 0x31, 0xd1, 0x57, 0x01, 0x26, 0xa9, 0xd7,
0x01, 0xdf, 0x48, 0x85, 0xf9, 0x25, 0xa9, 0xd7,
0x01, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00,
0x00, 0x04, 0x00, 0x04, 0x00, 0x31, 0x01, 0x00,
0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00,
}
r, err := NewReader(bytes.NewReader([]byte(data)), int64(len(data)))
if err != nil {
t.Fatalf("Error reading the archive: %v", err)
}
entryNames := []string{`/`, `//`, `\`, `/test.txt`}
var names []string
for _, f := range r.File {
names = append(names, f.Name)
if _, err := f.Open(); err != nil {
t.Errorf("Error opening %q: %v", f.Name, err)
}
if _, err := r.Open(f.Name); err == nil {
t.Errorf("Opening %q with fs.FS API succeeded", f.Name)
}
}
if !reflect.DeepEqual(names, entryNames) {
t.Errorf("Unexpected file entries: %q", names)
}
if _, err := r.Open(""); err == nil {
t.Errorf("Opening %q with fs.FS API succeeded", "")
}
if _, err := r.Open("test.txt"); err != nil {
t.Errorf("Error opening %q with fs.FS API: %v", "test.txt", err)
}
dirEntries, err := fs.ReadDir(r, ".")
if err != nil {
t.Fatalf("Error reading the root directory: %v", err)
}
if len(dirEntries) != 1 || dirEntries[0].Name() != "test.txt" {
t.Errorf("Unexpected directory entries")
for _, dirEntry := range dirEntries {
_, err := r.Open(dirEntry.Name())
t.Logf("%q (Open error: %v)", dirEntry.Name(), err)
}
t.FailNow()
}
info, err := dirEntries[0].Info()
if err != nil {
t.Fatalf("Error reading info entry: %v", err)
}
if name := info.Name(); name != "test.txt" {
t.Errorf("Inconsistent name in info entry: %v", name)
}
}

View File

@ -163,7 +163,7 @@ func (fi headerFileInfo) ModTime() time.Time {
}
func (fi headerFileInfo) Mode() fs.FileMode { return fi.fh.Mode() }
func (fi headerFileInfo) Type() fs.FileMode { return fi.fh.Mode().Type() }
func (fi headerFileInfo) Sys() interface{} { return fi.fh }
func (fi headerFileInfo) Sys() any { return fi.fh }
func (fi headerFileInfo) Info() (fs.FileInfo, error) { return fi, nil }
@ -390,11 +390,3 @@ func unixModeToFileMode(m uint32) fs.FileMode {
}
return mode
}
// dataDescriptor holds the data descriptor that optionally follows the file
// contents in the zip file.
type dataDescriptor struct {
crc32 uint32
compressedSize uint64
uncompressedSize uint64
}

View File

@ -362,7 +362,7 @@ func TestWriterDirAttributes(t *testing.T) {
}
binary.LittleEndian.PutUint32(sig[:], uint32(dataDescriptorSignature))
if bytes.Index(b, sig[:]) != -1 {
if bytes.Contains(b, sig[:]) {
t.Error("there should be no data descriptor")
}
}

View File

@ -68,7 +68,12 @@ func (b *Reader) Size() int { return len(b.buf) }
// Reset discards any buffered data, resets all state, and switches
// the buffered reader to read from r.
// Calling Reset on the zero value of Reader initializes the internal buffer
// to the default size.
func (b *Reader) Reset(r io.Reader) {
if b.buf == nil {
b.buf = make([]byte, defaultBufSize)
}
b.reset(b.buf, r)
}
@ -168,6 +173,10 @@ func (b *Reader) Discard(n int) (discarded int, err error) {
if n == 0 {
return
}
b.lastByte = -1
b.lastRuneSize = -1
remain := n
for {
skip := b.Buffered()
@ -235,6 +244,8 @@ func (b *Reader) Read(p []byte) (n int, err error) {
}
// copy as much as we can
// Note: if the slice panics here, it is probably because
// the underlying reader returned a bad count. See issue 49795.
n = copy(p, b.buf[b.r:b.w])
b.r += n
b.lastByte = int(b.buf[b.r-1])
@ -261,8 +272,8 @@ func (b *Reader) ReadByte() (byte, error) {
// UnreadByte unreads the last byte. Only the most recently read byte can be unread.
//
// UnreadByte returns an error if the most recent method called on the
// Reader was not a read operation. Notably, Peek is not considered a
// read operation.
// Reader was not a read operation. Notably, Peek, Discard, and WriteTo are not
// considered read operations.
func (b *Reader) UnreadByte() error {
if b.lastByte < 0 || b.r == 0 && b.w > 0 {
return ErrInvalidUnreadByte
@ -497,6 +508,9 @@ func (b *Reader) ReadString(delim byte) (string, error) {
// If the underlying reader supports the WriteTo method,
// this calls the underlying WriteTo without buffering.
func (b *Reader) WriteTo(w io.Writer) (n int64, err error) {
b.lastByte = -1
b.lastRuneSize = -1
n, err = b.writeBuf(w)
if err != nil {
return
@ -581,6 +595,8 @@ func NewWriterSize(w io.Writer, size int) *Writer {
}
// NewWriter returns a new Writer whose buffer has the default size.
// If the argument io.Writer is already a Writer with large enough buffer size,
// it returns the underlying Writer.
func NewWriter(w io.Writer) *Writer {
return NewWriterSize(w, defaultBufSize)
}
@ -590,7 +606,12 @@ func (b *Writer) Size() int { return len(b.buf) }
// Reset discards any unflushed buffered data, clears any error, and
// resets b to write its output to w.
// Calling Reset on the zero value of Writer initializes the internal buffer
// to the default size.
func (b *Writer) Reset(w io.Writer) {
if b.buf == nil {
b.buf = make([]byte, defaultBufSize)
}
b.err = nil
b.n = 0
b.wr = w
@ -623,6 +644,14 @@ func (b *Writer) Flush() error {
// Available returns how many bytes are unused in the buffer.
func (b *Writer) Available() int { return len(b.buf) - b.n }
// AvailableBuffer returns an empty buffer with b.Available() capacity.
// This buffer is intended to be appended to and
// passed to an immediately succeeding Write call.
// The buffer is only valid until the next write operation on b.
func (b *Writer) AvailableBuffer() []byte {
return b.buf[b.n:][:0]
}
// Buffered returns the number of bytes that have been written into the current buffer.
func (b *Writer) Buffered() int { return b.n }
@ -720,19 +749,14 @@ func (b *Writer) WriteString(s string) (int, error) {
}
// ReadFrom implements io.ReaderFrom. If the underlying writer
// supports the ReadFrom method, and b has no buffered data yet,
// this calls the underlying ReadFrom without buffering.
// supports the ReadFrom method, this calls the underlying ReadFrom.
// If there is buffered data and an underlying ReadFrom, this fills
// the buffer and writes it before calling ReadFrom.
func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) {
if b.err != nil {
return 0, b.err
}
if b.Buffered() == 0 {
if w, ok := b.wr.(io.ReaderFrom); ok {
n, err = w.ReadFrom(r)
b.err = err
return n, err
}
}
readerFrom, readerFromOK := b.wr.(io.ReaderFrom)
var m int
for {
if b.Available() == 0 {
@ -740,6 +764,12 @@ func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) {
return n, err1
}
}
if readerFromOK && b.Buffered() == 0 {
nn, err := readerFrom.ReadFrom(r)
b.err = err
n += nn
return n, err
}
nr := 0
for nr < maxConsecutiveEmptyReads {
m, err = r.Read(b.buf[b.n:])

View File

@ -10,6 +10,8 @@ import (
"errors"
"fmt"
"io"
"math/rand"
"strconv"
"strings"
"testing"
"testing/iotest"
@ -302,6 +304,40 @@ func TestNoUnreadByteAfterPeek(t *testing.T) {
}
}
func TestNoUnreadRuneAfterDiscard(t *testing.T) {
br := NewReader(strings.NewReader("example"))
br.ReadRune()
br.Discard(1)
if err := br.UnreadRune(); err == nil {
t.Error("UnreadRune didn't fail after Discard")
}
}
func TestNoUnreadByteAfterDiscard(t *testing.T) {
br := NewReader(strings.NewReader("example"))
br.ReadByte()
br.Discard(1)
if err := br.UnreadByte(); err == nil {
t.Error("UnreadByte didn't fail after Discard")
}
}
func TestNoUnreadRuneAfterWriteTo(t *testing.T) {
br := NewReader(strings.NewReader("example"))
br.WriteTo(io.Discard)
if err := br.UnreadRune(); err == nil {
t.Error("UnreadRune didn't fail after WriteTo")
}
}
func TestNoUnreadByteAfterWriteTo(t *testing.T) {
br := NewReader(strings.NewReader("example"))
br.WriteTo(io.Discard)
if err := br.UnreadByte(); err == nil {
t.Error("UnreadByte didn't fail after WriteTo")
}
}
func TestUnreadByte(t *testing.T) {
segments := []string{"Hello, ", "world"}
r := NewReader(&StringReader{data: segments})
@ -608,6 +644,37 @@ func TestWriter(t *testing.T) {
}
}
func TestWriterAppend(t *testing.T) {
got := new(bytes.Buffer)
var want []byte
rn := rand.New(rand.NewSource(0))
w := NewWriterSize(got, 64)
for i := 0; i < 100; i++ {
// Obtain a buffer to append to.
b := w.AvailableBuffer()
if w.Available() != cap(b) {
t.Fatalf("Available() = %v, want %v", w.Available(), cap(b))
}
// While not recommended, it is valid to append to a shifted buffer.
// This forces Write to copy the input.
if rn.Intn(8) == 0 && cap(b) > 0 {
b = b[1:1:cap(b)]
}
// Append a random integer of varying width.
n := int64(rn.Intn(1 << rn.Intn(30)))
want = append(strconv.AppendInt(want, n, 10), ' ')
b = append(strconv.AppendInt(b, n, 10), ' ')
w.Write(b)
}
w.Flush()
if !bytes.Equal(got.Bytes(), want) {
t.Errorf("output mismatch:\ngot %s\nwant %s", got.Bytes(), want)
}
}
// Check that write errors are returned properly.
type errorWriterTest struct {
@ -1284,6 +1351,54 @@ func TestWriterReadFromErrNoProgress(t *testing.T) {
}
}
type readFromWriter struct {
buf []byte
writeBytes int
readFromBytes int
}
func (w *readFromWriter) Write(p []byte) (int, error) {
w.buf = append(w.buf, p...)
w.writeBytes += len(p)
return len(p), nil
}
func (w *readFromWriter) ReadFrom(r io.Reader) (int64, error) {
b, err := io.ReadAll(r)
w.buf = append(w.buf, b...)
w.readFromBytes += len(b)
return int64(len(b)), err
}
// Test that calling (*Writer).ReadFrom with a partially-filled buffer
// fills the buffer before switching over to ReadFrom.
func TestWriterReadFromWithBufferedData(t *testing.T) {
const bufsize = 16
input := createTestInput(64)
rfw := &readFromWriter{}
w := NewWriterSize(rfw, bufsize)
const writeSize = 8
if n, err := w.Write(input[:writeSize]); n != writeSize || err != nil {
t.Errorf("w.Write(%v bytes) = %v, %v; want %v, nil", writeSize, n, err, writeSize)
}
n, err := w.ReadFrom(bytes.NewReader(input[writeSize:]))
if wantn := len(input[writeSize:]); int(n) != wantn || err != nil {
t.Errorf("io.Copy(w, %v bytes) = %v, %v; want %v, nil", wantn, n, err, wantn)
}
if err := w.Flush(); err != nil {
t.Errorf("w.Flush() = %v, want nil", err)
}
if got, want := rfw.writeBytes, bufsize; got != want {
t.Errorf("wrote %v bytes with Write, want %v", got, want)
}
if got, want := rfw.readFromBytes, len(input)-bufsize; got != want {
t.Errorf("wrote %v bytes with ReadFrom, want %v", got, want)
}
}
func TestReadZero(t *testing.T) {
for _, size := range []int{100, 2} {
t.Run(fmt.Sprintf("bufsize=%d", size), func(t *testing.T) {
@ -1312,6 +1427,7 @@ func TestReaderReset(t *testing.T) {
if string(buf) != "foo" {
t.Errorf("buf = %q; want foo", buf)
}
r.Reset(strings.NewReader("bar bar"))
all, err := io.ReadAll(r)
if err != nil {
@ -1320,12 +1436,23 @@ func TestReaderReset(t *testing.T) {
if string(all) != "bar bar" {
t.Errorf("ReadAll = %q; want bar bar", all)
}
*r = Reader{} // zero out the Reader
r.Reset(strings.NewReader("bar bar"))
all, err = io.ReadAll(r)
if err != nil {
t.Fatal(err)
}
if string(all) != "bar bar" {
t.Errorf("ReadAll = %q; want bar bar", all)
}
}
func TestWriterReset(t *testing.T) {
var buf1, buf2 bytes.Buffer
var buf1, buf2, buf3 bytes.Buffer
w := NewWriter(&buf1)
w.WriteString("foo")
w.Reset(&buf2) // and not flushed
w.WriteString("bar")
w.Flush()
@ -1335,6 +1462,17 @@ func TestWriterReset(t *testing.T) {
if buf2.String() != "bar" {
t.Errorf("buf2 = %q; want bar", buf2.String())
}
*w = Writer{} // zero out the Writer
w.Reset(&buf3) // and not flushed
w.WriteString("bar")
w.Flush()
if buf1.String() != "" {
t.Errorf("buf1 = %q; want empty", buf1.String())
}
if buf3.String() != "bar" {
t.Errorf("buf3 = %q; want bar", buf3.String())
}
}
func TestReaderDiscard(t *testing.T) {
@ -1382,7 +1520,7 @@ func TestReaderDiscard(t *testing.T) {
wantBuffered: 0,
},
// Any error from filling shouldn't show up until we
// get past the valid bytes. Here we return we return 5 valid bytes at the same time
// get past the valid bytes. Here we return 5 valid bytes at the same time
// as an error, but test that we don't see the error from Discard.
{
name: "fill error, discard less",

View File

@ -20,6 +20,18 @@ func ExampleWriter() {
// Output: Hello, world!
}
func ExampleWriter_AvailableBuffer() {
w := bufio.NewWriter(os.Stdout)
for _, i := range []int64{1, 2, 3, 4} {
b := w.AvailableBuffer()
b = strconv.AppendInt(b, i, 10)
b = append(b, ' ')
w.Write(b)
}
w.Flush()
// Output: 1 2 3 4
}
// The simplest use of a Scanner, to read standard input as a set of lines.
func ExampleScanner_lines() {
scanner := bufio.NewScanner(os.Stdin)

View File

@ -91,6 +91,16 @@ type byte = uint8
// used, by convention, to distinguish character values from integer values.
type rune = int32
// any is an alias for interface{} and is equivalent to interface{} in all ways.
type any = interface{}
// comparable is an interface that is implemented by all comparable types
// (booleans, numbers, strings, pointers, channels, interfaces,
// arrays of comparable types, structs whose fields are all comparable types).
// The comparable interface may only be used as a type parameter constraint,
// not as the type of a variable.
type comparable comparable
// iota is a predeclared identifier representing the untyped integer ordinal
// number of the current const specification in a (usually parenthesized)
// const declaration. It is zero-indexed.
@ -229,7 +239,7 @@ func close(c chan<- Type)
// that point, the program is terminated with a non-zero exit code. This
// termination sequence is called panicking and can be controlled by the
// built-in function recover.
func panic(v interface{})
func panic(v any)
// The recover built-in function allows a program to manage behavior of a
// panicking goroutine. Executing a call to recover inside a deferred
@ -240,7 +250,7 @@ func panic(v interface{})
// panicking, or if the argument supplied to panic was nil, recover returns
// nil. Thus the return value from recover reports whether the goroutine is
// panicking.
func recover() interface{}
func recover() any
// The print built-in function formats its arguments in an
// implementation-specific way and writes the result to standard error.

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//
//go:build linux
// +build linux
package bytes_test
@ -66,7 +65,11 @@ func TestIndexByteNearPageBoundary(t *testing.T) {
func TestIndexNearPageBoundary(t *testing.T) {
t.Parallel()
var q [64]byte
q := dangerousSlice(t)
if len(q) > 64 {
// Only worry about when we're near the end of a page.
q = q[len(q)-64:]
}
b := dangerousSlice(t)
if len(b) > 256 {
// Only worry about when we're near the end of a page.
@ -82,4 +85,16 @@ func TestIndexNearPageBoundary(t *testing.T) {
}
q[j-1] = 0
}
// Test differing alignments and sizes of q which always end on a page boundary.
q[len(q)-1] = 1 // difference is only found on the last byte
for j := 0; j < len(q); j++ {
for i := range b {
idx := Index(b[i:], q[j:])
if idx != -1 {
t.Fatalf("Index(b[%d:], q[%d:])=%d, want -1\n", i, j, idx)
}
}
}
q[len(q)-1] = 0
}

View File

@ -21,7 +21,7 @@ func Equal(a, b []byte) bool {
}
// Compare returns an integer comparing two byte slices lexicographically.
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
// The result will be 0 if a == b, -1 if a < b, and +1 if a > b.
// A nil argument is equivalent to an empty slice.
func Compare(a, b []byte) int {
return bytealg.Compare(a, b)
@ -699,7 +699,7 @@ func ToValidUTF8(s, replacement []byte) []byte {
if c < utf8.RuneSelf {
i++
invalid = false
b = append(b, byte(c))
b = append(b, c)
continue
}
_, wid := utf8.DecodeRune(s[i:])
@ -746,7 +746,8 @@ func isSeparator(r rune) bool {
// Title treats s as UTF-8-encoded bytes and returns a copy with all Unicode letters that begin
// words mapped to their title case.
//
// BUG(rsc): The rule Title uses for word boundaries does not handle Unicode punctuation properly.
// Deprecated: The rule Title uses for word boundaries does not handle Unicode
// punctuation properly. Use golang.org/x/text/cases instead.
func Title(s []byte) []byte {
// Use a closure here to remember state.
// Hackish but effective. Depends on Map scanning in order and calling
@ -867,6 +868,8 @@ func lastIndexFunc(s []byte, f func(r rune) bool, truth bool) int {
// most-significant bit of the highest word, map to the full range of all
// 128 ASCII characters. The 128-bits of the upper 16 bytes will be zeroed,
// ensuring that any non-ASCII character will be reported as not in the set.
// This allocates a total of 32 bytes even though the upper half
// is unused to avoid bounds checks in asciiSet.contains.
type asciiSet [8]uint32
// makeASCIISet creates a set of ASCII characters and reports whether all
@ -877,53 +880,133 @@ func makeASCIISet(chars string) (as asciiSet, ok bool) {
if c >= utf8.RuneSelf {
return as, false
}
as[c>>5] |= 1 << uint(c&31)
as[c/32] |= 1 << (c % 32)
}
return as, true
}
// contains reports whether c is inside the set.
func (as *asciiSet) contains(c byte) bool {
return (as[c>>5] & (1 << uint(c&31))) != 0
return (as[c/32] & (1 << (c % 32))) != 0
}
func makeCutsetFunc(cutset string) func(r rune) bool {
if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
return func(r rune) bool {
return r == rune(cutset[0])
// containsRune is a simplified version of strings.ContainsRune
// to avoid importing the strings package.
// We avoid bytes.ContainsRune to avoid allocating a temporary copy of s.
func containsRune(s string, r rune) bool {
for _, c := range s {
if c == r {
return true
}
}
if as, isASCII := makeASCIISet(cutset); isASCII {
return func(r rune) bool {
return r < utf8.RuneSelf && as.contains(byte(r))
}
}
return func(r rune) bool {
for _, c := range cutset {
if c == r {
return true
}
}
return false
}
return false
}
// Trim returns a subslice of s by slicing off all leading and
// trailing UTF-8-encoded code points contained in cutset.
func Trim(s []byte, cutset string) []byte {
return TrimFunc(s, makeCutsetFunc(cutset))
if len(s) == 0 || cutset == "" {
return s
}
if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
return trimLeftByte(trimRightByte(s, cutset[0]), cutset[0])
}
if as, ok := makeASCIISet(cutset); ok {
return trimLeftASCII(trimRightASCII(s, &as), &as)
}
return trimLeftUnicode(trimRightUnicode(s, cutset), cutset)
}
// TrimLeft returns a subslice of s by slicing off all leading
// UTF-8-encoded code points contained in cutset.
func TrimLeft(s []byte, cutset string) []byte {
return TrimLeftFunc(s, makeCutsetFunc(cutset))
if len(s) == 0 || cutset == "" {
return s
}
if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
return trimLeftByte(s, cutset[0])
}
if as, ok := makeASCIISet(cutset); ok {
return trimLeftASCII(s, &as)
}
return trimLeftUnicode(s, cutset)
}
func trimLeftByte(s []byte, c byte) []byte {
for len(s) > 0 && s[0] == c {
s = s[1:]
}
return s
}
func trimLeftASCII(s []byte, as *asciiSet) []byte {
for len(s) > 0 {
if !as.contains(s[0]) {
break
}
s = s[1:]
}
return s
}
func trimLeftUnicode(s []byte, cutset string) []byte {
for len(s) > 0 {
r, n := rune(s[0]), 1
if r >= utf8.RuneSelf {
r, n = utf8.DecodeRune(s)
}
if !containsRune(cutset, r) {
break
}
s = s[n:]
}
return s
}
// TrimRight returns a subslice of s by slicing off all trailing
// UTF-8-encoded code points that are contained in cutset.
func TrimRight(s []byte, cutset string) []byte {
return TrimRightFunc(s, makeCutsetFunc(cutset))
if len(s) == 0 || cutset == "" {
return s
}
if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
return trimRightByte(s, cutset[0])
}
if as, ok := makeASCIISet(cutset); ok {
return trimRightASCII(s, &as)
}
return trimRightUnicode(s, cutset)
}
func trimRightByte(s []byte, c byte) []byte {
for len(s) > 0 && s[len(s)-1] == c {
s = s[:len(s)-1]
}
return s
}
func trimRightASCII(s []byte, as *asciiSet) []byte {
for len(s) > 0 {
if !as.contains(s[len(s)-1]) {
break
}
s = s[:len(s)-1]
}
return s
}
func trimRightUnicode(s []byte, cutset string) []byte {
for len(s) > 0 {
r, n := rune(s[len(s)-1]), 1
if r >= utf8.RuneSelf {
r, n = utf8.DecodeLastRune(s)
}
if !containsRune(cutset, r) {
break
}
s = s[:len(s)-n]
}
return s
}
// TrimSpace returns a subslice of s by slicing off all leading and
@ -1174,3 +1257,16 @@ func Index(s, sep []byte) int {
}
return -1
}
// Cut slices s around the first instance of sep,
// returning the text before and after sep.
// The found result reports whether sep appears in s.
// If sep does not appear in s, cut returns s, nil, false.
//
// Cut returns slices of the original slice s, not copies.
func Cut(s, sep []byte) (before, after []byte, found bool) {
if i := Index(s, sep); i >= 0 {
return s[:i], s[i+len(sep):], true
}
return s, nil, false
}

View File

@ -1256,7 +1256,9 @@ var trimTests = []TrimTest{
{"TrimLeft", "abba", "ab", ""},
{"TrimRight", "abba", "ab", ""},
{"TrimLeft", "abba", "a", "bba"},
{"TrimLeft", "abba", "b", "abba"},
{"TrimRight", "abba", "a", "abb"},
{"TrimRight", "abba", "b", "abba"},
{"Trim", "<tag>", "<>", "tag"},
{"Trim", "* listitem", " *", "listitem"},
{"Trim", `"quote"`, `"`, "quote"},
@ -1570,6 +1572,29 @@ func TestEqualFold(t *testing.T) {
}
}
var cutTests = []struct {
s, sep string
before, after string
found bool
}{
{"abc", "b", "a", "c", true},
{"abc", "a", "", "bc", true},
{"abc", "c", "ab", "", true},
{"abc", "abc", "", "", true},
{"abc", "", "", "abc", true},
{"abc", "d", "abc", "", false},
{"", "d", "", "", false},
{"", "", "", "", true},
}
func TestCut(t *testing.T) {
for _, tt := range cutTests {
if before, after, found := Cut([]byte(tt.s), []byte(tt.sep)); string(before) != tt.before || string(after) != tt.after || found != tt.found {
t.Errorf("Cut(%q, %q) = %q, %q, %v, want %q, %q, %v", tt.s, tt.sep, before, after, found, tt.before, tt.after, tt.found)
}
}
}
func TestBufferGrowNegative(t *testing.T) {
defer func() {
if err := recover(); err == nil {
@ -1968,6 +1993,13 @@ func BenchmarkTrimASCII(b *testing.B) {
}
}
func BenchmarkTrimByte(b *testing.B) {
x := []byte(" the quick brown fox ")
for i := 0; i < b.N; i++ {
Trim(x, " ")
}
}
func BenchmarkIndexPeriodic(b *testing.B) {
key := []byte{1, 1}
for _, skip := range [...]int{2, 4, 8, 16, 32, 64} {

View File

@ -37,6 +37,16 @@ func ExampleBuffer_Bytes() {
// Output: hello world
}
func ExampleBuffer_Cap() {
buf1 := bytes.NewBuffer(make([]byte, 10))
buf2 := bytes.NewBuffer(make([]byte, 0, 10))
fmt.Println(buf1.Cap())
fmt.Println(buf2.Cap())
// Output:
// 10
// 10
}
func ExampleBuffer_Grow() {
var b bytes.Buffer
b.Grow(64)
@ -54,6 +64,52 @@ func ExampleBuffer_Len() {
// Output: 5
}
func ExampleBuffer_Next() {
var b bytes.Buffer
b.Grow(64)
b.Write([]byte("abcde"))
fmt.Printf("%s\n", string(b.Next(2)))
fmt.Printf("%s\n", string(b.Next(2)))
fmt.Printf("%s", string(b.Next(2)))
// Output:
// ab
// cd
// e
}
func ExampleBuffer_Read() {
var b bytes.Buffer
b.Grow(64)
b.Write([]byte("abcde"))
rdbuf := make([]byte, 1)
n, err := b.Read(rdbuf)
if err != nil {
panic(err)
}
fmt.Println(n)
fmt.Println(b.String())
fmt.Println(string(rdbuf))
// Output
// 1
// bcde
// a
}
func ExampleBuffer_ReadByte() {
var b bytes.Buffer
b.Grow(64)
b.Write([]byte("abcde"))
c, err := b.ReadByte()
if err != nil {
panic(err)
}
fmt.Println(c)
fmt.Println(b.String())
// Output
// 97
// bcde
}
func ExampleCompare() {
// Interpret Compare's result by comparing it to zero.
var a, b []byte
@ -92,36 +148,6 @@ func ExampleCompare_search() {
}
}
func ExampleTrimSuffix() {
var b = []byte("Hello, goodbye, etc!")
b = bytes.TrimSuffix(b, []byte("goodbye, etc!"))
b = bytes.TrimSuffix(b, []byte("gopher"))
b = append(b, bytes.TrimSuffix([]byte("world!"), []byte("x!"))...)
os.Stdout.Write(b)
// Output: Hello, world!
}
func ExampleTrimPrefix() {
var b = []byte("Goodbye,, world!")
b = bytes.TrimPrefix(b, []byte("Goodbye,"))
b = bytes.TrimPrefix(b, []byte("See ya,"))
fmt.Printf("Hello%s", b)
// Output: Hello, world!
}
func ExampleFields() {
fmt.Printf("Fields are: %q", bytes.Fields([]byte(" foo bar baz ")))
// Output: Fields are: ["foo" "bar" "baz"]
}
func ExampleFieldsFunc() {
f := func(c rune) bool {
return !unicode.IsLetter(c) && !unicode.IsNumber(c)
}
fmt.Printf("Fields are: %q", bytes.FieldsFunc([]byte(" foo1;bar2,baz3..."), f))
// Output: Fields are: ["foo1" "bar2" "baz3"]
}
func ExampleContains() {
fmt.Println(bytes.Contains([]byte("seafood"), []byte("foo")))
fmt.Println(bytes.Contains([]byte("seafood"), []byte("bar")))
@ -168,6 +194,22 @@ func ExampleCount() {
// 5
}
func ExampleCut() {
show := func(s, sep string) {
before, after, found := bytes.Cut([]byte(s), []byte(sep))
fmt.Printf("Cut(%q, %q) = %q, %q, %v\n", s, sep, before, after, found)
}
show("Gopher", "Go")
show("Gopher", "ph")
show("Gopher", "er")
show("Gopher", "Badger")
// Output:
// Cut("Gopher", "Go") = "", "pher", true
// Cut("Gopher", "ph") = "Go", "er", true
// Cut("Gopher", "er") = "Goph", "", true
// Cut("Gopher", "Badger") = "Gopher", "", false
}
func ExampleEqual() {
fmt.Println(bytes.Equal([]byte("Go"), []byte("Go")))
fmt.Println(bytes.Equal([]byte("Go"), []byte("C++")))
@ -181,6 +223,19 @@ func ExampleEqualFold() {
// Output: true
}
func ExampleFields() {
fmt.Printf("Fields are: %q", bytes.Fields([]byte(" foo bar baz ")))
// Output: Fields are: ["foo" "bar" "baz"]
}
func ExampleFieldsFunc() {
f := func(c rune) bool {
return !unicode.IsLetter(c) && !unicode.IsNumber(c)
}
fmt.Printf("Fields are: %q", bytes.FieldsFunc([]byte(" foo1;bar2,baz3..."), f))
// Output: Fields are: ["foo1" "bar2" "baz3"]
}
func ExampleHasPrefix() {
fmt.Println(bytes.HasPrefix([]byte("Gopher"), []byte("Go")))
fmt.Println(bytes.HasPrefix([]byte("Gopher"), []byte("C")))
@ -246,6 +301,12 @@ func ExampleIndexRune() {
// -1
}
func ExampleJoin() {
s := [][]byte{[]byte("foo"), []byte("bar"), []byte("baz")}
fmt.Printf("%s", bytes.Join(s, []byte(", ")))
// Output: foo, bar, baz
}
func ExampleLastIndex() {
fmt.Println(bytes.Index([]byte("go gopher"), []byte("go")))
fmt.Println(bytes.LastIndex([]byte("go gopher"), []byte("go")))
@ -286,10 +347,12 @@ func ExampleLastIndexFunc() {
// -1
}
func ExampleJoin() {
s := [][]byte{[]byte("foo"), []byte("bar"), []byte("baz")}
fmt.Printf("%s", bytes.Join(s, []byte(", ")))
// Output: foo, bar, baz
func ExampleReader_Len() {
fmt.Println(bytes.NewReader([]byte("Hi!")).Len())
fmt.Println(bytes.NewReader([]byte("こんにちは!")).Len())
// Output:
// 3
// 16
}
func ExampleRepeat() {
@ -399,20 +462,6 @@ func ExampleTrimFunc() {
// go-gopher!
}
func ExampleMap() {
rot13 := func(r rune) rune {
switch {
case r >= 'A' && r <= 'Z':
return 'A' + (r-'A'+13)%26
case r >= 'a' && r <= 'z':
return 'a' + (r-'a'+13)%26
}
return r
}
fmt.Printf("%s", bytes.Map(rot13, []byte("'Twas brillig and the slithy gopher...")))
// Output: 'Gjnf oevyyvt naq gur fyvgul tbcure...
}
func ExampleTrimLeft() {
fmt.Print(string(bytes.TrimLeft([]byte("453gopher8257"), "0123456789")))
// Output:
@ -429,11 +478,28 @@ func ExampleTrimLeftFunc() {
// go-gopher!567
}
func ExampleTrimPrefix() {
var b = []byte("Goodbye,, world!")
b = bytes.TrimPrefix(b, []byte("Goodbye,"))
b = bytes.TrimPrefix(b, []byte("See ya,"))
fmt.Printf("Hello%s", b)
// Output: Hello, world!
}
func ExampleTrimSpace() {
fmt.Printf("%s", bytes.TrimSpace([]byte(" \t\n a lone gopher \n\t\r\n")))
// Output: a lone gopher
}
func ExampleTrimSuffix() {
var b = []byte("Hello, goodbye, etc!")
b = bytes.TrimSuffix(b, []byte("goodbye, etc!"))
b = bytes.TrimSuffix(b, []byte("gopher"))
b = append(b, bytes.TrimSuffix([]byte("world!"), []byte("x!"))...)
os.Stdout.Write(b)
// Output: Hello, world!
}
func ExampleTrimRight() {
fmt.Print(string(bytes.TrimRight([]byte("453gopher8257"), "0123456789")))
// Output:
@ -450,21 +516,6 @@ func ExampleTrimRightFunc() {
// 1234go-gopher!
}
func ExampleToUpper() {
fmt.Printf("%s", bytes.ToUpper([]byte("Gopher")))
// Output: GOPHER
}
func ExampleToUpperSpecial() {
str := []byte("ahoj vývojári golang")
totitle := bytes.ToUpperSpecial(unicode.AzeriCase, str)
fmt.Println("Original : " + string(str))
fmt.Println("ToUpper : " + string(totitle))
// Output:
// Original : ahoj vývojári golang
// ToUpper : AHOJ VÝVOJÁRİ GOLANG
}
func ExampleToLower() {
fmt.Printf("%s", bytes.ToLower([]byte("Gopher")))
// Output: gopher
@ -480,10 +531,17 @@ func ExampleToLowerSpecial() {
// ToLower : ahoj vývojári golang
}
func ExampleReader_Len() {
fmt.Println(bytes.NewReader([]byte("Hi!")).Len())
fmt.Println(bytes.NewReader([]byte("こんにちは!")).Len())
// Output:
// 3
// 16
func ExampleToUpper() {
fmt.Printf("%s", bytes.ToUpper([]byte("Gopher")))
// Output: GOPHER
}
func ExampleToUpperSpecial() {
str := []byte("ahoj vývojári golang")
totitle := bytes.ToUpperSpecial(unicode.AzeriCase, str)
fmt.Println("Original : " + string(str))
fmt.Println("ToUpper : " + string(totitle))
// Output:
// Original : ahoj vývojári golang
// ToUpper : AHOJ VÝVOJÁRİ GOLANG
}

View File

@ -76,7 +76,7 @@ func TestReaderAt(t *testing.T) {
off int64
n int
want string
wanterr interface{}
wanterr any
}{
{0, 10, "0123456789", nil},
{1, 10, "123456789", io.EOF},

View File

@ -338,8 +338,7 @@ func (f *File) walk(x interface{}, context astContext, visit func(*File, interfa
// everything else just recurs
default:
error_(token.NoPos, "unexpected type %T in walk", x)
panic("unexpected type")
f.walkUnexpected(x, context, visit)
case nil:

View File

@ -0,0 +1,17 @@
// Copyright 2021 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.
//go:build compiler_bootstrap
// +build compiler_bootstrap
package main
import (
"go/token"
)
func (f *File) walkUnexpected(x interface{}, context astContext, visit func(*File, interface{}, astContext)) {
error_(token.NoPos, "unexpected type %T in walk", x)
panic("unexpected type")
}

View File

@ -0,0 +1,25 @@
// Copyright 2021 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.
//go:build !compiler_bootstrap
// +build !compiler_bootstrap
package main
import (
"go/ast"
"go/token"
)
func (f *File) walkUnexpected(x interface{}, context astContext, visit func(*File, interface{}, astContext)) {
switch n := x.(type) {
default:
error_(token.NoPos, "unexpected type %T in walk", x)
panic("unexpected type")
case *ast.IndexListExpr:
f.walk(&n.X, ctxExpr, visit)
f.walk(n.Indices, ctxExpr, visit)
}
}

View File

@ -23,10 +23,13 @@ import (
"internal/xcoff"
"math"
"os"
"os/exec"
"strconv"
"strings"
"unicode"
"unicode/utf8"
"cmd/internal/quoted"
)
var debugDefine = flag.Bool("debug-define", false, "print relevant #defines")
@ -400,7 +403,7 @@ func (p *Package) guessKinds(f *File) []*Name {
stderr = p.gccErrors(b.Bytes())
}
if stderr == "" {
fatalf("%s produced no output\non input:\n%s", p.gccBaseCmd()[0], b.Bytes())
fatalf("%s produced no output\non input:\n%s", gccBaseCmd[0], b.Bytes())
}
completed := false
@ -475,7 +478,7 @@ func (p *Package) guessKinds(f *File) []*Name {
}
if !completed {
fatalf("%s did not produce error at completed:1\non input:\n%s\nfull error output:\n%s", p.gccBaseCmd()[0], b.Bytes(), stderr)
fatalf("%s did not produce error at completed:1\non input:\n%s\nfull error output:\n%s", gccBaseCmd[0], b.Bytes(), stderr)
}
for i, n := range names {
@ -506,7 +509,7 @@ func (p *Package) guessKinds(f *File) []*Name {
// to users debugging preamble mistakes. See issue 8442.
preambleErrors := p.gccErrors([]byte(f.Preamble))
if len(preambleErrors) > 0 {
error_(token.NoPos, "\n%s errors for preamble:\n%s", p.gccBaseCmd()[0], preambleErrors)
error_(token.NoPos, "\n%s errors for preamble:\n%s", gccBaseCmd[0], preambleErrors)
}
fatalf("unresolved names")
@ -1521,7 +1524,7 @@ func (p *Package) rewriteName(f *File, r *Ref, addPosition bool) ast.Expr {
Args: []ast.Expr{getNewIdent(name.Mangle)},
}
case "type":
// Okay - might be new(T)
// Okay - might be new(T), T(x), Generic[T], etc.
if r.Name.Type == nil {
error_(r.Pos(), "expression C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
}
@ -1563,20 +1566,37 @@ func gofmtPos(n ast.Expr, pos token.Pos) string {
return fmt.Sprintf("/*line :%d:%d*/%s", p.Line, p.Column, s)
}
// gccBaseCmd returns the start of the compiler command line.
// checkGCCBaseCmd returns the start of the compiler command line.
// It uses $CC if set, or else $GCC, or else the compiler recorded
// during the initial build as defaultCC.
// defaultCC is defined in zdefaultcc.go, written by cmd/dist.
func (p *Package) gccBaseCmd() []string {
//
// The compiler command line is split into arguments on whitespace. Quotes
// are understood, so arguments may contain whitespace.
//
// checkGCCBaseCmd confirms that the compiler exists in PATH, returning
// an error if it does not.
func checkGCCBaseCmd() ([]string, error) {
// Use $CC if set, since that's what the build uses.
if ret := strings.Fields(os.Getenv("CC")); len(ret) > 0 {
return ret
value := os.Getenv("CC")
if value == "" {
// Try $GCC if set, since that's what we used to use.
value = os.Getenv("GCC")
}
// Try $GCC if set, since that's what we used to use.
if ret := strings.Fields(os.Getenv("GCC")); len(ret) > 0 {
return ret
if value == "" {
value = defaultCC(goos, goarch)
}
return strings.Fields(defaultCC(goos, goarch))
args, err := quoted.Split(value)
if err != nil {
return nil, err
}
if len(args) == 0 {
return nil, errors.New("CC not set and no default found")
}
if _, err := exec.LookPath(args[0]); err != nil {
return nil, fmt.Errorf("C compiler %q not found: %v", args[0], err)
}
return args[:len(args):len(args)], nil
}
// gccMachine returns the gcc -m flag to use, either "-m32", "-m64" or "-marm".
@ -1630,7 +1650,7 @@ func gccTmp() string {
// gccCmd returns the gcc command line to use for compiling
// the input.
func (p *Package) gccCmd() []string {
c := append(p.gccBaseCmd(),
c := append(gccBaseCmd,
"-w", // no warnings
"-Wno-error", // warnings are not errors
"-o"+gccTmp(), // write object to tmp
@ -2030,7 +2050,7 @@ func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int6
// #defines that gcc encountered while processing the input
// and its included files.
func (p *Package) gccDefines(stdin []byte) string {
base := append(p.gccBaseCmd(), "-E", "-dM", "-xc")
base := append(gccBaseCmd, "-E", "-dM", "-xc")
base = append(base, p.gccMachine()...)
stdout, _ := runGcc(stdin, append(append(base, p.GccOptions...), "-"))
return stdout
@ -2111,6 +2131,9 @@ type typeConv struct {
// Type names X for which there exists an XGetTypeID function with type func() CFTypeID.
getTypeIDs map[string]bool
// badStructs contains C structs that should be marked NotInHeap.
notInHeapStructs map[string]bool
// Predeclared types.
bool ast.Expr
byte ast.Expr // denotes padding
@ -2122,6 +2145,7 @@ type typeConv struct {
string ast.Expr
goVoid ast.Expr // _Ctype_void, denotes C's void
goVoidPtr ast.Expr // unsafe.Pointer or *byte
goVoidPtrNoHeap ast.Expr // *_Ctype_void_notinheap, like goVoidPtr but marked NotInHeap
ptrSize int64
intSize int64
@ -2145,6 +2169,7 @@ func (c *typeConv) Init(ptrSize, intSize int64) {
c.m = make(map[string]*Type)
c.ptrs = make(map[string][]*Type)
c.getTypeIDs = make(map[string]bool)
c.notInHeapStructs = make(map[string]bool)
c.bool = c.Ident("bool")
c.byte = c.Ident("byte")
c.int8 = c.Ident("int8")
@ -2163,6 +2188,7 @@ func (c *typeConv) Init(ptrSize, intSize int64) {
c.void = c.Ident("void")
c.string = c.Ident("string")
c.goVoid = c.Ident("_Ctype_void")
c.goVoidPtrNoHeap = c.Ident("*_Ctype_void_notinheap")
// Normally cgo translates void* to unsafe.Pointer,
// but for historical reasons -godefs uses *byte instead.
@ -2543,6 +2569,7 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ
tt.C = &TypeRepr{"struct %s", []interface{}{tag}}
}
tt.Go = g
tt.NotInHeap = c.notInHeapStructs[tag]
typedef[name.Name] = &tt
}
@ -2586,6 +2613,30 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ
oldType.BadPointer = true
}
}
if c.badVoidPointerTypedef(dt) {
// Treat this typedef as a pointer to a NotInHeap void.
s := *sub
s.Go = c.goVoidPtrNoHeap
sub = &s
// Make sure we update any previously computed type.
if oldType := typedef[name.Name]; oldType != nil {
oldType.Go = sub.Go
}
}
// Check for non-pointer "struct <tag>{...}; typedef struct <tag> *<name>"
// typedefs that should be marked NotInHeap.
if ptr, ok := dt.Type.(*dwarf.PtrType); ok {
if strct, ok := ptr.Type.(*dwarf.StructType); ok {
if c.badStructPointerTypedef(dt.Name, strct) {
c.notInHeapStructs[strct.StructName] = true
// Make sure we update any previously computed type.
name := "_Ctype_struct_" + strct.StructName
if oldType := typedef[name]; oldType != nil {
oldType.NotInHeap = true
}
}
}
}
t.Go = name
t.BadPointer = sub.BadPointer
t.NotInHeap = sub.NotInHeap
@ -3035,6 +3086,31 @@ func upper(s string) string {
// so that all fields are exported.
func godefsFields(fld []*ast.Field) {
prefix := fieldPrefix(fld)
// Issue 48396: check for duplicate field names.
if prefix != "" {
names := make(map[string]bool)
fldLoop:
for _, f := range fld {
for _, n := range f.Names {
name := n.Name
if name == "_" {
continue
}
if name != prefix {
name = strings.TrimPrefix(n.Name, prefix)
}
name = upper(name)
if names[name] {
// Field name conflict: don't remove prefix.
prefix = ""
break fldLoop
}
names[name] = true
}
}
}
npad := 0
for _, f := range fld {
for _, n := range f.Names {
@ -3112,6 +3188,48 @@ func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool {
return false
}
// badVoidPointerTypedef is like badPointerTypeDef, but for "void *" typedefs that should be NotInHeap.
func (c *typeConv) badVoidPointerTypedef(dt *dwarf.TypedefType) bool {
// Match the Windows HANDLE type (#42018).
if goos != "windows" || dt.Name != "HANDLE" {
return false
}
// Check that the typedef is "typedef void *<name>".
if ptr, ok := dt.Type.(*dwarf.PtrType); ok {
if _, ok := ptr.Type.(*dwarf.VoidType); ok {
return true
}
}
return false
}
// badStructPointerTypedef is like badVoidPointerTypedefs but for structs.
func (c *typeConv) badStructPointerTypedef(name string, dt *dwarf.StructType) bool {
// Windows handle types can all potentially contain non-pointers.
// badVoidPointerTypedef handles the "void *" HANDLE type, but other
// handles are defined as
//
// struct <name>__{int unused;}; typedef struct <name>__ *name;
//
// by the DECLARE_HANDLE macro in STRICT mode. The macro is declared in
// the Windows ntdef.h header,
//
// https://github.com/tpn/winsdk-10/blob/master/Include/10.0.16299.0/shared/ntdef.h#L779
if goos != "windows" {
return false
}
if len(dt.Field) != 1 {
return false
}
if dt.StructName != name+"__" {
return false
}
if f := dt.Field[0]; f.Name != "unused" || f.Type.Common().Name != "int" {
return false
}
return true
}
// baseBadPointerTypedef reports whether the base of a chain of typedefs is a bad typedef
// as badPointerTypedef reports.
func (c *typeConv) baseBadPointerTypedef(dt *dwarf.TypedefType) bool {

View File

@ -21,7 +21,6 @@ import (
"io"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"reflect"
"runtime"
@ -252,6 +251,7 @@ var importSyscall = flag.Bool("import_syscall", true, "import syscall in generat
var trimpath = flag.String("trimpath", "", "applies supplied rewrites or trims prefixes to recorded source file paths")
var goarch, goos, gomips, gomips64 string
var gccBaseCmd []string
func main() {
objabi.AddVersionFlag() // -V
@ -309,10 +309,10 @@ func main() {
p := newPackage(args[:i])
// We need a C compiler to be available. Check this.
gccName := p.gccBaseCmd()[0]
_, err := exec.LookPath(gccName)
var err error
gccBaseCmd, err = checkGCCBaseCmd()
if err != nil {
fatalf("C compiler %q not found: %v", gccName, err)
fatalf("%v", err)
os.Exit(2)
}

View File

@ -64,9 +64,9 @@ func (p *Package) writeDefs() {
// Write C main file for using gcc to resolve imports.
fmt.Fprintf(fm, "int main() { return 0; }\n")
if *importRuntimeCgo {
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*), void *a, int c, __SIZE_TYPE__ ctxt) { }\n")
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*) __attribute__((unused)), void *a __attribute__((unused)), int c __attribute__((unused)), __SIZE_TYPE__ ctxt __attribute__((unused))) { }\n")
fmt.Fprintf(fm, "__SIZE_TYPE__ _cgo_wait_runtime_init_done(void) { return 0; }\n")
fmt.Fprintf(fm, "void _cgo_release_context(__SIZE_TYPE__ ctxt) { }\n")
fmt.Fprintf(fm, "void _cgo_release_context(__SIZE_TYPE__ ctxt __attribute__((unused))) { }\n")
fmt.Fprintf(fm, "char* _cgo_topofstack(void) { return (char*)0; }\n")
} else {
// If we're not importing runtime/cgo, we *are* runtime/cgo,
@ -75,8 +75,8 @@ func (p *Package) writeDefs() {
fmt.Fprintf(fm, "__SIZE_TYPE__ _cgo_wait_runtime_init_done(void);\n")
fmt.Fprintf(fm, "void _cgo_release_context(__SIZE_TYPE__);\n")
}
fmt.Fprintf(fm, "void _cgo_allocate(void *a, int c) { }\n")
fmt.Fprintf(fm, "void _cgo_panic(void *a, int c) { }\n")
fmt.Fprintf(fm, "void _cgo_allocate(void *a __attribute__((unused)), int c __attribute__((unused))) { }\n")
fmt.Fprintf(fm, "void _cgo_panic(void *a __attribute__((unused)), int c __attribute__((unused))) { }\n")
fmt.Fprintf(fm, "void _cgo_reginit(void) { }\n")
// Write second Go output: definitions of _C_xxx.
@ -140,6 +140,7 @@ func (p *Package) writeDefs() {
fmt.Fprintf(fgo2, "%s", buf.Bytes())
fmt.Fprintf(fgo2, "\n\n")
}
fmt.Fprintf(fgo2, "//go:notinheap\ntype _Ctype_void_notinheap struct{}\n\n")
if *gccgo {
fmt.Fprintf(fgo2, "type _Ctype_void byte\n")
} else {
@ -1059,9 +1060,10 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
fmt.Fprintf(fm, "void _cgoexp%s_%s(void* p){}\n", cPrefix, exp.ExpName)
fmt.Fprintf(fgo2, "\t")
if gccResult != "void" {
// Write results back to frame.
fmt.Fprintf(fgo2, "\t")
forFieldList(fntype.Results,
func(i int, aname string, atype ast.Expr) {
if i > 0 {
@ -1463,10 +1465,10 @@ const gccProlog = `
(have a negative array count) and an inscrutable error will come
out of the compiler and hopefully mention "name".
*/
#define __cgo_compile_assert_eq(x, y, name) typedef char name[(x-y)*(x-y)*-2+1];
#define __cgo_compile_assert_eq(x, y, name) typedef char name[(x-y)*(x-y)*-2UL+1UL];
/* 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)
#define __cgo_size_assert(t, n) __cgo_compile_assert_eq(sizeof(t), (size_t)n, _cgo_sizeof_##t##_is_not_##n)
__cgo_size_assert(char, 1)
__cgo_size_assert(short, 2)

View File

@ -1,15 +1,19 @@
module cmd
go 1.17
go 1.18
require (
github.com/google/pprof v0.0.0-20210506205249-923b5ab0fc1a
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639 // indirect
golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e
golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e // indirect
golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a
golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 // indirect
golang.org/x/term v0.0.0-20210503060354-a79de5458b56
golang.org/x/tools v0.1.2-0.20210519160823-49064d2332f9
github.com/google/pprof v0.0.0-20211104044539-f987b9c94b31
golang.org/x/arch v0.0.0-20210923205945-b76863e36670
golang.org/x/mod v0.6.0-dev.0.20211102181907-3a5865c02020
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
golang.org/x/tools v0.1.9-0.20220124164225-97de9ec46646
)
require (
github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d // indirect
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
)

View File

@ -25,6 +25,7 @@
// install compile and install packages and dependencies
// list list packages or modules
// mod module maintenance
// work workspace maintenance
// run compile and run Go program
// test test packages
// tool run specified go tool
@ -114,13 +115,16 @@
// The default is GOMAXPROCS, normally the number of CPUs available.
// -race
// enable data race detection.
// Supported only on linux/amd64, freebsd/amd64, darwin/amd64, windows/amd64,
// Supported only on linux/amd64, freebsd/amd64, darwin/amd64, darwin/arm64, windows/amd64,
// linux/ppc64le and linux/arm64 (only for 48-bit VMA).
// -msan
// enable interoperation with memory sanitizer.
// Supported only on linux/amd64, linux/arm64
// and only with Clang/LLVM as the host C compiler.
// On linux/arm64, pie build mode will be used.
// -asan
// enable interoperation with address sanitizer.
// Supported only on linux/arm64, linux/amd64.
// -v
// print the names of packages as they are compiled.
// -work
@ -133,6 +137,12 @@
// arguments to pass on each go tool asm invocation.
// -buildmode mode
// build mode to use. See 'go help buildmode' for more.
// -buildvcs
// Whether to stamp binaries with version control information. By default,
// version control information is stamped into a binary if the main package
// and the main module containing it are in the repository containing the
// current directory (if there is a repository). Use -buildvcs=false to
// omit version control information.
// -compiler name
// name of compiler to use, as in runtime.Compiler (gccgo or gc).
// -gccgoflags '[pattern=]arg list'
@ -144,8 +154,8 @@
// 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
// has a similar effect.
// and -asan flags. Using a -buildmode option that requires non-default compile
// flags has a similar effect.
// -ldflags '[pattern=]arg list'
// arguments to pass on each go tool link invocation.
// -linkshared
@ -167,6 +177,14 @@
// directory, but it is not accessed. When -modfile is specified, an
// alternate go.sum file is also used: its path is derived from the
// -modfile flag by trimming the ".mod" extension and appending ".sum".
// -workfile file
// in module aware mode, use the given go.work file as a workspace file.
// By default or when -workfile is "auto", the go command searches for a
// file named go.work in the current directory and then containing directories
// until one is found. If a valid go.work file is found, the modules
// specified will collectively be used as the main modules. If -workfile
// is "off", or a go.work file is not found in "auto" mode, workspace
// mode is disabled.
// -overlay file
// read a JSON config file that provides an overlay for build operations.
// The file is a JSON struct with a single field, named 'Replace', that
@ -191,9 +209,8 @@
// -trimpath
// remove all file system paths from the resulting executable.
// Instead of absolute file system paths, the recorded file names
// will begin with either "go" (for the standard library),
// or a module path@version (when using modules),
// or a plain import path (when using GOPATH).
// will begin either a module path@version (when using modules),
// or a plain import path (when using the standard library, or GOPATH).
// -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
@ -284,6 +301,13 @@
// download cache, including unpacked source code of versioned
// dependencies.
//
// The -fuzzcache flag causes clean to remove files stored in the Go build
// cache for fuzz testing. The fuzzing engine caches files that expand
// code coverage, so removing them may make fuzzing less effective until
// new inputs are found that provide the same coverage. These files are
// distinct from those stored in testdata directory; clean does not remove
// those files.
//
// For more about build flags, see 'go help build'.
//
// For more about specifying packages, see 'go help packages'.
@ -338,9 +362,8 @@
// 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 with method or struct field.
// This is similar to the syntax accepted by godoc:
// When run with two arguments, the first is a package path (full path or suffix),
// and the second is a symbol, or symbol with method or struct field:
//
// go doc <pkg> <sym>[.<methodOrField>]
//
@ -438,14 +461,18 @@
//
// Usage:
//
// go fix [packages]
// go fix [-fix list] [packages]
//
// Fix runs the Go fix command on the packages named by the import paths.
//
// The -fix flag sets a comma-separated list of fixes to run.
// The default is all known fixes.
// (Its value is passed to 'go tool fix -r'.)
//
// For more about fix, see 'go doc cmd/fix'.
// For more about specifying packages, see 'go help packages'.
//
// To run fix with specific options, run 'go tool fix'.
// To run fix with other options, run 'go tool fix'.
//
// See also: go fmt, go vet.
//
@ -483,7 +510,7 @@
// files. Those commands can run any process but the intent is to
// create or update Go source files.
//
// Go generate is never run automatically by go build, go get, go test,
// Go generate is never run automatically by go build, go test,
// and so on. It must be run explicitly.
//
// Go generate scans the file for directives, which are lines of
@ -598,11 +625,11 @@
//
// Usage:
//
// go get [-d] [-t] [-u] [-v] [build flags] [packages]
// go get [-t] [-u] [-v] [build flags] [packages]
//
// Get resolves its command-line arguments to packages at specific module versions,
// updates go.mod to require those versions, downloads source code into the
// module cache, then builds and installs the named packages.
// updates go.mod to require those versions, and downloads source code into the
// module cache.
//
// To add a dependency for a package or upgrade it to its latest version:
//
@ -618,17 +645,18 @@
//
// See https://golang.org/ref/mod#go-get for details.
//
// The 'go install' command may be used to build and install packages. When a
// version is specified, 'go install' runs in module-aware mode and ignores
// the go.mod file in the current directory. For example:
// In earlier versions of Go, 'go get' was used to build and install packages.
// Now, 'go get' is dedicated to adjusting dependencies in go.mod. 'go install'
// may be used to build and install commands instead. When a version is specified,
// 'go install' runs in module-aware mode and ignores the go.mod file in the
// current directory. For example:
//
// go install example.com/pkg@v1.2.3
// go install example.com/pkg@latest
//
// See 'go help install' or https://golang.org/ref/mod#go-install for details.
//
// In addition to build flags (listed in 'go help build') 'go get' accepts the
// following flags.
// 'go get' accepts the following flags.
//
// The -t flag instructs get to consider modules needed to build tests of
// packages specified on the command line.
@ -643,15 +671,9 @@
// When the -t and -u flags are used together, get will update
// test dependencies as well.
//
// The -d flag instructs get not to build or install packages. get will only
// update go.mod and download source code needed to build packages.
//
// Building and installing packages with get is deprecated. In a future release,
// the -d flag will be enabled by default, and 'go get' will be only be used to
// adjust dependencies of the current module. To install a package using
// dependencies from the current module, use 'go install'. To install a package
// ignoring the current module, use 'go install' with an @version suffix like
// "@latest" after each argument.
// The -x flag prints commands as they are executed. This is useful for
// debugging version control commands when a module is downloaded directly
// from a repository.
//
// For more about modules, see https://golang.org/ref/mod.
//
@ -694,14 +716,17 @@
//
// - All arguments must refer to packages in the same module at the same version.
//
// - Package path arguments must refer to main packages. Pattern arguments
// will only match main packages.
//
// - No module is considered the "main" module. If the module containing
// packages named on the command line has a go.mod file, it must not contain
// directives (replace and exclude) that would cause it to be interpreted
// differently than if it were the main module. The module must not require
// a higher version of itself.
//
// - Package path arguments must refer to main packages. Pattern arguments
// will only match main packages.
// - Vendor directories are not used in any module. (Vendor directories are not
// included in the module zip files downloaded by 'go install'.)
//
// If the arguments don't have version suffixes, "go install" may run in
// module-aware mode or GOPATH mode, depending on the GO111MODULE environment
@ -1041,8 +1066,11 @@
//
// Download downloads the named modules, which can be module patterns selecting
// dependencies of the main module or module queries of the form path@version.
// With no arguments, download applies to all dependencies of the main module
// (equivalent to 'go mod download all').
//
// With no arguments, download applies to the modules needed to build and test
// the packages in the main module: the modules explicitly required by the main
// module if it is at 'go 1.17' or higher, or all transitively-required modules
// if at 'go 1.16' or lower.
//
// The go command will automatically download modules as needed during ordinary
// execution. The "go mod download" command is useful mainly for pre-filling
@ -1260,7 +1288,7 @@
//
// Usage:
//
// go mod vendor [-e] [-v]
// go mod vendor [-e] [-v] [-o outdir]
//
// Vendor resets the main module's vendor directory to include all packages
// needed to build and test all the main module's packages.
@ -1272,6 +1300,11 @@
// The -e flag causes vendor to attempt to proceed despite errors
// encountered while loading packages.
//
// The -o flag causes vendor to create the vendor directory at the given
// path instead of "vendor". The go command can only use a vendor directory
// named "vendor" within the module root directory, so this flag is
// primarily useful for other tools.
//
// See https://golang.org/ref/mod#go-mod-vendor for more about 'go mod vendor'.
//
//
@ -1329,6 +1362,202 @@
// See https://golang.org/ref/mod#go-mod-why for more about 'go mod why'.
//
//
// Workspace maintenance
//
// Go workspace provides access to operations on workspaces.
//
// Note that support for workspaces is built into many other commands, not
// just 'go work'.
//
// See 'go help modules' for information about Go's module system of which
// workspaces are a part.
//
// A workspace is specified by a go.work file that specifies a set of
// module directories with the "use" directive. These modules are used as
// root modules by the go command for builds and related operations. A
// workspace that does not specify modules to be used cannot be used to do
// builds from local modules.
//
// go.work files are line-oriented. Each line holds a single directive,
// made up of a keyword followed by aruments. For example:
//
// go 1.18
//
// use ../foo/bar
// use ./baz
//
// replace example.com/foo v1.2.3 => example.com/bar v1.4.5
//
// The leading keyword can be factored out of adjacent lines to create a block,
// like in Go imports.
//
// use (
// ../foo/bar
// ./baz
// )
//
// The use directive specifies a module to be included in the workspace's
// set of main modules. The argument to the use directive is the directory
// containing the module's go.mod file.
//
// The go directive specifies the version of Go the file was written at. It
// is possible there may be future changes in the semantics of workspaces
// that could be controlled by this version, but for now the version
// specified has no effect.
//
// The replace directive has the same syntax as the replace directive in a
// go.mod file and takes precedence over replaces in go.mod files. It is
// primarily intended to override conflicting replaces in different workspace
// modules.
//
// To determine whether the go command is operating in workspace mode, use
// the "go env GOWORK" command. This will specify the workspace file being
// used.
//
// Usage:
//
// go work <command> [arguments]
//
// The commands are:
//
// edit edit go.work from tools or scripts
// init initialize workspace file
// sync sync workspace build list to modules
// use add modules to workspace file
//
// Use "go help work <command>" for more information about a command.
//
// Edit go.work from tools or scripts
//
// Usage:
//
// go work edit [editing flags] [go.work]
//
// Edit provides a command-line interface for editing go.work,
// for use primarily by tools or scripts. It only reads go.work;
// it does not look up information about the modules involved.
// If no file is specified, Edit looks for a go.work file in the current
// directory and its parent directories
//
// The editing flags specify a sequence of editing operations.
//
// The -fmt flag reformats the go.work file without making other changes.
// This reformatting is also implied by any other modifications that use or
// rewrite the go.mod file. The only time this flag is needed is if no other
// flags are specified, as in 'go work edit -fmt'.
//
// The -use=path and -dropuse=path flags
// add and drop a use directive from the go.work file's set of module directories.
//
// The -replace=old[@v]=new[@v] flag adds a replacement of the given
// module path and version pair. If the @v in old@v is omitted, a
// replacement without a version on the left side is added, which applies
// to all versions of the old module path. If the @v in new@v is omitted,
// the new path should be a local module root directory, not a module
// path. Note that -replace overrides any redundant replacements for old[@v],
// so omitting @v will drop existing replacements for specific versions.
//
// The -dropreplace=old[@v] flag drops a replacement of the given
// module path and version pair. If the @v is omitted, a replacement without
// a version on the left side is dropped.
//
// The -use, -dropuse, -replace, and -dropreplace,
// editing flags may be repeated, and the changes are applied in the order given.
//
// The -go=version flag sets the expected Go language version.
//
// The -print flag prints the final go.work in its text format instead of
// writing it back to go.mod.
//
// The -json flag prints the final go.work file in JSON format instead of
// writing it back to go.mod. The JSON output corresponds to these Go types:
//
// type Module struct {
// Path string
// Version string
// }
//
// type GoWork struct {
// Go string
// Directory []Directory
// Replace []Replace
// }
//
// type Use struct {
// Path string
// ModulePath string
// }
//
// type Replace struct {
// Old Module
// New Module
// }
//
// See the workspaces design proposal at
// https://go.googlesource.com/proposal/+/master/design/45713-workspace.md for
// more information.
//
//
// Initialize workspace file
//
// Usage:
//
// go work init [moddirs]
//
// Init initializes and writes a new go.work file in the
// current directory, in effect creating a new workspace at the current
// directory.
//
// go work init optionally accepts paths to the workspace modules as
// arguments. If the argument is omitted, an empty workspace with no
// modules will be created.
//
// Each argument path is added to a use directive in the go.work file. The
// current go version will also be listed in the go.work file.
//
//
// Sync workspace build list to modules
//
// Usage:
//
// go work sync
//
// Sync syncs the workspace's build list back to the
// workspace's modules
//
// The workspace's build list is the set of versions of all the
// (transitive) dependency modules used to do builds in the workspace. go
// work sync generates that build list using the Minimal Version Selection
// algorithm, and then syncs those versions back to each of modules
// specified in the workspace (with use directives).
//
// The syncing is done by sequentially upgrading each of the dependency
// modules specified in a workspace module to the version in the build list
// if the dependency module's version is not already the same as the build
// list's version. Note that Minimal Version Selection guarantees that the
// build list's version of each module is always the same or higher than
// that in each workspace module.
//
//
// Add modules to workspace file
//
// Usage:
//
// go work use [-r] [moddirs]
//
// Use provides a command-line interface for adding
// directories, optionally recursively, to a go.work file.
//
// A use directive will be added to the go.work file for each argument
// directory listed on the command line go.work file, if it exists on disk,
// or removed from the go.work file if it does not exist on disk.
//
// The -r flag searches recursively for modules in the argument
// directories, and the use command operates as if each of the directories
// were specified as arguments: namely, use directives will be added for
// directories that exist, and removed for directories that do not exist.
//
//
// Compile and run Go program
//
// Usage:
@ -1387,8 +1616,8 @@
//
// 'Go test' recompiles each package along with any files with names matching
// the file pattern "*_test.go".
// These additional files can contain test functions, benchmark functions, and
// example functions. See 'go help testfunc' for more.
// These additional files can contain test functions, benchmark functions, fuzz
// tests and example functions. See 'go help testfunc' for more.
// Each listed package causes the execution of a separate test binary.
// Files whose names begin with "_" (including "_test.go") or "." are ignored.
//
@ -1405,7 +1634,8 @@
// used. That subset is: 'atomic', 'bool', 'buildtags', 'errorsas',
// 'ifaceassert', 'nilfunc', 'printf', and 'stringintconv'. You can see
// the documentation for these and other vet tests via "go doc cmd/vet".
// To disable the running of go vet, use the -vet=off flag.
// To disable the running of go vet, use the -vet=off flag. To run all
// checks, use the -vet=all flag.
//
// All test output and summary lines are printed to the go command's
// standard output, even if the test printed them to its own standard
@ -1446,16 +1676,16 @@
// The rule for a match in the cache is that the run involves the same
// test binary and the flags on the command line come entirely from a
// restricted set of 'cacheable' test flags, defined as -benchtime, -cpu,
// -list, -parallel, -run, -short, and -v. If a run of go test has any test
// or non-test flags outside this set, the result is not cached. To
// disable test caching, use any test flag or argument other than the
// cacheable flags. The idiomatic way to disable test caching explicitly
// is to use -count=1. Tests that open files within the package's source
// root (usually $GOPATH) or that consult environment variables only
// match future runs in which the files and environment variables are unchanged.
// A cached test result is treated as executing in no time at all,
// so a successful package test result will be cached and reused
// regardless of -timeout setting.
// -list, -parallel, -run, -short, -timeout, -failfast, and -v.
// If a run of go test has any test or non-test flags outside this set,
// the result is not cached. To disable test caching, use any test flag
// or argument other than the cacheable flags. The idiomatic way to disable
// test caching explicitly is to use -count=1. Tests that open files within
// the package's source root (usually $GOPATH) or that consult environment
// variables only match future runs in which the files and environment
// variables are unchanged. A cached test result is treated as executing
// in no time at all,so a successful package test result will be cached and
// reused regardless of -timeout setting.
//
// In addition to the build flags, the flags handled by 'go test' itself are:
//
@ -1746,6 +1976,13 @@
// See 'go help test' for details. Running 'go clean -testcache' removes
// all cached test results (but not cached build results).
//
// The go command also caches values used in fuzzing with 'go test -fuzz',
// specifically, values that expanded code coverage when passed to a
// fuzz function. These values are not used for regular building and
// testing, but they're stored in a subdirectory of the build cache.
// Running 'go clean -fuzzcache' removes all cached fuzzing values.
// This may make fuzzing less effective, temporarily.
//
// The GODEBUG environment variable can enable printing of debugging
// information about the state of the cache:
//
@ -1885,6 +2122,10 @@
// GO386
// For GOARCH=386, how to implement floating point instructions.
// Valid values are sse2 (default), softfloat.
// GOAMD64
// For GOARCH=amd64, the microarchitecture level for which to compile.
// Valid values are v1 (default), v2, v3, v4.
// See https://golang.org/wiki/MinimumRequirements#amd64
// GOMIPS
// For GOARCH=mips{,le}, whether to use floating point instructions.
// Valid values are hardfloat (default), softfloat.
@ -2622,9 +2863,10 @@
// (for example, -benchtime 100x).
//
// -count n
// Run each test and benchmark n times (default 1).
// Run each test, benchmark, and fuzz seed n times (default 1).
// If -cpu is set, run n times for each GOMAXPROCS value.
// Examples are always run once.
// Examples are always run once. -count does not apply to
// fuzz tests matched by -fuzz.
//
// -cover
// Enable coverage analysis.
@ -2651,32 +2893,67 @@
// Sets -cover.
//
// -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
// of GOMAXPROCS.
// Specify a list of GOMAXPROCS values for which the tests, benchmarks or
// fuzz tests should be executed. The default is the current value
// of GOMAXPROCS. -cpu does not apply to fuzz tests matched by -fuzz.
//
// -failfast
// Do not start new tests after the first test failure.
//
// -fuzz regexp
// Run the fuzz test matching the regular expression. When specified,
// the command line argument must match exactly one package within the
// main module, and regexp must match exactly one fuzz test within
// that package. Fuzzing will occur after tests, benchmarks, seed corpora
// of other fuzz tests, and examples have completed. See the Fuzzing
// section of the testing package documentation for details.
//
// -fuzztime t
// Run enough iterations of the fuzz target during fuzzing to take t,
// specified as a time.Duration (for example, -fuzztime 1h30s).
// The default is to run forever.
// The special syntax Nx means to run the fuzz target N times
// (for example, -fuzztime 1000x).
//
// -fuzzminimizetime t
// Run enough iterations of the fuzz target during each minimization
// attempt to take t, as specified as a time.Duration (for example,
// -fuzzminimizetime 30s).
// The default is 60s.
// The special syntax Nx means to run the fuzz target N times
// (for example, -fuzzminimizetime 100x).
//
// -json
// Log verbose output and test results in JSON. This presents the
// same information as the -v flag in a machine-readable format.
//
// -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.
// List tests, benchmarks, fuzz tests, or examples matching the regular
// expression. No tests, benchmarks, fuzz tests, 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.
// Allow parallel execution of test functions that call t.Parallel, and
// fuzz targets that call t.Parallel when running the seed corpus.
// The value of this flag is the maximum number of tests to run
// simultaneously; by default, it is set to the value of GOMAXPROCS.
// simultaneously.
// While fuzzing, the value of this flag is the maximum number of
// subprocesses that may call the fuzz function simultaneously, regardless of
// whether T.Parallel is called.
// By default, -parallel is set to the value of GOMAXPROCS.
// Setting -parallel to values higher than GOMAXPROCS may cause degraded
// performance due to CPU contention, especially when fuzzing.
// Note that -parallel only applies within a single test binary.
// The 'go test' command may run tests for different packages
// in parallel as well, according to the setting of the -p flag
// (see 'go help build').
//
// -run regexp
// Run only those tests and examples matching the regular expression.
// 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
// Run only those tests, examples, and fuzz tests matching the regular
// expression. 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,
@ -2689,11 +2966,11 @@
// exhaustive tests.
//
// -shuffle off,on,N
// Randomize the execution order of tests and benchmarks.
// It is off by default. If -shuffle is set to on, then it will seed
// the randomizer using the system clock. If -shuffle is set to an
// integer N, then N will be used as the seed value. In both cases,
// the seed will be reported for reproducibility.
// Randomize the execution order of tests and benchmarks.
// It is off by default. If -shuffle is set to on, then it will seed
// the randomizer using the system clock. If -shuffle is set to an
// integer N, then N will be used as the seed value. In both cases,
// the seed will be reported for reproducibility.
//
// -timeout d
// If a test binary runs longer than duration d, panic.
@ -2789,7 +3066,11 @@
// When 'go test' runs a test binary, it does so from within the
// corresponding package's source code directory. Depending on the test,
// it may be necessary to do the same when invoking a generated test
// binary directly.
// binary directly. Because that directory may be located within the
// module cache, which may be read-only and is verified by checksums, the
// test must not write to it or any other directory within the module
// unless explicitly requested by the user (such as with the -fuzz flag,
// which writes failures to testdata/fuzz).
//
// The command-line package list, if present, must appear before any
// flag not known to the go test command. Continuing the example above,
@ -2843,6 +3124,10 @@
//
// func BenchmarkXxx(b *testing.B) { ... }
//
// A fuzz test is one named FuzzXxx and should have the signature,
//
// func FuzzXxx(f *testing.F) { ... }
//
// An example function is similar to a test function but, instead of using
// *testing.T to report success or failure, prints output to os.Stdout.
// If the last comment in the function starts with "Output:" then the output
@ -2882,7 +3167,7 @@
//
// The entire test file is presented as the example when it contains a single
// example function, at least one other function, type, variable, or constant
// declaration, and no test or benchmark functions.
// declaration, and no tests, benchmarks, or fuzz tests.
//
// See the documentation of the testing package for more information.
//

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build go1.1
// +build go1.1
package main

View File

@ -13,6 +13,7 @@ import (
"flag"
"fmt"
"go/format"
"internal/godebug"
"internal/race"
"internal/testenv"
"io"
@ -31,7 +32,6 @@ import (
"cmd/go/internal/cache"
"cmd/go/internal/cfg"
"cmd/go/internal/robustio"
"cmd/go/internal/work"
"cmd/internal/sys"
)
@ -44,9 +44,12 @@ func init() {
}
var (
canRace = false // whether we can run the race detector
canCgo = false // whether we can use cgo
canMSan = false // whether we can run the memory sanitizer
canRace = false // whether we can run the race detector
canCgo = false // whether we can use cgo
canMSan = false // whether we can run the memory sanitizer
canASan = false // whether we can run the address sanitizer
canFuzz = false // whether we can search for new fuzz failures
fuzzInstrumented = false // whether fuzzing uses instrumentation
)
var exeSuffix string = func() string {
@ -198,6 +201,7 @@ func TestMain(m *testing.M) {
testGOCACHE = strings.TrimSpace(string(out))
canMSan = canCgo && sys.MSanSupported(runtime.GOOS, runtime.GOARCH)
canASan = canCgo && sys.ASanSupported(runtime.GOOS, runtime.GOARCH)
canRace = canCgo && sys.RaceDetectorSupported(runtime.GOOS, runtime.GOARCH)
// The race detector doesn't work on Alpine Linux:
// golang.org/issue/14481
@ -205,6 +209,8 @@ func TestMain(m *testing.M) {
if isAlpineLinux() || runtime.Compiler == "gccgo" {
canRace = false
}
canFuzz = sys.FuzzSupported(runtime.GOOS, runtime.GOARCH)
fuzzInstrumented = sys.FuzzInstrumented(runtime.GOOS, runtime.GOARCH)
}
// Don't let these environment variables confuse the test.
os.Setenv("GOENV", "off")
@ -806,7 +812,9 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
"src/internal/abi",
"src/internal/bytealg",
"src/internal/cpu",
"src/internal/goarch",
"src/internal/goexperiment",
"src/internal/goos",
"src/math/bits",
"src/unsafe",
filepath.Join("pkg", runtime.GOOS+"_"+runtime.GOARCH),
@ -1120,11 +1128,11 @@ func TestGoListTest(t *testing.T) {
tg.grepStdoutNot(`^testing \[sort.test\]$`, "unexpected test copy of testing")
tg.grepStdoutNot(`^testing$`, "unexpected real copy of testing")
tg.run("list", "-test", "cmd/dist", "cmd/doc")
tg.grepStdout(`^cmd/dist$`, "missing cmd/dist")
tg.run("list", "-test", "cmd/buildid", "cmd/doc")
tg.grepStdout(`^cmd/buildid$`, "missing cmd/buildid")
tg.grepStdout(`^cmd/doc$`, "missing cmd/doc")
tg.grepStdout(`^cmd/doc\.test$`, "missing cmd/doc test")
tg.grepStdoutNot(`^cmd/dist\.test$`, "unexpected cmd/dist test")
tg.grepStdoutNot(`^cmd/buildid\.test$`, "unexpected cmd/buildid test")
tg.grepStdoutNot(`^testing`, "unexpected testing")
tg.run("list", "-test", "runtime/cgo")
@ -1376,7 +1384,7 @@ func TestLdFlagsLongArgumentsIssue42295(t *testing.T) {
}`)
testStr := "test test test test test \n\\ "
var buf bytes.Buffer
for buf.Len() < work.ArgLengthForResponseFile+1 {
for buf.Len() < sys.ExecArgLengthLimit+1 {
buf.WriteString(testStr)
}
tg.run("run", "-ldflags", fmt.Sprintf(`-X "main.extern=%s"`, buf.String()), tg.path("main.go"))
@ -2274,7 +2282,7 @@ func TestUpxCompression(t *testing.T) {
func TestCacheListStale(t *testing.T) {
tooSlow(t)
if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
if godebug.Get("gocacheverify") == "1" {
t.Skip("GODEBUG gocacheverify")
}
tg := testgo(t)
@ -2297,7 +2305,7 @@ func TestCacheListStale(t *testing.T) {
func TestCacheCoverage(t *testing.T) {
tooSlow(t)
if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
if godebug.Get("gocacheverify") == "1" {
t.Skip("GODEBUG gocacheverify")
}
@ -2329,7 +2337,7 @@ func TestIssue22588(t *testing.T) {
func TestIssue22531(t *testing.T) {
tooSlow(t)
if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
if godebug.Get("gocacheverify") == "1" {
t.Skip("GODEBUG gocacheverify")
}
tg := testgo(t)
@ -2358,7 +2366,7 @@ func TestIssue22531(t *testing.T) {
func TestIssue22596(t *testing.T) {
tooSlow(t)
if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
if godebug.Get("gocacheverify") == "1" {
t.Skip("GODEBUG gocacheverify")
}
tg := testgo(t)
@ -2388,7 +2396,7 @@ func TestIssue22596(t *testing.T) {
func TestTestCache(t *testing.T) {
tooSlow(t)
if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
if godebug.Get("gocacheverify") == "1" {
t.Skip("GODEBUG gocacheverify")
}
tg := testgo(t)

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris
// +build darwin dragonfly freebsd hurd linux netbsd openbsd solaris
package main_test

View File

@ -117,12 +117,12 @@ func Exit() {
os.Exit(exitStatus)
}
func Fatalf(format string, args ...interface{}) {
func Fatalf(format string, args ...any) {
Errorf(format, args...)
Exit()
}
func Errorf(format string, args ...interface{}) {
func Errorf(format string, args ...any) {
log.Printf(format, args...)
SetExitStatus(1)
}
@ -151,7 +151,7 @@ func GetExitStatus() int {
// 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{}) {
func Run(cmdargs ...any) {
cmdline := str.StringList(cmdargs...)
if cfg.BuildN || cfg.BuildX {
fmt.Printf("%s\n", strings.Join(cmdline, " "))

View File

@ -9,7 +9,7 @@ import (
"cmd/go/internal/cfg"
"cmd/go/internal/fsys"
"cmd/go/internal/str"
"cmd/internal/quoted"
)
// A StringsFlag is a command-line flag that interprets its argument
@ -18,7 +18,7 @@ type StringsFlag []string
func (v *StringsFlag) Set(s string) error {
var err error
*v, err = str.SplitQuotedFields(s)
*v, err = quoted.Split(s)
if *v == nil {
*v = []string{}
}
@ -62,6 +62,13 @@ func AddModFlag(flags *flag.FlagSet) {
flags.Var(explicitStringFlag{value: &cfg.BuildMod, explicit: &cfg.BuildModExplicit}, "mod", "")
}
// AddWorkfileFlag adds the workfile flag to the flag set. It enables workspace
// mode for commands that support it by resetting the cfg.WorkFile variable
// to "" (equivalent to auto) rather than off.
func AddWorkfileFlag(flags *flag.FlagSet) {
flags.Var(explicitStringFlag{value: &cfg.WorkFile, explicit: &cfg.WorkFileExplicit}, "workfile", "")
}
// AddModCommonFlags adds the module-related flags common to build commands
// and 'go mod' subcommands.
func AddModCommonFlags(flags *flag.FlagSet) {

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build plan9 || windows
// +build plan9 windows
package base

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build aix || darwin || dragonfly || freebsd || hurd || js || linux || netbsd || openbsd || solaris
// +build aix darwin dragonfly freebsd hurd js linux netbsd openbsd solaris
package base

View File

@ -36,7 +36,7 @@ func Tool(toolName string) string {
}
// Give a nice message if there is no tool with that name.
if _, err := os.Stat(toolPath); err != nil {
fmt.Fprintf(os.Stderr, "go tool: no such tool %q\n", toolName)
fmt.Fprintf(os.Stderr, "go: no such tool %q\n", toolName)
SetExitStatus(2)
Exit()
}

View File

@ -40,7 +40,7 @@ func init() {
func runBug(ctx context.Context, cmd *base.Command, args []string) {
if len(args) > 0 {
base.Fatalf("go bug: bug takes no arguments")
base.Fatalf("go: bug takes no arguments")
}
var buf bytes.Buffer
buf.WriteString(bugHeader)
@ -106,8 +106,9 @@ func printGoEnv(w io.Writer) {
}
func printGoDetails(w io.Writer) {
printCmdOut(w, "GOROOT/bin/go version: ", filepath.Join(runtime.GOROOT(), "bin/go"), "version")
printCmdOut(w, "GOROOT/bin/go tool compile -V: ", filepath.Join(runtime.GOROOT(), "bin/go"), "tool", "compile", "-V")
gocmd := filepath.Join(runtime.GOROOT(), "bin/go")
printCmdOut(w, "GOROOT/bin/go version: ", gocmd, "version")
printCmdOut(w, "GOROOT/bin/go tool compile -V: ", gocmd, "tool", "compile", "-V")
}
func printOSDetails(w io.Writer) {

View File

@ -533,3 +533,15 @@ func (c *Cache) copyFile(file io.ReadSeeker, out OutputID, size int64) error {
return nil
}
// FuzzDir returns a subdirectory within the cache for storing fuzzing data.
// The subdirectory may not exist.
//
// This directory is managed by the internal/fuzz package. Files in this
// directory aren't removed by the 'go clean -cache' command or by Trim.
// They may be removed with 'go clean -fuzzcache'.
//
// TODO(#48526): make Trim remove unused files from this directory.
func (c *Cache) FuzzDir() string {
return filepath.Join(c.dir, "fuzz")
}

View File

@ -30,6 +30,7 @@ var (
// README as a courtesy to explain where it came from.
const cacheREADME = `This directory holds cached build artifacts from the Go build system.
Run "go clean -cache" if the directory is getting too large.
Run "go clean -fuzzcache" to delete the fuzz cache.
See golang.org to learn more about Go.
`

View File

@ -26,6 +26,7 @@ import (
var (
BuildA bool // -a flag
BuildBuildmode string // -buildmode flag
BuildBuildvcs bool // -buildvcs flag
BuildContext = defaultContext()
BuildMod string // -mod flag
BuildModExplicit bool // whether -mod was set explicitly
@ -33,6 +34,7 @@ var (
BuildI bool // -i flag
BuildLinkshared bool // -linkshared flag
BuildMSan bool // -msan flag
BuildASan bool // -asan flag
BuildN bool // -n flag
BuildO string // -o flag
BuildP = runtime.GOMAXPROCS(0) // -p flag
@ -47,17 +49,26 @@ var (
BuildWork bool // -work flag
BuildX bool // -x flag
ModCacheRW bool // -modcacherw flag
ModFile string // -modfile flag
ModCacheRW bool // -modcacherw flag
ModFile string // -modfile flag
WorkFile string // -workfile flag
WorkFileExplicit bool // whether -workfile was set explicitly
CmdName string // "build", "install", "list", "mod tidy", etc.
DebugActiongraph string // -debug-actiongraph flag (undocumented, unstable)
DebugTrace string // -debug-trace flag
// GoPathError is set when GOPATH is not set. it contains an
// explanation why GOPATH is unset.
GoPathError string
GOEXPERIMENT = envOr("GOEXPERIMENT", buildcfg.DefaultGOEXPERIMENT)
)
func defaultContext() build.Context {
ctxt := build.Default
ctxt.JoinPath = filepath.Join // back door to say "do not use go command"
ctxt.GOROOT = findGOROOT()
@ -70,7 +81,7 @@ func defaultContext() build.Context {
build.ToolDir = filepath.Join(ctxt.GOROOT, "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH)
}
ctxt.GOPATH = envOr("GOPATH", ctxt.GOPATH)
ctxt.GOPATH = envOr("GOPATH", gopath(ctxt))
// Override defaults computed in go/build with defaults
// from go environment configuration file, if known.
@ -79,7 +90,7 @@ func defaultContext() build.Context {
// The experiments flags are based on GOARCH, so they may
// need to change. TODO: This should be cleaned up.
buildcfg.UpdateExperiments(ctxt.GOOS, ctxt.GOARCH, envOr("GOEXPERIMENT", buildcfg.DefaultGOEXPERIMENT))
buildcfg.UpdateExperiments(ctxt.GOOS, ctxt.GOARCH, GOEXPERIMENT)
ctxt.ToolTags = nil
for _, exp := range buildcfg.EnabledExperiments() {
ctxt.ToolTags = append(ctxt.ToolTags, "goexperiment."+exp)
@ -261,6 +272,7 @@ var (
// Used in envcmd.MkEnv and build ID computations.
GOARM = envOr("GOARM", fmt.Sprint(buildcfg.GOARM))
GO386 = envOr("GO386", buildcfg.GO386)
GOAMD64 = envOr("GOAMD64", fmt.Sprintf("%s%d", "v", buildcfg.GOAMD64))
GOMIPS = envOr("GOMIPS", buildcfg.GOMIPS)
GOMIPS64 = envOr("GOMIPS64", buildcfg.GOMIPS64)
GOPPC64 = envOr("GOPPC64", fmt.Sprintf("%s%d", "power", buildcfg.GOPPC64))
@ -287,6 +299,8 @@ func GetArchEnv() (key, val string) {
return "GOARM", GOARM
case "386":
return "GO386", GO386
case "amd64":
return "GOAMD64", GOAMD64
case "mips", "mipsle":
return "GOMIPS", GOMIPS
case "mips64", "mips64le":
@ -396,3 +410,24 @@ func gopathDir(rel string) string {
}
return filepath.Join(list[0], rel)
}
func gopath(ctxt build.Context) string {
if len(ctxt.GOPATH) > 0 {
return ctxt.GOPATH
}
env := "HOME"
if runtime.GOOS == "windows" {
env = "USERPROFILE"
} else if runtime.GOOS == "plan9" {
env = "home"
}
if home := os.Getenv(env); home != "" {
def := filepath.Join(home, "go")
if filepath.Clean(def) == filepath.Clean(runtime.GOROOT()) {
GoPathError = "cannot set GOROOT as GOPATH"
}
return ""
}
GoPathError = fmt.Sprintf("%s is not set", env)
return ""
}

View File

@ -75,6 +75,13 @@ The -modcache flag causes clean to remove the entire module
download cache, including unpacked source code of versioned
dependencies.
The -fuzzcache flag causes clean to remove files stored in the Go build
cache for fuzz testing. The fuzzing engine caches files that expand
code coverage, so removing them may make fuzzing less effective until
new inputs are found that provide the same coverage. These files are
distinct from those stored in testdata directory; clean does not remove
those files.
For more about build flags, see 'go help build'.
For more about specifying packages, see 'go help packages'.
@ -85,6 +92,7 @@ var (
cleanI bool // clean -i flag
cleanR bool // clean -r flag
cleanCache bool // clean -cache flag
cleanFuzzcache bool // clean -fuzzcache flag
cleanModcache bool // clean -modcache flag
cleanTestcache bool // clean -testcache flag
)
@ -96,6 +104,7 @@ func init() {
CmdClean.Flag.BoolVar(&cleanI, "i", false, "")
CmdClean.Flag.BoolVar(&cleanR, "r", false, "")
CmdClean.Flag.BoolVar(&cleanCache, "cache", false, "")
CmdClean.Flag.BoolVar(&cleanFuzzcache, "fuzzcache", false, "")
CmdClean.Flag.BoolVar(&cleanModcache, "modcache", false, "")
CmdClean.Flag.BoolVar(&cleanTestcache, "testcache", false, "")
@ -112,7 +121,7 @@ func runClean(ctx context.Context, cmd *base.Command, args []string) {
// or no other target (such as a cache) was requested to be cleaned.
cleanPkg := len(args) > 0 || cleanI || cleanR
if (!modload.Enabled() || modload.HasModRoot()) &&
!cleanCache && !cleanModcache && !cleanTestcache {
!cleanCache && !cleanModcache && !cleanTestcache && !cleanFuzzcache {
cleanPkg = true
}
@ -144,7 +153,7 @@ func runClean(ctx context.Context, cmd *base.Command, args []string) {
// This also mimics what os.RemoveAll(dir) would do.
if err := os.RemoveAll(d); err != nil && !printedErrors {
printedErrors = true
base.Errorf("go clean -cache: %v", err)
base.Errorf("go: %v", err)
}
}
}
@ -157,7 +166,7 @@ func runClean(ctx context.Context, cmd *base.Command, args []string) {
if !cfg.BuildN {
if err := os.RemoveAll(logFile); err != nil && !printedErrors {
printedErrors = true
base.Errorf("go clean -cache: %v", err)
base.Errorf("go: %v", err)
}
}
}
@ -187,7 +196,7 @@ func runClean(ctx context.Context, cmd *base.Command, args []string) {
}
if err != nil {
if _, statErr := os.Stat(dir); !os.IsNotExist(statErr) {
base.Errorf("go clean -testcache: %v", err)
base.Errorf("go: %v", err)
}
}
}
@ -195,14 +204,26 @@ func runClean(ctx context.Context, cmd *base.Command, args []string) {
if cleanModcache {
if cfg.GOMODCACHE == "" {
base.Fatalf("go clean -modcache: no module cache")
base.Fatalf("go: cannot clean -modcache without a module cache")
}
if cfg.BuildN || cfg.BuildX {
b.Showcmd("", "rm -rf %s", cfg.GOMODCACHE)
}
if !cfg.BuildN {
if err := modfetch.RemoveAll(cfg.GOMODCACHE); err != nil {
base.Errorf("go clean -modcache: %v", err)
base.Errorf("go: %v", err)
}
}
}
if cleanFuzzcache {
fuzzDir := cache.Default().FuzzDir()
if cfg.BuildN || cfg.BuildX {
b.Showcmd("", "rm -rf %s", fuzzDir)
}
if !cfg.BuildN {
if err := os.RemoveAll(fuzzDir); err != nil {
base.Errorf("go: %v", err)
}
}
}
@ -245,7 +266,7 @@ func clean(p *load.Package) {
}
dirs, err := os.ReadDir(p.Dir)
if err != nil {
base.Errorf("go clean %s: %v", p.Dir, err)
base.Errorf("go: %s: %v", p.Dir, err)
return
}
@ -334,7 +355,7 @@ func clean(p *load.Package) {
}
}
if err := os.RemoveAll(filepath.Join(p.Dir, name)); err != nil {
base.Errorf("go clean: %v", err)
base.Errorf("go: %v", err)
}
}
continue
@ -386,5 +407,5 @@ func removeFile(f string) {
return
}
}
base.Errorf("go clean: %v", err)
base.Errorf("go: %v", err)
}

View File

@ -92,7 +92,7 @@ func ParseOne(fs *flag.FlagSet, args []string) (f *flag.Flag, remainingArgs []st
// Use fs.Set instead of f.Value.Set below so that any subsequent call to
// fs.Visit will correctly visit the flags that have been set.
failf := func(format string, a ...interface{}) (*flag.Flag, []string, error) {
failf := func(format string, a ...any) (*flag.Flag, []string, error) {
return f, args, fmt.Errorf(format, a...)
}

View File

@ -60,9 +60,8 @@ The package path must be either a qualified path or a proper suffix of a
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 with method or struct field.
This is similar to the syntax accepted by godoc:
When run with two arguments, the first is a package path (full path or suffix),
and the second is a symbol, or symbol with method or struct field:
go doc <pkg> <sym>[.<methodOrField>]

View File

@ -26,6 +26,7 @@ import (
"cmd/go/internal/load"
"cmd/go/internal/modload"
"cmd/go/internal/work"
"cmd/internal/quoted"
)
var CmdEnv = &base.Command{
@ -104,13 +105,13 @@ func MkEnv() []cfg.EnvVar {
env = append(env, cfg.EnvVar{Name: key, Value: val})
}
cc := cfg.DefaultCC(cfg.Goos, cfg.Goarch)
if env := strings.Fields(cfg.Getenv("CC")); len(env) > 0 {
cc = env[0]
cc := cfg.Getenv("CC")
if cc == "" {
cc = cfg.DefaultCC(cfg.Goos, cfg.Goarch)
}
cxx := cfg.DefaultCXX(cfg.Goos, cfg.Goarch)
if env := strings.Fields(cfg.Getenv("CXX")); len(env) > 0 {
cxx = env[0]
cxx := cfg.Getenv("CXX")
if cxx == "" {
cxx = cfg.DefaultCXX(cfg.Goos, cfg.Goarch)
}
env = append(env, cfg.EnvVar{Name: "AR", Value: envOr("AR", "ar")})
env = append(env, cfg.EnvVar{Name: "CC", Value: cc})
@ -145,13 +146,17 @@ func findEnv(env []cfg.EnvVar, name string) string {
// ExtraEnvVars returns environment variables that should not leak into child processes.
func ExtraEnvVars() []cfg.EnvVar {
gomod := ""
modload.Init()
if modload.HasModRoot() {
gomod = filepath.Join(modload.ModRoot(), "go.mod")
gomod = modload.ModFilePath()
} else if modload.Enabled() {
gomod = os.DevNull
}
modload.InitWorkfile()
gowork := modload.WorkFilePath()
return []cfg.EnvVar{
{Name: "GOMOD", Value: gomod},
{Name: "GOWORK", Value: gowork},
}
}
@ -191,13 +196,13 @@ func argKey(arg string) string {
func runEnv(ctx context.Context, cmd *base.Command, args []string) {
if *envJson && *envU {
base.Fatalf("go env: cannot use -json with -u")
base.Fatalf("go: cannot use -json with -u")
}
if *envJson && *envW {
base.Fatalf("go env: cannot use -json with -w")
base.Fatalf("go: cannot use -json with -w")
}
if *envU && *envW {
base.Fatalf("go env: cannot use -u with -w")
base.Fatalf("go: cannot use -u with -w")
}
// Handle 'go env -w' and 'go env -u' before calling buildcfg.Check,
@ -275,7 +280,7 @@ func runEnv(ctx context.Context, cmd *base.Command, args []string) {
func runEnvW(args []string) {
// Process and sanity-check command line.
if len(args) == 0 {
base.Fatalf("go env -w: no KEY=VALUE arguments given")
base.Fatalf("go: no KEY=VALUE arguments given")
}
osEnv := make(map[string]string)
for _, e := range cfg.OrigEnv {
@ -287,14 +292,14 @@ func runEnvW(args []string) {
for _, arg := range args {
i := strings.Index(arg, "=")
if i < 0 {
base.Fatalf("go env -w: arguments must be KEY=VALUE: invalid argument: %s", arg)
base.Fatalf("go: arguments must be KEY=VALUE: invalid argument: %s", arg)
}
key, val := arg[:i], arg[i+1:]
if err := checkEnvWrite(key, val); err != nil {
base.Fatalf("go env -w: %v", err)
base.Fatalf("go: %v", err)
}
if _, ok := add[key]; ok {
base.Fatalf("go env -w: multiple values for key: %s", key)
base.Fatalf("go: multiple values for key: %s", key)
}
add[key] = val
if osVal := osEnv[key]; osVal != "" && osVal != val {
@ -303,13 +308,13 @@ func runEnvW(args []string) {
}
if err := checkBuildConfig(add, nil); err != nil {
base.Fatalf("go env -w: %v", err)
base.Fatalf("go: %v", err)
}
gotmp, okGOTMP := add["GOTMPDIR"]
if okGOTMP {
if !filepath.IsAbs(gotmp) && gotmp != "" {
base.Fatalf("go env -w: GOTMPDIR must be an absolute path")
base.Fatalf("go: GOTMPDIR must be an absolute path")
}
}
@ -319,18 +324,18 @@ func runEnvW(args []string) {
func runEnvU(args []string) {
// Process and sanity-check command line.
if len(args) == 0 {
base.Fatalf("go env -u: no arguments given")
base.Fatalf("go: 'go env -u' requires an argument")
}
del := make(map[string]bool)
for _, arg := range args {
if err := checkEnvWrite(arg, ""); err != nil {
base.Fatalf("go env -u: %v", err)
base.Fatalf("go: %v", err)
}
del[arg] = true
}
if err := checkBuildConfig(nil, del); err != nil {
base.Fatalf("go env -u: %v", err)
base.Fatalf("go: %v", err)
}
updateEnvFile(nil, del)
@ -414,7 +419,7 @@ func printEnvAsJSON(env []cfg.EnvVar) {
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", "\t")
if err := enc.Encode(m); err != nil {
base.Fatalf("go env -json: %s", err)
base.Fatalf("go: %s", err)
}
}
@ -429,7 +434,7 @@ func getOrigEnv(key string) string {
func checkEnvWrite(key, val string) error {
switch key {
case "GOEXE", "GOGCCFLAGS", "GOHOSTARCH", "GOHOSTOS", "GOMOD", "GOTOOLDIR", "GOVERSION":
case "GOEXE", "GOGCCFLAGS", "GOHOSTARCH", "GOHOSTOS", "GOMOD", "GOWORK", "GOTOOLDIR", "GOVERSION":
return fmt.Errorf("%s cannot be modified", key)
case "GOENV":
return fmt.Errorf("%s can only be set using the OS environment", key)
@ -457,10 +462,23 @@ func checkEnvWrite(key, val string) error {
if !filepath.IsAbs(val) && val != "" {
return fmt.Errorf("GOPATH entry is relative; must be absolute path: %q", val)
}
// Make sure CC and CXX are absolute paths
case "CC", "CXX", "GOMODCACHE":
if !filepath.IsAbs(val) && val != "" && val != filepath.Base(val) {
return fmt.Errorf("%s entry is relative; must be absolute path: %q", key, val)
case "GOMODCACHE":
if !filepath.IsAbs(val) && val != "" {
return fmt.Errorf("GOMODCACHE entry is relative; must be absolute path: %q", val)
}
case "CC", "CXX":
if val == "" {
break
}
args, err := quoted.Split(val)
if err != nil {
return fmt.Errorf("invalid %s: %v", key, err)
}
if len(args) == 0 {
return fmt.Errorf("%s entry cannot contain only space", key)
}
if !filepath.IsAbs(args[0]) && args[0] != filepath.Base(args[0]) {
return fmt.Errorf("%s entry is relative; must be absolute path: %q", key, args[0])
}
}
@ -479,11 +497,11 @@ func checkEnvWrite(key, val string) error {
func updateEnvFile(add map[string]string, del map[string]bool) {
file, err := cfg.EnvFile()
if file == "" {
base.Fatalf("go env: cannot find go env config: %v", err)
base.Fatalf("go: cannot find go env config: %v", err)
}
data, err := os.ReadFile(file)
if err != nil && (!os.IsNotExist(err) || len(add) == 0) {
base.Fatalf("go env: reading go env config: %v", err)
base.Fatalf("go: reading go env config: %v", err)
}
lines := strings.SplitAfter(string(data), "\n")
@ -541,7 +559,7 @@ func updateEnvFile(add map[string]string, del map[string]bool) {
os.MkdirAll(filepath.Dir(file), 0777)
err = os.WriteFile(file, data, 0666)
if err != nil {
base.Fatalf("go env: writing go env config: %v", err)
base.Fatalf("go: writing go env config: %v", err)
}
}
}

View File

@ -11,27 +11,39 @@ import (
"cmd/go/internal/load"
"cmd/go/internal/modload"
"cmd/go/internal/str"
"cmd/go/internal/work"
"context"
"fmt"
"go/build"
"os"
)
var CmdFix = &base.Command{
Run: runFix,
UsageLine: "go fix [packages]",
UsageLine: "go fix [-fix list] [packages]",
Short: "update packages to use new APIs",
Long: `
Fix runs the Go fix command on the packages named by the import paths.
The -fix flag sets a comma-separated list of fixes to run.
The default is all known fixes.
(Its value is passed to 'go tool fix -r'.)
For more about fix, see 'go doc cmd/fix'.
For more about specifying packages, see 'go help packages'.
To run fix with specific options, run 'go tool fix'.
To run fix with other options, run 'go tool fix'.
See also: go fmt, go vet.
`,
}
var fixes = CmdFix.Flag.String("fix", "", "comma-separated list of fixes to apply")
func init() {
work.AddBuildFlags(CmdFix, work.DefaultBuildFlags)
CmdFix.Run = runFix // fix cycle
}
func runFix(ctx context.Context, cmd *base.Command, args []string) {
pkgs := load.PackagesAndErrors(ctx, load.PackageOpts{}, args)
w := 0
@ -58,6 +70,16 @@ func runFix(ctx context.Context, cmd *base.Command, args []string) {
// the command only applies to this package,
// not to packages in subdirectories.
files := base.RelPaths(pkg.InternalAllGoFiles())
base.Run(str.StringList(cfg.BuildToolexec, base.Tool("fix"), files))
goVersion := ""
if pkg.Module != nil {
goVersion = "go" + pkg.Module.GoVersion
} else if pkg.Standard {
goVersion = build.Default.ReleaseTags[len(build.Default.ReleaseTags)-1]
}
var fixArg []string
if *fixes != "" {
fixArg = []string{"-r=" + *fixes}
}
base.Run(str.StringList(cfg.BuildToolexec, base.Tool("fix"), "-go="+goVersion, fixArg, files))
}
}

View File

@ -11,14 +11,12 @@ import (
"fmt"
"os"
"path/filepath"
"runtime"
"sync"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/modload"
"cmd/go/internal/str"
"cmd/internal/sys"
)
func init() {
@ -53,18 +51,13 @@ See also: go fix, go vet.
func runFmt(ctx context.Context, cmd *base.Command, args []string) {
printed := false
gofmt := gofmtPath()
procs := runtime.GOMAXPROCS(0)
var wg sync.WaitGroup
wg.Add(procs)
fileC := make(chan string, 2*procs)
for i := 0; i < procs; i++ {
go func() {
defer wg.Done()
for file := range fileC {
base.Run(str.StringList(gofmt, "-l", "-w", file))
}
}()
}
gofmtArgs := []string{gofmt, "-l", "-w"}
gofmtArgLen := len(gofmt) + len(" -l -w")
baseGofmtArgs := len(gofmtArgs)
baseGofmtArgLen := gofmtArgLen
for _, pkg := range load.PackagesAndErrors(ctx, load.PackageOpts{}, args) {
if modload.Enabled() && pkg.Module != nil && !pkg.Module.Main {
if !printed {
@ -89,11 +82,18 @@ func runFmt(ctx context.Context, cmd *base.Command, args []string) {
// not to packages in subdirectories.
files := base.RelPaths(pkg.InternalAllGoFiles())
for _, file := range files {
fileC <- file
gofmtArgs = append(gofmtArgs, file)
gofmtArgLen += 1 + len(file) // plus separator
if gofmtArgLen >= sys.ExecArgLengthLimit {
base.Run(gofmtArgs)
gofmtArgs = gofmtArgs[:baseGofmtArgs]
gofmtArgLen = baseGofmtArgLen
}
}
}
close(fileC)
wg.Wait()
if len(gofmtArgs) > baseGofmtArgs {
base.Run(gofmtArgs)
}
}
func gofmtPath() string {

View File

@ -499,7 +499,7 @@ func (f fakeFile) Size() int64 { return f.real.Size() }
func (f fakeFile) Mode() fs.FileMode { return f.real.Mode() }
func (f fakeFile) ModTime() time.Time { return f.real.ModTime() }
func (f fakeFile) IsDir() bool { return f.real.IsDir() }
func (f fakeFile) Sys() interface{} { return f.real.Sys() }
func (f fakeFile) Sys() any { return f.real.Sys() }
// missingFile provides an fs.FileInfo for an overlaid file where the
// destination file in the overlay doesn't exist. It returns zero values
@ -512,7 +512,7 @@ func (f missingFile) Size() int64 { return 0 }
func (f missingFile) Mode() fs.FileMode { return fs.ModeIrregular }
func (f missingFile) ModTime() time.Time { return time.Unix(0, 0) }
func (f missingFile) IsDir() bool { return false }
func (f missingFile) Sys() interface{} { return nil }
func (f missingFile) Sys() any { return nil }
// fakeDir provides an fs.FileInfo implementation for directories that are
// implicitly created by overlaid files. Each directory in the
@ -524,7 +524,7 @@ func (f fakeDir) Size() int64 { return 0 }
func (f fakeDir) Mode() fs.FileMode { return fs.ModeDir | 0500 }
func (f fakeDir) ModTime() time.Time { return time.Unix(0, 0) }
func (f fakeDir) IsDir() bool { return true }
func (f fakeDir) Sys() interface{} { return nil }
func (f fakeDir) Sys() any { return nil }
// Glob is like filepath.Glob but uses the overlay file system.
func Glob(pattern string) (matches []string, err error) {

View File

@ -1,7 +1,6 @@
package fsys
import (
"cmd/go/internal/txtar"
"encoding/json"
"errors"
"fmt"
@ -12,6 +11,8 @@ import (
"path/filepath"
"reflect"
"testing"
"golang.org/x/tools/txtar"
)
// initOverlay resets the overlay state to reflect the config.

View File

@ -38,7 +38,7 @@ Generate runs commands described by directives within existing
files. Those commands can run any process but the intent is to
create or update Go source files.
Go generate is never run automatically by go build, go get, go test,
Go generate is never run automatically by go build, go test,
and so on. It must be run explicitly.
Go generate scans the file for directives, which are lines of
@ -408,7 +408,7 @@ var stop = fmt.Errorf("error in generation")
// errorf logs an error message prefixed with the file and line number.
// It then exits the program (with exit status 1) because generation stops
// at the first error.
func (g *Generator) errorf(format string, args ...interface{}) {
func (g *Generator) errorf(format string, args ...any) {
fmt.Fprintf(os.Stderr, "%s:%d: %s\n", base.ShortPath(g.path), g.lineNum,
fmt.Sprintf(format, args...))
panic(stop)

View File

@ -114,16 +114,16 @@ func init() {
func runGet(ctx context.Context, cmd *base.Command, args []string) {
if cfg.ModulesEnabled {
// Should not happen: main.go should install the separate module-enabled get code.
base.Fatalf("go get: modules not implemented")
base.Fatalf("go: modules not implemented")
}
work.BuildInit()
if *getF && !*getU {
base.Fatalf("go get: cannot use -f flag without -u")
base.Fatalf("go: cannot use -f flag without -u")
}
if *getInsecure {
base.Fatalf("go get: -insecure flag is no longer supported; use GOINSECURE instead")
base.Fatalf("go: -insecure flag is no longer supported; use GOINSECURE instead")
}
// Disable any prompting for passwords by Git itself.
@ -214,18 +214,19 @@ func downloadPaths(patterns []string) []string {
// if the argument has no slash or refers to an existing file.
if strings.HasSuffix(arg, ".go") {
if !strings.Contains(arg, "/") {
base.Errorf("go get %s: arguments must be package or module paths", arg)
base.Errorf("go: %s: arguments must be package or module paths", arg)
continue
}
if fi, err := os.Stat(arg); err == nil && !fi.IsDir() {
base.Errorf("go get: %s exists as a file, but 'go get' requires package arguments", arg)
base.Errorf("go: %s exists as a file, but 'go get' requires package arguments", arg)
}
}
}
base.ExitIfErrors()
var pkgs []string
for _, m := range search.ImportPathsQuiet(patterns) {
noModRoots := []string{}
for _, m := range search.ImportPathsQuiet(patterns, noModRoots) {
if len(m.Pkgs) == 0 && strings.Contains(m.Pattern(), "...") {
pkgs = append(pkgs, m.Pattern())
} else {
@ -315,7 +316,8 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int)
if wildcardOkay && strings.Contains(arg, "...") {
match := search.NewMatch(arg)
if match.IsLocal() {
match.MatchDirs()
noModRoots := []string{} // We're in gopath mode, so there are no modroots.
match.MatchDirs(noModRoots)
args = match.Dirs
} else {
match.MatchPackages()
@ -415,10 +417,10 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int)
// to make the first copy of or update a copy of the given package.
func downloadPackage(p *load.Package) error {
var (
vcsCmd *vcs.Cmd
repo, rootPath string
err error
blindRepo bool // set if the repo has unusual configuration
vcsCmd *vcs.Cmd
repo, rootPath, repoDir string
err error
blindRepo bool // set if the repo has unusual configuration
)
// p can be either a real package, or a pseudo-package whose “import path” is
@ -444,10 +446,19 @@ func downloadPackage(p *load.Package) error {
if p.Internal.Build.SrcRoot != "" {
// Directory exists. Look for checkout along path to src.
vcsCmd, rootPath, err = vcs.FromDir(p.Dir, p.Internal.Build.SrcRoot)
const allowNesting = false
repoDir, vcsCmd, err = vcs.FromDir(p.Dir, p.Internal.Build.SrcRoot, allowNesting)
if err != nil {
return err
}
if !str.HasFilePathPrefix(repoDir, p.Internal.Build.SrcRoot) {
panic(fmt.Sprintf("repository %q not in source root %q", repo, p.Internal.Build.SrcRoot))
}
rootPath = str.TrimFilePathPrefix(repoDir, p.Internal.Build.SrcRoot)
if err := vcs.CheckGOVCS(vcsCmd, rootPath); err != nil {
return err
}
repo = "<local>" // should be unused; make distinctive
// Double-check where it came from.

View File

@ -162,7 +162,7 @@ func (w *errWriter) Write(b []byte) (int, error) {
}
// tmpl executes the given template text on data, writing the result to w.
func tmpl(w io.Writer, text string, data interface{}) {
func tmpl(w io.Writer, text string, data any) {
t := template.New("top")
t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize})
template.Must(t.Parse(text))

View File

@ -592,6 +592,10 @@ Architecture-specific environment variables:
GO386
For GOARCH=386, how to implement floating point instructions.
Valid values are sse2 (default), softfloat.
GOAMD64
For GOARCH=amd64, the microarchitecture level for which to compile.
Valid values are v1 (default), v2, v3, v4.
See https://golang.org/wiki/MinimumRequirements#amd64
GOMIPS
For GOARCH=mips{,le}, whether to use floating point instructions.
Valid values are hardfloat (default), softfloat.
@ -771,6 +775,13 @@ The go command also caches successful package test results.
See 'go help test' for details. Running 'go clean -testcache' removes
all cached test results (but not cached build results).
The go command also caches values used in fuzzing with 'go test -fuzz',
specifically, values that expanded code coverage when passed to a
fuzz function. These values are not used for regular building and
testing, but they're stored in a subdirectory of the build cache.
Running 'go clean -fuzzcache' removes all cached fuzzing values.
This may make fuzzing less effective, temporarily.
The GODEBUG environment variable can enable printing of debugging
information about the state of the cache:

View File

@ -2,17 +2,51 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Copied from Go distribution src/go/build/build.go, syslist.go
// Copied from Go distribution src/go/build/build.go, syslist.go.
// That package does not export the ability to process raw file data,
// although we could fake it with an appropriate build.Context
// and a lot of unwrapping.
// More importantly, that package does not implement the tags["*"]
// special case, in which both tag and !tag are considered to be true
// for essentially all tags (except "ignore").
//
// If we added this API to go/build directly, we wouldn't need this
// file anymore, but this API is not terribly general-purpose and we
// don't really want to commit to any public form of it, nor do we
// want to move the core parts of go/build into a top-level internal package.
// These details change very infrequently, so the copy is fine.
package imports
import (
"bytes"
"errors"
"fmt"
"go/build/constraint"
"strings"
"unicode"
)
var slashslash = []byte("//")
var (
bSlashSlash = []byte("//")
bStarSlash = []byte("*/")
bSlashStar = []byte("/*")
bPlusBuild = []byte("+build")
goBuildComment = []byte("//go:build")
errGoBuildWithoutBuild = errors.New("//go:build comment without // +build comment")
errMultipleGoBuild = errors.New("multiple //go:build comments")
)
func isGoBuildComment(line []byte) bool {
if !bytes.HasPrefix(line, goBuildComment) {
return false
}
line = bytes.TrimSpace(line)
rest := line[len(goBuildComment):]
return len(rest) == 0 || len(bytes.TrimSpace(rest)) < len(rest)
}
// ShouldBuild reports whether it is okay to use this file,
// The rule is that in the file's leading run of // comments
@ -34,90 +68,124 @@ var slashslash = []byte("//")
// in any build.
//
func ShouldBuild(content []byte, tags map[string]bool) bool {
// Pass 1. Identify leading run of // comments and blank lines,
// Identify leading run of // comments and blank lines,
// which must be followed by a blank line.
end := 0
p := content
for len(p) > 0 {
line := p
if i := bytes.IndexByte(line, '\n'); i >= 0 {
line, p = line[:i], p[i+1:]
} else {
p = p[len(p):]
}
line = bytes.TrimSpace(line)
if len(line) == 0 { // Blank line
end = len(content) - len(p)
continue
}
if !bytes.HasPrefix(line, slashslash) { // Not comment line
break
}
// Also identify any //go:build comments.
content, goBuild, _, err := parseFileHeader(content)
if err != nil {
return false
}
content = content[:end]
// Pass 2. Process each line in the run.
p = content
allok := true
for len(p) > 0 {
line := p
if i := bytes.IndexByte(line, '\n'); i >= 0 {
line, p = line[:i], p[i+1:]
} else {
p = p[len(p):]
// If //go:build line is present, it controls.
// Otherwise fall back to +build processing.
var shouldBuild bool
switch {
case goBuild != nil:
x, err := constraint.Parse(string(goBuild))
if err != nil {
return false
}
line = bytes.TrimSpace(line)
if !bytes.HasPrefix(line, slashslash) {
continue
}
line = bytes.TrimSpace(line[len(slashslash):])
if len(line) > 0 && line[0] == '+' {
// Looks like a comment +line.
f := strings.Fields(string(line))
if f[0] == "+build" {
ok := false
for _, tok := range f[1:] {
if matchTags(tok, tags) {
ok = true
}
}
if !ok {
allok = false
shouldBuild = eval(x, tags, true)
default:
shouldBuild = true
p := content
for len(p) > 0 {
line := p
if i := bytes.IndexByte(line, '\n'); i >= 0 {
line, p = line[:i], p[i+1:]
} else {
p = p[len(p):]
}
line = bytes.TrimSpace(line)
if !bytes.HasPrefix(line, bSlashSlash) || !bytes.Contains(line, bPlusBuild) {
continue
}
text := string(line)
if !constraint.IsPlusBuild(text) {
continue
}
if x, err := constraint.Parse(text); err == nil {
if !eval(x, tags, true) {
shouldBuild = false
}
}
}
}
return allok
return shouldBuild
}
// matchTags reports whether the name is one of:
//
// tag (if tags[tag] is true)
// !tag (if tags[tag] is false)
// a comma-separated list of any of these
//
func matchTags(name string, tags map[string]bool) bool {
if name == "" {
return false
func parseFileHeader(content []byte) (trimmed, goBuild []byte, sawBinaryOnly bool, err error) {
end := 0
p := content
ended := false // found non-blank, non-// line, so stopped accepting // +build lines
inSlashStar := false // in /* */ comment
Lines:
for len(p) > 0 {
line := p
if i := bytes.IndexByte(line, '\n'); i >= 0 {
line, p = line[:i], p[i+1:]
} else {
p = p[len(p):]
}
line = bytes.TrimSpace(line)
if len(line) == 0 && !ended { // Blank line
// Remember position of most recent blank line.
// When we find the first non-blank, non-// line,
// this "end" position marks the latest file position
// where a // +build line can appear.
// (It must appear _before_ a blank line before the non-blank, non-// line.
// Yes, that's confusing, which is part of why we moved to //go:build lines.)
// Note that ended==false here means that inSlashStar==false,
// since seeing a /* would have set ended==true.
end = len(content) - len(p)
continue Lines
}
if !bytes.HasPrefix(line, bSlashSlash) { // Not comment line
ended = true
}
if !inSlashStar && isGoBuildComment(line) {
if goBuild != nil {
return nil, nil, false, errMultipleGoBuild
}
goBuild = line
}
Comments:
for len(line) > 0 {
if inSlashStar {
if i := bytes.Index(line, bStarSlash); i >= 0 {
inSlashStar = false
line = bytes.TrimSpace(line[i+len(bStarSlash):])
continue Comments
}
continue Lines
}
if bytes.HasPrefix(line, bSlashSlash) {
continue Lines
}
if bytes.HasPrefix(line, bSlashStar) {
inSlashStar = true
line = bytes.TrimSpace(line[len(bSlashStar):])
continue Comments
}
// Found non-comment text.
break Lines
}
}
if i := strings.Index(name, ","); i >= 0 {
// comma-separated list
ok1 := matchTags(name[:i], tags)
ok2 := matchTags(name[i+1:], tags)
return ok1 && ok2
}
if strings.HasPrefix(name, "!!") { // bad syntax, reject always
return false
}
if strings.HasPrefix(name, "!") { // negation
return len(name) > 1 && matchTag(name[1:], tags, false)
}
return matchTag(name, tags, true)
return content[:end], goBuild, sawBinaryOnly, nil
}
// matchTag reports whether the tag name is valid and satisfied by tags[name]==want.
func matchTag(name string, tags map[string]bool, want bool) bool {
// matchTag reports whether the tag name is valid and tags[name] is true.
// As a special case, if tags["*"] is true and name is not empty or ignore,
// then matchTag will return prefer instead of the actual answer,
// which allows the caller to pretend in that case that most tags are
// both true and false.
func matchTag(name string, tags map[string]bool, prefer bool) bool {
// Tags must be letters, digits, underscores or dots.
// Unlike in Go identifiers, all digits are fine (e.g., "386").
for _, c := range name {
@ -131,7 +199,7 @@ func matchTag(name string, tags map[string]bool, want bool) bool {
// if we put * in the tags map then all tags
// except "ignore" are considered both present and not
// (so we return true no matter how 'want' is set).
return true
return prefer
}
have := tags[name]
@ -144,7 +212,25 @@ func matchTag(name string, tags map[string]bool, want bool) bool {
if name == "darwin" {
have = have || tags["ios"]
}
return have == want
return have
}
// eval is like
// x.Eval(func(tag string) bool { return matchTag(tag, tags) })
// except that it implements the special case for tags["*"] meaning
// all tags are both true and false at the same time.
func eval(x constraint.Expr, tags map[string]bool, prefer bool) bool {
switch x := x.(type) {
case *constraint.TagExpr:
return matchTag(x.Tag, tags, prefer)
case *constraint.NotExpr:
return !eval(x.X, tags, !prefer)
case *constraint.AndExpr:
return eval(x.X, tags, prefer) && eval(x.Y, tags, prefer)
case *constraint.OrExpr:
return eval(x.X, tags, prefer) || eval(x.Y, tags, prefer)
}
panic(fmt.Sprintf("unexpected constraint expression %T", x))
}
// MatchFile returns false if the name contains a $GOOS or $GOARCH

View File

@ -33,7 +33,7 @@ func TestScan(t *testing.T) {
}
if p == "net/http" {
// A test import but not an import
t.Errorf("json reported as importing encoding/binary but does not")
t.Errorf("json reported as importing net/http but does not")
}
}
if !foundBase64 {

View File

@ -1,3 +1,4 @@
//go:build android
// +build android
package android

View File

@ -1,3 +1,4 @@
//go:build linux
// +build linux
package android

View File

@ -1,3 +1,4 @@
//go:build !android
// +build !android
package android

View File

@ -1,3 +1,4 @@
//go:build illumos
// +build illumos
package illumos

View File

@ -1,3 +1,4 @@
//go:build solaris
// +build solaris
package illumos

View File

@ -1,3 +1,4 @@
//go:build !illumos
// +build !illumos
package illumos

View File

@ -1,8 +1,5 @@
// +build blahblh
// +build linux
// +build !linux
// +build windows
// +build darwin
//go:build blahblh && linux && !linux && windows && darwin
// +build blahblh,linux,!linux,windows,darwin
package x

View File

@ -316,6 +316,7 @@ For more about modules, see https://golang.org/ref/mod.
func init() {
CmdList.Run = runList // break init cycle
work.AddBuildFlags(CmdList, work.DefaultBuildFlags)
base.AddWorkfileFlag(&CmdList.Flag)
}
var (
@ -336,6 +337,8 @@ var (
var nl = []byte{'\n'}
func runList(ctx context.Context, cmd *base.Command, args []string) {
modload.InitWorkfile()
if *listFmt != "" && *listJson == true {
base.Fatalf("go list -f cannot be used with -json")
}
@ -355,9 +358,9 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
}
}
var do func(interface{})
var do func(any)
if *listJson {
do = func(x interface{}) {
do = func(x any) {
b, err := json.MarshalIndent(x, "", "\t")
if err != nil {
out.Flush()
@ -383,7 +386,7 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
if err != nil {
base.Fatalf("%s", err)
}
do = func(x interface{}) {
do = func(x any) {
if err := tmpl.Execute(out, x); err != nil {
out.Flush()
base.Fatalf("%s", err)
@ -424,12 +427,12 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
}
if modload.Init(); !modload.Enabled() {
base.Fatalf("go list -m: not using modules")
base.Fatalf("go: list -m cannot be used with GO111MODULE=off")
}
modload.LoadModFile(ctx) // Sets cfg.BuildMod as a side-effect.
if cfg.BuildMod == "vendor" {
const actionDisabledFormat = "go list -m: can't %s using the vendor directory\n\t(Use -mod=mod or -mod=readonly to bypass.)"
const actionDisabledFormat = "go: can't %s using the vendor directory\n\t(Use -mod=mod or -mod=readonly to bypass.)"
if *listVersions {
base.Fatalf(actionDisabledFormat, "determine available versions")
@ -468,11 +471,11 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
if !*listE {
for _, m := range mods {
if m.Error != nil {
base.Errorf("go list -m: %v", m.Error.Err)
base.Errorf("go: %v", m.Error.Err)
}
}
if err != nil {
base.Errorf("go list -m: %v", err)
base.Errorf("go: %v", err)
}
base.ExitIfErrors()
}
@ -708,7 +711,7 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
}
rmods, err := modload.ListModules(ctx, args, mode)
if err != nil && !*listE {
base.Errorf("go list -retracted: %v", err)
base.Errorf("go: %v", err)
}
for i, arg := range args {
rmod := rmods[i]

View File

@ -6,7 +6,7 @@ package load
import (
"cmd/go/internal/base"
"cmd/go/internal/str"
"cmd/internal/quoted"
"fmt"
"strings"
)
@ -22,6 +22,7 @@ var (
// that allows specifying different effective flags for different packages.
// See 'go help build' for more details about per-package flags.
type PerPackageFlag struct {
raw string
present bool
values []ppfValue
}
@ -39,6 +40,7 @@ func (f *PerPackageFlag) Set(v string) error {
// set is the implementation of Set, taking a cwd (current working directory) for easier testing.
func (f *PerPackageFlag) set(v, cwd string) error {
f.raw = v
f.present = true
match := func(p *Package) bool { return p.Internal.CmdlinePkg || p.Internal.CmdlineFiles } // default predicate with no pattern
// For backwards compatibility with earlier flag splitting, ignore spaces around flags.
@ -61,7 +63,7 @@ func (f *PerPackageFlag) set(v, cwd string) error {
match = MatchPackage(pattern, cwd)
v = v[i+1:]
}
flags, err := str.SplitQuotedFields(v)
flags, err := quoted.Split(v)
if err != nil {
return err
}
@ -72,9 +74,7 @@ func (f *PerPackageFlag) set(v, cwd string) error {
return nil
}
// String is required to implement flag.Value.
// It is not used, because cmd/go never calls flag.PrintDefaults.
func (f *PerPackageFlag) String() string { return "<PerPackageFlag>" }
func (f *PerPackageFlag) String() string { return f.raw }
// Present reports whether the flag appeared on the command line.
func (f *PerPackageFlag) Present() bool {

View File

@ -21,9 +21,11 @@ import (
pathpkg "path"
"path/filepath"
"runtime"
"runtime/debug"
"sort"
"strconv"
"strings"
"time"
"unicode"
"unicode/utf8"
@ -38,6 +40,7 @@ import (
"cmd/go/internal/search"
"cmd/go/internal/str"
"cmd/go/internal/trace"
"cmd/go/internal/vcs"
"cmd/internal/sys"
"golang.org/x/mod/modfile"
@ -203,6 +206,7 @@ type PackageInternal struct {
Local bool // imported via local path (./ or ../)
LocalPrefix string // interpret ./ and ../ imports relative to this prefix
ExeName string // desired name for temporary executable
FuzzInstrument bool // package should be instrumented for fuzzing
CoverMode string // preprocess Go source files with the coverage tool in this mode
CoverVars map[string]*CoverVar // variables created by coverage analysis
OmitDebug bool // tell linker not to write debug information
@ -494,7 +498,7 @@ type importError struct {
err error // created with fmt.Errorf
}
func ImportErrorf(path, format string, args ...interface{}) ImportPathError {
func ImportErrorf(path, format string, args ...any) ImportPathError {
err := &importError{importPath: path, err: fmt.Errorf(format, args...)}
if errStr := err.Error(); !strings.Contains(errStr, path) {
panic(fmt.Sprintf("path %q not in error %q", path, errStr))
@ -585,10 +589,10 @@ func ClearPackageCachePartial(args []string) {
delete(packageCache, arg)
}
}
resolvedImportCache.DeleteIf(func(key interface{}) bool {
resolvedImportCache.DeleteIf(func(key any) bool {
return shouldDelete[key.(importSpec).path]
})
packageDataCache.DeleteIf(func(key interface{}) bool {
packageDataCache.DeleteIf(func(key any) bool {
return shouldDelete[key.(string)]
})
}
@ -601,7 +605,7 @@ func ReloadPackageNoFlags(arg string, stk *ImportStack) *Package {
p := packageCache[arg]
if p != nil {
delete(packageCache, arg)
resolvedImportCache.DeleteIf(func(key interface{}) bool {
resolvedImportCache.DeleteIf(func(key any) bool {
return key.(importSpec).path == p.ImportPath
})
packageDataCache.Delete(p.ImportPath)
@ -813,7 +817,7 @@ func loadPackageData(ctx context.Context, path, parentPath, parentDir, parentRoo
parentIsStd: parentIsStd,
mode: mode,
}
r := resolvedImportCache.Do(importKey, func() interface{} {
r := resolvedImportCache.Do(importKey, func() any {
var r resolvedImport
if build.IsLocalImport(path) {
r.dir = filepath.Join(parentDir, path)
@ -840,7 +844,7 @@ func loadPackageData(ctx context.Context, path, parentPath, parentDir, parentRoo
// Load the package from its directory. If we already found the package's
// directory when resolving its import path, use that.
data := packageDataCache.Do(r.path, func() interface{} {
data := packageDataCache.Do(r.path, func() any {
loaded = true
var data packageData
if r.dir != "" {
@ -1059,7 +1063,7 @@ func cleanImport(path string) string {
var isDirCache par.Cache
func isDir(path string) bool {
return isDirCache.Do(path, func() interface{} {
return isDirCache.Do(path, func() any {
fi, err := fsys.Stat(path)
return err == nil && fi.IsDir()
}).(bool)
@ -1187,7 +1191,7 @@ var (
// goModPath returns the module path in the go.mod in dir, if any.
func goModPath(dir string) (path string) {
return goModPathCache.Do(dir, func() interface{} {
return goModPathCache.Do(dir, func() any {
data, err := os.ReadFile(filepath.Join(dir, "go.mod"))
if err != nil {
return ""
@ -1456,9 +1460,9 @@ func disallowInternal(ctx context.Context, srcDir string, importer *Package, imp
// The importer is a list of command-line files.
// Pretend that the import path is the import path of the
// directory containing them.
// If the directory is outside the main module, this will resolve to ".",
// If the directory is outside the main modules, this will resolve to ".",
// which is not a prefix of any valid module.
importerPath = modload.DirImportPath(ctx, importer.Dir)
importerPath, _ = modload.MainModules.DirImportPath(ctx, importer.Dir)
}
parentOfInternal := p.ImportPath[:i]
if str.HasPathPrefix(importerPath, parentOfInternal) {
@ -1628,6 +1632,7 @@ var cgoSyscallExclude = map[string]bool{
"runtime/cgo": true,
"runtime/race": true,
"runtime/msan": true,
"runtime/asan": true,
}
var foldPath = make(map[string]string)
@ -1683,9 +1688,10 @@ func (p *Package) DefaultExecName() string {
func (p *Package) load(ctx context.Context, opts PackageOpts, path string, stk *ImportStack, importPos []token.Position, bp *build.Package, err error) {
p.copyBuild(opts, bp)
// The localPrefix is the path we interpret ./ imports relative to.
// The localPrefix is the path we interpret ./ imports relative to,
// if we support them at all (not in module mode!).
// Synthesized main packages sometimes override this.
if p.Internal.Local {
if p.Internal.Local && !cfg.ModulesEnabled {
p.Internal.LocalPrefix = dirToImportPath(p.Dir)
}
@ -1925,9 +1931,8 @@ func (p *Package) load(ctx context.Context, opts PackageOpts, path string, stk *
}
p.Internal.Imports = imports
p.collectDeps()
if cfg.ModulesEnabled && p.Error == nil && p.Name == "main" && len(p.DepsErrors) == 0 {
p.Internal.BuildInfo = modload.PackageBuildInfo(pkgPath, p.Deps)
if p.Error == nil && p.Name == "main" && len(p.DepsErrors) == 0 {
p.setBuildInfo()
}
// unsafe is a fake package.
@ -2018,13 +2023,18 @@ func resolveEmbed(pkgdir string, patterns []string) (files []string, pmap map[st
for _, pattern = range patterns {
pid++
glob := pattern
all := strings.HasPrefix(pattern, "all:")
if all {
glob = pattern[len("all:"):]
}
// Check pattern is valid for //go:embed.
if _, err := path.Match(pattern, ""); err != nil || !validEmbedPattern(pattern) {
if _, err := path.Match(glob, ""); err != nil || !validEmbedPattern(glob) {
return nil, nil, fmt.Errorf("invalid pattern syntax")
}
// Glob to find matches.
match, err := fsys.Glob(pkgdir + string(filepath.Separator) + filepath.FromSlash(pattern))
match, err := fsys.Glob(pkgdir + string(filepath.Separator) + filepath.FromSlash(glob))
if err != nil {
return nil, nil, err
}
@ -2087,7 +2097,7 @@ func resolveEmbed(pkgdir string, patterns []string) (files []string, pmap map[st
}
rel := filepath.ToSlash(path[len(pkgdir)+1:])
name := info.Name()
if path != file && (isBadEmbedName(name) || name[0] == '.' || name[0] == '_') {
if path != file && (isBadEmbedName(name) || ((name[0] == '.' || name[0] == '_') && !all)) {
// Ignore bad names, assuming they won't go into modules.
// Also avoid hidden files that user may not know about.
// See golang.org/issue/42328.
@ -2199,6 +2209,229 @@ func (p *Package) collectDeps() {
}
}
// vcsStatusCache maps repository directories (string)
// to their VCS information (vcsStatusError).
var vcsStatusCache par.Cache
// setBuildInfo gathers build information, formats it as a string to be
// embedded in the binary, then sets p.Internal.BuildInfo to that string.
// setBuildInfo should only be called on a main package with no errors.
//
// This information can be retrieved using debug.ReadBuildInfo.
//
// Note that the GoVersion field is not set here to avoid encoding it twice.
// It is stored separately in the binary, mostly for historical reasons.
func (p *Package) setBuildInfo() {
// TODO: build and vcs information is not embedded for executables in GOROOT.
// cmd/dist uses -gcflags=all= -ldflags=all= by default, which means these
// executables always appear stale unless the user sets the same flags.
// Perhaps it's safe to omit those flags when GO_GCFLAGS and GO_LDFLAGS
// are not set?
setPkgErrorf := func(format string, args ...any) {
if p.Error == nil {
p.Error = &PackageError{Err: fmt.Errorf(format, args...)}
}
}
var debugModFromModinfo func(*modinfo.ModulePublic) *debug.Module
debugModFromModinfo = func(mi *modinfo.ModulePublic) *debug.Module {
dm := &debug.Module{
Path: mi.Path,
Version: mi.Version,
}
if mi.Replace != nil {
dm.Replace = debugModFromModinfo(mi.Replace)
} else {
dm.Sum = modfetch.Sum(module.Version{Path: mi.Path, Version: mi.Version})
}
return dm
}
var main debug.Module
if p.Module != nil {
main = *debugModFromModinfo(p.Module)
}
visited := make(map[*Package]bool)
mdeps := make(map[module.Version]*debug.Module)
var q []*Package
q = append(q, p.Internal.Imports...)
for len(q) > 0 {
p1 := q[0]
q = q[1:]
if visited[p1] {
continue
}
visited[p1] = true
if p1.Module != nil {
m := module.Version{Path: p1.Module.Path, Version: p1.Module.Version}
if p1.Module.Path != main.Path && mdeps[m] == nil {
mdeps[m] = debugModFromModinfo(p1.Module)
}
}
q = append(q, p1.Internal.Imports...)
}
sortedMods := make([]module.Version, 0, len(mdeps))
for mod := range mdeps {
sortedMods = append(sortedMods, mod)
}
module.Sort(sortedMods)
deps := make([]*debug.Module, len(sortedMods))
for i, mod := range sortedMods {
deps[i] = mdeps[mod]
}
pkgPath := p.ImportPath
if p.Internal.CmdlineFiles {
pkgPath = "command-line-arguments"
}
info := &debug.BuildInfo{
Path: pkgPath,
Main: main,
Deps: deps,
}
appendSetting := func(key, value string) {
value = strings.ReplaceAll(value, "\n", " ") // make value safe
info.Settings = append(info.Settings, debug.BuildSetting{Key: key, Value: value})
}
// Add command-line flags relevant to the build.
// This is informational, not an exhaustive list.
// Please keep the list sorted.
if !p.Standard {
if cfg.BuildASan {
appendSetting("-asan", "true")
}
if BuildAsmflags.present {
appendSetting("-asmflags", BuildAsmflags.String())
}
appendSetting("-compiler", cfg.BuildContext.Compiler)
if BuildGccgoflags.present && cfg.BuildContext.Compiler == "gccgo" {
appendSetting("-gccgoflags", BuildGccgoflags.String())
}
if BuildGcflags.present && cfg.BuildContext.Compiler == "gc" {
appendSetting("-gcflags", BuildGcflags.String())
}
if BuildLdflags.present {
appendSetting("-ldflags", BuildLdflags.String())
}
if cfg.BuildMSan {
appendSetting("-msan", "true")
}
if cfg.BuildRace {
appendSetting("-race", "true")
}
if tags := cfg.BuildContext.BuildTags; len(tags) > 0 {
appendSetting("-tags", strings.Join(tags, ","))
}
cgo := "0"
if cfg.BuildContext.CgoEnabled {
cgo = "1"
}
appendSetting("CGO_ENABLED", cgo)
if cfg.BuildContext.CgoEnabled {
for _, name := range []string{"CGO_CFLAGS", "CGO_CPPFLAGS", "CGO_CXXFLAGS", "CGO_LDFLAGS"} {
appendSetting(name, cfg.Getenv(name))
}
}
appendSetting("GOARCH", cfg.BuildContext.GOARCH)
if cfg.GOEXPERIMENT != "" {
appendSetting("GOEXPERIMENT", cfg.GOEXPERIMENT)
}
appendSetting("GOOS", cfg.BuildContext.GOOS)
if key, val := cfg.GetArchEnv(); key != "" && val != "" {
appendSetting(key, val)
}
}
// Add VCS status if all conditions are true:
//
// - -buildvcs is enabled.
// - p is contained within a main module (there may be multiple main modules
// in a workspace, but local replacements don't count).
// - Both the current directory and p's module's root directory are contained
// in the same local repository.
// - We know the VCS commands needed to get the status.
setVCSError := func(err error) {
setPkgErrorf("error obtaining VCS status: %v\n\tUse -buildvcs=false to disable VCS stamping.", err)
}
var repoDir string
var vcsCmd *vcs.Cmd
var err error
const allowNesting = true
if cfg.BuildBuildvcs && p.Module != nil && p.Module.Version == "" && !p.Standard {
repoDir, vcsCmd, err = vcs.FromDir(base.Cwd(), "", allowNesting)
if err != nil && !errors.Is(err, os.ErrNotExist) {
setVCSError(err)
return
}
if !str.HasFilePathPrefix(p.Module.Dir, repoDir) &&
!str.HasFilePathPrefix(repoDir, p.Module.Dir) {
// The module containing the main package does not overlap with the
// repository containing the working directory. Don't include VCS info.
// If the repo contains the module or vice versa, but they are not
// the same directory, it's likely an error (see below).
repoDir, vcsCmd = "", nil
}
}
if repoDir != "" && vcsCmd.Status != nil {
// Check that the current directory, package, and module are in the same
// repository. vcs.FromDir allows nested Git repositories, but nesting
// is not allowed for other VCS tools. The current directory may be outside
// p.Module.Dir when a workspace is used.
pkgRepoDir, _, err := vcs.FromDir(p.Dir, "", allowNesting)
if err != nil {
setVCSError(err)
return
}
if pkgRepoDir != repoDir {
setVCSError(fmt.Errorf("main package is in repository %q but current directory is in repository %q", pkgRepoDir, repoDir))
return
}
modRepoDir, _, err := vcs.FromDir(p.Module.Dir, "", allowNesting)
if err != nil {
setVCSError(err)
return
}
if modRepoDir != repoDir {
setVCSError(fmt.Errorf("main module is in repository %q but current directory is in repository %q", modRepoDir, repoDir))
return
}
type vcsStatusError struct {
Status vcs.Status
Err error
}
cached := vcsStatusCache.Do(repoDir, func() any {
st, err := vcsCmd.Status(vcsCmd, repoDir)
return vcsStatusError{st, err}
}).(vcsStatusError)
if err := cached.Err; err != nil {
setVCSError(err)
return
}
st := cached.Status
appendSetting("vcs", vcsCmd.Cmd)
if st.Revision != "" {
appendSetting("vcs.revision", st.Revision)
}
if !st.CommitTime.IsZero() {
stamp := st.CommitTime.UTC().Format(time.RFC3339Nano)
appendSetting("vcs.time", stamp)
}
appendSetting("vcs.modified", strconv.FormatBool(st.Uncommitted))
}
text, err := info.MarshalText()
if err != nil {
setPkgErrorf("error formatting build info: %v", err)
return
}
p.Internal.BuildInfo = string(text)
}
// SafeArg reports whether arg is a "safe" command-line argument,
// meaning that when it appears in a command-line, it probably
// doesn't have some special meaning other than its own name.
@ -2237,6 +2470,10 @@ func LinkerDeps(p *Package) []string {
if cfg.BuildMSan {
deps = append(deps, "runtime/msan")
}
// Using address sanitizer forces an import of runtime/asan.
if cfg.BuildASan {
deps = append(deps, "runtime/asan")
}
return deps
}
@ -2453,7 +2690,8 @@ func PackagesAndErrors(ctx context.Context, opts PackageOpts, patterns []string)
}
matches, _ = modload.LoadPackages(ctx, modOpts, patterns...)
} else {
matches = search.ImportPaths(patterns)
noModRoots := []string{}
matches = search.ImportPaths(patterns, noModRoots)
}
var (
@ -2679,10 +2917,7 @@ func GoFilesPackage(ctx context.Context, opts PackageOpts, gofiles []string) *Pa
if fi.IsDir() {
base.Fatalf("%s is a directory, should be a Go file", file)
}
dir1, _ := filepath.Split(file)
if dir1 == "" {
dir1 = "./"
}
dir1 := filepath.Dir(file)
if dir == "" {
dir = dir1
} else if dir != dir1 {
@ -2710,7 +2945,9 @@ func GoFilesPackage(ctx context.Context, opts PackageOpts, gofiles []string) *Pa
pkg.Internal.Local = true
pkg.Internal.CmdlineFiles = true
pkg.load(ctx, opts, "command-line-arguments", &stk, nil, bp, err)
pkg.Internal.LocalPrefix = dirToImportPath(dir)
if !cfg.ModulesEnabled {
pkg.Internal.LocalPrefix = dirToImportPath(dir)
}
pkg.ImportPath = "command-line-arguments"
pkg.Target = ""
pkg.Match = gofiles

View File

@ -555,6 +555,7 @@ func formatTestmain(t *testFuncs) ([]byte, error) {
type testFuncs struct {
Tests []testFunc
Benchmarks []testFunc
FuzzTargets []testFunc
Examples []testFunc
TestMain *testFunc
Package *Package
@ -653,6 +654,13 @@ func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error {
}
t.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, "", false})
*doImport, *seen = true, true
case isTest(name, "Fuzz"):
err := checkTestFunc(n, "F")
if err != nil {
return err
}
t.FuzzTargets = append(t.FuzzTargets, testFunc{pkg, name, "", false})
*doImport, *seen = true, true
}
}
ex := doc.Examples(f)
@ -670,10 +678,16 @@ func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error {
}
func checkTestFunc(fn *ast.FuncDecl, arg string) error {
var why string
if !isTestFunc(fn, arg) {
name := fn.Name.String()
why = fmt.Sprintf("must be: func %s(%s *testing.%s)", fn.Name.String(), strings.ToLower(arg), arg)
}
if fn.Type.TypeParams.NumFields() > 0 {
why = "test functions cannot have type parameters"
}
if why != "" {
pos := testFileSet.Position(fn.Pos())
return fmt.Errorf("%s: wrong signature for %s, must be: func %s(%s *testing.%s)", pos, name, name, strings.ToLower(arg), arg)
return fmt.Errorf("%s: wrong signature for %s, %s", pos, fn.Name.String(), why)
}
return nil
}
@ -716,6 +730,12 @@ var benchmarks = []testing.InternalBenchmark{
{{end}}
}
var fuzzTargets = []testing.InternalFuzzTarget{
{{range .FuzzTargets}}
{"{{.Name}}", {{.Package}}.{{.Name}}},
{{end}}
}
var examples = []testing.InternalExample{
{{range .Examples}}
{"{{.Name}}", {{.Package}}.{{.Name}}, {{.Output | printf "%q"}}, {{.Unordered}}},
@ -774,7 +794,7 @@ func main() {
CoveredPackages: {{printf "%q" .Covered}},
})
{{end}}
m := testing.MainStart(testdeps.TestDeps{}, tests, benchmarks, examples)
m := testing.MainStart(testdeps.TestDeps{}, tests, benchmarks, fuzzTargets, examples)
{{with .TestMain}}
{{.Package}}.{{.Name}}(m)
os.Exit(int(reflect.ValueOf(m).Elem().FieldByName("exitCode").Int()))

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build aix || (solaris && !illumos)
// +build aix solaris,!illumos
// This code implements the filelock API using POSIX 'fcntl' locks, which attach
// to an (inode, process) pair rather than a file descriptor. To avoid unlocking

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build !aix && !darwin && !dragonfly && !freebsd && !hurd && !linux && !netbsd && !openbsd && !plan9 && !solaris && !windows
// +build !aix,!darwin,!dragonfly,!freebsd,!hurd,!linux,!netbsd,!openbsd,!plan9,!solaris,!windows
package filelock

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build plan9
// +build plan9
package filelock

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build !js && !plan9
// +build !js,!plan9
package filelock_test

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build darwin || dragonfly || freebsd || hurd || illumos || linux || netbsd || openbsd
// +build darwin dragonfly freebsd hurd illumos linux netbsd openbsd
package filelock

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build windows
// +build windows
package filelock

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build !plan9
// +build !plan9
package lockedfile

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build plan9
// +build plan9
package lockedfile

View File

@ -4,7 +4,6 @@
// js does not support inter-process file locking.
//go:build !js
// +build !js
package lockedfile_test

View File

@ -4,7 +4,6 @@
// js does not support inter-process file locking.
//go:build !js
// +build !js
package lockedfile_test

View File

@ -16,6 +16,7 @@ import (
"cmd/go/internal/modload"
"golang.org/x/mod/module"
"golang.org/x/mod/semver"
)
var cmdDownload = &base.Command{
@ -24,8 +25,11 @@ var cmdDownload = &base.Command{
Long: `
Download downloads the named modules, which can be module patterns selecting
dependencies of the main module or module queries of the form path@version.
With no arguments, download applies to all dependencies of the main module
(equivalent to 'go mod download all').
With no arguments, download applies to the modules needed to build and test
the packages in the main module: the modules explicitly required by the main
module if it is at 'go 1.17' or higher, or all transitively-required modules
if at 'go 1.16' or lower.
The go command will automatically download modules as needed during ordinary
execution. The "go mod download" command is useful mainly for pre-filling
@ -66,6 +70,7 @@ func init() {
// TODO(jayconrod): https://golang.org/issue/35849 Apply -x to other 'go mod' commands.
cmdDownload.Flag.BoolVar(&cfg.BuildX, "x", false, "")
base.AddModCommonFlags(&cmdDownload.Flag)
base.AddWorkfileFlag(&cmdDownload.Flag)
}
type moduleJSON struct {
@ -81,27 +86,68 @@ type moduleJSON struct {
}
func runDownload(ctx context.Context, cmd *base.Command, args []string) {
modload.InitWorkfile()
// Check whether modules are enabled and whether we're in a module.
modload.ForceUseModules = true
if !modload.HasModRoot() && len(args) == 0 {
base.Fatalf("go mod download: no modules specified (see 'go help mod download')")
}
modload.ExplicitWriteGoMod = true
haveExplicitArgs := len(args) > 0
if !haveExplicitArgs {
args = []string{"all"}
}
if modload.HasModRoot() {
modload.LoadModFile(ctx) // to fill Target
targetAtUpgrade := modload.Target.Path + "@upgrade"
targetAtPatch := modload.Target.Path + "@patch"
for _, arg := range args {
switch arg {
case modload.Target.Path, targetAtUpgrade, targetAtPatch:
os.Stderr.WriteString("go mod download: skipping argument " + arg + " that resolves to the main module\n")
if modload.HasModRoot() || modload.WorkFilePath() != "" {
modload.LoadModFile(ctx) // to fill MainModules
if haveExplicitArgs {
for _, mainModule := range modload.MainModules.Versions() {
targetAtUpgrade := mainModule.Path + "@upgrade"
targetAtPatch := mainModule.Path + "@patch"
for _, arg := range args {
switch arg {
case mainModule.Path, targetAtUpgrade, targetAtPatch:
os.Stderr.WriteString("go: skipping download of " + arg + " that resolves to the main module\n")
}
}
}
} else if modload.WorkFilePath() != "" {
// TODO(#44435): Think about what the correct query is to download the
// right set of modules. Also see code review comment at
// https://go-review.googlesource.com/c/go/+/359794/comments/ce946a80_6cf53992.
args = []string{"all"}
} else {
mainModule := modload.MainModules.Versions()[0]
modFile := modload.MainModules.ModFile(mainModule)
if modFile.Go == nil || semver.Compare("v"+modFile.Go.Version, modload.ExplicitIndirectVersionV) < 0 {
if len(modFile.Require) > 0 {
args = []string{"all"}
}
} else {
// As of Go 1.17, the go.mod file explicitly requires every module
// that provides any package imported by the main module.
// 'go mod download' is typically run before testing packages in the
// main module, so by default we shouldn't download the others
// (which are presumed irrelevant to the packages in the main module).
// See https://golang.org/issue/44435.
//
// However, we also need to load the full module graph, to ensure that
// we have downloaded enough of the module graph to run 'go list all',
// 'go mod graph', and similar commands.
_ = modload.LoadModGraph(ctx, "")
for _, m := range modFile.Require {
args = append(args, m.Mod.Path)
}
}
}
}
if len(args) == 0 {
if modload.HasModRoot() {
os.Stderr.WriteString("go: no module dependencies to download\n")
} else {
base.Errorf("go: no modules specified (see 'go help mod download')")
}
base.Exit()
}
downloadModule := func(m *moduleJSON) {
var err error
m.Info, err = modfetch.InfoFile(m.Path, m.Version)
@ -140,13 +186,16 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
if !haveExplicitArgs {
// 'go mod download' is sometimes run without arguments to pre-populate the
// module cache. It may fetch modules that aren't needed to build packages
// in the main mdoule. This is usually not intended, so don't save sums for
// downloaded modules (golang.org/issue/45332).
// TODO(golang.org/issue/45551): For now, in ListModules, save sums needed
// to load the build list (same as 1.15 behavior). In the future, report an
// error if go.mod or go.sum need to be updated after loading the build
// list.
modload.DisallowWriteGoMod()
// in the main module. This is usually not intended, so don't save sums for
// downloaded modules (golang.org/issue/45332). We do still fix
// inconsistencies in go.mod though.
//
// TODO(#45551): In the future, report an error if go.mod or go.sum need to
// be updated after loading the build list. This may require setting
// the mode to "mod" or "readonly" depending on haveExplicitArgs.
if err := modload.WriteGoMod(ctx); err != nil {
base.Fatalf("go: %v", err)
}
}
for _, info := range infos {
@ -183,7 +232,7 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
for _, m := range mods {
b, err := json.MarshalIndent(m, "", "\t")
if err != nil {
base.Fatalf("go mod download: %v", err)
base.Fatalf("go: %v", err)
}
os.Stdout.Write(append(b, '\n'))
if m.Error != "" {
@ -193,7 +242,7 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
} else {
for _, m := range mods {
if m.Error != "" {
base.Errorf("go mod download: %v", m.Error)
base.Errorf("go: %v", m.Error)
}
}
base.ExitIfErrors()
@ -206,13 +255,15 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
//
// Don't save sums for 'go mod download' without arguments; see comment above.
if haveExplicitArgs {
modload.WriteGoMod(ctx)
if err := modload.WriteGoMod(ctx); err != nil {
base.Errorf("go: %v", err)
}
}
// If there was an error matching some of the requested packages, emit it now
// (after we've written the checksums for the modules that were downloaded
// successfully).
if infosErr != nil {
base.Errorf("go mod download: %v", infosErr)
base.Errorf("go: %v", infosErr)
}
}

View File

@ -171,15 +171,15 @@ func runEdit(ctx context.Context, cmd *base.Command, args []string) {
len(edits) > 0
if !anyFlags {
base.Fatalf("go mod edit: no flags specified (see 'go help mod edit').")
base.Fatalf("go: no flags specified (see 'go help mod edit').")
}
if *editJSON && *editPrint {
base.Fatalf("go mod edit: cannot use both -json and -print")
base.Fatalf("go: cannot use both -json and -print")
}
if len(args) > 1 {
base.Fatalf("go mod edit: too many arguments")
base.Fatalf("go: too many arguments")
}
var gomod string
if len(args) == 1 {
@ -190,7 +190,7 @@ func runEdit(ctx context.Context, cmd *base.Command, args []string) {
if *editModule != "" {
if err := module.CheckImportPath(*editModule); err != nil {
base.Fatalf("go mod: invalid -module: %v", err)
base.Fatalf("go: invalid -module: %v", err)
}
}
@ -264,15 +264,15 @@ func runEdit(ctx context.Context, cmd *base.Command, args []string) {
func parsePathVersion(flag, arg string) (path, version string) {
i := strings.Index(arg, "@")
if i < 0 {
base.Fatalf("go mod: -%s=%s: need path@version", flag, arg)
base.Fatalf("go: -%s=%s: need path@version", flag, arg)
}
path, version = strings.TrimSpace(arg[:i]), strings.TrimSpace(arg[i+1:])
if err := module.CheckImportPath(path); err != nil {
base.Fatalf("go mod: -%s=%s: invalid path: %v", flag, arg, err)
base.Fatalf("go: -%s=%s: invalid path: %v", flag, arg, err)
}
if !allowedVersionArg(version) {
base.Fatalf("go mod: -%s=%s: invalid version %q", flag, arg, version)
base.Fatalf("go: -%s=%s: invalid version %q", flag, arg, version)
}
return path, version
@ -281,11 +281,11 @@ func parsePathVersion(flag, arg string) (path, version string) {
// parsePath parses -flag=arg expecting arg to be path (not path@version).
func parsePath(flag, arg string) (path string) {
if strings.Contains(arg, "@") {
base.Fatalf("go mod: -%s=%s: need just path, not path@version", flag, arg)
base.Fatalf("go: -%s=%s: need just path, not path@version", flag, arg)
}
path = arg
if err := module.CheckImportPath(path); err != nil {
base.Fatalf("go mod: -%s=%s: invalid path: %v", flag, arg, err)
base.Fatalf("go: -%s=%s: invalid path: %v", flag, arg, err)
}
return path
}
@ -350,7 +350,7 @@ func flagRequire(arg string) {
path, version := parsePathVersion("require", arg)
edits = append(edits, func(f *modfile.File) {
if err := f.AddRequire(path, version); err != nil {
base.Fatalf("go mod: -require=%s: %v", arg, err)
base.Fatalf("go: -require=%s: %v", arg, err)
}
})
}
@ -360,7 +360,7 @@ func flagDropRequire(arg string) {
path := parsePath("droprequire", arg)
edits = append(edits, func(f *modfile.File) {
if err := f.DropRequire(path); err != nil {
base.Fatalf("go mod: -droprequire=%s: %v", arg, err)
base.Fatalf("go: -droprequire=%s: %v", arg, err)
}
})
}
@ -370,7 +370,7 @@ func flagExclude(arg string) {
path, version := parsePathVersion("exclude", arg)
edits = append(edits, func(f *modfile.File) {
if err := f.AddExclude(path, version); err != nil {
base.Fatalf("go mod: -exclude=%s: %v", arg, err)
base.Fatalf("go: -exclude=%s: %v", arg, err)
}
})
}
@ -380,7 +380,7 @@ func flagDropExclude(arg string) {
path, version := parsePathVersion("dropexclude", arg)
edits = append(edits, func(f *modfile.File) {
if err := f.DropExclude(path, version); err != nil {
base.Fatalf("go mod: -dropexclude=%s: %v", arg, err)
base.Fatalf("go: -dropexclude=%s: %v", arg, err)
}
})
}
@ -389,27 +389,27 @@ func flagDropExclude(arg string) {
func flagReplace(arg string) {
var i int
if i = strings.Index(arg, "="); i < 0 {
base.Fatalf("go mod: -replace=%s: need old[@v]=new[@w] (missing =)", arg)
base.Fatalf("go: -replace=%s: need old[@v]=new[@w] (missing =)", arg)
}
old, new := strings.TrimSpace(arg[:i]), strings.TrimSpace(arg[i+1:])
if strings.HasPrefix(new, ">") {
base.Fatalf("go mod: -replace=%s: separator between old and new is =, not =>", arg)
base.Fatalf("go: -replace=%s: separator between old and new is =, not =>", arg)
}
oldPath, oldVersion, err := parsePathVersionOptional("old", old, false)
if err != nil {
base.Fatalf("go mod: -replace=%s: %v", arg, err)
base.Fatalf("go: -replace=%s: %v", arg, err)
}
newPath, newVersion, err := parsePathVersionOptional("new", new, true)
if err != nil {
base.Fatalf("go mod: -replace=%s: %v", arg, err)
base.Fatalf("go: -replace=%s: %v", arg, err)
}
if newPath == new && !modfile.IsDirectoryPath(new) {
base.Fatalf("go mod: -replace=%s: unversioned new path must be local directory", arg)
base.Fatalf("go: -replace=%s: unversioned new path must be local directory", arg)
}
edits = append(edits, func(f *modfile.File) {
if err := f.AddReplace(oldPath, oldVersion, newPath, newVersion); err != nil {
base.Fatalf("go mod: -replace=%s: %v", arg, err)
base.Fatalf("go: -replace=%s: %v", arg, err)
}
})
}
@ -418,11 +418,11 @@ func flagReplace(arg string) {
func flagDropReplace(arg string) {
path, version, err := parsePathVersionOptional("old", arg, true)
if err != nil {
base.Fatalf("go mod: -dropreplace=%s: %v", arg, err)
base.Fatalf("go: -dropreplace=%s: %v", arg, err)
}
edits = append(edits, func(f *modfile.File) {
if err := f.DropReplace(path, version); err != nil {
base.Fatalf("go mod: -dropreplace=%s: %v", arg, err)
base.Fatalf("go: -dropreplace=%s: %v", arg, err)
}
})
}
@ -431,11 +431,11 @@ func flagDropReplace(arg string) {
func flagRetract(arg string) {
vi, err := parseVersionInterval(arg)
if err != nil {
base.Fatalf("go mod: -retract=%s: %v", arg, err)
base.Fatalf("go: -retract=%s: %v", arg, err)
}
edits = append(edits, func(f *modfile.File) {
if err := f.AddRetract(vi, ""); err != nil {
base.Fatalf("go mod: -retract=%s: %v", arg, err)
base.Fatalf("go: -retract=%s: %v", arg, err)
}
})
}
@ -444,11 +444,11 @@ func flagRetract(arg string) {
func flagDropRetract(arg string) {
vi, err := parseVersionInterval(arg)
if err != nil {
base.Fatalf("go mod: -dropretract=%s: %v", arg, err)
base.Fatalf("go: -dropretract=%s: %v", arg, err)
}
edits = append(edits, func(f *modfile.File) {
if err := f.DropRetract(vi); err != nil {
base.Fatalf("go mod: -dropretract=%s: %v", arg, err)
base.Fatalf("go: -dropretract=%s: %v", arg, err)
}
})
}

View File

@ -42,11 +42,14 @@ var (
func init() {
cmdGraph.Flag.Var(&graphGo, "go", "")
base.AddModCommonFlags(&cmdGraph.Flag)
base.AddWorkfileFlag(&cmdGraph.Flag)
}
func runGraph(ctx context.Context, cmd *base.Command, args []string) {
modload.InitWorkfile()
if len(args) > 0 {
base.Fatalf("go mod graph: graph takes no arguments")
base.Fatalf("go: 'go mod graph' accepts no arguments")
}
modload.ForceUseModules = true
modload.RootMode = modload.NeedRoot

View File

@ -39,7 +39,7 @@ func init() {
func runInit(ctx context.Context, cmd *base.Command, args []string) {
if len(args) > 1 {
base.Fatalf("go mod init: too many arguments")
base.Fatalf("go: 'go mod init' accepts at most one argument")
}
var modPath string
if len(args) == 1 {

View File

@ -75,8 +75,8 @@ type goVersionFlag struct {
v string
}
func (f *goVersionFlag) String() string { return f.v }
func (f *goVersionFlag) Get() interface{} { return f.v }
func (f *goVersionFlag) String() string { return f.v }
func (f *goVersionFlag) Get() any { return f.v }
func (f *goVersionFlag) Set(s string) error {
if s != "" {
@ -95,7 +95,7 @@ func (f *goVersionFlag) Set(s string) error {
func runTidy(ctx context.Context, cmd *base.Command, args []string) {
if len(args) > 0 {
base.Fatalf("go mod tidy: no arguments allowed")
base.Fatalf("go: 'go mod tidy' accepts no arguments")
}
// Tidy aims to make 'go test' reproducible for any package in 'all', so we

View File

@ -31,7 +31,7 @@ import (
)
var cmdVendor = &base.Command{
UsageLine: "go mod vendor [-e] [-v]",
UsageLine: "go mod vendor [-e] [-v] [-o outdir]",
Short: "make vendored copy of dependencies",
Long: `
Vendor resets the main module's vendor directory to include all packages
@ -44,22 +44,29 @@ modules and packages to standard error.
The -e flag causes vendor to attempt to proceed despite errors
encountered while loading packages.
The -o flag causes vendor to create the vendor directory at the given
path instead of "vendor". The go command can only use a vendor directory
named "vendor" within the module root directory, so this flag is
primarily useful for other tools.
See https://golang.org/ref/mod#go-mod-vendor for more about 'go mod vendor'.
`,
Run: runVendor,
}
var vendorE bool // if true, report errors but proceed anyway
var vendorE bool // if true, report errors but proceed anyway
var vendorO string // if set, overrides the default output directory
func init() {
cmdVendor.Flag.BoolVar(&cfg.BuildV, "v", false, "")
cmdVendor.Flag.BoolVar(&vendorE, "e", false, "")
cmdVendor.Flag.StringVar(&vendorO, "o", "", "")
base.AddModCommonFlags(&cmdVendor.Flag)
}
func runVendor(ctx context.Context, cmd *base.Command, args []string) {
if len(args) != 0 {
base.Fatalf("go mod vendor: vendor takes no arguments")
base.Fatalf("go: 'go mod vendor' accepts no arguments")
}
modload.ForceUseModules = true
modload.RootMode = modload.NeedRoot
@ -74,15 +81,23 @@ func runVendor(ctx context.Context, cmd *base.Command, args []string) {
}
_, pkgs := modload.LoadPackages(ctx, loadOpts, "all")
vdir := filepath.Join(modload.ModRoot(), "vendor")
var vdir string
switch {
case filepath.IsAbs(vendorO):
vdir = vendorO
case vendorO != "":
vdir = filepath.Join(base.Cwd(), vendorO)
default:
vdir = filepath.Join(modload.VendorDir())
}
if err := os.RemoveAll(vdir); err != nil {
base.Fatalf("go mod vendor: %v", err)
base.Fatalf("go: %v", err)
}
modpkgs := make(map[module.Version][]string)
for _, pkg := range pkgs {
m := modload.PackageModule(pkg)
if m.Path == "" || m == modload.Target {
if m.Path == "" || m.Version == "" && modload.MainModules.Contains(m.Path) {
continue
}
modpkgs[m] = append(modpkgs[m], pkg)
@ -128,7 +143,8 @@ func runVendor(ctx context.Context, cmd *base.Command, args []string) {
}
for _, m := range vendorMods {
line := moduleLine(m, modload.Replacement(m))
replacement := modload.Replacement(m)
line := moduleLine(m, replacement)
io.WriteString(w, line)
goVersion := ""
@ -177,11 +193,11 @@ func runVendor(ctx context.Context, cmd *base.Command, args []string) {
}
if err := os.MkdirAll(vdir, 0777); err != nil {
base.Fatalf("go mod vendor: %v", err)
base.Fatalf("go: %v", err)
}
if err := os.WriteFile(filepath.Join(vdir, "modules.txt"), buf.Bytes(), 0666); err != nil {
base.Fatalf("go mod vendor: %v", err)
base.Fatalf("go: %v", err)
}
}
@ -242,14 +258,14 @@ func vendorPkg(vdir, pkg string) {
if err != nil {
if errors.As(err, &noGoError) {
return // No source files in this package are built. Skip embeds in ignored files.
} else if !errors.As(err, &multiplePackageError) { // multiplePackgeErrors are okay, but others are not.
} else if !errors.As(err, &multiplePackageError) { // multiplePackageErrors are OK, but others are not.
base.Fatalf("internal error: failed to find embedded files of %s: %v\n", pkg, err)
}
}
embedPatterns := str.StringList(bp.EmbedPatterns, bp.TestEmbedPatterns, bp.XTestEmbedPatterns)
embeds, err := load.ResolveEmbed(bp.Dir, embedPatterns)
if err != nil {
base.Fatalf("go mod vendor: %v", err)
base.Fatalf("go: %v", err)
}
for _, embed := range embeds {
embedDst := filepath.Join(dst, embed)
@ -260,21 +276,21 @@ func vendorPkg(vdir, pkg string) {
// Copy the file as is done by copyDir below.
r, err := os.Open(filepath.Join(src, embed))
if err != nil {
base.Fatalf("go mod vendor: %v", err)
base.Fatalf("go: %v", err)
}
if err := os.MkdirAll(filepath.Dir(embedDst), 0777); err != nil {
base.Fatalf("go mod vendor: %v", err)
base.Fatalf("go: %v", err)
}
w, err := os.Create(embedDst)
if err != nil {
base.Fatalf("go mod vendor: %v", err)
base.Fatalf("go: %v", err)
}
if _, err := io.Copy(w, r); err != nil {
base.Fatalf("go mod vendor: %v", err)
base.Fatalf("go: %v", err)
}
r.Close()
if err := w.Close(); err != nil {
base.Fatalf("go mod vendor: %v", err)
base.Fatalf("go: %v", err)
}
}
}
@ -353,7 +369,7 @@ func matchPotentialSourceFile(dir string, info fs.DirEntry) bool {
if strings.HasSuffix(info.Name(), ".go") {
f, err := fsys.Open(filepath.Join(dir, info.Name()))
if err != nil {
base.Fatalf("go mod vendor: %v", err)
base.Fatalf("go: %v", err)
}
defer f.Close()
@ -375,10 +391,10 @@ func matchPotentialSourceFile(dir string, info fs.DirEntry) bool {
func copyDir(dst, src string, match func(dir string, info fs.DirEntry) bool, copiedFiles map[string]bool) {
files, err := os.ReadDir(src)
if err != nil {
base.Fatalf("go mod vendor: %v", err)
base.Fatalf("go: %v", err)
}
if err := os.MkdirAll(dst, 0777); err != nil {
base.Fatalf("go mod vendor: %v", err)
base.Fatalf("go: %v", err)
}
for _, file := range files {
if file.IsDir() || !file.Type().IsRegular() || !match(src, file) {
@ -387,20 +403,20 @@ func copyDir(dst, src string, match func(dir string, info fs.DirEntry) bool, cop
copiedFiles[file.Name()] = true
r, err := os.Open(filepath.Join(src, file.Name()))
if err != nil {
base.Fatalf("go mod vendor: %v", err)
base.Fatalf("go: %v", err)
}
dstPath := filepath.Join(dst, file.Name())
copiedFiles[dstPath] = true
w, err := os.Create(dstPath)
if err != nil {
base.Fatalf("go mod vendor: %v", err)
base.Fatalf("go: %v", err)
}
if _, err := io.Copy(w, r); err != nil {
base.Fatalf("go mod vendor: %v", err)
base.Fatalf("go: %v", err)
}
r.Close()
if err := w.Close(); err != nil {
base.Fatalf("go mod vendor: %v", err)
base.Fatalf("go: %v", err)
}
}
}

View File

@ -39,12 +39,15 @@ See https://golang.org/ref/mod#go-mod-verify for more about 'go mod verify'.
func init() {
base.AddModCommonFlags(&cmdVerify.Flag)
base.AddWorkfileFlag(&cmdVerify.Flag)
}
func runVerify(ctx context.Context, cmd *base.Command, args []string) {
modload.InitWorkfile()
if len(args) != 0 {
// NOTE(rsc): Could take a module pattern.
base.Fatalf("go mod verify: verify takes no arguments")
base.Fatalf("go: verify takes no arguments")
}
modload.ForceUseModules = true
modload.RootMode = modload.NeedRoot

View File

@ -12,8 +12,6 @@ import (
"cmd/go/internal/base"
"cmd/go/internal/imports"
"cmd/go/internal/modload"
"golang.org/x/mod/module"
)
var cmdWhy = &base.Command{
@ -61,11 +59,14 @@ var (
func init() {
cmdWhy.Run = runWhy // break init cycle
base.AddModCommonFlags(&cmdWhy.Flag)
base.AddWorkfileFlag(&cmdWhy.Flag)
}
func runWhy(ctx context.Context, cmd *base.Command, args []string) {
modload.InitWorkfile()
modload.ForceUseModules = true
modload.RootMode = modload.NeedRoot
modload.ExplicitWriteGoMod = true // don't write go.mod in ListModules
loadOpts := modload.PackageOpts{
Tags: imports.AnyTags(),
@ -78,28 +79,28 @@ func runWhy(ctx context.Context, cmd *base.Command, args []string) {
if *whyM {
for _, arg := range args {
if strings.Contains(arg, "@") {
base.Fatalf("go mod why: module query not allowed")
base.Fatalf("go: %s: 'go mod why' requires a module path, not a version query", arg)
}
}
mods, err := modload.ListModules(ctx, args, 0)
if err != nil {
base.Fatalf("go mod why: %v", err)
base.Fatalf("go: %v", err)
}
byModule := make(map[module.Version][]string)
byModule := make(map[string][]string)
_, pkgs := modload.LoadPackages(ctx, loadOpts, "all")
for _, path := range pkgs {
m := modload.PackageModule(path)
if m.Path != "" {
byModule[m] = append(byModule[m], path)
byModule[m.Path] = append(byModule[m.Path], path)
}
}
sep := ""
for _, m := range mods {
best := ""
bestDepth := 1000000000
for _, path := range byModule[module.Version{Path: m.Path, Version: m.Version}] {
for _, path := range byModule[m.Path] {
d := modload.WhyDepth(path)
if d > 0 && d < bestDepth {
best = path

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
//go:build cmd_go_bootstrap
// +build cmd_go_bootstrap
package modfetch

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