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
This commit is contained in:
parent
9a56779dbc
commit
8dc2499aa6
1980 changed files with 84424 additions and 36492 deletions
|
@ -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.
|
||||
|
|
|
@ -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)`; \
|
||||
|
|
|
@ -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)`; \
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1 +1 @@
|
|||
go1.17.1
|
||||
go1.18beta2
|
||||
|
|
|
@ -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
13
libgo/configure
vendored
|
@ -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 :
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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] }
|
||||
|
|
80
libgo/go/archive/tar/fuzz_test.go
Normal file
80
libgo/go/archive/tar/fuzz_test.go
Normal 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.
|
||||
})
|
||||
}
|
|
@ -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{}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build darwin || freebsd || netbsd
|
||||
// +build darwin freebsd netbsd
|
||||
|
||||
package tar
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
81
libgo/go/archive/zip/fuzz_test.go
Normal file
81
libgo/go/archive/zip/fuzz_test.go
Normal 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.
|
||||
})
|
||||
}
|
|
@ -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]
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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:])
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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} {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
17
libgo/go/cmd/cgo/ast_go1.go
Normal file
17
libgo/go/cmd/cgo/ast_go1.go
Normal 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")
|
||||
}
|
25
libgo/go/cmd/cgo/ast_go118.go
Normal file
25
libgo/go/cmd/cgo/ast_go118.go
Normal 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)
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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.
|
||||
//
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build go1.1
|
||||
// +build go1.1
|
||||
|
||||
package main
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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, " "))
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build plan9 || windows
|
||||
// +build plan9 windows
|
||||
|
||||
package base
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
12
libgo/go/cmd/go/internal/cache/cache.go
vendored
12
libgo/go/cmd/go/internal/cache/cache.go
vendored
|
@ -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")
|
||||
}
|
||||
|
|
1
libgo/go/cmd/go/internal/cache/default.go
vendored
1
libgo/go/cmd/go/internal/cache/default.go
vendored
|
@ -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.
|
||||
`
|
||||
|
||||
|
|
|
@ -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 ""
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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...)
|
||||
}
|
||||
|
||||
|
|
|
@ -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>]
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
//go:build android
|
||||
// +build android
|
||||
|
||||
package android
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package android
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
//go:build !android
|
||||
// +build !android
|
||||
|
||||
package android
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
//go:build illumos
|
||||
// +build illumos
|
||||
|
||||
package illumos
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
//go:build solaris
|
||||
// +build solaris
|
||||
|
||||
package illumos
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
//go:build !illumos
|
||||
// +build !illumos
|
||||
|
||||
package illumos
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build plan9
|
||||
// +build plan9
|
||||
|
||||
package filelock
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !js && !plan9
|
||||
// +build !js,!plan9
|
||||
|
||||
package filelock_test
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package filelock
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !plan9
|
||||
// +build !plan9
|
||||
|
||||
package lockedfile
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build plan9
|
||||
// +build plan9
|
||||
|
||||
package lockedfile
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
// js does not support inter-process file locking.
|
||||
//go:build !js
|
||||
// +build !js
|
||||
|
||||
package lockedfile_test
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
// js does not support inter-process file locking.
|
||||
//go:build !js
|
||||
// +build !js
|
||||
|
||||
package lockedfile_test
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
Loading…
Add table
Reference in a new issue