mirror of git://gcc.gnu.org/git/gcc.git
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
|
|
@ -1,4 +1,4 @@
|
||||||
b0dcd2d1e5e73952408b9f2d4d86ae12d102b20c
|
47380f733ca932384e59492d2f04374edd8ec95e
|
||||||
|
|
||||||
The first line of this file holds the git revision number of the last
|
The first line of this file holds the git revision number of the last
|
||||||
merge done from the gofrontend repository.
|
merge done from the gofrontend repository.
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ go_cmd_gofmt_files = \
|
||||||
|
|
||||||
go_cmd_cgo_files = \
|
go_cmd_cgo_files = \
|
||||||
$(cmdsrcdir)/cgo/ast.go \
|
$(cmdsrcdir)/cgo/ast.go \
|
||||||
|
$(cmdsrcdir)/cgo/ast_go118.go \
|
||||||
$(cmdsrcdir)/cgo/doc.go \
|
$(cmdsrcdir)/cgo/doc.go \
|
||||||
$(cmdsrcdir)/cgo/gcc.go \
|
$(cmdsrcdir)/cgo/gcc.go \
|
||||||
$(cmdsrcdir)/cgo/godefs.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/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/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/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/
|
cp $(libgodir)/objabi.go check-go-dir/src/cmd/internal/objabi/
|
||||||
@abs_libgodir=`cd $(libgodir) && $(PWD_COMMAND)`; \
|
@abs_libgodir=`cd $(libgodir) && $(PWD_COMMAND)`; \
|
||||||
abs_checkdir=`cd check-go-dir && $(PWD_COMMAND)`; \
|
abs_checkdir=`cd check-go-dir && $(PWD_COMMAND)`; \
|
||||||
|
|
|
||||||
|
|
@ -366,6 +366,7 @@ go_cmd_gofmt_files = \
|
||||||
|
|
||||||
go_cmd_cgo_files = \
|
go_cmd_cgo_files = \
|
||||||
$(cmdsrcdir)/cgo/ast.go \
|
$(cmdsrcdir)/cgo/ast.go \
|
||||||
|
$(cmdsrcdir)/cgo/ast_go118.go \
|
||||||
$(cmdsrcdir)/cgo/doc.go \
|
$(cmdsrcdir)/cgo/doc.go \
|
||||||
$(cmdsrcdir)/cgo/gcc.go \
|
$(cmdsrcdir)/cgo/gcc.go \
|
||||||
$(cmdsrcdir)/cgo/godefs.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/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/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/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@ cp $(libgodir)/objabi.go check-go-dir/src/cmd/internal/objabi/
|
||||||
@NATIVE_TRUE@ @abs_libgodir=`cd $(libgodir) && $(PWD_COMMAND)`; \
|
@NATIVE_TRUE@ @abs_libgodir=`cd $(libgodir) && $(PWD_COMMAND)`; \
|
||||||
@NATIVE_TRUE@ abs_checkdir=`cd check-go-dir && $(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
|
The first line of this file holds the git revision number of the
|
||||||
last merge done from the master library sources.
|
last merge done from the master library sources.
|
||||||
|
|
|
||||||
|
|
@ -220,6 +220,7 @@ toolexeclibgodatabasesql_DATA = \
|
||||||
toolexeclibgodebugdir = $(toolexeclibgodir)/debug
|
toolexeclibgodebugdir = $(toolexeclibgodir)/debug
|
||||||
|
|
||||||
toolexeclibgodebug_DATA = \
|
toolexeclibgodebug_DATA = \
|
||||||
|
debug/buildinfo.gox \
|
||||||
debug/dwarf.gox \
|
debug/dwarf.gox \
|
||||||
debug/elf.gox \
|
debug/elf.gox \
|
||||||
debug/gosym.gox \
|
debug/gosym.gox \
|
||||||
|
|
@ -325,6 +326,7 @@ toolexeclibgonetdir = $(toolexeclibgodir)/net
|
||||||
toolexeclibgonet_DATA = \
|
toolexeclibgonet_DATA = \
|
||||||
net/http.gox \
|
net/http.gox \
|
||||||
net/mail.gox \
|
net/mail.gox \
|
||||||
|
net/netip.gox \
|
||||||
net/rpc.gox \
|
net/rpc.gox \
|
||||||
net/smtp.gox \
|
net/smtp.gox \
|
||||||
net/textproto.gox \
|
net/textproto.gox \
|
||||||
|
|
@ -429,6 +431,7 @@ noinst_DATA = \
|
||||||
internal/testenv.gox \
|
internal/testenv.gox \
|
||||||
internal/trace.gox \
|
internal/trace.gox \
|
||||||
net/internal/socktest.gox \
|
net/internal/socktest.gox \
|
||||||
|
os/exec/internal/fdtest.gox \
|
||||||
os/signal/internal/pty.gox \
|
os/signal/internal/pty.gox \
|
||||||
reflect/internal/example1.gox \
|
reflect/internal/example1.gox \
|
||||||
reflect/internal/example2.gox
|
reflect/internal/example2.gox
|
||||||
|
|
@ -483,53 +486,68 @@ version.go: s-version; @true
|
||||||
s-version: Makefile
|
s-version: Makefile
|
||||||
rm -f version.go.tmp
|
rm -f version.go.tmp
|
||||||
echo "package sys" > 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 GccgoToolDir = "$(libexecsubdir)"' >> version.go.tmp
|
||||||
echo 'const StackGuardMultiplierDefault = 1' >> version.go.tmp
|
echo 'const StackGuardMultiplierDefault = 1' >> version.go.tmp
|
||||||
echo >> version.go.tmp
|
$(SHELL) $(srcdir)/mvifdiff.sh version.go.tmp version.go
|
||||||
echo "const (" >> version.go.tmp
|
$(STAMP) $@
|
||||||
echo " UNKNOWN ArchFamilyType = iota" >> version.go.tmp
|
|
||||||
|
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 \
|
for a in $(ALLGOARCHFAMILY); do \
|
||||||
echo " $${a}" >> version.go.tmp; \
|
echo " $${a}" >> zgoarch.go.tmp; \
|
||||||
done
|
done
|
||||||
echo ")" >> version.go.tmp
|
echo ")" >> zgoarch.go.tmp
|
||||||
echo >> version.go.tmp
|
echo >> zgoarch.go.tmp
|
||||||
for a in $(ALLGOARCH); do \
|
for a in $(ALLGOARCH); do \
|
||||||
f=`echo $${a} | sed -e 's/\(.\).*/\1/' -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`; \
|
f=`echo $${a} | sed -e 's/\(.\).*/\1/' -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`; \
|
||||||
n="$${f}`echo $${a} | sed -e 's/.//'`"; \
|
n="$${f}`echo $${a} | sed -e 's/.//'`"; \
|
||||||
if test "$${a}" = "$(GOARCH)"; then \
|
if test "$${a}" = "$(GOARCH)"; then \
|
||||||
echo "const Goarch$${n} = 1" >> version.go.tmp; \
|
echo "const Is$${n} = 1" >> zgoarch.go.tmp; \
|
||||||
else \
|
else \
|
||||||
echo "const Goarch$${n} = 0" >> version.go.tmp; \
|
echo "const Is$${n} = 0" >> zgoarch.go.tmp; \
|
||||||
fi; \
|
fi; \
|
||||||
done
|
done
|
||||||
echo >> version.go.tmp
|
$(SHELL) $(srcdir)/mvifdiff.sh zgoarch.go.tmp zgoarch.go
|
||||||
echo "const (" >> version.go.tmp
|
$(STAMP) $@
|
||||||
echo " _ArchFamily = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) family`" >> version.go.tmp
|
|
||||||
echo " _BigEndian = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) bigendian`" >> version.go.tmp
|
zgoos.go: s-zgoos; @true
|
||||||
echo " _DefaultPhysPageSize = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) defaultphyspagesize`" >> version.go.tmp
|
s-zgoos: Makefile
|
||||||
echo " _Int64Align = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) int64align`" >> version.go.tmp
|
rm -f zgoos.go.tmp
|
||||||
echo " _MinFrameSize = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) minframesize`" >> version.go.tmp
|
echo "package goos" > zgoos.go.tmp
|
||||||
echo " _PCQuantum = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) pcquantum`" >> version.go.tmp
|
echo >> zgoos.go.tmp
|
||||||
echo " _StackAlign = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) stackalign`" >> version.go.tmp
|
echo 'const GOOS = "'$(GOOS)'"' >> zgoos.go.tmp
|
||||||
echo ")" >> version.go.tmp
|
echo >> zgoos.go.tmp
|
||||||
echo >> version.go.tmp
|
|
||||||
for a in $(ALLGOOS); do \
|
for a in $(ALLGOOS); do \
|
||||||
f=`echo $${a} | sed -e 's/\(.\).*/\1/' -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`; \
|
f=`echo $${a} | sed -e 's/\(.\).*/\1/' -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`; \
|
||||||
n="$${f}`echo $${a} | sed -e 's/.//'`"; \
|
n="$${f}`echo $${a} | sed -e 's/.//'`"; \
|
||||||
if test "$${a}" = "$(GOOS)"; then \
|
if test "$${a}" = "$(GOOS)"; then \
|
||||||
echo "const Goos$${n} = 1" >> version.go.tmp; \
|
echo "const Is$${n} = 1" >> zgoos.go.tmp; \
|
||||||
else \
|
else \
|
||||||
echo "const Goos$${n} = 0" >> version.go.tmp; \
|
echo "const Is$${n} = 0" >> zgoos.go.tmp; \
|
||||||
fi; \
|
fi; \
|
||||||
done
|
done
|
||||||
echo >> version.go.tmp
|
$(SHELL) $(srcdir)/mvifdiff.sh zgoos.go.tmp zgoos.go
|
||||||
$(SHELL) $(srcdir)/mvifdiff.sh version.go.tmp version.go
|
|
||||||
$(STAMP) $@
|
$(STAMP) $@
|
||||||
|
|
||||||
cpugen.go: s-cpu; @true
|
cpugen.go: s-cpu; @true
|
||||||
s-cpu: Makefile
|
s-cpu: Makefile goarch.sh
|
||||||
rm -f cpugen.go.tmp
|
rm -f cpugen.go.tmp
|
||||||
echo "package cpu" > cpugen.go.tmp
|
echo "package cpu" > cpugen.go.tmp
|
||||||
echo "const CacheLinePadSize = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) cachelinesize`" >> cpugen.go.tmp
|
echo "const CacheLinePadSize = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) cachelinesize`" >> cpugen.go.tmp
|
||||||
|
|
@ -538,7 +556,7 @@ s-cpu: Makefile
|
||||||
$(STAMP) $@
|
$(STAMP) $@
|
||||||
|
|
||||||
gcpugen.go: s-gcpu; @true
|
gcpugen.go: s-gcpu; @true
|
||||||
s-gcpu: Makefile
|
s-gcpu: Makefile goarch.sh
|
||||||
rm -f gcpugen.go.tmp
|
rm -f gcpugen.go.tmp
|
||||||
echo "package cpu" > gcpugen.go.tmp
|
echo "package cpu" > gcpugen.go.tmp
|
||||||
echo "const cacheLineSize = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) cachelinesize`" >> 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 "import \"runtime\"" >> buildcfg.go.tmp
|
||||||
echo 'func defaultGOROOTValue() string { return `$(prefix)` }' >> buildcfg.go.tmp
|
echo 'func defaultGOROOTValue() string { return `$(prefix)` }' >> buildcfg.go.tmp
|
||||||
echo 'const defaultGO386 = `sse2`' >> 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 defaultGOARM = `5`' >> buildcfg.go.tmp
|
||||||
echo 'const defaultGOMIPS = `hardfloat`' >> buildcfg.go.tmp
|
echo 'const defaultGOMIPS = `hardfloat`' >> buildcfg.go.tmp
|
||||||
echo 'const defaultGOMIPS64 = `hardfloat`' >> buildcfg.go.tmp
|
echo 'const defaultGOMIPS64 = `hardfloat`' >> buildcfg.go.tmp
|
||||||
|
|
@ -813,7 +832,8 @@ libgo_ldflags = \
|
||||||
|
|
||||||
libgo_libadd = \
|
libgo_libadd = \
|
||||||
$(libgo_go_objs) ../libbacktrace/libbacktrace.la \
|
$(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_SOURCES = $(runtime_files)
|
||||||
libgo_la_LDFLAGS = $(libgo_ldflags)
|
libgo_la_LDFLAGS = $(libgo_ldflags)
|
||||||
|
|
@ -904,7 +924,7 @@ GOBENCH =
|
||||||
CHECK = \
|
CHECK = \
|
||||||
GC="$(GOC) $(GOCFLAGS) $($(subst /,_,$@)_GOCFLAGS) -L `${PWD_COMMAND}` -L `${PWD_COMMAND}`/.libs"; \
|
GC="$(GOC) $(GOCFLAGS) $($(subst /,_,$@)_GOCFLAGS) -L `${PWD_COMMAND}` -L `${PWD_COMMAND}`/.libs"; \
|
||||||
export GC; \
|
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; \
|
export GOLIBS; \
|
||||||
RUNTESTFLAGS="$(RUNTESTFLAGS)"; \
|
RUNTESTFLAGS="$(RUNTESTFLAGS)"; \
|
||||||
export 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
|
extra_go_files_internal_cpu = cpugen.go
|
||||||
internal/cpu.lo.dep: $(extra_go_files_internal_cpu)
|
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
|
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)
|
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) \
|
am__DEPENDENCIES_5 = $(am__DEPENDENCIES_3) \
|
||||||
../libbacktrace/libbacktrace.la $(am__DEPENDENCIES_4) \
|
../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) $(am__DEPENDENCIES_4) \
|
||||||
|
$(am__DEPENDENCIES_4)
|
||||||
libgo_llgo_la_DEPENDENCIES = $(am__DEPENDENCIES_5)
|
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@am__objects_1 = \
|
||||||
@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_X86_TRUE@ runtime/go-context.lo
|
@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_CFLAGS = @PTHREAD_CFLAGS@
|
||||||
PTHREAD_LIBS = @PTHREAD_LIBS@
|
PTHREAD_LIBS = @PTHREAD_LIBS@
|
||||||
RANLIB = @RANLIB@
|
RANLIB = @RANLIB@
|
||||||
|
RT_LIBS = @RT_LIBS@
|
||||||
SED = @SED@
|
SED = @SED@
|
||||||
SET_MAKE = @SET_MAKE@
|
SET_MAKE = @SET_MAKE@
|
||||||
SHELL = @SHELL@
|
SHELL = @SHELL@
|
||||||
|
|
@ -712,6 +714,7 @@ toolexeclibgodatabasesql_DATA = \
|
||||||
|
|
||||||
toolexeclibgodebugdir = $(toolexeclibgodir)/debug
|
toolexeclibgodebugdir = $(toolexeclibgodir)/debug
|
||||||
toolexeclibgodebug_DATA = \
|
toolexeclibgodebug_DATA = \
|
||||||
|
debug/buildinfo.gox \
|
||||||
debug/dwarf.gox \
|
debug/dwarf.gox \
|
||||||
debug/elf.gox \
|
debug/elf.gox \
|
||||||
debug/gosym.gox \
|
debug/gosym.gox \
|
||||||
|
|
@ -804,6 +807,7 @@ toolexeclibgonetdir = $(toolexeclibgodir)/net
|
||||||
toolexeclibgonet_DATA = \
|
toolexeclibgonet_DATA = \
|
||||||
net/http.gox \
|
net/http.gox \
|
||||||
net/mail.gox \
|
net/mail.gox \
|
||||||
|
net/netip.gox \
|
||||||
net/rpc.gox \
|
net/rpc.gox \
|
||||||
net/smtp.gox \
|
net/smtp.gox \
|
||||||
net/textproto.gox \
|
net/textproto.gox \
|
||||||
|
|
@ -892,9 +896,9 @@ toolexeclibgointernal_DATA = \
|
||||||
noinst_DATA = golang.org/x/net/nettest.gox internal/cfg.gox \
|
noinst_DATA = golang.org/x/net/nettest.gox internal/cfg.gox \
|
||||||
internal/obscuretestdata.gox internal/profile.gox \
|
internal/obscuretestdata.gox internal/profile.gox \
|
||||||
internal/testenv.gox internal/trace.gox \
|
internal/testenv.gox internal/trace.gox \
|
||||||
net/internal/socktest.gox os/signal/internal/pty.gox \
|
net/internal/socktest.gox os/exec/internal/fdtest.gox \
|
||||||
reflect/internal/example1.gox reflect/internal/example2.gox \
|
os/signal/internal/pty.gox reflect/internal/example1.gox \
|
||||||
zdefaultcc.go
|
reflect/internal/example2.gox zdefaultcc.go
|
||||||
@LIBGO_IS_RTEMS_FALSE@rtems_task_variable_add_file =
|
@LIBGO_IS_RTEMS_FALSE@rtems_task_variable_add_file =
|
||||||
@LIBGO_IS_RTEMS_TRUE@rtems_task_variable_add_file = runtime/rtems-task-variable-add.c
|
@LIBGO_IS_RTEMS_TRUE@rtems_task_variable_add_file = runtime/rtems-task-variable-add.c
|
||||||
runtime_context_asm_file = $(am__append_3)
|
runtime_context_asm_file = $(am__append_3)
|
||||||
|
|
@ -968,7 +972,8 @@ libgo_ldflags = \
|
||||||
|
|
||||||
libgo_libadd = \
|
libgo_libadd = \
|
||||||
$(libgo_go_objs) ../libbacktrace/libbacktrace.la \
|
$(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_SOURCES = $(runtime_files)
|
||||||
libgo_la_LDFLAGS = $(libgo_ldflags)
|
libgo_la_LDFLAGS = $(libgo_ldflags)
|
||||||
|
|
@ -1042,7 +1047,7 @@ GOBENCH =
|
||||||
CHECK = \
|
CHECK = \
|
||||||
GC="$(GOC) $(GOCFLAGS) $($(subst /,_,$@)_GOCFLAGS) -L `${PWD_COMMAND}` -L `${PWD_COMMAND}`/.libs"; \
|
GC="$(GOC) $(GOCFLAGS) $($(subst /,_,$@)_GOCFLAGS) -L `${PWD_COMMAND}` -L `${PWD_COMMAND}`/.libs"; \
|
||||||
export GC; \
|
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; \
|
export GOLIBS; \
|
||||||
RUNTESTFLAGS="$(RUNTESTFLAGS)"; \
|
RUNTESTFLAGS="$(RUNTESTFLAGS)"; \
|
||||||
export RUNTESTFLAGS; \
|
export RUNTESTFLAGS; \
|
||||||
|
|
@ -1138,6 +1143,8 @@ runtime_pprof_check_GOCFLAGS = -static-libgo -fno-inline
|
||||||
@HAVE_STATIC_LINK_TRUE@syscall_check_GOCFLAGS = -static
|
@HAVE_STATIC_LINK_TRUE@syscall_check_GOCFLAGS = -static
|
||||||
extra_go_files_runtime_internal_sys = version.go
|
extra_go_files_runtime_internal_sys = version.go
|
||||||
extra_go_files_internal_cpu = cpugen.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_golang_org_x_sys_cpu = gcpugen.go
|
||||||
extra_go_files_internal_buildcfg = buildcfg.go
|
extra_go_files_internal_buildcfg = buildcfg.go
|
||||||
extra_go_files_internal_goroot = zstdpkglist.go
|
extra_go_files_internal_goroot = zstdpkglist.go
|
||||||
|
|
@ -2692,53 +2699,68 @@ version.go: s-version; @true
|
||||||
s-version: Makefile
|
s-version: Makefile
|
||||||
rm -f version.go.tmp
|
rm -f version.go.tmp
|
||||||
echo "package sys" > 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 GccgoToolDir = "$(libexecsubdir)"' >> version.go.tmp
|
||||||
echo 'const StackGuardMultiplierDefault = 1' >> version.go.tmp
|
echo 'const StackGuardMultiplierDefault = 1' >> version.go.tmp
|
||||||
echo >> version.go.tmp
|
$(SHELL) $(srcdir)/mvifdiff.sh version.go.tmp version.go
|
||||||
echo "const (" >> version.go.tmp
|
$(STAMP) $@
|
||||||
echo " UNKNOWN ArchFamilyType = iota" >> version.go.tmp
|
|
||||||
|
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 \
|
for a in $(ALLGOARCHFAMILY); do \
|
||||||
echo " $${a}" >> version.go.tmp; \
|
echo " $${a}" >> zgoarch.go.tmp; \
|
||||||
done
|
done
|
||||||
echo ")" >> version.go.tmp
|
echo ")" >> zgoarch.go.tmp
|
||||||
echo >> version.go.tmp
|
echo >> zgoarch.go.tmp
|
||||||
for a in $(ALLGOARCH); do \
|
for a in $(ALLGOARCH); do \
|
||||||
f=`echo $${a} | sed -e 's/\(.\).*/\1/' -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`; \
|
f=`echo $${a} | sed -e 's/\(.\).*/\1/' -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`; \
|
||||||
n="$${f}`echo $${a} | sed -e 's/.//'`"; \
|
n="$${f}`echo $${a} | sed -e 's/.//'`"; \
|
||||||
if test "$${a}" = "$(GOARCH)"; then \
|
if test "$${a}" = "$(GOARCH)"; then \
|
||||||
echo "const Goarch$${n} = 1" >> version.go.tmp; \
|
echo "const Is$${n} = 1" >> zgoarch.go.tmp; \
|
||||||
else \
|
else \
|
||||||
echo "const Goarch$${n} = 0" >> version.go.tmp; \
|
echo "const Is$${n} = 0" >> zgoarch.go.tmp; \
|
||||||
fi; \
|
fi; \
|
||||||
done
|
done
|
||||||
echo >> version.go.tmp
|
$(SHELL) $(srcdir)/mvifdiff.sh zgoarch.go.tmp zgoarch.go
|
||||||
echo "const (" >> version.go.tmp
|
$(STAMP) $@
|
||||||
echo " _ArchFamily = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) family`" >> version.go.tmp
|
|
||||||
echo " _BigEndian = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) bigendian`" >> version.go.tmp
|
zgoos.go: s-zgoos; @true
|
||||||
echo " _DefaultPhysPageSize = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) defaultphyspagesize`" >> version.go.tmp
|
s-zgoos: Makefile
|
||||||
echo " _Int64Align = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) int64align`" >> version.go.tmp
|
rm -f zgoos.go.tmp
|
||||||
echo " _MinFrameSize = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) minframesize`" >> version.go.tmp
|
echo "package goos" > zgoos.go.tmp
|
||||||
echo " _PCQuantum = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) pcquantum`" >> version.go.tmp
|
echo >> zgoos.go.tmp
|
||||||
echo " _StackAlign = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) stackalign`" >> version.go.tmp
|
echo 'const GOOS = "'$(GOOS)'"' >> zgoos.go.tmp
|
||||||
echo ")" >> version.go.tmp
|
echo >> zgoos.go.tmp
|
||||||
echo >> version.go.tmp
|
|
||||||
for a in $(ALLGOOS); do \
|
for a in $(ALLGOOS); do \
|
||||||
f=`echo $${a} | sed -e 's/\(.\).*/\1/' -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`; \
|
f=`echo $${a} | sed -e 's/\(.\).*/\1/' -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`; \
|
||||||
n="$${f}`echo $${a} | sed -e 's/.//'`"; \
|
n="$${f}`echo $${a} | sed -e 's/.//'`"; \
|
||||||
if test "$${a}" = "$(GOOS)"; then \
|
if test "$${a}" = "$(GOOS)"; then \
|
||||||
echo "const Goos$${n} = 1" >> version.go.tmp; \
|
echo "const Is$${n} = 1" >> zgoos.go.tmp; \
|
||||||
else \
|
else \
|
||||||
echo "const Goos$${n} = 0" >> version.go.tmp; \
|
echo "const Is$${n} = 0" >> zgoos.go.tmp; \
|
||||||
fi; \
|
fi; \
|
||||||
done
|
done
|
||||||
echo >> version.go.tmp
|
$(SHELL) $(srcdir)/mvifdiff.sh zgoos.go.tmp zgoos.go
|
||||||
$(SHELL) $(srcdir)/mvifdiff.sh version.go.tmp version.go
|
|
||||||
$(STAMP) $@
|
$(STAMP) $@
|
||||||
|
|
||||||
cpugen.go: s-cpu; @true
|
cpugen.go: s-cpu; @true
|
||||||
s-cpu: Makefile
|
s-cpu: Makefile goarch.sh
|
||||||
rm -f cpugen.go.tmp
|
rm -f cpugen.go.tmp
|
||||||
echo "package cpu" > cpugen.go.tmp
|
echo "package cpu" > cpugen.go.tmp
|
||||||
echo "const CacheLinePadSize = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) cachelinesize`" >> cpugen.go.tmp
|
echo "const CacheLinePadSize = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) cachelinesize`" >> cpugen.go.tmp
|
||||||
|
|
@ -2747,7 +2769,7 @@ s-cpu: Makefile
|
||||||
$(STAMP) $@
|
$(STAMP) $@
|
||||||
|
|
||||||
gcpugen.go: s-gcpu; @true
|
gcpugen.go: s-gcpu; @true
|
||||||
s-gcpu: Makefile
|
s-gcpu: Makefile goarch.sh
|
||||||
rm -f gcpugen.go.tmp
|
rm -f gcpugen.go.tmp
|
||||||
echo "package cpu" > gcpugen.go.tmp
|
echo "package cpu" > gcpugen.go.tmp
|
||||||
echo "const cacheLineSize = `$(SHELL) $(srcdir)/goarch.sh $(GOARCH) cachelinesize`" >> 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 "import \"runtime\"" >> buildcfg.go.tmp
|
||||||
echo 'func defaultGOROOTValue() string { return `$(prefix)` }' >> buildcfg.go.tmp
|
echo 'func defaultGOROOTValue() string { return `$(prefix)` }' >> buildcfg.go.tmp
|
||||||
echo 'const defaultGO386 = `sse2`' >> 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 defaultGOARM = `5`' >> buildcfg.go.tmp
|
||||||
echo 'const defaultGOMIPS = `hardfloat`' >> buildcfg.go.tmp
|
echo 'const defaultGOMIPS = `hardfloat`' >> buildcfg.go.tmp
|
||||||
echo 'const defaultGOMIPS64 = `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)
|
syscall.lo.dep: $(extra_go_files_syscall)
|
||||||
runtime/internal/sys.lo.dep: $(extra_go_files_runtime_internal_sys)
|
runtime/internal/sys.lo.dep: $(extra_go_files_runtime_internal_sys)
|
||||||
internal/cpu.lo.dep: $(extra_go_files_internal_cpu)
|
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)
|
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)
|
cmd/internal/buildcfg.lo.dep: $(extra_go_files_internal_buildcfg)
|
||||||
internal/goroot.lo.dep: $(extra_go_files_internal_goroot)
|
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/search
|
||||||
cmd/go/internal/str
|
cmd/go/internal/str
|
||||||
cmd/go/internal/test
|
cmd/go/internal/test
|
||||||
cmd/go/internal/txtar
|
|
||||||
cmd/go/internal/vcs
|
cmd/go/internal/vcs
|
||||||
cmd/go/internal/work
|
cmd/go/internal/work
|
||||||
cmd/internal/buildid
|
cmd/internal/buildid
|
||||||
cmd/internal/edit
|
cmd/internal/edit
|
||||||
cmd/internal/objabi
|
cmd/internal/objabi
|
||||||
cmd/internal/pkgpath
|
cmd/internal/pkgpath
|
||||||
|
cmd/internal/quoted
|
||||||
cmd/internal/test2json
|
cmd/internal/test2json
|
||||||
compress/bzip2
|
compress/bzip2
|
||||||
compress/flate
|
compress/flate
|
||||||
|
|
@ -46,7 +46,7 @@ crypto/ed25519
|
||||||
crypto/ed25519/internal/edwards25519
|
crypto/ed25519/internal/edwards25519
|
||||||
crypto/ed25519/internal/edwards25519/field
|
crypto/ed25519/internal/edwards25519/field
|
||||||
crypto/elliptic
|
crypto/elliptic
|
||||||
crypto/elliptic/internal/fiat
|
crypto/elliptic/internal/nistec
|
||||||
crypto/hmac
|
crypto/hmac
|
||||||
crypto/internal/subtle
|
crypto/internal/subtle
|
||||||
crypto/md5
|
crypto/md5
|
||||||
|
|
@ -61,6 +61,7 @@ crypto/tls
|
||||||
crypto/x509
|
crypto/x509
|
||||||
database/sql
|
database/sql
|
||||||
database/sql/driver
|
database/sql/driver
|
||||||
|
debug/buildinfo
|
||||||
debug/dwarf
|
debug/dwarf
|
||||||
debug/elf
|
debug/elf
|
||||||
debug/macho
|
debug/macho
|
||||||
|
|
@ -110,9 +111,13 @@ image/draw
|
||||||
image/jpeg
|
image/jpeg
|
||||||
image/png
|
image/png
|
||||||
index/suffixarray
|
index/suffixarray
|
||||||
|
internal/buildcfg
|
||||||
internal/cpu
|
internal/cpu
|
||||||
internal/execabs
|
internal/execabs
|
||||||
internal/fmtsort
|
internal/fmtsort
|
||||||
|
internal/fuzz
|
||||||
|
internal/godebug
|
||||||
|
internal/intern
|
||||||
internal/itoa
|
internal/itoa
|
||||||
internal/poll
|
internal/poll
|
||||||
internal/profile
|
internal/profile
|
||||||
|
|
@ -147,6 +152,7 @@ net/http/internal/ascii
|
||||||
net/http/pprof
|
net/http/pprof
|
||||||
net/internal/socktest
|
net/internal/socktest
|
||||||
net/mail
|
net/mail
|
||||||
|
net/netip
|
||||||
net/rpc
|
net/rpc
|
||||||
net/rpc/jsonrpc
|
net/rpc/jsonrpc
|
||||||
net/smtp
|
net/smtp
|
||||||
|
|
|
||||||
|
|
@ -649,6 +649,7 @@ HAVE_SYS_MMAN_H_FALSE
|
||||||
HAVE_SYS_MMAN_H_TRUE
|
HAVE_SYS_MMAN_H_TRUE
|
||||||
PTHREAD_LIBS
|
PTHREAD_LIBS
|
||||||
PTHREAD_CFLAGS
|
PTHREAD_CFLAGS
|
||||||
|
RT_LIBS
|
||||||
NET_LIBS
|
NET_LIBS
|
||||||
MATH_LIBS
|
MATH_LIBS
|
||||||
GOC_IS_LLGO_FALSE
|
GOC_IS_LLGO_FALSE
|
||||||
|
|
@ -2608,7 +2609,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
|
||||||
ac_config_headers="$ac_config_headers config.h"
|
ac_config_headers="$ac_config_headers config.h"
|
||||||
|
|
||||||
|
|
||||||
libtool_VERSION=20:0:0
|
libtool_VERSION=21:0:0
|
||||||
|
|
||||||
|
|
||||||
# Default to --enable-multilib
|
# Default to --enable-multilib
|
||||||
|
|
@ -11544,7 +11545,7 @@ else
|
||||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||||
lt_status=$lt_dlunknown
|
lt_status=$lt_dlunknown
|
||||||
cat > conftest.$ac_ext <<_LT_EOF
|
cat > conftest.$ac_ext <<_LT_EOF
|
||||||
#line 11547 "configure"
|
#line 11548 "configure"
|
||||||
#include "confdefs.h"
|
#include "confdefs.h"
|
||||||
|
|
||||||
#if HAVE_DLFCN_H
|
#if HAVE_DLFCN_H
|
||||||
|
|
@ -11650,7 +11651,7 @@ else
|
||||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||||
lt_status=$lt_dlunknown
|
lt_status=$lt_dlunknown
|
||||||
cat > conftest.$ac_ext <<_LT_EOF
|
cat > conftest.$ac_ext <<_LT_EOF
|
||||||
#line 11653 "configure"
|
#line 11654 "configure"
|
||||||
#include "confdefs.h"
|
#include "confdefs.h"
|
||||||
|
|
||||||
#if HAVE_DLFCN_H
|
#if HAVE_DLFCN_H
|
||||||
|
|
@ -14747,6 +14748,12 @@ $as_echo "$libgo_cv_lib_sockets" >&6; }
|
||||||
NET_LIBS="$libgo_cv_lib_sockets"
|
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 "$as_me:${as_lineno-$LINENO}: checking whether -pthread is supported" >&5
|
||||||
$as_echo_n "checking whether -pthread is supported... " >&6; }
|
$as_echo_n "checking whether -pthread is supported... " >&6; }
|
||||||
if ${libgo_cv_lib_pthread+:} false; then :
|
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_SRCDIR(Makefile.am)
|
||||||
AC_CONFIG_HEADER(config.h)
|
AC_CONFIG_HEADER(config.h)
|
||||||
|
|
||||||
libtool_VERSION=20:0:0
|
libtool_VERSION=21:0:0
|
||||||
AC_SUBST(libtool_VERSION)
|
AC_SUBST(libtool_VERSION)
|
||||||
|
|
||||||
AM_ENABLE_MULTILIB(, ..)
|
AM_ENABLE_MULTILIB(, ..)
|
||||||
|
|
@ -549,6 +549,12 @@ AC_CACHE_CHECK([for socket libraries], libgo_cv_lib_sockets,
|
||||||
NET_LIBS="$libgo_cv_lib_sockets"
|
NET_LIBS="$libgo_cv_lib_sockets"
|
||||||
AC_SUBST(NET_LIBS)
|
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.
|
dnl Test whether the compiler supports the -pthread option.
|
||||||
AC_CACHE_CHECK([whether -pthread is supported],
|
AC_CACHE_CHECK([whether -pthread is supported],
|
||||||
[libgo_cv_lib_pthread],
|
[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
|
// fileState tracks the number of logical (includes sparse holes) and physical
|
||||||
// (actual in tar archive) bytes remaining for the current file.
|
// (actual in tar archive) bytes remaining for the current file.
|
||||||
//
|
//
|
||||||
// Invariant: LogicalRemaining >= PhysicalRemaining
|
// Invariant: logicalRemaining >= physicalRemaining
|
||||||
type fileState interface {
|
type fileState interface {
|
||||||
LogicalRemaining() int64
|
logicalRemaining() int64
|
||||||
PhysicalRemaining() int64
|
physicalRemaining() int64
|
||||||
}
|
}
|
||||||
|
|
||||||
// allowedFormats determines which formats can be used.
|
// 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.
|
// Check basic fields.
|
||||||
var blk block
|
var blk block
|
||||||
v7 := blk.V7()
|
v7 := blk.toV7()
|
||||||
ustar := blk.USTAR()
|
ustar := blk.toUSTAR()
|
||||||
gnu := blk.GNU()
|
gnu := blk.toGNU()
|
||||||
verifyString(h.Name, len(v7.Name()), "Name", paxPath)
|
verifyString(h.Name, len(v7.name()), "Name", paxPath)
|
||||||
verifyString(h.Linkname, len(v7.LinkName()), "Linkname", paxLinkpath)
|
verifyString(h.Linkname, len(v7.linkName()), "Linkname", paxLinkpath)
|
||||||
verifyString(h.Uname, len(ustar.UserName()), "Uname", paxUname)
|
verifyString(h.Uname, len(ustar.userName()), "Uname", paxUname)
|
||||||
verifyString(h.Gname, len(ustar.GroupName()), "Gname", paxGname)
|
verifyString(h.Gname, len(ustar.groupName()), "Gname", paxGname)
|
||||||
verifyNumeric(h.Mode, len(v7.Mode()), "Mode", paxNone)
|
verifyNumeric(h.Mode, len(v7.mode()), "Mode", paxNone)
|
||||||
verifyNumeric(int64(h.Uid), len(v7.UID()), "Uid", paxUid)
|
verifyNumeric(int64(h.Uid), len(v7.uid()), "Uid", paxUid)
|
||||||
verifyNumeric(int64(h.Gid), len(v7.GID()), "Gid", paxGid)
|
verifyNumeric(int64(h.Gid), len(v7.gid()), "Gid", paxGid)
|
||||||
verifyNumeric(h.Size, len(v7.Size()), "Size", paxSize)
|
verifyNumeric(h.Size, len(v7.size()), "Size", paxSize)
|
||||||
verifyNumeric(h.Devmajor, len(ustar.DevMajor()), "Devmajor", paxNone)
|
verifyNumeric(h.Devmajor, len(ustar.devMajor()), "Devmajor", paxNone)
|
||||||
verifyNumeric(h.Devminor, len(ustar.DevMinor()), "Devminor", paxNone)
|
verifyNumeric(h.Devminor, len(ustar.devMinor()), "Devminor", paxNone)
|
||||||
verifyTime(h.ModTime, len(v7.ModTime()), "ModTime", paxMtime)
|
verifyTime(h.ModTime, len(v7.modTime()), "ModTime", paxMtime)
|
||||||
verifyTime(h.AccessTime, len(gnu.AccessTime()), "AccessTime", paxAtime)
|
verifyTime(h.AccessTime, len(gnu.accessTime()), "AccessTime", paxAtime)
|
||||||
verifyTime(h.ChangeTime, len(gnu.ChangeTime()), "ChangeTime", paxCtime)
|
verifyTime(h.ChangeTime, len(gnu.changeTime()), "ChangeTime", paxCtime)
|
||||||
|
|
||||||
// Check for header-only types.
|
// Check for header-only types.
|
||||||
var whyOnlyPAX, whyOnlyGNU string
|
var whyOnlyPAX, whyOnlyGNU string
|
||||||
|
|
@ -538,7 +538,7 @@ type headerFileInfo struct {
|
||||||
func (fi headerFileInfo) Size() int64 { return fi.h.Size }
|
func (fi headerFileInfo) Size() int64 { return fi.h.Size }
|
||||||
func (fi headerFileInfo) IsDir() bool { return fi.Mode().IsDir() }
|
func (fi headerFileInfo) IsDir() bool { return fi.Mode().IsDir() }
|
||||||
func (fi headerFileInfo) ModTime() time.Time { return fi.h.ModTime }
|
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.
|
// Name returns the base name of the file.
|
||||||
func (fi headerFileInfo) Name() string {
|
func (fi headerFileInfo) Name() string {
|
||||||
|
|
|
||||||
|
|
@ -156,28 +156,28 @@ var zeroBlock block
|
||||||
type block [blockSize]byte
|
type block [blockSize]byte
|
||||||
|
|
||||||
// Convert block to any number of formats.
|
// Convert block to any number of formats.
|
||||||
func (b *block) V7() *headerV7 { return (*headerV7)(b) }
|
func (b *block) toV7() *headerV7 { return (*headerV7)(b) }
|
||||||
func (b *block) GNU() *headerGNU { return (*headerGNU)(b) }
|
func (b *block) toGNU() *headerGNU { return (*headerGNU)(b) }
|
||||||
func (b *block) STAR() *headerSTAR { return (*headerSTAR)(b) }
|
func (b *block) toSTAR() *headerSTAR { return (*headerSTAR)(b) }
|
||||||
func (b *block) USTAR() *headerUSTAR { return (*headerUSTAR)(b) }
|
func (b *block) toUSTAR() *headerUSTAR { return (*headerUSTAR)(b) }
|
||||||
func (b *block) Sparse() sparseArray { return sparseArray(b[:]) }
|
func (b *block) toSparse() sparseArray { return sparseArray(b[:]) }
|
||||||
|
|
||||||
// GetFormat checks that the block is a valid tar header based on the checksum.
|
// 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.
|
// It then attempts to guess the specific format based on magic values.
|
||||||
// If the checksum fails, then FormatUnknown is returned.
|
// If the checksum fails, then FormatUnknown is returned.
|
||||||
func (b *block) GetFormat() Format {
|
func (b *block) getFormat() Format {
|
||||||
// Verify checksum.
|
// Verify checksum.
|
||||||
var p parser
|
var p parser
|
||||||
value := p.parseOctal(b.V7().Chksum())
|
value := p.parseOctal(b.toV7().chksum())
|
||||||
chksum1, chksum2 := b.ComputeChecksum()
|
chksum1, chksum2 := b.computeChecksum()
|
||||||
if p.err != nil || (value != chksum1 && value != chksum2) {
|
if p.err != nil || (value != chksum1 && value != chksum2) {
|
||||||
return FormatUnknown
|
return FormatUnknown
|
||||||
}
|
}
|
||||||
|
|
||||||
// Guess the magic values.
|
// Guess the magic values.
|
||||||
magic := string(b.USTAR().Magic())
|
magic := string(b.toUSTAR().magic())
|
||||||
version := string(b.USTAR().Version())
|
version := string(b.toUSTAR().version())
|
||||||
trailer := string(b.STAR().Trailer())
|
trailer := string(b.toSTAR().trailer())
|
||||||
switch {
|
switch {
|
||||||
case magic == magicUSTAR && trailer == trailerSTAR:
|
case magic == magicUSTAR && trailer == trailerSTAR:
|
||||||
return formatSTAR
|
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.
|
// and then updates the checksum accordingly.
|
||||||
func (b *block) SetFormat(format Format) {
|
func (b *block) setFormat(format Format) {
|
||||||
// Set the magic values.
|
// Set the magic values.
|
||||||
switch {
|
switch {
|
||||||
case format.has(formatV7):
|
case format.has(formatV7):
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
case format.has(FormatGNU):
|
case format.has(FormatGNU):
|
||||||
copy(b.GNU().Magic(), magicGNU)
|
copy(b.toGNU().magic(), magicGNU)
|
||||||
copy(b.GNU().Version(), versionGNU)
|
copy(b.toGNU().version(), versionGNU)
|
||||||
case format.has(formatSTAR):
|
case format.has(formatSTAR):
|
||||||
copy(b.STAR().Magic(), magicUSTAR)
|
copy(b.toSTAR().magic(), magicUSTAR)
|
||||||
copy(b.STAR().Version(), versionUSTAR)
|
copy(b.toSTAR().version(), versionUSTAR)
|
||||||
copy(b.STAR().Trailer(), trailerSTAR)
|
copy(b.toSTAR().trailer(), trailerSTAR)
|
||||||
case format.has(FormatUSTAR | FormatPAX):
|
case format.has(FormatUSTAR | FormatPAX):
|
||||||
copy(b.USTAR().Magic(), magicUSTAR)
|
copy(b.toUSTAR().magic(), magicUSTAR)
|
||||||
copy(b.USTAR().Version(), versionUSTAR)
|
copy(b.toUSTAR().version(), versionUSTAR)
|
||||||
default:
|
default:
|
||||||
panic("invalid format")
|
panic("invalid format")
|
||||||
}
|
}
|
||||||
|
|
@ -214,17 +214,17 @@ func (b *block) SetFormat(format Format) {
|
||||||
// Update checksum.
|
// Update checksum.
|
||||||
// This field is special in that it is terminated by a NULL then space.
|
// This field is special in that it is terminated by a NULL then space.
|
||||||
var f formatter
|
var f formatter
|
||||||
field := b.V7().Chksum()
|
field := b.toV7().chksum()
|
||||||
chksum, _ := b.ComputeChecksum() // Possible values are 256..128776
|
chksum, _ := b.computeChecksum() // Possible values are 256..128776
|
||||||
f.formatOctal(field[:7], chksum) // Never fails since 128776 < 262143
|
f.formatOctal(field[:7], chksum) // Never fails since 128776 < 262143
|
||||||
field[7] = ' '
|
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
|
// POSIX specifies a sum of the unsigned byte values, but the Sun tar used
|
||||||
// signed byte values.
|
// signed byte values.
|
||||||
// We compute and return both.
|
// We compute and return both.
|
||||||
func (b *block) ComputeChecksum() (unsigned, signed int64) {
|
func (b *block) computeChecksum() (unsigned, signed int64) {
|
||||||
for i, c := range b {
|
for i, c := range b {
|
||||||
if 148 <= i && i < 156 {
|
if 148 <= i && i < 156 {
|
||||||
c = ' ' // Treat the checksum field itself as all spaces.
|
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.
|
// Reset clears the block with all zeros.
|
||||||
func (b *block) Reset() {
|
func (b *block) reset() {
|
||||||
*b = block{}
|
*b = block{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type headerV7 [blockSize]byte
|
type headerV7 [blockSize]byte
|
||||||
|
|
||||||
func (h *headerV7) Name() []byte { return h[000:][:100] }
|
func (h *headerV7) name() []byte { return h[000:][:100] }
|
||||||
func (h *headerV7) Mode() []byte { return h[100:][:8] }
|
func (h *headerV7) mode() []byte { return h[100:][:8] }
|
||||||
func (h *headerV7) UID() []byte { return h[108:][:8] }
|
func (h *headerV7) uid() []byte { return h[108:][:8] }
|
||||||
func (h *headerV7) GID() []byte { return h[116:][:8] }
|
func (h *headerV7) gid() []byte { return h[116:][:8] }
|
||||||
func (h *headerV7) Size() []byte { return h[124:][:12] }
|
func (h *headerV7) size() []byte { return h[124:][:12] }
|
||||||
func (h *headerV7) ModTime() []byte { return h[136:][:12] }
|
func (h *headerV7) modTime() []byte { return h[136:][:12] }
|
||||||
func (h *headerV7) Chksum() []byte { return h[148:][:8] }
|
func (h *headerV7) chksum() []byte { return h[148:][:8] }
|
||||||
func (h *headerV7) TypeFlag() []byte { return h[156:][:1] }
|
func (h *headerV7) typeFlag() []byte { return h[156:][:1] }
|
||||||
func (h *headerV7) LinkName() []byte { return h[157:][:100] }
|
func (h *headerV7) linkName() []byte { return h[157:][:100] }
|
||||||
|
|
||||||
type headerGNU [blockSize]byte
|
type headerGNU [blockSize]byte
|
||||||
|
|
||||||
func (h *headerGNU) V7() *headerV7 { return (*headerV7)(h) }
|
func (h *headerGNU) v7() *headerV7 { return (*headerV7)(h) }
|
||||||
func (h *headerGNU) Magic() []byte { return h[257:][:6] }
|
func (h *headerGNU) magic() []byte { return h[257:][:6] }
|
||||||
func (h *headerGNU) Version() []byte { return h[263:][:2] }
|
func (h *headerGNU) version() []byte { return h[263:][:2] }
|
||||||
func (h *headerGNU) UserName() []byte { return h[265:][:32] }
|
func (h *headerGNU) userName() []byte { return h[265:][:32] }
|
||||||
func (h *headerGNU) GroupName() []byte { return h[297:][:32] }
|
func (h *headerGNU) groupName() []byte { return h[297:][:32] }
|
||||||
func (h *headerGNU) DevMajor() []byte { return h[329:][:8] }
|
func (h *headerGNU) devMajor() []byte { return h[329:][:8] }
|
||||||
func (h *headerGNU) DevMinor() []byte { return h[337:][:8] }
|
func (h *headerGNU) devMinor() []byte { return h[337:][:8] }
|
||||||
func (h *headerGNU) AccessTime() []byte { return h[345:][:12] }
|
func (h *headerGNU) accessTime() []byte { return h[345:][:12] }
|
||||||
func (h *headerGNU) ChangeTime() []byte { return h[357:][: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) sparse() sparseArray { return sparseArray(h[386:][:24*4+1]) }
|
||||||
func (h *headerGNU) RealSize() []byte { return h[483:][:12] }
|
func (h *headerGNU) realSize() []byte { return h[483:][:12] }
|
||||||
|
|
||||||
type headerSTAR [blockSize]byte
|
type headerSTAR [blockSize]byte
|
||||||
|
|
||||||
func (h *headerSTAR) V7() *headerV7 { return (*headerV7)(h) }
|
func (h *headerSTAR) v7() *headerV7 { return (*headerV7)(h) }
|
||||||
func (h *headerSTAR) Magic() []byte { return h[257:][:6] }
|
func (h *headerSTAR) magic() []byte { return h[257:][:6] }
|
||||||
func (h *headerSTAR) Version() []byte { return h[263:][:2] }
|
func (h *headerSTAR) version() []byte { return h[263:][:2] }
|
||||||
func (h *headerSTAR) UserName() []byte { return h[265:][:32] }
|
func (h *headerSTAR) userName() []byte { return h[265:][:32] }
|
||||||
func (h *headerSTAR) GroupName() []byte { return h[297:][:32] }
|
func (h *headerSTAR) groupName() []byte { return h[297:][:32] }
|
||||||
func (h *headerSTAR) DevMajor() []byte { return h[329:][:8] }
|
func (h *headerSTAR) devMajor() []byte { return h[329:][:8] }
|
||||||
func (h *headerSTAR) DevMinor() []byte { return h[337:][:8] }
|
func (h *headerSTAR) devMinor() []byte { return h[337:][:8] }
|
||||||
func (h *headerSTAR) Prefix() []byte { return h[345:][:131] }
|
func (h *headerSTAR) prefix() []byte { return h[345:][:131] }
|
||||||
func (h *headerSTAR) AccessTime() []byte { return h[476:][:12] }
|
func (h *headerSTAR) accessTime() []byte { return h[476:][:12] }
|
||||||
func (h *headerSTAR) ChangeTime() []byte { return h[488:][:12] }
|
func (h *headerSTAR) changeTime() []byte { return h[488:][:12] }
|
||||||
func (h *headerSTAR) Trailer() []byte { return h[508:][:4] }
|
func (h *headerSTAR) trailer() []byte { return h[508:][:4] }
|
||||||
|
|
||||||
type headerUSTAR [blockSize]byte
|
type headerUSTAR [blockSize]byte
|
||||||
|
|
||||||
func (h *headerUSTAR) V7() *headerV7 { return (*headerV7)(h) }
|
func (h *headerUSTAR) v7() *headerV7 { return (*headerV7)(h) }
|
||||||
func (h *headerUSTAR) Magic() []byte { return h[257:][:6] }
|
func (h *headerUSTAR) magic() []byte { return h[257:][:6] }
|
||||||
func (h *headerUSTAR) Version() []byte { return h[263:][:2] }
|
func (h *headerUSTAR) version() []byte { return h[263:][:2] }
|
||||||
func (h *headerUSTAR) UserName() []byte { return h[265:][:32] }
|
func (h *headerUSTAR) userName() []byte { return h[265:][:32] }
|
||||||
func (h *headerUSTAR) GroupName() []byte { return h[297:][:32] }
|
func (h *headerUSTAR) groupName() []byte { return h[297:][:32] }
|
||||||
func (h *headerUSTAR) DevMajor() []byte { return h[329:][:8] }
|
func (h *headerUSTAR) devMajor() []byte { return h[329:][:8] }
|
||||||
func (h *headerUSTAR) DevMinor() []byte { return h[337:][:8] }
|
func (h *headerUSTAR) devMinor() []byte { return h[337:][:8] }
|
||||||
func (h *headerUSTAR) Prefix() []byte { return h[345:][:155] }
|
func (h *headerUSTAR) prefix() []byte { return h[345:][:155] }
|
||||||
|
|
||||||
type sparseArray []byte
|
type sparseArray []byte
|
||||||
|
|
||||||
func (s sparseArray) Entry(i int) sparseElem { return sparseElem(s[i*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) isExtended() []byte { return s[24*s.maxEntries():][:1] }
|
||||||
func (s sparseArray) MaxEntries() int { return len(s) / 24 }
|
func (s sparseArray) maxEntries() int { return len(s) / 24 }
|
||||||
|
|
||||||
type sparseElem []byte
|
type sparseElem []byte
|
||||||
|
|
||||||
func (s sparseElem) Offset() []byte { return s[00:][:12] }
|
func (s sparseElem) offset() []byte { return s[00:][:12] }
|
||||||
func (s sparseElem) Length() []byte { return s[12:][:12] }
|
func (s sparseElem) length() []byte { return s[12:][:12] }
|
||||||
|
|
|
||||||
|
|
@ -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
|
format := FormatUSTAR | FormatPAX | FormatGNU
|
||||||
for {
|
for {
|
||||||
// Discard the remainder of the file and any padding.
|
// 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
|
return nil, err
|
||||||
}
|
}
|
||||||
if _, err := tryReadFull(tr.r, tr.blk[:tr.pad]); err != nil {
|
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.
|
// Verify the header matches a known format.
|
||||||
format := tr.blk.GetFormat()
|
format := tr.blk.getFormat()
|
||||||
if format == FormatUnknown {
|
if format == FormatUnknown {
|
||||||
return nil, nil, ErrHeader
|
return nil, nil, ErrHeader
|
||||||
}
|
}
|
||||||
|
|
@ -364,30 +364,30 @@ func (tr *Reader) readHeader() (*Header, *block, error) {
|
||||||
hdr := new(Header)
|
hdr := new(Header)
|
||||||
|
|
||||||
// Unpack the V7 header.
|
// Unpack the V7 header.
|
||||||
v7 := tr.blk.V7()
|
v7 := tr.blk.toV7()
|
||||||
hdr.Typeflag = v7.TypeFlag()[0]
|
hdr.Typeflag = v7.typeFlag()[0]
|
||||||
hdr.Name = p.parseString(v7.Name())
|
hdr.Name = p.parseString(v7.name())
|
||||||
hdr.Linkname = p.parseString(v7.LinkName())
|
hdr.Linkname = p.parseString(v7.linkName())
|
||||||
hdr.Size = p.parseNumeric(v7.Size())
|
hdr.Size = p.parseNumeric(v7.size())
|
||||||
hdr.Mode = p.parseNumeric(v7.Mode())
|
hdr.Mode = p.parseNumeric(v7.mode())
|
||||||
hdr.Uid = int(p.parseNumeric(v7.UID()))
|
hdr.Uid = int(p.parseNumeric(v7.uid()))
|
||||||
hdr.Gid = int(p.parseNumeric(v7.GID()))
|
hdr.Gid = int(p.parseNumeric(v7.gid()))
|
||||||
hdr.ModTime = time.Unix(p.parseNumeric(v7.ModTime()), 0)
|
hdr.ModTime = time.Unix(p.parseNumeric(v7.modTime()), 0)
|
||||||
|
|
||||||
// Unpack format specific fields.
|
// Unpack format specific fields.
|
||||||
if format > formatV7 {
|
if format > formatV7 {
|
||||||
ustar := tr.blk.USTAR()
|
ustar := tr.blk.toUSTAR()
|
||||||
hdr.Uname = p.parseString(ustar.UserName())
|
hdr.Uname = p.parseString(ustar.userName())
|
||||||
hdr.Gname = p.parseString(ustar.GroupName())
|
hdr.Gname = p.parseString(ustar.groupName())
|
||||||
hdr.Devmajor = p.parseNumeric(ustar.DevMajor())
|
hdr.Devmajor = p.parseNumeric(ustar.devMajor())
|
||||||
hdr.Devminor = p.parseNumeric(ustar.DevMinor())
|
hdr.Devminor = p.parseNumeric(ustar.devMinor())
|
||||||
|
|
||||||
var prefix string
|
var prefix string
|
||||||
switch {
|
switch {
|
||||||
case format.has(FormatUSTAR | FormatPAX):
|
case format.has(FormatUSTAR | FormatPAX):
|
||||||
hdr.Format = format
|
hdr.Format = format
|
||||||
ustar := tr.blk.USTAR()
|
ustar := tr.blk.toUSTAR()
|
||||||
prefix = p.parseString(ustar.Prefix())
|
prefix = p.parseString(ustar.prefix())
|
||||||
|
|
||||||
// For Format detection, check if block is properly formatted since
|
// For Format detection, check if block is properly formatted since
|
||||||
// the parser is more liberal than what USTAR actually permits.
|
// 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.
|
hdr.Format = FormatUnknown // Non-ASCII characters in block.
|
||||||
}
|
}
|
||||||
nul := func(b []byte) bool { return int(b[len(b)-1]) == 0 }
|
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()) &&
|
if !(nul(v7.size()) && nul(v7.mode()) && nul(v7.uid()) && nul(v7.gid()) &&
|
||||||
nul(v7.ModTime()) && nul(ustar.DevMajor()) && nul(ustar.DevMinor())) {
|
nul(v7.modTime()) && nul(ustar.devMajor()) && nul(ustar.devMinor())) {
|
||||||
hdr.Format = FormatUnknown // Numeric fields must end in NUL
|
hdr.Format = FormatUnknown // Numeric fields must end in NUL
|
||||||
}
|
}
|
||||||
case format.has(formatSTAR):
|
case format.has(formatSTAR):
|
||||||
star := tr.blk.STAR()
|
star := tr.blk.toSTAR()
|
||||||
prefix = p.parseString(star.Prefix())
|
prefix = p.parseString(star.prefix())
|
||||||
hdr.AccessTime = time.Unix(p.parseNumeric(star.AccessTime()), 0)
|
hdr.AccessTime = time.Unix(p.parseNumeric(star.accessTime()), 0)
|
||||||
hdr.ChangeTime = time.Unix(p.parseNumeric(star.ChangeTime()), 0)
|
hdr.ChangeTime = time.Unix(p.parseNumeric(star.changeTime()), 0)
|
||||||
case format.has(FormatGNU):
|
case format.has(FormatGNU):
|
||||||
hdr.Format = format
|
hdr.Format = format
|
||||||
var p2 parser
|
var p2 parser
|
||||||
gnu := tr.blk.GNU()
|
gnu := tr.blk.toGNU()
|
||||||
if b := gnu.AccessTime(); b[0] != 0 {
|
if b := gnu.accessTime(); b[0] != 0 {
|
||||||
hdr.AccessTime = time.Unix(p2.parseNumeric(b), 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)
|
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
|
// See https://golang.org/issues/21005
|
||||||
if p2.err != nil {
|
if p2.err != nil {
|
||||||
hdr.AccessTime, hdr.ChangeTime = time.Time{}, time.Time{}
|
hdr.AccessTime, hdr.ChangeTime = time.Time{}, time.Time{}
|
||||||
ustar := tr.blk.USTAR()
|
ustar := tr.blk.toUSTAR()
|
||||||
if s := p.parseString(ustar.Prefix()); isASCII(s) {
|
if s := p.parseString(ustar.prefix()); isASCII(s) {
|
||||||
prefix = s
|
prefix = s
|
||||||
}
|
}
|
||||||
hdr.Format = FormatUnknown // Buggy file is not GNU
|
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.
|
// Make sure that the input format is GNU.
|
||||||
// Unfortunately, the STAR format also has a sparse header format that uses
|
// Unfortunately, the STAR format also has a sparse header format that uses
|
||||||
// the same type flag but has a completely different layout.
|
// the same type flag but has a completely different layout.
|
||||||
if blk.GetFormat() != FormatGNU {
|
if blk.getFormat() != FormatGNU {
|
||||||
return nil, ErrHeader
|
return nil, ErrHeader
|
||||||
}
|
}
|
||||||
hdr.Format.mayOnlyBe(FormatGNU)
|
hdr.Format.mayOnlyBe(FormatGNU)
|
||||||
|
|
||||||
var p parser
|
var p parser
|
||||||
hdr.Size = p.parseNumeric(blk.GNU().RealSize())
|
hdr.Size = p.parseNumeric(blk.toGNU().realSize())
|
||||||
if p.err != nil {
|
if p.err != nil {
|
||||||
return nil, p.err
|
return nil, p.err
|
||||||
}
|
}
|
||||||
s := blk.GNU().Sparse()
|
s := blk.toGNU().sparse()
|
||||||
spd := make(sparseDatas, 0, s.MaxEntries())
|
spd := make(sparseDatas, 0, s.maxEntries())
|
||||||
for {
|
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.
|
// 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)
|
break // Don't return, need to process extended headers (even if empty)
|
||||||
}
|
}
|
||||||
offset := p.parseNumeric(s.Entry(i).Offset())
|
offset := p.parseNumeric(s.entry(i).offset())
|
||||||
length := p.parseNumeric(s.Entry(i).Length())
|
length := p.parseNumeric(s.entry(i).length())
|
||||||
if p.err != nil {
|
if p.err != nil {
|
||||||
return nil, p.err
|
return nil, p.err
|
||||||
}
|
}
|
||||||
spd = append(spd, sparseEntry{Offset: offset, Length: length})
|
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.
|
// There are more entries. Read an extension header and parse its entries.
|
||||||
if _, err := mustReadFull(tr.r, blk[:]); err != nil {
|
if _, err := mustReadFull(tr.r, blk[:]); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
s = blk.Sparse()
|
s = blk.toSparse()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return spd, nil // Done
|
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})
|
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
|
return fr.nb
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fr regFileReader) PhysicalRemaining() int64 {
|
// logicalRemaining implements fileState.physicalRemaining.
|
||||||
|
func (fr regFileReader) physicalRemaining() int64 {
|
||||||
return fr.nb
|
return fr.nb
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -694,9 +696,9 @@ type sparseFileReader struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sr *sparseFileReader) Read(b []byte) (n int, err error) {
|
func (sr *sparseFileReader) Read(b []byte) (n int, err error) {
|
||||||
finished := int64(len(b)) >= sr.LogicalRemaining()
|
finished := int64(len(b)) >= sr.logicalRemaining()
|
||||||
if finished {
|
if finished {
|
||||||
b = b[:sr.LogicalRemaining()]
|
b = b[:sr.logicalRemaining()]
|
||||||
}
|
}
|
||||||
|
|
||||||
b0 := b
|
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
|
return n, errMissData // Less data in dense file than sparse file
|
||||||
case err != nil:
|
case err != nil:
|
||||||
return n, err
|
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
|
return n, errUnrefData // More data in dense file than sparse file
|
||||||
case finished:
|
case finished:
|
||||||
return n, io.EOF
|
return n, io.EOF
|
||||||
|
|
@ -746,7 +748,7 @@ func (sr *sparseFileReader) WriteTo(w io.Writer) (n int64, err error) {
|
||||||
|
|
||||||
var writeLastByte bool
|
var writeLastByte bool
|
||||||
pos0 := sr.pos
|
pos0 := sr.pos
|
||||||
for sr.LogicalRemaining() > 0 && !writeLastByte && err == nil {
|
for sr.logicalRemaining() > 0 && !writeLastByte && err == nil {
|
||||||
var nf int64 // Size of fragment
|
var nf int64 // Size of fragment
|
||||||
holeStart, holeEnd := sr.sp[0].Offset, sr.sp[0].endOffset()
|
holeStart, holeEnd := sr.sp[0].Offset, sr.sp[0].endOffset()
|
||||||
if sr.pos < holeStart { // In a data fragment
|
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)
|
nf, err = io.CopyN(ws, sr.fr, nf)
|
||||||
} else { // In a hole fragment
|
} else { // In a hole fragment
|
||||||
nf = holeEnd - sr.pos
|
nf = holeEnd - sr.pos
|
||||||
if sr.PhysicalRemaining() == 0 {
|
if sr.physicalRemaining() == 0 {
|
||||||
writeLastByte = true
|
writeLastByte = true
|
||||||
nf--
|
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
|
return n, errMissData // Less data in dense file than sparse file
|
||||||
case err != nil:
|
case err != nil:
|
||||||
return n, err
|
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
|
return n, errUnrefData // More data in dense file than sparse file
|
||||||
default:
|
default:
|
||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sr sparseFileReader) LogicalRemaining() int64 {
|
func (sr sparseFileReader) logicalRemaining() int64 {
|
||||||
return sr.sp[len(sr.sp)-1].endOffset() - sr.pos
|
return sr.sp[len(sr.sp)-1].endOffset() - sr.pos
|
||||||
}
|
}
|
||||||
func (sr sparseFileReader) PhysicalRemaining() int64 {
|
func (sr sparseFileReader) physicalRemaining() int64 {
|
||||||
return sr.fr.PhysicalRemaining()
|
return sr.fr.physicalRemaining()
|
||||||
}
|
}
|
||||||
|
|
||||||
type zeroReader struct{}
|
type zeroReader struct{}
|
||||||
|
|
|
||||||
|
|
@ -1021,12 +1021,12 @@ func TestParsePAX(t *testing.T) {
|
||||||
|
|
||||||
func TestReadOldGNUSparseMap(t *testing.T) {
|
func TestReadOldGNUSparseMap(t *testing.T) {
|
||||||
populateSparseMap := func(sa sparseArray, sps []string) []string {
|
populateSparseMap := func(sa sparseArray, sps []string) []string {
|
||||||
for i := 0; len(sps) > 0 && i < sa.MaxEntries(); i++ {
|
for i := 0; len(sps) > 0 && i < sa.maxEntries(); i++ {
|
||||||
copy(sa.Entry(i), sps[0])
|
copy(sa.entry(i), sps[0])
|
||||||
sps = sps[1:]
|
sps = sps[1:]
|
||||||
}
|
}
|
||||||
if len(sps) > 0 {
|
if len(sps) > 0 {
|
||||||
copy(sa.IsExtended(), "\x80")
|
copy(sa.isExtended(), "\x80")
|
||||||
}
|
}
|
||||||
return sps
|
return sps
|
||||||
}
|
}
|
||||||
|
|
@ -1034,19 +1034,19 @@ func TestReadOldGNUSparseMap(t *testing.T) {
|
||||||
makeInput := func(format Format, size string, sps ...string) (out []byte) {
|
makeInput := func(format Format, size string, sps ...string) (out []byte) {
|
||||||
// Write the initial GNU header.
|
// Write the initial GNU header.
|
||||||
var blk block
|
var blk block
|
||||||
gnu := blk.GNU()
|
gnu := blk.toGNU()
|
||||||
sparse := gnu.Sparse()
|
sparse := gnu.sparse()
|
||||||
copy(gnu.RealSize(), size)
|
copy(gnu.realSize(), size)
|
||||||
sps = populateSparseMap(sparse, sps)
|
sps = populateSparseMap(sparse, sps)
|
||||||
if format != FormatUnknown {
|
if format != FormatUnknown {
|
||||||
blk.SetFormat(format)
|
blk.setFormat(format)
|
||||||
}
|
}
|
||||||
out = append(out, blk[:]...)
|
out = append(out, blk[:]...)
|
||||||
|
|
||||||
// Write extended sparse blocks.
|
// Write extended sparse blocks.
|
||||||
for len(sps) > 0 {
|
for len(sps) > 0 {
|
||||||
var blk block
|
var blk block
|
||||||
sps = populateSparseMap(blk.Sparse(), sps)
|
sps = populateSparseMap(blk.toSparse(), sps)
|
||||||
out = append(out, blk[:]...)
|
out = append(out, blk[:]...)
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
|
|
@ -1359,11 +1359,11 @@ func TestFileReader(t *testing.T) {
|
||||||
wantCnt int64
|
wantCnt int64
|
||||||
wantErr error
|
wantErr error
|
||||||
}
|
}
|
||||||
testRemaining struct { // LogicalRemaining() == wantLCnt, PhysicalRemaining() == wantPCnt
|
testRemaining struct { // logicalRemaining() == wantLCnt, physicalRemaining() == wantPCnt
|
||||||
wantLCnt int64
|
wantLCnt int64
|
||||||
wantPCnt int64
|
wantPCnt int64
|
||||||
}
|
}
|
||||||
testFnc interface{} // testRead | testWriteTo | testRemaining
|
testFnc any // testRead | testWriteTo | testRemaining
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
|
@ -1376,7 +1376,7 @@ func TestFileReader(t *testing.T) {
|
||||||
spd sparseDatas
|
spd sparseDatas
|
||||||
size int64
|
size int64
|
||||||
}
|
}
|
||||||
fileMaker interface{} // makeReg | makeSparse
|
fileMaker any // makeReg | makeSparse
|
||||||
)
|
)
|
||||||
|
|
||||||
vectors := []struct {
|
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))
|
t.Errorf("test %d.%d, expected %d more operations", i, j, len(f.ops))
|
||||||
}
|
}
|
||||||
case testRemaining:
|
case testRemaining:
|
||||||
if got := fr.LogicalRemaining(); got != tf.wantLCnt {
|
if got := fr.logicalRemaining(); got != tf.wantLCnt {
|
||||||
t.Errorf("test %d.%d, LogicalRemaining() = %d, want %d", i, j, got, tf.wantLCnt)
|
t.Errorf("test %d.%d, logicalRemaining() = %d, want %d", i, j, got, tf.wantLCnt)
|
||||||
}
|
}
|
||||||
if got := fr.PhysicalRemaining(); got != tf.wantPCnt {
|
if got := fr.physicalRemaining(); got != tf.wantPCnt {
|
||||||
t.Errorf("test %d.%d, PhysicalRemaining() = %d, want %d", i, j, got, tf.wantPCnt)
|
t.Errorf("test %d.%d, physicalRemaining() = %d, want %d", i, j, got, tf.wantPCnt)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
t.Fatalf("test %d.%d, unknown test operation: %T", i, j, tf)
|
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.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build aix || hurd || linux || dragonfly || openbsd || solaris
|
//go:build aix || hurd || linux || dragonfly || openbsd || solaris
|
||||||
// +build aix hurd linux dragonfly openbsd solaris
|
|
||||||
|
|
||||||
package tar
|
package tar
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build darwin || freebsd || netbsd
|
//go:build darwin || freebsd || netbsd
|
||||||
// +build darwin freebsd netbsd
|
|
||||||
|
|
||||||
package tar
|
package tar
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build aix || hurd || linux || darwin || dragonfly || freebsd || openbsd || netbsd || solaris
|
//go:build aix || hurd || linux || darwin || dragonfly || freebsd || openbsd || netbsd || solaris
|
||||||
// +build aix hurd linux darwin dragonfly freebsd openbsd netbsd solaris
|
|
||||||
|
|
||||||
package tar
|
package tar
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import (
|
||||||
|
|
||||||
// hasNUL reports whether the NUL character exists within s.
|
// hasNUL reports whether the NUL character exists within s.
|
||||||
func hasNUL(s string) bool {
|
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.
|
// 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
|
const maxNanoSecondDigits = 9
|
||||||
|
|
||||||
// Split string into seconds and sub-seconds parts.
|
// Split string into seconds and sub-seconds parts.
|
||||||
ss, sn := s, ""
|
ss, sn, _ := strings.Cut(s, ".")
|
||||||
if pos := strings.IndexByte(s, '.'); pos >= 0 {
|
|
||||||
ss, sn = s[:pos], s[pos+1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the seconds.
|
// Parse the seconds.
|
||||||
secs, err := strconv.ParseInt(ss, 10, 64)
|
secs, err := strconv.ParseInt(ss, 10, 64)
|
||||||
|
|
@ -254,48 +251,32 @@ func formatPAXTime(ts time.Time) (s string) {
|
||||||
// return the remainder as r.
|
// return the remainder as r.
|
||||||
func parsePAXRecord(s string) (k, v, r string, err error) {
|
func parsePAXRecord(s string) (k, v, r string, err error) {
|
||||||
// The size field ends at the first space.
|
// The size field ends at the first space.
|
||||||
sp := strings.IndexByte(s, ' ')
|
nStr, rest, ok := strings.Cut(s, " ")
|
||||||
if sp == -1 {
|
if !ok {
|
||||||
return "", "", s, ErrHeader
|
return "", "", s, ErrHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the first token as a decimal integer.
|
// Parse the first token as a decimal integer.
|
||||||
n, perr := strconv.ParseInt(s[:sp], 10, 0) // Intentionally parse as native int
|
n, perr := strconv.ParseInt(nStr, 10, 0) // Intentionally parse as native int
|
||||||
if perr != nil || n < 5 || int64(len(s)) < n {
|
if perr != nil || n < 5 || n > int64(len(s)) {
|
||||||
return "", "", s, ErrHeader
|
return "", "", s, ErrHeader
|
||||||
}
|
}
|
||||||
|
n -= int64(len(nStr) + 1) // convert from index in s to index in rest
|
||||||
afterSpace := int64(sp + 1)
|
if n <= 0 {
|
||||||
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 {
|
|
||||||
return "", "", s, ErrHeader
|
return "", "", s, ErrHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract everything between the space and the final newline.
|
// 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" {
|
if nl != "\n" {
|
||||||
return "", "", s, ErrHeader
|
return "", "", s, ErrHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
// The first equals separates the key from the value.
|
// The first equals separates the key from the value.
|
||||||
eq := strings.IndexByte(rec, '=')
|
k, v, ok = strings.Cut(rec, "=")
|
||||||
if eq == -1 {
|
if !ok {
|
||||||
return "", "", s, ErrHeader
|
return "", "", s, ErrHeader
|
||||||
}
|
}
|
||||||
k, v = rec[:eq], rec[eq+1:]
|
|
||||||
|
|
||||||
if !validPAXRecord(k, v) {
|
if !validPAXRecord(k, v) {
|
||||||
return "", "", s, ErrHeader
|
return "", "", s, ErrHeader
|
||||||
|
|
@ -333,7 +314,7 @@ func formatPAXRecord(k, v string) (string, error) {
|
||||||
// for the PAX version of the USTAR string fields.
|
// for the PAX version of the USTAR string fields.
|
||||||
// The key must not contain an '=' character.
|
// The key must not contain an '=' character.
|
||||||
func validPAXRecord(k, v string) bool {
|
func validPAXRecord(k, v string) bool {
|
||||||
if k == "" || strings.IndexByte(k, '=') >= 0 {
|
if k == "" || strings.Contains(k, "=") {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
switch k {
|
switch k {
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ import (
|
||||||
|
|
||||||
type testError struct{ error }
|
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
|
// testFile is an io.ReadWriteSeeker where the IO operations performed
|
||||||
// on it must match the list of operations in ops.
|
// on it must match the list of operations in ops.
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ func (tw *Writer) Flush() error {
|
||||||
if tw.err != nil {
|
if tw.err != nil {
|
||||||
return tw.err
|
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)
|
return fmt.Errorf("archive/tar: missed writing %d bytes", nb)
|
||||||
}
|
}
|
||||||
if _, tw.err = tw.w.Write(zeroBlock[:tw.pad]); tw.err != nil {
|
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.
|
// Pack the main header.
|
||||||
var f formatter
|
var f formatter
|
||||||
blk := tw.templateV7Plus(hdr, f.formatString, f.formatOctal)
|
blk := tw.templateV7Plus(hdr, f.formatString, f.formatOctal)
|
||||||
f.formatString(blk.USTAR().Prefix(), namePrefix)
|
f.formatString(blk.toUSTAR().prefix(), namePrefix)
|
||||||
blk.SetFormat(FormatUSTAR)
|
blk.setFormat(FormatUSTAR)
|
||||||
if f.err != nil {
|
if f.err != nil {
|
||||||
return f.err // Should never happen since header is validated
|
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
|
var f formatter // Ignore errors since they are expected
|
||||||
fmtStr := func(b []byte, s string) { f.formatString(b, toASCII(s)) }
|
fmtStr := func(b []byte, s string) { f.formatString(b, toASCII(s)) }
|
||||||
blk := tw.templateV7Plus(hdr, fmtStr, f.formatOctal)
|
blk := tw.templateV7Plus(hdr, fmtStr, f.formatOctal)
|
||||||
blk.SetFormat(FormatPAX)
|
blk.setFormat(FormatPAX)
|
||||||
if err := tw.writeRawHeader(blk, hdr.Size, hdr.Typeflag); err != nil {
|
if err := tw.writeRawHeader(blk, hdr.Size, hdr.Typeflag); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -250,10 +250,10 @@ func (tw *Writer) writeGNUHeader(hdr *Header) error {
|
||||||
var spb []byte
|
var spb []byte
|
||||||
blk := tw.templateV7Plus(hdr, f.formatString, f.formatNumeric)
|
blk := tw.templateV7Plus(hdr, f.formatString, f.formatNumeric)
|
||||||
if !hdr.AccessTime.IsZero() {
|
if !hdr.AccessTime.IsZero() {
|
||||||
f.formatNumeric(blk.GNU().AccessTime(), hdr.AccessTime.Unix())
|
f.formatNumeric(blk.toGNU().accessTime(), hdr.AccessTime.Unix())
|
||||||
}
|
}
|
||||||
if !hdr.ChangeTime.IsZero() {
|
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.
|
// TODO(dsnet): Re-enable this when adding sparse support.
|
||||||
// See https://golang.org/issue/22735
|
// See https://golang.org/issue/22735
|
||||||
|
|
@ -293,7 +293,7 @@ func (tw *Writer) writeGNUHeader(hdr *Header) error {
|
||||||
f.formatNumeric(blk.GNU().RealSize(), realSize)
|
f.formatNumeric(blk.GNU().RealSize(), realSize)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
blk.SetFormat(FormatGNU)
|
blk.setFormat(FormatGNU)
|
||||||
if err := tw.writeRawHeader(blk, hdr.Size, hdr.Typeflag); err != nil {
|
if err := tw.writeRawHeader(blk, hdr.Size, hdr.Typeflag); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -321,28 +321,28 @@ type (
|
||||||
// The block returned is only valid until the next call to
|
// The block returned is only valid until the next call to
|
||||||
// templateV7Plus or writeRawFile.
|
// templateV7Plus or writeRawFile.
|
||||||
func (tw *Writer) templateV7Plus(hdr *Header, fmtStr stringFormatter, fmtNum numberFormatter) *block {
|
func (tw *Writer) templateV7Plus(hdr *Header, fmtStr stringFormatter, fmtNum numberFormatter) *block {
|
||||||
tw.blk.Reset()
|
tw.blk.reset()
|
||||||
|
|
||||||
modTime := hdr.ModTime
|
modTime := hdr.ModTime
|
||||||
if modTime.IsZero() {
|
if modTime.IsZero() {
|
||||||
modTime = time.Unix(0, 0)
|
modTime = time.Unix(0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
v7 := tw.blk.V7()
|
v7 := tw.blk.toV7()
|
||||||
v7.TypeFlag()[0] = hdr.Typeflag
|
v7.typeFlag()[0] = hdr.Typeflag
|
||||||
fmtStr(v7.Name(), hdr.Name)
|
fmtStr(v7.name(), hdr.Name)
|
||||||
fmtStr(v7.LinkName(), hdr.Linkname)
|
fmtStr(v7.linkName(), hdr.Linkname)
|
||||||
fmtNum(v7.Mode(), hdr.Mode)
|
fmtNum(v7.mode(), hdr.Mode)
|
||||||
fmtNum(v7.UID(), int64(hdr.Uid))
|
fmtNum(v7.uid(), int64(hdr.Uid))
|
||||||
fmtNum(v7.GID(), int64(hdr.Gid))
|
fmtNum(v7.gid(), int64(hdr.Gid))
|
||||||
fmtNum(v7.Size(), hdr.Size)
|
fmtNum(v7.size(), hdr.Size)
|
||||||
fmtNum(v7.ModTime(), modTime.Unix())
|
fmtNum(v7.modTime(), modTime.Unix())
|
||||||
|
|
||||||
ustar := tw.blk.USTAR()
|
ustar := tw.blk.toUSTAR()
|
||||||
fmtStr(ustar.UserName(), hdr.Uname)
|
fmtStr(ustar.userName(), hdr.Uname)
|
||||||
fmtStr(ustar.GroupName(), hdr.Gname)
|
fmtStr(ustar.groupName(), hdr.Gname)
|
||||||
fmtNum(ustar.DevMajor(), hdr.Devmajor)
|
fmtNum(ustar.devMajor(), hdr.Devmajor)
|
||||||
fmtNum(ustar.DevMinor(), hdr.Devminor)
|
fmtNum(ustar.devMinor(), hdr.Devminor)
|
||||||
|
|
||||||
return &tw.blk
|
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 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).
|
// 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 {
|
func (tw *Writer) writeRawFile(name, data string, flag byte, format Format) error {
|
||||||
tw.blk.Reset()
|
tw.blk.reset()
|
||||||
|
|
||||||
// Best effort for the filename.
|
// Best effort for the filename.
|
||||||
name = toASCII(name)
|
name = toASCII(name)
|
||||||
|
|
@ -361,15 +361,15 @@ func (tw *Writer) writeRawFile(name, data string, flag byte, format Format) erro
|
||||||
name = strings.TrimRight(name, "/")
|
name = strings.TrimRight(name, "/")
|
||||||
|
|
||||||
var f formatter
|
var f formatter
|
||||||
v7 := tw.blk.V7()
|
v7 := tw.blk.toV7()
|
||||||
v7.TypeFlag()[0] = flag
|
v7.typeFlag()[0] = flag
|
||||||
f.formatString(v7.Name(), name)
|
f.formatString(v7.name(), name)
|
||||||
f.formatOctal(v7.Mode(), 0)
|
f.formatOctal(v7.mode(), 0)
|
||||||
f.formatOctal(v7.UID(), 0)
|
f.formatOctal(v7.uid(), 0)
|
||||||
f.formatOctal(v7.GID(), 0)
|
f.formatOctal(v7.gid(), 0)
|
||||||
f.formatOctal(v7.Size(), int64(len(data))) // Must be < 8GiB
|
f.formatOctal(v7.size(), int64(len(data))) // Must be < 8GiB
|
||||||
f.formatOctal(v7.ModTime(), 0)
|
f.formatOctal(v7.modTime(), 0)
|
||||||
tw.blk.SetFormat(format)
|
tw.blk.setFormat(format)
|
||||||
if f.err != nil {
|
if f.err != nil {
|
||||||
return f.err // Only occurs if size condition is violated
|
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)
|
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
|
return fw.nb
|
||||||
}
|
}
|
||||||
func (fw regFileWriter) PhysicalRemaining() int64 {
|
|
||||||
|
// logicalRemaining implements fileState.physicalRemaining.
|
||||||
|
func (fw regFileWriter) physicalRemaining() int64 {
|
||||||
return fw.nb
|
return fw.nb
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -526,9 +529,9 @@ type sparseFileWriter struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sw *sparseFileWriter) Write(b []byte) (n int, err error) {
|
func (sw *sparseFileWriter) Write(b []byte) (n int, err error) {
|
||||||
overwrite := int64(len(b)) > sw.LogicalRemaining()
|
overwrite := int64(len(b)) > sw.logicalRemaining()
|
||||||
if overwrite {
|
if overwrite {
|
||||||
b = b[:sw.LogicalRemaining()]
|
b = b[:sw.logicalRemaining()]
|
||||||
}
|
}
|
||||||
|
|
||||||
b0 := b
|
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
|
return n, errMissData // Not possible; implies bug in validation logic
|
||||||
case err != nil:
|
case err != nil:
|
||||||
return n, err
|
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
|
return n, errUnrefData // Not possible; implies bug in validation logic
|
||||||
case overwrite:
|
case overwrite:
|
||||||
return n, ErrWriteTooLong
|
return n, ErrWriteTooLong
|
||||||
|
|
@ -578,12 +581,12 @@ func (sw *sparseFileWriter) ReadFrom(r io.Reader) (n int64, err error) {
|
||||||
|
|
||||||
var readLastByte bool
|
var readLastByte bool
|
||||||
pos0 := sw.pos
|
pos0 := sw.pos
|
||||||
for sw.LogicalRemaining() > 0 && !readLastByte && err == nil {
|
for sw.logicalRemaining() > 0 && !readLastByte && err == nil {
|
||||||
var nf int64 // Size of fragment
|
var nf int64 // Size of fragment
|
||||||
dataStart, dataEnd := sw.sp[0].Offset, sw.sp[0].endOffset()
|
dataStart, dataEnd := sw.sp[0].Offset, sw.sp[0].endOffset()
|
||||||
if sw.pos < dataStart { // In a hole fragment
|
if sw.pos < dataStart { // In a hole fragment
|
||||||
nf = dataStart - sw.pos
|
nf = dataStart - sw.pos
|
||||||
if sw.PhysicalRemaining() == 0 {
|
if sw.physicalRemaining() == 0 {
|
||||||
readLastByte = true
|
readLastByte = true
|
||||||
nf--
|
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
|
return n, errMissData // Not possible; implies bug in validation logic
|
||||||
case err != nil:
|
case err != nil:
|
||||||
return n, err
|
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
|
return n, errUnrefData // Not possible; implies bug in validation logic
|
||||||
default:
|
default:
|
||||||
return n, ensureEOF(rs)
|
return n, ensureEOF(rs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sw sparseFileWriter) LogicalRemaining() int64 {
|
func (sw sparseFileWriter) logicalRemaining() int64 {
|
||||||
return sw.sp[len(sw.sp)-1].endOffset() - sw.pos
|
return sw.sp[len(sw.sp)-1].endOffset() - sw.pos
|
||||||
}
|
}
|
||||||
func (sw sparseFileWriter) PhysicalRemaining() int64 {
|
func (sw sparseFileWriter) physicalRemaining() int64 {
|
||||||
return sw.fw.PhysicalRemaining()
|
return sw.fw.physicalRemaining()
|
||||||
}
|
}
|
||||||
|
|
||||||
// zeroWriter may only be written with NULs, otherwise it returns errWriteHole.
|
// zeroWriter may only be written with NULs, otherwise it returns errWriteHole.
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ func TestWriter(t *testing.T) {
|
||||||
testClose struct { // Close() == wantErr
|
testClose struct { // Close() == wantErr
|
||||||
wantErr error
|
wantErr error
|
||||||
}
|
}
|
||||||
testFnc interface{} // testHeader | testWrite | testReadFrom | testClose
|
testFnc any // testHeader | testWrite | testReadFrom | testClose
|
||||||
)
|
)
|
||||||
|
|
||||||
vectors := []struct {
|
vectors := []struct {
|
||||||
|
|
@ -987,11 +987,9 @@ func TestIssue12594(t *testing.T) {
|
||||||
// The prefix field should never appear in the GNU format.
|
// The prefix field should never appear in the GNU format.
|
||||||
var blk block
|
var blk block
|
||||||
copy(blk[:], b.Bytes())
|
copy(blk[:], b.Bytes())
|
||||||
prefix := string(blk.USTAR().Prefix())
|
prefix := string(blk.toUSTAR().prefix())
|
||||||
if i := strings.IndexByte(prefix, 0); i >= 0 {
|
prefix, _, _ = strings.Cut(prefix, "\x00") // Truncate at the NUL terminator
|
||||||
prefix = prefix[:i] // Truncate at the NUL terminator
|
if blk.getFormat() == FormatGNU && len(prefix) > 0 && strings.HasPrefix(name, prefix) {
|
||||||
}
|
|
||||||
if blk.GetFormat() == FormatGNU && len(prefix) > 0 && strings.HasPrefix(name, prefix) {
|
|
||||||
t.Errorf("test %d, found prefix in GNU format: %s", i, prefix)
|
t.Errorf("test %d, found prefix in GNU format: %s", i, prefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1029,11 +1027,11 @@ func TestFileWriter(t *testing.T) {
|
||||||
wantCnt int64
|
wantCnt int64
|
||||||
wantErr error
|
wantErr error
|
||||||
}
|
}
|
||||||
testRemaining struct { // LogicalRemaining() == wantLCnt, PhysicalRemaining() == wantPCnt
|
testRemaining struct { // logicalRemaining() == wantLCnt, physicalRemaining() == wantPCnt
|
||||||
wantLCnt int64
|
wantLCnt int64
|
||||||
wantPCnt int64
|
wantPCnt int64
|
||||||
}
|
}
|
||||||
testFnc interface{} // testWrite | testReadFrom | testRemaining
|
testFnc any // testWrite | testReadFrom | testRemaining
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
|
@ -1046,7 +1044,7 @@ func TestFileWriter(t *testing.T) {
|
||||||
sph sparseHoles
|
sph sparseHoles
|
||||||
size int64
|
size int64
|
||||||
}
|
}
|
||||||
fileMaker interface{} // makeReg | makeSparse
|
fileMaker any // makeReg | makeSparse
|
||||||
)
|
)
|
||||||
|
|
||||||
vectors := []struct {
|
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))
|
t.Errorf("test %d.%d, expected %d more operations", i, j, len(f.ops))
|
||||||
}
|
}
|
||||||
case testRemaining:
|
case testRemaining:
|
||||||
if got := fw.LogicalRemaining(); got != tf.wantLCnt {
|
if got := fw.logicalRemaining(); got != tf.wantLCnt {
|
||||||
t.Errorf("test %d.%d, LogicalRemaining() = %d, want %d", i, j, got, tf.wantLCnt)
|
t.Errorf("test %d.%d, logicalRemaining() = %d, want %d", i, j, got, tf.wantLCnt)
|
||||||
}
|
}
|
||||||
if got := fw.PhysicalRemaining(); got != tf.wantPCnt {
|
if got := fw.physicalRemaining(); got != tf.wantPCnt {
|
||||||
t.Errorf("test %d.%d, PhysicalRemaining() = %d, want %d", i, j, got, tf.wantPCnt)
|
t.Errorf("test %d.%d, physicalRemaining() = %d, want %d", i, j, got, tf.wantPCnt)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
t.Fatalf("test %d.%d, unknown test operation: %T", i, j, tf)
|
t.Fatalf("test %d.%d, unknown test operation: %T", i, j, tf)
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
f.readDataDescriptor()
|
|
||||||
z.File = append(z.File, f)
|
z.File = append(z.File, f)
|
||||||
}
|
}
|
||||||
if uint16(len(z.File)) != uint16(end.directoryRecords) { // only compare 16 bits here
|
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
|
return nil, ErrAlgorithm
|
||||||
}
|
}
|
||||||
var rc io.ReadCloser = dcomp(r)
|
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 = &checksumReader{
|
||||||
rc: rc,
|
rc: rc,
|
||||||
hash: crc32.NewIEEE(),
|
hash: crc32.NewIEEE(),
|
||||||
f: f,
|
f: f,
|
||||||
|
desr: desr,
|
||||||
}
|
}
|
||||||
return rc, nil
|
return rc, nil
|
||||||
}
|
}
|
||||||
|
|
@ -205,49 +209,13 @@ func (f *File) OpenRaw() (io.Reader, error) {
|
||||||
return r, nil
|
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 {
|
type checksumReader struct {
|
||||||
rc io.ReadCloser
|
rc io.ReadCloser
|
||||||
hash hash.Hash32
|
hash hash.Hash32
|
||||||
nread uint64 // number of bytes read so far
|
nread uint64 // number of bytes read so far
|
||||||
f *File
|
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) {
|
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 {
|
if r.nread != r.f.UncompressedSize64 {
|
||||||
return 0, io.ErrUnexpectedEOF
|
return 0, io.ErrUnexpectedEOF
|
||||||
}
|
}
|
||||||
if r.f.hasDataDescriptor() {
|
if r.desr != nil {
|
||||||
if r.f.descErr != nil {
|
if err1 := readDataDescriptor(r.desr, r.f); err1 != nil {
|
||||||
if r.f.descErr == io.EOF {
|
if err1 == io.EOF {
|
||||||
err = io.ErrUnexpectedEOF
|
err = io.ErrUnexpectedEOF
|
||||||
} else {
|
} else {
|
||||||
err = r.f.descErr
|
err = err1
|
||||||
}
|
}
|
||||||
} else if r.hash.Sum32() != r.f.CRC32 {
|
} else if r.hash.Sum32() != r.f.CRC32 {
|
||||||
err = ErrChecksum
|
err = ErrChecksum
|
||||||
|
|
@ -485,10 +453,8 @@ parseExtras:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func readDataDescriptor(r io.Reader, zip64 bool) (*dataDescriptor, error) {
|
func readDataDescriptor(r io.Reader, f *File) error {
|
||||||
// Create enough space for the largest possible size
|
var buf [dataDescriptorLen]byte
|
||||||
var buf [dataDescriptor64Len]byte
|
|
||||||
|
|
||||||
// The spec says: "Although not originally assigned a
|
// The spec says: "Although not originally assigned a
|
||||||
// signature, the value 0x08074b50 has commonly been adopted
|
// signature, the value 0x08074b50 has commonly been adopted
|
||||||
// as a signature value for the data descriptor record.
|
// 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
|
// descriptors and should account for either case when reading
|
||||||
// ZIP files to ensure compatibility."
|
// 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 {
|
if _, err := io.ReadFull(r, buf[:4]); err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
off := 0
|
off := 0
|
||||||
maybeSig := readBuf(buf[:4])
|
maybeSig := readBuf(buf[:4])
|
||||||
|
|
@ -508,28 +475,21 @@ func readDataDescriptor(r io.Reader, zip64 bool) (*dataDescriptor, error) {
|
||||||
// bytes.
|
// bytes.
|
||||||
off += 4
|
off += 4
|
||||||
}
|
}
|
||||||
|
if _, err := io.ReadFull(r, buf[off:12]); err != nil {
|
||||||
end := dataDescriptorLen - 4
|
return err
|
||||||
if zip64 {
|
|
||||||
end = dataDescriptor64Len - 4
|
|
||||||
}
|
}
|
||||||
if _, err := io.ReadFull(r, buf[off:end]); err != nil {
|
b := readBuf(buf[:12])
|
||||||
return nil, err
|
if b.uint32() != f.CRC32 {
|
||||||
}
|
return ErrChecksum
|
||||||
b := readBuf(buf[:end])
|
|
||||||
|
|
||||||
out := &dataDescriptor{
|
|
||||||
crc32: b.uint32(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if zip64 {
|
// The two sizes that follow here can be either 32 bits or 64 bits
|
||||||
out.compressedSize = b.uint64()
|
// but the spec is not very clear on this and different
|
||||||
out.uncompressedSize = b.uint64()
|
// interpretations has been made causing incompatibilities. We
|
||||||
} else {
|
// already have the sizes from the central directory so we can
|
||||||
out.compressedSize = uint64(b.uint32())
|
// just ignore these.
|
||||||
out.uncompressedSize = uint64(b.uint32())
|
|
||||||
}
|
return nil
|
||||||
return out, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func readDirectoryEnd(r io.ReaderAt, size int64) (dir *directoryEnd, err error) {
|
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) Mode() fs.FileMode { return fs.ModeDir | 0555 }
|
||||||
func (f *fileListEntry) Type() fs.FileMode { return fs.ModeDir }
|
func (f *fileListEntry) Type() fs.FileMode { return fs.ModeDir }
|
||||||
func (f *fileListEntry) IsDir() bool { return true }
|
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 {
|
func (f *fileListEntry) ModTime() time.Time {
|
||||||
if f.file == nil {
|
if f.file == nil {
|
||||||
|
|
@ -741,6 +701,9 @@ func (r *Reader) initFileList() {
|
||||||
for _, file := range r.File {
|
for _, file := range r.File {
|
||||||
isDir := len(file.Name) > 0 && file.Name[len(file.Name)-1] == '/'
|
isDir := len(file.Name) > 0 && file.Name[len(file.Name)-1] == '/'
|
||||||
name := toValidName(file.Name)
|
name := toValidName(file.Name)
|
||||||
|
if name == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
for dir := path.Dir(name); dir != "."; dir = path.Dir(dir) {
|
for dir := path.Dir(name); dir != "."; dir = path.Dir(dir) {
|
||||||
dirs[dir] = true
|
dirs[dir] = true
|
||||||
}
|
}
|
||||||
|
|
@ -782,8 +745,11 @@ func fileEntryLess(x, y string) bool {
|
||||||
func (r *Reader) Open(name string) (fs.File, error) {
|
func (r *Reader) Open(name string) (fs.File, error) {
|
||||||
r.initFileList()
|
r.initFileList()
|
||||||
|
|
||||||
|
if !fs.ValidPath(name) {
|
||||||
|
return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrInvalid}
|
||||||
|
}
|
||||||
e := r.openLookup(name)
|
e := r.openLookup(name)
|
||||||
if e == nil || !fs.ValidPath(name) {
|
if e == nil {
|
||||||
return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrNotExist}
|
return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrNotExist}
|
||||||
}
|
}
|
||||||
if e.isDir {
|
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) {
|
func split(name string) (dir, elem string, isDir bool) {
|
||||||
if name[len(name)-1] == '/' {
|
if len(name) > 0 && name[len(name)-1] == '/' {
|
||||||
isDir = true
|
isDir = true
|
||||||
name = name[:len(name)-1]
|
name = name[:len(name)-1]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
@ -1202,127 +1203,14 @@ func TestCVE202127919(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Error reading file: %v", err)
|
t.Errorf("Error reading file: %v", err)
|
||||||
}
|
}
|
||||||
}
|
if len(r.File) != 1 {
|
||||||
|
t.Fatalf("No entries in the file list")
|
||||||
func TestReadDataDescriptor(t *testing.T) {
|
}
|
||||||
tests := []struct {
|
if r.File[0].Name != "../test.txt" {
|
||||||
desc string
|
t.Errorf("Unexpected entry name: %s", r.File[0].Name)
|
||||||
in []byte
|
}
|
||||||
zip64 bool
|
if _, err := r.File[0].Open(); err != nil {
|
||||||
want *dataDescriptor
|
t.Errorf("Error opening file: %v", err)
|
||||||
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)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1402,3 +1290,121 @@ func TestCVE202139293(t *testing.T) {
|
||||||
t.Fatalf("unexpected error, got: %v, want: %v", err, ErrFormat)
|
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) Mode() fs.FileMode { return fi.fh.Mode() }
|
||||||
func (fi headerFileInfo) Type() fs.FileMode { return fi.fh.Mode().Type() }
|
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 }
|
func (fi headerFileInfo) Info() (fs.FileInfo, error) { return fi, nil }
|
||||||
|
|
||||||
|
|
@ -390,11 +390,3 @@ func unixModeToFileMode(m uint32) fs.FileMode {
|
||||||
}
|
}
|
||||||
return mode
|
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))
|
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")
|
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
|
// Reset discards any buffered data, resets all state, and switches
|
||||||
// the buffered reader to read from r.
|
// 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) {
|
func (b *Reader) Reset(r io.Reader) {
|
||||||
|
if b.buf == nil {
|
||||||
|
b.buf = make([]byte, defaultBufSize)
|
||||||
|
}
|
||||||
b.reset(b.buf, r)
|
b.reset(b.buf, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -168,6 +173,10 @@ func (b *Reader) Discard(n int) (discarded int, err error) {
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b.lastByte = -1
|
||||||
|
b.lastRuneSize = -1
|
||||||
|
|
||||||
remain := n
|
remain := n
|
||||||
for {
|
for {
|
||||||
skip := b.Buffered()
|
skip := b.Buffered()
|
||||||
|
|
@ -235,6 +244,8 @@ func (b *Reader) Read(p []byte) (n int, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy as much as we can
|
// 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])
|
n = copy(p, b.buf[b.r:b.w])
|
||||||
b.r += n
|
b.r += n
|
||||||
b.lastByte = int(b.buf[b.r-1])
|
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 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
|
// UnreadByte returns an error if the most recent method called on the
|
||||||
// Reader was not a read operation. Notably, Peek is not considered a
|
// Reader was not a read operation. Notably, Peek, Discard, and WriteTo are not
|
||||||
// read operation.
|
// considered read operations.
|
||||||
func (b *Reader) UnreadByte() error {
|
func (b *Reader) UnreadByte() error {
|
||||||
if b.lastByte < 0 || b.r == 0 && b.w > 0 {
|
if b.lastByte < 0 || b.r == 0 && b.w > 0 {
|
||||||
return ErrInvalidUnreadByte
|
return ErrInvalidUnreadByte
|
||||||
|
|
@ -497,6 +508,9 @@ func (b *Reader) ReadString(delim byte) (string, error) {
|
||||||
// If the underlying reader supports the WriteTo method,
|
// If the underlying reader supports the WriteTo method,
|
||||||
// this calls the underlying WriteTo without buffering.
|
// this calls the underlying WriteTo without buffering.
|
||||||
func (b *Reader) WriteTo(w io.Writer) (n int64, err error) {
|
func (b *Reader) WriteTo(w io.Writer) (n int64, err error) {
|
||||||
|
b.lastByte = -1
|
||||||
|
b.lastRuneSize = -1
|
||||||
|
|
||||||
n, err = b.writeBuf(w)
|
n, err = b.writeBuf(w)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
|
@ -581,6 +595,8 @@ func NewWriterSize(w io.Writer, size int) *Writer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWriter returns a new Writer whose buffer has the default size.
|
// 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 {
|
func NewWriter(w io.Writer) *Writer {
|
||||||
return NewWriterSize(w, defaultBufSize)
|
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
|
// Reset discards any unflushed buffered data, clears any error, and
|
||||||
// resets b to write its output to w.
|
// 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) {
|
func (b *Writer) Reset(w io.Writer) {
|
||||||
|
if b.buf == nil {
|
||||||
|
b.buf = make([]byte, defaultBufSize)
|
||||||
|
}
|
||||||
b.err = nil
|
b.err = nil
|
||||||
b.n = 0
|
b.n = 0
|
||||||
b.wr = w
|
b.wr = w
|
||||||
|
|
@ -623,6 +644,14 @@ func (b *Writer) Flush() error {
|
||||||
// Available returns how many bytes are unused in the buffer.
|
// Available returns how many bytes are unused in the buffer.
|
||||||
func (b *Writer) Available() int { return len(b.buf) - b.n }
|
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.
|
// Buffered returns the number of bytes that have been written into the current buffer.
|
||||||
func (b *Writer) Buffered() int { return b.n }
|
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
|
// ReadFrom implements io.ReaderFrom. If the underlying writer
|
||||||
// supports the ReadFrom method, and b has no buffered data yet,
|
// supports the ReadFrom method, this calls the underlying ReadFrom.
|
||||||
// this calls the underlying ReadFrom without buffering.
|
// 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) {
|
func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) {
|
||||||
if b.err != nil {
|
if b.err != nil {
|
||||||
return 0, b.err
|
return 0, b.err
|
||||||
}
|
}
|
||||||
if b.Buffered() == 0 {
|
readerFrom, readerFromOK := b.wr.(io.ReaderFrom)
|
||||||
if w, ok := b.wr.(io.ReaderFrom); ok {
|
|
||||||
n, err = w.ReadFrom(r)
|
|
||||||
b.err = err
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var m int
|
var m int
|
||||||
for {
|
for {
|
||||||
if b.Available() == 0 {
|
if b.Available() == 0 {
|
||||||
|
|
@ -740,6 +764,12 @@ func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) {
|
||||||
return n, err1
|
return n, err1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if readerFromOK && b.Buffered() == 0 {
|
||||||
|
nn, err := readerFrom.ReadFrom(r)
|
||||||
|
b.err = err
|
||||||
|
n += nn
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
nr := 0
|
nr := 0
|
||||||
for nr < maxConsecutiveEmptyReads {
|
for nr < maxConsecutiveEmptyReads {
|
||||||
m, err = r.Read(b.buf[b.n:])
|
m, err = r.Read(b.buf[b.n:])
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"math/rand"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"testing/iotest"
|
"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) {
|
func TestUnreadByte(t *testing.T) {
|
||||||
segments := []string{"Hello, ", "world"}
|
segments := []string{"Hello, ", "world"}
|
||||||
r := NewReader(&StringReader{data: segments})
|
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.
|
// Check that write errors are returned properly.
|
||||||
|
|
||||||
type errorWriterTest struct {
|
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) {
|
func TestReadZero(t *testing.T) {
|
||||||
for _, size := range []int{100, 2} {
|
for _, size := range []int{100, 2} {
|
||||||
t.Run(fmt.Sprintf("bufsize=%d", size), func(t *testing.T) {
|
t.Run(fmt.Sprintf("bufsize=%d", size), func(t *testing.T) {
|
||||||
|
|
@ -1312,6 +1427,7 @@ func TestReaderReset(t *testing.T) {
|
||||||
if string(buf) != "foo" {
|
if string(buf) != "foo" {
|
||||||
t.Errorf("buf = %q; want foo", buf)
|
t.Errorf("buf = %q; want foo", buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
r.Reset(strings.NewReader("bar bar"))
|
r.Reset(strings.NewReader("bar bar"))
|
||||||
all, err := io.ReadAll(r)
|
all, err := io.ReadAll(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -1320,12 +1436,23 @@ func TestReaderReset(t *testing.T) {
|
||||||
if string(all) != "bar bar" {
|
if string(all) != "bar bar" {
|
||||||
t.Errorf("ReadAll = %q; want bar bar", all)
|
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) {
|
func TestWriterReset(t *testing.T) {
|
||||||
var buf1, buf2 bytes.Buffer
|
var buf1, buf2, buf3 bytes.Buffer
|
||||||
w := NewWriter(&buf1)
|
w := NewWriter(&buf1)
|
||||||
w.WriteString("foo")
|
w.WriteString("foo")
|
||||||
|
|
||||||
w.Reset(&buf2) // and not flushed
|
w.Reset(&buf2) // and not flushed
|
||||||
w.WriteString("bar")
|
w.WriteString("bar")
|
||||||
w.Flush()
|
w.Flush()
|
||||||
|
|
@ -1335,6 +1462,17 @@ func TestWriterReset(t *testing.T) {
|
||||||
if buf2.String() != "bar" {
|
if buf2.String() != "bar" {
|
||||||
t.Errorf("buf2 = %q; want bar", buf2.String())
|
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) {
|
func TestReaderDiscard(t *testing.T) {
|
||||||
|
|
@ -1382,7 +1520,7 @@ func TestReaderDiscard(t *testing.T) {
|
||||||
wantBuffered: 0,
|
wantBuffered: 0,
|
||||||
},
|
},
|
||||||
// Any error from filling shouldn't show up until we
|
// 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.
|
// as an error, but test that we don't see the error from Discard.
|
||||||
{
|
{
|
||||||
name: "fill error, discard less",
|
name: "fill error, discard less",
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,18 @@ func ExampleWriter() {
|
||||||
// Output: Hello, world!
|
// 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.
|
// The simplest use of a Scanner, to read standard input as a set of lines.
|
||||||
func ExampleScanner_lines() {
|
func ExampleScanner_lines() {
|
||||||
scanner := bufio.NewScanner(os.Stdin)
|
scanner := bufio.NewScanner(os.Stdin)
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,16 @@ type byte = uint8
|
||||||
// used, by convention, to distinguish character values from integer values.
|
// used, by convention, to distinguish character values from integer values.
|
||||||
type rune = int32
|
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
|
// iota is a predeclared identifier representing the untyped integer ordinal
|
||||||
// number of the current const specification in a (usually parenthesized)
|
// number of the current const specification in a (usually parenthesized)
|
||||||
// const declaration. It is zero-indexed.
|
// 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
|
// that point, the program is terminated with a non-zero exit code. This
|
||||||
// termination sequence is called panicking and can be controlled by the
|
// termination sequence is called panicking and can be controlled by the
|
||||||
// built-in function recover.
|
// 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
|
// The recover built-in function allows a program to manage behavior of a
|
||||||
// panicking goroutine. Executing a call to recover inside a deferred
|
// 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
|
// panicking, or if the argument supplied to panic was nil, recover returns
|
||||||
// nil. Thus the return value from recover reports whether the goroutine is
|
// nil. Thus the return value from recover reports whether the goroutine is
|
||||||
// panicking.
|
// panicking.
|
||||||
func recover() interface{}
|
func recover() any
|
||||||
|
|
||||||
// The print built-in function formats its arguments in an
|
// The print built-in function formats its arguments in an
|
||||||
// implementation-specific way and writes the result to standard error.
|
// implementation-specific way and writes the result to standard error.
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
//
|
//
|
||||||
//go:build linux
|
//go:build linux
|
||||||
// +build linux
|
|
||||||
|
|
||||||
package bytes_test
|
package bytes_test
|
||||||
|
|
||||||
|
|
@ -66,7 +65,11 @@ func TestIndexByteNearPageBoundary(t *testing.T) {
|
||||||
|
|
||||||
func TestIndexNearPageBoundary(t *testing.T) {
|
func TestIndexNearPageBoundary(t *testing.T) {
|
||||||
t.Parallel()
|
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)
|
b := dangerousSlice(t)
|
||||||
if len(b) > 256 {
|
if len(b) > 256 {
|
||||||
// Only worry about when we're near the end of a page.
|
// 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
|
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.
|
// 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.
|
// A nil argument is equivalent to an empty slice.
|
||||||
func Compare(a, b []byte) int {
|
func Compare(a, b []byte) int {
|
||||||
return bytealg.Compare(a, b)
|
return bytealg.Compare(a, b)
|
||||||
|
|
@ -699,7 +699,7 @@ func ToValidUTF8(s, replacement []byte) []byte {
|
||||||
if c < utf8.RuneSelf {
|
if c < utf8.RuneSelf {
|
||||||
i++
|
i++
|
||||||
invalid = false
|
invalid = false
|
||||||
b = append(b, byte(c))
|
b = append(b, c)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
_, wid := utf8.DecodeRune(s[i:])
|
_, 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
|
// Title treats s as UTF-8-encoded bytes and returns a copy with all Unicode letters that begin
|
||||||
// words mapped to their title case.
|
// 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 {
|
func Title(s []byte) []byte {
|
||||||
// Use a closure here to remember state.
|
// Use a closure here to remember state.
|
||||||
// Hackish but effective. Depends on Map scanning in order and calling
|
// 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
|
// 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,
|
// 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.
|
// 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
|
type asciiSet [8]uint32
|
||||||
|
|
||||||
// makeASCIISet creates a set of ASCII characters and reports whether all
|
// 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 {
|
if c >= utf8.RuneSelf {
|
||||||
return as, false
|
return as, false
|
||||||
}
|
}
|
||||||
as[c>>5] |= 1 << uint(c&31)
|
as[c/32] |= 1 << (c % 32)
|
||||||
}
|
}
|
||||||
return as, true
|
return as, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// contains reports whether c is inside the set.
|
// contains reports whether c is inside the set.
|
||||||
func (as *asciiSet) contains(c byte) bool {
|
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 {
|
// containsRune is a simplified version of strings.ContainsRune
|
||||||
if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
|
// to avoid importing the strings package.
|
||||||
return func(r rune) bool {
|
// We avoid bytes.ContainsRune to avoid allocating a temporary copy of s.
|
||||||
return r == rune(cutset[0])
|
func containsRune(s string, r rune) bool {
|
||||||
|
for _, c := range s {
|
||||||
|
if c == r {
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if as, isASCII := makeASCIISet(cutset); isASCII {
|
return false
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trim returns a subslice of s by slicing off all leading and
|
// Trim returns a subslice of s by slicing off all leading and
|
||||||
// trailing UTF-8-encoded code points contained in cutset.
|
// trailing UTF-8-encoded code points contained in cutset.
|
||||||
func Trim(s []byte, cutset string) []byte {
|
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
|
// TrimLeft returns a subslice of s by slicing off all leading
|
||||||
// UTF-8-encoded code points contained in cutset.
|
// UTF-8-encoded code points contained in cutset.
|
||||||
func TrimLeft(s []byte, cutset string) []byte {
|
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
|
// TrimRight returns a subslice of s by slicing off all trailing
|
||||||
// UTF-8-encoded code points that are contained in cutset.
|
// UTF-8-encoded code points that are contained in cutset.
|
||||||
func TrimRight(s []byte, cutset string) []byte {
|
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
|
// TrimSpace returns a subslice of s by slicing off all leading and
|
||||||
|
|
@ -1174,3 +1257,16 @@ func Index(s, sep []byte) int {
|
||||||
}
|
}
|
||||||
return -1
|
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", ""},
|
{"TrimLeft", "abba", "ab", ""},
|
||||||
{"TrimRight", "abba", "ab", ""},
|
{"TrimRight", "abba", "ab", ""},
|
||||||
{"TrimLeft", "abba", "a", "bba"},
|
{"TrimLeft", "abba", "a", "bba"},
|
||||||
|
{"TrimLeft", "abba", "b", "abba"},
|
||||||
{"TrimRight", "abba", "a", "abb"},
|
{"TrimRight", "abba", "a", "abb"},
|
||||||
|
{"TrimRight", "abba", "b", "abba"},
|
||||||
{"Trim", "<tag>", "<>", "tag"},
|
{"Trim", "<tag>", "<>", "tag"},
|
||||||
{"Trim", "* listitem", " *", "listitem"},
|
{"Trim", "* listitem", " *", "listitem"},
|
||||||
{"Trim", `"quote"`, `"`, "quote"},
|
{"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) {
|
func TestBufferGrowNegative(t *testing.T) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err == nil {
|
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) {
|
func BenchmarkIndexPeriodic(b *testing.B) {
|
||||||
key := []byte{1, 1}
|
key := []byte{1, 1}
|
||||||
for _, skip := range [...]int{2, 4, 8, 16, 32, 64} {
|
for _, skip := range [...]int{2, 4, 8, 16, 32, 64} {
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,16 @@ func ExampleBuffer_Bytes() {
|
||||||
// Output: hello world
|
// 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() {
|
func ExampleBuffer_Grow() {
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
b.Grow(64)
|
b.Grow(64)
|
||||||
|
|
@ -54,6 +64,52 @@ func ExampleBuffer_Len() {
|
||||||
// Output: 5
|
// 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() {
|
func ExampleCompare() {
|
||||||
// Interpret Compare's result by comparing it to zero.
|
// Interpret Compare's result by comparing it to zero.
|
||||||
var a, b []byte
|
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() {
|
func ExampleContains() {
|
||||||
fmt.Println(bytes.Contains([]byte("seafood"), []byte("foo")))
|
fmt.Println(bytes.Contains([]byte("seafood"), []byte("foo")))
|
||||||
fmt.Println(bytes.Contains([]byte("seafood"), []byte("bar")))
|
fmt.Println(bytes.Contains([]byte("seafood"), []byte("bar")))
|
||||||
|
|
@ -168,6 +194,22 @@ func ExampleCount() {
|
||||||
// 5
|
// 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() {
|
func ExampleEqual() {
|
||||||
fmt.Println(bytes.Equal([]byte("Go"), []byte("Go")))
|
fmt.Println(bytes.Equal([]byte("Go"), []byte("Go")))
|
||||||
fmt.Println(bytes.Equal([]byte("Go"), []byte("C++")))
|
fmt.Println(bytes.Equal([]byte("Go"), []byte("C++")))
|
||||||
|
|
@ -181,6 +223,19 @@ func ExampleEqualFold() {
|
||||||
// Output: true
|
// 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() {
|
func ExampleHasPrefix() {
|
||||||
fmt.Println(bytes.HasPrefix([]byte("Gopher"), []byte("Go")))
|
fmt.Println(bytes.HasPrefix([]byte("Gopher"), []byte("Go")))
|
||||||
fmt.Println(bytes.HasPrefix([]byte("Gopher"), []byte("C")))
|
fmt.Println(bytes.HasPrefix([]byte("Gopher"), []byte("C")))
|
||||||
|
|
@ -246,6 +301,12 @@ func ExampleIndexRune() {
|
||||||
// -1
|
// -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleJoin() {
|
||||||
|
s := [][]byte{[]byte("foo"), []byte("bar"), []byte("baz")}
|
||||||
|
fmt.Printf("%s", bytes.Join(s, []byte(", ")))
|
||||||
|
// Output: foo, bar, baz
|
||||||
|
}
|
||||||
|
|
||||||
func ExampleLastIndex() {
|
func ExampleLastIndex() {
|
||||||
fmt.Println(bytes.Index([]byte("go gopher"), []byte("go")))
|
fmt.Println(bytes.Index([]byte("go gopher"), []byte("go")))
|
||||||
fmt.Println(bytes.LastIndex([]byte("go gopher"), []byte("go")))
|
fmt.Println(bytes.LastIndex([]byte("go gopher"), []byte("go")))
|
||||||
|
|
@ -286,10 +347,12 @@ func ExampleLastIndexFunc() {
|
||||||
// -1
|
// -1
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExampleJoin() {
|
func ExampleReader_Len() {
|
||||||
s := [][]byte{[]byte("foo"), []byte("bar"), []byte("baz")}
|
fmt.Println(bytes.NewReader([]byte("Hi!")).Len())
|
||||||
fmt.Printf("%s", bytes.Join(s, []byte(", ")))
|
fmt.Println(bytes.NewReader([]byte("こんにちは!")).Len())
|
||||||
// Output: foo, bar, baz
|
// Output:
|
||||||
|
// 3
|
||||||
|
// 16
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExampleRepeat() {
|
func ExampleRepeat() {
|
||||||
|
|
@ -399,20 +462,6 @@ func ExampleTrimFunc() {
|
||||||
// go-gopher!
|
// 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() {
|
func ExampleTrimLeft() {
|
||||||
fmt.Print(string(bytes.TrimLeft([]byte("453gopher8257"), "0123456789")))
|
fmt.Print(string(bytes.TrimLeft([]byte("453gopher8257"), "0123456789")))
|
||||||
// Output:
|
// Output:
|
||||||
|
|
@ -429,11 +478,28 @@ func ExampleTrimLeftFunc() {
|
||||||
// go-gopher!567
|
// 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() {
|
func ExampleTrimSpace() {
|
||||||
fmt.Printf("%s", bytes.TrimSpace([]byte(" \t\n a lone gopher \n\t\r\n")))
|
fmt.Printf("%s", bytes.TrimSpace([]byte(" \t\n a lone gopher \n\t\r\n")))
|
||||||
// Output: a lone gopher
|
// 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() {
|
func ExampleTrimRight() {
|
||||||
fmt.Print(string(bytes.TrimRight([]byte("453gopher8257"), "0123456789")))
|
fmt.Print(string(bytes.TrimRight([]byte("453gopher8257"), "0123456789")))
|
||||||
// Output:
|
// Output:
|
||||||
|
|
@ -450,21 +516,6 @@ func ExampleTrimRightFunc() {
|
||||||
// 1234go-gopher!
|
// 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() {
|
func ExampleToLower() {
|
||||||
fmt.Printf("%s", bytes.ToLower([]byte("Gopher")))
|
fmt.Printf("%s", bytes.ToLower([]byte("Gopher")))
|
||||||
// Output: gopher
|
// Output: gopher
|
||||||
|
|
@ -480,10 +531,17 @@ func ExampleToLowerSpecial() {
|
||||||
// ToLower : ahoj vývojári golang
|
// ToLower : ahoj vývojári golang
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExampleReader_Len() {
|
func ExampleToUpper() {
|
||||||
fmt.Println(bytes.NewReader([]byte("Hi!")).Len())
|
fmt.Printf("%s", bytes.ToUpper([]byte("Gopher")))
|
||||||
fmt.Println(bytes.NewReader([]byte("こんにちは!")).Len())
|
// Output: GOPHER
|
||||||
// Output:
|
}
|
||||||
// 3
|
|
||||||
// 16
|
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
|
off int64
|
||||||
n int
|
n int
|
||||||
want string
|
want string
|
||||||
wanterr interface{}
|
wanterr any
|
||||||
}{
|
}{
|
||||||
{0, 10, "0123456789", nil},
|
{0, 10, "0123456789", nil},
|
||||||
{1, 10, "123456789", io.EOF},
|
{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
|
// everything else just recurs
|
||||||
default:
|
default:
|
||||||
error_(token.NoPos, "unexpected type %T in walk", x)
|
f.walkUnexpected(x, context, visit)
|
||||||
panic("unexpected type")
|
|
||||||
|
|
||||||
case nil:
|
case nil:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
}
|
||||||
|
|
@ -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"
|
"internal/xcoff"
|
||||||
"math"
|
"math"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"cmd/internal/quoted"
|
||||||
)
|
)
|
||||||
|
|
||||||
var debugDefine = flag.Bool("debug-define", false, "print relevant #defines")
|
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())
|
stderr = p.gccErrors(b.Bytes())
|
||||||
}
|
}
|
||||||
if stderr == "" {
|
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
|
completed := false
|
||||||
|
|
@ -475,7 +478,7 @@ func (p *Package) guessKinds(f *File) []*Name {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !completed {
|
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 {
|
for i, n := range names {
|
||||||
|
|
@ -506,7 +509,7 @@ func (p *Package) guessKinds(f *File) []*Name {
|
||||||
// to users debugging preamble mistakes. See issue 8442.
|
// to users debugging preamble mistakes. See issue 8442.
|
||||||
preambleErrors := p.gccErrors([]byte(f.Preamble))
|
preambleErrors := p.gccErrors([]byte(f.Preamble))
|
||||||
if len(preambleErrors) > 0 {
|
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")
|
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)},
|
Args: []ast.Expr{getNewIdent(name.Mangle)},
|
||||||
}
|
}
|
||||||
case "type":
|
case "type":
|
||||||
// Okay - might be new(T)
|
// Okay - might be new(T), T(x), Generic[T], etc.
|
||||||
if r.Name.Type == nil {
|
if r.Name.Type == nil {
|
||||||
error_(r.Pos(), "expression C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
|
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)
|
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
|
// It uses $CC if set, or else $GCC, or else the compiler recorded
|
||||||
// during the initial build as defaultCC.
|
// during the initial build as defaultCC.
|
||||||
// defaultCC is defined in zdefaultcc.go, written by cmd/dist.
|
// 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.
|
// Use $CC if set, since that's what the build uses.
|
||||||
if ret := strings.Fields(os.Getenv("CC")); len(ret) > 0 {
|
value := os.Getenv("CC")
|
||||||
return ret
|
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 value == "" {
|
||||||
if ret := strings.Fields(os.Getenv("GCC")); len(ret) > 0 {
|
value = defaultCC(goos, goarch)
|
||||||
return ret
|
|
||||||
}
|
}
|
||||||
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".
|
// 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
|
// gccCmd returns the gcc command line to use for compiling
|
||||||
// the input.
|
// the input.
|
||||||
func (p *Package) gccCmd() []string {
|
func (p *Package) gccCmd() []string {
|
||||||
c := append(p.gccBaseCmd(),
|
c := append(gccBaseCmd,
|
||||||
"-w", // no warnings
|
"-w", // no warnings
|
||||||
"-Wno-error", // warnings are not errors
|
"-Wno-error", // warnings are not errors
|
||||||
"-o"+gccTmp(), // write object to tmp
|
"-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
|
// #defines that gcc encountered while processing the input
|
||||||
// and its included files.
|
// and its included files.
|
||||||
func (p *Package) gccDefines(stdin []byte) string {
|
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()...)
|
base = append(base, p.gccMachine()...)
|
||||||
stdout, _ := runGcc(stdin, append(append(base, p.GccOptions...), "-"))
|
stdout, _ := runGcc(stdin, append(append(base, p.GccOptions...), "-"))
|
||||||
return stdout
|
return stdout
|
||||||
|
|
@ -2111,6 +2131,9 @@ type typeConv struct {
|
||||||
// Type names X for which there exists an XGetTypeID function with type func() CFTypeID.
|
// Type names X for which there exists an XGetTypeID function with type func() CFTypeID.
|
||||||
getTypeIDs map[string]bool
|
getTypeIDs map[string]bool
|
||||||
|
|
||||||
|
// badStructs contains C structs that should be marked NotInHeap.
|
||||||
|
notInHeapStructs map[string]bool
|
||||||
|
|
||||||
// Predeclared types.
|
// Predeclared types.
|
||||||
bool ast.Expr
|
bool ast.Expr
|
||||||
byte ast.Expr // denotes padding
|
byte ast.Expr // denotes padding
|
||||||
|
|
@ -2122,6 +2145,7 @@ type typeConv struct {
|
||||||
string ast.Expr
|
string ast.Expr
|
||||||
goVoid ast.Expr // _Ctype_void, denotes C's void
|
goVoid ast.Expr // _Ctype_void, denotes C's void
|
||||||
goVoidPtr ast.Expr // unsafe.Pointer or *byte
|
goVoidPtr ast.Expr // unsafe.Pointer or *byte
|
||||||
|
goVoidPtrNoHeap ast.Expr // *_Ctype_void_notinheap, like goVoidPtr but marked NotInHeap
|
||||||
|
|
||||||
ptrSize int64
|
ptrSize int64
|
||||||
intSize int64
|
intSize int64
|
||||||
|
|
@ -2145,6 +2169,7 @@ func (c *typeConv) Init(ptrSize, intSize int64) {
|
||||||
c.m = make(map[string]*Type)
|
c.m = make(map[string]*Type)
|
||||||
c.ptrs = make(map[string][]*Type)
|
c.ptrs = make(map[string][]*Type)
|
||||||
c.getTypeIDs = make(map[string]bool)
|
c.getTypeIDs = make(map[string]bool)
|
||||||
|
c.notInHeapStructs = make(map[string]bool)
|
||||||
c.bool = c.Ident("bool")
|
c.bool = c.Ident("bool")
|
||||||
c.byte = c.Ident("byte")
|
c.byte = c.Ident("byte")
|
||||||
c.int8 = c.Ident("int8")
|
c.int8 = c.Ident("int8")
|
||||||
|
|
@ -2163,6 +2188,7 @@ func (c *typeConv) Init(ptrSize, intSize int64) {
|
||||||
c.void = c.Ident("void")
|
c.void = c.Ident("void")
|
||||||
c.string = c.Ident("string")
|
c.string = c.Ident("string")
|
||||||
c.goVoid = c.Ident("_Ctype_void")
|
c.goVoid = c.Ident("_Ctype_void")
|
||||||
|
c.goVoidPtrNoHeap = c.Ident("*_Ctype_void_notinheap")
|
||||||
|
|
||||||
// Normally cgo translates void* to unsafe.Pointer,
|
// Normally cgo translates void* to unsafe.Pointer,
|
||||||
// but for historical reasons -godefs uses *byte instead.
|
// 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.C = &TypeRepr{"struct %s", []interface{}{tag}}
|
||||||
}
|
}
|
||||||
tt.Go = g
|
tt.Go = g
|
||||||
|
tt.NotInHeap = c.notInHeapStructs[tag]
|
||||||
typedef[name.Name] = &tt
|
typedef[name.Name] = &tt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2586,6 +2613,30 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ
|
||||||
oldType.BadPointer = true
|
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.Go = name
|
||||||
t.BadPointer = sub.BadPointer
|
t.BadPointer = sub.BadPointer
|
||||||
t.NotInHeap = sub.NotInHeap
|
t.NotInHeap = sub.NotInHeap
|
||||||
|
|
@ -3035,6 +3086,31 @@ func upper(s string) string {
|
||||||
// so that all fields are exported.
|
// so that all fields are exported.
|
||||||
func godefsFields(fld []*ast.Field) {
|
func godefsFields(fld []*ast.Field) {
|
||||||
prefix := fieldPrefix(fld)
|
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
|
npad := 0
|
||||||
for _, f := range fld {
|
for _, f := range fld {
|
||||||
for _, n := range f.Names {
|
for _, n := range f.Names {
|
||||||
|
|
@ -3112,6 +3188,48 @@ func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool {
|
||||||
return false
|
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
|
// baseBadPointerTypedef reports whether the base of a chain of typedefs is a bad typedef
|
||||||
// as badPointerTypedef reports.
|
// as badPointerTypedef reports.
|
||||||
func (c *typeConv) baseBadPointerTypedef(dt *dwarf.TypedefType) bool {
|
func (c *typeConv) baseBadPointerTypedef(dt *dwarf.TypedefType) bool {
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"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 trimpath = flag.String("trimpath", "", "applies supplied rewrites or trims prefixes to recorded source file paths")
|
||||||
|
|
||||||
var goarch, goos, gomips, gomips64 string
|
var goarch, goos, gomips, gomips64 string
|
||||||
|
var gccBaseCmd []string
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
objabi.AddVersionFlag() // -V
|
objabi.AddVersionFlag() // -V
|
||||||
|
|
@ -309,10 +309,10 @@ func main() {
|
||||||
p := newPackage(args[:i])
|
p := newPackage(args[:i])
|
||||||
|
|
||||||
// We need a C compiler to be available. Check this.
|
// We need a C compiler to be available. Check this.
|
||||||
gccName := p.gccBaseCmd()[0]
|
var err error
|
||||||
_, err := exec.LookPath(gccName)
|
gccBaseCmd, err = checkGCCBaseCmd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fatalf("C compiler %q not found: %v", gccName, err)
|
fatalf("%v", err)
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -64,9 +64,9 @@ func (p *Package) writeDefs() {
|
||||||
// Write C main file for using gcc to resolve imports.
|
// Write C main file for using gcc to resolve imports.
|
||||||
fmt.Fprintf(fm, "int main() { return 0; }\n")
|
fmt.Fprintf(fm, "int main() { return 0; }\n")
|
||||||
if *importRuntimeCgo {
|
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, "__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")
|
fmt.Fprintf(fm, "char* _cgo_topofstack(void) { return (char*)0; }\n")
|
||||||
} else {
|
} else {
|
||||||
// If we're not importing runtime/cgo, we *are* runtime/cgo,
|
// 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, "__SIZE_TYPE__ _cgo_wait_runtime_init_done(void);\n")
|
||||||
fmt.Fprintf(fm, "void _cgo_release_context(__SIZE_TYPE__);\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_allocate(void *a __attribute__((unused)), int c __attribute__((unused))) { }\n")
|
||||||
fmt.Fprintf(fm, "void _cgo_panic(void *a, int c) { }\n")
|
fmt.Fprintf(fm, "void _cgo_panic(void *a __attribute__((unused)), int c __attribute__((unused))) { }\n")
|
||||||
fmt.Fprintf(fm, "void _cgo_reginit(void) { }\n")
|
fmt.Fprintf(fm, "void _cgo_reginit(void) { }\n")
|
||||||
|
|
||||||
// Write second Go output: definitions of _C_xxx.
|
// 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, "%s", buf.Bytes())
|
||||||
fmt.Fprintf(fgo2, "\n\n")
|
fmt.Fprintf(fgo2, "\n\n")
|
||||||
}
|
}
|
||||||
|
fmt.Fprintf(fgo2, "//go:notinheap\ntype _Ctype_void_notinheap struct{}\n\n")
|
||||||
if *gccgo {
|
if *gccgo {
|
||||||
fmt.Fprintf(fgo2, "type _Ctype_void byte\n")
|
fmt.Fprintf(fgo2, "type _Ctype_void byte\n")
|
||||||
} else {
|
} 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(fm, "void _cgoexp%s_%s(void* p){}\n", cPrefix, exp.ExpName)
|
||||||
|
|
||||||
|
fmt.Fprintf(fgo2, "\t")
|
||||||
|
|
||||||
if gccResult != "void" {
|
if gccResult != "void" {
|
||||||
// Write results back to frame.
|
// Write results back to frame.
|
||||||
fmt.Fprintf(fgo2, "\t")
|
|
||||||
forFieldList(fntype.Results,
|
forFieldList(fntype.Results,
|
||||||
func(i int, aname string, atype ast.Expr) {
|
func(i int, aname string, atype ast.Expr) {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
|
|
@ -1463,10 +1465,10 @@ const gccProlog = `
|
||||||
(have a negative array count) and an inscrutable error will come
|
(have a negative array count) and an inscrutable error will come
|
||||||
out of the compiler and hopefully mention "name".
|
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. */
|
/* 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(char, 1)
|
||||||
__cgo_size_assert(short, 2)
|
__cgo_size_assert(short, 2)
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,19 @@
|
||||||
module cmd
|
module cmd
|
||||||
|
|
||||||
go 1.17
|
go 1.18
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/google/pprof v0.0.0-20210506205249-923b5ab0fc1a
|
github.com/google/pprof v0.0.0-20211104044539-f987b9c94b31
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639 // indirect
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670
|
||||||
golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e
|
golang.org/x/mod v0.6.0-dev.0.20211102181907-3a5865c02020
|
||||||
golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e // indirect
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||||
golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
|
||||||
golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 // indirect
|
golang.org/x/tools v0.1.9-0.20220124164225-97de9ec46646
|
||||||
golang.org/x/term v0.0.0-20210503060354-a79de5458b56
|
)
|
||||||
golang.org/x/tools v0.1.2-0.20210519160823-49064d2332f9
|
|
||||||
|
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
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
// install compile and install packages and dependencies
|
// install compile and install packages and dependencies
|
||||||
// list list packages or modules
|
// list list packages or modules
|
||||||
// mod module maintenance
|
// mod module maintenance
|
||||||
|
// work workspace maintenance
|
||||||
// run compile and run Go program
|
// run compile and run Go program
|
||||||
// test test packages
|
// test test packages
|
||||||
// tool run specified go tool
|
// tool run specified go tool
|
||||||
|
|
@ -114,13 +115,16 @@
|
||||||
// The default is GOMAXPROCS, normally the number of CPUs available.
|
// The default is GOMAXPROCS, normally the number of CPUs available.
|
||||||
// -race
|
// -race
|
||||||
// enable data race detection.
|
// 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).
|
// linux/ppc64le and linux/arm64 (only for 48-bit VMA).
|
||||||
// -msan
|
// -msan
|
||||||
// enable interoperation with memory sanitizer.
|
// enable interoperation with memory sanitizer.
|
||||||
// Supported only on linux/amd64, linux/arm64
|
// Supported only on linux/amd64, linux/arm64
|
||||||
// and only with Clang/LLVM as the host C compiler.
|
// and only with Clang/LLVM as the host C compiler.
|
||||||
// On linux/arm64, pie build mode will be used.
|
// On linux/arm64, pie build mode will be used.
|
||||||
|
// -asan
|
||||||
|
// enable interoperation with address sanitizer.
|
||||||
|
// Supported only on linux/arm64, linux/amd64.
|
||||||
// -v
|
// -v
|
||||||
// print the names of packages as they are compiled.
|
// print the names of packages as they are compiled.
|
||||||
// -work
|
// -work
|
||||||
|
|
@ -133,6 +137,12 @@
|
||||||
// arguments to pass on each go tool asm invocation.
|
// arguments to pass on each go tool asm invocation.
|
||||||
// -buildmode mode
|
// -buildmode mode
|
||||||
// build mode to use. See 'go help buildmode' for more.
|
// 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
|
// -compiler name
|
||||||
// name of compiler to use, as in runtime.Compiler (gccgo or gc).
|
// name of compiler to use, as in runtime.Compiler (gccgo or gc).
|
||||||
// -gccgoflags '[pattern=]arg list'
|
// -gccgoflags '[pattern=]arg list'
|
||||||
|
|
@ -144,8 +154,8 @@
|
||||||
// in order to keep output separate from default builds.
|
// in order to keep output separate from default builds.
|
||||||
// If using the -race flag, the install suffix is automatically set to race
|
// 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
|
// or, if set explicitly, has _race appended to it. Likewise for the -msan
|
||||||
// flag. Using a -buildmode option that requires non-default compile flags
|
// and -asan flags. Using a -buildmode option that requires non-default compile
|
||||||
// has a similar effect.
|
// flags has a similar effect.
|
||||||
// -ldflags '[pattern=]arg list'
|
// -ldflags '[pattern=]arg list'
|
||||||
// arguments to pass on each go tool link invocation.
|
// arguments to pass on each go tool link invocation.
|
||||||
// -linkshared
|
// -linkshared
|
||||||
|
|
@ -167,6 +177,14 @@
|
||||||
// directory, but it is not accessed. When -modfile is specified, an
|
// directory, but it is not accessed. When -modfile is specified, an
|
||||||
// alternate go.sum file is also used: its path is derived from the
|
// alternate go.sum file is also used: its path is derived from the
|
||||||
// -modfile flag by trimming the ".mod" extension and appending ".sum".
|
// -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
|
// -overlay file
|
||||||
// read a JSON config file that provides an overlay for build operations.
|
// 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
|
// The file is a JSON struct with a single field, named 'Replace', that
|
||||||
|
|
@ -191,9 +209,8 @@
|
||||||
// -trimpath
|
// -trimpath
|
||||||
// remove all file system paths from the resulting executable.
|
// remove all file system paths from the resulting executable.
|
||||||
// Instead of absolute file system paths, the recorded file names
|
// Instead of absolute file system paths, the recorded file names
|
||||||
// will begin with either "go" (for the standard library),
|
// will begin either a module path@version (when using modules),
|
||||||
// or a module path@version (when using modules),
|
// or a plain import path (when using the standard library, or GOPATH).
|
||||||
// or a plain import path (when using GOPATH).
|
|
||||||
// -toolexec 'cmd args'
|
// -toolexec 'cmd args'
|
||||||
// a program to use to invoke toolchain programs like vet and asm.
|
// a program to use to invoke toolchain programs like vet and asm.
|
||||||
// For example, instead of running asm, the go command will run
|
// For example, instead of running asm, the go command will run
|
||||||
|
|
@ -284,6 +301,13 @@
|
||||||
// download cache, including unpacked source code of versioned
|
// download cache, including unpacked source code of versioned
|
||||||
// dependencies.
|
// 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 build flags, see 'go help build'.
|
||||||
//
|
//
|
||||||
// For more about specifying packages, see 'go help packages'.
|
// 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
|
// path. The go tool's usual package mechanism does not apply: package path
|
||||||
// elements like . and ... are not implemented by go doc.
|
// 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
|
// When run with two arguments, the first is a package path (full path or suffix),
|
||||||
// suffix), and the second is a symbol, or symbol with method or struct field.
|
// and the second is a symbol, or symbol with method or struct field:
|
||||||
// This is similar to the syntax accepted by godoc:
|
|
||||||
//
|
//
|
||||||
// go doc <pkg> <sym>[.<methodOrField>]
|
// go doc <pkg> <sym>[.<methodOrField>]
|
||||||
//
|
//
|
||||||
|
|
@ -438,14 +461,18 @@
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
//
|
//
|
||||||
// go fix [packages]
|
// go fix [-fix list] [packages]
|
||||||
//
|
//
|
||||||
// Fix runs the Go fix command on the packages named by the import paths.
|
// 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 fix, see 'go doc cmd/fix'.
|
||||||
// For more about specifying packages, see 'go help packages'.
|
// 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.
|
// See also: go fmt, go vet.
|
||||||
//
|
//
|
||||||
|
|
@ -483,7 +510,7 @@
|
||||||
// files. Those commands can run any process but the intent is to
|
// files. Those commands can run any process but the intent is to
|
||||||
// create or update Go source files.
|
// 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.
|
// and so on. It must be run explicitly.
|
||||||
//
|
//
|
||||||
// Go generate scans the file for directives, which are lines of
|
// Go generate scans the file for directives, which are lines of
|
||||||
|
|
@ -598,11 +625,11 @@
|
||||||
//
|
//
|
||||||
// Usage:
|
// 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,
|
// Get resolves its command-line arguments to packages at specific module versions,
|
||||||
// updates go.mod to require those versions, downloads source code into the
|
// updates go.mod to require those versions, and downloads source code into the
|
||||||
// module cache, then builds and installs the named packages.
|
// module cache.
|
||||||
//
|
//
|
||||||
// To add a dependency for a package or upgrade it to its latest version:
|
// 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.
|
// See https://golang.org/ref/mod#go-get for details.
|
||||||
//
|
//
|
||||||
// The 'go install' command may be used to build and install packages. When a
|
// In earlier versions of Go, 'go get' was used to build and install packages.
|
||||||
// version is specified, 'go install' runs in module-aware mode and ignores
|
// Now, 'go get' is dedicated to adjusting dependencies in go.mod. 'go install'
|
||||||
// the go.mod file in the current directory. For example:
|
// 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@v1.2.3
|
||||||
// go install example.com/pkg@latest
|
// go install example.com/pkg@latest
|
||||||
//
|
//
|
||||||
// See 'go help install' or https://golang.org/ref/mod#go-install for details.
|
// 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
|
// 'go get' accepts the following flags.
|
||||||
// following flags.
|
|
||||||
//
|
//
|
||||||
// The -t flag instructs get to consider modules needed to build tests of
|
// The -t flag instructs get to consider modules needed to build tests of
|
||||||
// packages specified on the command line.
|
// packages specified on the command line.
|
||||||
|
|
@ -643,15 +671,9 @@
|
||||||
// When the -t and -u flags are used together, get will update
|
// When the -t and -u flags are used together, get will update
|
||||||
// test dependencies as well.
|
// test dependencies as well.
|
||||||
//
|
//
|
||||||
// The -d flag instructs get not to build or install packages. get will only
|
// The -x flag prints commands as they are executed. This is useful for
|
||||||
// update go.mod and download source code needed to build packages.
|
// debugging version control commands when a module is downloaded directly
|
||||||
//
|
// from a repository.
|
||||||
// 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.
|
|
||||||
//
|
//
|
||||||
// For more about modules, see https://golang.org/ref/mod.
|
// 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.
|
// - 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
|
// - 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
|
// 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
|
// directives (replace and exclude) that would cause it to be interpreted
|
||||||
// differently than if it were the main module. The module must not require
|
// differently than if it were the main module. The module must not require
|
||||||
// a higher version of itself.
|
// a higher version of itself.
|
||||||
//
|
//
|
||||||
// - Package path arguments must refer to main packages. Pattern arguments
|
// - Vendor directories are not used in any module. (Vendor directories are not
|
||||||
// will only match main packages.
|
// included in the module zip files downloaded by 'go install'.)
|
||||||
//
|
//
|
||||||
// If the arguments don't have version suffixes, "go install" may run in
|
// If the arguments don't have version suffixes, "go install" may run in
|
||||||
// module-aware mode or GOPATH mode, depending on the GO111MODULE environment
|
// 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
|
// Download downloads the named modules, which can be module patterns selecting
|
||||||
// dependencies of the main module or module queries of the form path@version.
|
// 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
|
// The go command will automatically download modules as needed during ordinary
|
||||||
// execution. The "go mod download" command is useful mainly for pre-filling
|
// execution. The "go mod download" command is useful mainly for pre-filling
|
||||||
|
|
@ -1260,7 +1288,7 @@
|
||||||
//
|
//
|
||||||
// Usage:
|
// 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
|
// Vendor resets the main module's vendor directory to include all packages
|
||||||
// needed to build and test all the main module's 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
|
// The -e flag causes vendor to attempt to proceed despite errors
|
||||||
// encountered while loading packages.
|
// 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'.
|
// 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'.
|
// 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
|
// Compile and run Go program
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
|
|
@ -1387,8 +1616,8 @@
|
||||||
//
|
//
|
||||||
// 'Go test' recompiles each package along with any files with names matching
|
// 'Go test' recompiles each package along with any files with names matching
|
||||||
// the file pattern "*_test.go".
|
// the file pattern "*_test.go".
|
||||||
// These additional files can contain test functions, benchmark functions, and
|
// These additional files can contain test functions, benchmark functions, fuzz
|
||||||
// example functions. See 'go help testfunc' for more.
|
// tests and example functions. See 'go help testfunc' for more.
|
||||||
// Each listed package causes the execution of a separate test binary.
|
// Each listed package causes the execution of a separate test binary.
|
||||||
// Files whose names begin with "_" (including "_test.go") or "." are ignored.
|
// Files whose names begin with "_" (including "_test.go") or "." are ignored.
|
||||||
//
|
//
|
||||||
|
|
@ -1405,7 +1634,8 @@
|
||||||
// used. That subset is: 'atomic', 'bool', 'buildtags', 'errorsas',
|
// used. That subset is: 'atomic', 'bool', 'buildtags', 'errorsas',
|
||||||
// 'ifaceassert', 'nilfunc', 'printf', and 'stringintconv'. You can see
|
// 'ifaceassert', 'nilfunc', 'printf', and 'stringintconv'. You can see
|
||||||
// the documentation for these and other vet tests via "go doc cmd/vet".
|
// 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
|
// 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
|
// 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
|
// 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
|
// test binary and the flags on the command line come entirely from a
|
||||||
// restricted set of 'cacheable' test flags, defined as -benchtime, -cpu,
|
// 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
|
// -list, -parallel, -run, -short, -timeout, -failfast, and -v.
|
||||||
// or non-test flags outside this set, the result is not cached. To
|
// If a run of go test has any test or non-test flags outside this set,
|
||||||
// disable test caching, use any test flag or argument other than the
|
// the result is not cached. To disable test caching, use any test flag
|
||||||
// cacheable flags. The idiomatic way to disable test caching explicitly
|
// or argument other than the cacheable flags. The idiomatic way to disable
|
||||||
// is to use -count=1. Tests that open files within the package's source
|
// test caching explicitly is to use -count=1. Tests that open files within
|
||||||
// root (usually $GOPATH) or that consult environment variables only
|
// the package's source root (usually $GOPATH) or that consult environment
|
||||||
// match future runs in which the files and environment variables are unchanged.
|
// variables only match future runs in which the files and environment
|
||||||
// A cached test result is treated as executing in no time at all,
|
// variables are unchanged. A cached test result is treated as executing
|
||||||
// so a successful package test result will be cached and reused
|
// in no time at all,so a successful package test result will be cached and
|
||||||
// regardless of -timeout setting.
|
// reused regardless of -timeout setting.
|
||||||
//
|
//
|
||||||
// In addition to the build flags, the flags handled by 'go test' itself are:
|
// 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
|
// See 'go help test' for details. Running 'go clean -testcache' removes
|
||||||
// all cached test results (but not cached build results).
|
// 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
|
// The GODEBUG environment variable can enable printing of debugging
|
||||||
// information about the state of the cache:
|
// information about the state of the cache:
|
||||||
//
|
//
|
||||||
|
|
@ -1885,6 +2122,10 @@
|
||||||
// GO386
|
// GO386
|
||||||
// For GOARCH=386, how to implement floating point instructions.
|
// For GOARCH=386, how to implement floating point instructions.
|
||||||
// Valid values are sse2 (default), softfloat.
|
// 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
|
// GOMIPS
|
||||||
// For GOARCH=mips{,le}, whether to use floating point instructions.
|
// For GOARCH=mips{,le}, whether to use floating point instructions.
|
||||||
// Valid values are hardfloat (default), softfloat.
|
// Valid values are hardfloat (default), softfloat.
|
||||||
|
|
@ -2622,9 +2863,10 @@
|
||||||
// (for example, -benchtime 100x).
|
// (for example, -benchtime 100x).
|
||||||
//
|
//
|
||||||
// -count n
|
// -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.
|
// 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
|
// -cover
|
||||||
// Enable coverage analysis.
|
// Enable coverage analysis.
|
||||||
|
|
@ -2651,32 +2893,67 @@
|
||||||
// Sets -cover.
|
// Sets -cover.
|
||||||
//
|
//
|
||||||
// -cpu 1,2,4
|
// -cpu 1,2,4
|
||||||
// Specify a list of GOMAXPROCS values for which the tests or
|
// Specify a list of GOMAXPROCS values for which the tests, benchmarks or
|
||||||
// benchmarks should be executed. The default is the current value
|
// fuzz tests should be executed. The default is the current value
|
||||||
// of GOMAXPROCS.
|
// of GOMAXPROCS. -cpu does not apply to fuzz tests matched by -fuzz.
|
||||||
//
|
//
|
||||||
// -failfast
|
// -failfast
|
||||||
// Do not start new tests after the first test failure.
|
// 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 regexp
|
||||||
// List tests, benchmarks, or examples matching the regular expression.
|
// List tests, benchmarks, fuzz tests, or examples matching the regular
|
||||||
// No tests, benchmarks or examples will be run. This will only
|
// expression. No tests, benchmarks, fuzz tests, or examples will be run.
|
||||||
// list top-level tests. No subtest or subbenchmarks will be shown.
|
// This will only list top-level tests. No subtest or subbenchmarks will be
|
||||||
|
// shown.
|
||||||
//
|
//
|
||||||
// -parallel n
|
// -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
|
// 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.
|
// Note that -parallel only applies within a single test binary.
|
||||||
// The 'go test' command may run tests for different packages
|
// The 'go test' command may run tests for different packages
|
||||||
// in parallel as well, according to the setting of the -p flag
|
// in parallel as well, according to the setting of the -p flag
|
||||||
// (see 'go help build').
|
// (see 'go help build').
|
||||||
//
|
//
|
||||||
// -run regexp
|
// -run regexp
|
||||||
// Run only those tests and examples matching the regular expression.
|
// Run only those tests, examples, and fuzz tests matching the regular
|
||||||
// For tests, the regular expression is split by unbracketed slash (/)
|
// expression. For tests, the regular expression is split by unbracketed
|
||||||
// characters into a sequence of regular expressions, and each part
|
// slash (/) characters into a sequence of regular expressions, and each
|
||||||
// of a test's identifier must match the corresponding element in
|
// part of a test's identifier must match the corresponding element in
|
||||||
// the sequence, if any. Note that possible parents of matches are
|
// 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
|
// 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,
|
// of all tests matching X, even those without sub-tests matching Y,
|
||||||
|
|
@ -2689,11 +2966,11 @@
|
||||||
// exhaustive tests.
|
// exhaustive tests.
|
||||||
//
|
//
|
||||||
// -shuffle off,on,N
|
// -shuffle off,on,N
|
||||||
// Randomize the execution order of tests and benchmarks.
|
// Randomize the execution order of tests and benchmarks.
|
||||||
// It is off by default. If -shuffle is set to on, then it will seed
|
// 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
|
// 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,
|
// integer N, then N will be used as the seed value. In both cases,
|
||||||
// the seed will be reported for reproducibility.
|
// the seed will be reported for reproducibility.
|
||||||
//
|
//
|
||||||
// -timeout d
|
// -timeout d
|
||||||
// If a test binary runs longer than duration d, panic.
|
// 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
|
// When 'go test' runs a test binary, it does so from within the
|
||||||
// corresponding package's source code directory. Depending on the test,
|
// corresponding package's source code directory. Depending on the test,
|
||||||
// it may be necessary to do the same when invoking a generated 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
|
// The command-line package list, if present, must appear before any
|
||||||
// flag not known to the go test command. Continuing the example above,
|
// flag not known to the go test command. Continuing the example above,
|
||||||
|
|
@ -2843,6 +3124,10 @@
|
||||||
//
|
//
|
||||||
// func BenchmarkXxx(b *testing.B) { ... }
|
// 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
|
// 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.
|
// *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
|
// 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
|
// 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
|
// 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.
|
// See the documentation of the testing package for more information.
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build go1.1
|
//go:build go1.1
|
||||||
// +build go1.1
|
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/format"
|
"go/format"
|
||||||
|
"internal/godebug"
|
||||||
"internal/race"
|
"internal/race"
|
||||||
"internal/testenv"
|
"internal/testenv"
|
||||||
"io"
|
"io"
|
||||||
|
|
@ -31,7 +32,6 @@ import (
|
||||||
"cmd/go/internal/cache"
|
"cmd/go/internal/cache"
|
||||||
"cmd/go/internal/cfg"
|
"cmd/go/internal/cfg"
|
||||||
"cmd/go/internal/robustio"
|
"cmd/go/internal/robustio"
|
||||||
"cmd/go/internal/work"
|
|
||||||
"cmd/internal/sys"
|
"cmd/internal/sys"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -44,9 +44,12 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
canRace = false // whether we can run the race detector
|
canRace = false // whether we can run the race detector
|
||||||
canCgo = false // whether we can use cgo
|
canCgo = false // whether we can use cgo
|
||||||
canMSan = false // whether we can run the memory sanitizer
|
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 {
|
var exeSuffix string = func() string {
|
||||||
|
|
@ -198,6 +201,7 @@ func TestMain(m *testing.M) {
|
||||||
testGOCACHE = strings.TrimSpace(string(out))
|
testGOCACHE = strings.TrimSpace(string(out))
|
||||||
|
|
||||||
canMSan = canCgo && sys.MSanSupported(runtime.GOOS, runtime.GOARCH)
|
canMSan = canCgo && sys.MSanSupported(runtime.GOOS, runtime.GOARCH)
|
||||||
|
canASan = canCgo && sys.ASanSupported(runtime.GOOS, runtime.GOARCH)
|
||||||
canRace = canCgo && sys.RaceDetectorSupported(runtime.GOOS, runtime.GOARCH)
|
canRace = canCgo && sys.RaceDetectorSupported(runtime.GOOS, runtime.GOARCH)
|
||||||
// The race detector doesn't work on Alpine Linux:
|
// The race detector doesn't work on Alpine Linux:
|
||||||
// golang.org/issue/14481
|
// golang.org/issue/14481
|
||||||
|
|
@ -205,6 +209,8 @@ func TestMain(m *testing.M) {
|
||||||
if isAlpineLinux() || runtime.Compiler == "gccgo" {
|
if isAlpineLinux() || runtime.Compiler == "gccgo" {
|
||||||
canRace = false
|
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.
|
// Don't let these environment variables confuse the test.
|
||||||
os.Setenv("GOENV", "off")
|
os.Setenv("GOENV", "off")
|
||||||
|
|
@ -806,7 +812,9 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
|
||||||
"src/internal/abi",
|
"src/internal/abi",
|
||||||
"src/internal/bytealg",
|
"src/internal/bytealg",
|
||||||
"src/internal/cpu",
|
"src/internal/cpu",
|
||||||
|
"src/internal/goarch",
|
||||||
"src/internal/goexperiment",
|
"src/internal/goexperiment",
|
||||||
|
"src/internal/goos",
|
||||||
"src/math/bits",
|
"src/math/bits",
|
||||||
"src/unsafe",
|
"src/unsafe",
|
||||||
filepath.Join("pkg", runtime.GOOS+"_"+runtime.GOARCH),
|
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 \[sort.test\]$`, "unexpected test copy of testing")
|
||||||
tg.grepStdoutNot(`^testing$`, "unexpected real copy of testing")
|
tg.grepStdoutNot(`^testing$`, "unexpected real copy of testing")
|
||||||
|
|
||||||
tg.run("list", "-test", "cmd/dist", "cmd/doc")
|
tg.run("list", "-test", "cmd/buildid", "cmd/doc")
|
||||||
tg.grepStdout(`^cmd/dist$`, "missing cmd/dist")
|
tg.grepStdout(`^cmd/buildid$`, "missing cmd/buildid")
|
||||||
tg.grepStdout(`^cmd/doc$`, "missing cmd/doc")
|
tg.grepStdout(`^cmd/doc$`, "missing cmd/doc")
|
||||||
tg.grepStdout(`^cmd/doc\.test$`, "missing cmd/doc test")
|
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.grepStdoutNot(`^testing`, "unexpected testing")
|
||||||
|
|
||||||
tg.run("list", "-test", "runtime/cgo")
|
tg.run("list", "-test", "runtime/cgo")
|
||||||
|
|
@ -1376,7 +1384,7 @@ func TestLdFlagsLongArgumentsIssue42295(t *testing.T) {
|
||||||
}`)
|
}`)
|
||||||
testStr := "test test test test test \n\\ "
|
testStr := "test test test test test \n\\ "
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
for buf.Len() < work.ArgLengthForResponseFile+1 {
|
for buf.Len() < sys.ExecArgLengthLimit+1 {
|
||||||
buf.WriteString(testStr)
|
buf.WriteString(testStr)
|
||||||
}
|
}
|
||||||
tg.run("run", "-ldflags", fmt.Sprintf(`-X "main.extern=%s"`, buf.String()), tg.path("main.go"))
|
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) {
|
func TestCacheListStale(t *testing.T) {
|
||||||
tooSlow(t)
|
tooSlow(t)
|
||||||
if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
|
if godebug.Get("gocacheverify") == "1" {
|
||||||
t.Skip("GODEBUG gocacheverify")
|
t.Skip("GODEBUG gocacheverify")
|
||||||
}
|
}
|
||||||
tg := testgo(t)
|
tg := testgo(t)
|
||||||
|
|
@ -2297,7 +2305,7 @@ func TestCacheListStale(t *testing.T) {
|
||||||
func TestCacheCoverage(t *testing.T) {
|
func TestCacheCoverage(t *testing.T) {
|
||||||
tooSlow(t)
|
tooSlow(t)
|
||||||
|
|
||||||
if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
|
if godebug.Get("gocacheverify") == "1" {
|
||||||
t.Skip("GODEBUG gocacheverify")
|
t.Skip("GODEBUG gocacheverify")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2329,7 +2337,7 @@ func TestIssue22588(t *testing.T) {
|
||||||
|
|
||||||
func TestIssue22531(t *testing.T) {
|
func TestIssue22531(t *testing.T) {
|
||||||
tooSlow(t)
|
tooSlow(t)
|
||||||
if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
|
if godebug.Get("gocacheverify") == "1" {
|
||||||
t.Skip("GODEBUG gocacheverify")
|
t.Skip("GODEBUG gocacheverify")
|
||||||
}
|
}
|
||||||
tg := testgo(t)
|
tg := testgo(t)
|
||||||
|
|
@ -2358,7 +2366,7 @@ func TestIssue22531(t *testing.T) {
|
||||||
|
|
||||||
func TestIssue22596(t *testing.T) {
|
func TestIssue22596(t *testing.T) {
|
||||||
tooSlow(t)
|
tooSlow(t)
|
||||||
if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
|
if godebug.Get("gocacheverify") == "1" {
|
||||||
t.Skip("GODEBUG gocacheverify")
|
t.Skip("GODEBUG gocacheverify")
|
||||||
}
|
}
|
||||||
tg := testgo(t)
|
tg := testgo(t)
|
||||||
|
|
@ -2388,7 +2396,7 @@ func TestIssue22596(t *testing.T) {
|
||||||
func TestTestCache(t *testing.T) {
|
func TestTestCache(t *testing.T) {
|
||||||
tooSlow(t)
|
tooSlow(t)
|
||||||
|
|
||||||
if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
|
if godebug.Get("gocacheverify") == "1" {
|
||||||
t.Skip("GODEBUG gocacheverify")
|
t.Skip("GODEBUG gocacheverify")
|
||||||
}
|
}
|
||||||
tg := testgo(t)
|
tg := testgo(t)
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris
|
//go:build darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd || solaris
|
||||||
// +build darwin dragonfly freebsd hurd linux netbsd openbsd solaris
|
|
||||||
|
|
||||||
package main_test
|
package main_test
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -117,12 +117,12 @@ func Exit() {
|
||||||
os.Exit(exitStatus)
|
os.Exit(exitStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Fatalf(format string, args ...interface{}) {
|
func Fatalf(format string, args ...any) {
|
||||||
Errorf(format, args...)
|
Errorf(format, args...)
|
||||||
Exit()
|
Exit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func Errorf(format string, args ...interface{}) {
|
func Errorf(format string, args ...any) {
|
||||||
log.Printf(format, args...)
|
log.Printf(format, args...)
|
||||||
SetExitStatus(1)
|
SetExitStatus(1)
|
||||||
}
|
}
|
||||||
|
|
@ -151,7 +151,7 @@ func GetExitStatus() int {
|
||||||
// Run runs the command, with stdout and stderr
|
// Run runs the command, with stdout and stderr
|
||||||
// connected to the go command's own stdout and stderr.
|
// connected to the go command's own stdout and stderr.
|
||||||
// If the command fails, Run reports the error using Errorf.
|
// If the command fails, Run reports the error using Errorf.
|
||||||
func Run(cmdargs ...interface{}) {
|
func Run(cmdargs ...any) {
|
||||||
cmdline := str.StringList(cmdargs...)
|
cmdline := str.StringList(cmdargs...)
|
||||||
if cfg.BuildN || cfg.BuildX {
|
if cfg.BuildN || cfg.BuildX {
|
||||||
fmt.Printf("%s\n", strings.Join(cmdline, " "))
|
fmt.Printf("%s\n", strings.Join(cmdline, " "))
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import (
|
||||||
|
|
||||||
"cmd/go/internal/cfg"
|
"cmd/go/internal/cfg"
|
||||||
"cmd/go/internal/fsys"
|
"cmd/go/internal/fsys"
|
||||||
"cmd/go/internal/str"
|
"cmd/internal/quoted"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A StringsFlag is a command-line flag that interprets its argument
|
// 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 {
|
func (v *StringsFlag) Set(s string) error {
|
||||||
var err error
|
var err error
|
||||||
*v, err = str.SplitQuotedFields(s)
|
*v, err = quoted.Split(s)
|
||||||
if *v == nil {
|
if *v == nil {
|
||||||
*v = []string{}
|
*v = []string{}
|
||||||
}
|
}
|
||||||
|
|
@ -62,6 +62,13 @@ func AddModFlag(flags *flag.FlagSet) {
|
||||||
flags.Var(explicitStringFlag{value: &cfg.BuildMod, explicit: &cfg.BuildModExplicit}, "mod", "")
|
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
|
// AddModCommonFlags adds the module-related flags common to build commands
|
||||||
// and 'go mod' subcommands.
|
// and 'go mod' subcommands.
|
||||||
func AddModCommonFlags(flags *flag.FlagSet) {
|
func AddModCommonFlags(flags *flag.FlagSet) {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build plan9 || windows
|
//go:build plan9 || windows
|
||||||
// +build plan9 windows
|
|
||||||
|
|
||||||
package base
|
package base
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build aix || darwin || dragonfly || freebsd || hurd || js || linux || netbsd || openbsd || solaris
|
//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
|
package base
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ func Tool(toolName string) string {
|
||||||
}
|
}
|
||||||
// Give a nice message if there is no tool with that name.
|
// Give a nice message if there is no tool with that name.
|
||||||
if _, err := os.Stat(toolPath); err != nil {
|
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)
|
SetExitStatus(2)
|
||||||
Exit()
|
Exit()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ func init() {
|
||||||
|
|
||||||
func runBug(ctx context.Context, cmd *base.Command, args []string) {
|
func runBug(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
base.Fatalf("go bug: bug takes no arguments")
|
base.Fatalf("go: bug takes no arguments")
|
||||||
}
|
}
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
buf.WriteString(bugHeader)
|
buf.WriteString(bugHeader)
|
||||||
|
|
@ -106,8 +106,9 @@ func printGoEnv(w io.Writer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func printGoDetails(w io.Writer) {
|
func printGoDetails(w io.Writer) {
|
||||||
printCmdOut(w, "GOROOT/bin/go version: ", filepath.Join(runtime.GOROOT(), "bin/go"), "version")
|
gocmd := filepath.Join(runtime.GOROOT(), "bin/go")
|
||||||
printCmdOut(w, "GOROOT/bin/go tool compile -V: ", filepath.Join(runtime.GOROOT(), "bin/go"), "tool", "compile", "-V")
|
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) {
|
func printOSDetails(w io.Writer) {
|
||||||
|
|
|
||||||
|
|
@ -533,3 +533,15 @@ func (c *Cache) copyFile(file io.ReadSeeker, out OutputID, size int64) error {
|
||||||
|
|
||||||
return nil
|
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")
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ var (
|
||||||
// README as a courtesy to explain where it came from.
|
// README as a courtesy to explain where it came from.
|
||||||
const cacheREADME = `This directory holds cached build artifacts from the Go build system.
|
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 -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.
|
See golang.org to learn more about Go.
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import (
|
||||||
var (
|
var (
|
||||||
BuildA bool // -a flag
|
BuildA bool // -a flag
|
||||||
BuildBuildmode string // -buildmode flag
|
BuildBuildmode string // -buildmode flag
|
||||||
|
BuildBuildvcs bool // -buildvcs flag
|
||||||
BuildContext = defaultContext()
|
BuildContext = defaultContext()
|
||||||
BuildMod string // -mod flag
|
BuildMod string // -mod flag
|
||||||
BuildModExplicit bool // whether -mod was set explicitly
|
BuildModExplicit bool // whether -mod was set explicitly
|
||||||
|
|
@ -33,6 +34,7 @@ var (
|
||||||
BuildI bool // -i flag
|
BuildI bool // -i flag
|
||||||
BuildLinkshared bool // -linkshared flag
|
BuildLinkshared bool // -linkshared flag
|
||||||
BuildMSan bool // -msan flag
|
BuildMSan bool // -msan flag
|
||||||
|
BuildASan bool // -asan flag
|
||||||
BuildN bool // -n flag
|
BuildN bool // -n flag
|
||||||
BuildO string // -o flag
|
BuildO string // -o flag
|
||||||
BuildP = runtime.GOMAXPROCS(0) // -p flag
|
BuildP = runtime.GOMAXPROCS(0) // -p flag
|
||||||
|
|
@ -47,17 +49,26 @@ var (
|
||||||
BuildWork bool // -work flag
|
BuildWork bool // -work flag
|
||||||
BuildX bool // -x flag
|
BuildX bool // -x flag
|
||||||
|
|
||||||
ModCacheRW bool // -modcacherw flag
|
ModCacheRW bool // -modcacherw flag
|
||||||
ModFile string // -modfile flag
|
ModFile string // -modfile flag
|
||||||
|
WorkFile string // -workfile flag
|
||||||
|
WorkFileExplicit bool // whether -workfile was set explicitly
|
||||||
|
|
||||||
CmdName string // "build", "install", "list", "mod tidy", etc.
|
CmdName string // "build", "install", "list", "mod tidy", etc.
|
||||||
|
|
||||||
DebugActiongraph string // -debug-actiongraph flag (undocumented, unstable)
|
DebugActiongraph string // -debug-actiongraph flag (undocumented, unstable)
|
||||||
DebugTrace string // -debug-trace flag
|
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 {
|
func defaultContext() build.Context {
|
||||||
ctxt := build.Default
|
ctxt := build.Default
|
||||||
|
|
||||||
ctxt.JoinPath = filepath.Join // back door to say "do not use go command"
|
ctxt.JoinPath = filepath.Join // back door to say "do not use go command"
|
||||||
|
|
||||||
ctxt.GOROOT = findGOROOT()
|
ctxt.GOROOT = findGOROOT()
|
||||||
|
|
@ -70,7 +81,7 @@ func defaultContext() build.Context {
|
||||||
build.ToolDir = filepath.Join(ctxt.GOROOT, "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH)
|
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
|
// Override defaults computed in go/build with defaults
|
||||||
// from go environment configuration file, if known.
|
// 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
|
// The experiments flags are based on GOARCH, so they may
|
||||||
// need to change. TODO: This should be cleaned up.
|
// 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
|
ctxt.ToolTags = nil
|
||||||
for _, exp := range buildcfg.EnabledExperiments() {
|
for _, exp := range buildcfg.EnabledExperiments() {
|
||||||
ctxt.ToolTags = append(ctxt.ToolTags, "goexperiment."+exp)
|
ctxt.ToolTags = append(ctxt.ToolTags, "goexperiment."+exp)
|
||||||
|
|
@ -261,6 +272,7 @@ var (
|
||||||
// Used in envcmd.MkEnv and build ID computations.
|
// Used in envcmd.MkEnv and build ID computations.
|
||||||
GOARM = envOr("GOARM", fmt.Sprint(buildcfg.GOARM))
|
GOARM = envOr("GOARM", fmt.Sprint(buildcfg.GOARM))
|
||||||
GO386 = envOr("GO386", buildcfg.GO386)
|
GO386 = envOr("GO386", buildcfg.GO386)
|
||||||
|
GOAMD64 = envOr("GOAMD64", fmt.Sprintf("%s%d", "v", buildcfg.GOAMD64))
|
||||||
GOMIPS = envOr("GOMIPS", buildcfg.GOMIPS)
|
GOMIPS = envOr("GOMIPS", buildcfg.GOMIPS)
|
||||||
GOMIPS64 = envOr("GOMIPS64", buildcfg.GOMIPS64)
|
GOMIPS64 = envOr("GOMIPS64", buildcfg.GOMIPS64)
|
||||||
GOPPC64 = envOr("GOPPC64", fmt.Sprintf("%s%d", "power", buildcfg.GOPPC64))
|
GOPPC64 = envOr("GOPPC64", fmt.Sprintf("%s%d", "power", buildcfg.GOPPC64))
|
||||||
|
|
@ -287,6 +299,8 @@ func GetArchEnv() (key, val string) {
|
||||||
return "GOARM", GOARM
|
return "GOARM", GOARM
|
||||||
case "386":
|
case "386":
|
||||||
return "GO386", GO386
|
return "GO386", GO386
|
||||||
|
case "amd64":
|
||||||
|
return "GOAMD64", GOAMD64
|
||||||
case "mips", "mipsle":
|
case "mips", "mipsle":
|
||||||
return "GOMIPS", GOMIPS
|
return "GOMIPS", GOMIPS
|
||||||
case "mips64", "mips64le":
|
case "mips64", "mips64le":
|
||||||
|
|
@ -396,3 +410,24 @@ func gopathDir(rel string) string {
|
||||||
}
|
}
|
||||||
return filepath.Join(list[0], rel)
|
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
|
download cache, including unpacked source code of versioned
|
||||||
dependencies.
|
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 build flags, see 'go help build'.
|
||||||
|
|
||||||
For more about specifying packages, see 'go help packages'.
|
For more about specifying packages, see 'go help packages'.
|
||||||
|
|
@ -85,6 +92,7 @@ var (
|
||||||
cleanI bool // clean -i flag
|
cleanI bool // clean -i flag
|
||||||
cleanR bool // clean -r flag
|
cleanR bool // clean -r flag
|
||||||
cleanCache bool // clean -cache flag
|
cleanCache bool // clean -cache flag
|
||||||
|
cleanFuzzcache bool // clean -fuzzcache flag
|
||||||
cleanModcache bool // clean -modcache flag
|
cleanModcache bool // clean -modcache flag
|
||||||
cleanTestcache bool // clean -testcache flag
|
cleanTestcache bool // clean -testcache flag
|
||||||
)
|
)
|
||||||
|
|
@ -96,6 +104,7 @@ func init() {
|
||||||
CmdClean.Flag.BoolVar(&cleanI, "i", false, "")
|
CmdClean.Flag.BoolVar(&cleanI, "i", false, "")
|
||||||
CmdClean.Flag.BoolVar(&cleanR, "r", false, "")
|
CmdClean.Flag.BoolVar(&cleanR, "r", false, "")
|
||||||
CmdClean.Flag.BoolVar(&cleanCache, "cache", false, "")
|
CmdClean.Flag.BoolVar(&cleanCache, "cache", false, "")
|
||||||
|
CmdClean.Flag.BoolVar(&cleanFuzzcache, "fuzzcache", false, "")
|
||||||
CmdClean.Flag.BoolVar(&cleanModcache, "modcache", false, "")
|
CmdClean.Flag.BoolVar(&cleanModcache, "modcache", false, "")
|
||||||
CmdClean.Flag.BoolVar(&cleanTestcache, "testcache", 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.
|
// or no other target (such as a cache) was requested to be cleaned.
|
||||||
cleanPkg := len(args) > 0 || cleanI || cleanR
|
cleanPkg := len(args) > 0 || cleanI || cleanR
|
||||||
if (!modload.Enabled() || modload.HasModRoot()) &&
|
if (!modload.Enabled() || modload.HasModRoot()) &&
|
||||||
!cleanCache && !cleanModcache && !cleanTestcache {
|
!cleanCache && !cleanModcache && !cleanTestcache && !cleanFuzzcache {
|
||||||
cleanPkg = true
|
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.
|
// This also mimics what os.RemoveAll(dir) would do.
|
||||||
if err := os.RemoveAll(d); err != nil && !printedErrors {
|
if err := os.RemoveAll(d); err != nil && !printedErrors {
|
||||||
printedErrors = true
|
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 !cfg.BuildN {
|
||||||
if err := os.RemoveAll(logFile); err != nil && !printedErrors {
|
if err := os.RemoveAll(logFile); err != nil && !printedErrors {
|
||||||
printedErrors = true
|
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 err != nil {
|
||||||
if _, statErr := os.Stat(dir); !os.IsNotExist(statErr) {
|
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 cleanModcache {
|
||||||
if cfg.GOMODCACHE == "" {
|
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 {
|
if cfg.BuildN || cfg.BuildX {
|
||||||
b.Showcmd("", "rm -rf %s", cfg.GOMODCACHE)
|
b.Showcmd("", "rm -rf %s", cfg.GOMODCACHE)
|
||||||
}
|
}
|
||||||
if !cfg.BuildN {
|
if !cfg.BuildN {
|
||||||
if err := modfetch.RemoveAll(cfg.GOMODCACHE); err != nil {
|
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)
|
dirs, err := os.ReadDir(p.Dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Errorf("go clean %s: %v", p.Dir, err)
|
base.Errorf("go: %s: %v", p.Dir, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -334,7 +355,7 @@ func clean(p *load.Package) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := os.RemoveAll(filepath.Join(p.Dir, name)); err != nil {
|
if err := os.RemoveAll(filepath.Join(p.Dir, name)); err != nil {
|
||||||
base.Errorf("go clean: %v", err)
|
base.Errorf("go: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
|
|
@ -386,5 +407,5 @@ func removeFile(f string) {
|
||||||
return
|
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
|
// 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.
|
// 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...)
|
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
|
path. The go tool's usual package mechanism does not apply: package path
|
||||||
elements like . and ... are not implemented by go doc.
|
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
|
When run with two arguments, the first is a package path (full path or suffix),
|
||||||
suffix), and the second is a symbol, or symbol with method or struct field.
|
and the second is a symbol, or symbol with method or struct field:
|
||||||
This is similar to the syntax accepted by godoc:
|
|
||||||
|
|
||||||
go doc <pkg> <sym>[.<methodOrField>]
|
go doc <pkg> <sym>[.<methodOrField>]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import (
|
||||||
"cmd/go/internal/load"
|
"cmd/go/internal/load"
|
||||||
"cmd/go/internal/modload"
|
"cmd/go/internal/modload"
|
||||||
"cmd/go/internal/work"
|
"cmd/go/internal/work"
|
||||||
|
"cmd/internal/quoted"
|
||||||
)
|
)
|
||||||
|
|
||||||
var CmdEnv = &base.Command{
|
var CmdEnv = &base.Command{
|
||||||
|
|
@ -104,13 +105,13 @@ func MkEnv() []cfg.EnvVar {
|
||||||
env = append(env, cfg.EnvVar{Name: key, Value: val})
|
env = append(env, cfg.EnvVar{Name: key, Value: val})
|
||||||
}
|
}
|
||||||
|
|
||||||
cc := cfg.DefaultCC(cfg.Goos, cfg.Goarch)
|
cc := cfg.Getenv("CC")
|
||||||
if env := strings.Fields(cfg.Getenv("CC")); len(env) > 0 {
|
if cc == "" {
|
||||||
cc = env[0]
|
cc = cfg.DefaultCC(cfg.Goos, cfg.Goarch)
|
||||||
}
|
}
|
||||||
cxx := cfg.DefaultCXX(cfg.Goos, cfg.Goarch)
|
cxx := cfg.Getenv("CXX")
|
||||||
if env := strings.Fields(cfg.Getenv("CXX")); len(env) > 0 {
|
if cxx == "" {
|
||||||
cxx = env[0]
|
cxx = cfg.DefaultCXX(cfg.Goos, cfg.Goarch)
|
||||||
}
|
}
|
||||||
env = append(env, cfg.EnvVar{Name: "AR", Value: envOr("AR", "ar")})
|
env = append(env, cfg.EnvVar{Name: "AR", Value: envOr("AR", "ar")})
|
||||||
env = append(env, cfg.EnvVar{Name: "CC", Value: cc})
|
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.
|
// ExtraEnvVars returns environment variables that should not leak into child processes.
|
||||||
func ExtraEnvVars() []cfg.EnvVar {
|
func ExtraEnvVars() []cfg.EnvVar {
|
||||||
gomod := ""
|
gomod := ""
|
||||||
|
modload.Init()
|
||||||
if modload.HasModRoot() {
|
if modload.HasModRoot() {
|
||||||
gomod = filepath.Join(modload.ModRoot(), "go.mod")
|
gomod = modload.ModFilePath()
|
||||||
} else if modload.Enabled() {
|
} else if modload.Enabled() {
|
||||||
gomod = os.DevNull
|
gomod = os.DevNull
|
||||||
}
|
}
|
||||||
|
modload.InitWorkfile()
|
||||||
|
gowork := modload.WorkFilePath()
|
||||||
return []cfg.EnvVar{
|
return []cfg.EnvVar{
|
||||||
{Name: "GOMOD", Value: gomod},
|
{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) {
|
func runEnv(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
if *envJson && *envU {
|
if *envJson && *envU {
|
||||||
base.Fatalf("go env: cannot use -json with -u")
|
base.Fatalf("go: cannot use -json with -u")
|
||||||
}
|
}
|
||||||
if *envJson && *envW {
|
if *envJson && *envW {
|
||||||
base.Fatalf("go env: cannot use -json with -w")
|
base.Fatalf("go: cannot use -json with -w")
|
||||||
}
|
}
|
||||||
if *envU && *envW {
|
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,
|
// 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) {
|
func runEnvW(args []string) {
|
||||||
// Process and sanity-check command line.
|
// Process and sanity-check command line.
|
||||||
if len(args) == 0 {
|
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)
|
osEnv := make(map[string]string)
|
||||||
for _, e := range cfg.OrigEnv {
|
for _, e := range cfg.OrigEnv {
|
||||||
|
|
@ -287,14 +292,14 @@ func runEnvW(args []string) {
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
i := strings.Index(arg, "=")
|
i := strings.Index(arg, "=")
|
||||||
if i < 0 {
|
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:]
|
key, val := arg[:i], arg[i+1:]
|
||||||
if err := checkEnvWrite(key, val); err != nil {
|
if err := checkEnvWrite(key, val); err != nil {
|
||||||
base.Fatalf("go env -w: %v", err)
|
base.Fatalf("go: %v", err)
|
||||||
}
|
}
|
||||||
if _, ok := add[key]; ok {
|
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
|
add[key] = val
|
||||||
if osVal := osEnv[key]; osVal != "" && osVal != val {
|
if osVal := osEnv[key]; osVal != "" && osVal != val {
|
||||||
|
|
@ -303,13 +308,13 @@ func runEnvW(args []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := checkBuildConfig(add, nil); err != nil {
|
if err := checkBuildConfig(add, nil); err != nil {
|
||||||
base.Fatalf("go env -w: %v", err)
|
base.Fatalf("go: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
gotmp, okGOTMP := add["GOTMPDIR"]
|
gotmp, okGOTMP := add["GOTMPDIR"]
|
||||||
if okGOTMP {
|
if okGOTMP {
|
||||||
if !filepath.IsAbs(gotmp) && gotmp != "" {
|
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) {
|
func runEnvU(args []string) {
|
||||||
// Process and sanity-check command line.
|
// Process and sanity-check command line.
|
||||||
if len(args) == 0 {
|
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)
|
del := make(map[string]bool)
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
if err := checkEnvWrite(arg, ""); err != nil {
|
if err := checkEnvWrite(arg, ""); err != nil {
|
||||||
base.Fatalf("go env -u: %v", err)
|
base.Fatalf("go: %v", err)
|
||||||
}
|
}
|
||||||
del[arg] = true
|
del[arg] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := checkBuildConfig(nil, del); err != nil {
|
if err := checkBuildConfig(nil, del); err != nil {
|
||||||
base.Fatalf("go env -u: %v", err)
|
base.Fatalf("go: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
updateEnvFile(nil, del)
|
updateEnvFile(nil, del)
|
||||||
|
|
@ -414,7 +419,7 @@ func printEnvAsJSON(env []cfg.EnvVar) {
|
||||||
enc := json.NewEncoder(os.Stdout)
|
enc := json.NewEncoder(os.Stdout)
|
||||||
enc.SetIndent("", "\t")
|
enc.SetIndent("", "\t")
|
||||||
if err := enc.Encode(m); err != nil {
|
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 {
|
func checkEnvWrite(key, val string) error {
|
||||||
switch key {
|
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)
|
return fmt.Errorf("%s cannot be modified", key)
|
||||||
case "GOENV":
|
case "GOENV":
|
||||||
return fmt.Errorf("%s can only be set using the OS environment", key)
|
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 != "" {
|
if !filepath.IsAbs(val) && val != "" {
|
||||||
return fmt.Errorf("GOPATH entry is relative; must be absolute path: %q", val)
|
return fmt.Errorf("GOPATH entry is relative; must be absolute path: %q", val)
|
||||||
}
|
}
|
||||||
// Make sure CC and CXX are absolute paths
|
case "GOMODCACHE":
|
||||||
case "CC", "CXX", "GOMODCACHE":
|
if !filepath.IsAbs(val) && val != "" {
|
||||||
if !filepath.IsAbs(val) && val != "" && val != filepath.Base(val) {
|
return fmt.Errorf("GOMODCACHE entry is relative; must be absolute path: %q", val)
|
||||||
return fmt.Errorf("%s entry is relative; must be absolute path: %q", key, 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) {
|
func updateEnvFile(add map[string]string, del map[string]bool) {
|
||||||
file, err := cfg.EnvFile()
|
file, err := cfg.EnvFile()
|
||||||
if file == "" {
|
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)
|
data, err := os.ReadFile(file)
|
||||||
if err != nil && (!os.IsNotExist(err) || len(add) == 0) {
|
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")
|
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)
|
os.MkdirAll(filepath.Dir(file), 0777)
|
||||||
err = os.WriteFile(file, data, 0666)
|
err = os.WriteFile(file, data, 0666)
|
||||||
if err != nil {
|
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/load"
|
||||||
"cmd/go/internal/modload"
|
"cmd/go/internal/modload"
|
||||||
"cmd/go/internal/str"
|
"cmd/go/internal/str"
|
||||||
|
"cmd/go/internal/work"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"go/build"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
var CmdFix = &base.Command{
|
var CmdFix = &base.Command{
|
||||||
Run: runFix,
|
UsageLine: "go fix [-fix list] [packages]",
|
||||||
UsageLine: "go fix [packages]",
|
|
||||||
Short: "update packages to use new APIs",
|
Short: "update packages to use new APIs",
|
||||||
Long: `
|
Long: `
|
||||||
Fix runs the Go fix command on the packages named by the import paths.
|
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 fix, see 'go doc cmd/fix'.
|
||||||
For more about specifying packages, see 'go help packages'.
|
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.
|
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) {
|
func runFix(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
pkgs := load.PackagesAndErrors(ctx, load.PackageOpts{}, args)
|
pkgs := load.PackagesAndErrors(ctx, load.PackageOpts{}, args)
|
||||||
w := 0
|
w := 0
|
||||||
|
|
@ -58,6 +70,16 @@ func runFix(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
// the command only applies to this package,
|
// the command only applies to this package,
|
||||||
// not to packages in subdirectories.
|
// not to packages in subdirectories.
|
||||||
files := base.RelPaths(pkg.InternalAllGoFiles())
|
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"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"cmd/go/internal/base"
|
"cmd/go/internal/base"
|
||||||
"cmd/go/internal/cfg"
|
"cmd/go/internal/cfg"
|
||||||
"cmd/go/internal/load"
|
"cmd/go/internal/load"
|
||||||
"cmd/go/internal/modload"
|
"cmd/go/internal/modload"
|
||||||
"cmd/go/internal/str"
|
"cmd/internal/sys"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
@ -53,18 +51,13 @@ See also: go fix, go vet.
|
||||||
func runFmt(ctx context.Context, cmd *base.Command, args []string) {
|
func runFmt(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
printed := false
|
printed := false
|
||||||
gofmt := gofmtPath()
|
gofmt := gofmtPath()
|
||||||
procs := runtime.GOMAXPROCS(0)
|
|
||||||
var wg sync.WaitGroup
|
gofmtArgs := []string{gofmt, "-l", "-w"}
|
||||||
wg.Add(procs)
|
gofmtArgLen := len(gofmt) + len(" -l -w")
|
||||||
fileC := make(chan string, 2*procs)
|
|
||||||
for i := 0; i < procs; i++ {
|
baseGofmtArgs := len(gofmtArgs)
|
||||||
go func() {
|
baseGofmtArgLen := gofmtArgLen
|
||||||
defer wg.Done()
|
|
||||||
for file := range fileC {
|
|
||||||
base.Run(str.StringList(gofmt, "-l", "-w", file))
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
for _, pkg := range load.PackagesAndErrors(ctx, load.PackageOpts{}, args) {
|
for _, pkg := range load.PackagesAndErrors(ctx, load.PackageOpts{}, args) {
|
||||||
if modload.Enabled() && pkg.Module != nil && !pkg.Module.Main {
|
if modload.Enabled() && pkg.Module != nil && !pkg.Module.Main {
|
||||||
if !printed {
|
if !printed {
|
||||||
|
|
@ -89,11 +82,18 @@ func runFmt(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
// not to packages in subdirectories.
|
// not to packages in subdirectories.
|
||||||
files := base.RelPaths(pkg.InternalAllGoFiles())
|
files := base.RelPaths(pkg.InternalAllGoFiles())
|
||||||
for _, file := range files {
|
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)
|
if len(gofmtArgs) > baseGofmtArgs {
|
||||||
wg.Wait()
|
base.Run(gofmtArgs)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func gofmtPath() string {
|
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) Mode() fs.FileMode { return f.real.Mode() }
|
||||||
func (f fakeFile) ModTime() time.Time { return f.real.ModTime() }
|
func (f fakeFile) ModTime() time.Time { return f.real.ModTime() }
|
||||||
func (f fakeFile) IsDir() bool { return f.real.IsDir() }
|
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
|
// missingFile provides an fs.FileInfo for an overlaid file where the
|
||||||
// destination file in the overlay doesn't exist. It returns zero values
|
// 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) Mode() fs.FileMode { return fs.ModeIrregular }
|
||||||
func (f missingFile) ModTime() time.Time { return time.Unix(0, 0) }
|
func (f missingFile) ModTime() time.Time { return time.Unix(0, 0) }
|
||||||
func (f missingFile) IsDir() bool { return false }
|
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
|
// fakeDir provides an fs.FileInfo implementation for directories that are
|
||||||
// implicitly created by overlaid files. Each directory in the
|
// 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) Mode() fs.FileMode { return fs.ModeDir | 0500 }
|
||||||
func (f fakeDir) ModTime() time.Time { return time.Unix(0, 0) }
|
func (f fakeDir) ModTime() time.Time { return time.Unix(0, 0) }
|
||||||
func (f fakeDir) IsDir() bool { return true }
|
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.
|
// Glob is like filepath.Glob but uses the overlay file system.
|
||||||
func Glob(pattern string) (matches []string, err error) {
|
func Glob(pattern string) (matches []string, err error) {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package fsys
|
package fsys
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"cmd/go/internal/txtar"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -12,6 +11,8 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"golang.org/x/tools/txtar"
|
||||||
)
|
)
|
||||||
|
|
||||||
// initOverlay resets the overlay state to reflect the config.
|
// 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
|
files. Those commands can run any process but the intent is to
|
||||||
create or update Go source files.
|
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.
|
and so on. It must be run explicitly.
|
||||||
|
|
||||||
Go generate scans the file for directives, which are lines of
|
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.
|
// errorf logs an error message prefixed with the file and line number.
|
||||||
// It then exits the program (with exit status 1) because generation stops
|
// It then exits the program (with exit status 1) because generation stops
|
||||||
// at the first error.
|
// 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.Fprintf(os.Stderr, "%s:%d: %s\n", base.ShortPath(g.path), g.lineNum,
|
||||||
fmt.Sprintf(format, args...))
|
fmt.Sprintf(format, args...))
|
||||||
panic(stop)
|
panic(stop)
|
||||||
|
|
|
||||||
|
|
@ -114,16 +114,16 @@ func init() {
|
||||||
func runGet(ctx context.Context, cmd *base.Command, args []string) {
|
func runGet(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
if cfg.ModulesEnabled {
|
if cfg.ModulesEnabled {
|
||||||
// Should not happen: main.go should install the separate module-enabled get code.
|
// 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()
|
work.BuildInit()
|
||||||
|
|
||||||
if *getF && !*getU {
|
if *getF && !*getU {
|
||||||
base.Fatalf("go get: cannot use -f flag without -u")
|
base.Fatalf("go: cannot use -f flag without -u")
|
||||||
}
|
}
|
||||||
if *getInsecure {
|
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.
|
// 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 the argument has no slash or refers to an existing file.
|
||||||
if strings.HasSuffix(arg, ".go") {
|
if strings.HasSuffix(arg, ".go") {
|
||||||
if !strings.Contains(arg, "/") {
|
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
|
continue
|
||||||
}
|
}
|
||||||
if fi, err := os.Stat(arg); err == nil && !fi.IsDir() {
|
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()
|
base.ExitIfErrors()
|
||||||
|
|
||||||
var pkgs []string
|
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(), "...") {
|
if len(m.Pkgs) == 0 && strings.Contains(m.Pattern(), "...") {
|
||||||
pkgs = append(pkgs, m.Pattern())
|
pkgs = append(pkgs, m.Pattern())
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -315,7 +316,8 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int)
|
||||||
if wildcardOkay && strings.Contains(arg, "...") {
|
if wildcardOkay && strings.Contains(arg, "...") {
|
||||||
match := search.NewMatch(arg)
|
match := search.NewMatch(arg)
|
||||||
if match.IsLocal() {
|
if match.IsLocal() {
|
||||||
match.MatchDirs()
|
noModRoots := []string{} // We're in gopath mode, so there are no modroots.
|
||||||
|
match.MatchDirs(noModRoots)
|
||||||
args = match.Dirs
|
args = match.Dirs
|
||||||
} else {
|
} else {
|
||||||
match.MatchPackages()
|
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.
|
// to make the first copy of or update a copy of the given package.
|
||||||
func downloadPackage(p *load.Package) error {
|
func downloadPackage(p *load.Package) error {
|
||||||
var (
|
var (
|
||||||
vcsCmd *vcs.Cmd
|
vcsCmd *vcs.Cmd
|
||||||
repo, rootPath string
|
repo, rootPath, repoDir string
|
||||||
err error
|
err error
|
||||||
blindRepo bool // set if the repo has unusual configuration
|
blindRepo bool // set if the repo has unusual configuration
|
||||||
)
|
)
|
||||||
|
|
||||||
// p can be either a real package, or a pseudo-package whose “import path” is
|
// 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 != "" {
|
if p.Internal.Build.SrcRoot != "" {
|
||||||
// Directory exists. Look for checkout along path to src.
|
// 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 {
|
if err != nil {
|
||||||
return err
|
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
|
repo = "<local>" // should be unused; make distinctive
|
||||||
|
|
||||||
// Double-check where it came from.
|
// 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.
|
// 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 := template.New("top")
|
||||||
t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize})
|
t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize})
|
||||||
template.Must(t.Parse(text))
|
template.Must(t.Parse(text))
|
||||||
|
|
|
||||||
|
|
@ -592,6 +592,10 @@ Architecture-specific environment variables:
|
||||||
GO386
|
GO386
|
||||||
For GOARCH=386, how to implement floating point instructions.
|
For GOARCH=386, how to implement floating point instructions.
|
||||||
Valid values are sse2 (default), softfloat.
|
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
|
GOMIPS
|
||||||
For GOARCH=mips{,le}, whether to use floating point instructions.
|
For GOARCH=mips{,le}, whether to use floating point instructions.
|
||||||
Valid values are hardfloat (default), softfloat.
|
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
|
See 'go help test' for details. Running 'go clean -testcache' removes
|
||||||
all cached test results (but not cached build results).
|
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
|
The GODEBUG environment variable can enable printing of debugging
|
||||||
information about the state of the cache:
|
information about the state of the cache:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,51 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// 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
|
package imports
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"go/build/constraint"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"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,
|
// ShouldBuild reports whether it is okay to use this file,
|
||||||
// The rule is that in the file's leading run of // comments
|
// The rule is that in the file's leading run of // comments
|
||||||
|
|
@ -34,90 +68,124 @@ var slashslash = []byte("//")
|
||||||
// in any build.
|
// in any build.
|
||||||
//
|
//
|
||||||
func ShouldBuild(content []byte, tags map[string]bool) bool {
|
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.
|
// which must be followed by a blank line.
|
||||||
end := 0
|
// Also identify any //go:build comments.
|
||||||
p := content
|
content, goBuild, _, err := parseFileHeader(content)
|
||||||
for len(p) > 0 {
|
if err != nil {
|
||||||
line := p
|
return false
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
content = content[:end]
|
|
||||||
|
|
||||||
// Pass 2. Process each line in the run.
|
// If //go:build line is present, it controls.
|
||||||
p = content
|
// Otherwise fall back to +build processing.
|
||||||
allok := true
|
var shouldBuild bool
|
||||||
for len(p) > 0 {
|
switch {
|
||||||
line := p
|
case goBuild != nil:
|
||||||
if i := bytes.IndexByte(line, '\n'); i >= 0 {
|
x, err := constraint.Parse(string(goBuild))
|
||||||
line, p = line[:i], p[i+1:]
|
if err != nil {
|
||||||
} else {
|
return false
|
||||||
p = p[len(p):]
|
|
||||||
}
|
}
|
||||||
line = bytes.TrimSpace(line)
|
shouldBuild = eval(x, tags, true)
|
||||||
if !bytes.HasPrefix(line, slashslash) {
|
|
||||||
continue
|
default:
|
||||||
}
|
shouldBuild = true
|
||||||
line = bytes.TrimSpace(line[len(slashslash):])
|
p := content
|
||||||
if len(line) > 0 && line[0] == '+' {
|
for len(p) > 0 {
|
||||||
// Looks like a comment +line.
|
line := p
|
||||||
f := strings.Fields(string(line))
|
if i := bytes.IndexByte(line, '\n'); i >= 0 {
|
||||||
if f[0] == "+build" {
|
line, p = line[:i], p[i+1:]
|
||||||
ok := false
|
} else {
|
||||||
for _, tok := range f[1:] {
|
p = p[len(p):]
|
||||||
if matchTags(tok, tags) {
|
}
|
||||||
ok = true
|
line = bytes.TrimSpace(line)
|
||||||
}
|
if !bytes.HasPrefix(line, bSlashSlash) || !bytes.Contains(line, bPlusBuild) {
|
||||||
}
|
continue
|
||||||
if !ok {
|
}
|
||||||
allok = false
|
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:
|
func parseFileHeader(content []byte) (trimmed, goBuild []byte, sawBinaryOnly bool, err error) {
|
||||||
//
|
end := 0
|
||||||
// tag (if tags[tag] is true)
|
p := content
|
||||||
// !tag (if tags[tag] is false)
|
ended := false // found non-blank, non-// line, so stopped accepting // +build lines
|
||||||
// a comma-separated list of any of these
|
inSlashStar := false // in /* */ comment
|
||||||
//
|
|
||||||
func matchTags(name string, tags map[string]bool) bool {
|
Lines:
|
||||||
if name == "" {
|
for len(p) > 0 {
|
||||||
return false
|
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
|
return content[:end], goBuild, sawBinaryOnly, nil
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// matchTag reports whether the tag name is valid and satisfied by tags[name]==want.
|
// matchTag reports whether the tag name is valid and tags[name] is true.
|
||||||
func matchTag(name string, tags map[string]bool, want bool) bool {
|
// 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.
|
// Tags must be letters, digits, underscores or dots.
|
||||||
// Unlike in Go identifiers, all digits are fine (e.g., "386").
|
// Unlike in Go identifiers, all digits are fine (e.g., "386").
|
||||||
for _, c := range name {
|
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
|
// if we put * in the tags map then all tags
|
||||||
// except "ignore" are considered both present and not
|
// except "ignore" are considered both present and not
|
||||||
// (so we return true no matter how 'want' is set).
|
// (so we return true no matter how 'want' is set).
|
||||||
return true
|
return prefer
|
||||||
}
|
}
|
||||||
|
|
||||||
have := tags[name]
|
have := tags[name]
|
||||||
|
|
@ -144,7 +212,25 @@ func matchTag(name string, tags map[string]bool, want bool) bool {
|
||||||
if name == "darwin" {
|
if name == "darwin" {
|
||||||
have = have || tags["ios"]
|
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
|
// MatchFile returns false if the name contains a $GOOS or $GOARCH
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ func TestScan(t *testing.T) {
|
||||||
}
|
}
|
||||||
if p == "net/http" {
|
if p == "net/http" {
|
||||||
// A test import but not an import
|
// 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 {
|
if !foundBase64 {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
//go:build android
|
||||||
// +build android
|
// +build android
|
||||||
|
|
||||||
package android
|
package android
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
//go:build linux
|
||||||
// +build linux
|
// +build linux
|
||||||
|
|
||||||
package android
|
package android
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
//go:build !android
|
||||||
// +build !android
|
// +build !android
|
||||||
|
|
||||||
package android
|
package android
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
//go:build illumos
|
||||||
// +build illumos
|
// +build illumos
|
||||||
|
|
||||||
package illumos
|
package illumos
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
//go:build solaris
|
||||||
// +build solaris
|
// +build solaris
|
||||||
|
|
||||||
package illumos
|
package illumos
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
//go:build !illumos
|
||||||
// +build !illumos
|
// +build !illumos
|
||||||
|
|
||||||
package illumos
|
package illumos
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
// +build blahblh
|
//go:build blahblh && linux && !linux && windows && darwin
|
||||||
// +build linux
|
// +build blahblh,linux,!linux,windows,darwin
|
||||||
// +build !linux
|
|
||||||
// +build windows
|
|
||||||
// +build darwin
|
|
||||||
|
|
||||||
package x
|
package x
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -316,6 +316,7 @@ For more about modules, see https://golang.org/ref/mod.
|
||||||
func init() {
|
func init() {
|
||||||
CmdList.Run = runList // break init cycle
|
CmdList.Run = runList // break init cycle
|
||||||
work.AddBuildFlags(CmdList, work.DefaultBuildFlags)
|
work.AddBuildFlags(CmdList, work.DefaultBuildFlags)
|
||||||
|
base.AddWorkfileFlag(&CmdList.Flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -336,6 +337,8 @@ var (
|
||||||
var nl = []byte{'\n'}
|
var nl = []byte{'\n'}
|
||||||
|
|
||||||
func runList(ctx context.Context, cmd *base.Command, args []string) {
|
func runList(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
|
modload.InitWorkfile()
|
||||||
|
|
||||||
if *listFmt != "" && *listJson == true {
|
if *listFmt != "" && *listJson == true {
|
||||||
base.Fatalf("go list -f cannot be used with -json")
|
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 {
|
if *listJson {
|
||||||
do = func(x interface{}) {
|
do = func(x any) {
|
||||||
b, err := json.MarshalIndent(x, "", "\t")
|
b, err := json.MarshalIndent(x, "", "\t")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
out.Flush()
|
out.Flush()
|
||||||
|
|
@ -383,7 +386,7 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf("%s", err)
|
base.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
do = func(x interface{}) {
|
do = func(x any) {
|
||||||
if err := tmpl.Execute(out, x); err != nil {
|
if err := tmpl.Execute(out, x); err != nil {
|
||||||
out.Flush()
|
out.Flush()
|
||||||
base.Fatalf("%s", err)
|
base.Fatalf("%s", err)
|
||||||
|
|
@ -424,12 +427,12 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if modload.Init(); !modload.Enabled() {
|
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.
|
modload.LoadModFile(ctx) // Sets cfg.BuildMod as a side-effect.
|
||||||
if cfg.BuildMod == "vendor" {
|
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 {
|
if *listVersions {
|
||||||
base.Fatalf(actionDisabledFormat, "determine available versions")
|
base.Fatalf(actionDisabledFormat, "determine available versions")
|
||||||
|
|
@ -468,11 +471,11 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
if !*listE {
|
if !*listE {
|
||||||
for _, m := range mods {
|
for _, m := range mods {
|
||||||
if m.Error != nil {
|
if m.Error != nil {
|
||||||
base.Errorf("go list -m: %v", m.Error.Err)
|
base.Errorf("go: %v", m.Error.Err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Errorf("go list -m: %v", err)
|
base.Errorf("go: %v", err)
|
||||||
}
|
}
|
||||||
base.ExitIfErrors()
|
base.ExitIfErrors()
|
||||||
}
|
}
|
||||||
|
|
@ -708,7 +711,7 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
}
|
}
|
||||||
rmods, err := modload.ListModules(ctx, args, mode)
|
rmods, err := modload.ListModules(ctx, args, mode)
|
||||||
if err != nil && !*listE {
|
if err != nil && !*listE {
|
||||||
base.Errorf("go list -retracted: %v", err)
|
base.Errorf("go: %v", err)
|
||||||
}
|
}
|
||||||
for i, arg := range args {
|
for i, arg := range args {
|
||||||
rmod := rmods[i]
|
rmod := rmods[i]
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ package load
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"cmd/go/internal/base"
|
"cmd/go/internal/base"
|
||||||
"cmd/go/internal/str"
|
"cmd/internal/quoted"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
@ -22,6 +22,7 @@ var (
|
||||||
// that allows specifying different effective flags for different packages.
|
// that allows specifying different effective flags for different packages.
|
||||||
// See 'go help build' for more details about per-package flags.
|
// See 'go help build' for more details about per-package flags.
|
||||||
type PerPackageFlag struct {
|
type PerPackageFlag struct {
|
||||||
|
raw string
|
||||||
present bool
|
present bool
|
||||||
values []ppfValue
|
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.
|
// set is the implementation of Set, taking a cwd (current working directory) for easier testing.
|
||||||
func (f *PerPackageFlag) set(v, cwd string) error {
|
func (f *PerPackageFlag) set(v, cwd string) error {
|
||||||
|
f.raw = v
|
||||||
f.present = true
|
f.present = true
|
||||||
match := func(p *Package) bool { return p.Internal.CmdlinePkg || p.Internal.CmdlineFiles } // default predicate with no pattern
|
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.
|
// 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)
|
match = MatchPackage(pattern, cwd)
|
||||||
v = v[i+1:]
|
v = v[i+1:]
|
||||||
}
|
}
|
||||||
flags, err := str.SplitQuotedFields(v)
|
flags, err := quoted.Split(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -72,9 +74,7 @@ func (f *PerPackageFlag) set(v, cwd string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// String is required to implement flag.Value.
|
func (f *PerPackageFlag) String() string { return f.raw }
|
||||||
// It is not used, because cmd/go never calls flag.PrintDefaults.
|
|
||||||
func (f *PerPackageFlag) String() string { return "<PerPackageFlag>" }
|
|
||||||
|
|
||||||
// Present reports whether the flag appeared on the command line.
|
// Present reports whether the flag appeared on the command line.
|
||||||
func (f *PerPackageFlag) Present() bool {
|
func (f *PerPackageFlag) Present() bool {
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,11 @@ import (
|
||||||
pathpkg "path"
|
pathpkg "path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"runtime/debug"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
"unicode"
|
"unicode"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
|
|
@ -38,6 +40,7 @@ import (
|
||||||
"cmd/go/internal/search"
|
"cmd/go/internal/search"
|
||||||
"cmd/go/internal/str"
|
"cmd/go/internal/str"
|
||||||
"cmd/go/internal/trace"
|
"cmd/go/internal/trace"
|
||||||
|
"cmd/go/internal/vcs"
|
||||||
"cmd/internal/sys"
|
"cmd/internal/sys"
|
||||||
|
|
||||||
"golang.org/x/mod/modfile"
|
"golang.org/x/mod/modfile"
|
||||||
|
|
@ -203,6 +206,7 @@ type PackageInternal struct {
|
||||||
Local bool // imported via local path (./ or ../)
|
Local bool // imported via local path (./ or ../)
|
||||||
LocalPrefix string // interpret ./ and ../ imports relative to this prefix
|
LocalPrefix string // interpret ./ and ../ imports relative to this prefix
|
||||||
ExeName string // desired name for temporary executable
|
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
|
CoverMode string // preprocess Go source files with the coverage tool in this mode
|
||||||
CoverVars map[string]*CoverVar // variables created by coverage analysis
|
CoverVars map[string]*CoverVar // variables created by coverage analysis
|
||||||
OmitDebug bool // tell linker not to write debug information
|
OmitDebug bool // tell linker not to write debug information
|
||||||
|
|
@ -494,7 +498,7 @@ type importError struct {
|
||||||
err error // created with fmt.Errorf
|
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...)}
|
err := &importError{importPath: path, err: fmt.Errorf(format, args...)}
|
||||||
if errStr := err.Error(); !strings.Contains(errStr, path) {
|
if errStr := err.Error(); !strings.Contains(errStr, path) {
|
||||||
panic(fmt.Sprintf("path %q not in error %q", path, errStr))
|
panic(fmt.Sprintf("path %q not in error %q", path, errStr))
|
||||||
|
|
@ -585,10 +589,10 @@ func ClearPackageCachePartial(args []string) {
|
||||||
delete(packageCache, arg)
|
delete(packageCache, arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resolvedImportCache.DeleteIf(func(key interface{}) bool {
|
resolvedImportCache.DeleteIf(func(key any) bool {
|
||||||
return shouldDelete[key.(importSpec).path]
|
return shouldDelete[key.(importSpec).path]
|
||||||
})
|
})
|
||||||
packageDataCache.DeleteIf(func(key interface{}) bool {
|
packageDataCache.DeleteIf(func(key any) bool {
|
||||||
return shouldDelete[key.(string)]
|
return shouldDelete[key.(string)]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -601,7 +605,7 @@ func ReloadPackageNoFlags(arg string, stk *ImportStack) *Package {
|
||||||
p := packageCache[arg]
|
p := packageCache[arg]
|
||||||
if p != nil {
|
if p != nil {
|
||||||
delete(packageCache, arg)
|
delete(packageCache, arg)
|
||||||
resolvedImportCache.DeleteIf(func(key interface{}) bool {
|
resolvedImportCache.DeleteIf(func(key any) bool {
|
||||||
return key.(importSpec).path == p.ImportPath
|
return key.(importSpec).path == p.ImportPath
|
||||||
})
|
})
|
||||||
packageDataCache.Delete(p.ImportPath)
|
packageDataCache.Delete(p.ImportPath)
|
||||||
|
|
@ -813,7 +817,7 @@ func loadPackageData(ctx context.Context, path, parentPath, parentDir, parentRoo
|
||||||
parentIsStd: parentIsStd,
|
parentIsStd: parentIsStd,
|
||||||
mode: mode,
|
mode: mode,
|
||||||
}
|
}
|
||||||
r := resolvedImportCache.Do(importKey, func() interface{} {
|
r := resolvedImportCache.Do(importKey, func() any {
|
||||||
var r resolvedImport
|
var r resolvedImport
|
||||||
if build.IsLocalImport(path) {
|
if build.IsLocalImport(path) {
|
||||||
r.dir = filepath.Join(parentDir, 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
|
// Load the package from its directory. If we already found the package's
|
||||||
// directory when resolving its import path, use that.
|
// directory when resolving its import path, use that.
|
||||||
data := packageDataCache.Do(r.path, func() interface{} {
|
data := packageDataCache.Do(r.path, func() any {
|
||||||
loaded = true
|
loaded = true
|
||||||
var data packageData
|
var data packageData
|
||||||
if r.dir != "" {
|
if r.dir != "" {
|
||||||
|
|
@ -1059,7 +1063,7 @@ func cleanImport(path string) string {
|
||||||
var isDirCache par.Cache
|
var isDirCache par.Cache
|
||||||
|
|
||||||
func isDir(path string) bool {
|
func isDir(path string) bool {
|
||||||
return isDirCache.Do(path, func() interface{} {
|
return isDirCache.Do(path, func() any {
|
||||||
fi, err := fsys.Stat(path)
|
fi, err := fsys.Stat(path)
|
||||||
return err == nil && fi.IsDir()
|
return err == nil && fi.IsDir()
|
||||||
}).(bool)
|
}).(bool)
|
||||||
|
|
@ -1187,7 +1191,7 @@ var (
|
||||||
|
|
||||||
// goModPath returns the module path in the go.mod in dir, if any.
|
// goModPath returns the module path in the go.mod in dir, if any.
|
||||||
func goModPath(dir string) (path string) {
|
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"))
|
data, err := os.ReadFile(filepath.Join(dir, "go.mod"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ""
|
return ""
|
||||||
|
|
@ -1456,9 +1460,9 @@ func disallowInternal(ctx context.Context, srcDir string, importer *Package, imp
|
||||||
// The importer is a list of command-line files.
|
// The importer is a list of command-line files.
|
||||||
// Pretend that the import path is the import path of the
|
// Pretend that the import path is the import path of the
|
||||||
// directory containing them.
|
// 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.
|
// 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]
|
parentOfInternal := p.ImportPath[:i]
|
||||||
if str.HasPathPrefix(importerPath, parentOfInternal) {
|
if str.HasPathPrefix(importerPath, parentOfInternal) {
|
||||||
|
|
@ -1628,6 +1632,7 @@ var cgoSyscallExclude = map[string]bool{
|
||||||
"runtime/cgo": true,
|
"runtime/cgo": true,
|
||||||
"runtime/race": true,
|
"runtime/race": true,
|
||||||
"runtime/msan": true,
|
"runtime/msan": true,
|
||||||
|
"runtime/asan": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
var foldPath = make(map[string]string)
|
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) {
|
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)
|
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.
|
// Synthesized main packages sometimes override this.
|
||||||
if p.Internal.Local {
|
if p.Internal.Local && !cfg.ModulesEnabled {
|
||||||
p.Internal.LocalPrefix = dirToImportPath(p.Dir)
|
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.Internal.Imports = imports
|
||||||
p.collectDeps()
|
p.collectDeps()
|
||||||
|
if p.Error == nil && p.Name == "main" && len(p.DepsErrors) == 0 {
|
||||||
if cfg.ModulesEnabled && p.Error == nil && p.Name == "main" && len(p.DepsErrors) == 0 {
|
p.setBuildInfo()
|
||||||
p.Internal.BuildInfo = modload.PackageBuildInfo(pkgPath, p.Deps)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// unsafe is a fake package.
|
// unsafe is a fake package.
|
||||||
|
|
@ -2018,13 +2023,18 @@ func resolveEmbed(pkgdir string, patterns []string) (files []string, pmap map[st
|
||||||
for _, pattern = range patterns {
|
for _, pattern = range patterns {
|
||||||
pid++
|
pid++
|
||||||
|
|
||||||
|
glob := pattern
|
||||||
|
all := strings.HasPrefix(pattern, "all:")
|
||||||
|
if all {
|
||||||
|
glob = pattern[len("all:"):]
|
||||||
|
}
|
||||||
// Check pattern is valid for //go:embed.
|
// 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")
|
return nil, nil, fmt.Errorf("invalid pattern syntax")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Glob to find matches.
|
// 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 {
|
if err != nil {
|
||||||
return nil, nil, err
|
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:])
|
rel := filepath.ToSlash(path[len(pkgdir)+1:])
|
||||||
name := info.Name()
|
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.
|
// Ignore bad names, assuming they won't go into modules.
|
||||||
// Also avoid hidden files that user may not know about.
|
// Also avoid hidden files that user may not know about.
|
||||||
// See golang.org/issue/42328.
|
// 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,
|
// SafeArg reports whether arg is a "safe" command-line argument,
|
||||||
// meaning that when it appears in a command-line, it probably
|
// meaning that when it appears in a command-line, it probably
|
||||||
// doesn't have some special meaning other than its own name.
|
// doesn't have some special meaning other than its own name.
|
||||||
|
|
@ -2237,6 +2470,10 @@ func LinkerDeps(p *Package) []string {
|
||||||
if cfg.BuildMSan {
|
if cfg.BuildMSan {
|
||||||
deps = append(deps, "runtime/msan")
|
deps = append(deps, "runtime/msan")
|
||||||
}
|
}
|
||||||
|
// Using address sanitizer forces an import of runtime/asan.
|
||||||
|
if cfg.BuildASan {
|
||||||
|
deps = append(deps, "runtime/asan")
|
||||||
|
}
|
||||||
|
|
||||||
return deps
|
return deps
|
||||||
}
|
}
|
||||||
|
|
@ -2453,7 +2690,8 @@ func PackagesAndErrors(ctx context.Context, opts PackageOpts, patterns []string)
|
||||||
}
|
}
|
||||||
matches, _ = modload.LoadPackages(ctx, modOpts, patterns...)
|
matches, _ = modload.LoadPackages(ctx, modOpts, patterns...)
|
||||||
} else {
|
} else {
|
||||||
matches = search.ImportPaths(patterns)
|
noModRoots := []string{}
|
||||||
|
matches = search.ImportPaths(patterns, noModRoots)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -2679,10 +2917,7 @@ func GoFilesPackage(ctx context.Context, opts PackageOpts, gofiles []string) *Pa
|
||||||
if fi.IsDir() {
|
if fi.IsDir() {
|
||||||
base.Fatalf("%s is a directory, should be a Go file", file)
|
base.Fatalf("%s is a directory, should be a Go file", file)
|
||||||
}
|
}
|
||||||
dir1, _ := filepath.Split(file)
|
dir1 := filepath.Dir(file)
|
||||||
if dir1 == "" {
|
|
||||||
dir1 = "./"
|
|
||||||
}
|
|
||||||
if dir == "" {
|
if dir == "" {
|
||||||
dir = dir1
|
dir = dir1
|
||||||
} else if 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.Local = true
|
||||||
pkg.Internal.CmdlineFiles = true
|
pkg.Internal.CmdlineFiles = true
|
||||||
pkg.load(ctx, opts, "command-line-arguments", &stk, nil, bp, err)
|
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.ImportPath = "command-line-arguments"
|
||||||
pkg.Target = ""
|
pkg.Target = ""
|
||||||
pkg.Match = gofiles
|
pkg.Match = gofiles
|
||||||
|
|
|
||||||
|
|
@ -555,6 +555,7 @@ func formatTestmain(t *testFuncs) ([]byte, error) {
|
||||||
type testFuncs struct {
|
type testFuncs struct {
|
||||||
Tests []testFunc
|
Tests []testFunc
|
||||||
Benchmarks []testFunc
|
Benchmarks []testFunc
|
||||||
|
FuzzTargets []testFunc
|
||||||
Examples []testFunc
|
Examples []testFunc
|
||||||
TestMain *testFunc
|
TestMain *testFunc
|
||||||
Package *Package
|
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})
|
t.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, "", false})
|
||||||
*doImport, *seen = true, true
|
*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)
|
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 {
|
func checkTestFunc(fn *ast.FuncDecl, arg string) error {
|
||||||
|
var why string
|
||||||
if !isTestFunc(fn, arg) {
|
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())
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -716,6 +730,12 @@ var benchmarks = []testing.InternalBenchmark{
|
||||||
{{end}}
|
{{end}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var fuzzTargets = []testing.InternalFuzzTarget{
|
||||||
|
{{range .FuzzTargets}}
|
||||||
|
{"{{.Name}}", {{.Package}}.{{.Name}}},
|
||||||
|
{{end}}
|
||||||
|
}
|
||||||
|
|
||||||
var examples = []testing.InternalExample{
|
var examples = []testing.InternalExample{
|
||||||
{{range .Examples}}
|
{{range .Examples}}
|
||||||
{"{{.Name}}", {{.Package}}.{{.Name}}, {{.Output | printf "%q"}}, {{.Unordered}}},
|
{"{{.Name}}", {{.Package}}.{{.Name}}, {{.Output | printf "%q"}}, {{.Unordered}}},
|
||||||
|
|
@ -774,7 +794,7 @@ func main() {
|
||||||
CoveredPackages: {{printf "%q" .Covered}},
|
CoveredPackages: {{printf "%q" .Covered}},
|
||||||
})
|
})
|
||||||
{{end}}
|
{{end}}
|
||||||
m := testing.MainStart(testdeps.TestDeps{}, tests, benchmarks, examples)
|
m := testing.MainStart(testdeps.TestDeps{}, tests, benchmarks, fuzzTargets, examples)
|
||||||
{{with .TestMain}}
|
{{with .TestMain}}
|
||||||
{{.Package}}.{{.Name}}(m)
|
{{.Package}}.{{.Name}}(m)
|
||||||
os.Exit(int(reflect.ValueOf(m).Elem().FieldByName("exitCode").Int()))
|
os.Exit(int(reflect.ValueOf(m).Elem().FieldByName("exitCode").Int()))
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build aix || (solaris && !illumos)
|
//go:build aix || (solaris && !illumos)
|
||||||
// +build aix solaris,!illumos
|
|
||||||
|
|
||||||
// This code implements the filelock API using POSIX 'fcntl' locks, which attach
|
// 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
|
// 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.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build !aix && !darwin && !dragonfly && !freebsd && !hurd && !linux && !netbsd && !openbsd && !plan9 && !solaris && !windows
|
//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
|
package filelock
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build plan9
|
//go:build plan9
|
||||||
// +build plan9
|
|
||||||
|
|
||||||
package filelock
|
package filelock
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build !js && !plan9
|
//go:build !js && !plan9
|
||||||
// +build !js,!plan9
|
|
||||||
|
|
||||||
package filelock_test
|
package filelock_test
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build darwin || dragonfly || freebsd || hurd || illumos || linux || netbsd || openbsd
|
//go:build darwin || dragonfly || freebsd || hurd || illumos || linux || netbsd || openbsd
|
||||||
// +build darwin dragonfly freebsd hurd illumos linux netbsd openbsd
|
|
||||||
|
|
||||||
package filelock
|
package filelock
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build windows
|
//go:build windows
|
||||||
// +build windows
|
|
||||||
|
|
||||||
package filelock
|
package filelock
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build !plan9
|
//go:build !plan9
|
||||||
// +build !plan9
|
|
||||||
|
|
||||||
package lockedfile
|
package lockedfile
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build plan9
|
//go:build plan9
|
||||||
// +build plan9
|
|
||||||
|
|
||||||
package lockedfile
|
package lockedfile
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
// js does not support inter-process file locking.
|
// js does not support inter-process file locking.
|
||||||
//go:build !js
|
//go:build !js
|
||||||
// +build !js
|
|
||||||
|
|
||||||
package lockedfile_test
|
package lockedfile_test
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
// js does not support inter-process file locking.
|
// js does not support inter-process file locking.
|
||||||
//go:build !js
|
//go:build !js
|
||||||
// +build !js
|
|
||||||
|
|
||||||
package lockedfile_test
|
package lockedfile_test
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"cmd/go/internal/modload"
|
"cmd/go/internal/modload"
|
||||||
|
|
||||||
"golang.org/x/mod/module"
|
"golang.org/x/mod/module"
|
||||||
|
"golang.org/x/mod/semver"
|
||||||
)
|
)
|
||||||
|
|
||||||
var cmdDownload = &base.Command{
|
var cmdDownload = &base.Command{
|
||||||
|
|
@ -24,8 +25,11 @@ var cmdDownload = &base.Command{
|
||||||
Long: `
|
Long: `
|
||||||
Download downloads the named modules, which can be module patterns selecting
|
Download downloads the named modules, which can be module patterns selecting
|
||||||
dependencies of the main module or module queries of the form path@version.
|
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
|
The go command will automatically download modules as needed during ordinary
|
||||||
execution. The "go mod download" command is useful mainly for pre-filling
|
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.
|
// TODO(jayconrod): https://golang.org/issue/35849 Apply -x to other 'go mod' commands.
|
||||||
cmdDownload.Flag.BoolVar(&cfg.BuildX, "x", false, "")
|
cmdDownload.Flag.BoolVar(&cfg.BuildX, "x", false, "")
|
||||||
base.AddModCommonFlags(&cmdDownload.Flag)
|
base.AddModCommonFlags(&cmdDownload.Flag)
|
||||||
|
base.AddWorkfileFlag(&cmdDownload.Flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
type moduleJSON struct {
|
type moduleJSON struct {
|
||||||
|
|
@ -81,27 +86,68 @@ type moduleJSON struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDownload(ctx context.Context, cmd *base.Command, args []string) {
|
func runDownload(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
|
modload.InitWorkfile()
|
||||||
|
|
||||||
// Check whether modules are enabled and whether we're in a module.
|
// Check whether modules are enabled and whether we're in a module.
|
||||||
modload.ForceUseModules = true
|
modload.ForceUseModules = true
|
||||||
if !modload.HasModRoot() && len(args) == 0 {
|
modload.ExplicitWriteGoMod = true
|
||||||
base.Fatalf("go mod download: no modules specified (see 'go help mod download')")
|
|
||||||
}
|
|
||||||
haveExplicitArgs := len(args) > 0
|
haveExplicitArgs := len(args) > 0
|
||||||
if !haveExplicitArgs {
|
|
||||||
args = []string{"all"}
|
if modload.HasModRoot() || modload.WorkFilePath() != "" {
|
||||||
}
|
modload.LoadModFile(ctx) // to fill MainModules
|
||||||
if modload.HasModRoot() {
|
|
||||||
modload.LoadModFile(ctx) // to fill Target
|
if haveExplicitArgs {
|
||||||
targetAtUpgrade := modload.Target.Path + "@upgrade"
|
for _, mainModule := range modload.MainModules.Versions() {
|
||||||
targetAtPatch := modload.Target.Path + "@patch"
|
targetAtUpgrade := mainModule.Path + "@upgrade"
|
||||||
for _, arg := range args {
|
targetAtPatch := mainModule.Path + "@patch"
|
||||||
switch arg {
|
for _, arg := range args {
|
||||||
case modload.Target.Path, targetAtUpgrade, targetAtPatch:
|
switch arg {
|
||||||
os.Stderr.WriteString("go mod download: skipping argument " + arg + " that resolves to the main module\n")
|
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) {
|
downloadModule := func(m *moduleJSON) {
|
||||||
var err error
|
var err error
|
||||||
m.Info, err = modfetch.InfoFile(m.Path, m.Version)
|
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 {
|
if !haveExplicitArgs {
|
||||||
// 'go mod download' is sometimes run without arguments to pre-populate the
|
// '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
|
// 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
|
// in the main module. This is usually not intended, so don't save sums for
|
||||||
// downloaded modules (golang.org/issue/45332).
|
// downloaded modules (golang.org/issue/45332). We do still fix
|
||||||
// TODO(golang.org/issue/45551): For now, in ListModules, save sums needed
|
// inconsistencies in go.mod though.
|
||||||
// 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
|
// TODO(#45551): In the future, report an error if go.mod or go.sum need to
|
||||||
// list.
|
// be updated after loading the build list. This may require setting
|
||||||
modload.DisallowWriteGoMod()
|
// 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 {
|
for _, info := range infos {
|
||||||
|
|
@ -183,7 +232,7 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
for _, m := range mods {
|
for _, m := range mods {
|
||||||
b, err := json.MarshalIndent(m, "", "\t")
|
b, err := json.MarshalIndent(m, "", "\t")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf("go mod download: %v", err)
|
base.Fatalf("go: %v", err)
|
||||||
}
|
}
|
||||||
os.Stdout.Write(append(b, '\n'))
|
os.Stdout.Write(append(b, '\n'))
|
||||||
if m.Error != "" {
|
if m.Error != "" {
|
||||||
|
|
@ -193,7 +242,7 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
} else {
|
} else {
|
||||||
for _, m := range mods {
|
for _, m := range mods {
|
||||||
if m.Error != "" {
|
if m.Error != "" {
|
||||||
base.Errorf("go mod download: %v", m.Error)
|
base.Errorf("go: %v", m.Error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
base.ExitIfErrors()
|
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.
|
// Don't save sums for 'go mod download' without arguments; see comment above.
|
||||||
if haveExplicitArgs {
|
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
|
// 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
|
// (after we've written the checksums for the modules that were downloaded
|
||||||
// successfully).
|
// successfully).
|
||||||
if infosErr != nil {
|
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
|
len(edits) > 0
|
||||||
|
|
||||||
if !anyFlags {
|
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 {
|
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 {
|
if len(args) > 1 {
|
||||||
base.Fatalf("go mod edit: too many arguments")
|
base.Fatalf("go: too many arguments")
|
||||||
}
|
}
|
||||||
var gomod string
|
var gomod string
|
||||||
if len(args) == 1 {
|
if len(args) == 1 {
|
||||||
|
|
@ -190,7 +190,7 @@ func runEdit(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
|
|
||||||
if *editModule != "" {
|
if *editModule != "" {
|
||||||
if err := module.CheckImportPath(*editModule); err != nil {
|
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) {
|
func parsePathVersion(flag, arg string) (path, version string) {
|
||||||
i := strings.Index(arg, "@")
|
i := strings.Index(arg, "@")
|
||||||
if i < 0 {
|
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:])
|
path, version = strings.TrimSpace(arg[:i]), strings.TrimSpace(arg[i+1:])
|
||||||
if err := module.CheckImportPath(path); err != nil {
|
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) {
|
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
|
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).
|
// parsePath parses -flag=arg expecting arg to be path (not path@version).
|
||||||
func parsePath(flag, arg string) (path string) {
|
func parsePath(flag, arg string) (path string) {
|
||||||
if strings.Contains(arg, "@") {
|
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
|
path = arg
|
||||||
if err := module.CheckImportPath(path); err != nil {
|
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
|
return path
|
||||||
}
|
}
|
||||||
|
|
@ -350,7 +350,7 @@ func flagRequire(arg string) {
|
||||||
path, version := parsePathVersion("require", arg)
|
path, version := parsePathVersion("require", arg)
|
||||||
edits = append(edits, func(f *modfile.File) {
|
edits = append(edits, func(f *modfile.File) {
|
||||||
if err := f.AddRequire(path, version); err != nil {
|
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)
|
path := parsePath("droprequire", arg)
|
||||||
edits = append(edits, func(f *modfile.File) {
|
edits = append(edits, func(f *modfile.File) {
|
||||||
if err := f.DropRequire(path); err != nil {
|
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)
|
path, version := parsePathVersion("exclude", arg)
|
||||||
edits = append(edits, func(f *modfile.File) {
|
edits = append(edits, func(f *modfile.File) {
|
||||||
if err := f.AddExclude(path, version); err != nil {
|
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)
|
path, version := parsePathVersion("dropexclude", arg)
|
||||||
edits = append(edits, func(f *modfile.File) {
|
edits = append(edits, func(f *modfile.File) {
|
||||||
if err := f.DropExclude(path, version); err != nil {
|
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) {
|
func flagReplace(arg string) {
|
||||||
var i int
|
var i int
|
||||||
if i = strings.Index(arg, "="); i < 0 {
|
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:])
|
old, new := strings.TrimSpace(arg[:i]), strings.TrimSpace(arg[i+1:])
|
||||||
if strings.HasPrefix(new, ">") {
|
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)
|
oldPath, oldVersion, err := parsePathVersionOptional("old", old, false)
|
||||||
if err != nil {
|
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)
|
newPath, newVersion, err := parsePathVersionOptional("new", new, true)
|
||||||
if err != nil {
|
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) {
|
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) {
|
edits = append(edits, func(f *modfile.File) {
|
||||||
if err := f.AddReplace(oldPath, oldVersion, newPath, newVersion); err != nil {
|
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) {
|
func flagDropReplace(arg string) {
|
||||||
path, version, err := parsePathVersionOptional("old", arg, true)
|
path, version, err := parsePathVersionOptional("old", arg, true)
|
||||||
if err != nil {
|
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) {
|
edits = append(edits, func(f *modfile.File) {
|
||||||
if err := f.DropReplace(path, version); err != nil {
|
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) {
|
func flagRetract(arg string) {
|
||||||
vi, err := parseVersionInterval(arg)
|
vi, err := parseVersionInterval(arg)
|
||||||
if err != nil {
|
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) {
|
edits = append(edits, func(f *modfile.File) {
|
||||||
if err := f.AddRetract(vi, ""); err != nil {
|
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) {
|
func flagDropRetract(arg string) {
|
||||||
vi, err := parseVersionInterval(arg)
|
vi, err := parseVersionInterval(arg)
|
||||||
if err != nil {
|
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) {
|
edits = append(edits, func(f *modfile.File) {
|
||||||
if err := f.DropRetract(vi); err != nil {
|
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() {
|
func init() {
|
||||||
cmdGraph.Flag.Var(&graphGo, "go", "")
|
cmdGraph.Flag.Var(&graphGo, "go", "")
|
||||||
base.AddModCommonFlags(&cmdGraph.Flag)
|
base.AddModCommonFlags(&cmdGraph.Flag)
|
||||||
|
base.AddWorkfileFlag(&cmdGraph.Flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runGraph(ctx context.Context, cmd *base.Command, args []string) {
|
func runGraph(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
|
modload.InitWorkfile()
|
||||||
|
|
||||||
if len(args) > 0 {
|
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.ForceUseModules = true
|
||||||
modload.RootMode = modload.NeedRoot
|
modload.RootMode = modload.NeedRoot
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ func init() {
|
||||||
|
|
||||||
func runInit(ctx context.Context, cmd *base.Command, args []string) {
|
func runInit(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
if len(args) > 1 {
|
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
|
var modPath string
|
||||||
if len(args) == 1 {
|
if len(args) == 1 {
|
||||||
|
|
|
||||||
|
|
@ -75,8 +75,8 @@ type goVersionFlag struct {
|
||||||
v string
|
v string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *goVersionFlag) String() string { return f.v }
|
func (f *goVersionFlag) String() string { return f.v }
|
||||||
func (f *goVersionFlag) Get() interface{} { return f.v }
|
func (f *goVersionFlag) Get() any { return f.v }
|
||||||
|
|
||||||
func (f *goVersionFlag) Set(s string) error {
|
func (f *goVersionFlag) Set(s string) error {
|
||||||
if s != "" {
|
if s != "" {
|
||||||
|
|
@ -95,7 +95,7 @@ func (f *goVersionFlag) Set(s string) error {
|
||||||
|
|
||||||
func runTidy(ctx context.Context, cmd *base.Command, args []string) {
|
func runTidy(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
if len(args) > 0 {
|
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
|
// Tidy aims to make 'go test' reproducible for any package in 'all', so we
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var cmdVendor = &base.Command{
|
var cmdVendor = &base.Command{
|
||||||
UsageLine: "go mod vendor [-e] [-v]",
|
UsageLine: "go mod vendor [-e] [-v] [-o outdir]",
|
||||||
Short: "make vendored copy of dependencies",
|
Short: "make vendored copy of dependencies",
|
||||||
Long: `
|
Long: `
|
||||||
Vendor resets the main module's vendor directory to include all packages
|
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
|
The -e flag causes vendor to attempt to proceed despite errors
|
||||||
encountered while loading packages.
|
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'.
|
See https://golang.org/ref/mod#go-mod-vendor for more about 'go mod vendor'.
|
||||||
`,
|
`,
|
||||||
Run: runVendor,
|
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() {
|
func init() {
|
||||||
cmdVendor.Flag.BoolVar(&cfg.BuildV, "v", false, "")
|
cmdVendor.Flag.BoolVar(&cfg.BuildV, "v", false, "")
|
||||||
cmdVendor.Flag.BoolVar(&vendorE, "e", false, "")
|
cmdVendor.Flag.BoolVar(&vendorE, "e", false, "")
|
||||||
|
cmdVendor.Flag.StringVar(&vendorO, "o", "", "")
|
||||||
base.AddModCommonFlags(&cmdVendor.Flag)
|
base.AddModCommonFlags(&cmdVendor.Flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runVendor(ctx context.Context, cmd *base.Command, args []string) {
|
func runVendor(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
if len(args) != 0 {
|
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.ForceUseModules = true
|
||||||
modload.RootMode = modload.NeedRoot
|
modload.RootMode = modload.NeedRoot
|
||||||
|
|
@ -74,15 +81,23 @@ func runVendor(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
}
|
}
|
||||||
_, pkgs := modload.LoadPackages(ctx, loadOpts, "all")
|
_, 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 {
|
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)
|
modpkgs := make(map[module.Version][]string)
|
||||||
for _, pkg := range pkgs {
|
for _, pkg := range pkgs {
|
||||||
m := modload.PackageModule(pkg)
|
m := modload.PackageModule(pkg)
|
||||||
if m.Path == "" || m == modload.Target {
|
if m.Path == "" || m.Version == "" && modload.MainModules.Contains(m.Path) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
modpkgs[m] = append(modpkgs[m], pkg)
|
modpkgs[m] = append(modpkgs[m], pkg)
|
||||||
|
|
@ -128,7 +143,8 @@ func runVendor(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, m := range vendorMods {
|
for _, m := range vendorMods {
|
||||||
line := moduleLine(m, modload.Replacement(m))
|
replacement := modload.Replacement(m)
|
||||||
|
line := moduleLine(m, replacement)
|
||||||
io.WriteString(w, line)
|
io.WriteString(w, line)
|
||||||
|
|
||||||
goVersion := ""
|
goVersion := ""
|
||||||
|
|
@ -177,11 +193,11 @@ func runVendor(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.MkdirAll(vdir, 0777); err != nil {
|
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 {
|
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 err != nil {
|
||||||
if errors.As(err, &noGoError) {
|
if errors.As(err, &noGoError) {
|
||||||
return // No source files in this package are built. Skip embeds in ignored files.
|
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)
|
base.Fatalf("internal error: failed to find embedded files of %s: %v\n", pkg, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
embedPatterns := str.StringList(bp.EmbedPatterns, bp.TestEmbedPatterns, bp.XTestEmbedPatterns)
|
embedPatterns := str.StringList(bp.EmbedPatterns, bp.TestEmbedPatterns, bp.XTestEmbedPatterns)
|
||||||
embeds, err := load.ResolveEmbed(bp.Dir, embedPatterns)
|
embeds, err := load.ResolveEmbed(bp.Dir, embedPatterns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf("go mod vendor: %v", err)
|
base.Fatalf("go: %v", err)
|
||||||
}
|
}
|
||||||
for _, embed := range embeds {
|
for _, embed := range embeds {
|
||||||
embedDst := filepath.Join(dst, embed)
|
embedDst := filepath.Join(dst, embed)
|
||||||
|
|
@ -260,21 +276,21 @@ func vendorPkg(vdir, pkg string) {
|
||||||
// Copy the file as is done by copyDir below.
|
// Copy the file as is done by copyDir below.
|
||||||
r, err := os.Open(filepath.Join(src, embed))
|
r, err := os.Open(filepath.Join(src, embed))
|
||||||
if err != nil {
|
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 {
|
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)
|
w, err := os.Create(embedDst)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf("go mod vendor: %v", err)
|
base.Fatalf("go: %v", err)
|
||||||
}
|
}
|
||||||
if _, err := io.Copy(w, r); err != nil {
|
if _, err := io.Copy(w, r); err != nil {
|
||||||
base.Fatalf("go mod vendor: %v", err)
|
base.Fatalf("go: %v", err)
|
||||||
}
|
}
|
||||||
r.Close()
|
r.Close()
|
||||||
if err := w.Close(); err != nil {
|
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") {
|
if strings.HasSuffix(info.Name(), ".go") {
|
||||||
f, err := fsys.Open(filepath.Join(dir, info.Name()))
|
f, err := fsys.Open(filepath.Join(dir, info.Name()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf("go mod vendor: %v", err)
|
base.Fatalf("go: %v", err)
|
||||||
}
|
}
|
||||||
defer f.Close()
|
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) {
|
func copyDir(dst, src string, match func(dir string, info fs.DirEntry) bool, copiedFiles map[string]bool) {
|
||||||
files, err := os.ReadDir(src)
|
files, err := os.ReadDir(src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf("go mod vendor: %v", err)
|
base.Fatalf("go: %v", err)
|
||||||
}
|
}
|
||||||
if err := os.MkdirAll(dst, 0777); err != nil {
|
if err := os.MkdirAll(dst, 0777); err != nil {
|
||||||
base.Fatalf("go mod vendor: %v", err)
|
base.Fatalf("go: %v", err)
|
||||||
}
|
}
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
if file.IsDir() || !file.Type().IsRegular() || !match(src, file) {
|
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
|
copiedFiles[file.Name()] = true
|
||||||
r, err := os.Open(filepath.Join(src, file.Name()))
|
r, err := os.Open(filepath.Join(src, file.Name()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf("go mod vendor: %v", err)
|
base.Fatalf("go: %v", err)
|
||||||
}
|
}
|
||||||
dstPath := filepath.Join(dst, file.Name())
|
dstPath := filepath.Join(dst, file.Name())
|
||||||
copiedFiles[dstPath] = true
|
copiedFiles[dstPath] = true
|
||||||
w, err := os.Create(dstPath)
|
w, err := os.Create(dstPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf("go mod vendor: %v", err)
|
base.Fatalf("go: %v", err)
|
||||||
}
|
}
|
||||||
if _, err := io.Copy(w, r); err != nil {
|
if _, err := io.Copy(w, r); err != nil {
|
||||||
base.Fatalf("go mod vendor: %v", err)
|
base.Fatalf("go: %v", err)
|
||||||
}
|
}
|
||||||
r.Close()
|
r.Close()
|
||||||
if err := w.Close(); err != nil {
|
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() {
|
func init() {
|
||||||
base.AddModCommonFlags(&cmdVerify.Flag)
|
base.AddModCommonFlags(&cmdVerify.Flag)
|
||||||
|
base.AddWorkfileFlag(&cmdVerify.Flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runVerify(ctx context.Context, cmd *base.Command, args []string) {
|
func runVerify(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
|
modload.InitWorkfile()
|
||||||
|
|
||||||
if len(args) != 0 {
|
if len(args) != 0 {
|
||||||
// NOTE(rsc): Could take a module pattern.
|
// 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.ForceUseModules = true
|
||||||
modload.RootMode = modload.NeedRoot
|
modload.RootMode = modload.NeedRoot
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,6 @@ import (
|
||||||
"cmd/go/internal/base"
|
"cmd/go/internal/base"
|
||||||
"cmd/go/internal/imports"
|
"cmd/go/internal/imports"
|
||||||
"cmd/go/internal/modload"
|
"cmd/go/internal/modload"
|
||||||
|
|
||||||
"golang.org/x/mod/module"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var cmdWhy = &base.Command{
|
var cmdWhy = &base.Command{
|
||||||
|
|
@ -61,11 +59,14 @@ var (
|
||||||
func init() {
|
func init() {
|
||||||
cmdWhy.Run = runWhy // break init cycle
|
cmdWhy.Run = runWhy // break init cycle
|
||||||
base.AddModCommonFlags(&cmdWhy.Flag)
|
base.AddModCommonFlags(&cmdWhy.Flag)
|
||||||
|
base.AddWorkfileFlag(&cmdWhy.Flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runWhy(ctx context.Context, cmd *base.Command, args []string) {
|
func runWhy(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
|
modload.InitWorkfile()
|
||||||
modload.ForceUseModules = true
|
modload.ForceUseModules = true
|
||||||
modload.RootMode = modload.NeedRoot
|
modload.RootMode = modload.NeedRoot
|
||||||
|
modload.ExplicitWriteGoMod = true // don't write go.mod in ListModules
|
||||||
|
|
||||||
loadOpts := modload.PackageOpts{
|
loadOpts := modload.PackageOpts{
|
||||||
Tags: imports.AnyTags(),
|
Tags: imports.AnyTags(),
|
||||||
|
|
@ -78,28 +79,28 @@ func runWhy(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
if *whyM {
|
if *whyM {
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
if strings.Contains(arg, "@") {
|
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)
|
mods, err := modload.ListModules(ctx, args, 0)
|
||||||
if err != nil {
|
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")
|
_, pkgs := modload.LoadPackages(ctx, loadOpts, "all")
|
||||||
for _, path := range pkgs {
|
for _, path := range pkgs {
|
||||||
m := modload.PackageModule(path)
|
m := modload.PackageModule(path)
|
||||||
if m.Path != "" {
|
if m.Path != "" {
|
||||||
byModule[m] = append(byModule[m], path)
|
byModule[m.Path] = append(byModule[m.Path], path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sep := ""
|
sep := ""
|
||||||
for _, m := range mods {
|
for _, m := range mods {
|
||||||
best := ""
|
best := ""
|
||||||
bestDepth := 1000000000
|
bestDepth := 1000000000
|
||||||
for _, path := range byModule[module.Version{Path: m.Path, Version: m.Version}] {
|
for _, path := range byModule[m.Path] {
|
||||||
d := modload.WhyDepth(path)
|
d := modload.WhyDepth(path)
|
||||||
if d > 0 && d < bestDepth {
|
if d > 0 && d < bestDepth {
|
||||||
best = path
|
best = path
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build cmd_go_bootstrap
|
//go:build cmd_go_bootstrap
|
||||||
// +build cmd_go_bootstrap
|
|
||||||
|
|
||||||
package modfetch
|
package modfetch
|
||||||
|
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue