libgo: update to Go1.16beta1 release
This does not yet include support for the //go:embed directive added in this release. * Makefile.am (check-runtime): Don't create check-runtime-dir. (mostlyclean-local): Don't remove check-runtime-dir. (check-go-tool, check-vet): Copy in go.mod and modules.txt. (check-cgo-test, check-carchive-test): Add go.mod file. * Makefile.in: Regenerate. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/280172
This commit is contained in:
parent
0696141107
commit
cfcbb4227f
@ -1,4 +1,4 @@
|
|||||||
d67579759e1769c08148304b2d378ec0b05637d6
|
47bdc8bb36f16f9d1dec72df5dd6b45d7b0b0725
|
||||||
|
|
||||||
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.
|
||||||
|
@ -101,7 +101,7 @@ MOSTLYCLEANFILES = \
|
|||||||
|
|
||||||
mostlyclean-local:
|
mostlyclean-local:
|
||||||
if test -d check-go-dir; then chmod -R u+w check-go-dir; fi
|
if test -d check-go-dir; then chmod -R u+w check-go-dir; fi
|
||||||
rm -rf check-go-dir check-runtime-dir cgo-test-dir carchive-test-dir \
|
rm -rf check-go-dir cgo-test-dir carchive-test-dir \
|
||||||
check-vet-dir gocache-test
|
check-vet-dir gocache-test
|
||||||
|
|
||||||
if NATIVE
|
if NATIVE
|
||||||
@ -210,6 +210,11 @@ check-go-tool: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc
|
|||||||
if test -d check-go-dir; then chmod -R u+w check-go-dir; fi
|
if test -d check-go-dir; then chmod -R u+w check-go-dir; fi
|
||||||
rm -rf check-go-dir cmd_go-testlog
|
rm -rf check-go-dir cmd_go-testlog
|
||||||
$(MKDIR_P) check-go-dir/src/cmd/go
|
$(MKDIR_P) check-go-dir/src/cmd/go
|
||||||
|
cp $(libgosrcdir)/go.mod check-go-dir/src/
|
||||||
|
cp $(cmdsrcdir)/go.mod check-go-dir/src/cmd/
|
||||||
|
$(MKDIR_P) check-go-dir/src/vendor check-go-dir/src/cmd/vendor
|
||||||
|
cp $(libgosrcdir)/vendor/modules.txt check-go-dir/src/vendor/
|
||||||
|
cp $(libgosrcdir)/cmd/vendor/modules.txt check-go-dir/src/cmd/vendor/
|
||||||
cp $(cmdsrcdir)/go/*.go check-go-dir/src/cmd/go/
|
cp $(cmdsrcdir)/go/*.go check-go-dir/src/cmd/go/
|
||||||
cp -r $(cmdsrcdir)/go/internal check-go-dir/src/cmd/go/
|
cp -r $(cmdsrcdir)/go/internal check-go-dir/src/cmd/go/
|
||||||
cp $(libgodir)/zdefaultcc.go check-go-dir/src/cmd/go/internal/cfg/
|
cp $(libgodir)/zdefaultcc.go check-go-dir/src/cmd/go/internal/cfg/
|
||||||
@ -234,8 +239,7 @@ check-go-tool: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc
|
|||||||
# but the runtime tests use the go tool heavily, so testing
|
# but the runtime tests use the go tool heavily, so testing
|
||||||
# here too will catch more problems.
|
# here too will catch more problems.
|
||||||
check-runtime: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc
|
check-runtime: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc
|
||||||
rm -rf check-runtime-dir runtime-testlog
|
rm -f runtime-testlog
|
||||||
$(MKDIR_P) check-runtime-dir
|
|
||||||
@abs_libgodir=`cd $(libgodir) && $(PWD_COMMAND)`; \
|
@abs_libgodir=`cd $(libgodir) && $(PWD_COMMAND)`; \
|
||||||
LD_LIBRARY_PATH=`echo $${abs_libgodir}/.libs:$${LD_LIBRARY_PATH} | sed 's,::*,:,g;s,^:*,,;s,:*$$,,'`; \
|
LD_LIBRARY_PATH=`echo $${abs_libgodir}/.libs:$${LD_LIBRARY_PATH} | sed 's,::*,:,g;s,^:*,,;s,:*$$,,'`; \
|
||||||
export LD_LIBRARY_PATH; \
|
export LD_LIBRARY_PATH; \
|
||||||
@ -256,6 +260,7 @@ check-runtime: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc
|
|||||||
check-cgo-test: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc
|
check-cgo-test: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc
|
||||||
rm -rf cgo-test-dir cgo-testlog
|
rm -rf cgo-test-dir cgo-testlog
|
||||||
$(MKDIR_P) cgo-test-dir/misc/cgo
|
$(MKDIR_P) cgo-test-dir/misc/cgo
|
||||||
|
echo 'module misc' > cgo-test-dir/misc/go.mod
|
||||||
cp -r $(libgomiscdir)/cgo/test cgo-test-dir/misc/cgo/
|
cp -r $(libgomiscdir)/cgo/test cgo-test-dir/misc/cgo/
|
||||||
@abs_libgodir=`cd $(libgodir) && $(PWD_COMMAND)`; \
|
@abs_libgodir=`cd $(libgodir) && $(PWD_COMMAND)`; \
|
||||||
echo "cd cgo-test-dir/misc/cgo/test && $(ECHO_ENV) GOTRACEBACK=2 $(abs_builddir)/go$(EXEEXT) test -test.short -test.timeout=$(GOTOOLS_TEST_TIMEOUT)s -test.v" > cgo-testlog
|
echo "cd cgo-test-dir/misc/cgo/test && $(ECHO_ENV) GOTRACEBACK=2 $(abs_builddir)/go$(EXEEXT) test -test.short -test.timeout=$(GOTOOLS_TEST_TIMEOUT)s -test.v" > cgo-testlog
|
||||||
@ -270,6 +275,7 @@ check-cgo-test: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc
|
|||||||
check-carchive-test: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc
|
check-carchive-test: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc
|
||||||
rm -rf carchive-test-dir carchive-testlog
|
rm -rf carchive-test-dir carchive-testlog
|
||||||
$(MKDIR_P) carchive-test-dir/misc/cgo
|
$(MKDIR_P) carchive-test-dir/misc/cgo
|
||||||
|
echo 'module misc' > carchive-test-dir/misc/go.mod
|
||||||
cp -r $(libgomiscdir)/cgo/testcarchive carchive-test-dir/misc/cgo/
|
cp -r $(libgomiscdir)/cgo/testcarchive carchive-test-dir/misc/cgo/
|
||||||
@abs_libgodir=`cd $(libgodir) && $(PWD_COMMAND)`; \
|
@abs_libgodir=`cd $(libgodir) && $(PWD_COMMAND)`; \
|
||||||
echo "cd carchive-test-dir/misc/cgo/testcarchive && $(ECHO_ENV) LIBRARY_PATH=`echo $${abs_libgodir}/.libs` $(abs_builddir)/go$(EXEEXT) test -test.timeout=$(GOTOOLS_TEST_TIMEOUT)s -test.v" > carchive-testlog
|
echo "cd carchive-test-dir/misc/cgo/testcarchive && $(ECHO_ENV) LIBRARY_PATH=`echo $${abs_libgodir}/.libs` $(abs_builddir)/go$(EXEEXT) test -test.timeout=$(GOTOOLS_TEST_TIMEOUT)s -test.v" > carchive-testlog
|
||||||
@ -283,6 +289,11 @@ check-carchive-test: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check
|
|||||||
check-vet: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc
|
check-vet: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc
|
||||||
rm -rf check-vet-dir cmd_vet-testlog
|
rm -rf check-vet-dir cmd_vet-testlog
|
||||||
$(MKDIR_P) check-vet-dir/src/cmd/internal check-vet-dir/src/cmd/vendor/golang.org/x
|
$(MKDIR_P) check-vet-dir/src/cmd/internal check-vet-dir/src/cmd/vendor/golang.org/x
|
||||||
|
cp $(libgosrcdir)/go.mod check-vet-dir/src/
|
||||||
|
cp $(cmdsrcdir)/go.mod check-vet-dir/src/cmd/
|
||||||
|
$(MKDIR_P) check-vet-dir/src/vendor check-vet-dir/src/cmd/vendor
|
||||||
|
cp $(libgosrcdir)/vendor/modules.txt check-vet-dir/src/vendor/
|
||||||
|
cp $(libgosrcdir)/cmd/vendor/modules.txt check-vet-dir/src/cmd/vendor/
|
||||||
cp -r $(cmdsrcdir)/vet check-vet-dir/src/cmd/
|
cp -r $(cmdsrcdir)/vet check-vet-dir/src/cmd/
|
||||||
cp -r $(cmdsrcdir)/internal/objabi check-vet-dir/src/cmd/internal
|
cp -r $(cmdsrcdir)/internal/objabi check-vet-dir/src/cmd/internal
|
||||||
cp $(libgodir)/objabi.go check-vet-dir/src/cmd/internal/objabi/
|
cp $(libgodir)/objabi.go check-vet-dir/src/cmd/internal/objabi/
|
||||||
|
@ -703,8 +703,8 @@ distclean-generic:
|
|||||||
maintainer-clean-generic:
|
maintainer-clean-generic:
|
||||||
@echo "This command is intended for maintainers to use"
|
@echo "This command is intended for maintainers to use"
|
||||||
@echo "it deletes files that may require special tools to rebuild."
|
@echo "it deletes files that may require special tools to rebuild."
|
||||||
@NATIVE_FALSE@uninstall-local:
|
|
||||||
@NATIVE_FALSE@install-exec-local:
|
@NATIVE_FALSE@install-exec-local:
|
||||||
|
@NATIVE_FALSE@uninstall-local:
|
||||||
clean: clean-am
|
clean: clean-am
|
||||||
|
|
||||||
clean-am: clean-binPROGRAMS clean-generic clean-noinstPROGRAMS \
|
clean-am: clean-binPROGRAMS clean-generic clean-noinstPROGRAMS \
|
||||||
@ -814,7 +814,7 @@ s-zdefaultcc: Makefile
|
|||||||
|
|
||||||
mostlyclean-local:
|
mostlyclean-local:
|
||||||
if test -d check-go-dir; then chmod -R u+w check-go-dir; fi
|
if test -d check-go-dir; then chmod -R u+w check-go-dir; fi
|
||||||
rm -rf check-go-dir check-runtime-dir cgo-test-dir carchive-test-dir \
|
rm -rf check-go-dir cgo-test-dir carchive-test-dir \
|
||||||
check-vet-dir gocache-test
|
check-vet-dir gocache-test
|
||||||
|
|
||||||
@NATIVE_TRUE@go$(EXEEXT): $(go_cmd_go_files) $(LIBGOTOOL) $(LIBGODEP)
|
@NATIVE_TRUE@go$(EXEEXT): $(go_cmd_go_files) $(LIBGOTOOL) $(LIBGODEP)
|
||||||
@ -881,6 +881,11 @@ mostlyclean-local:
|
|||||||
@NATIVE_TRUE@ if test -d check-go-dir; then chmod -R u+w check-go-dir; fi
|
@NATIVE_TRUE@ if test -d check-go-dir; then chmod -R u+w check-go-dir; fi
|
||||||
@NATIVE_TRUE@ rm -rf check-go-dir cmd_go-testlog
|
@NATIVE_TRUE@ rm -rf check-go-dir cmd_go-testlog
|
||||||
@NATIVE_TRUE@ $(MKDIR_P) check-go-dir/src/cmd/go
|
@NATIVE_TRUE@ $(MKDIR_P) check-go-dir/src/cmd/go
|
||||||
|
@NATIVE_TRUE@ cp $(libgosrcdir)/go.mod check-go-dir/src/
|
||||||
|
@NATIVE_TRUE@ cp $(cmdsrcdir)/go.mod check-go-dir/src/cmd/
|
||||||
|
@NATIVE_TRUE@ $(MKDIR_P) check-go-dir/src/vendor check-go-dir/src/cmd/vendor
|
||||||
|
@NATIVE_TRUE@ cp $(libgosrcdir)/vendor/modules.txt check-go-dir/src/vendor/
|
||||||
|
@NATIVE_TRUE@ cp $(libgosrcdir)/cmd/vendor/modules.txt check-go-dir/src/cmd/vendor/
|
||||||
@NATIVE_TRUE@ cp $(cmdsrcdir)/go/*.go check-go-dir/src/cmd/go/
|
@NATIVE_TRUE@ cp $(cmdsrcdir)/go/*.go check-go-dir/src/cmd/go/
|
||||||
@NATIVE_TRUE@ cp -r $(cmdsrcdir)/go/internal check-go-dir/src/cmd/go/
|
@NATIVE_TRUE@ cp -r $(cmdsrcdir)/go/internal check-go-dir/src/cmd/go/
|
||||||
@NATIVE_TRUE@ cp $(libgodir)/zdefaultcc.go check-go-dir/src/cmd/go/internal/cfg/
|
@NATIVE_TRUE@ cp $(libgodir)/zdefaultcc.go check-go-dir/src/cmd/go/internal/cfg/
|
||||||
@ -905,8 +910,7 @@ mostlyclean-local:
|
|||||||
# but the runtime tests use the go tool heavily, so testing
|
# but the runtime tests use the go tool heavily, so testing
|
||||||
# here too will catch more problems.
|
# here too will catch more problems.
|
||||||
@NATIVE_TRUE@check-runtime: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc
|
@NATIVE_TRUE@check-runtime: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc
|
||||||
@NATIVE_TRUE@ rm -rf check-runtime-dir runtime-testlog
|
@NATIVE_TRUE@ rm -f runtime-testlog
|
||||||
@NATIVE_TRUE@ $(MKDIR_P) check-runtime-dir
|
|
||||||
@NATIVE_TRUE@ @abs_libgodir=`cd $(libgodir) && $(PWD_COMMAND)`; \
|
@NATIVE_TRUE@ @abs_libgodir=`cd $(libgodir) && $(PWD_COMMAND)`; \
|
||||||
@NATIVE_TRUE@ LD_LIBRARY_PATH=`echo $${abs_libgodir}/.libs:$${LD_LIBRARY_PATH} | sed 's,::*,:,g;s,^:*,,;s,:*$$,,'`; \
|
@NATIVE_TRUE@ LD_LIBRARY_PATH=`echo $${abs_libgodir}/.libs:$${LD_LIBRARY_PATH} | sed 's,::*,:,g;s,^:*,,;s,:*$$,,'`; \
|
||||||
@NATIVE_TRUE@ export LD_LIBRARY_PATH; \
|
@NATIVE_TRUE@ export LD_LIBRARY_PATH; \
|
||||||
@ -927,6 +931,7 @@ mostlyclean-local:
|
|||||||
@NATIVE_TRUE@check-cgo-test: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc
|
@NATIVE_TRUE@check-cgo-test: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc
|
||||||
@NATIVE_TRUE@ rm -rf cgo-test-dir cgo-testlog
|
@NATIVE_TRUE@ rm -rf cgo-test-dir cgo-testlog
|
||||||
@NATIVE_TRUE@ $(MKDIR_P) cgo-test-dir/misc/cgo
|
@NATIVE_TRUE@ $(MKDIR_P) cgo-test-dir/misc/cgo
|
||||||
|
@NATIVE_TRUE@ echo 'module misc' > cgo-test-dir/misc/go.mod
|
||||||
@NATIVE_TRUE@ cp -r $(libgomiscdir)/cgo/test cgo-test-dir/misc/cgo/
|
@NATIVE_TRUE@ cp -r $(libgomiscdir)/cgo/test cgo-test-dir/misc/cgo/
|
||||||
@NATIVE_TRUE@ @abs_libgodir=`cd $(libgodir) && $(PWD_COMMAND)`; \
|
@NATIVE_TRUE@ @abs_libgodir=`cd $(libgodir) && $(PWD_COMMAND)`; \
|
||||||
@NATIVE_TRUE@ echo "cd cgo-test-dir/misc/cgo/test && $(ECHO_ENV) GOTRACEBACK=2 $(abs_builddir)/go$(EXEEXT) test -test.short -test.timeout=$(GOTOOLS_TEST_TIMEOUT)s -test.v" > cgo-testlog
|
@NATIVE_TRUE@ echo "cd cgo-test-dir/misc/cgo/test && $(ECHO_ENV) GOTRACEBACK=2 $(abs_builddir)/go$(EXEEXT) test -test.short -test.timeout=$(GOTOOLS_TEST_TIMEOUT)s -test.v" > cgo-testlog
|
||||||
@ -941,6 +946,7 @@ mostlyclean-local:
|
|||||||
@NATIVE_TRUE@check-carchive-test: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc
|
@NATIVE_TRUE@check-carchive-test: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc
|
||||||
@NATIVE_TRUE@ rm -rf carchive-test-dir carchive-testlog
|
@NATIVE_TRUE@ rm -rf carchive-test-dir carchive-testlog
|
||||||
@NATIVE_TRUE@ $(MKDIR_P) carchive-test-dir/misc/cgo
|
@NATIVE_TRUE@ $(MKDIR_P) carchive-test-dir/misc/cgo
|
||||||
|
@NATIVE_TRUE@ echo 'module misc' > carchive-test-dir/misc/go.mod
|
||||||
@NATIVE_TRUE@ cp -r $(libgomiscdir)/cgo/testcarchive carchive-test-dir/misc/cgo/
|
@NATIVE_TRUE@ cp -r $(libgomiscdir)/cgo/testcarchive carchive-test-dir/misc/cgo/
|
||||||
@NATIVE_TRUE@ @abs_libgodir=`cd $(libgodir) && $(PWD_COMMAND)`; \
|
@NATIVE_TRUE@ @abs_libgodir=`cd $(libgodir) && $(PWD_COMMAND)`; \
|
||||||
@NATIVE_TRUE@ echo "cd carchive-test-dir/misc/cgo/testcarchive && $(ECHO_ENV) LIBRARY_PATH=`echo $${abs_libgodir}/.libs` $(abs_builddir)/go$(EXEEXT) test -test.timeout=$(GOTOOLS_TEST_TIMEOUT)s -test.v" > carchive-testlog
|
@NATIVE_TRUE@ echo "cd carchive-test-dir/misc/cgo/testcarchive && $(ECHO_ENV) LIBRARY_PATH=`echo $${abs_libgodir}/.libs` $(abs_builddir)/go$(EXEEXT) test -test.timeout=$(GOTOOLS_TEST_TIMEOUT)s -test.v" > carchive-testlog
|
||||||
@ -954,6 +960,11 @@ mostlyclean-local:
|
|||||||
@NATIVE_TRUE@check-vet: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc
|
@NATIVE_TRUE@check-vet: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc
|
||||||
@NATIVE_TRUE@ rm -rf check-vet-dir cmd_vet-testlog
|
@NATIVE_TRUE@ rm -rf check-vet-dir cmd_vet-testlog
|
||||||
@NATIVE_TRUE@ $(MKDIR_P) check-vet-dir/src/cmd/internal check-vet-dir/src/cmd/vendor/golang.org/x
|
@NATIVE_TRUE@ $(MKDIR_P) check-vet-dir/src/cmd/internal check-vet-dir/src/cmd/vendor/golang.org/x
|
||||||
|
@NATIVE_TRUE@ cp $(libgosrcdir)/go.mod check-vet-dir/src/
|
||||||
|
@NATIVE_TRUE@ cp $(cmdsrcdir)/go.mod check-vet-dir/src/cmd/
|
||||||
|
@NATIVE_TRUE@ $(MKDIR_P) check-vet-dir/src/vendor check-vet-dir/src/cmd/vendor
|
||||||
|
@NATIVE_TRUE@ cp $(libgosrcdir)/vendor/modules.txt check-vet-dir/src/vendor/
|
||||||
|
@NATIVE_TRUE@ cp $(libgosrcdir)/cmd/vendor/modules.txt check-vet-dir/src/cmd/vendor/
|
||||||
@NATIVE_TRUE@ cp -r $(cmdsrcdir)/vet check-vet-dir/src/cmd/
|
@NATIVE_TRUE@ cp -r $(cmdsrcdir)/vet check-vet-dir/src/cmd/
|
||||||
@NATIVE_TRUE@ cp -r $(cmdsrcdir)/internal/objabi check-vet-dir/src/cmd/internal
|
@NATIVE_TRUE@ cp -r $(cmdsrcdir)/internal/objabi check-vet-dir/src/cmd/internal
|
||||||
@NATIVE_TRUE@ cp $(libgodir)/objabi.go check-vet-dir/src/cmd/internal/objabi/
|
@NATIVE_TRUE@ cp $(libgodir)/objabi.go check-vet-dir/src/cmd/internal/objabi/
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
9b955d2d3fcff6a5bc8bce7bafdc4c634a28e95b
|
2ff33f5e443165e55a080f3a649e4c070c4096d1
|
||||||
|
|
||||||
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.
|
||||||
|
@ -775,6 +775,7 @@ libgo_go_objs = \
|
|||||||
syscall/errno.lo \
|
syscall/errno.lo \
|
||||||
syscall/signame.lo \
|
syscall/signame.lo \
|
||||||
syscall/wait.lo \
|
syscall/wait.lo \
|
||||||
|
os/dir_gccgo_c.lo \
|
||||||
$(golangorg_x_net_lif_lo) \
|
$(golangorg_x_net_lif_lo) \
|
||||||
$(golangorg_x_net_route_lo) \
|
$(golangorg_x_net_route_lo) \
|
||||||
log/syslog/syslog_c.lo \
|
log/syslog/syslog_c.lo \
|
||||||
@ -1062,6 +1063,7 @@ extra_go_files_os_user = os_user_linknames.go
|
|||||||
os/user.lo.dep: $(extra_go_files_os_user)
|
os/user.lo.dep: $(extra_go_files_os_user)
|
||||||
|
|
||||||
extra_check_libs_cmd_go_internal_cache = $(abs_builddir)/libgotool.a
|
extra_check_libs_cmd_go_internal_cache = $(abs_builddir)/libgotool.a
|
||||||
|
extra_check_libs_cmd_go_internal_fsys = $(abs_builddir)/libgotool.a
|
||||||
extra_check_libs_cmd_go_internal_generate = $(abs_builddir)/libgotool.a
|
extra_check_libs_cmd_go_internal_generate = $(abs_builddir)/libgotool.a
|
||||||
extra_check_libs_cmd_go_internal_get = $(abs_builddir)/libgotool.a
|
extra_check_libs_cmd_go_internal_get = $(abs_builddir)/libgotool.a
|
||||||
extra_check_libs_cmd_go_internal_load = $(abs_builddir)/libgotool.a
|
extra_check_libs_cmd_go_internal_load = $(abs_builddir)/libgotool.a
|
||||||
@ -1075,10 +1077,14 @@ extra_check_libs_cmd_go_internal_modload = $(abs_builddir)/libgotool.a
|
|||||||
extra_check_libs_cmd_go_internal_module = $(abs_builddir)/libgotool.a
|
extra_check_libs_cmd_go_internal_module = $(abs_builddir)/libgotool.a
|
||||||
extra_check_libs_cmd_go_internal_mvs = $(abs_builddir)/libgotool.a
|
extra_check_libs_cmd_go_internal_mvs = $(abs_builddir)/libgotool.a
|
||||||
extra_check_libs_cmd_go_internal_search = $(abs_builddir)/libgotool.a
|
extra_check_libs_cmd_go_internal_search = $(abs_builddir)/libgotool.a
|
||||||
|
extra_check_libs_cmd_go_internal_str = $(abs_builddir)/libgotool.a
|
||||||
extra_check_libs_cmd_go_internal_test = $(abs_builddir)/libgotool.a
|
extra_check_libs_cmd_go_internal_test = $(abs_builddir)/libgotool.a
|
||||||
|
extra_check_libs_cmd_go_internal_vcs = $(abs_builddir)/libgotool.a
|
||||||
extra_check_libs_cmd_go_internal_web2 = $(abs_builddir)/libgotool.a
|
extra_check_libs_cmd_go_internal_web2 = $(abs_builddir)/libgotool.a
|
||||||
extra_check_libs_cmd_go_internal_work = $(abs_builddir)/libgotool.a
|
extra_check_libs_cmd_go_internal_work = $(abs_builddir)/libgotool.a
|
||||||
|
|
||||||
|
extra_check_libs_cmd_internal_buildid = $(abs_builddir)/libgotool.a
|
||||||
|
|
||||||
extra_check_libs_cmd_vet_internal_cfg = $(abs_builddir)/libgotool.a
|
extra_check_libs_cmd_vet_internal_cfg = $(abs_builddir)/libgotool.a
|
||||||
|
|
||||||
# FIXME: The following C files may as well move to the runtime
|
# FIXME: The following C files may as well move to the runtime
|
||||||
@ -1122,6 +1128,11 @@ syscall/wait.lo: go/syscall/wait.c runtime.inc
|
|||||||
@$(MKDIR_P) syscall
|
@$(MKDIR_P) syscall
|
||||||
$(LTCOMPILE) -c -o $@ $(srcdir)/go/syscall/wait.c
|
$(LTCOMPILE) -c -o $@ $(srcdir)/go/syscall/wait.c
|
||||||
|
|
||||||
|
# An os function is written in C.
|
||||||
|
os/dir_gccgo_c.lo: go/os/dir_gccgo_c.c runtime.inc
|
||||||
|
@$(MKDIR_P) os
|
||||||
|
$(LTCOMPILE) -c -o $@ $(srcdir)/go/os/dir_gccgo_c.c
|
||||||
|
|
||||||
# internal/cpu needs some C code.
|
# internal/cpu needs some C code.
|
||||||
internal/cpu/cpu_gccgo.lo: go/internal/cpu/cpu_gccgo.c runtime.inc
|
internal/cpu/cpu_gccgo.lo: go/internal/cpu/cpu_gccgo.c runtime.inc
|
||||||
@$(MKDIR_P) internal/cpu
|
@$(MKDIR_P) internal/cpu
|
||||||
|
@ -224,7 +224,7 @@ LTLIBRARIES = $(toolexeclib_LTLIBRARIES)
|
|||||||
am__DEPENDENCIES_3 = $(addsuffix .lo,$(PACKAGES)) \
|
am__DEPENDENCIES_3 = $(addsuffix .lo,$(PACKAGES)) \
|
||||||
internal/bytealg/bytealg.lo reflect/makefunc_ffi_c.lo \
|
internal/bytealg/bytealg.lo reflect/makefunc_ffi_c.lo \
|
||||||
$(am__DEPENDENCIES_1) syscall/errno.lo syscall/signame.lo \
|
$(am__DEPENDENCIES_1) syscall/errno.lo syscall/signame.lo \
|
||||||
syscall/wait.lo $(golangorg_x_net_lif_lo) \
|
syscall/wait.lo os/dir_gccgo_c.lo $(golangorg_x_net_lif_lo) \
|
||||||
$(golangorg_x_net_route_lo) log/syslog/syslog_c.lo \
|
$(golangorg_x_net_route_lo) log/syslog/syslog_c.lo \
|
||||||
runtime/internal/atomic_c.lo sync/atomic_c.lo \
|
runtime/internal/atomic_c.lo sync/atomic_c.lo \
|
||||||
internal/cpu/cpu_gccgo.lo $(am__DEPENDENCIES_2)
|
internal/cpu/cpu_gccgo.lo $(am__DEPENDENCIES_2)
|
||||||
@ -940,6 +940,7 @@ libgo_go_objs = \
|
|||||||
syscall/errno.lo \
|
syscall/errno.lo \
|
||||||
syscall/signame.lo \
|
syscall/signame.lo \
|
||||||
syscall/wait.lo \
|
syscall/wait.lo \
|
||||||
|
os/dir_gccgo_c.lo \
|
||||||
$(golangorg_x_net_lif_lo) \
|
$(golangorg_x_net_lif_lo) \
|
||||||
$(golangorg_x_net_route_lo) \
|
$(golangorg_x_net_route_lo) \
|
||||||
log/syslog/syslog_c.lo \
|
log/syslog/syslog_c.lo \
|
||||||
@ -1130,6 +1131,7 @@ extra_go_files_cmd_go_internal_cfg = zdefaultcc.go
|
|||||||
extra_go_files_os = os_linknames.go
|
extra_go_files_os = os_linknames.go
|
||||||
extra_go_files_os_user = os_user_linknames.go
|
extra_go_files_os_user = os_user_linknames.go
|
||||||
extra_check_libs_cmd_go_internal_cache = $(abs_builddir)/libgotool.a
|
extra_check_libs_cmd_go_internal_cache = $(abs_builddir)/libgotool.a
|
||||||
|
extra_check_libs_cmd_go_internal_fsys = $(abs_builddir)/libgotool.a
|
||||||
extra_check_libs_cmd_go_internal_generate = $(abs_builddir)/libgotool.a
|
extra_check_libs_cmd_go_internal_generate = $(abs_builddir)/libgotool.a
|
||||||
extra_check_libs_cmd_go_internal_get = $(abs_builddir)/libgotool.a
|
extra_check_libs_cmd_go_internal_get = $(abs_builddir)/libgotool.a
|
||||||
extra_check_libs_cmd_go_internal_load = $(abs_builddir)/libgotool.a
|
extra_check_libs_cmd_go_internal_load = $(abs_builddir)/libgotool.a
|
||||||
@ -1143,9 +1145,12 @@ extra_check_libs_cmd_go_internal_modload = $(abs_builddir)/libgotool.a
|
|||||||
extra_check_libs_cmd_go_internal_module = $(abs_builddir)/libgotool.a
|
extra_check_libs_cmd_go_internal_module = $(abs_builddir)/libgotool.a
|
||||||
extra_check_libs_cmd_go_internal_mvs = $(abs_builddir)/libgotool.a
|
extra_check_libs_cmd_go_internal_mvs = $(abs_builddir)/libgotool.a
|
||||||
extra_check_libs_cmd_go_internal_search = $(abs_builddir)/libgotool.a
|
extra_check_libs_cmd_go_internal_search = $(abs_builddir)/libgotool.a
|
||||||
|
extra_check_libs_cmd_go_internal_str = $(abs_builddir)/libgotool.a
|
||||||
extra_check_libs_cmd_go_internal_test = $(abs_builddir)/libgotool.a
|
extra_check_libs_cmd_go_internal_test = $(abs_builddir)/libgotool.a
|
||||||
|
extra_check_libs_cmd_go_internal_vcs = $(abs_builddir)/libgotool.a
|
||||||
extra_check_libs_cmd_go_internal_web2 = $(abs_builddir)/libgotool.a
|
extra_check_libs_cmd_go_internal_web2 = $(abs_builddir)/libgotool.a
|
||||||
extra_check_libs_cmd_go_internal_work = $(abs_builddir)/libgotool.a
|
extra_check_libs_cmd_go_internal_work = $(abs_builddir)/libgotool.a
|
||||||
|
extra_check_libs_cmd_internal_buildid = $(abs_builddir)/libgotool.a
|
||||||
extra_check_libs_cmd_vet_internal_cfg = $(abs_builddir)/libgotool.a
|
extra_check_libs_cmd_vet_internal_cfg = $(abs_builddir)/libgotool.a
|
||||||
@HAVE_STAT_TIMESPEC_FALSE@@LIBGO_IS_SOLARIS_TRUE@matchargs_os =
|
@HAVE_STAT_TIMESPEC_FALSE@@LIBGO_IS_SOLARIS_TRUE@matchargs_os =
|
||||||
|
|
||||||
@ -3009,6 +3014,11 @@ syscall/wait.lo: go/syscall/wait.c runtime.inc
|
|||||||
@$(MKDIR_P) syscall
|
@$(MKDIR_P) syscall
|
||||||
$(LTCOMPILE) -c -o $@ $(srcdir)/go/syscall/wait.c
|
$(LTCOMPILE) -c -o $@ $(srcdir)/go/syscall/wait.c
|
||||||
|
|
||||||
|
# An os function is written in C.
|
||||||
|
os/dir_gccgo_c.lo: go/os/dir_gccgo_c.c runtime.inc
|
||||||
|
@$(MKDIR_P) os
|
||||||
|
$(LTCOMPILE) -c -o $@ $(srcdir)/go/os/dir_gccgo_c.c
|
||||||
|
|
||||||
# internal/cpu needs some C code.
|
# internal/cpu needs some C code.
|
||||||
internal/cpu/cpu_gccgo.lo: go/internal/cpu/cpu_gccgo.c runtime.inc
|
internal/cpu/cpu_gccgo.lo: go/internal/cpu/cpu_gccgo.c runtime.inc
|
||||||
@$(MKDIR_P) internal/cpu
|
@$(MKDIR_P) internal/cpu
|
||||||
|
@ -1 +1 @@
|
|||||||
go1.15.6
|
go1.16beta1
|
||||||
|
@ -3,6 +3,7 @@ archive/zip
|
|||||||
bufio
|
bufio
|
||||||
bytes
|
bytes
|
||||||
cmd/go/internal/cache
|
cmd/go/internal/cache
|
||||||
|
cmd/go/internal/fsys
|
||||||
cmd/go/internal/generate
|
cmd/go/internal/generate
|
||||||
cmd/go/internal/get
|
cmd/go/internal/get
|
||||||
cmd/go/internal/imports
|
cmd/go/internal/imports
|
||||||
@ -16,8 +17,10 @@ cmd/go/internal/modload
|
|||||||
cmd/go/internal/mvs
|
cmd/go/internal/mvs
|
||||||
cmd/go/internal/par
|
cmd/go/internal/par
|
||||||
cmd/go/internal/search
|
cmd/go/internal/search
|
||||||
|
cmd/go/internal/str
|
||||||
cmd/go/internal/test
|
cmd/go/internal/test
|
||||||
cmd/go/internal/txtar
|
cmd/go/internal/txtar
|
||||||
|
cmd/go/internal/vcs
|
||||||
cmd/go/internal/work
|
cmd/go/internal/work
|
||||||
cmd/internal/buildid
|
cmd/internal/buildid
|
||||||
cmd/internal/edit
|
cmd/internal/edit
|
||||||
@ -113,6 +116,7 @@ internal/trace
|
|||||||
internal/unsafeheader
|
internal/unsafeheader
|
||||||
internal/xcoff
|
internal/xcoff
|
||||||
io
|
io
|
||||||
|
io/fs
|
||||||
io/ioutil
|
io/ioutil
|
||||||
log
|
log
|
||||||
log/syslog
|
log/syslog
|
||||||
@ -155,6 +159,7 @@ runtime/debug
|
|||||||
runtime/internal/atomic
|
runtime/internal/atomic
|
||||||
runtime/internal/math
|
runtime/internal/math
|
||||||
runtime/internal/sys
|
runtime/internal/sys
|
||||||
|
runtime/metrics
|
||||||
runtime/pprof
|
runtime/pprof
|
||||||
runtime/trace
|
runtime/trace
|
||||||
sort
|
sort
|
||||||
@ -164,6 +169,7 @@ sync
|
|||||||
sync/atomic
|
sync/atomic
|
||||||
syscall
|
syscall
|
||||||
testing
|
testing
|
||||||
|
testing/fstest
|
||||||
testing/iotest
|
testing/iotest
|
||||||
testing/quick
|
testing/quick
|
||||||
text/scanner
|
text/scanner
|
||||||
|
@ -36,6 +36,10 @@
|
|||||||
/* Define to 1 if you have the `cosl' function. */
|
/* Define to 1 if you have the `cosl' function. */
|
||||||
#undef HAVE_COSL
|
#undef HAVE_COSL
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
|
||||||
|
*/
|
||||||
|
#undef HAVE_DIRENT_H
|
||||||
|
|
||||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||||
#undef HAVE_DLFCN_H
|
#undef HAVE_DLFCN_H
|
||||||
|
|
||||||
@ -159,6 +163,9 @@
|
|||||||
/* Define to 1 if you have the `mknodat' function. */
|
/* Define to 1 if you have the `mknodat' function. */
|
||||||
#undef HAVE_MKNODAT
|
#undef HAVE_MKNODAT
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
|
||||||
|
#undef HAVE_NDIR_H
|
||||||
|
|
||||||
/* Define to 1 if you have the <netinet/icmp6.h> header file. */
|
/* Define to 1 if you have the <netinet/icmp6.h> header file. */
|
||||||
#undef HAVE_NETINET_ICMP6_H
|
#undef HAVE_NETINET_ICMP6_H
|
||||||
|
|
||||||
@ -249,6 +256,9 @@
|
|||||||
/* Define to 1 if you have the `strsignal' function. */
|
/* Define to 1 if you have the `strsignal' function. */
|
||||||
#undef HAVE_STRSIGNAL
|
#undef HAVE_STRSIGNAL
|
||||||
|
|
||||||
|
/* Define to 1 if `d_type' is a member of `struct dirent'. */
|
||||||
|
#undef HAVE_STRUCT_DIRENT_D_TYPE
|
||||||
|
|
||||||
/* Define to 1 if <math.h> defines struct exception */
|
/* Define to 1 if <math.h> defines struct exception */
|
||||||
#undef HAVE_STRUCT_EXCEPTION
|
#undef HAVE_STRUCT_EXCEPTION
|
||||||
|
|
||||||
@ -261,6 +271,10 @@
|
|||||||
/* Define to 1 if you have the <syscall.h> header file. */
|
/* Define to 1 if you have the <syscall.h> header file. */
|
||||||
#undef HAVE_SYSCALL_H
|
#undef HAVE_SYSCALL_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
|
||||||
|
*/
|
||||||
|
#undef HAVE_SYS_DIR_H
|
||||||
|
|
||||||
/* Define to 1 if you have the <sys/epoll.h> header file. */
|
/* Define to 1 if you have the <sys/epoll.h> header file. */
|
||||||
#undef HAVE_SYS_EPOLL_H
|
#undef HAVE_SYS_EPOLL_H
|
||||||
|
|
||||||
@ -279,6 +293,10 @@
|
|||||||
/* Define to 1 if you have the <sys/mount.h> header file. */
|
/* Define to 1 if you have the <sys/mount.h> header file. */
|
||||||
#undef HAVE_SYS_MOUNT_H
|
#undef HAVE_SYS_MOUNT_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
|
||||||
|
*/
|
||||||
|
#undef HAVE_SYS_NDIR_H
|
||||||
|
|
||||||
/* Define to 1 if you have the <sys/prctl.h> header file. */
|
/* Define to 1 if you have the <sys/prctl.h> header file. */
|
||||||
#undef HAVE_SYS_PRCTL_H
|
#undef HAVE_SYS_PRCTL_H
|
||||||
|
|
||||||
|
254
libgo/configure
vendored
254
libgo/configure
vendored
@ -1956,6 +1956,63 @@ fi
|
|||||||
|
|
||||||
} # ac_fn_c_check_header_mongrel
|
} # ac_fn_c_check_header_mongrel
|
||||||
|
|
||||||
|
# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES
|
||||||
|
# ----------------------------------------------------
|
||||||
|
# Tries to find if the field MEMBER exists in type AGGR, after including
|
||||||
|
# INCLUDES, setting cache variable VAR accordingly.
|
||||||
|
ac_fn_c_check_member ()
|
||||||
|
{
|
||||||
|
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5
|
||||||
|
$as_echo_n "checking for $2.$3... " >&6; }
|
||||||
|
if eval \${$4+:} false; then :
|
||||||
|
$as_echo_n "(cached) " >&6
|
||||||
|
else
|
||||||
|
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||||
|
/* end confdefs.h. */
|
||||||
|
$5
|
||||||
|
int
|
||||||
|
main ()
|
||||||
|
{
|
||||||
|
static $2 ac_aggr;
|
||||||
|
if (ac_aggr.$3)
|
||||||
|
return 0;
|
||||||
|
;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
_ACEOF
|
||||||
|
if ac_fn_c_try_compile "$LINENO"; then :
|
||||||
|
eval "$4=yes"
|
||||||
|
else
|
||||||
|
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||||
|
/* end confdefs.h. */
|
||||||
|
$5
|
||||||
|
int
|
||||||
|
main ()
|
||||||
|
{
|
||||||
|
static $2 ac_aggr;
|
||||||
|
if (sizeof ac_aggr.$3)
|
||||||
|
return 0;
|
||||||
|
;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
_ACEOF
|
||||||
|
if ac_fn_c_try_compile "$LINENO"; then :
|
||||||
|
eval "$4=yes"
|
||||||
|
else
|
||||||
|
eval "$4=no"
|
||||||
|
fi
|
||||||
|
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||||
|
fi
|
||||||
|
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||||
|
fi
|
||||||
|
eval ac_res=\$$4
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
|
||||||
|
$as_echo "$ac_res" >&6; }
|
||||||
|
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
|
||||||
|
|
||||||
|
} # ac_fn_c_check_member
|
||||||
|
|
||||||
# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
|
# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
|
||||||
# -------------------------------------------
|
# -------------------------------------------
|
||||||
# Tests whether TYPE exists after having included INCLUDES, setting cache
|
# Tests whether TYPE exists after having included INCLUDES, setting cache
|
||||||
@ -2551,7 +2608,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=18:0:0
|
libtool_VERSION=19:0:0
|
||||||
|
|
||||||
|
|
||||||
# Default to --enable-multilib
|
# Default to --enable-multilib
|
||||||
@ -11497,7 +11554,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 11500 "configure"
|
#line 11557 "configure"
|
||||||
#include "confdefs.h"
|
#include "confdefs.h"
|
||||||
|
|
||||||
#if HAVE_DLFCN_H
|
#if HAVE_DLFCN_H
|
||||||
@ -11603,7 +11660,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 11606 "configure"
|
#line 11663 "configure"
|
||||||
#include "confdefs.h"
|
#include "confdefs.h"
|
||||||
|
|
||||||
#if HAVE_DLFCN_H
|
#if HAVE_DLFCN_H
|
||||||
@ -13923,7 +13980,7 @@ go_include="-include"
|
|||||||
# All known GOOS values. This is the union of all operating systems
|
# All known GOOS values. This is the union of all operating systems
|
||||||
# supported by the gofrontend and all operating systems supported by
|
# supported by the gofrontend and all operating systems supported by
|
||||||
# the gc toolchain.
|
# the gc toolchain.
|
||||||
ALLGOOS="aix android darwin dragonfly freebsd hurd illumos irix js linux netbsd openbsd plan9 rtems solaris windows"
|
ALLGOOS="aix android darwin dragonfly freebsd hurd illumos ios irix js linux netbsd openbsd plan9 rtems solaris windows zos"
|
||||||
|
|
||||||
is_darwin=no
|
is_darwin=no
|
||||||
is_freebsd=no
|
is_freebsd=no
|
||||||
@ -15287,6 +15344,195 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
ac_header_dirent=no
|
||||||
|
for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do
|
||||||
|
as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh`
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5
|
||||||
|
$as_echo_n "checking for $ac_hdr that defines DIR... " >&6; }
|
||||||
|
if eval \${$as_ac_Header+:} false; then :
|
||||||
|
$as_echo_n "(cached) " >&6
|
||||||
|
else
|
||||||
|
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||||
|
/* end confdefs.h. */
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <$ac_hdr>
|
||||||
|
|
||||||
|
int
|
||||||
|
main ()
|
||||||
|
{
|
||||||
|
if ((DIR *) 0)
|
||||||
|
return 0;
|
||||||
|
;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
_ACEOF
|
||||||
|
if ac_fn_c_try_compile "$LINENO"; then :
|
||||||
|
eval "$as_ac_Header=yes"
|
||||||
|
else
|
||||||
|
eval "$as_ac_Header=no"
|
||||||
|
fi
|
||||||
|
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||||
|
fi
|
||||||
|
eval ac_res=\$$as_ac_Header
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
|
||||||
|
$as_echo "$ac_res" >&6; }
|
||||||
|
if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
|
||||||
|
cat >>confdefs.h <<_ACEOF
|
||||||
|
#define `$as_echo "HAVE_$ac_hdr" | $as_tr_cpp` 1
|
||||||
|
_ACEOF
|
||||||
|
|
||||||
|
ac_header_dirent=$ac_hdr; break
|
||||||
|
fi
|
||||||
|
|
||||||
|
done
|
||||||
|
# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
|
||||||
|
if test $ac_header_dirent = dirent.h; then
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5
|
||||||
|
$as_echo_n "checking for library containing opendir... " >&6; }
|
||||||
|
if ${ac_cv_search_opendir+:} false; then :
|
||||||
|
$as_echo_n "(cached) " >&6
|
||||||
|
else
|
||||||
|
ac_func_search_save_LIBS=$LIBS
|
||||||
|
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||||
|
/* end confdefs.h. */
|
||||||
|
|
||||||
|
/* Override any GCC internal prototype to avoid an error.
|
||||||
|
Use char because int might match the return type of a GCC
|
||||||
|
builtin and then its argument prototype would still apply. */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
#endif
|
||||||
|
char opendir ();
|
||||||
|
int
|
||||||
|
main ()
|
||||||
|
{
|
||||||
|
return opendir ();
|
||||||
|
;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
_ACEOF
|
||||||
|
for ac_lib in '' dir; do
|
||||||
|
if test -z "$ac_lib"; then
|
||||||
|
ac_res="none required"
|
||||||
|
else
|
||||||
|
ac_res=-l$ac_lib
|
||||||
|
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
|
||||||
|
fi
|
||||||
|
if ac_fn_c_try_link "$LINENO"; then :
|
||||||
|
ac_cv_search_opendir=$ac_res
|
||||||
|
fi
|
||||||
|
rm -f core conftest.err conftest.$ac_objext \
|
||||||
|
conftest$ac_exeext
|
||||||
|
if ${ac_cv_search_opendir+:} false; then :
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if ${ac_cv_search_opendir+:} false; then :
|
||||||
|
|
||||||
|
else
|
||||||
|
ac_cv_search_opendir=no
|
||||||
|
fi
|
||||||
|
rm conftest.$ac_ext
|
||||||
|
LIBS=$ac_func_search_save_LIBS
|
||||||
|
fi
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5
|
||||||
|
$as_echo "$ac_cv_search_opendir" >&6; }
|
||||||
|
ac_res=$ac_cv_search_opendir
|
||||||
|
if test "$ac_res" != no; then :
|
||||||
|
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
else
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5
|
||||||
|
$as_echo_n "checking for library containing opendir... " >&6; }
|
||||||
|
if ${ac_cv_search_opendir+:} false; then :
|
||||||
|
$as_echo_n "(cached) " >&6
|
||||||
|
else
|
||||||
|
ac_func_search_save_LIBS=$LIBS
|
||||||
|
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||||
|
/* end confdefs.h. */
|
||||||
|
|
||||||
|
/* Override any GCC internal prototype to avoid an error.
|
||||||
|
Use char because int might match the return type of a GCC
|
||||||
|
builtin and then its argument prototype would still apply. */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
#endif
|
||||||
|
char opendir ();
|
||||||
|
int
|
||||||
|
main ()
|
||||||
|
{
|
||||||
|
return opendir ();
|
||||||
|
;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
_ACEOF
|
||||||
|
for ac_lib in '' x; do
|
||||||
|
if test -z "$ac_lib"; then
|
||||||
|
ac_res="none required"
|
||||||
|
else
|
||||||
|
ac_res=-l$ac_lib
|
||||||
|
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
|
||||||
|
fi
|
||||||
|
if ac_fn_c_try_link "$LINENO"; then :
|
||||||
|
ac_cv_search_opendir=$ac_res
|
||||||
|
fi
|
||||||
|
rm -f core conftest.err conftest.$ac_objext \
|
||||||
|
conftest$ac_exeext
|
||||||
|
if ${ac_cv_search_opendir+:} false; then :
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if ${ac_cv_search_opendir+:} false; then :
|
||||||
|
|
||||||
|
else
|
||||||
|
ac_cv_search_opendir=no
|
||||||
|
fi
|
||||||
|
rm conftest.$ac_ext
|
||||||
|
LIBS=$ac_func_search_save_LIBS
|
||||||
|
fi
|
||||||
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5
|
||||||
|
$as_echo "$ac_cv_search_opendir" >&6; }
|
||||||
|
ac_res=$ac_cv_search_opendir
|
||||||
|
if test "$ac_res" != no; then :
|
||||||
|
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ac_fn_c_check_member "$LINENO" "struct dirent" "d_type" "ac_cv_member_struct_dirent_d_type" "
|
||||||
|
#include <sys/types.h>
|
||||||
|
#ifdef HAVE_DIRENT_H
|
||||||
|
# include <dirent.h>
|
||||||
|
#else
|
||||||
|
# define dirent direct
|
||||||
|
# ifdef HAVE_SYS_NDIR_H
|
||||||
|
# include <sys/ndir.h>
|
||||||
|
# endif
|
||||||
|
# ifdef HAVE_SYS_DIR_H
|
||||||
|
# include <sys/dir.h>
|
||||||
|
# endif
|
||||||
|
# ifdef HAVE_NDIR_H
|
||||||
|
# include <ndir.h>
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
"
|
||||||
|
if test "x$ac_cv_member_struct_dirent_d_type" = xyes; then :
|
||||||
|
|
||||||
|
cat >>confdefs.h <<_ACEOF
|
||||||
|
#define HAVE_STRUCT_DIRENT_D_TYPE 1
|
||||||
|
_ACEOF
|
||||||
|
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for ac_func in accept4 dup3 epoll_create1 faccessat fallocate fchmodat fchownat futimesat getxattr inotify_add_watch inotify_init inotify_init1 inotify_rm_watch listxattr mkdirat mknodat open64 openat pipe2 removexattr renameat setxattr sync_file_range splice syscall tee unlinkat unshare utimensat
|
for ac_func in accept4 dup3 epoll_create1 faccessat fallocate fchmodat fchownat futimesat getxattr inotify_add_watch inotify_init inotify_init1 inotify_rm_watch listxattr mkdirat mknodat open64 openat pipe2 removexattr renameat setxattr sync_file_range splice syscall tee unlinkat unshare utimensat
|
||||||
do :
|
do :
|
||||||
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
||||||
|
@ -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=18:0:0
|
libtool_VERSION=19:0:0
|
||||||
AC_SUBST(libtool_VERSION)
|
AC_SUBST(libtool_VERSION)
|
||||||
|
|
||||||
AM_ENABLE_MULTILIB(, ..)
|
AM_ENABLE_MULTILIB(, ..)
|
||||||
@ -167,7 +167,7 @@ AC_SUBST(go_include)
|
|||||||
# All known GOOS values. This is the union of all operating systems
|
# All known GOOS values. This is the union of all operating systems
|
||||||
# supported by the gofrontend and all operating systems supported by
|
# supported by the gofrontend and all operating systems supported by
|
||||||
# the gc toolchain.
|
# the gc toolchain.
|
||||||
ALLGOOS="aix android darwin dragonfly freebsd hurd illumos irix js linux netbsd openbsd plan9 rtems solaris windows"
|
ALLGOOS="aix android darwin dragonfly freebsd hurd illumos ios irix js linux netbsd openbsd plan9 rtems solaris windows zos"
|
||||||
|
|
||||||
is_darwin=no
|
is_darwin=no
|
||||||
is_freebsd=no
|
is_freebsd=no
|
||||||
@ -598,6 +598,8 @@ AC_CHECK_FUNCS(strerror_r strsignal wait4 mincore setenv unsetenv dl_iterate_phd
|
|||||||
AM_CONDITIONAL(HAVE_STRERROR_R, test "$ac_cv_func_strerror_r" = yes)
|
AM_CONDITIONAL(HAVE_STRERROR_R, test "$ac_cv_func_strerror_r" = yes)
|
||||||
AM_CONDITIONAL(HAVE_WAIT4, test "$ac_cv_func_wait4" = yes)
|
AM_CONDITIONAL(HAVE_WAIT4, test "$ac_cv_func_wait4" = yes)
|
||||||
|
|
||||||
|
AC_STRUCT_DIRENT_D_TYPE
|
||||||
|
|
||||||
AC_CHECK_FUNCS(accept4 dup3 epoll_create1 faccessat fallocate fchmodat fchownat futimesat getxattr inotify_add_watch inotify_init inotify_init1 inotify_rm_watch listxattr mkdirat mknodat open64 openat pipe2 removexattr renameat setxattr sync_file_range splice syscall tee unlinkat unshare utimensat)
|
AC_CHECK_FUNCS(accept4 dup3 epoll_create1 faccessat fallocate fchmodat fchownat futimesat getxattr inotify_add_watch inotify_init inotify_init1 inotify_rm_watch listxattr mkdirat mknodat open64 openat pipe2 removexattr renameat setxattr sync_file_range splice syscall tee unlinkat unshare utimensat)
|
||||||
AC_TYPE_OFF_T
|
AC_TYPE_OFF_T
|
||||||
AC_CHECK_TYPES([loff_t])
|
AC_CHECK_TYPES([loff_t])
|
||||||
|
@ -13,8 +13,8 @@ package tar
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
"math"
|
"math"
|
||||||
"os"
|
|
||||||
"path"
|
"path"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -525,12 +525,12 @@ func (h Header) allowedFormats() (format Format, paxHdrs map[string]string, err
|
|||||||
return format, paxHdrs, err
|
return format, paxHdrs, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileInfo returns an os.FileInfo for the Header.
|
// FileInfo returns an fs.FileInfo for the Header.
|
||||||
func (h *Header) FileInfo() os.FileInfo {
|
func (h *Header) FileInfo() fs.FileInfo {
|
||||||
return headerFileInfo{h}
|
return headerFileInfo{h}
|
||||||
}
|
}
|
||||||
|
|
||||||
// headerFileInfo implements os.FileInfo.
|
// headerFileInfo implements fs.FileInfo.
|
||||||
type headerFileInfo struct {
|
type headerFileInfo struct {
|
||||||
h *Header
|
h *Header
|
||||||
}
|
}
|
||||||
@ -549,57 +549,57 @@ func (fi headerFileInfo) Name() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Mode returns the permission and mode bits for the headerFileInfo.
|
// Mode returns the permission and mode bits for the headerFileInfo.
|
||||||
func (fi headerFileInfo) Mode() (mode os.FileMode) {
|
func (fi headerFileInfo) Mode() (mode fs.FileMode) {
|
||||||
// Set file permission bits.
|
// Set file permission bits.
|
||||||
mode = os.FileMode(fi.h.Mode).Perm()
|
mode = fs.FileMode(fi.h.Mode).Perm()
|
||||||
|
|
||||||
// Set setuid, setgid and sticky bits.
|
// Set setuid, setgid and sticky bits.
|
||||||
if fi.h.Mode&c_ISUID != 0 {
|
if fi.h.Mode&c_ISUID != 0 {
|
||||||
mode |= os.ModeSetuid
|
mode |= fs.ModeSetuid
|
||||||
}
|
}
|
||||||
if fi.h.Mode&c_ISGID != 0 {
|
if fi.h.Mode&c_ISGID != 0 {
|
||||||
mode |= os.ModeSetgid
|
mode |= fs.ModeSetgid
|
||||||
}
|
}
|
||||||
if fi.h.Mode&c_ISVTX != 0 {
|
if fi.h.Mode&c_ISVTX != 0 {
|
||||||
mode |= os.ModeSticky
|
mode |= fs.ModeSticky
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set file mode bits; clear perm, setuid, setgid, and sticky bits.
|
// Set file mode bits; clear perm, setuid, setgid, and sticky bits.
|
||||||
switch m := os.FileMode(fi.h.Mode) &^ 07777; m {
|
switch m := fs.FileMode(fi.h.Mode) &^ 07777; m {
|
||||||
case c_ISDIR:
|
case c_ISDIR:
|
||||||
mode |= os.ModeDir
|
mode |= fs.ModeDir
|
||||||
case c_ISFIFO:
|
case c_ISFIFO:
|
||||||
mode |= os.ModeNamedPipe
|
mode |= fs.ModeNamedPipe
|
||||||
case c_ISLNK:
|
case c_ISLNK:
|
||||||
mode |= os.ModeSymlink
|
mode |= fs.ModeSymlink
|
||||||
case c_ISBLK:
|
case c_ISBLK:
|
||||||
mode |= os.ModeDevice
|
mode |= fs.ModeDevice
|
||||||
case c_ISCHR:
|
case c_ISCHR:
|
||||||
mode |= os.ModeDevice
|
mode |= fs.ModeDevice
|
||||||
mode |= os.ModeCharDevice
|
mode |= fs.ModeCharDevice
|
||||||
case c_ISSOCK:
|
case c_ISSOCK:
|
||||||
mode |= os.ModeSocket
|
mode |= fs.ModeSocket
|
||||||
}
|
}
|
||||||
|
|
||||||
switch fi.h.Typeflag {
|
switch fi.h.Typeflag {
|
||||||
case TypeSymlink:
|
case TypeSymlink:
|
||||||
mode |= os.ModeSymlink
|
mode |= fs.ModeSymlink
|
||||||
case TypeChar:
|
case TypeChar:
|
||||||
mode |= os.ModeDevice
|
mode |= fs.ModeDevice
|
||||||
mode |= os.ModeCharDevice
|
mode |= fs.ModeCharDevice
|
||||||
case TypeBlock:
|
case TypeBlock:
|
||||||
mode |= os.ModeDevice
|
mode |= fs.ModeDevice
|
||||||
case TypeDir:
|
case TypeDir:
|
||||||
mode |= os.ModeDir
|
mode |= fs.ModeDir
|
||||||
case TypeFifo:
|
case TypeFifo:
|
||||||
mode |= os.ModeNamedPipe
|
mode |= fs.ModeNamedPipe
|
||||||
}
|
}
|
||||||
|
|
||||||
return mode
|
return mode
|
||||||
}
|
}
|
||||||
|
|
||||||
// sysStat, if non-nil, populates h from system-dependent fields of fi.
|
// sysStat, if non-nil, populates h from system-dependent fields of fi.
|
||||||
var sysStat func(fi os.FileInfo, h *Header) error
|
var sysStat func(fi fs.FileInfo, h *Header) error
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Mode constants from the USTAR spec:
|
// Mode constants from the USTAR spec:
|
||||||
@ -623,10 +623,10 @@ const (
|
|||||||
// If fi describes a symlink, FileInfoHeader records link as the link target.
|
// If fi describes a symlink, FileInfoHeader records link as the link target.
|
||||||
// If fi describes a directory, a slash is appended to the name.
|
// If fi describes a directory, a slash is appended to the name.
|
||||||
//
|
//
|
||||||
// Since os.FileInfo's Name method only returns the base name of
|
// Since fs.FileInfo's Name method only returns the base name of
|
||||||
// the file it describes, it may be necessary to modify Header.Name
|
// the file it describes, it may be necessary to modify Header.Name
|
||||||
// to provide the full path name of the file.
|
// to provide the full path name of the file.
|
||||||
func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) {
|
func FileInfoHeader(fi fs.FileInfo, link string) (*Header, error) {
|
||||||
if fi == nil {
|
if fi == nil {
|
||||||
return nil, errors.New("archive/tar: FileInfo is nil")
|
return nil, errors.New("archive/tar: FileInfo is nil")
|
||||||
}
|
}
|
||||||
@ -643,29 +643,29 @@ func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) {
|
|||||||
case fi.IsDir():
|
case fi.IsDir():
|
||||||
h.Typeflag = TypeDir
|
h.Typeflag = TypeDir
|
||||||
h.Name += "/"
|
h.Name += "/"
|
||||||
case fm&os.ModeSymlink != 0:
|
case fm&fs.ModeSymlink != 0:
|
||||||
h.Typeflag = TypeSymlink
|
h.Typeflag = TypeSymlink
|
||||||
h.Linkname = link
|
h.Linkname = link
|
||||||
case fm&os.ModeDevice != 0:
|
case fm&fs.ModeDevice != 0:
|
||||||
if fm&os.ModeCharDevice != 0 {
|
if fm&fs.ModeCharDevice != 0 {
|
||||||
h.Typeflag = TypeChar
|
h.Typeflag = TypeChar
|
||||||
} else {
|
} else {
|
||||||
h.Typeflag = TypeBlock
|
h.Typeflag = TypeBlock
|
||||||
}
|
}
|
||||||
case fm&os.ModeNamedPipe != 0:
|
case fm&fs.ModeNamedPipe != 0:
|
||||||
h.Typeflag = TypeFifo
|
h.Typeflag = TypeFifo
|
||||||
case fm&os.ModeSocket != 0:
|
case fm&fs.ModeSocket != 0:
|
||||||
return nil, fmt.Errorf("archive/tar: sockets not supported")
|
return nil, fmt.Errorf("archive/tar: sockets not supported")
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("archive/tar: unknown file mode %v", fm)
|
return nil, fmt.Errorf("archive/tar: unknown file mode %v", fm)
|
||||||
}
|
}
|
||||||
if fm&os.ModeSetuid != 0 {
|
if fm&fs.ModeSetuid != 0 {
|
||||||
h.Mode |= c_ISUID
|
h.Mode |= c_ISUID
|
||||||
}
|
}
|
||||||
if fm&os.ModeSetgid != 0 {
|
if fm&fs.ModeSetgid != 0 {
|
||||||
h.Mode |= c_ISGID
|
h.Mode |= c_ISGID
|
||||||
}
|
}
|
||||||
if fm&os.ModeSticky != 0 {
|
if fm&fs.ModeSticky != 0 {
|
||||||
h.Mode |= c_ISVTX
|
h.Mode |= c_ISVTX
|
||||||
}
|
}
|
||||||
// If possible, populate additional fields from OS-specific
|
// If possible, populate additional fields from OS-specific
|
||||||
|
@ -7,7 +7,6 @@ package tar
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -104,7 +103,7 @@ func (tr *Reader) next() (*Header, error) {
|
|||||||
continue // This is a meta header affecting the next header
|
continue // This is a meta header affecting the next header
|
||||||
case TypeGNULongName, TypeGNULongLink:
|
case TypeGNULongName, TypeGNULongLink:
|
||||||
format.mayOnlyBe(FormatGNU)
|
format.mayOnlyBe(FormatGNU)
|
||||||
realname, err := ioutil.ReadAll(tr)
|
realname, err := io.ReadAll(tr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -294,7 +293,7 @@ func mergePAX(hdr *Header, paxHdrs map[string]string) (err error) {
|
|||||||
// parsePAX parses PAX headers.
|
// parsePAX parses PAX headers.
|
||||||
// If an extended header (type 'x') is invalid, ErrHeader is returned
|
// If an extended header (type 'x') is invalid, ErrHeader is returned
|
||||||
func parsePAX(r io.Reader) (map[string]string, error) {
|
func parsePAX(r io.Reader) (map[string]string, error) {
|
||||||
buf, err := ioutil.ReadAll(r)
|
buf, err := io.ReadAll(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -850,7 +849,7 @@ func discard(r io.Reader, n int64) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
copySkipped, err := io.CopyN(ioutil.Discard, r, n-seekSkipped)
|
copySkipped, err := io.CopyN(io.Discard, r, n-seekSkipped)
|
||||||
if err == io.EOF && seekSkipped+copySkipped < n {
|
if err == io.EOF && seekSkipped+copySkipped < n {
|
||||||
err = io.ErrUnexpectedEOF
|
err = io.ErrUnexpectedEOF
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"math"
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
@ -773,7 +772,7 @@ func TestReadTruncation(t *testing.T) {
|
|||||||
"testdata/pax-path-hdr.tar",
|
"testdata/pax-path-hdr.tar",
|
||||||
"testdata/sparse-formats.tar",
|
"testdata/sparse-formats.tar",
|
||||||
} {
|
} {
|
||||||
buf, err := ioutil.ReadFile(p)
|
buf, err := os.ReadFile(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@ -865,7 +864,7 @@ func TestReadTruncation(t *testing.T) {
|
|||||||
}
|
}
|
||||||
cnt++
|
cnt++
|
||||||
if s2 == "manual" {
|
if s2 == "manual" {
|
||||||
if _, err = tr.writeTo(ioutil.Discard); err != nil {
|
if _, err = tr.writeTo(io.Discard); err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
package tar
|
package tar
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"io/fs"
|
||||||
"os/user"
|
"os/user"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -23,7 +23,7 @@ func init() {
|
|||||||
// The downside is that renaming uname or gname by the OS never takes effect.
|
// The downside is that renaming uname or gname by the OS never takes effect.
|
||||||
var userMap, groupMap sync.Map // map[int]string
|
var userMap, groupMap sync.Map // map[int]string
|
||||||
|
|
||||||
func statUnix(fi os.FileInfo, h *Header) error {
|
func statUnix(fi fs.FileInfo, h *Header) error {
|
||||||
sys, ok := fi.Sys().(*syscall.Stat_t)
|
sys, ok := fi.Sys().(*syscall.Stat_t)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
@ -71,7 +71,7 @@ func statUnix(fi os.FileInfo, h *Header) error {
|
|||||||
minor := uint32((dev & 0x00000000000000ff) >> 0)
|
minor := uint32((dev & 0x00000000000000ff) >> 0)
|
||||||
minor |= uint32((dev & 0x00000ffffff00000) >> 12)
|
minor |= uint32((dev & 0x00000ffffff00000) >> 12)
|
||||||
h.Devmajor, h.Devminor = int64(major), int64(minor)
|
h.Devmajor, h.Devminor = int64(major), int64(minor)
|
||||||
case "darwin":
|
case "darwin", "ios":
|
||||||
// Copied from golang.org/x/sys/unix/dev_darwin.go.
|
// Copied from golang.org/x/sys/unix/dev_darwin.go.
|
||||||
major := uint32((dev >> 24) & 0xff)
|
major := uint32((dev >> 24) & 0xff)
|
||||||
minor := uint32(dev & 0xffffff)
|
minor := uint32(dev & 0xffffff)
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"internal/testenv"
|
"internal/testenv"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/fs"
|
||||||
"math"
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
@ -262,7 +262,7 @@ func TestFileInfoHeaderDir(t *testing.T) {
|
|||||||
func TestFileInfoHeaderSymlink(t *testing.T) {
|
func TestFileInfoHeaderSymlink(t *testing.T) {
|
||||||
testenv.MustHaveSymlink(t)
|
testenv.MustHaveSymlink(t)
|
||||||
|
|
||||||
tmpdir, err := ioutil.TempDir("", "TestFileInfoHeaderSymlink")
|
tmpdir, err := os.MkdirTemp("", "TestFileInfoHeaderSymlink")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -327,7 +327,7 @@ func TestRoundTrip(t *testing.T) {
|
|||||||
if !reflect.DeepEqual(rHdr, hdr) {
|
if !reflect.DeepEqual(rHdr, hdr) {
|
||||||
t.Errorf("Header mismatch.\n got %+v\nwant %+v", rHdr, hdr)
|
t.Errorf("Header mismatch.\n got %+v\nwant %+v", rHdr, hdr)
|
||||||
}
|
}
|
||||||
rData, err := ioutil.ReadAll(tr)
|
rData, err := io.ReadAll(tr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Read: %v", err)
|
t.Fatalf("Read: %v", err)
|
||||||
}
|
}
|
||||||
@ -338,7 +338,7 @@ func TestRoundTrip(t *testing.T) {
|
|||||||
|
|
||||||
type headerRoundTripTest struct {
|
type headerRoundTripTest struct {
|
||||||
h *Header
|
h *Header
|
||||||
fm os.FileMode
|
fm fs.FileMode
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHeaderRoundTrip(t *testing.T) {
|
func TestHeaderRoundTrip(t *testing.T) {
|
||||||
@ -361,7 +361,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
|||||||
ModTime: time.Unix(1360600852, 0),
|
ModTime: time.Unix(1360600852, 0),
|
||||||
Typeflag: TypeSymlink,
|
Typeflag: TypeSymlink,
|
||||||
},
|
},
|
||||||
fm: 0777 | os.ModeSymlink,
|
fm: 0777 | fs.ModeSymlink,
|
||||||
}, {
|
}, {
|
||||||
// character device node.
|
// character device node.
|
||||||
h: &Header{
|
h: &Header{
|
||||||
@ -371,7 +371,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
|||||||
ModTime: time.Unix(1360578951, 0),
|
ModTime: time.Unix(1360578951, 0),
|
||||||
Typeflag: TypeChar,
|
Typeflag: TypeChar,
|
||||||
},
|
},
|
||||||
fm: 0666 | os.ModeDevice | os.ModeCharDevice,
|
fm: 0666 | fs.ModeDevice | fs.ModeCharDevice,
|
||||||
}, {
|
}, {
|
||||||
// block device node.
|
// block device node.
|
||||||
h: &Header{
|
h: &Header{
|
||||||
@ -381,7 +381,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
|||||||
ModTime: time.Unix(1360578954, 0),
|
ModTime: time.Unix(1360578954, 0),
|
||||||
Typeflag: TypeBlock,
|
Typeflag: TypeBlock,
|
||||||
},
|
},
|
||||||
fm: 0660 | os.ModeDevice,
|
fm: 0660 | fs.ModeDevice,
|
||||||
}, {
|
}, {
|
||||||
// directory.
|
// directory.
|
||||||
h: &Header{
|
h: &Header{
|
||||||
@ -391,7 +391,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
|||||||
ModTime: time.Unix(1360601116, 0),
|
ModTime: time.Unix(1360601116, 0),
|
||||||
Typeflag: TypeDir,
|
Typeflag: TypeDir,
|
||||||
},
|
},
|
||||||
fm: 0755 | os.ModeDir,
|
fm: 0755 | fs.ModeDir,
|
||||||
}, {
|
}, {
|
||||||
// fifo node.
|
// fifo node.
|
||||||
h: &Header{
|
h: &Header{
|
||||||
@ -401,7 +401,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
|||||||
ModTime: time.Unix(1360578949, 0),
|
ModTime: time.Unix(1360578949, 0),
|
||||||
Typeflag: TypeFifo,
|
Typeflag: TypeFifo,
|
||||||
},
|
},
|
||||||
fm: 0600 | os.ModeNamedPipe,
|
fm: 0600 | fs.ModeNamedPipe,
|
||||||
}, {
|
}, {
|
||||||
// setuid.
|
// setuid.
|
||||||
h: &Header{
|
h: &Header{
|
||||||
@ -411,7 +411,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
|||||||
ModTime: time.Unix(1355405093, 0),
|
ModTime: time.Unix(1355405093, 0),
|
||||||
Typeflag: TypeReg,
|
Typeflag: TypeReg,
|
||||||
},
|
},
|
||||||
fm: 0755 | os.ModeSetuid,
|
fm: 0755 | fs.ModeSetuid,
|
||||||
}, {
|
}, {
|
||||||
// setguid.
|
// setguid.
|
||||||
h: &Header{
|
h: &Header{
|
||||||
@ -421,7 +421,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
|||||||
ModTime: time.Unix(1360602346, 0),
|
ModTime: time.Unix(1360602346, 0),
|
||||||
Typeflag: TypeReg,
|
Typeflag: TypeReg,
|
||||||
},
|
},
|
||||||
fm: 0750 | os.ModeSetgid,
|
fm: 0750 | fs.ModeSetgid,
|
||||||
}, {
|
}, {
|
||||||
// sticky.
|
// sticky.
|
||||||
h: &Header{
|
h: &Header{
|
||||||
@ -431,7 +431,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
|||||||
ModTime: time.Unix(1360602540, 0),
|
ModTime: time.Unix(1360602540, 0),
|
||||||
Typeflag: TypeReg,
|
Typeflag: TypeReg,
|
||||||
},
|
},
|
||||||
fm: 0600 | os.ModeSticky,
|
fm: 0600 | fs.ModeSticky,
|
||||||
}, {
|
}, {
|
||||||
// hard link.
|
// hard link.
|
||||||
h: &Header{
|
h: &Header{
|
||||||
@ -804,9 +804,9 @@ func Benchmark(b *testing.B) {
|
|||||||
b.Run(v.label, func(b *testing.B) {
|
b.Run(v.label, func(b *testing.B) {
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
// Writing to ioutil.Discard because we want to
|
// Writing to io.Discard because we want to
|
||||||
// test purely the writer code and not bring in disk performance into this.
|
// test purely the writer code and not bring in disk performance into this.
|
||||||
tw := NewWriter(ioutil.Discard)
|
tw := NewWriter(io.Discard)
|
||||||
for _, file := range v.files {
|
for _, file := range v.files {
|
||||||
if err := tw.WriteHeader(file.hdr); err != nil {
|
if err := tw.WriteHeader(file.hdr); err != nil {
|
||||||
b.Errorf("unexpected WriteHeader error: %v", err)
|
b.Errorf("unexpected WriteHeader error: %v", err)
|
||||||
@ -844,7 +844,7 @@ func Benchmark(b *testing.B) {
|
|||||||
if _, err := tr.Next(); err != nil {
|
if _, err := tr.Next(); err != nil {
|
||||||
b.Errorf("unexpected Next error: %v", err)
|
b.Errorf("unexpected Next error: %v", err)
|
||||||
}
|
}
|
||||||
if _, err := io.Copy(ioutil.Discard, tr); err != nil {
|
if _, err := io.Copy(io.Discard, tr); err != nil {
|
||||||
b.Errorf("unexpected Copy error : %v", err)
|
b.Errorf("unexpected Copy error : %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"reflect"
|
"reflect"
|
||||||
@ -520,7 +519,7 @@ func TestWriter(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if v.file != "" {
|
if v.file != "" {
|
||||||
want, err := ioutil.ReadFile(v.file)
|
want, err := os.ReadFile(v.file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("ReadFile() = %v, want nil", err)
|
t.Fatalf("ReadFile() = %v, want nil", err)
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,12 @@ import (
|
|||||||
"hash"
|
"hash"
|
||||||
"hash/crc32"
|
"hash/crc32"
|
||||||
"io"
|
"io"
|
||||||
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -21,18 +26,28 @@ var (
|
|||||||
ErrChecksum = errors.New("zip: checksum error")
|
ErrChecksum = errors.New("zip: checksum error")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// A Reader serves content from a ZIP archive.
|
||||||
type Reader struct {
|
type Reader struct {
|
||||||
r io.ReaderAt
|
r io.ReaderAt
|
||||||
File []*File
|
File []*File
|
||||||
Comment string
|
Comment string
|
||||||
decompressors map[uint16]Decompressor
|
decompressors map[uint16]Decompressor
|
||||||
|
|
||||||
|
// fileList is a list of files sorted by ename,
|
||||||
|
// for use by the Open method.
|
||||||
|
fileListOnce sync.Once
|
||||||
|
fileList []fileListEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A ReadCloser is a Reader that must be closed when no longer needed.
|
||||||
type ReadCloser struct {
|
type ReadCloser struct {
|
||||||
f *os.File
|
f *os.File
|
||||||
Reader
|
Reader
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A File is a single file in a ZIP archive.
|
||||||
|
// The file information is in the embedded FileHeader.
|
||||||
|
// The file content can be accessed by calling Open.
|
||||||
type File struct {
|
type File struct {
|
||||||
FileHeader
|
FileHeader
|
||||||
zip *Reader
|
zip *Reader
|
||||||
@ -187,6 +202,10 @@ type checksumReader struct {
|
|||||||
err error // sticky error
|
err error // sticky error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *checksumReader) Stat() (fs.FileInfo, error) {
|
||||||
|
return headerFileInfo{&r.f.FileHeader}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *checksumReader) Read(b []byte) (n int, err error) {
|
func (r *checksumReader) Read(b []byte) (n int, err error) {
|
||||||
if r.err != nil {
|
if r.err != nil {
|
||||||
return 0, r.err
|
return 0, r.err
|
||||||
@ -607,3 +626,173 @@ func (b *readBuf) sub(n int) readBuf {
|
|||||||
*b = (*b)[n:]
|
*b = (*b)[n:]
|
||||||
return b2
|
return b2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A fileListEntry is a File and its ename.
|
||||||
|
// If file == nil, the fileListEntry describes a directory, without metadata.
|
||||||
|
type fileListEntry struct {
|
||||||
|
name string
|
||||||
|
file *File // nil for directories
|
||||||
|
}
|
||||||
|
|
||||||
|
type fileInfoDirEntry interface {
|
||||||
|
fs.FileInfo
|
||||||
|
fs.DirEntry
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *fileListEntry) stat() fileInfoDirEntry {
|
||||||
|
if e.file != nil {
|
||||||
|
return headerFileInfo{&e.file.FileHeader}
|
||||||
|
}
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only used for directories.
|
||||||
|
func (f *fileListEntry) Name() string { _, elem, _ := split(f.name); return elem }
|
||||||
|
func (f *fileListEntry) Size() int64 { return 0 }
|
||||||
|
func (f *fileListEntry) ModTime() time.Time { return time.Time{} }
|
||||||
|
func (f *fileListEntry) Mode() fs.FileMode { return fs.ModeDir | 0555 }
|
||||||
|
func (f *fileListEntry) Type() fs.FileMode { return fs.ModeDir }
|
||||||
|
func (f *fileListEntry) IsDir() bool { return true }
|
||||||
|
func (f *fileListEntry) Sys() interface{} { return nil }
|
||||||
|
|
||||||
|
func (f *fileListEntry) Info() (fs.FileInfo, error) { return f, nil }
|
||||||
|
|
||||||
|
// toValidName coerces name to be a valid name for fs.FS.Open.
|
||||||
|
func toValidName(name string) string {
|
||||||
|
name = strings.ReplaceAll(name, `\`, `/`)
|
||||||
|
p := path.Clean(name)
|
||||||
|
if strings.HasPrefix(p, "/") {
|
||||||
|
p = p[len("/"):]
|
||||||
|
}
|
||||||
|
for strings.HasPrefix(name, "../") {
|
||||||
|
p = p[len("../"):]
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Reader) initFileList() {
|
||||||
|
r.fileListOnce.Do(func() {
|
||||||
|
dirs := make(map[string]bool)
|
||||||
|
for _, file := range r.File {
|
||||||
|
name := toValidName(file.Name)
|
||||||
|
for dir := path.Dir(name); dir != "."; dir = path.Dir(dir) {
|
||||||
|
dirs[dir] = true
|
||||||
|
}
|
||||||
|
r.fileList = append(r.fileList, fileListEntry{name, file})
|
||||||
|
}
|
||||||
|
for dir := range dirs {
|
||||||
|
r.fileList = append(r.fileList, fileListEntry{dir + "/", nil})
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(r.fileList, func(i, j int) bool { return fileEntryLess(r.fileList[i].name, r.fileList[j].name) })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func fileEntryLess(x, y string) bool {
|
||||||
|
xdir, xelem, _ := split(x)
|
||||||
|
ydir, yelem, _ := split(y)
|
||||||
|
return xdir < ydir || xdir == ydir && xelem < yelem
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open opens the named file in the ZIP archive,
|
||||||
|
// using the semantics of fs.FS.Open:
|
||||||
|
// paths are always slash separated, with no
|
||||||
|
// leading / or ../ elements.
|
||||||
|
func (r *Reader) Open(name string) (fs.File, error) {
|
||||||
|
r.initFileList()
|
||||||
|
|
||||||
|
e := r.openLookup(name)
|
||||||
|
if e == nil || !fs.ValidPath(name) {
|
||||||
|
return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrNotExist}
|
||||||
|
}
|
||||||
|
if e.file == nil || strings.HasSuffix(e.file.Name, "/") {
|
||||||
|
return &openDir{e, r.openReadDir(name), 0}, nil
|
||||||
|
}
|
||||||
|
rc, err := e.file.Open()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return rc.(fs.File), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func split(name string) (dir, elem string, isDir bool) {
|
||||||
|
if name[len(name)-1] == '/' {
|
||||||
|
isDir = true
|
||||||
|
name = name[:len(name)-1]
|
||||||
|
}
|
||||||
|
i := len(name) - 1
|
||||||
|
for i >= 0 && name[i] != '/' {
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
if i < 0 {
|
||||||
|
return ".", name, isDir
|
||||||
|
}
|
||||||
|
return name[:i], name[i+1:], isDir
|
||||||
|
}
|
||||||
|
|
||||||
|
var dotFile = &fileListEntry{name: "./"}
|
||||||
|
|
||||||
|
func (r *Reader) openLookup(name string) *fileListEntry {
|
||||||
|
if name == "." {
|
||||||
|
return dotFile
|
||||||
|
}
|
||||||
|
|
||||||
|
dir, elem, _ := split(name)
|
||||||
|
files := r.fileList
|
||||||
|
i := sort.Search(len(files), func(i int) bool {
|
||||||
|
idir, ielem, _ := split(files[i].name)
|
||||||
|
return idir > dir || idir == dir && ielem >= elem
|
||||||
|
})
|
||||||
|
if i < len(files) {
|
||||||
|
fname := files[i].name
|
||||||
|
if fname == name || len(fname) == len(name)+1 && fname[len(name)] == '/' && fname[:len(name)] == name {
|
||||||
|
return &files[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Reader) openReadDir(dir string) []fileListEntry {
|
||||||
|
files := r.fileList
|
||||||
|
i := sort.Search(len(files), func(i int) bool {
|
||||||
|
idir, _, _ := split(files[i].name)
|
||||||
|
return idir >= dir
|
||||||
|
})
|
||||||
|
j := sort.Search(len(files), func(j int) bool {
|
||||||
|
jdir, _, _ := split(files[j].name)
|
||||||
|
return jdir > dir
|
||||||
|
})
|
||||||
|
return files[i:j]
|
||||||
|
}
|
||||||
|
|
||||||
|
type openDir struct {
|
||||||
|
e *fileListEntry
|
||||||
|
files []fileListEntry
|
||||||
|
offset int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *openDir) Close() error { return nil }
|
||||||
|
func (d *openDir) Stat() (fs.FileInfo, error) { return d.e.stat(), nil }
|
||||||
|
|
||||||
|
func (d *openDir) Read([]byte) (int, error) {
|
||||||
|
return 0, &fs.PathError{Op: "read", Path: d.e.name, Err: errors.New("is a directory")}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *openDir) ReadDir(count int) ([]fs.DirEntry, error) {
|
||||||
|
n := len(d.files) - d.offset
|
||||||
|
if count > 0 && n > count {
|
||||||
|
n = count
|
||||||
|
}
|
||||||
|
if n == 0 {
|
||||||
|
if count <= 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, io.EOF
|
||||||
|
}
|
||||||
|
list := make([]fs.DirEntry, n)
|
||||||
|
for i := range list {
|
||||||
|
list[i] = d.files[d.offset+i].stat()
|
||||||
|
}
|
||||||
|
d.offset += n
|
||||||
|
return list, nil
|
||||||
|
}
|
||||||
|
@ -10,12 +10,13 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"internal/obscuretestdata"
|
"internal/obscuretestdata"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"testing/fstest"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -30,7 +31,7 @@ type ZipTest struct {
|
|||||||
|
|
||||||
type ZipTestFile struct {
|
type ZipTestFile struct {
|
||||||
Name string
|
Name string
|
||||||
Mode os.FileMode
|
Mode fs.FileMode
|
||||||
NonUTF8 bool
|
NonUTF8 bool
|
||||||
ModTime time.Time
|
ModTime time.Time
|
||||||
Modified time.Time
|
Modified time.Time
|
||||||
@ -107,7 +108,7 @@ var tests = []ZipTest{
|
|||||||
Name: "symlink",
|
Name: "symlink",
|
||||||
Content: []byte("../target"),
|
Content: []byte("../target"),
|
||||||
Modified: time.Date(2012, 2, 3, 19, 56, 48, 0, timeZone(-2*time.Hour)),
|
Modified: time.Date(2012, 2, 3, 19, 56, 48, 0, timeZone(-2*time.Hour)),
|
||||||
Mode: 0777 | os.ModeSymlink,
|
Mode: 0777 | fs.ModeSymlink,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -149,7 +150,7 @@ var tests = []ZipTest{
|
|||||||
Name: "dir/empty/",
|
Name: "dir/empty/",
|
||||||
Content: []byte{},
|
Content: []byte{},
|
||||||
Modified: time.Date(2011, 12, 8, 10, 8, 6, 0, time.UTC),
|
Modified: time.Date(2011, 12, 8, 10, 8, 6, 0, time.UTC),
|
||||||
Mode: os.ModeDir | 0777,
|
Mode: fs.ModeDir | 0777,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "readonly",
|
Name: "readonly",
|
||||||
@ -179,7 +180,7 @@ var tests = []ZipTest{
|
|||||||
Name: "dir/empty/",
|
Name: "dir/empty/",
|
||||||
Content: []byte{},
|
Content: []byte{},
|
||||||
Modified: time.Date(2011, 12, 8, 10, 8, 6, 0, timeZone(0)),
|
Modified: time.Date(2011, 12, 8, 10, 8, 6, 0, timeZone(0)),
|
||||||
Mode: os.ModeDir | 0777,
|
Mode: fs.ModeDir | 0777,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "readonly",
|
Name: "readonly",
|
||||||
@ -627,7 +628,7 @@ func readTestFile(t *testing.T, zt ZipTest, ft ZipTestFile, f *File) {
|
|||||||
var c []byte
|
var c []byte
|
||||||
if ft.Content != nil {
|
if ft.Content != nil {
|
||||||
c = ft.Content
|
c = ft.Content
|
||||||
} else if c, err = ioutil.ReadFile("testdata/" + ft.File); err != nil {
|
} else if c, err = os.ReadFile("testdata/" + ft.File); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -645,7 +646,7 @@ func readTestFile(t *testing.T, zt ZipTest, ft ZipTestFile, f *File) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testFileMode(t *testing.T, f *File, want os.FileMode) {
|
func testFileMode(t *testing.T, f *File, want fs.FileMode) {
|
||||||
mode := f.Mode()
|
mode := f.Mode()
|
||||||
if want == 0 {
|
if want == 0 {
|
||||||
t.Errorf("%s mode: got %v, want none", f.Name, mode)
|
t.Errorf("%s mode: got %v, want none", f.Name, mode)
|
||||||
@ -683,7 +684,7 @@ func TestInvalidFiles(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func messWith(fileName string, corrupter func(b []byte)) (r io.ReaderAt, size int64) {
|
func messWith(fileName string, corrupter func(b []byte)) (r io.ReaderAt, size int64) {
|
||||||
data, err := ioutil.ReadFile(filepath.Join("testdata", fileName))
|
data, err := os.ReadFile(filepath.Join("testdata", fileName))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("Error reading " + fileName + ": " + err.Error())
|
panic("Error reading " + fileName + ": " + err.Error())
|
||||||
}
|
}
|
||||||
@ -790,17 +791,17 @@ func returnRecursiveZip() (r io.ReaderAt, size int64) {
|
|||||||
//
|
//
|
||||||
// func main() {
|
// func main() {
|
||||||
// bigZip := makeZip("big.file", io.LimitReader(zeros{}, 1<<32-1))
|
// bigZip := makeZip("big.file", io.LimitReader(zeros{}, 1<<32-1))
|
||||||
// if err := ioutil.WriteFile("/tmp/big.zip", bigZip, 0666); err != nil {
|
// if err := os.WriteFile("/tmp/big.zip", bigZip, 0666); err != nil {
|
||||||
// log.Fatal(err)
|
// log.Fatal(err)
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// biggerZip := makeZip("big.zip", bytes.NewReader(bigZip))
|
// biggerZip := makeZip("big.zip", bytes.NewReader(bigZip))
|
||||||
// if err := ioutil.WriteFile("/tmp/bigger.zip", biggerZip, 0666); err != nil {
|
// if err := os.WriteFile("/tmp/bigger.zip", biggerZip, 0666); err != nil {
|
||||||
// log.Fatal(err)
|
// log.Fatal(err)
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// biggestZip := makeZip("bigger.zip", bytes.NewReader(biggerZip))
|
// biggestZip := makeZip("bigger.zip", bytes.NewReader(biggerZip))
|
||||||
// if err := ioutil.WriteFile("/tmp/biggest.zip", biggestZip, 0666); err != nil {
|
// if err := os.WriteFile("/tmp/biggest.zip", biggestZip, 0666); err != nil {
|
||||||
// log.Fatal(err)
|
// log.Fatal(err)
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
@ -928,7 +929,7 @@ func returnBigZipBytes() (r io.ReaderAt, size int64) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
b, err = ioutil.ReadAll(f)
|
b, err = io.ReadAll(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -985,7 +986,7 @@ func TestIssue10957(t *testing.T) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if f.UncompressedSize64 < 1e6 {
|
if f.UncompressedSize64 < 1e6 {
|
||||||
n, err := io.Copy(ioutil.Discard, r)
|
n, err := io.Copy(io.Discard, r)
|
||||||
if i == 3 && err != io.ErrUnexpectedEOF {
|
if i == 3 && err != io.ErrUnexpectedEOF {
|
||||||
t.Errorf("File[3] error = %v; want io.ErrUnexpectedEOF", err)
|
t.Errorf("File[3] error = %v; want io.ErrUnexpectedEOF", err)
|
||||||
}
|
}
|
||||||
@ -1027,7 +1028,7 @@ func TestIssue11146(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
_, err = ioutil.ReadAll(r)
|
_, err = io.ReadAll(r)
|
||||||
if err != io.ErrUnexpectedEOF {
|
if err != io.ErrUnexpectedEOF {
|
||||||
t.Errorf("File[0] error = %v; want io.ErrUnexpectedEOF", err)
|
t.Errorf("File[0] error = %v; want io.ErrUnexpectedEOF", err)
|
||||||
}
|
}
|
||||||
@ -1070,3 +1071,13 @@ func TestIssue12449(t *testing.T) {
|
|||||||
t.Errorf("Error reading the archive: %v", err)
|
t.Errorf("Error reading the archive: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFS(t *testing.T) {
|
||||||
|
z, err := OpenReader("testdata/unix.zip")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := fstest.TestFS(z, "hello", "dir/bar", "dir/empty", "readonly"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
"compress/flate"
|
"compress/flate"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -111,7 +110,7 @@ func init() {
|
|||||||
compressors.Store(Store, Compressor(func(w io.Writer) (io.WriteCloser, error) { return &nopCloser{w}, nil }))
|
compressors.Store(Store, Compressor(func(w io.Writer) (io.WriteCloser, error) { return &nopCloser{w}, nil }))
|
||||||
compressors.Store(Deflate, Compressor(func(w io.Writer) (io.WriteCloser, error) { return newFlateWriter(w), nil }))
|
compressors.Store(Deflate, Compressor(func(w io.Writer) (io.WriteCloser, error) { return newFlateWriter(w), nil }))
|
||||||
|
|
||||||
decompressors.Store(Store, Decompressor(ioutil.NopCloser))
|
decompressors.Store(Store, Decompressor(io.NopCloser))
|
||||||
decompressors.Store(Deflate, Decompressor(newFlateReader))
|
decompressors.Store(Deflate, Decompressor(newFlateReader))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ fields must be used instead.
|
|||||||
package zip
|
package zip
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"io/fs"
|
||||||
"path"
|
"path"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -137,12 +137,12 @@ type FileHeader struct {
|
|||||||
ExternalAttrs uint32 // Meaning depends on CreatorVersion
|
ExternalAttrs uint32 // Meaning depends on CreatorVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileInfo returns an os.FileInfo for the FileHeader.
|
// FileInfo returns an fs.FileInfo for the FileHeader.
|
||||||
func (h *FileHeader) FileInfo() os.FileInfo {
|
func (h *FileHeader) FileInfo() fs.FileInfo {
|
||||||
return headerFileInfo{h}
|
return headerFileInfo{h}
|
||||||
}
|
}
|
||||||
|
|
||||||
// headerFileInfo implements os.FileInfo.
|
// headerFileInfo implements fs.FileInfo.
|
||||||
type headerFileInfo struct {
|
type headerFileInfo struct {
|
||||||
fh *FileHeader
|
fh *FileHeader
|
||||||
}
|
}
|
||||||
@ -161,17 +161,20 @@ func (fi headerFileInfo) ModTime() time.Time {
|
|||||||
}
|
}
|
||||||
return fi.fh.Modified.UTC()
|
return fi.fh.Modified.UTC()
|
||||||
}
|
}
|
||||||
func (fi headerFileInfo) Mode() os.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) Sys() interface{} { return fi.fh }
|
func (fi headerFileInfo) Sys() interface{} { return fi.fh }
|
||||||
|
|
||||||
|
func (fi headerFileInfo) Info() (fs.FileInfo, error) { return fi, nil }
|
||||||
|
|
||||||
// FileInfoHeader creates a partially-populated FileHeader from an
|
// FileInfoHeader creates a partially-populated FileHeader from an
|
||||||
// os.FileInfo.
|
// fs.FileInfo.
|
||||||
// Because os.FileInfo's Name method returns only the base name of
|
// Because fs.FileInfo's Name method returns only the base name of
|
||||||
// the file it describes, it may be necessary to modify the Name field
|
// the file it describes, it may be necessary to modify the Name field
|
||||||
// of the returned header to provide the full path name of the file.
|
// of the returned header to provide the full path name of the file.
|
||||||
// If compression is desired, callers should set the FileHeader.Method
|
// If compression is desired, callers should set the FileHeader.Method
|
||||||
// field; it is unset by default.
|
// field; it is unset by default.
|
||||||
func FileInfoHeader(fi os.FileInfo) (*FileHeader, error) {
|
func FileInfoHeader(fi fs.FileInfo) (*FileHeader, error) {
|
||||||
size := fi.Size()
|
size := fi.Size()
|
||||||
fh := &FileHeader{
|
fh := &FileHeader{
|
||||||
Name: fi.Name(),
|
Name: fi.Name(),
|
||||||
@ -280,7 +283,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Mode returns the permission and mode bits for the FileHeader.
|
// Mode returns the permission and mode bits for the FileHeader.
|
||||||
func (h *FileHeader) Mode() (mode os.FileMode) {
|
func (h *FileHeader) Mode() (mode fs.FileMode) {
|
||||||
switch h.CreatorVersion >> 8 {
|
switch h.CreatorVersion >> 8 {
|
||||||
case creatorUnix, creatorMacOSX:
|
case creatorUnix, creatorMacOSX:
|
||||||
mode = unixModeToFileMode(h.ExternalAttrs >> 16)
|
mode = unixModeToFileMode(h.ExternalAttrs >> 16)
|
||||||
@ -288,18 +291,18 @@ func (h *FileHeader) Mode() (mode os.FileMode) {
|
|||||||
mode = msdosModeToFileMode(h.ExternalAttrs)
|
mode = msdosModeToFileMode(h.ExternalAttrs)
|
||||||
}
|
}
|
||||||
if len(h.Name) > 0 && h.Name[len(h.Name)-1] == '/' {
|
if len(h.Name) > 0 && h.Name[len(h.Name)-1] == '/' {
|
||||||
mode |= os.ModeDir
|
mode |= fs.ModeDir
|
||||||
}
|
}
|
||||||
return mode
|
return mode
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetMode changes the permission and mode bits for the FileHeader.
|
// SetMode changes the permission and mode bits for the FileHeader.
|
||||||
func (h *FileHeader) SetMode(mode os.FileMode) {
|
func (h *FileHeader) SetMode(mode fs.FileMode) {
|
||||||
h.CreatorVersion = h.CreatorVersion&0xff | creatorUnix<<8
|
h.CreatorVersion = h.CreatorVersion&0xff | creatorUnix<<8
|
||||||
h.ExternalAttrs = fileModeToUnixMode(mode) << 16
|
h.ExternalAttrs = fileModeToUnixMode(mode) << 16
|
||||||
|
|
||||||
// set MSDOS attributes too, as the original zip does.
|
// set MSDOS attributes too, as the original zip does.
|
||||||
if mode&os.ModeDir != 0 {
|
if mode&fs.ModeDir != 0 {
|
||||||
h.ExternalAttrs |= msdosDir
|
h.ExternalAttrs |= msdosDir
|
||||||
}
|
}
|
||||||
if mode&0200 == 0 {
|
if mode&0200 == 0 {
|
||||||
@ -312,9 +315,9 @@ func (h *FileHeader) isZip64() bool {
|
|||||||
return h.CompressedSize64 >= uint32max || h.UncompressedSize64 >= uint32max
|
return h.CompressedSize64 >= uint32max || h.UncompressedSize64 >= uint32max
|
||||||
}
|
}
|
||||||
|
|
||||||
func msdosModeToFileMode(m uint32) (mode os.FileMode) {
|
func msdosModeToFileMode(m uint32) (mode fs.FileMode) {
|
||||||
if m&msdosDir != 0 {
|
if m&msdosDir != 0 {
|
||||||
mode = os.ModeDir | 0777
|
mode = fs.ModeDir | 0777
|
||||||
} else {
|
} else {
|
||||||
mode = 0666
|
mode = 0666
|
||||||
}
|
}
|
||||||
@ -324,64 +327,64 @@ func msdosModeToFileMode(m uint32) (mode os.FileMode) {
|
|||||||
return mode
|
return mode
|
||||||
}
|
}
|
||||||
|
|
||||||
func fileModeToUnixMode(mode os.FileMode) uint32 {
|
func fileModeToUnixMode(mode fs.FileMode) uint32 {
|
||||||
var m uint32
|
var m uint32
|
||||||
switch mode & os.ModeType {
|
switch mode & fs.ModeType {
|
||||||
default:
|
default:
|
||||||
m = s_IFREG
|
m = s_IFREG
|
||||||
case os.ModeDir:
|
case fs.ModeDir:
|
||||||
m = s_IFDIR
|
m = s_IFDIR
|
||||||
case os.ModeSymlink:
|
case fs.ModeSymlink:
|
||||||
m = s_IFLNK
|
m = s_IFLNK
|
||||||
case os.ModeNamedPipe:
|
case fs.ModeNamedPipe:
|
||||||
m = s_IFIFO
|
m = s_IFIFO
|
||||||
case os.ModeSocket:
|
case fs.ModeSocket:
|
||||||
m = s_IFSOCK
|
m = s_IFSOCK
|
||||||
case os.ModeDevice:
|
case fs.ModeDevice:
|
||||||
if mode&os.ModeCharDevice != 0 {
|
if mode&fs.ModeCharDevice != 0 {
|
||||||
m = s_IFCHR
|
m = s_IFCHR
|
||||||
} else {
|
} else {
|
||||||
m = s_IFBLK
|
m = s_IFBLK
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if mode&os.ModeSetuid != 0 {
|
if mode&fs.ModeSetuid != 0 {
|
||||||
m |= s_ISUID
|
m |= s_ISUID
|
||||||
}
|
}
|
||||||
if mode&os.ModeSetgid != 0 {
|
if mode&fs.ModeSetgid != 0 {
|
||||||
m |= s_ISGID
|
m |= s_ISGID
|
||||||
}
|
}
|
||||||
if mode&os.ModeSticky != 0 {
|
if mode&fs.ModeSticky != 0 {
|
||||||
m |= s_ISVTX
|
m |= s_ISVTX
|
||||||
}
|
}
|
||||||
return m | uint32(mode&0777)
|
return m | uint32(mode&0777)
|
||||||
}
|
}
|
||||||
|
|
||||||
func unixModeToFileMode(m uint32) os.FileMode {
|
func unixModeToFileMode(m uint32) fs.FileMode {
|
||||||
mode := os.FileMode(m & 0777)
|
mode := fs.FileMode(m & 0777)
|
||||||
switch m & s_IFMT {
|
switch m & s_IFMT {
|
||||||
case s_IFBLK:
|
case s_IFBLK:
|
||||||
mode |= os.ModeDevice
|
mode |= fs.ModeDevice
|
||||||
case s_IFCHR:
|
case s_IFCHR:
|
||||||
mode |= os.ModeDevice | os.ModeCharDevice
|
mode |= fs.ModeDevice | fs.ModeCharDevice
|
||||||
case s_IFDIR:
|
case s_IFDIR:
|
||||||
mode |= os.ModeDir
|
mode |= fs.ModeDir
|
||||||
case s_IFIFO:
|
case s_IFIFO:
|
||||||
mode |= os.ModeNamedPipe
|
mode |= fs.ModeNamedPipe
|
||||||
case s_IFLNK:
|
case s_IFLNK:
|
||||||
mode |= os.ModeSymlink
|
mode |= fs.ModeSymlink
|
||||||
case s_IFREG:
|
case s_IFREG:
|
||||||
// nothing to do
|
// nothing to do
|
||||||
case s_IFSOCK:
|
case s_IFSOCK:
|
||||||
mode |= os.ModeSocket
|
mode |= fs.ModeSocket
|
||||||
}
|
}
|
||||||
if m&s_ISGID != 0 {
|
if m&s_ISGID != 0 {
|
||||||
mode |= os.ModeSetgid
|
mode |= fs.ModeSetgid
|
||||||
}
|
}
|
||||||
if m&s_ISUID != 0 {
|
if m&s_ISUID != 0 {
|
||||||
mode |= os.ModeSetuid
|
mode |= fs.ModeSetuid
|
||||||
}
|
}
|
||||||
if m&s_ISVTX != 0 {
|
if m&s_ISVTX != 0 {
|
||||||
mode |= os.ModeSticky
|
mode |= fs.ModeSticky
|
||||||
}
|
}
|
||||||
return mode
|
return mode
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import (
|
|||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/fs"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
@ -23,7 +23,7 @@ type WriteTest struct {
|
|||||||
Name string
|
Name string
|
||||||
Data []byte
|
Data []byte
|
||||||
Method uint16
|
Method uint16
|
||||||
Mode os.FileMode
|
Mode fs.FileMode
|
||||||
}
|
}
|
||||||
|
|
||||||
var writeTests = []WriteTest{
|
var writeTests = []WriteTest{
|
||||||
@ -43,19 +43,19 @@ var writeTests = []WriteTest{
|
|||||||
Name: "setuid",
|
Name: "setuid",
|
||||||
Data: []byte("setuid file"),
|
Data: []byte("setuid file"),
|
||||||
Method: Deflate,
|
Method: Deflate,
|
||||||
Mode: 0755 | os.ModeSetuid,
|
Mode: 0755 | fs.ModeSetuid,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "setgid",
|
Name: "setgid",
|
||||||
Data: []byte("setgid file"),
|
Data: []byte("setgid file"),
|
||||||
Method: Deflate,
|
Method: Deflate,
|
||||||
Mode: 0755 | os.ModeSetgid,
|
Mode: 0755 | fs.ModeSetgid,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "symlink",
|
Name: "symlink",
|
||||||
Data: []byte("../link/target"),
|
Data: []byte("../link/target"),
|
||||||
Method: Deflate,
|
Method: Deflate,
|
||||||
Mode: 0755 | os.ModeSymlink,
|
Mode: 0755 | fs.ModeSymlink,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,7 +237,7 @@ func TestWriterTime(t *testing.T) {
|
|||||||
t.Fatalf("unexpected Close error: %v", err)
|
t.Fatalf("unexpected Close error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
want, err := ioutil.ReadFile("testdata/time-go.zip")
|
want, err := os.ReadFile("testdata/time-go.zip")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected ReadFile error: %v", err)
|
t.Fatalf("unexpected ReadFile error: %v", err)
|
||||||
}
|
}
|
||||||
@ -301,7 +301,7 @@ func TestWriterFlush(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestWriterDir(t *testing.T) {
|
func TestWriterDir(t *testing.T) {
|
||||||
w := NewWriter(ioutil.Discard)
|
w := NewWriter(io.Discard)
|
||||||
dw, err := w.Create("dir/")
|
dw, err := w.Create("dir/")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -380,7 +380,7 @@ func testReadFile(t *testing.T, f *File, wt *WriteTest) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("opening:", err)
|
t.Fatal("opening:", err)
|
||||||
}
|
}
|
||||||
b, err := ioutil.ReadAll(rc)
|
b, err := io.ReadAll(rc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("reading:", err)
|
t.Fatal("reading:", err)
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@ import (
|
|||||||
"hash"
|
"hash"
|
||||||
"internal/testenv"
|
"internal/testenv"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
@ -620,7 +619,7 @@ func testZip64(t testing.TB, size int64) *rleBuffer {
|
|||||||
t.Fatal("read:", err)
|
t.Fatal("read:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gotEnd, err := ioutil.ReadAll(rc)
|
gotEnd, err := io.ReadAll(rc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("read end:", err)
|
t.Fatal("read end:", err)
|
||||||
}
|
}
|
||||||
|
@ -425,7 +425,7 @@ func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error) {
|
|||||||
// of bytes in the combined first two elements, error).
|
// of bytes in the combined first two elements, error).
|
||||||
// The complete result is equal to
|
// The complete result is equal to
|
||||||
// `bytes.Join(append(fullBuffers, finalFragment), nil)`, which has a
|
// `bytes.Join(append(fullBuffers, finalFragment), nil)`, which has a
|
||||||
// length of `totalLen`. The result is strucured in this way to allow callers
|
// length of `totalLen`. The result is structured in this way to allow callers
|
||||||
// to minimize allocations and copies.
|
// to minimize allocations and copies.
|
||||||
func (b *Reader) collectFragments(delim byte) (fullBuffers [][]byte, finalFragment []byte, totalLen int, err error) {
|
func (b *Reader) collectFragments(delim byte) (fullBuffers [][]byte, finalFragment []byte, totalLen int, err error) {
|
||||||
var frag []byte
|
var frag []byte
|
||||||
|
@ -10,7 +10,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"testing/iotest"
|
"testing/iotest"
|
||||||
@ -147,7 +146,7 @@ func TestReader(t *testing.T) {
|
|||||||
for i := 0; i < len(texts)-1; i++ {
|
for i := 0; i < len(texts)-1; i++ {
|
||||||
texts[i] = str + "\n"
|
texts[i] = str + "\n"
|
||||||
all += texts[i]
|
all += texts[i]
|
||||||
str += string(rune(i)%26 + 'a')
|
str += string(rune(i%26 + 'a'))
|
||||||
}
|
}
|
||||||
texts[len(texts)-1] = all
|
texts[len(texts)-1] = all
|
||||||
|
|
||||||
@ -886,7 +885,7 @@ func TestReadEmptyBuffer(t *testing.T) {
|
|||||||
|
|
||||||
func TestLinesAfterRead(t *testing.T) {
|
func TestLinesAfterRead(t *testing.T) {
|
||||||
l := NewReaderSize(bytes.NewReader([]byte("foo")), minReadBufferSize)
|
l := NewReaderSize(bytes.NewReader([]byte("foo")), minReadBufferSize)
|
||||||
_, err := ioutil.ReadAll(l)
|
_, err := io.ReadAll(l)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
@ -1130,7 +1129,7 @@ func TestWriterReadFromCounts(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A writeCountingDiscard is like ioutil.Discard and counts the number of times
|
// A writeCountingDiscard is like io.Discard and counts the number of times
|
||||||
// Write is called on it.
|
// Write is called on it.
|
||||||
type writeCountingDiscard int
|
type writeCountingDiscard int
|
||||||
|
|
||||||
@ -1300,7 +1299,7 @@ func TestReaderReset(t *testing.T) {
|
|||||||
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 := ioutil.ReadAll(r)
|
all, err := io.ReadAll(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -1645,13 +1644,13 @@ func BenchmarkReaderWriteToOptimal(b *testing.B) {
|
|||||||
buf := make([]byte, bufSize)
|
buf := make([]byte, bufSize)
|
||||||
r := bytes.NewReader(buf)
|
r := bytes.NewReader(buf)
|
||||||
srcReader := NewReaderSize(onlyReader{r}, 1<<10)
|
srcReader := NewReaderSize(onlyReader{r}, 1<<10)
|
||||||
if _, ok := ioutil.Discard.(io.ReaderFrom); !ok {
|
if _, ok := io.Discard.(io.ReaderFrom); !ok {
|
||||||
b.Fatal("ioutil.Discard doesn't support ReaderFrom")
|
b.Fatal("io.Discard doesn't support ReaderFrom")
|
||||||
}
|
}
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
r.Seek(0, io.SeekStart)
|
r.Seek(0, io.SeekStart)
|
||||||
srcReader.Reset(onlyReader{r})
|
srcReader.Reset(onlyReader{r})
|
||||||
n, err := srcReader.WriteTo(ioutil.Discard)
|
n, err := srcReader.WriteTo(io.Discard)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -1722,7 +1721,7 @@ func BenchmarkReaderEmpty(b *testing.B) {
|
|||||||
str := strings.Repeat("x", 16<<10)
|
str := strings.Repeat("x", 16<<10)
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
br := NewReader(strings.NewReader(str))
|
br := NewReader(strings.NewReader(str))
|
||||||
n, err := io.Copy(ioutil.Discard, br)
|
n, err := io.Copy(io.Discard, br)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -1737,7 +1736,7 @@ func BenchmarkWriterEmpty(b *testing.B) {
|
|||||||
str := strings.Repeat("x", 1<<10)
|
str := strings.Repeat("x", 1<<10)
|
||||||
bs := []byte(str)
|
bs := []byte(str)
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
bw := NewWriter(ioutil.Discard)
|
bw := NewWriter(io.Discard)
|
||||||
bw.Flush()
|
bw.Flush()
|
||||||
bw.WriteByte('a')
|
bw.WriteByte('a')
|
||||||
bw.Flush()
|
bw.Flush()
|
||||||
@ -1752,7 +1751,7 @@ func BenchmarkWriterEmpty(b *testing.B) {
|
|||||||
|
|
||||||
func BenchmarkWriterFlush(b *testing.B) {
|
func BenchmarkWriterFlush(b *testing.B) {
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
bw := NewWriter(ioutil.Discard)
|
bw := NewWriter(io.Discard)
|
||||||
str := strings.Repeat("x", 50)
|
str := strings.Repeat("x", 50)
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
bw.WriteString(str)
|
bw.WriteString(str)
|
||||||
|
@ -30,6 +30,13 @@ func ExampleBuffer_reader() {
|
|||||||
// Output: Gophers rule!
|
// Output: Gophers rule!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleBuffer_Bytes() {
|
||||||
|
buf := bytes.Buffer{}
|
||||||
|
buf.Write([]byte{'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'})
|
||||||
|
os.Stdout.Write(buf.Bytes())
|
||||||
|
// Output: hello world
|
||||||
|
}
|
||||||
|
|
||||||
func ExampleBuffer_Grow() {
|
func ExampleBuffer_Grow() {
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
b.Grow(64)
|
b.Grow(64)
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
. "bytes"
|
. "bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
@ -235,7 +234,7 @@ func TestReaderCopyNothing(t *testing.T) {
|
|||||||
type justWriter struct {
|
type justWriter struct {
|
||||||
io.Writer
|
io.Writer
|
||||||
}
|
}
|
||||||
discard := justWriter{ioutil.Discard} // hide ReadFrom
|
discard := justWriter{io.Discard} // hide ReadFrom
|
||||||
|
|
||||||
var with, withOut nErr
|
var with, withOut nErr
|
||||||
with.n, with.err = io.Copy(discard, NewReader(nil))
|
with.n, with.err = io.Copy(discard, NewReader(nil))
|
||||||
@ -248,7 +247,7 @@ func TestReaderCopyNothing(t *testing.T) {
|
|||||||
// tests that Len is affected by reads, but Size is not.
|
// tests that Len is affected by reads, but Size is not.
|
||||||
func TestReaderLenSize(t *testing.T) {
|
func TestReaderLenSize(t *testing.T) {
|
||||||
r := NewReader([]byte("abc"))
|
r := NewReader([]byte("abc"))
|
||||||
io.CopyN(ioutil.Discard, r, 1)
|
io.CopyN(io.Discard, r, 1)
|
||||||
if r.Len() != 2 {
|
if r.Len() != 2 {
|
||||||
t.Errorf("Len = %d; want 2", r.Len())
|
t.Errorf("Len = %d; want 2", r.Len())
|
||||||
}
|
}
|
||||||
@ -268,7 +267,7 @@ func TestReaderReset(t *testing.T) {
|
|||||||
if err := r.UnreadRune(); err == nil {
|
if err := r.UnreadRune(); err == nil {
|
||||||
t.Errorf("UnreadRune: expected error, got nil")
|
t.Errorf("UnreadRune: expected error, got nil")
|
||||||
}
|
}
|
||||||
buf, err := ioutil.ReadAll(r)
|
buf, err := io.ReadAll(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("ReadAll: unexpected error: %v", err)
|
t.Errorf("ReadAll: unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
@ -314,7 +313,7 @@ func TestReaderZero(t *testing.T) {
|
|||||||
t.Errorf("UnreadRune: got nil, want error")
|
t.Errorf("UnreadRune: got nil, want error")
|
||||||
}
|
}
|
||||||
|
|
||||||
if n, err := (&Reader{}).WriteTo(ioutil.Discard); n != 0 || err != nil {
|
if n, err := (&Reader{}).WriteTo(io.Discard); n != 0 || err != nil {
|
||||||
t.Errorf("WriteTo: got %d, %v; want 0, nil", n, err)
|
t.Errorf("WriteTo: got %d, %v; want 0, nil", n, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,21 +22,6 @@ func usage() {
|
|||||||
|
|
||||||
var wflag = flag.Bool("w", false, "write build ID")
|
var wflag = flag.Bool("w", false, "write build ID")
|
||||||
|
|
||||||
// taken from cmd/go/internal/work/buildid.go
|
|
||||||
func hashToString(h [32]byte) string {
|
|
||||||
const b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
|
|
||||||
const chunks = 5
|
|
||||||
var dst [chunks * 4]byte
|
|
||||||
for i := 0; i < chunks; i++ {
|
|
||||||
v := uint32(h[3*i])<<16 | uint32(h[3*i+1])<<8 | uint32(h[3*i+2])
|
|
||||||
dst[4*i+0] = b64[(v>>18)&0x3F]
|
|
||||||
dst[4*i+1] = b64[(v>>12)&0x3F]
|
|
||||||
dst[4*i+2] = b64[(v>>6)&0x3F]
|
|
||||||
dst[4*i+3] = b64[v&0x3F]
|
|
||||||
}
|
|
||||||
return string(dst[:])
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
log.SetPrefix("buildid: ")
|
log.SetPrefix("buildid: ")
|
||||||
log.SetFlags(0)
|
log.SetFlags(0)
|
||||||
@ -63,12 +48,12 @@ func main() {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
matches, hash, err := buildid.FindAndHash(f, id, 0)
|
matches, hash, err := buildid.FindAndHash(f, id, 0)
|
||||||
|
f.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
f.Close()
|
|
||||||
|
|
||||||
newID := id[:strings.LastIndex(id, "/")] + "/" + hashToString(hash)
|
newID := id[:strings.LastIndex(id, "/")] + "/" + buildid.HashToString(hash)
|
||||||
if len(newID) != len(id) {
|
if len(newID) != len(id) {
|
||||||
log.Fatalf("%s: build ID length mismatch %q vs %q", file, id, newID)
|
log.Fatalf("%s: build ID length mismatch %q vs %q", file, id, newID)
|
||||||
}
|
}
|
||||||
@ -77,7 +62,7 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
f, err = os.OpenFile(file, os.O_WRONLY, 0)
|
f, err = os.OpenFile(file, os.O_RDWR, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@ import (
|
|||||||
"go/scanner"
|
"go/scanner"
|
||||||
"go/token"
|
"go/token"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -44,14 +43,7 @@ func sourceLine(n ast.Node) int {
|
|||||||
// attached to the import "C" comment, a list of references to C.xxx,
|
// attached to the import "C" comment, a list of references to C.xxx,
|
||||||
// a list of exported functions, and the actual AST, to be rewritten and
|
// a list of exported functions, and the actual AST, to be rewritten and
|
||||||
// printed.
|
// printed.
|
||||||
func (f *File) ParseGo(name string, src []byte) {
|
func (f *File) ParseGo(abspath string, src []byte) {
|
||||||
// Create absolute path for file, so that it will be used in error
|
|
||||||
// messages and recorded in debug line number information.
|
|
||||||
// This matches the rest of the toolchain. See golang.org/issue/5122.
|
|
||||||
if aname, err := filepath.Abs(name); err == nil {
|
|
||||||
name = aname
|
|
||||||
}
|
|
||||||
|
|
||||||
// Two different parses: once with comments, once without.
|
// Two different parses: once with comments, once without.
|
||||||
// The printer is not good enough at printing comments in the
|
// The printer is not good enough at printing comments in the
|
||||||
// right place when we start editing the AST behind its back,
|
// right place when we start editing the AST behind its back,
|
||||||
@ -60,8 +52,8 @@ func (f *File) ParseGo(name string, src []byte) {
|
|||||||
// and reprinting.
|
// and reprinting.
|
||||||
// In cgo mode, we ignore ast2 and just apply edits directly
|
// In cgo mode, we ignore ast2 and just apply edits directly
|
||||||
// the text behind ast1. In godefs mode we modify and print ast2.
|
// the text behind ast1. In godefs mode we modify and print ast2.
|
||||||
ast1 := parse(name, src, parser.ParseComments)
|
ast1 := parse(abspath, src, parser.ParseComments)
|
||||||
ast2 := parse(name, src, 0)
|
ast2 := parse(abspath, src, 0)
|
||||||
|
|
||||||
f.Package = ast1.Name.Name
|
f.Package = ast1.Name.Name
|
||||||
f.Name = make(map[string]*Name)
|
f.Name = make(map[string]*Name)
|
||||||
@ -88,7 +80,7 @@ func (f *File) ParseGo(name string, src []byte) {
|
|||||||
cg = d.Doc
|
cg = d.Doc
|
||||||
}
|
}
|
||||||
if cg != nil {
|
if cg != nil {
|
||||||
f.Preamble += fmt.Sprintf("#line %d %q\n", sourceLine(cg), name)
|
f.Preamble += fmt.Sprintf("#line %d %q\n", sourceLine(cg), abspath)
|
||||||
f.Preamble += commentText(cg) + "\n"
|
f.Preamble += commentText(cg) + "\n"
|
||||||
f.Preamble += "#line 1 \"cgo-generated-wrapper\"\n"
|
f.Preamble += "#line 1 \"cgo-generated-wrapper\"\n"
|
||||||
}
|
}
|
||||||
|
@ -112,6 +112,13 @@ The default C and C++ compilers may be changed by the CC and CXX
|
|||||||
environment variables, respectively; those environment variables
|
environment variables, respectively; those environment variables
|
||||||
may include command line options.
|
may include command line options.
|
||||||
|
|
||||||
|
The cgo tool will always invoke the C compiler with the source file's
|
||||||
|
directory in the include path; i.e. -I${SRCDIR} is always implied. This
|
||||||
|
means that if a header file foo/bar.h exists both in the source
|
||||||
|
directory and also in the system include directory (or some other place
|
||||||
|
specified by a -I flag), then "#include <foo/bar.h>" will always find the
|
||||||
|
local version in preference to any other version.
|
||||||
|
|
||||||
The cgo tool is enabled by default for native builds on systems where
|
The cgo tool is enabled by default for native builds on systems where
|
||||||
it is expected to work. It is disabled by default when
|
it is expected to work. It is disabled by default when
|
||||||
cross-compiling. You can control this by setting the CGO_ENABLED
|
cross-compiling. You can control this by setting the CGO_ENABLED
|
||||||
@ -714,7 +721,7 @@ linkage to the desired libraries. The main function is provided by
|
|||||||
_cgo_main.c:
|
_cgo_main.c:
|
||||||
|
|
||||||
int main() { return 0; }
|
int main() { return 0; }
|
||||||
void crosscall2(void(*fn)(void*, int, uintptr_t), void *a, int c, uintptr_t ctxt) { }
|
void crosscall2(void(*fn)(void*), void *a, int c, uintptr_t ctxt) { }
|
||||||
uintptr_t _cgo_wait_runtime_init_done(void) { return 0; }
|
uintptr_t _cgo_wait_runtime_init_done(void) { return 0; }
|
||||||
void _cgo_release_context(uintptr_t ctxt) { }
|
void _cgo_release_context(uintptr_t ctxt) { }
|
||||||
char* _cgo_topofstack(void) { return (char*)0; }
|
char* _cgo_topofstack(void) { return (char*)0; }
|
||||||
|
@ -316,7 +316,7 @@ func (p *Package) guessKinds(f *File) []*Name {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if goos == "darwin" && strings.HasSuffix(n.C, "Ref") {
|
if (goos == "darwin" || goos == "ios") && strings.HasSuffix(n.C, "Ref") {
|
||||||
// For FooRef, find out if FooGetTypeID exists.
|
// For FooRef, find out if FooGetTypeID exists.
|
||||||
s := n.C[:len(n.C)-3] + "GetTypeID"
|
s := n.C[:len(n.C)-3] + "GetTypeID"
|
||||||
n := &Name{Go: s, C: s}
|
n := &Name{Go: s, C: s}
|
||||||
@ -387,7 +387,18 @@ func (p *Package) guessKinds(f *File) []*Name {
|
|||||||
fmt.Fprintf(&b, "#line 1 \"completed\"\n"+
|
fmt.Fprintf(&b, "#line 1 \"completed\"\n"+
|
||||||
"int __cgo__1 = __cgo__2;\n")
|
"int __cgo__1 = __cgo__2;\n")
|
||||||
|
|
||||||
stderr := p.gccErrors(b.Bytes())
|
// We need to parse the output from this gcc command, so ensure that it
|
||||||
|
// doesn't have any ANSI escape sequences in it. (TERM=dumb is
|
||||||
|
// insufficient; if the user specifies CGO_CFLAGS=-fdiagnostics-color,
|
||||||
|
// GCC will ignore TERM, and GCC can also be configured at compile-time
|
||||||
|
// to ignore TERM.)
|
||||||
|
stderr := p.gccErrors(b.Bytes(), "-fdiagnostics-color=never")
|
||||||
|
if strings.Contains(stderr, "unrecognized command line option") {
|
||||||
|
// We're using an old version of GCC that doesn't understand
|
||||||
|
// -fdiagnostics-color. Those versions can't print color anyway,
|
||||||
|
// so just rerun without that option.
|
||||||
|
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", p.gccBaseCmd()[0], b.Bytes())
|
||||||
}
|
}
|
||||||
@ -1995,22 +2006,25 @@ func (p *Package) gccDefines(stdin []byte) string {
|
|||||||
// gccErrors runs gcc over the C program stdin and returns
|
// gccErrors runs gcc over the C program stdin and returns
|
||||||
// the errors that gcc prints. That is, this function expects
|
// the errors that gcc prints. That is, this function expects
|
||||||
// gcc to fail.
|
// gcc to fail.
|
||||||
func (p *Package) gccErrors(stdin []byte) string {
|
func (p *Package) gccErrors(stdin []byte, extraArgs ...string) string {
|
||||||
// TODO(rsc): require failure
|
// TODO(rsc): require failure
|
||||||
args := p.gccCmd()
|
args := p.gccCmd()
|
||||||
|
|
||||||
// Optimization options can confuse the error messages; remove them.
|
// Optimization options can confuse the error messages; remove them.
|
||||||
nargs := make([]string, 0, len(args))
|
nargs := make([]string, 0, len(args)+len(extraArgs))
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
if !strings.HasPrefix(arg, "-O") {
|
if !strings.HasPrefix(arg, "-O") {
|
||||||
nargs = append(nargs, arg)
|
nargs = append(nargs, arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Force -O0 optimization but keep the trailing "-" at the end.
|
// Force -O0 optimization and append extra arguments, but keep the
|
||||||
nargs = append(nargs, "-O0")
|
// trailing "-" at the end.
|
||||||
nl := len(nargs)
|
li := len(nargs) - 1
|
||||||
nargs[nl-2], nargs[nl-1] = nargs[nl-1], nargs[nl-2]
|
last := nargs[li]
|
||||||
|
nargs[li] = "-O0"
|
||||||
|
nargs = append(nargs, extraArgs...)
|
||||||
|
nargs = append(nargs, last)
|
||||||
|
|
||||||
if *debugGcc {
|
if *debugGcc {
|
||||||
fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(nargs, " "))
|
fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(nargs, " "))
|
||||||
@ -2856,21 +2870,11 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
|
|||||||
tgo := t.Go
|
tgo := t.Go
|
||||||
size := t.Size
|
size := t.Size
|
||||||
talign := t.Align
|
talign := t.Align
|
||||||
if f.BitSize > 0 {
|
if f.BitOffset > 0 || f.BitSize > 0 {
|
||||||
switch f.BitSize {
|
// The layout of bitfields is implementation defined,
|
||||||
case 8, 16, 32, 64:
|
// so we don't know how they correspond to Go fields
|
||||||
default:
|
// even if they are aligned at byte boundaries.
|
||||||
continue
|
continue
|
||||||
}
|
|
||||||
size = f.BitSize / 8
|
|
||||||
name := tgo.(*ast.Ident).String()
|
|
||||||
if strings.HasPrefix(name, "int") {
|
|
||||||
name = "int"
|
|
||||||
} else {
|
|
||||||
name = "uint"
|
|
||||||
}
|
|
||||||
tgo = ast.NewIdent(name + fmt.Sprint(f.BitSize))
|
|
||||||
talign = size
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if talign > 0 && f.ByteOffset%talign != 0 {
|
if talign > 0 && f.ByteOffset%talign != 0 {
|
||||||
@ -3096,7 +3100,7 @@ func (c *typeConv) badCFType(dt *dwarf.TypedefType) bool {
|
|||||||
// We identify the correct set of types as those ending in Ref and for which
|
// We identify the correct set of types as those ending in Ref and for which
|
||||||
// there exists a corresponding GetTypeID function.
|
// there exists a corresponding GetTypeID function.
|
||||||
// See comment below for details about the bad pointers.
|
// See comment below for details about the bad pointers.
|
||||||
if goos != "darwin" {
|
if goos != "darwin" && goos != "ios" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
s := dt.Name
|
s := dt.Name
|
||||||
|
@ -16,7 +16,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// godefs returns the output for -godefs mode.
|
// godefs returns the output for -godefs mode.
|
||||||
func (p *Package) godefs(f *File, srcfile string) string {
|
func (p *Package) godefs(f *File) string {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
|
||||||
fmt.Fprintf(&buf, "// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n")
|
fmt.Fprintf(&buf, "// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n")
|
||||||
|
@ -247,6 +247,8 @@ var gccgopkgpath = flag.String("gccgopkgpath", "", "-fgo-pkgpath option used wit
|
|||||||
var gccgoMangler func(string) string
|
var gccgoMangler func(string) string
|
||||||
var importRuntimeCgo = flag.Bool("import_runtime_cgo", true, "import runtime/cgo in generated code")
|
var importRuntimeCgo = flag.Bool("import_runtime_cgo", true, "import runtime/cgo in generated code")
|
||||||
var importSyscall = flag.Bool("import_syscall", true, "import syscall in generated code")
|
var importSyscall = flag.Bool("import_syscall", true, "import syscall in generated code")
|
||||||
|
var trimpath = flag.String("trimpath", "", "applies supplied rewrites or trims prefixes to recorded source file paths")
|
||||||
|
|
||||||
var goarch, goos string
|
var goarch, goos string
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -326,6 +328,13 @@ func main() {
|
|||||||
input = filepath.Join(*srcDir, input)
|
input = filepath.Join(*srcDir, input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create absolute path for file, so that it will be used in error
|
||||||
|
// messages and recorded in debug line number information.
|
||||||
|
// This matches the rest of the toolchain. See golang.org/issue/5122.
|
||||||
|
if aname, err := filepath.Abs(input); err == nil {
|
||||||
|
input = aname
|
||||||
|
}
|
||||||
|
|
||||||
b, err := ioutil.ReadFile(input)
|
b, err := ioutil.ReadFile(input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fatalf("%s", err)
|
fatalf("%s", err)
|
||||||
@ -334,6 +343,10 @@ func main() {
|
|||||||
fatalf("%s", err)
|
fatalf("%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply trimpath to the file path. The path won't be read from after this point.
|
||||||
|
input, _ = objabi.ApplyRewrites(input, *trimpath)
|
||||||
|
goFiles[i] = input
|
||||||
|
|
||||||
f := new(File)
|
f := new(File)
|
||||||
f.Edit = edit.NewBuffer(b)
|
f.Edit = edit.NewBuffer(b)
|
||||||
f.ParseGo(input, b)
|
f.ParseGo(input, b)
|
||||||
@ -371,7 +384,7 @@ func main() {
|
|||||||
p.PackagePath = f.Package
|
p.PackagePath = f.Package
|
||||||
p.Record(f)
|
p.Record(f)
|
||||||
if *godefs {
|
if *godefs {
|
||||||
os.Stdout.WriteString(p.godefs(f, input))
|
os.Stdout.WriteString(p.godefs(f))
|
||||||
} else {
|
} else {
|
||||||
p.writeOutput(f, input)
|
p.writeOutput(f, input)
|
||||||
}
|
}
|
||||||
|
@ -64,14 +64,14 @@ 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*, int, __SIZE_TYPE__), void *a, int c, __SIZE_TYPE__ ctxt) { }\n")
|
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*), void *a, int c, __SIZE_TYPE__ ctxt) { }\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) { }\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,
|
||||||
// which provides these functions. We just need a prototype.
|
// which provides these functions. We just need a prototype.
|
||||||
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int, __SIZE_TYPE__), void *a, int c, __SIZE_TYPE__ ctxt);\n")
|
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*), void *a, int c, __SIZE_TYPE__ ctxt);\n")
|
||||||
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")
|
||||||
}
|
}
|
||||||
@ -251,6 +251,7 @@ func (p *Package) writeDefs() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
fatalf("%s", err)
|
fatalf("%s", err)
|
||||||
}
|
}
|
||||||
|
defer fgcch.Close()
|
||||||
_, err = io.Copy(fexp, fgcch)
|
_, err = io.Copy(fexp, fgcch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fatalf("%s", err)
|
fatalf("%s", err)
|
||||||
@ -879,7 +880,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
|||||||
fmt.Fprintf(fgcc, "#pragma GCC diagnostic ignored \"-Wpragmas\"\n")
|
fmt.Fprintf(fgcc, "#pragma GCC diagnostic ignored \"-Wpragmas\"\n")
|
||||||
fmt.Fprintf(fgcc, "#pragma GCC diagnostic ignored \"-Waddress-of-packed-member\"\n")
|
fmt.Fprintf(fgcc, "#pragma GCC diagnostic ignored \"-Waddress-of-packed-member\"\n")
|
||||||
|
|
||||||
fmt.Fprintf(fgcc, "extern void crosscall2(void (*fn)(void *, int, __SIZE_TYPE__), void *, int, __SIZE_TYPE__);\n")
|
fmt.Fprintf(fgcc, "extern void crosscall2(void (*fn)(void *), void *, int, __SIZE_TYPE__);\n")
|
||||||
fmt.Fprintf(fgcc, "extern __SIZE_TYPE__ _cgo_wait_runtime_init_done(void);\n")
|
fmt.Fprintf(fgcc, "extern __SIZE_TYPE__ _cgo_wait_runtime_init_done(void);\n")
|
||||||
fmt.Fprintf(fgcc, "extern void _cgo_release_context(__SIZE_TYPE__);\n\n")
|
fmt.Fprintf(fgcc, "extern void _cgo_release_context(__SIZE_TYPE__);\n\n")
|
||||||
fmt.Fprintf(fgcc, "extern char* _cgo_topofstack(void);")
|
fmt.Fprintf(fgcc, "extern char* _cgo_topofstack(void);")
|
||||||
@ -889,59 +890,48 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
|||||||
for _, exp := range p.ExpFunc {
|
for _, exp := range p.ExpFunc {
|
||||||
fn := exp.Func
|
fn := exp.Func
|
||||||
|
|
||||||
// Construct a gcc struct matching the gc argument and
|
// Construct a struct that will be used to communicate
|
||||||
// result frame. The gcc struct will be compiled with
|
// arguments from C to Go. The C and Go definitions
|
||||||
// __attribute__((packed)) so all padding must be accounted
|
// just have to agree. The gcc struct will be compiled
|
||||||
// for explicitly.
|
// with __attribute__((packed)) so all padding must be
|
||||||
|
// accounted for explicitly.
|
||||||
ctype := "struct {\n"
|
ctype := "struct {\n"
|
||||||
|
gotype := new(bytes.Buffer)
|
||||||
|
fmt.Fprintf(gotype, "struct {\n")
|
||||||
off := int64(0)
|
off := int64(0)
|
||||||
npad := 0
|
npad := 0
|
||||||
if fn.Recv != nil {
|
argField := func(typ ast.Expr, namePat string, args ...interface{}) {
|
||||||
t := p.cgoType(fn.Recv.List[0].Type)
|
name := fmt.Sprintf(namePat, args...)
|
||||||
ctype += fmt.Sprintf("\t\t%s recv;\n", t.C)
|
t := p.cgoType(typ)
|
||||||
|
if off%t.Align != 0 {
|
||||||
|
pad := t.Align - off%t.Align
|
||||||
|
ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
|
||||||
|
off += pad
|
||||||
|
npad++
|
||||||
|
}
|
||||||
|
ctype += fmt.Sprintf("\t\t%s %s;\n", t.C, name)
|
||||||
|
fmt.Fprintf(gotype, "\t\t%s ", name)
|
||||||
|
noSourceConf.Fprint(gotype, fset, typ)
|
||||||
|
fmt.Fprintf(gotype, "\n")
|
||||||
off += t.Size
|
off += t.Size
|
||||||
}
|
}
|
||||||
|
if fn.Recv != nil {
|
||||||
|
argField(fn.Recv.List[0].Type, "recv")
|
||||||
|
}
|
||||||
fntype := fn.Type
|
fntype := fn.Type
|
||||||
forFieldList(fntype.Params,
|
forFieldList(fntype.Params,
|
||||||
func(i int, aname string, atype ast.Expr) {
|
func(i int, aname string, atype ast.Expr) {
|
||||||
t := p.cgoType(atype)
|
argField(atype, "p%d", i)
|
||||||
if off%t.Align != 0 {
|
|
||||||
pad := t.Align - off%t.Align
|
|
||||||
ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
|
|
||||||
off += pad
|
|
||||||
npad++
|
|
||||||
}
|
|
||||||
ctype += fmt.Sprintf("\t\t%s p%d;\n", t.C, i)
|
|
||||||
off += t.Size
|
|
||||||
})
|
})
|
||||||
if off%p.PtrSize != 0 {
|
|
||||||
pad := p.PtrSize - off%p.PtrSize
|
|
||||||
ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
|
|
||||||
off += pad
|
|
||||||
npad++
|
|
||||||
}
|
|
||||||
forFieldList(fntype.Results,
|
forFieldList(fntype.Results,
|
||||||
func(i int, aname string, atype ast.Expr) {
|
func(i int, aname string, atype ast.Expr) {
|
||||||
t := p.cgoType(atype)
|
argField(atype, "r%d", i)
|
||||||
if off%t.Align != 0 {
|
|
||||||
pad := t.Align - off%t.Align
|
|
||||||
ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
|
|
||||||
off += pad
|
|
||||||
npad++
|
|
||||||
}
|
|
||||||
ctype += fmt.Sprintf("\t\t%s r%d;\n", t.C, i)
|
|
||||||
off += t.Size
|
|
||||||
})
|
})
|
||||||
if off%p.PtrSize != 0 {
|
|
||||||
pad := p.PtrSize - off%p.PtrSize
|
|
||||||
ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
|
|
||||||
off += pad
|
|
||||||
npad++
|
|
||||||
}
|
|
||||||
if ctype == "struct {\n" {
|
if ctype == "struct {\n" {
|
||||||
ctype += "\t\tchar unused;\n" // avoid empty struct
|
ctype += "\t\tchar unused;\n" // avoid empty struct
|
||||||
}
|
}
|
||||||
ctype += "\t}"
|
ctype += "\t}"
|
||||||
|
fmt.Fprintf(gotype, "\t}")
|
||||||
|
|
||||||
// Get the return type of the wrapper function
|
// Get the return type of the wrapper function
|
||||||
// compiled by gcc.
|
// compiled by gcc.
|
||||||
@ -966,7 +956,11 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Build the wrapper function compiled by gcc.
|
// Build the wrapper function compiled by gcc.
|
||||||
s := fmt.Sprintf("%s %s(", gccResult, exp.ExpName)
|
gccExport := ""
|
||||||
|
if goos == "windows" {
|
||||||
|
gccExport = "__declspec(dllexport)"
|
||||||
|
}
|
||||||
|
s := fmt.Sprintf("%s %s %s(", gccExport, gccResult, exp.ExpName)
|
||||||
if fn.Recv != nil {
|
if fn.Recv != nil {
|
||||||
s += p.cgoType(fn.Recv.List[0].Type).C.String()
|
s += p.cgoType(fn.Recv.List[0].Type).C.String()
|
||||||
s += " recv"
|
s += " recv"
|
||||||
@ -988,12 +982,23 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
|||||||
}
|
}
|
||||||
fmt.Fprintf(fgcch, "extern %s;\n", s)
|
fmt.Fprintf(fgcch, "extern %s;\n", s)
|
||||||
|
|
||||||
fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *, int, __SIZE_TYPE__);\n", cPrefix, exp.ExpName)
|
fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *);\n", cPrefix, exp.ExpName)
|
||||||
fmt.Fprintf(fgcc, "\nCGO_NO_SANITIZE_THREAD")
|
fmt.Fprintf(fgcc, "\nCGO_NO_SANITIZE_THREAD")
|
||||||
fmt.Fprintf(fgcc, "\n%s\n", s)
|
fmt.Fprintf(fgcc, "\n%s\n", s)
|
||||||
fmt.Fprintf(fgcc, "{\n")
|
fmt.Fprintf(fgcc, "{\n")
|
||||||
fmt.Fprintf(fgcc, "\t__SIZE_TYPE__ _cgo_ctxt = _cgo_wait_runtime_init_done();\n")
|
fmt.Fprintf(fgcc, "\t__SIZE_TYPE__ _cgo_ctxt = _cgo_wait_runtime_init_done();\n")
|
||||||
fmt.Fprintf(fgcc, "\t%s %v _cgo_a;\n", ctype, p.packedAttribute())
|
// The results part of the argument structure must be
|
||||||
|
// initialized to 0 so the write barriers generated by
|
||||||
|
// the assignments to these fields in Go are safe.
|
||||||
|
//
|
||||||
|
// We use a local static variable to get the zeroed
|
||||||
|
// value of the argument type. This avoids including
|
||||||
|
// string.h for memset, and is also robust to C++
|
||||||
|
// types with constructors. Both GCC and LLVM optimize
|
||||||
|
// this into just zeroing _cgo_a.
|
||||||
|
fmt.Fprintf(fgcc, "\ttypedef %s %v _cgo_argtype;\n", ctype, p.packedAttribute())
|
||||||
|
fmt.Fprintf(fgcc, "\tstatic _cgo_argtype _cgo_zero;\n")
|
||||||
|
fmt.Fprintf(fgcc, "\t_cgo_argtype _cgo_a = _cgo_zero;\n")
|
||||||
if gccResult != "void" && (len(fntype.Results.List) > 1 || len(fntype.Results.List[0].Names) > 1) {
|
if gccResult != "void" && (len(fntype.Results.List) > 1 || len(fntype.Results.List[0].Names) > 1) {
|
||||||
fmt.Fprintf(fgcc, "\t%s r;\n", gccResult)
|
fmt.Fprintf(fgcc, "\t%s r;\n", gccResult)
|
||||||
}
|
}
|
||||||
@ -1022,82 +1027,28 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
|||||||
fmt.Fprintf(fgcc, "}\n")
|
fmt.Fprintf(fgcc, "}\n")
|
||||||
|
|
||||||
// Build the wrapper function compiled by cmd/compile.
|
// Build the wrapper function compiled by cmd/compile.
|
||||||
goname := "_cgoexpwrap" + cPrefix + "_"
|
// This unpacks the argument struct above and calls the Go function.
|
||||||
if fn.Recv != nil {
|
|
||||||
goname += fn.Recv.List[0].Names[0].Name + "_"
|
|
||||||
}
|
|
||||||
goname += exp.Func.Name.Name
|
|
||||||
fmt.Fprintf(fgo2, "//go:cgo_export_dynamic %s\n", exp.ExpName)
|
fmt.Fprintf(fgo2, "//go:cgo_export_dynamic %s\n", exp.ExpName)
|
||||||
fmt.Fprintf(fgo2, "//go:linkname _cgoexp%s_%s _cgoexp%s_%s\n", cPrefix, exp.ExpName, cPrefix, exp.ExpName)
|
fmt.Fprintf(fgo2, "//go:linkname _cgoexp%s_%s _cgoexp%s_%s\n", cPrefix, exp.ExpName, cPrefix, exp.ExpName)
|
||||||
fmt.Fprintf(fgo2, "//go:cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName)
|
fmt.Fprintf(fgo2, "//go:cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName)
|
||||||
fmt.Fprintf(fgo2, "//go:nosplit\n") // no split stack, so no use of m or g
|
fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a *%s) {\n", cPrefix, exp.ExpName, gotype)
|
||||||
fmt.Fprintf(fgo2, "//go:norace\n") // must not have race detector calls inserted
|
|
||||||
fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a unsafe.Pointer, n int32, ctxt uintptr) {\n", cPrefix, exp.ExpName)
|
|
||||||
fmt.Fprintf(fgo2, "\tfn := %s\n", goname)
|
|
||||||
// The indirect here is converting from a Go function pointer to a C function pointer.
|
|
||||||
fmt.Fprintf(fgo2, "\t_cgo_runtime_cgocallback(**(**unsafe.Pointer)(unsafe.Pointer(&fn)), a, uintptr(n), ctxt);\n")
|
|
||||||
fmt.Fprintf(fgo2, "}\n")
|
|
||||||
|
|
||||||
fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName)
|
fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName)
|
||||||
|
|
||||||
// This code uses printer.Fprint, not conf.Fprint,
|
|
||||||
// because we don't want //line comments in the middle
|
|
||||||
// of the function types.
|
|
||||||
fmt.Fprintf(fgo2, "\n")
|
|
||||||
fmt.Fprintf(fgo2, "func %s(", goname)
|
|
||||||
comma := false
|
|
||||||
if fn.Recv != nil {
|
|
||||||
fmt.Fprintf(fgo2, "recv ")
|
|
||||||
printer.Fprint(fgo2, fset, fn.Recv.List[0].Type)
|
|
||||||
comma = true
|
|
||||||
}
|
|
||||||
forFieldList(fntype.Params,
|
|
||||||
func(i int, aname string, atype ast.Expr) {
|
|
||||||
if comma {
|
|
||||||
fmt.Fprintf(fgo2, ", ")
|
|
||||||
}
|
|
||||||
fmt.Fprintf(fgo2, "p%d ", i)
|
|
||||||
printer.Fprint(fgo2, fset, atype)
|
|
||||||
comma = true
|
|
||||||
})
|
|
||||||
fmt.Fprintf(fgo2, ")")
|
|
||||||
if gccResult != "void" {
|
if gccResult != "void" {
|
||||||
fmt.Fprint(fgo2, " (")
|
// 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 {
|
||||||
fmt.Fprint(fgo2, ", ")
|
fmt.Fprintf(fgo2, ", ")
|
||||||
}
|
}
|
||||||
fmt.Fprintf(fgo2, "r%d ", i)
|
fmt.Fprintf(fgo2, "a.r%d", i)
|
||||||
printer.Fprint(fgo2, fset, atype)
|
|
||||||
})
|
})
|
||||||
fmt.Fprint(fgo2, ")")
|
fmt.Fprintf(fgo2, " = ")
|
||||||
}
|
|
||||||
fmt.Fprint(fgo2, " {\n")
|
|
||||||
if gccResult == "void" {
|
|
||||||
fmt.Fprint(fgo2, "\t")
|
|
||||||
} else {
|
|
||||||
// Verify that any results don't contain any
|
|
||||||
// Go pointers.
|
|
||||||
addedDefer := false
|
|
||||||
forFieldList(fntype.Results,
|
|
||||||
func(i int, aname string, atype ast.Expr) {
|
|
||||||
if !p.hasPointer(nil, atype, false) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !addedDefer {
|
|
||||||
fmt.Fprint(fgo2, "\tdefer func() {\n")
|
|
||||||
addedDefer = true
|
|
||||||
}
|
|
||||||
fmt.Fprintf(fgo2, "\t\t_cgoCheckResult(r%d)\n", i)
|
|
||||||
})
|
|
||||||
if addedDefer {
|
|
||||||
fmt.Fprint(fgo2, "\t}()\n")
|
|
||||||
}
|
|
||||||
fmt.Fprint(fgo2, "\treturn ")
|
|
||||||
}
|
}
|
||||||
if fn.Recv != nil {
|
if fn.Recv != nil {
|
||||||
fmt.Fprintf(fgo2, "recv.")
|
fmt.Fprintf(fgo2, "a.recv.")
|
||||||
}
|
}
|
||||||
fmt.Fprintf(fgo2, "%s(", exp.Func.Name)
|
fmt.Fprintf(fgo2, "%s(", exp.Func.Name)
|
||||||
forFieldList(fntype.Params,
|
forFieldList(fntype.Params,
|
||||||
@ -1105,9 +1056,20 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
|||||||
if i > 0 {
|
if i > 0 {
|
||||||
fmt.Fprint(fgo2, ", ")
|
fmt.Fprint(fgo2, ", ")
|
||||||
}
|
}
|
||||||
fmt.Fprintf(fgo2, "p%d", i)
|
fmt.Fprintf(fgo2, "a.p%d", i)
|
||||||
})
|
})
|
||||||
fmt.Fprint(fgo2, ")\n")
|
fmt.Fprint(fgo2, ")\n")
|
||||||
|
if gccResult != "void" {
|
||||||
|
// Verify that any results don't contain any
|
||||||
|
// Go pointers.
|
||||||
|
forFieldList(fntype.Results,
|
||||||
|
func(i int, aname string, atype ast.Expr) {
|
||||||
|
if !p.hasPointer(nil, atype, false) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Fprintf(fgo2, "\t_cgoCheckResult(a.r%d)\n", i)
|
||||||
|
})
|
||||||
|
}
|
||||||
fmt.Fprint(fgo2, "}\n")
|
fmt.Fprint(fgo2, "}\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1604,9 +1566,6 @@ const goProlog = `
|
|||||||
//go:linkname _cgo_runtime_cgocall runtime.cgocall
|
//go:linkname _cgo_runtime_cgocall runtime.cgocall
|
||||||
func _cgo_runtime_cgocall(unsafe.Pointer, uintptr) int32
|
func _cgo_runtime_cgocall(unsafe.Pointer, uintptr) int32
|
||||||
|
|
||||||
//go:linkname _cgo_runtime_cgocallback runtime.cgocallback
|
|
||||||
func _cgo_runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr, uintptr)
|
|
||||||
|
|
||||||
//go:linkname _cgoCheckPointer runtime.cgoCheckPointer
|
//go:linkname _cgoCheckPointer runtime.cgoCheckPointer
|
||||||
func _cgoCheckPointer(interface{}, interface{})
|
func _cgoCheckPointer(interface{}, interface{})
|
||||||
|
|
||||||
|
12
libgo/go/cmd/go.mod
Normal file
12
libgo/go/cmd/go.mod
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
module cmd
|
||||||
|
|
||||||
|
go 1.16
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2
|
||||||
|
golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff
|
||||||
|
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897
|
||||||
|
golang.org/x/mod v0.4.0
|
||||||
|
golang.org/x/sys v0.0.0-20201204225414-ed752295db88 // indirect
|
||||||
|
golang.org/x/tools v0.0.0-20201211025543-abf6a1d87e11
|
||||||
|
)
|
@ -49,10 +49,11 @@
|
|||||||
// modules modules, module versions, and more
|
// modules modules, module versions, and more
|
||||||
// module-get module-aware go get
|
// module-get module-aware go get
|
||||||
// module-auth module authentication using go.sum
|
// module-auth module authentication using go.sum
|
||||||
// module-private module configuration for non-public modules
|
|
||||||
// packages package lists and patterns
|
// packages package lists and patterns
|
||||||
|
// private configuration for downloading non-public code
|
||||||
// testflag testing flags
|
// testflag testing flags
|
||||||
// testfunc testing functions
|
// testfunc testing functions
|
||||||
|
// vcs controlling version control with GOVCS
|
||||||
//
|
//
|
||||||
// Use "go help <topic>" for more information about that topic.
|
// Use "go help <topic>" for more information about that topic.
|
||||||
//
|
//
|
||||||
@ -71,7 +72,7 @@
|
|||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
//
|
//
|
||||||
// go build [-o output] [-i] [build flags] [packages]
|
// go build [-o output] [build flags] [packages]
|
||||||
//
|
//
|
||||||
// Build compiles the packages named by the import paths,
|
// Build compiles the packages named by the import paths,
|
||||||
// along with their dependencies, but it does not install the results.
|
// along with their dependencies, but it does not install the results.
|
||||||
@ -93,10 +94,12 @@
|
|||||||
//
|
//
|
||||||
// The -o flag forces build to write the resulting executable or object
|
// The -o flag forces build to write the resulting executable or object
|
||||||
// to the named output file or directory, instead of the default behavior described
|
// to the named output file or directory, instead of the default behavior described
|
||||||
// in the last two paragraphs. If the named output is a directory that exists,
|
// in the last two paragraphs. If the named output is an existing directory or
|
||||||
// then any resulting executables will be written to that directory.
|
// ends with a slash or backslash, then any resulting executables
|
||||||
|
// will be written to that directory.
|
||||||
//
|
//
|
||||||
// The -i flag installs the packages that are dependencies of the target.
|
// The -i flag installs the packages that are dependencies of the target.
|
||||||
|
// The -i flag is deprecated. Compiled packages are cached automatically.
|
||||||
//
|
//
|
||||||
// The build flags are shared by the build, clean, get, install, list, run,
|
// The build flags are shared by the build, clean, get, install, list, run,
|
||||||
// and test commands:
|
// and test commands:
|
||||||
@ -161,6 +164,17 @@
|
|||||||
// 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".
|
||||||
|
// -overlay file
|
||||||
|
// read a JSON config file that provides an overlay for build operations.
|
||||||
|
// The file is a JSON struct with a single field, named 'Replace', that
|
||||||
|
// maps each disk file path (a string) to its backing file path, so that
|
||||||
|
// a build will run as if the disk file path exists with the contents
|
||||||
|
// given by the backing file paths, or as if the disk file path does not
|
||||||
|
// exist if its backing file path is empty. Support for the -overlay flag
|
||||||
|
// has some limitations:importantly, cgo files included from outside the
|
||||||
|
// include path must be in the same directory as the Go package they are
|
||||||
|
// included from, and overlays will not appear when binaries and tests are
|
||||||
|
// run through go run and go test respectively.
|
||||||
// -pkgdir dir
|
// -pkgdir dir
|
||||||
// install and load all packages from dir instead of the usual locations.
|
// install and load all packages from dir instead of the usual locations.
|
||||||
// For example, when building with a non-standard configuration,
|
// For example, when building with a non-standard configuration,
|
||||||
@ -616,15 +630,15 @@
|
|||||||
// dependency should be removed entirely, downgrading or removing modules
|
// dependency should be removed entirely, downgrading or removing modules
|
||||||
// depending on it as needed.
|
// depending on it as needed.
|
||||||
//
|
//
|
||||||
// The version suffix @latest explicitly requests the latest minor release of the
|
// The version suffix @latest explicitly requests the latest minor release of
|
||||||
// module named by the given path. The suffix @upgrade is like @latest but
|
// the module named by the given path. The suffix @upgrade is like @latest but
|
||||||
// will not downgrade a module if it is already required at a revision or
|
// will not downgrade a module if it is already required at a revision or
|
||||||
// pre-release version newer than the latest released version. The suffix
|
// pre-release version newer than the latest released version. The suffix
|
||||||
// @patch requests the latest patch release: the latest released version
|
// @patch requests the latest patch release: the latest released version
|
||||||
// with the same major and minor version numbers as the currently required
|
// with the same major and minor version numbers as the currently required
|
||||||
// version. Like @upgrade, @patch will not downgrade a module already required
|
// version. Like @upgrade, @patch will not downgrade a module already required
|
||||||
// at a newer version. If the path is not already required, @upgrade and @patch
|
// at a newer version. If the path is not already required, @upgrade is
|
||||||
// are equivalent to @latest.
|
// equivalent to @latest, and @patch is disallowed.
|
||||||
//
|
//
|
||||||
// Although get defaults to using the latest version of the module containing
|
// Although get defaults to using the latest version of the module containing
|
||||||
// a named package, it does not use the latest version of that module's
|
// a named package, it does not use the latest version of that module's
|
||||||
@ -661,14 +675,27 @@
|
|||||||
// this automatically as well.
|
// this automatically as well.
|
||||||
//
|
//
|
||||||
// The -insecure flag permits fetching from repositories and resolving
|
// The -insecure flag permits fetching from repositories and resolving
|
||||||
// custom domains using insecure schemes such as HTTP. Use with caution. The
|
// custom domains using insecure schemes such as HTTP, and also bypassess
|
||||||
// GOINSECURE environment variable is usually a better alternative, since it
|
// module sum validation using the checksum database. Use with caution.
|
||||||
// provides control over which modules may be retrieved using an insecure scheme.
|
// This flag is deprecated and will be removed in a future version of go.
|
||||||
// See 'go help environment' for details.
|
// To permit the use of insecure schemes, use the GOINSECURE environment
|
||||||
|
// variable instead. To bypass module sum validation, use GOPRIVATE or
|
||||||
|
// GONOSUMDB. See 'go help environment' for details.
|
||||||
//
|
//
|
||||||
// The second step is to download (if needed), build, and install
|
// The second step is to download (if needed), build, and install
|
||||||
// the named packages.
|
// the named packages.
|
||||||
//
|
//
|
||||||
|
// The -d flag instructs get to skip this step, downloading source code
|
||||||
|
// needed to build the named packages and their dependencies, but not
|
||||||
|
// building or installing.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
// If an argument names a module but not a package (because there is no
|
// If an argument names a module but not a package (because there is no
|
||||||
// Go source code in the module's root directory), then the install step
|
// Go source code in the module's root directory), then the install step
|
||||||
// is skipped for that argument, instead of causing a build failure.
|
// is skipped for that argument, instead of causing a build failure.
|
||||||
@ -680,10 +707,6 @@
|
|||||||
// adds the latest golang.org/x/perf and then installs the commands in that
|
// adds the latest golang.org/x/perf and then installs the commands in that
|
||||||
// latest version.
|
// latest version.
|
||||||
//
|
//
|
||||||
// The -d flag instructs get to download the source code needed to build
|
|
||||||
// the named packages, including downloading necessary dependencies,
|
|
||||||
// but not to build and install them.
|
|
||||||
//
|
|
||||||
// With no package arguments, 'go get' applies to Go package in the
|
// With no package arguments, 'go get' applies to Go package in the
|
||||||
// current directory, if any. In particular, 'go get -u' and
|
// current directory, if any. In particular, 'go get -u' and
|
||||||
// 'go get -u=patch' update all the dependencies of that package.
|
// 'go get -u=patch' update all the dependencies of that package.
|
||||||
@ -706,7 +729,7 @@
|
|||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
//
|
//
|
||||||
// go install [-i] [build flags] [packages]
|
// go install [build flags] [packages]
|
||||||
//
|
//
|
||||||
// Install compiles and installs the packages named by the import paths.
|
// Install compiles and installs the packages named by the import paths.
|
||||||
//
|
//
|
||||||
@ -715,11 +738,39 @@
|
|||||||
// environment variable is not set. Executables in $GOROOT
|
// environment variable is not set. Executables in $GOROOT
|
||||||
// are installed in $GOROOT/bin or $GOTOOLDIR instead of $GOBIN.
|
// are installed in $GOROOT/bin or $GOTOOLDIR instead of $GOBIN.
|
||||||
//
|
//
|
||||||
|
// If the arguments have version suffixes (like @latest or @v1.0.0), "go install"
|
||||||
|
// builds packages in module-aware mode, ignoring the go.mod file in the current
|
||||||
|
// directory or any parent directory, if there is one. This is useful for
|
||||||
|
// installing executables without affecting the dependencies of the main module.
|
||||||
|
// To eliminate ambiguity about which module versions are used in the build, the
|
||||||
|
// arguments must satisfy the following constraints:
|
||||||
|
//
|
||||||
|
// - Arguments must be package paths or package patterns (with "..." wildcards).
|
||||||
|
// They must not be standard packages (like fmt), meta-patterns (std, cmd,
|
||||||
|
// all), or relative or absolute file paths.
|
||||||
|
// - All arguments must have the same version suffix. Different queries are not
|
||||||
|
// allowed, even if they refer to the same version.
|
||||||
|
// - All arguments must refer to packages in the same module at the same version.
|
||||||
|
// - No module is considered the "main" module. If the module containing
|
||||||
|
// packages named on the command line has a go.mod file, it must not contain
|
||||||
|
// directives (replace and exclude) that would cause it to be interpreted
|
||||||
|
// differently than if it were the main module. The module must not require
|
||||||
|
// a higher version of itself.
|
||||||
|
// - Package path arguments must refer to main packages. Pattern arguments
|
||||||
|
// will only match main packages.
|
||||||
|
//
|
||||||
|
// If the arguments don't have version suffixes, "go install" may run in
|
||||||
|
// module-aware mode or GOPATH mode, depending on the GO111MODULE environment
|
||||||
|
// variable and the presence of a go.mod file. See 'go help modules' for details.
|
||||||
|
// If module-aware mode is enabled, "go install" runs in the context of the main
|
||||||
|
// module.
|
||||||
|
//
|
||||||
// When module-aware mode is disabled, other packages are installed in the
|
// When module-aware mode is disabled, other packages are installed in the
|
||||||
// directory $GOPATH/pkg/$GOOS_$GOARCH. When module-aware mode is enabled,
|
// directory $GOPATH/pkg/$GOOS_$GOARCH. When module-aware mode is enabled,
|
||||||
// other packages are built and cached but not installed.
|
// other packages are built and cached but not installed.
|
||||||
//
|
//
|
||||||
// The -i flag installs the dependencies of the named packages as well.
|
// The -i flag installs the dependencies of the named packages as well.
|
||||||
|
// The -i flag is deprecated. Compiled packages are cached automatically.
|
||||||
//
|
//
|
||||||
// For more about the build flags, see 'go help build'.
|
// For more about the build flags, see 'go help build'.
|
||||||
// For more about specifying packages, see 'go help packages'.
|
// For more about specifying packages, see 'go help packages'.
|
||||||
@ -766,26 +817,28 @@
|
|||||||
// BinaryOnly bool // binary-only package (no longer supported)
|
// BinaryOnly bool // binary-only package (no longer supported)
|
||||||
// ForTest string // package is only for use in named test
|
// ForTest string // package is only for use in named test
|
||||||
// Export string // file containing export data (when using -export)
|
// Export string // file containing export data (when using -export)
|
||||||
|
// BuildID string // build ID of the compiled package (when using -export)
|
||||||
// Module *Module // info about package's containing module, if any (can be nil)
|
// Module *Module // info about package's containing module, if any (can be nil)
|
||||||
// Match []string // command-line patterns matching this package
|
// Match []string // command-line patterns matching this package
|
||||||
// DepOnly bool // package is only a dependency, not explicitly listed
|
// DepOnly bool // package is only a dependency, not explicitly listed
|
||||||
//
|
//
|
||||||
// // Source files
|
// // Source files
|
||||||
// GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
|
// GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
|
||||||
// CgoFiles []string // .go source files that import "C"
|
// CgoFiles []string // .go source files that import "C"
|
||||||
// CompiledGoFiles []string // .go files presented to compiler (when using -compiled)
|
// CompiledGoFiles []string // .go files presented to compiler (when using -compiled)
|
||||||
// IgnoredGoFiles []string // .go source files ignored due to build constraints
|
// IgnoredGoFiles []string // .go source files ignored due to build constraints
|
||||||
// CFiles []string // .c source files
|
// IgnoredOtherFiles []string // non-.go source files ignored due to build constraints
|
||||||
// CXXFiles []string // .cc, .cxx and .cpp source files
|
// CFiles []string // .c source files
|
||||||
// MFiles []string // .m source files
|
// CXXFiles []string // .cc, .cxx and .cpp source files
|
||||||
// HFiles []string // .h, .hh, .hpp and .hxx source files
|
// MFiles []string // .m source files
|
||||||
// FFiles []string // .f, .F, .for and .f90 Fortran source files
|
// HFiles []string // .h, .hh, .hpp and .hxx source files
|
||||||
// SFiles []string // .s source files
|
// FFiles []string // .f, .F, .for and .f90 Fortran source files
|
||||||
// SwigFiles []string // .swig files
|
// SFiles []string // .s source files
|
||||||
// SwigCXXFiles []string // .swigcxx files
|
// SwigFiles []string // .swig files
|
||||||
// SysoFiles []string // .syso object files to add to archive
|
// SwigCXXFiles []string // .swigcxx files
|
||||||
// TestGoFiles []string // _test.go files in package
|
// SysoFiles []string // .syso object files to add to archive
|
||||||
// XTestGoFiles []string // _test.go files outside package
|
// TestGoFiles []string // _test.go files in package
|
||||||
|
// XTestGoFiles []string // _test.go files outside package
|
||||||
//
|
//
|
||||||
// // Cgo directives
|
// // Cgo directives
|
||||||
// CgoCFLAGS []string // cgo: flags for C compiler
|
// CgoCFLAGS []string // cgo: flags for C compiler
|
||||||
@ -916,6 +969,7 @@
|
|||||||
// Dir string // directory holding files for this module, if any
|
// Dir string // directory holding files for this module, if any
|
||||||
// GoMod string // path to go.mod file used when loading this module, if any
|
// GoMod string // path to go.mod file used when loading this module, if any
|
||||||
// GoVersion string // go version used in module
|
// GoVersion string // go version used in module
|
||||||
|
// Retracted string // retraction information, if any (with -retracted or -u)
|
||||||
// Error *ModuleError // error loading module
|
// Error *ModuleError // error loading module
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
@ -947,14 +1001,16 @@
|
|||||||
// The -u flag adds information about available upgrades.
|
// The -u flag adds information about available upgrades.
|
||||||
// When the latest version of a given module is newer than
|
// When the latest version of a given module is newer than
|
||||||
// the current one, list -u sets the Module's Update field
|
// the current one, list -u sets the Module's Update field
|
||||||
// to information about the newer module.
|
// to information about the newer module. list -u will also set
|
||||||
|
// the module's Retracted field if the current version is retracted.
|
||||||
// The Module's String method indicates an available upgrade by
|
// The Module's String method indicates an available upgrade by
|
||||||
// formatting the newer version in brackets after the current version.
|
// formatting the newer version in brackets after the current version.
|
||||||
|
// If a version is retracted, the string "(retracted)" will follow it.
|
||||||
// For example, 'go list -m -u all' might print:
|
// For example, 'go list -m -u all' might print:
|
||||||
//
|
//
|
||||||
// my/main/module
|
// my/main/module
|
||||||
// golang.org/x/text v0.3.0 [v0.4.0] => /tmp/text
|
// golang.org/x/text v0.3.0 [v0.4.0] => /tmp/text
|
||||||
// rsc.io/pdf v0.1.1 [v0.1.2]
|
// rsc.io/pdf v0.1.1 (retracted) [v0.1.2]
|
||||||
//
|
//
|
||||||
// (For tools, 'go list -m -u -json all' may be more convenient to parse.)
|
// (For tools, 'go list -m -u -json all' may be more convenient to parse.)
|
||||||
//
|
//
|
||||||
@ -964,6 +1020,14 @@
|
|||||||
// the default output format to display the module path followed by the
|
// the default output format to display the module path followed by the
|
||||||
// space-separated version list.
|
// space-separated version list.
|
||||||
//
|
//
|
||||||
|
// The -retracted flag causes list to report information about retracted
|
||||||
|
// module versions. When -retracted is used with -f or -json, the Retracted
|
||||||
|
// field will be set to a string explaining why the version was retracted.
|
||||||
|
// The string is taken from comments on the retract directive in the
|
||||||
|
// module's go.mod file. When -retracted is used with -versions, retracted
|
||||||
|
// versions are listed together with unretracted versions. The -retracted
|
||||||
|
// flag may be used with or without -m.
|
||||||
|
//
|
||||||
// The arguments to list -m are interpreted as a list of modules, not packages.
|
// The arguments to list -m are interpreted as a list of modules, not packages.
|
||||||
// The main module is the module containing the current directory.
|
// The main module is the module containing the current directory.
|
||||||
// The active modules are the main module and its dependencies.
|
// The active modules are the main module and its dependencies.
|
||||||
@ -1100,9 +1164,14 @@
|
|||||||
// module path and version pair. If the @v is omitted, a replacement without
|
// module path and version pair. If the @v is omitted, a replacement without
|
||||||
// a version on the left side is dropped.
|
// a version on the left side is dropped.
|
||||||
//
|
//
|
||||||
|
// The -retract=version and -dropretract=version flags add and drop a
|
||||||
|
// retraction on the given version. The version may be a single version
|
||||||
|
// like "v1.2.3" or a closed interval like "[v1.1.0,v1.1.9]". Note that
|
||||||
|
// -retract=version is a no-op if that retraction already exists.
|
||||||
|
//
|
||||||
// The -require, -droprequire, -exclude, -dropexclude, -replace,
|
// The -require, -droprequire, -exclude, -dropexclude, -replace,
|
||||||
// and -dropreplace editing flags may be repeated, and the changes
|
// -dropreplace, -retract, and -dropretract editing flags may be repeated,
|
||||||
// are applied in the order given.
|
// and the changes are applied in the order given.
|
||||||
//
|
//
|
||||||
// The -go=version flag sets the expected Go language version.
|
// The -go=version flag sets the expected Go language version.
|
||||||
//
|
//
|
||||||
@ -1136,6 +1205,15 @@
|
|||||||
// New Module
|
// New Module
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
|
// type Retract struct {
|
||||||
|
// Low string
|
||||||
|
// High string
|
||||||
|
// Rationale string
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Retract entries representing a single version (not an interval) will have
|
||||||
|
// the "Low" and "High" fields set to the same value.
|
||||||
|
//
|
||||||
// Note that this only describes the go.mod file itself, not other modules
|
// Note that this only describes the go.mod file itself, not other modules
|
||||||
// referred to indirectly. For the full set of modules available to a build,
|
// referred to indirectly. For the full set of modules available to a build,
|
||||||
// use 'go list -m -json all'.
|
// use 'go list -m -json all'.
|
||||||
@ -1163,19 +1241,24 @@
|
|||||||
//
|
//
|
||||||
// go mod init [module]
|
// go mod init [module]
|
||||||
//
|
//
|
||||||
// Init initializes and writes a new go.mod to the current directory,
|
// Init initializes and writes a new go.mod file in the current directory, in
|
||||||
// in effect creating a new module rooted at the current directory.
|
// effect creating a new module rooted at the current directory. The go.mod file
|
||||||
// The file go.mod must not already exist.
|
// must not already exist.
|
||||||
// If possible, init will guess the module path from import comments
|
//
|
||||||
// (see 'go help importpath') or from version control configuration.
|
// Init accepts one optional argument, the module path for the new module. If the
|
||||||
// To override this guess, supply the module path as an argument.
|
// module path argument is omitted, init will attempt to infer the module path
|
||||||
|
// using import comments in .go files, vendoring tool configuration files (like
|
||||||
|
// Gopkg.lock), and the current directory (if in GOPATH).
|
||||||
|
//
|
||||||
|
// If a configuration file for a vendoring tool is present, init will attempt to
|
||||||
|
// import module requirements from it.
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// Add missing and remove unused modules
|
// Add missing and remove unused modules
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
//
|
//
|
||||||
// go mod tidy [-v]
|
// go mod tidy [-e] [-v]
|
||||||
//
|
//
|
||||||
// Tidy makes sure go.mod matches the source code in the module.
|
// Tidy makes sure go.mod matches the source code in the module.
|
||||||
// It adds any missing modules necessary to build the current module's
|
// It adds any missing modules necessary to build the current module's
|
||||||
@ -1186,12 +1269,15 @@
|
|||||||
// The -v flag causes tidy to print information about removed modules
|
// The -v flag causes tidy to print information about removed modules
|
||||||
// to standard error.
|
// to standard error.
|
||||||
//
|
//
|
||||||
|
// The -e flag causes tidy to attempt to proceed despite errors
|
||||||
|
// encountered while loading packages.
|
||||||
|
//
|
||||||
//
|
//
|
||||||
// Make vendored copy of dependencies
|
// Make vendored copy of dependencies
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
//
|
//
|
||||||
// go mod vendor [-v]
|
// go mod vendor [-e] [-v]
|
||||||
//
|
//
|
||||||
// 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.
|
||||||
@ -1200,6 +1286,9 @@
|
|||||||
// The -v flag causes vendor to print the names of vendored
|
// The -v flag causes vendor to print the names of vendored
|
||||||
// modules and packages to standard error.
|
// modules and packages to standard error.
|
||||||
//
|
//
|
||||||
|
// The -e flag causes vendor to attempt to proceed despite errors
|
||||||
|
// encountered while loading packages.
|
||||||
|
//
|
||||||
//
|
//
|
||||||
// Verify dependencies have expected content
|
// Verify dependencies have expected content
|
||||||
//
|
//
|
||||||
@ -1388,6 +1477,7 @@
|
|||||||
// -i
|
// -i
|
||||||
// Install packages that are dependencies of the test.
|
// Install packages that are dependencies of the test.
|
||||||
// Do not run the test.
|
// Do not run the test.
|
||||||
|
// The -i flag is deprecated. Compiled packages are cached automatically.
|
||||||
//
|
//
|
||||||
// -json
|
// -json
|
||||||
// Convert test output to JSON suitable for automated processing.
|
// Convert test output to JSON suitable for automated processing.
|
||||||
@ -1546,6 +1636,9 @@
|
|||||||
// Using GOOS=illumos matches build tags and files as for GOOS=solaris
|
// Using GOOS=illumos matches build tags and files as for GOOS=solaris
|
||||||
// in addition to illumos tags and files.
|
// in addition to illumos tags and files.
|
||||||
//
|
//
|
||||||
|
// Using GOOS=ios matches build tags and files as for GOOS=darwin
|
||||||
|
// in addition to ios tags and files.
|
||||||
|
//
|
||||||
// To keep a file from being considered for the build:
|
// To keep a file from being considered for the build:
|
||||||
//
|
//
|
||||||
// // +build ignore
|
// // +build ignore
|
||||||
@ -1733,7 +1826,7 @@
|
|||||||
// Comma-separated list of glob patterns (in the syntax of Go's path.Match)
|
// Comma-separated list of glob patterns (in the syntax of Go's path.Match)
|
||||||
// of module path prefixes that should always be fetched directly
|
// of module path prefixes that should always be fetched directly
|
||||||
// or that should not be compared against the checksum database.
|
// or that should not be compared against the checksum database.
|
||||||
// See 'go help module-private'.
|
// See 'go help private'.
|
||||||
// GOROOT
|
// GOROOT
|
||||||
// The root of the go tree.
|
// The root of the go tree.
|
||||||
// GOSUMDB
|
// GOSUMDB
|
||||||
@ -1789,8 +1882,8 @@
|
|||||||
// For GOARCH=arm, the ARM architecture for which to compile.
|
// For GOARCH=arm, the ARM architecture for which to compile.
|
||||||
// Valid values are 5, 6, 7.
|
// Valid values are 5, 6, 7.
|
||||||
// GO386
|
// GO386
|
||||||
// For GOARCH=386, the floating point instruction set.
|
// For GOARCH=386, how to implement floating point instructions.
|
||||||
// Valid values are 387, sse2.
|
// Valid values are sse2 (default), softfloat.
|
||||||
// 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.
|
||||||
@ -1839,6 +1932,8 @@
|
|||||||
// If module-aware mode is disabled, GOMOD will be the empty string.
|
// If module-aware mode is disabled, GOMOD will be the empty string.
|
||||||
// GOTOOLDIR
|
// GOTOOLDIR
|
||||||
// The directory where the go tools (compile, cover, doc, etc...) are installed.
|
// The directory where the go tools (compile, cover, doc, etc...) are installed.
|
||||||
|
// GOVERSION
|
||||||
|
// The version of the installed Go tree, as reported by runtime.Version.
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// File types
|
// File types
|
||||||
@ -1894,21 +1989,23 @@
|
|||||||
// require new/thing/v2 v2.3.4
|
// require new/thing/v2 v2.3.4
|
||||||
// exclude old/thing v1.2.3
|
// exclude old/thing v1.2.3
|
||||||
// replace bad/thing v1.4.5 => good/thing v1.4.5
|
// replace bad/thing v1.4.5 => good/thing v1.4.5
|
||||||
|
// retract v1.5.6
|
||||||
//
|
//
|
||||||
// The verbs are
|
// The verbs are
|
||||||
// module, to define the module path;
|
// module, to define the module path;
|
||||||
// go, to set the expected language version;
|
// go, to set the expected language version;
|
||||||
// require, to require a particular module at a given version or later;
|
// require, to require a particular module at a given version or later;
|
||||||
// exclude, to exclude a particular module version from use; and
|
// exclude, to exclude a particular module version from use;
|
||||||
// replace, to replace a module version with a different module version.
|
// replace, to replace a module version with a different module version; and
|
||||||
|
// retract, to indicate a previously released version should not be used.
|
||||||
// Exclude and replace apply only in the main module's go.mod and are ignored
|
// Exclude and replace apply only in the main module's go.mod and are ignored
|
||||||
// in dependencies. See https://research.swtch.com/vgo-mvs for details.
|
// in dependencies. See https://golang.org/ref/mod for details.
|
||||||
//
|
//
|
||||||
// The leading verb can be factored out of adjacent lines to create a block,
|
// The leading verb can be factored out of adjacent lines to create a block,
|
||||||
// like in Go imports:
|
// like in Go imports:
|
||||||
//
|
//
|
||||||
// require (
|
// require (
|
||||||
// new/thing v2.3.4
|
// new/thing/v2 v2.3.4
|
||||||
// old/thing v1.2.3
|
// old/thing v1.2.3
|
||||||
// )
|
// )
|
||||||
//
|
//
|
||||||
@ -2146,6 +2243,10 @@
|
|||||||
//
|
//
|
||||||
// The -insecure flag permits fetching from repositories and resolving
|
// The -insecure flag permits fetching from repositories and resolving
|
||||||
// custom domains using insecure schemes such as HTTP. Use with caution.
|
// custom domains using insecure schemes such as HTTP. Use with caution.
|
||||||
|
// This flag is deprecated and will be removed in a future version of go.
|
||||||
|
// The GOINSECURE environment variable should be used instead, since it
|
||||||
|
// provides control over which packages may be retrieved using an insecure
|
||||||
|
// scheme. See 'go help environment' for details.
|
||||||
//
|
//
|
||||||
// The -t flag instructs get to also download the packages required to build
|
// The -t flag instructs get to also download the packages required to build
|
||||||
// the tests for the specified packages.
|
// the tests for the specified packages.
|
||||||
@ -2556,72 +2657,63 @@
|
|||||||
//
|
//
|
||||||
// Maintaining module requirements
|
// Maintaining module requirements
|
||||||
//
|
//
|
||||||
// The go.mod file is meant to be readable and editable by both
|
// The go.mod file is meant to be readable and editable by both programmers and
|
||||||
// programmers and tools. The go command itself automatically updates the go.mod file
|
// tools. Most updates to dependencies can be performed using "go get" and
|
||||||
// to maintain a standard formatting and the accuracy of require statements.
|
// "go mod tidy". Other module-aware build commands may be invoked using the
|
||||||
|
// -mod=mod flag to automatically add missing requirements and fix inconsistencies.
|
||||||
//
|
//
|
||||||
// Any go command that finds an unfamiliar import will look up the module
|
// The "go get" command updates go.mod to change the module versions used in a
|
||||||
// containing that import and add the latest version of that module
|
// build. An upgrade of one module may imply upgrading others, and similarly a
|
||||||
// to go.mod automatically. In most cases, therefore, it suffices to
|
// downgrade of one module may imply downgrading others. The "go get" command
|
||||||
// add an import to source code and run 'go build', 'go test', or even 'go list':
|
// makes these implied changes as well. See "go help module-get".
|
||||||
// as part of analyzing the package, the go command will discover
|
|
||||||
// and resolve the import and update the go.mod file.
|
|
||||||
//
|
//
|
||||||
// Any go command can determine that a module requirement is
|
// The "go mod" command provides other functionality for use in maintaining
|
||||||
// missing and must be added, even when considering only a single
|
// and understanding modules and go.mod files. See "go help mod", particularly
|
||||||
// package from the module. On the other hand, determining that a module requirement
|
// "go help mod tidy" and "go help mod edit".
|
||||||
// is no longer necessary and can be deleted requires a full view of
|
|
||||||
// all packages in the module, across all possible build configurations
|
|
||||||
// (architectures, operating systems, build tags, and so on).
|
|
||||||
// The 'go mod tidy' command builds that view and then
|
|
||||||
// adds any missing module requirements and removes unnecessary ones.
|
|
||||||
//
|
//
|
||||||
// As part of maintaining the require statements in go.mod, the go command
|
// As part of maintaining the require statements in go.mod, the go command
|
||||||
// tracks which ones provide packages imported directly by the current module
|
// tracks which ones provide packages imported directly by the current module
|
||||||
// and which ones provide packages only used indirectly by other module
|
// and which ones provide packages only used indirectly by other module
|
||||||
// dependencies. Requirements needed only for indirect uses are marked with a
|
// dependencies. Requirements needed only for indirect uses are marked with a
|
||||||
// "// indirect" comment in the go.mod file. Indirect requirements are
|
// "// indirect" comment in the go.mod file. Indirect requirements may be
|
||||||
// automatically removed from the go.mod file once they are implied by other
|
// automatically removed from the go.mod file once they are implied by other
|
||||||
// direct requirements. Indirect requirements only arise when using modules
|
// direct requirements. Indirect requirements only arise when using modules
|
||||||
// that fail to state some of their own dependencies or when explicitly
|
// that fail to state some of their own dependencies or when explicitly
|
||||||
// upgrading a module's dependencies ahead of its own stated requirements.
|
// upgrading a module's dependencies ahead of its own stated requirements.
|
||||||
//
|
//
|
||||||
// Because of this automatic maintenance, the information in go.mod is an
|
// The -mod build flag provides additional control over the updating and use of
|
||||||
// up-to-date, readable description of the build.
|
// go.mod for commands that build packages like "go build" and "go test".
|
||||||
//
|
//
|
||||||
// The 'go get' command updates go.mod to change the module versions used in a
|
// If invoked with -mod=readonly (the default in most situations), the go command
|
||||||
// build. An upgrade of one module may imply upgrading others, and similarly a
|
// reports an error if a package named on the command line or an imported package
|
||||||
// downgrade of one module may imply downgrading others. The 'go get' command
|
// is not provided by any module in the build list computed from the main module's
|
||||||
// makes these implied changes as well. If go.mod is edited directly, commands
|
// requirements. The go command also reports an error if a module's checksum is
|
||||||
// like 'go build' or 'go list' will assume that an upgrade is intended and
|
// missing from go.sum (see Module downloading and verification). Either go.mod or
|
||||||
// automatically make any implied upgrades and update go.mod to reflect them.
|
// go.sum must be updated in these situations.
|
||||||
//
|
//
|
||||||
// The 'go mod' command provides other functionality for use in maintaining
|
// If invoked with -mod=mod, the go command automatically updates go.mod and
|
||||||
// and understanding modules and go.mod files. See 'go help mod'.
|
// go.sum, fixing inconsistencies and adding missing requirements and checksums
|
||||||
//
|
// as needed. If the go command finds an unfamiliar import, it looks up the
|
||||||
// The -mod build flag provides additional control over updating and use of go.mod.
|
// module containing that import and adds a requirement for the latest version
|
||||||
//
|
// of that module to go.mod. In most cases, therefore, one may add an import to
|
||||||
// If invoked with -mod=readonly, the go command is disallowed from the implicit
|
// source code and run "go build", "go test", or even "go list" with -mod=mod:
|
||||||
// automatic updating of go.mod described above. Instead, it fails when any changes
|
// as part of analyzing the package, the go command will resolve the import and
|
||||||
// to go.mod are needed. This setting is most useful to check that go.mod does
|
// update the go.mod file.
|
||||||
// not need updates, such as in a continuous integration and testing system.
|
|
||||||
// The "go get" command remains permitted to update go.mod even with -mod=readonly,
|
|
||||||
// and the "go mod" commands do not take the -mod flag (or any other build flags).
|
|
||||||
//
|
//
|
||||||
// If invoked with -mod=vendor, the go command loads packages from the main
|
// If invoked with -mod=vendor, the go command loads packages from the main
|
||||||
// module's vendor directory instead of downloading modules to and loading packages
|
// module's vendor directory instead of downloading modules to and loading packages
|
||||||
// from the module cache. The go command assumes the vendor directory holds
|
// from the module cache. The go command assumes the vendor directory holds
|
||||||
// correct copies of dependencies, and it does not compute the set of required
|
// correct copies of dependencies, and it does not compute the set of required
|
||||||
// module versions from go.mod files. However, the go command does check that
|
// module versions from go.mod files. However, the go command does check that
|
||||||
// vendor/modules.txt (generated by 'go mod vendor') contains metadata consistent
|
// vendor/modules.txt (generated by "go mod vendor") contains metadata consistent
|
||||||
// with go.mod.
|
// with go.mod.
|
||||||
//
|
//
|
||||||
// If invoked with -mod=mod, the go command loads modules from the module cache
|
// If the go command is not invoked with a -mod flag, and the vendor directory
|
||||||
// even if there is a vendor directory present.
|
// is present, and the "go" version in go.mod is 1.14 or higher, the go command
|
||||||
|
// will act as if it were invoked with -mod=vendor. Otherwise, the -mod flag
|
||||||
|
// defaults to -mod=readonly.
|
||||||
//
|
//
|
||||||
// If the go command is not invoked with a -mod flag and the vendor directory
|
// Note that neither "go get" nor the "go mod" subcommands accept the -mod flag.
|
||||||
// is present and the "go" version in go.mod is 1.14 or higher, the go command
|
|
||||||
// will act as if it were invoked with -mod=vendor.
|
|
||||||
//
|
//
|
||||||
// Pseudo-versions
|
// Pseudo-versions
|
||||||
//
|
//
|
||||||
@ -2806,7 +2898,7 @@
|
|||||||
// followed by a pipe character, indicating it is safe to fall back on any error.
|
// followed by a pipe character, indicating it is safe to fall back on any error.
|
||||||
//
|
//
|
||||||
// The GOPRIVATE and GONOPROXY environment variables allow bypassing
|
// The GOPRIVATE and GONOPROXY environment variables allow bypassing
|
||||||
// the proxy for selected modules. See 'go help module-private' for details.
|
// the proxy for selected modules. See 'go help private' for details.
|
||||||
//
|
//
|
||||||
// No matter the source of the modules, the go command checks downloads against
|
// No matter the source of the modules, the go command checks downloads against
|
||||||
// known checksums, to detect unexpected changes in the content of any specific
|
// known checksums, to detect unexpected changes in the content of any specific
|
||||||
@ -2926,52 +3018,7 @@
|
|||||||
// accepted, at the cost of giving up the security guarantee of verified repeatable
|
// accepted, at the cost of giving up the security guarantee of verified repeatable
|
||||||
// downloads for all modules. A better way to bypass the checksum database
|
// downloads for all modules. A better way to bypass the checksum database
|
||||||
// for specific modules is to use the GOPRIVATE or GONOSUMDB environment
|
// for specific modules is to use the GOPRIVATE or GONOSUMDB environment
|
||||||
// variables. See 'go help module-private' for details.
|
// variables. See 'go help private' for details.
|
||||||
//
|
|
||||||
// The 'go env -w' command (see 'go help env') can be used to set these variables
|
|
||||||
// for future go command invocations.
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Module configuration for non-public modules
|
|
||||||
//
|
|
||||||
// The go command defaults to downloading modules from the public Go module
|
|
||||||
// mirror at proxy.golang.org. It also defaults to validating downloaded modules,
|
|
||||||
// regardless of source, against the public Go checksum database at sum.golang.org.
|
|
||||||
// These defaults work well for publicly available source code.
|
|
||||||
//
|
|
||||||
// The GOPRIVATE environment variable controls which modules the go command
|
|
||||||
// considers to be private (not available publicly) and should therefore not use the
|
|
||||||
// proxy or checksum database. The variable is a comma-separated list of
|
|
||||||
// glob patterns (in the syntax of Go's path.Match) of module path prefixes.
|
|
||||||
// For example,
|
|
||||||
//
|
|
||||||
// GOPRIVATE=*.corp.example.com,rsc.io/private
|
|
||||||
//
|
|
||||||
// causes the go command to treat as private any module with a path prefix
|
|
||||||
// matching either pattern, including git.corp.example.com/xyzzy, rsc.io/private,
|
|
||||||
// and rsc.io/private/quux.
|
|
||||||
//
|
|
||||||
// The GOPRIVATE environment variable may be used by other tools as well to
|
|
||||||
// identify non-public modules. For example, an editor could use GOPRIVATE
|
|
||||||
// to decide whether to hyperlink a package import to a godoc.org page.
|
|
||||||
//
|
|
||||||
// For fine-grained control over module download and validation, the GONOPROXY
|
|
||||||
// and GONOSUMDB environment variables accept the same kind of glob list
|
|
||||||
// and override GOPRIVATE for the specific decision of whether to use the proxy
|
|
||||||
// and checksum database, respectively.
|
|
||||||
//
|
|
||||||
// For example, if a company ran a module proxy serving private modules,
|
|
||||||
// users would configure go using:
|
|
||||||
//
|
|
||||||
// GOPRIVATE=*.corp.example.com
|
|
||||||
// GOPROXY=proxy.example.com
|
|
||||||
// GONOPROXY=none
|
|
||||||
//
|
|
||||||
// This would tell the go command and other tools that modules beginning with
|
|
||||||
// a corp.example.com subdomain are private but that the company proxy should
|
|
||||||
// be used for downloading both public and private modules, because
|
|
||||||
// GONOPROXY has been set to a pattern that won't match any modules,
|
|
||||||
// overriding GOPRIVATE.
|
|
||||||
//
|
//
|
||||||
// The 'go env -w' command (see 'go help env') can be used to set these variables
|
// The 'go env -w' command (see 'go help env') can be used to set these variables
|
||||||
// for future go command invocations.
|
// for future go command invocations.
|
||||||
@ -3061,6 +3108,56 @@
|
|||||||
// by the go tool, as are directories named "testdata".
|
// by the go tool, as are directories named "testdata".
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
// Configuration for downloading non-public code
|
||||||
|
//
|
||||||
|
// The go command defaults to downloading modules from the public Go module
|
||||||
|
// mirror at proxy.golang.org. It also defaults to validating downloaded modules,
|
||||||
|
// regardless of source, against the public Go checksum database at sum.golang.org.
|
||||||
|
// These defaults work well for publicly available source code.
|
||||||
|
//
|
||||||
|
// The GOPRIVATE environment variable controls which modules the go command
|
||||||
|
// considers to be private (not available publicly) and should therefore not use the
|
||||||
|
// proxy or checksum database. The variable is a comma-separated list of
|
||||||
|
// glob patterns (in the syntax of Go's path.Match) of module path prefixes.
|
||||||
|
// For example,
|
||||||
|
//
|
||||||
|
// GOPRIVATE=*.corp.example.com,rsc.io/private
|
||||||
|
//
|
||||||
|
// causes the go command to treat as private any module with a path prefix
|
||||||
|
// matching either pattern, including git.corp.example.com/xyzzy, rsc.io/private,
|
||||||
|
// and rsc.io/private/quux.
|
||||||
|
//
|
||||||
|
// The GOPRIVATE environment variable may be used by other tools as well to
|
||||||
|
// identify non-public modules. For example, an editor could use GOPRIVATE
|
||||||
|
// to decide whether to hyperlink a package import to a godoc.org page.
|
||||||
|
//
|
||||||
|
// For fine-grained control over module download and validation, the GONOPROXY
|
||||||
|
// and GONOSUMDB environment variables accept the same kind of glob list
|
||||||
|
// and override GOPRIVATE for the specific decision of whether to use the proxy
|
||||||
|
// and checksum database, respectively.
|
||||||
|
//
|
||||||
|
// For example, if a company ran a module proxy serving private modules,
|
||||||
|
// users would configure go using:
|
||||||
|
//
|
||||||
|
// GOPRIVATE=*.corp.example.com
|
||||||
|
// GOPROXY=proxy.example.com
|
||||||
|
// GONOPROXY=none
|
||||||
|
//
|
||||||
|
// This would tell the go command and other tools that modules beginning with
|
||||||
|
// a corp.example.com subdomain are private but that the company proxy should
|
||||||
|
// be used for downloading both public and private modules, because
|
||||||
|
// GONOPROXY has been set to a pattern that won't match any modules,
|
||||||
|
// overriding GOPRIVATE.
|
||||||
|
//
|
||||||
|
// The GOPRIVATE variable is also used to define the "public" and "private"
|
||||||
|
// patterns for the GOVCS variable; see 'go help vcs'. For that usage,
|
||||||
|
// GOPRIVATE applies even in GOPATH mode. In that case, it matches import paths
|
||||||
|
// instead of module paths.
|
||||||
|
//
|
||||||
|
// The 'go env -w' command (see 'go help env') can be used to set these variables
|
||||||
|
// for future go command invocations.
|
||||||
|
//
|
||||||
|
//
|
||||||
// Testing flags
|
// Testing flags
|
||||||
//
|
//
|
||||||
// The 'go test' command takes both flags that apply to 'go test' itself
|
// The 'go test' command takes both flags that apply to 'go test' itself
|
||||||
@ -3353,4 +3450,77 @@
|
|||||||
// See the documentation of the testing package for more information.
|
// See the documentation of the testing package for more information.
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
// Controlling version control with GOVCS
|
||||||
|
//
|
||||||
|
// The 'go get' command can run version control commands like git
|
||||||
|
// to download imported code. This functionality is critical to the decentralized
|
||||||
|
// Go package ecosystem, in which code can be imported from any server,
|
||||||
|
// but it is also a potential security problem, if a malicious server finds a
|
||||||
|
// way to cause the invoked version control command to run unintended code.
|
||||||
|
//
|
||||||
|
// To balance the functionality and security concerns, the 'go get' command
|
||||||
|
// by default will only use git and hg to download code from public servers.
|
||||||
|
// But it will use any known version control system (bzr, fossil, git, hg, svn)
|
||||||
|
// to download code from private servers, defined as those hosting packages
|
||||||
|
// matching the GOPRIVATE variable (see 'go help private'). The rationale behind
|
||||||
|
// allowing only Git and Mercurial is that these two systems have had the most
|
||||||
|
// attention to issues of being run as clients of untrusted servers. In contrast,
|
||||||
|
// Bazaar, Fossil, and Subversion have primarily been used in trusted,
|
||||||
|
// authenticated environments and are not as well scrutinized as attack surfaces.
|
||||||
|
//
|
||||||
|
// The version control command restrictions only apply when using direct version
|
||||||
|
// control access to download code. When downloading modules from a proxy,
|
||||||
|
// 'go get' uses the proxy protocol instead, which is always permitted.
|
||||||
|
// By default, the 'go get' command uses the Go module mirror (proxy.golang.org)
|
||||||
|
// for public packages and only falls back to version control for private
|
||||||
|
// packages or when the mirror refuses to serve a public package (typically for
|
||||||
|
// legal reasons). Therefore, clients can still access public code served from
|
||||||
|
// Bazaar, Fossil, or Subversion repositories by default, because those downloads
|
||||||
|
// use the Go module mirror, which takes on the security risk of running the
|
||||||
|
// version control commands, using a custom sandbox.
|
||||||
|
//
|
||||||
|
// The GOVCS variable can be used to change the allowed version control systems
|
||||||
|
// for specific packages (identified by a module or import path).
|
||||||
|
// The GOVCS variable applies both when using modules and when using GOPATH.
|
||||||
|
// When using modules, the patterns match against the module path.
|
||||||
|
// When using GOPATH, the patterns match against the import path
|
||||||
|
// corresponding to the root of the version control repository.
|
||||||
|
//
|
||||||
|
// The general form of the GOVCS setting is a comma-separated list of
|
||||||
|
// pattern:vcslist rules. The pattern is a glob pattern that must match
|
||||||
|
// one or more leading elements of the module or import path. The vcslist
|
||||||
|
// is a pipe-separated list of allowed version control commands, or "all"
|
||||||
|
// to allow use of any known command, or "off" to allow nothing.
|
||||||
|
// The earliest matching pattern in the list applies, even if later patterns
|
||||||
|
// might also match.
|
||||||
|
//
|
||||||
|
// For example, consider:
|
||||||
|
//
|
||||||
|
// GOVCS=github.com:git,evil.com:off,*:git|hg
|
||||||
|
//
|
||||||
|
// With this setting, code with an module or import path beginning with
|
||||||
|
// github.com/ can only use git; paths on evil.com cannot use any version
|
||||||
|
// control command, and all other paths (* matches everything) can use
|
||||||
|
// only git or hg.
|
||||||
|
//
|
||||||
|
// The special patterns "public" and "private" match public and private
|
||||||
|
// module or import paths. A path is private if it matches the GOPRIVATE
|
||||||
|
// variable; otherwise it is public.
|
||||||
|
//
|
||||||
|
// If no rules in the GOVCS variable match a particular module or import path,
|
||||||
|
// the 'go get' command applies its default rule, which can now be summarized
|
||||||
|
// in GOVCS notation as 'public:git|hg,private:all'.
|
||||||
|
//
|
||||||
|
// To allow unfettered use of any version control system for any package, use:
|
||||||
|
//
|
||||||
|
// GOVCS=*:all
|
||||||
|
//
|
||||||
|
// To disable all use of version control, use:
|
||||||
|
//
|
||||||
|
// GOVCS=*:off
|
||||||
|
//
|
||||||
|
// The 'go env -w' command (see 'go help env') can be used to set the GOVCS
|
||||||
|
// variable for future go command invocations.
|
||||||
|
//
|
||||||
|
//
|
||||||
package main
|
package main
|
||||||
|
@ -9,13 +9,14 @@ import (
|
|||||||
"debug/elf"
|
"debug/elf"
|
||||||
"debug/macho"
|
"debug/macho"
|
||||||
"debug/pe"
|
"debug/pe"
|
||||||
|
"encoding/binary"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/format"
|
"go/format"
|
||||||
"internal/race"
|
"internal/race"
|
||||||
"internal/testenv"
|
"internal/testenv"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@ -30,77 +31,42 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// GOVCS defaults to public:git|hg,private:all,
|
||||||
|
// which breaks many tests here - they can't use non-git, non-hg VCS at all!
|
||||||
|
// Change to fully permissive.
|
||||||
|
// The tests of the GOVCS setting itself are in ../../testdata/script/govcs.txt.
|
||||||
|
os.Setenv("GOVCS", "*:all")
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
canRun = true // whether we can run go or ./testgo
|
|
||||||
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
|
||||||
|
|
||||||
exeSuffix string // ".exe" on Windows
|
|
||||||
|
|
||||||
skipExternal = false // skip external tests
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var exeSuffix string = func() string {
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
return ".exe"
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}()
|
||||||
|
|
||||||
func tooSlow(t *testing.T) {
|
func tooSlow(t *testing.T) {
|
||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
// In -short mode; skip test, except run it on the {darwin,linux,windows}/amd64 builders.
|
// In -short mode; skip test, except run it on the {darwin,linux,windows}/amd64 builders.
|
||||||
if testenv.Builder() != "" && runtime.GOARCH == "amd64" && (runtime.GOOS == "linux" || runtime.GOOS == "darwin" || runtime.GOOS == "windows") {
|
if testenv.Builder() != "" && runtime.GOARCH == "amd64" && (runtime.GOOS == "linux" || runtime.GOOS == "darwin" || runtime.GOOS == "windows") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
t.Helper()
|
||||||
t.Skip("skipping test in -short mode")
|
t.Skip("skipping test in -short mode")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
|
||||||
switch runtime.GOOS {
|
|
||||||
case "android", "js":
|
|
||||||
canRun = false
|
|
||||||
case "darwin":
|
|
||||||
switch runtime.GOARCH {
|
|
||||||
case "arm64":
|
|
||||||
canRun = false
|
|
||||||
}
|
|
||||||
case "linux":
|
|
||||||
switch runtime.GOARCH {
|
|
||||||
case "arm":
|
|
||||||
// many linux/arm machines are too slow to run
|
|
||||||
// the full set of external tests.
|
|
||||||
skipExternal = true
|
|
||||||
case "mips", "mipsle", "mips64", "mips64le":
|
|
||||||
// Also slow.
|
|
||||||
skipExternal = true
|
|
||||||
if testenv.Builder() != "" {
|
|
||||||
// On the builders, skip the cmd/go
|
|
||||||
// tests. They're too slow and already
|
|
||||||
// covered by other ports. There's
|
|
||||||
// nothing os/arch specific in the
|
|
||||||
// tests.
|
|
||||||
canRun = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case "freebsd":
|
|
||||||
switch runtime.GOARCH {
|
|
||||||
case "arm":
|
|
||||||
// many freebsd/arm machines are too slow to run
|
|
||||||
// the full set of external tests.
|
|
||||||
skipExternal = true
|
|
||||||
canRun = false
|
|
||||||
}
|
|
||||||
case "plan9":
|
|
||||||
switch runtime.GOARCH {
|
|
||||||
case "arm":
|
|
||||||
// many plan9/arm machines are too slow to run
|
|
||||||
// the full set of external tests.
|
|
||||||
skipExternal = true
|
|
||||||
}
|
|
||||||
case "windows":
|
|
||||||
exeSuffix = ".exe"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// testGOROOT is the GOROOT to use when running testgo, a cmd/go binary
|
// testGOROOT is the GOROOT to use when running testgo, a cmd/go binary
|
||||||
// build from this process's current GOROOT, but run from a different
|
// build from this process's current GOROOT, but run from a different
|
||||||
// (temp) directory.
|
// (temp) directory.
|
||||||
@ -134,7 +100,7 @@ func TestMain(m *testing.M) {
|
|||||||
|
|
||||||
// Run with a temporary TMPDIR to check that the tests don't
|
// Run with a temporary TMPDIR to check that the tests don't
|
||||||
// leave anything behind.
|
// leave anything behind.
|
||||||
topTmpdir, err := ioutil.TempDir("", "cmd-go-test-")
|
topTmpdir, err := os.MkdirTemp("", "cmd-go-test-")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -143,7 +109,7 @@ func TestMain(m *testing.M) {
|
|||||||
}
|
}
|
||||||
os.Setenv(tempEnvName(), topTmpdir)
|
os.Setenv(tempEnvName(), topTmpdir)
|
||||||
|
|
||||||
dir, err := ioutil.TempDir(topTmpdir, "tmpdir")
|
dir, err := os.MkdirTemp(topTmpdir, "tmpdir")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -153,7 +119,7 @@ func TestMain(m *testing.M) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
testGOCACHE = cache.DefaultDir()
|
testGOCACHE = cache.DefaultDir()
|
||||||
if canRun {
|
if testenv.HasGoBuild() {
|
||||||
testBin = filepath.Join(testTmpDir, "testbin")
|
testBin = filepath.Join(testTmpDir, "testbin")
|
||||||
if err := os.Mkdir(testBin, 0777); err != nil {
|
if err := os.Mkdir(testBin, 0777); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
@ -224,7 +190,7 @@ func TestMain(m *testing.M) {
|
|||||||
cmd.Stderr = new(strings.Builder)
|
cmd.Stderr = new(strings.Builder)
|
||||||
if out, err := cmd.Output(); err != nil {
|
if out, err := cmd.Output(); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "running testgo failed: %v\n%s", err, cmd.Stderr)
|
fmt.Fprintf(os.Stderr, "running testgo failed: %v\n%s", err, cmd.Stderr)
|
||||||
canRun = false
|
os.Exit(2)
|
||||||
} else {
|
} else {
|
||||||
canCgo, err = strconv.ParseBool(strings.TrimSpace(string(out)))
|
canCgo, err = strconv.ParseBool(strings.TrimSpace(string(out)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -324,10 +290,7 @@ func skipIfGccgo(t *testing.T, msg string) {
|
|||||||
func testgo(t *testing.T) *testgoData {
|
func testgo(t *testing.T) *testgoData {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
testenv.MustHaveGoBuild(t)
|
testenv.MustHaveGoBuild(t)
|
||||||
|
testenv.SkipIfShortAndSlow(t)
|
||||||
if skipExternal {
|
|
||||||
t.Skipf("skipping external tests on %s/%s", runtime.GOOS, runtime.GOARCH)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &testgoData{t: t}
|
return &testgoData{t: t}
|
||||||
}
|
}
|
||||||
@ -416,9 +379,6 @@ func (tg *testgoData) goTool() string {
|
|||||||
// returning exit status.
|
// returning exit status.
|
||||||
func (tg *testgoData) doRun(args []string) error {
|
func (tg *testgoData) doRun(args []string) error {
|
||||||
tg.t.Helper()
|
tg.t.Helper()
|
||||||
if !canRun {
|
|
||||||
panic("testgoData.doRun called but canRun false")
|
|
||||||
}
|
|
||||||
if tg.inParallel {
|
if tg.inParallel {
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
if strings.HasPrefix(arg, "testdata") || strings.HasPrefix(arg, "./testdata") {
|
if strings.HasPrefix(arg, "testdata") || strings.HasPrefix(arg, "./testdata") {
|
||||||
@ -656,7 +616,7 @@ func (tg *testgoData) makeTempdir() {
|
|||||||
tg.t.Helper()
|
tg.t.Helper()
|
||||||
if tg.tempdir == "" {
|
if tg.tempdir == "" {
|
||||||
var err error
|
var err error
|
||||||
tg.tempdir, err = ioutil.TempDir("", "gotest")
|
tg.tempdir, err = os.MkdirTemp("", "gotest")
|
||||||
tg.must(err)
|
tg.must(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -673,7 +633,7 @@ func (tg *testgoData) tempFile(path, contents string) {
|
|||||||
bytes = formatted
|
bytes = formatted
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tg.must(ioutil.WriteFile(filepath.Join(tg.tempdir, path), bytes, 0644))
|
tg.must(os.WriteFile(filepath.Join(tg.tempdir, path), bytes, 0644))
|
||||||
}
|
}
|
||||||
|
|
||||||
// tempDir adds a temporary directory for a run of testgo.
|
// tempDir adds a temporary directory for a run of testgo.
|
||||||
@ -814,7 +774,7 @@ func (tg *testgoData) cleanup() {
|
|||||||
func removeAll(dir string) error {
|
func removeAll(dir string) error {
|
||||||
// module cache has 0444 directories;
|
// module cache has 0444 directories;
|
||||||
// make them writable in order to remove content.
|
// make them writable in order to remove content.
|
||||||
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
filepath.WalkDir(dir, func(path string, info fs.DirEntry, err error) error {
|
||||||
// chmod not only directories, but also things that we couldn't even stat
|
// chmod not only directories, but also things that we couldn't even stat
|
||||||
// due to permission errors: they may also be unreadable directories.
|
// due to permission errors: they may also be unreadable directories.
|
||||||
if err != nil || info.IsDir() {
|
if err != nil || info.IsDir() {
|
||||||
@ -860,8 +820,8 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
|
|||||||
} {
|
} {
|
||||||
srcdir := filepath.Join(testGOROOT, copydir)
|
srcdir := filepath.Join(testGOROOT, copydir)
|
||||||
tg.tempDir(filepath.Join("goroot", copydir))
|
tg.tempDir(filepath.Join("goroot", copydir))
|
||||||
err := filepath.Walk(srcdir,
|
err := filepath.WalkDir(srcdir,
|
||||||
func(path string, info os.FileInfo, err error) error {
|
func(path string, info fs.DirEntry, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -873,13 +833,13 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
dest := filepath.Join("goroot", copydir, srcrel)
|
dest := filepath.Join("goroot", copydir, srcrel)
|
||||||
data, err := ioutil.ReadFile(path)
|
data, err := os.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
tg.tempFile(dest, string(data))
|
tg.tempFile(dest, string(data))
|
||||||
if err := os.Chmod(tg.path(dest), info.Mode()|0200); err != nil {
|
if strings.Contains(copydir, filepath.Join("pkg", "tool")) {
|
||||||
return err
|
os.Chmod(tg.path(dest), 0777)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
@ -890,18 +850,18 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
|
|||||||
tg.setenv("GOROOT", tg.path("goroot"))
|
tg.setenv("GOROOT", tg.path("goroot"))
|
||||||
|
|
||||||
addVar := func(name string, idx int) (restore func()) {
|
addVar := func(name string, idx int) (restore func()) {
|
||||||
data, err := ioutil.ReadFile(name)
|
data, err := os.ReadFile(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
old := data
|
old := data
|
||||||
data = append(data, fmt.Sprintf("var DummyUnusedVar%d bool\n", idx)...)
|
data = append(data, fmt.Sprintf("var DummyUnusedVar%d bool\n", idx)...)
|
||||||
if err := ioutil.WriteFile(name, append(data, '\n'), 0666); err != nil {
|
if err := os.WriteFile(name, append(data, '\n'), 0666); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
tg.sleep()
|
tg.sleep()
|
||||||
return func() {
|
return func() {
|
||||||
if err := ioutil.WriteFile(name, old, 0666); err != nil {
|
if err := os.WriteFile(name, old, 0666); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1237,6 +1197,18 @@ func TestGoListExport(t *testing.T) {
|
|||||||
if _, err := os.Stat(file); err != nil {
|
if _, err := os.Stat(file); err != nil {
|
||||||
t.Fatalf("cannot find .Export result %s: %v", file, err)
|
t.Fatalf("cannot find .Export result %s: %v", file, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tg.run("list", "-export", "-f", "{{.BuildID}}", "strings")
|
||||||
|
buildID := strings.TrimSpace(tg.stdout.String())
|
||||||
|
if buildID == "" {
|
||||||
|
t.Fatalf(".BuildID with -export was empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
tg.run("tool", "buildid", file)
|
||||||
|
toolBuildID := strings.TrimSpace(tg.stdout.String())
|
||||||
|
if buildID != toolBuildID {
|
||||||
|
t.Fatalf(".BuildID with -export %q disagrees with 'go tool buildid' %q", buildID, toolBuildID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Issue 4096. Validate the output of unsuccessful go install foo/quxx.
|
// Issue 4096. Validate the output of unsuccessful go install foo/quxx.
|
||||||
@ -1394,6 +1366,30 @@ func TestLdflagsArgumentsWithSpacesIssue3941(t *testing.T) {
|
|||||||
tg.grepStderr("^hello world", `ldflags -X "main.extern=hello world"' failed`)
|
tg.grepStderr("^hello world", `ldflags -X "main.extern=hello world"' failed`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLdFlagsLongArgumentsIssue42295(t *testing.T) {
|
||||||
|
// Test the extremely long command line arguments that contain '\n' characters
|
||||||
|
// get encoded and passed correctly.
|
||||||
|
skipIfGccgo(t, "gccgo does not support -ldflags -X")
|
||||||
|
tooSlow(t)
|
||||||
|
tg := testgo(t)
|
||||||
|
defer tg.cleanup()
|
||||||
|
tg.parallel()
|
||||||
|
tg.tempFile("main.go", `package main
|
||||||
|
var extern string
|
||||||
|
func main() {
|
||||||
|
print(extern)
|
||||||
|
}`)
|
||||||
|
testStr := "test test test test test \n\\ "
|
||||||
|
var buf bytes.Buffer
|
||||||
|
for buf.Len() < work.ArgLengthForResponseFile+1 {
|
||||||
|
buf.WriteString(testStr)
|
||||||
|
}
|
||||||
|
tg.run("run", "-ldflags", fmt.Sprintf(`-X "main.extern=%s"`, buf.String()), tg.path("main.go"))
|
||||||
|
if tg.stderr.String() != buf.String() {
|
||||||
|
t.Errorf("strings differ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestGoTestDashCDashOControlsBinaryLocation(t *testing.T) {
|
func TestGoTestDashCDashOControlsBinaryLocation(t *testing.T) {
|
||||||
skipIfGccgo(t, "gccgo has no standard packages")
|
skipIfGccgo(t, "gccgo has no standard packages")
|
||||||
tooSlow(t)
|
tooSlow(t)
|
||||||
@ -1914,6 +1910,18 @@ func TestGoEnv(t *testing.T) {
|
|||||||
tg.grepStdout("gcc", "CC not found")
|
tg.grepStdout("gcc", "CC not found")
|
||||||
tg.run("env", "GOGCCFLAGS")
|
tg.run("env", "GOGCCFLAGS")
|
||||||
tg.grepStdout("-ffaster", "CC arguments not found")
|
tg.grepStdout("-ffaster", "CC arguments not found")
|
||||||
|
|
||||||
|
tg.run("env", "GOVERSION")
|
||||||
|
envVersion := strings.TrimSpace(tg.stdout.String())
|
||||||
|
|
||||||
|
tg.run("version")
|
||||||
|
cmdVersion := strings.TrimSpace(tg.stdout.String())
|
||||||
|
|
||||||
|
// If 'go version' is "go version <version> <goos>/<goarch>", then
|
||||||
|
// 'go env GOVERSION' is just "<version>".
|
||||||
|
if cmdVersion == envVersion || !strings.Contains(cmdVersion, envVersion) {
|
||||||
|
t.Fatalf("'go env GOVERSION' %q should be a shorter substring of 'go version' %q", envVersion, cmdVersion)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -2019,7 +2027,7 @@ func main() {
|
|||||||
tg.run("build", "-o", exe, "p")
|
tg.run("build", "-o", exe, "p")
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyFile(src, dst string, perm os.FileMode) error {
|
func copyFile(src, dst string, perm fs.FileMode) error {
|
||||||
sf, err := os.Open(src)
|
sf, err := os.Open(src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -2058,7 +2066,7 @@ func TestBuildmodePIE(t *testing.T) {
|
|||||||
|
|
||||||
platform := fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH)
|
platform := fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH)
|
||||||
switch platform {
|
switch platform {
|
||||||
case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x",
|
case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/riscv64", "linux/s390x",
|
||||||
"android/amd64", "android/arm", "android/arm64", "android/386",
|
"android/amd64", "android/arm", "android/arm64", "android/386",
|
||||||
"freebsd/amd64",
|
"freebsd/amd64",
|
||||||
"windows/386", "windows/amd64", "windows/arm":
|
"windows/386", "windows/amd64", "windows/arm":
|
||||||
@ -2166,6 +2174,38 @@ func testBuildmodePIE(t *testing.T, useCgo, setBuildmodeToPIE bool) {
|
|||||||
if (dc & pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) == 0 {
|
if (dc & pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) == 0 {
|
||||||
t.Error("IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE flag is not set")
|
t.Error("IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE flag is not set")
|
||||||
}
|
}
|
||||||
|
if useCgo {
|
||||||
|
// Test that only one symbol is exported (#40795).
|
||||||
|
// PIE binaries don´t require .edata section but unfortunately
|
||||||
|
// binutils doesn´t generate a .reloc section unless there is
|
||||||
|
// at least one symbol exported.
|
||||||
|
// See https://sourceware.org/bugzilla/show_bug.cgi?id=19011
|
||||||
|
section := f.Section(".edata")
|
||||||
|
if section == nil {
|
||||||
|
t.Fatalf(".edata section is not present")
|
||||||
|
}
|
||||||
|
// TODO: deduplicate this struct from cmd/link/internal/ld/pe.go
|
||||||
|
type IMAGE_EXPORT_DIRECTORY struct {
|
||||||
|
_ [2]uint32
|
||||||
|
_ [2]uint16
|
||||||
|
_ [2]uint32
|
||||||
|
NumberOfFunctions uint32
|
||||||
|
NumberOfNames uint32
|
||||||
|
_ [3]uint32
|
||||||
|
}
|
||||||
|
var e IMAGE_EXPORT_DIRECTORY
|
||||||
|
if err := binary.Read(section.Open(), binary.LittleEndian, &e); err != nil {
|
||||||
|
t.Fatalf("binary.Read failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only _cgo_dummy_export should be exported
|
||||||
|
if e.NumberOfFunctions != 1 {
|
||||||
|
t.Fatalf("got %d exported functions; want 1", e.NumberOfFunctions)
|
||||||
|
}
|
||||||
|
if e.NumberOfNames != 1 {
|
||||||
|
t.Fatalf("got %d exported names; want 1", e.NumberOfNames)
|
||||||
|
}
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
panic("unreachable")
|
panic("unreachable")
|
||||||
}
|
}
|
||||||
@ -2658,7 +2698,7 @@ echo $* >>`+tg.path("pkg-config.out"))
|
|||||||
tg.setenv("GOPATH", tg.path("."))
|
tg.setenv("GOPATH", tg.path("."))
|
||||||
tg.setenv("PKG_CONFIG", tg.path("pkg-config.sh"))
|
tg.setenv("PKG_CONFIG", tg.path("pkg-config.sh"))
|
||||||
tg.run("build", "x")
|
tg.run("build", "x")
|
||||||
out, err := ioutil.ReadFile(tg.path("pkg-config.out"))
|
out, err := os.ReadFile(tg.path("pkg-config.out"))
|
||||||
tg.must(err)
|
tg.must(err)
|
||||||
out = bytes.TrimSpace(out)
|
out = bytes.TrimSpace(out)
|
||||||
want := "--cflags --static --static -- a a\n--libs --static --static -- a a"
|
want := "--cflags --static --static -- a a\n--libs --static --static -- a a"
|
||||||
|
@ -2,11 +2,9 @@
|
|||||||
// 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.
|
||||||
|
|
||||||
package main
|
package main_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"internal/testenv"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -17,16 +15,18 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestAbsolutePath(t *testing.T) {
|
func TestAbsolutePath(t *testing.T) {
|
||||||
t.Parallel()
|
tg := testgo(t)
|
||||||
|
defer tg.cleanup()
|
||||||
|
tg.parallel()
|
||||||
|
|
||||||
tmp, err := ioutil.TempDir("", "TestAbsolutePath")
|
tmp, err := os.MkdirTemp("", "TestAbsolutePath")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer robustio.RemoveAll(tmp)
|
defer robustio.RemoveAll(tmp)
|
||||||
|
|
||||||
file := filepath.Join(tmp, "a.go")
|
file := filepath.Join(tmp, "a.go")
|
||||||
err = ioutil.WriteFile(file, []byte{}, 0644)
|
err = os.WriteFile(file, []byte{}, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -38,7 +38,7 @@ func TestAbsolutePath(t *testing.T) {
|
|||||||
|
|
||||||
noVolume := file[len(filepath.VolumeName(file)):]
|
noVolume := file[len(filepath.VolumeName(file)):]
|
||||||
wrongPath := filepath.Join(dir, noVolume)
|
wrongPath := filepath.Join(dir, noVolume)
|
||||||
cmd := exec.Command(testenv.GoToolPath(t), "build", noVolume)
|
cmd := exec.Command(tg.goTool(), "build", noVolume)
|
||||||
cmd.Dir = dir
|
cmd.Dir = dir
|
||||||
output, err := cmd.CombinedOutput()
|
output, err := cmd.CombinedOutput()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -6,7 +6,7 @@ package main_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"io/ioutil"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"cmd/go/internal/help"
|
"cmd/go/internal/help"
|
||||||
@ -23,7 +23,7 @@ func TestDocsUpToDate(t *testing.T) {
|
|||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
// Match the command in mkalldocs.sh that generates alldocs.go.
|
// Match the command in mkalldocs.sh that generates alldocs.go.
|
||||||
help.Help(buf, []string{"documentation"})
|
help.Help(buf, []string{"documentation"})
|
||||||
data, err := ioutil.ReadFile("alldocs.go")
|
data, err := os.ReadFile("alldocs.go")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error reading alldocs.go: %v", err)
|
t.Fatalf("error reading alldocs.go: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ package main_test
|
|||||||
import (
|
import (
|
||||||
"internal/testenv"
|
"internal/testenv"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -15,20 +16,27 @@ import (
|
|||||||
// the benchmark if any changes were done.
|
// the benchmark if any changes were done.
|
||||||
func BenchmarkExecGoEnv(b *testing.B) {
|
func BenchmarkExecGoEnv(b *testing.B) {
|
||||||
testenv.MustHaveExec(b)
|
testenv.MustHaveExec(b)
|
||||||
b.StopTimer()
|
|
||||||
gotool, err := testenv.GoTool()
|
gotool, err := testenv.GoTool()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
cmd := exec.Command(gotool, "env", "GOARCH")
|
|
||||||
|
|
||||||
b.StartTimer()
|
// We collect extra metrics.
|
||||||
err := cmd.Run()
|
var n, userTime, systemTime int64
|
||||||
b.StopTimer()
|
|
||||||
|
|
||||||
if err != nil {
|
b.ResetTimer()
|
||||||
b.Fatal(err)
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
|
for pb.Next() {
|
||||||
|
cmd := exec.Command(gotool, "env", "GOARCH")
|
||||||
|
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
atomic.AddInt64(&n, 1)
|
||||||
|
atomic.AddInt64(&userTime, int64(cmd.ProcessState.UserTime()))
|
||||||
|
atomic.AddInt64(&systemTime, int64(cmd.ProcessState.SystemTime()))
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
b.ReportMetric(float64(userTime)/float64(n), "user-ns/op")
|
||||||
|
b.ReportMetric(float64(systemTime)/float64(n), "sys-ns/op")
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
package auth
|
package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
@ -99,7 +98,7 @@ func readNetrc() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := ioutil.ReadFile(path)
|
data, err := os.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !os.IsNotExist(err) {
|
if !os.IsNotExist(err) {
|
||||||
netrcErr = err
|
netrcErr = err
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
package base
|
package base
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
@ -24,7 +25,7 @@ import (
|
|||||||
type Command struct {
|
type Command struct {
|
||||||
// Run runs the command.
|
// Run runs the command.
|
||||||
// The args are the arguments after the command name.
|
// The args are the arguments after the command name.
|
||||||
Run func(cmd *Command, args []string)
|
Run func(ctx context.Context, cmd *Command, args []string)
|
||||||
|
|
||||||
// UsageLine is the one-line usage message.
|
// UsageLine is the one-line usage message.
|
||||||
// The words between "go" and the first flag or argument in the line are taken to be the command name.
|
// The words between "go" and the first flag or argument in the line are taken to be the command name.
|
||||||
@ -55,6 +56,20 @@ var Go = &Command{
|
|||||||
// Commands initialized in package main
|
// Commands initialized in package main
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// hasFlag reports whether a command or any of its subcommands contain the given
|
||||||
|
// flag.
|
||||||
|
func hasFlag(c *Command, name string) bool {
|
||||||
|
if f := c.Flag.Lookup(name); f != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
for _, sub := range c.Commands {
|
||||||
|
if hasFlag(sub, name) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// LongName returns the command's long name: all the words in the usage line between "go" and a flag or argument,
|
// LongName returns the command's long name: all the words in the usage line between "go" and a flag or argument,
|
||||||
func (c *Command) LongName() string {
|
func (c *Command) LongName() string {
|
||||||
name := c.UsageLine
|
name := c.UsageLine
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
|
|
||||||
"cmd/go/internal/cfg"
|
"cmd/go/internal/cfg"
|
||||||
|
"cmd/go/internal/fsys"
|
||||||
"cmd/go/internal/str"
|
"cmd/go/internal/str"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -28,13 +29,43 @@ func (v *StringsFlag) String() string {
|
|||||||
return "<StringsFlag>"
|
return "<StringsFlag>"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// explicitStringFlag is like a regular string flag, but it also tracks whether
|
||||||
|
// the string was set explicitly to a non-empty value.
|
||||||
|
type explicitStringFlag struct {
|
||||||
|
value *string
|
||||||
|
explicit *bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f explicitStringFlag) String() string {
|
||||||
|
if f.value == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return *f.value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f explicitStringFlag) Set(v string) error {
|
||||||
|
*f.value = v
|
||||||
|
if v != "" {
|
||||||
|
*f.explicit = true
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// AddBuildFlagsNX adds the -n and -x build flags to the flag set.
|
// AddBuildFlagsNX adds the -n and -x build flags to the flag set.
|
||||||
func AddBuildFlagsNX(flags *flag.FlagSet) {
|
func AddBuildFlagsNX(flags *flag.FlagSet) {
|
||||||
flags.BoolVar(&cfg.BuildN, "n", false, "")
|
flags.BoolVar(&cfg.BuildN, "n", false, "")
|
||||||
flags.BoolVar(&cfg.BuildX, "x", false, "")
|
flags.BoolVar(&cfg.BuildX, "x", false, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddLoadFlags adds the -mod build flag to the flag set.
|
// AddModFlag adds the -mod build flag to the flag set.
|
||||||
func AddLoadFlags(flags *flag.FlagSet) {
|
func AddModFlag(flags *flag.FlagSet) {
|
||||||
flags.StringVar(&cfg.BuildMod, "mod", "", "")
|
flags.Var(explicitStringFlag{value: &cfg.BuildMod, explicit: &cfg.BuildModExplicit}, "mod", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddModCommonFlags adds the module-related flags common to build commands
|
||||||
|
// and 'go mod' subcommands.
|
||||||
|
func AddModCommonFlags(flags *flag.FlagSet) {
|
||||||
|
flags.BoolVar(&cfg.ModCacheRW, "modcacherw", false, "")
|
||||||
|
flags.StringVar(&cfg.ModFile, "modfile", "", "")
|
||||||
|
flags.StringVar(&fsys.OverlayFile, "overlay", "", "")
|
||||||
}
|
}
|
||||||
|
@ -13,15 +13,7 @@ import (
|
|||||||
"cmd/go/internal/cfg"
|
"cmd/go/internal/cfg"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var goflags []string // cached $GOFLAGS list; can be -x or --x form
|
||||||
goflags []string // cached $GOFLAGS list; can be -x or --x form
|
|
||||||
knownFlag = make(map[string]bool) // flags allowed to appear in $GOFLAGS; no leading dashes
|
|
||||||
)
|
|
||||||
|
|
||||||
// AddKnownFlag adds name to the list of known flags for use in $GOFLAGS.
|
|
||||||
func AddKnownFlag(name string) {
|
|
||||||
knownFlag[name] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// GOFLAGS returns the flags from $GOFLAGS.
|
// GOFLAGS returns the flags from $GOFLAGS.
|
||||||
// The list can be assumed to contain one string per flag,
|
// The list can be assumed to contain one string per flag,
|
||||||
@ -38,22 +30,12 @@ func InitGOFLAGS() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build list of all flags for all commands.
|
goflags = strings.Fields(cfg.Getenv("GOFLAGS"))
|
||||||
// If no command has that flag, then we report the problem.
|
if len(goflags) == 0 {
|
||||||
// This catches typos while still letting users record flags in GOFLAGS
|
// nothing to do; avoid work on later InitGOFLAGS call
|
||||||
// that only apply to a subset of go commands.
|
goflags = []string{}
|
||||||
// Commands using CustomFlags can report their flag names
|
return
|
||||||
// by calling AddKnownFlag instead.
|
|
||||||
var walkFlags func(*Command)
|
|
||||||
walkFlags = func(cmd *Command) {
|
|
||||||
for _, sub := range cmd.Commands {
|
|
||||||
walkFlags(sub)
|
|
||||||
}
|
|
||||||
cmd.Flag.VisitAll(func(f *flag.Flag) {
|
|
||||||
knownFlag[f.Name] = true
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
walkFlags(Go)
|
|
||||||
|
|
||||||
// Ignore bad flag in go env and go bug, because
|
// Ignore bad flag in go env and go bug, because
|
||||||
// they are what people reach for when debugging
|
// they are what people reach for when debugging
|
||||||
@ -61,11 +43,6 @@ func InitGOFLAGS() {
|
|||||||
// (Both will show the GOFLAGS setting if let succeed.)
|
// (Both will show the GOFLAGS setting if let succeed.)
|
||||||
hideErrors := cfg.CmdName == "env" || cfg.CmdName == "bug"
|
hideErrors := cfg.CmdName == "env" || cfg.CmdName == "bug"
|
||||||
|
|
||||||
goflags = strings.Fields(cfg.Getenv("GOFLAGS"))
|
|
||||||
if goflags == nil {
|
|
||||||
goflags = []string{} // avoid work on later InitGOFLAGS call
|
|
||||||
}
|
|
||||||
|
|
||||||
// Each of the words returned by strings.Fields must be its own flag.
|
// Each of the words returned by strings.Fields must be its own flag.
|
||||||
// To set flag arguments use -x=value instead of -x value.
|
// To set flag arguments use -x=value instead of -x value.
|
||||||
// For boolean flags, -x is fine instead of -x=true.
|
// For boolean flags, -x is fine instead of -x=true.
|
||||||
@ -85,7 +62,7 @@ func InitGOFLAGS() {
|
|||||||
if i := strings.Index(name, "="); i >= 0 {
|
if i := strings.Index(name, "="); i >= 0 {
|
||||||
name = name[:i]
|
name = name[:i]
|
||||||
}
|
}
|
||||||
if !knownFlag[name] {
|
if !hasFlag(Go, name) {
|
||||||
if hideErrors {
|
if hideErrors {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -115,7 +92,11 @@ func SetFromGOFLAGS(flags *flag.FlagSet) {
|
|||||||
}
|
}
|
||||||
for _, goflag := range goflags {
|
for _, goflag := range goflags {
|
||||||
name, value, hasValue := goflag, "", false
|
name, value, hasValue := goflag, "", false
|
||||||
if i := strings.Index(goflag, "="); i >= 0 {
|
// Ignore invalid flags like '=' or '=value'.
|
||||||
|
// If it is not reported in InitGOFlags it means we don't want to report it.
|
||||||
|
if i := strings.Index(goflag, "="); i == 0 {
|
||||||
|
continue
|
||||||
|
} else if i > 0 {
|
||||||
name, value, hasValue = goflag[:i], goflag[i+1:], true
|
name, value, hasValue = goflag[:i], goflag[i+1:], true
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(name, "--") {
|
if strings.HasPrefix(name, "--") {
|
||||||
|
@ -15,7 +15,7 @@ var Interrupted = make(chan struct{})
|
|||||||
|
|
||||||
// processSignals setups signal handler.
|
// processSignals setups signal handler.
|
||||||
func processSignals() {
|
func processSignals() {
|
||||||
sig := make(chan os.Signal)
|
sig := make(chan os.Signal, 1)
|
||||||
signal.Notify(sig, signalsToIgnore...)
|
signal.Notify(sig, signalsToIgnore...)
|
||||||
go func() {
|
go func() {
|
||||||
<-sig
|
<-sig
|
||||||
|
@ -7,9 +7,9 @@ package bug
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
urlpkg "net/url"
|
urlpkg "net/url"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@ -37,7 +37,7 @@ func init() {
|
|||||||
CmdBug.Flag.BoolVar(&cfg.BuildV, "v", false, "")
|
CmdBug.Flag.BoolVar(&cfg.BuildV, "v", false, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func runBug(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: bug takes no arguments")
|
||||||
}
|
}
|
||||||
@ -104,7 +104,7 @@ func printGoDetails(w io.Writer) {
|
|||||||
|
|
||||||
func printOSDetails(w io.Writer) {
|
func printOSDetails(w io.Writer) {
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "darwin":
|
case "darwin", "ios":
|
||||||
printCmdOut(w, "uname -v: ", "uname", "-v")
|
printCmdOut(w, "uname -v: ", "uname", "-v")
|
||||||
printCmdOut(w, "", "sw_vers")
|
printCmdOut(w, "", "sw_vers")
|
||||||
case "linux":
|
case "linux":
|
||||||
@ -116,7 +116,7 @@ func printOSDetails(w io.Writer) {
|
|||||||
case "illumos", "solaris":
|
case "illumos", "solaris":
|
||||||
// Be sure to use the OS-supplied uname, in "/usr/bin":
|
// Be sure to use the OS-supplied uname, in "/usr/bin":
|
||||||
printCmdOut(w, "uname -srv: ", "/usr/bin/uname", "-srv")
|
printCmdOut(w, "uname -srv: ", "/usr/bin/uname", "-srv")
|
||||||
out, err := ioutil.ReadFile("/etc/release")
|
out, err := os.ReadFile("/etc/release")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
fmt.Fprintf(w, "/etc/release: %s\n", out)
|
fmt.Fprintf(w, "/etc/release: %s\n", out)
|
||||||
} else {
|
} else {
|
||||||
@ -176,7 +176,7 @@ func printGlibcVersion(w io.Writer) {
|
|||||||
src := []byte(`int main() {}`)
|
src := []byte(`int main() {}`)
|
||||||
srcfile := filepath.Join(tempdir, "go-bug.c")
|
srcfile := filepath.Join(tempdir, "go-bug.c")
|
||||||
outfile := filepath.Join(tempdir, "go-bug")
|
outfile := filepath.Join(tempdir, "go-bug")
|
||||||
err := ioutil.WriteFile(srcfile, src, 0644)
|
err := os.WriteFile(srcfile, src, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
8
libgo/go/cmd/go/internal/cache/cache.go
vendored
8
libgo/go/cmd/go/internal/cache/cache.go
vendored
@ -12,7 +12,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -54,7 +54,7 @@ func Open(dir string) (*Cache, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if !info.IsDir() {
|
if !info.IsDir() {
|
||||||
return nil, &os.PathError{Op: "open", Path: dir, Err: fmt.Errorf("not a directory")}
|
return nil, &fs.PathError{Op: "open", Path: dir, Err: fmt.Errorf("not a directory")}
|
||||||
}
|
}
|
||||||
for i := 0; i < 256; i++ {
|
for i := 0; i < 256; i++ {
|
||||||
name := filepath.Join(dir, fmt.Sprintf("%02x", i))
|
name := filepath.Join(dir, fmt.Sprintf("%02x", i))
|
||||||
@ -238,7 +238,7 @@ func (c *Cache) GetBytes(id ActionID) ([]byte, Entry, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, entry, err
|
return nil, entry, err
|
||||||
}
|
}
|
||||||
data, _ := ioutil.ReadFile(c.OutputFile(entry.OutputID))
|
data, _ := os.ReadFile(c.OutputFile(entry.OutputID))
|
||||||
if sha256.Sum256(data) != entry.OutputID {
|
if sha256.Sum256(data) != entry.OutputID {
|
||||||
return nil, entry, &entryNotFoundError{Err: errors.New("bad checksum")}
|
return nil, entry, &entryNotFoundError{Err: errors.New("bad checksum")}
|
||||||
}
|
}
|
||||||
@ -377,7 +377,7 @@ func (c *Cache) putIndexEntry(id ActionID, out OutputID, size int64, allowVerify
|
|||||||
// Truncate the file only *after* writing it.
|
// Truncate the file only *after* writing it.
|
||||||
// (This should be a no-op, but truncate just in case of previous corruption.)
|
// (This should be a no-op, but truncate just in case of previous corruption.)
|
||||||
//
|
//
|
||||||
// This differs from ioutil.WriteFile, which truncates to 0 *before* writing
|
// This differs from os.WriteFile, which truncates to 0 *before* writing
|
||||||
// via os.O_TRUNC. Truncating only after writing ensures that a second write
|
// via os.O_TRUNC. Truncating only after writing ensures that a second write
|
||||||
// of the same content to the same file is idempotent, and does not — even
|
// of the same content to the same file is idempotent, and does not — even
|
||||||
// temporarily! — undo the effect of the first write.
|
// temporarily! — undo the effect of the first write.
|
||||||
|
13
libgo/go/cmd/go/internal/cache/cache_test.go
vendored
13
libgo/go/cmd/go/internal/cache/cache_test.go
vendored
@ -8,7 +8,6 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
@ -20,7 +19,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestBasic(t *testing.T) {
|
func TestBasic(t *testing.T) {
|
||||||
dir, err := ioutil.TempDir("", "cachetest-")
|
dir, err := os.MkdirTemp("", "cachetest-")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -65,7 +64,7 @@ func TestBasic(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGrowth(t *testing.T) {
|
func TestGrowth(t *testing.T) {
|
||||||
dir, err := ioutil.TempDir("", "cachetest-")
|
dir, err := os.MkdirTemp("", "cachetest-")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -118,7 +117,7 @@ func TestVerifyPanic(t *testing.T) {
|
|||||||
t.Fatal("initEnv did not set verify")
|
t.Fatal("initEnv did not set verify")
|
||||||
}
|
}
|
||||||
|
|
||||||
dir, err := ioutil.TempDir("", "cachetest-")
|
dir, err := os.MkdirTemp("", "cachetest-")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -151,7 +150,7 @@ func dummyID(x int) [HashSize]byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCacheTrim(t *testing.T) {
|
func TestCacheTrim(t *testing.T) {
|
||||||
dir, err := ioutil.TempDir("", "cachetest-")
|
dir, err := os.MkdirTemp("", "cachetest-")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -207,7 +206,7 @@ func TestCacheTrim(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
c.OutputFile(entry.OutputID)
|
c.OutputFile(entry.OutputID)
|
||||||
data, err := ioutil.ReadFile(filepath.Join(dir, "trim.txt"))
|
data, err := os.ReadFile(filepath.Join(dir, "trim.txt"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -220,7 +219,7 @@ func TestCacheTrim(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
c.OutputFile(entry.OutputID)
|
c.OutputFile(entry.OutputID)
|
||||||
data2, err := ioutil.ReadFile(filepath.Join(dir, "trim.txt"))
|
data2, err := os.ReadFile(filepath.Join(dir, "trim.txt"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
3
libgo/go/cmd/go/internal/cache/default.go
vendored
3
libgo/go/cmd/go/internal/cache/default.go
vendored
@ -6,7 +6,6 @@ package cache
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sync"
|
"sync"
|
||||||
@ -49,7 +48,7 @@ func initDefaultCache() {
|
|||||||
}
|
}
|
||||||
if _, err := os.Stat(filepath.Join(dir, "README")); err != nil {
|
if _, err := os.Stat(filepath.Join(dir, "README")); err != nil {
|
||||||
// Best effort.
|
// Best effort.
|
||||||
ioutil.WriteFile(filepath.Join(dir, "README"), []byte(cacheREADME), 0666)
|
os.WriteFile(filepath.Join(dir, "README"), []byte(cacheREADME), 0666)
|
||||||
}
|
}
|
||||||
|
|
||||||
c, err := Open(dir)
|
c, err := Open(dir)
|
||||||
|
3
libgo/go/cmd/go/internal/cache/hash_test.go
vendored
3
libgo/go/cmd/go/internal/cache/hash_test.go
vendored
@ -6,7 +6,6 @@ package cache
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
@ -28,7 +27,7 @@ func TestHash(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestHashFile(t *testing.T) {
|
func TestHashFile(t *testing.T) {
|
||||||
f, err := ioutil.TempFile("", "cmd-go-test-")
|
f, err := os.CreateTemp("", "cmd-go-test-")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -11,13 +11,15 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"go/build"
|
"go/build"
|
||||||
"internal/cfg"
|
"internal/cfg"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"cmd/go/internal/fsys"
|
||||||
|
|
||||||
"cmd/internal/objabi"
|
"cmd/internal/objabi"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -27,7 +29,8 @@ var (
|
|||||||
BuildBuildmode string // -buildmode flag
|
BuildBuildmode string // -buildmode flag
|
||||||
BuildContext = defaultContext()
|
BuildContext = defaultContext()
|
||||||
BuildMod string // -mod flag
|
BuildMod string // -mod flag
|
||||||
BuildModReason string // reason -mod flag is set, if set by default
|
BuildModExplicit bool // whether -mod was set explicitly
|
||||||
|
BuildModReason string // reason -mod was set, if set by default
|
||||||
BuildI bool // -i flag
|
BuildI bool // -i flag
|
||||||
BuildLinkshared bool // -linkshared flag
|
BuildLinkshared bool // -linkshared flag
|
||||||
BuildMSan bool // -msan flag
|
BuildMSan bool // -msan flag
|
||||||
@ -48,9 +51,12 @@ var (
|
|||||||
ModCacheRW bool // -modcacherw flag
|
ModCacheRW bool // -modcacherw flag
|
||||||
ModFile string // -modfile flag
|
ModFile string // -modfile flag
|
||||||
|
|
||||||
|
Insecure bool // -insecure flag
|
||||||
|
|
||||||
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
|
||||||
)
|
)
|
||||||
|
|
||||||
func defaultContext() build.Context {
|
func defaultContext() build.Context {
|
||||||
@ -100,6 +106,15 @@ func defaultContext() build.Context {
|
|||||||
// Nothing to do here.
|
// Nothing to do here.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctxt.OpenFile = func(path string) (io.ReadCloser, error) {
|
||||||
|
return fsys.Open(path)
|
||||||
|
}
|
||||||
|
ctxt.ReadDir = fsys.ReadDir
|
||||||
|
ctxt.IsDir = func(path string) bool {
|
||||||
|
isDir, err := fsys.IsDir(path)
|
||||||
|
return err == nil && isDir
|
||||||
|
}
|
||||||
|
|
||||||
return ctxt
|
return ctxt
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,7 +186,7 @@ func initEnvCache() {
|
|||||||
if file == "" {
|
if file == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
data, err := ioutil.ReadFile(file)
|
data, err := os.ReadFile(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -252,6 +267,7 @@ var (
|
|||||||
GONOPROXY = envOr("GONOPROXY", GOPRIVATE)
|
GONOPROXY = envOr("GONOPROXY", GOPRIVATE)
|
||||||
GONOSUMDB = envOr("GONOSUMDB", GOPRIVATE)
|
GONOSUMDB = envOr("GONOSUMDB", GOPRIVATE)
|
||||||
GOINSECURE = Getenv("GOINSECURE")
|
GOINSECURE = Getenv("GOINSECURE")
|
||||||
|
GOVCS = Getenv("GOVCS")
|
||||||
)
|
)
|
||||||
|
|
||||||
var SumdbDir = gopathDir("pkg/sumdb")
|
var SumdbDir = gopathDir("pkg/sumdb")
|
||||||
|
@ -6,8 +6,9 @@
|
|||||||
package clean
|
package clean
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -105,7 +106,7 @@ func init() {
|
|||||||
work.AddBuildFlags(CmdClean, work.DefaultBuildFlags)
|
work.AddBuildFlags(CmdClean, work.DefaultBuildFlags)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runClean(cmd *base.Command, args []string) {
|
func runClean(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
// golang.org/issue/29925: only load packages before cleaning if
|
// golang.org/issue/29925: only load packages before cleaning if
|
||||||
// either the flags and arguments explicitly imply a package,
|
// either the flags and arguments explicitly imply a package,
|
||||||
// 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.
|
||||||
@ -116,7 +117,7 @@ func runClean(cmd *base.Command, args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if cleanPkg {
|
if cleanPkg {
|
||||||
for _, pkg := range load.PackagesAndErrors(args) {
|
for _, pkg := range load.PackagesAndErrors(ctx, args) {
|
||||||
clean(pkg)
|
clean(pkg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -171,7 +172,7 @@ func runClean(cmd *base.Command, args []string) {
|
|||||||
f, err := lockedfile.Edit(filepath.Join(dir, "testexpire.txt"))
|
f, err := lockedfile.Edit(filepath.Join(dir, "testexpire.txt"))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
now := time.Now().UnixNano()
|
now := time.Now().UnixNano()
|
||||||
buf, _ := ioutil.ReadAll(f)
|
buf, _ := io.ReadAll(f)
|
||||||
prev, _ := strconv.ParseInt(strings.TrimSpace(string(buf)), 10, 64)
|
prev, _ := strconv.ParseInt(strings.TrimSpace(string(buf)), 10, 64)
|
||||||
if now > prev {
|
if now > prev {
|
||||||
if err = f.Truncate(0); err == nil {
|
if err = f.Truncate(0); err == nil {
|
||||||
@ -242,7 +243,7 @@ func clean(p *load.Package) {
|
|||||||
base.Errorf("%v", p.Error)
|
base.Errorf("%v", p.Error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
dirs, err := ioutil.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 clean %s: %v", p.Dir, err)
|
||||||
return
|
return
|
||||||
@ -274,6 +275,8 @@ func clean(p *load.Package) {
|
|||||||
allRemove = append(allRemove,
|
allRemove = append(allRemove,
|
||||||
elem,
|
elem,
|
||||||
elem+".exe",
|
elem+".exe",
|
||||||
|
p.DefaultExecName(),
|
||||||
|
p.DefaultExecName()+".exe",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,16 +284,28 @@ func clean(p *load.Package) {
|
|||||||
allRemove = append(allRemove,
|
allRemove = append(allRemove,
|
||||||
elem+".test",
|
elem+".test",
|
||||||
elem+".test.exe",
|
elem+".test.exe",
|
||||||
|
p.DefaultExecName()+".test",
|
||||||
|
p.DefaultExecName()+".test.exe",
|
||||||
)
|
)
|
||||||
|
|
||||||
// Remove a potential executable for each .go file in the directory that
|
// Remove a potential executable, test executable for each .go file in the directory that
|
||||||
// is not part of the directory's package.
|
// is not part of the directory's package.
|
||||||
for _, dir := range dirs {
|
for _, dir := range dirs {
|
||||||
name := dir.Name()
|
name := dir.Name()
|
||||||
if packageFile[name] {
|
if packageFile[name] {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !dir.IsDir() && strings.HasSuffix(name, ".go") {
|
|
||||||
|
if dir.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasSuffix(name, "_test.go") {
|
||||||
|
base := name[:len(name)-len("_test.go")]
|
||||||
|
allRemove = append(allRemove, base+".test", base+".test.exe")
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasSuffix(name, ".go") {
|
||||||
// TODO(adg,rsc): check that this .go file is actually
|
// TODO(adg,rsc): check that this .go file is actually
|
||||||
// in "package main", and therefore capable of building
|
// in "package main", and therefore capable of building
|
||||||
// to an executable file.
|
// to an executable file.
|
||||||
|
@ -8,6 +8,7 @@ package doc
|
|||||||
import (
|
import (
|
||||||
"cmd/go/internal/base"
|
"cmd/go/internal/base"
|
||||||
"cmd/go/internal/cfg"
|
"cmd/go/internal/cfg"
|
||||||
|
"context"
|
||||||
)
|
)
|
||||||
|
|
||||||
var CmdDoc = &base.Command{
|
var CmdDoc = &base.Command{
|
||||||
@ -129,6 +130,6 @@ Flags:
|
|||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDoc(cmd *base.Command, args []string) {
|
func runDoc(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
base.Run(cfg.BuildToolexec, base.Tool("doc"), args)
|
base.Run(cfg.BuildToolexec, base.Tool("doc"), args)
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,10 @@
|
|||||||
package envcmd
|
package envcmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/build"
|
"go/build"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
@ -20,6 +20,7 @@ import (
|
|||||||
"cmd/go/internal/base"
|
"cmd/go/internal/base"
|
||||||
"cmd/go/internal/cache"
|
"cmd/go/internal/cache"
|
||||||
"cmd/go/internal/cfg"
|
"cmd/go/internal/cfg"
|
||||||
|
"cmd/go/internal/fsys"
|
||||||
"cmd/go/internal/load"
|
"cmd/go/internal/load"
|
||||||
"cmd/go/internal/modload"
|
"cmd/go/internal/modload"
|
||||||
"cmd/go/internal/work"
|
"cmd/go/internal/work"
|
||||||
@ -62,9 +63,6 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func MkEnv() []cfg.EnvVar {
|
func MkEnv() []cfg.EnvVar {
|
||||||
var b work.Builder
|
|
||||||
b.Init()
|
|
||||||
|
|
||||||
envFile, _ := cfg.EnvFile()
|
envFile, _ := cfg.EnvFile()
|
||||||
env := []cfg.EnvVar{
|
env := []cfg.EnvVar{
|
||||||
{Name: "GO111MODULE", Value: cfg.Getenv("GO111MODULE")},
|
{Name: "GO111MODULE", Value: cfg.Getenv("GO111MODULE")},
|
||||||
@ -88,6 +86,8 @@ func MkEnv() []cfg.EnvVar {
|
|||||||
{Name: "GOSUMDB", Value: cfg.GOSUMDB},
|
{Name: "GOSUMDB", Value: cfg.GOSUMDB},
|
||||||
{Name: "GOTMPDIR", Value: cfg.Getenv("GOTMPDIR")},
|
{Name: "GOTMPDIR", Value: cfg.Getenv("GOTMPDIR")},
|
||||||
{Name: "GOTOOLDIR", Value: base.ToolDir},
|
{Name: "GOTOOLDIR", Value: base.ToolDir},
|
||||||
|
{Name: "GOVCS", Value: cfg.GOVCS},
|
||||||
|
{Name: "GOVERSION", Value: runtime.Version()},
|
||||||
}
|
}
|
||||||
|
|
||||||
if work.GccgoBin != "" {
|
if work.GccgoBin != "" {
|
||||||
@ -186,7 +186,7 @@ func argKey(arg string) string {
|
|||||||
return arg[:i]
|
return arg[:i]
|
||||||
}
|
}
|
||||||
|
|
||||||
func runEnv(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 env: cannot use -json with -u")
|
||||||
}
|
}
|
||||||
@ -199,12 +199,26 @@ func runEnv(cmd *base.Command, args []string) {
|
|||||||
env := cfg.CmdEnv
|
env := cfg.CmdEnv
|
||||||
env = append(env, ExtraEnvVars()...)
|
env = append(env, ExtraEnvVars()...)
|
||||||
|
|
||||||
|
if err := fsys.Init(base.Cwd); err != nil {
|
||||||
|
base.Fatalf("go: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Do we need to call ExtraEnvVarsCostly, which is a bit expensive?
|
// Do we need to call ExtraEnvVarsCostly, which is a bit expensive?
|
||||||
// Only if we're listing all environment variables ("go env")
|
needCostly := false
|
||||||
// or the variables being requested are in the extra list.
|
if *envU || *envW {
|
||||||
needCostly := true
|
// We're overwriting or removing default settings,
|
||||||
if len(args) > 0 {
|
// so it doesn't really matter what the existing settings are.
|
||||||
|
//
|
||||||
|
// Moreover, we haven't validated the new settings yet, so it is
|
||||||
|
// important that we NOT perform any actions based on them,
|
||||||
|
// such as initializing the builder to compute other variables.
|
||||||
|
} else if len(args) == 0 {
|
||||||
|
// We're listing all environment variables ("go env"),
|
||||||
|
// including the expensive ones.
|
||||||
|
needCostly = true
|
||||||
|
} else {
|
||||||
needCostly = false
|
needCostly = false
|
||||||
|
checkCostly:
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
switch argKey(arg) {
|
switch argKey(arg) {
|
||||||
case "CGO_CFLAGS",
|
case "CGO_CFLAGS",
|
||||||
@ -215,6 +229,7 @@ func runEnv(cmd *base.Command, args []string) {
|
|||||||
"PKG_CONFIG",
|
"PKG_CONFIG",
|
||||||
"GOGCCFLAGS":
|
"GOGCCFLAGS":
|
||||||
needCostly = true
|
needCostly = true
|
||||||
|
break checkCostly
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -266,6 +281,13 @@ func runEnv(cmd *base.Command, args []string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gotmp, okGOTMP := add["GOTMPDIR"]
|
||||||
|
if okGOTMP {
|
||||||
|
if !filepath.IsAbs(gotmp) && gotmp != "" {
|
||||||
|
base.Fatalf("go env -w: GOTMPDIR must be an absolute path")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
updateEnvFile(add, nil)
|
updateEnvFile(add, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -377,7 +399,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":
|
case "GOEXE", "GOGCCFLAGS", "GOHOSTARCH", "GOHOSTOS", "GOMOD", "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)
|
||||||
@ -405,6 +427,11 @@ 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 "CC", "CXX":
|
||||||
|
if !filepath.IsAbs(val) && val != "" && val != filepath.Base(val) {
|
||||||
|
return fmt.Errorf("%s entry is relative; must be absolute path: %q", key, val)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !utf8.ValidString(val) {
|
if !utf8.ValidString(val) {
|
||||||
@ -424,7 +451,7 @@ func updateEnvFile(add map[string]string, del map[string]bool) {
|
|||||||
if file == "" {
|
if file == "" {
|
||||||
base.Fatalf("go env: cannot find go env config: %v", err)
|
base.Fatalf("go env: cannot find go env config: %v", err)
|
||||||
}
|
}
|
||||||
data, err := ioutil.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 env: reading go env config: %v", err)
|
||||||
}
|
}
|
||||||
@ -478,11 +505,11 @@ func updateEnvFile(add map[string]string, del map[string]bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
data = []byte(strings.Join(lines, ""))
|
data = []byte(strings.Join(lines, ""))
|
||||||
err = ioutil.WriteFile(file, data, 0666)
|
err = os.WriteFile(file, data, 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Try creating directory.
|
// Try creating directory.
|
||||||
os.MkdirAll(filepath.Dir(file), 0777)
|
os.MkdirAll(filepath.Dir(file), 0777)
|
||||||
err = ioutil.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 env: writing go env config: %v", err)
|
||||||
}
|
}
|
||||||
@ -499,7 +526,10 @@ func lineToKey(line string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// sortKeyValues sorts a sequence of lines by key.
|
// sortKeyValues sorts a sequence of lines by key.
|
||||||
// It differs from sort.Strings in that GO386= sorts after GO=.
|
// It differs from sort.Strings in that keys which are GOx where x is an ASCII
|
||||||
|
// character smaller than = sort after GO=.
|
||||||
|
// (There are no such keys currently. It used to matter for GO386 which was
|
||||||
|
// removed in Go 1.16.)
|
||||||
func sortKeyValues(lines []string) {
|
func sortKeyValues(lines []string) {
|
||||||
sort.Slice(lines, func(i, j int) bool {
|
sort.Slice(lines, func(i, j int) bool {
|
||||||
return lineToKey(lines[i]) < lineToKey(lines[j])
|
return lineToKey(lines[i]) < lineToKey(lines[j])
|
||||||
|
@ -11,6 +11,7 @@ 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"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
@ -31,9 +32,21 @@ See also: go fmt, go vet.
|
|||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
|
||||||
func runFix(cmd *base.Command, args []string) {
|
func runFix(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
|
pkgs := load.PackagesAndErrors(ctx, args)
|
||||||
|
w := 0
|
||||||
|
for _, pkg := range pkgs {
|
||||||
|
if pkg.Error != nil {
|
||||||
|
base.Errorf("%v", pkg.Error)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
pkgs[w] = pkg
|
||||||
|
w++
|
||||||
|
}
|
||||||
|
pkgs = pkgs[:w]
|
||||||
|
|
||||||
printed := false
|
printed := false
|
||||||
for _, pkg := range load.Packages(args) {
|
for _, pkg := range pkgs {
|
||||||
if modload.Enabled() && pkg.Module != nil && !pkg.Module.Main {
|
if modload.Enabled() && pkg.Module != nil && !pkg.Module.Main {
|
||||||
if !printed {
|
if !printed {
|
||||||
fmt.Fprintf(os.Stderr, "go: not fixing packages in dependency modules\n")
|
fmt.Fprintf(os.Stderr, "go: not fixing packages in dependency modules\n")
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
package fmtcmd
|
package fmtcmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
@ -22,7 +23,8 @@ import (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
base.AddBuildFlagsNX(&CmdFmt.Flag)
|
base.AddBuildFlagsNX(&CmdFmt.Flag)
|
||||||
base.AddLoadFlags(&CmdFmt.Flag)
|
base.AddModFlag(&CmdFmt.Flag)
|
||||||
|
base.AddModCommonFlags(&CmdFmt.Flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
var CmdFmt = &base.Command{
|
var CmdFmt = &base.Command{
|
||||||
@ -48,7 +50,7 @@ See also: go fix, go vet.
|
|||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
|
||||||
func runFmt(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)
|
procs := runtime.GOMAXPROCS(0)
|
||||||
@ -63,7 +65,7 @@ func runFmt(cmd *base.Command, args []string) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
for _, pkg := range load.PackagesAndErrors(args) {
|
for _, pkg := range load.PackagesAndErrors(ctx, args) {
|
||||||
if modload.Enabled() && pkg.Module != nil && !pkg.Module.Main {
|
if modload.Enabled() && pkg.Module != nil && !pkg.Module.Main {
|
||||||
if !printed {
|
if !printed {
|
||||||
fmt.Fprintf(os.Stderr, "go: not formatting packages in dependency modules\n")
|
fmt.Fprintf(os.Stderr, "go: not formatting packages in dependency modules\n")
|
||||||
|
689
libgo/go/cmd/go/internal/fsys/fsys.go
Normal file
689
libgo/go/cmd/go/internal/fsys/fsys.go
Normal file
@ -0,0 +1,689 @@
|
|||||||
|
// Package fsys is an abstraction for reading files that
|
||||||
|
// allows for virtual overlays on top of the files on disk.
|
||||||
|
package fsys
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OverlayFile is the path to a text file in the OverlayJSON format.
|
||||||
|
// It is the value of the -overlay flag.
|
||||||
|
var OverlayFile string
|
||||||
|
|
||||||
|
// OverlayJSON is the format overlay files are expected to be in.
|
||||||
|
// The Replace map maps from overlaid paths to replacement paths:
|
||||||
|
// the Go command will forward all reads trying to open
|
||||||
|
// each overlaid path to its replacement path, or consider the overlaid
|
||||||
|
// path not to exist if the replacement path is empty.
|
||||||
|
type OverlayJSON struct {
|
||||||
|
Replace map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
type node struct {
|
||||||
|
actualFilePath string // empty if a directory
|
||||||
|
children map[string]*node // path element → file or directory
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *node) isDir() bool {
|
||||||
|
return n.actualFilePath == "" && n.children != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *node) isDeleted() bool {
|
||||||
|
return n.actualFilePath == "" && n.children == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(matloob): encapsulate these in an io/fs-like interface
|
||||||
|
var overlay map[string]*node // path -> file or directory node
|
||||||
|
var cwd string // copy of base.Cwd to avoid dependency
|
||||||
|
|
||||||
|
// Canonicalize a path for looking it up in the overlay.
|
||||||
|
// Important: filepath.Join(cwd, path) doesn't always produce
|
||||||
|
// the correct absolute path if path is relative, because on
|
||||||
|
// Windows producing the correct absolute path requires making
|
||||||
|
// a syscall. So this should only be used when looking up paths
|
||||||
|
// in the overlay, or canonicalizing the paths in the overlay.
|
||||||
|
func canonicalize(path string) string {
|
||||||
|
if path == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if filepath.IsAbs(path) {
|
||||||
|
return filepath.Clean(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v := filepath.VolumeName(cwd); v != "" && path[0] == filepath.Separator {
|
||||||
|
// On Windows filepath.Join(cwd, path) doesn't always work. In general
|
||||||
|
// filepath.Abs needs to make a syscall on Windows. Elsewhere in cmd/go
|
||||||
|
// use filepath.Join(cwd, path), but cmd/go specifically supports Windows
|
||||||
|
// paths that start with "\" which implies the path is relative to the
|
||||||
|
// volume of the working directory. See golang.org/issue/8130.
|
||||||
|
return filepath.Join(v, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make the path absolute.
|
||||||
|
return filepath.Join(cwd, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init initializes the overlay, if one is being used.
|
||||||
|
func Init(wd string) error {
|
||||||
|
if overlay != nil {
|
||||||
|
// already initialized
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cwd = wd
|
||||||
|
|
||||||
|
if OverlayFile == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := os.ReadFile(OverlayFile)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("reading overlay file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var overlayJSON OverlayJSON
|
||||||
|
if err := json.Unmarshal(b, &overlayJSON); err != nil {
|
||||||
|
return fmt.Errorf("parsing overlay JSON: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return initFromJSON(overlayJSON)
|
||||||
|
}
|
||||||
|
|
||||||
|
func initFromJSON(overlayJSON OverlayJSON) error {
|
||||||
|
// Canonicalize the paths in in the overlay map.
|
||||||
|
// Use reverseCanonicalized to check for collisions:
|
||||||
|
// no two 'from' paths should canonicalize to the same path.
|
||||||
|
overlay = make(map[string]*node)
|
||||||
|
reverseCanonicalized := make(map[string]string) // inverse of canonicalize operation, to check for duplicates
|
||||||
|
// Build a table of file and directory nodes from the replacement map.
|
||||||
|
|
||||||
|
// Remove any potential non-determinism from iterating over map by sorting it.
|
||||||
|
replaceFrom := make([]string, 0, len(overlayJSON.Replace))
|
||||||
|
for k := range overlayJSON.Replace {
|
||||||
|
replaceFrom = append(replaceFrom, k)
|
||||||
|
}
|
||||||
|
sort.Strings(replaceFrom)
|
||||||
|
|
||||||
|
for _, from := range replaceFrom {
|
||||||
|
to := overlayJSON.Replace[from]
|
||||||
|
// Canonicalize paths and check for a collision.
|
||||||
|
if from == "" {
|
||||||
|
return fmt.Errorf("empty string key in overlay file Replace map")
|
||||||
|
}
|
||||||
|
cfrom := canonicalize(from)
|
||||||
|
if to != "" {
|
||||||
|
// Don't canonicalize "", meaning to delete a file, because then it will turn into ".".
|
||||||
|
to = canonicalize(to)
|
||||||
|
}
|
||||||
|
if otherFrom, seen := reverseCanonicalized[cfrom]; seen {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"paths %q and %q both canonicalize to %q in overlay file Replace map", otherFrom, from, cfrom)
|
||||||
|
}
|
||||||
|
reverseCanonicalized[cfrom] = from
|
||||||
|
from = cfrom
|
||||||
|
|
||||||
|
// Create node for overlaid file.
|
||||||
|
dir, base := filepath.Dir(from), filepath.Base(from)
|
||||||
|
if n, ok := overlay[from]; ok {
|
||||||
|
// All 'from' paths in the overlay are file paths. Since the from paths
|
||||||
|
// are in a map, they are unique, so if the node already exists we added
|
||||||
|
// it below when we create parent directory nodes. That is, that
|
||||||
|
// both a file and a path to one of its parent directories exist as keys
|
||||||
|
// in the Replace map.
|
||||||
|
//
|
||||||
|
// This only applies if the overlay directory has any files or directories
|
||||||
|
// in it: placeholder directories that only contain deleted files don't
|
||||||
|
// count. They are safe to be overwritten with actual files.
|
||||||
|
for _, f := range n.children {
|
||||||
|
if !f.isDeleted() {
|
||||||
|
return fmt.Errorf("invalid overlay: path %v is used as both file and directory", from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
overlay[from] = &node{actualFilePath: to}
|
||||||
|
|
||||||
|
// Add parent directory nodes to overlay structure.
|
||||||
|
childNode := overlay[from]
|
||||||
|
for {
|
||||||
|
dirNode := overlay[dir]
|
||||||
|
if dirNode == nil || dirNode.isDeleted() {
|
||||||
|
dirNode = &node{children: make(map[string]*node)}
|
||||||
|
overlay[dir] = dirNode
|
||||||
|
}
|
||||||
|
if childNode.isDeleted() {
|
||||||
|
// Only create one parent for a deleted file:
|
||||||
|
// the directory only conditionally exists if
|
||||||
|
// there are any non-deleted children, so
|
||||||
|
// we don't create their parents.
|
||||||
|
if dirNode.isDir() {
|
||||||
|
dirNode.children[base] = childNode
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if !dirNode.isDir() {
|
||||||
|
// This path already exists as a file, so it can't be a parent
|
||||||
|
// directory. See comment at error above.
|
||||||
|
return fmt.Errorf("invalid overlay: path %v is used as both file and directory", dir)
|
||||||
|
}
|
||||||
|
dirNode.children[base] = childNode
|
||||||
|
parent := filepath.Dir(dir)
|
||||||
|
if parent == dir {
|
||||||
|
break // reached the top; there is no parent
|
||||||
|
}
|
||||||
|
dir, base = parent, filepath.Base(dir)
|
||||||
|
childNode = dirNode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsDir returns true if path is a directory on disk or in the
|
||||||
|
// overlay.
|
||||||
|
func IsDir(path string) (bool, error) {
|
||||||
|
path = canonicalize(path)
|
||||||
|
|
||||||
|
if _, ok := parentIsOverlayFile(path); ok {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, ok := overlay[path]; ok {
|
||||||
|
return n.isDir(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fi, err := os.Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fi.IsDir(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// parentIsOverlayFile returns whether name or any of
|
||||||
|
// its parents are files in the overlay, and the first parent found,
|
||||||
|
// including name itself, that's a file in the overlay.
|
||||||
|
func parentIsOverlayFile(name string) (string, bool) {
|
||||||
|
if overlay != nil {
|
||||||
|
// Check if name can't possibly be a directory because
|
||||||
|
// it or one of its parents is overlaid with a file.
|
||||||
|
// TODO(matloob): Maybe save this to avoid doing it every time?
|
||||||
|
prefix := name
|
||||||
|
for {
|
||||||
|
node := overlay[prefix]
|
||||||
|
if node != nil && !node.isDir() {
|
||||||
|
return prefix, true
|
||||||
|
}
|
||||||
|
parent := filepath.Dir(prefix)
|
||||||
|
if parent == prefix {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
prefix = parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
// errNotDir is used to communicate from ReadDir to IsDirWithGoFiles
|
||||||
|
// that the argument is not a directory, so that IsDirWithGoFiles doesn't
|
||||||
|
// return an error.
|
||||||
|
var errNotDir = errors.New("not a directory")
|
||||||
|
|
||||||
|
// readDir reads a dir on disk, returning an error that is errNotDir if the dir is not a directory.
|
||||||
|
// Unfortunately, the error returned by ioutil.ReadDir if dir is not a directory
|
||||||
|
// can vary depending on the OS (Linux, Mac, Windows return ENOTDIR; BSD returns EINVAL).
|
||||||
|
func readDir(dir string) ([]fs.FileInfo, error) {
|
||||||
|
fis, err := ioutil.ReadDir(dir)
|
||||||
|
if err == nil {
|
||||||
|
return fis, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if dirfi, staterr := os.Stat(dir); staterr == nil && !dirfi.IsDir() {
|
||||||
|
return nil, &fs.PathError{Op: "ReadDir", Path: dir, Err: errNotDir}
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadDir provides a slice of fs.FileInfo entries corresponding
|
||||||
|
// to the overlaid files in the directory.
|
||||||
|
func ReadDir(dir string) ([]fs.FileInfo, error) {
|
||||||
|
dir = canonicalize(dir)
|
||||||
|
if _, ok := parentIsOverlayFile(dir); ok {
|
||||||
|
return nil, &fs.PathError{Op: "ReadDir", Path: dir, Err: errNotDir}
|
||||||
|
}
|
||||||
|
|
||||||
|
dirNode := overlay[dir]
|
||||||
|
if dirNode == nil {
|
||||||
|
return readDir(dir)
|
||||||
|
}
|
||||||
|
if dirNode.isDeleted() {
|
||||||
|
return nil, &fs.PathError{Op: "ReadDir", Path: dir, Err: fs.ErrNotExist}
|
||||||
|
}
|
||||||
|
diskfis, err := readDir(dir)
|
||||||
|
if err != nil && !os.IsNotExist(err) && !errors.Is(err, errNotDir) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stat files in overlay to make composite list of fileinfos
|
||||||
|
files := make(map[string]fs.FileInfo)
|
||||||
|
for _, f := range diskfis {
|
||||||
|
files[f.Name()] = f
|
||||||
|
}
|
||||||
|
for name, to := range dirNode.children {
|
||||||
|
switch {
|
||||||
|
case to.isDir():
|
||||||
|
files[name] = fakeDir(name)
|
||||||
|
case to.isDeleted():
|
||||||
|
delete(files, name)
|
||||||
|
default:
|
||||||
|
// This is a regular file.
|
||||||
|
f, err := os.Lstat(to.actualFilePath)
|
||||||
|
if err != nil {
|
||||||
|
files[name] = missingFile(name)
|
||||||
|
continue
|
||||||
|
} else if f.IsDir() {
|
||||||
|
return nil, fmt.Errorf("for overlay of %q to %q: overlay Replace entries can't point to dirctories",
|
||||||
|
filepath.Join(dir, name), to.actualFilePath)
|
||||||
|
}
|
||||||
|
// Add a fileinfo for the overlaid file, so that it has
|
||||||
|
// the original file's name, but the overlaid file's metadata.
|
||||||
|
files[name] = fakeFile{name, f}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sortedFiles := diskfis[:0]
|
||||||
|
for _, f := range files {
|
||||||
|
sortedFiles = append(sortedFiles, f)
|
||||||
|
}
|
||||||
|
sort.Slice(sortedFiles, func(i, j int) bool { return sortedFiles[i].Name() < sortedFiles[j].Name() })
|
||||||
|
return sortedFiles, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// OverlayPath returns the path to the overlaid contents of the
|
||||||
|
// file, the empty string if the overlay deletes the file, or path
|
||||||
|
// itself if the file is not in the overlay, the file is a directory
|
||||||
|
// in the overlay, or there is no overlay.
|
||||||
|
// It returns true if the path is overlaid with a regular file
|
||||||
|
// or deleted, and false otherwise.
|
||||||
|
func OverlayPath(path string) (string, bool) {
|
||||||
|
if p, ok := overlay[canonicalize(path)]; ok && !p.isDir() {
|
||||||
|
return p.actualFilePath, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
return path, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open opens the file at or overlaid on the given path.
|
||||||
|
func Open(path string) (*os.File, error) {
|
||||||
|
return OpenFile(path, os.O_RDONLY, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenFile opens the file at or overlaid on the given path with the flag and perm.
|
||||||
|
func OpenFile(path string, flag int, perm os.FileMode) (*os.File, error) {
|
||||||
|
cpath := canonicalize(path)
|
||||||
|
if node, ok := overlay[cpath]; ok {
|
||||||
|
// Opening a file in the overlay.
|
||||||
|
if node.isDir() {
|
||||||
|
return nil, &fs.PathError{Op: "OpenFile", Path: path, Err: errors.New("fsys.OpenFile doesn't support opening directories yet")}
|
||||||
|
}
|
||||||
|
// We can't open overlaid paths for write.
|
||||||
|
if perm != os.FileMode(os.O_RDONLY) {
|
||||||
|
return nil, &fs.PathError{Op: "OpenFile", Path: path, Err: errors.New("overlaid files can't be opened for write")}
|
||||||
|
}
|
||||||
|
return os.OpenFile(node.actualFilePath, flag, perm)
|
||||||
|
}
|
||||||
|
if parent, ok := parentIsOverlayFile(filepath.Dir(cpath)); ok {
|
||||||
|
// The file is deleted explicitly in the Replace map,
|
||||||
|
// or implicitly because one of its parent directories was
|
||||||
|
// replaced by a file.
|
||||||
|
return nil, &fs.PathError{
|
||||||
|
Op: "Open",
|
||||||
|
Path: path,
|
||||||
|
Err: fmt.Errorf("file %s does not exist: parent directory %s is replaced by a file in overlay", path, parent),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return os.OpenFile(cpath, flag, perm)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsDirWithGoFiles reports whether dir is a directory containing Go files
|
||||||
|
// either on disk or in the overlay.
|
||||||
|
func IsDirWithGoFiles(dir string) (bool, error) {
|
||||||
|
fis, err := ReadDir(dir)
|
||||||
|
if os.IsNotExist(err) || errors.Is(err, errNotDir) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var firstErr error
|
||||||
|
for _, fi := range fis {
|
||||||
|
if fi.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(matloob): this enforces that the "from" in the map
|
||||||
|
// has a .go suffix, but the actual destination file
|
||||||
|
// doesn't need to have a .go suffix. Is this okay with the
|
||||||
|
// compiler?
|
||||||
|
if !strings.HasSuffix(fi.Name(), ".go") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if fi.Mode().IsRegular() {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// fi is the result of an Lstat, so it doesn't follow symlinks.
|
||||||
|
// But it's okay if the file is a symlink pointing to a regular
|
||||||
|
// file, so use os.Stat to follow symlinks and check that.
|
||||||
|
actualFilePath, _ := OverlayPath(filepath.Join(dir, fi.Name()))
|
||||||
|
fi, err := os.Stat(actualFilePath)
|
||||||
|
if err == nil && fi.Mode().IsRegular() {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
if err != nil && firstErr == nil {
|
||||||
|
firstErr = err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No go files found in directory.
|
||||||
|
return false, firstErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// walk recursively descends path, calling walkFn. Copied, with some
|
||||||
|
// modifications from path/filepath.walk.
|
||||||
|
func walk(path string, info fs.FileInfo, walkFn filepath.WalkFunc) error {
|
||||||
|
if !info.IsDir() {
|
||||||
|
return walkFn(path, info, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
fis, readErr := ReadDir(path)
|
||||||
|
walkErr := walkFn(path, info, readErr)
|
||||||
|
// If readErr != nil, walk can't walk into this directory.
|
||||||
|
// walkErr != nil means walkFn want walk to skip this directory or stop walking.
|
||||||
|
// Therefore, if one of readErr and walkErr isn't nil, walk will return.
|
||||||
|
if readErr != nil || walkErr != nil {
|
||||||
|
// The caller's behavior is controlled by the return value, which is decided
|
||||||
|
// by walkFn. walkFn may ignore readErr and return nil.
|
||||||
|
// If walkFn returns SkipDir, it will be handled by the caller.
|
||||||
|
// So walk should return whatever walkFn returns.
|
||||||
|
return walkErr
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, fi := range fis {
|
||||||
|
filename := filepath.Join(path, fi.Name())
|
||||||
|
if walkErr = walk(filename, fi, walkFn); walkErr != nil {
|
||||||
|
if !fi.IsDir() || walkErr != filepath.SkipDir {
|
||||||
|
return walkErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walk walks the file tree rooted at root, calling walkFn for each file or
|
||||||
|
// directory in the tree, including root.
|
||||||
|
func Walk(root string, walkFn filepath.WalkFunc) error {
|
||||||
|
info, err := Lstat(root)
|
||||||
|
if err != nil {
|
||||||
|
err = walkFn(root, nil, err)
|
||||||
|
} else {
|
||||||
|
err = walk(root, info, walkFn)
|
||||||
|
}
|
||||||
|
if err == filepath.SkipDir {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// lstat implements a version of os.Lstat that operates on the overlay filesystem.
|
||||||
|
func Lstat(path string) (fs.FileInfo, error) {
|
||||||
|
return overlayStat(path, os.Lstat, "lstat")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stat implements a version of os.Stat that operates on the overlay filesystem.
|
||||||
|
func Stat(path string) (fs.FileInfo, error) {
|
||||||
|
return overlayStat(path, os.Stat, "stat")
|
||||||
|
}
|
||||||
|
|
||||||
|
// overlayStat implements lstat or Stat (depending on whether os.Lstat or os.Stat is passed in).
|
||||||
|
func overlayStat(path string, osStat func(string) (fs.FileInfo, error), opName string) (fs.FileInfo, error) {
|
||||||
|
cpath := canonicalize(path)
|
||||||
|
|
||||||
|
if _, ok := parentIsOverlayFile(filepath.Dir(cpath)); ok {
|
||||||
|
return nil, &fs.PathError{Op: opName, Path: cpath, Err: fs.ErrNotExist}
|
||||||
|
}
|
||||||
|
|
||||||
|
node, ok := overlay[cpath]
|
||||||
|
if !ok {
|
||||||
|
// The file or directory is not overlaid.
|
||||||
|
return osStat(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case node.isDeleted():
|
||||||
|
return nil, &fs.PathError{Op: "lstat", Path: cpath, Err: fs.ErrNotExist}
|
||||||
|
case node.isDir():
|
||||||
|
return fakeDir(filepath.Base(path)), nil
|
||||||
|
default:
|
||||||
|
fi, err := osStat(node.actualFilePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return fakeFile{name: filepath.Base(path), real: fi}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fakeFile provides an fs.FileInfo implementation for an overlaid file,
|
||||||
|
// so that the file has the name of the overlaid file, but takes all
|
||||||
|
// other characteristics of the replacement file.
|
||||||
|
type fakeFile struct {
|
||||||
|
name string
|
||||||
|
real fs.FileInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f fakeFile) Name() string { return f.name }
|
||||||
|
func (f fakeFile) Size() int64 { return f.real.Size() }
|
||||||
|
func (f fakeFile) Mode() fs.FileMode { return f.real.Mode() }
|
||||||
|
func (f fakeFile) ModTime() time.Time { return f.real.ModTime() }
|
||||||
|
func (f fakeFile) IsDir() bool { return f.real.IsDir() }
|
||||||
|
func (f fakeFile) Sys() interface{} { return f.real.Sys() }
|
||||||
|
|
||||||
|
// missingFile provides an fs.FileInfo for an overlaid file where the
|
||||||
|
// destination file in the overlay doesn't exist. It returns zero values
|
||||||
|
// for the fileInfo methods other than Name, set to the file's name, and Mode
|
||||||
|
// set to ModeIrregular.
|
||||||
|
type missingFile string
|
||||||
|
|
||||||
|
func (f missingFile) Name() string { return string(f) }
|
||||||
|
func (f missingFile) Size() int64 { return 0 }
|
||||||
|
func (f missingFile) Mode() fs.FileMode { return fs.ModeIrregular }
|
||||||
|
func (f missingFile) ModTime() time.Time { return time.Unix(0, 0) }
|
||||||
|
func (f missingFile) IsDir() bool { return false }
|
||||||
|
func (f missingFile) Sys() interface{} { return nil }
|
||||||
|
|
||||||
|
// fakeDir provides an fs.FileInfo implementation for directories that are
|
||||||
|
// implicitly created by overlaid files. Each directory in the
|
||||||
|
// path of an overlaid file is considered to exist in the overlay filesystem.
|
||||||
|
type fakeDir string
|
||||||
|
|
||||||
|
func (f fakeDir) Name() string { return string(f) }
|
||||||
|
func (f fakeDir) Size() int64 { return 0 }
|
||||||
|
func (f fakeDir) Mode() fs.FileMode { return fs.ModeDir | 0500 }
|
||||||
|
func (f fakeDir) ModTime() time.Time { return time.Unix(0, 0) }
|
||||||
|
func (f fakeDir) IsDir() bool { return true }
|
||||||
|
func (f fakeDir) Sys() interface{} { return nil }
|
||||||
|
|
||||||
|
// Glob is like filepath.Glob but uses the overlay file system.
|
||||||
|
func Glob(pattern string) (matches []string, err error) {
|
||||||
|
// Check pattern is well-formed.
|
||||||
|
if _, err := filepath.Match(pattern, ""); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !hasMeta(pattern) {
|
||||||
|
if _, err = Lstat(pattern); err != nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return []string{pattern}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
dir, file := filepath.Split(pattern)
|
||||||
|
volumeLen := 0
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
volumeLen, dir = cleanGlobPathWindows(dir)
|
||||||
|
} else {
|
||||||
|
dir = cleanGlobPath(dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hasMeta(dir[volumeLen:]) {
|
||||||
|
return glob(dir, file, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent infinite recursion. See issue 15879.
|
||||||
|
if dir == pattern {
|
||||||
|
return nil, filepath.ErrBadPattern
|
||||||
|
}
|
||||||
|
|
||||||
|
var m []string
|
||||||
|
m, err = Glob(dir)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, d := range m {
|
||||||
|
matches, err = glob(d, file, matches)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanGlobPath prepares path for glob matching.
|
||||||
|
func cleanGlobPath(path string) string {
|
||||||
|
switch path {
|
||||||
|
case "":
|
||||||
|
return "."
|
||||||
|
case string(filepath.Separator):
|
||||||
|
// do nothing to the path
|
||||||
|
return path
|
||||||
|
default:
|
||||||
|
return path[0 : len(path)-1] // chop off trailing separator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func volumeNameLen(path string) int {
|
||||||
|
isSlash := func(c uint8) bool {
|
||||||
|
return c == '\\' || c == '/'
|
||||||
|
}
|
||||||
|
if len(path) < 2 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
// with drive letter
|
||||||
|
c := path[0]
|
||||||
|
if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') {
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
// is it UNC? https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
|
||||||
|
if l := len(path); l >= 5 && isSlash(path[0]) && isSlash(path[1]) &&
|
||||||
|
!isSlash(path[2]) && path[2] != '.' {
|
||||||
|
// first, leading `\\` and next shouldn't be `\`. its server name.
|
||||||
|
for n := 3; n < l-1; n++ {
|
||||||
|
// second, next '\' shouldn't be repeated.
|
||||||
|
if isSlash(path[n]) {
|
||||||
|
n++
|
||||||
|
// third, following something characters. its share name.
|
||||||
|
if !isSlash(path[n]) {
|
||||||
|
if path[n] == '.' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
for ; n < l; n++ {
|
||||||
|
if isSlash(path[n]) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanGlobPathWindows is windows version of cleanGlobPath.
|
||||||
|
func cleanGlobPathWindows(path string) (prefixLen int, cleaned string) {
|
||||||
|
vollen := volumeNameLen(path)
|
||||||
|
switch {
|
||||||
|
case path == "":
|
||||||
|
return 0, "."
|
||||||
|
case vollen+1 == len(path) && os.IsPathSeparator(path[len(path)-1]): // /, \, C:\ and C:/
|
||||||
|
// do nothing to the path
|
||||||
|
return vollen + 1, path
|
||||||
|
case vollen == len(path) && len(path) == 2: // C:
|
||||||
|
return vollen, path + "." // convert C: into C:.
|
||||||
|
default:
|
||||||
|
if vollen >= len(path) {
|
||||||
|
vollen = len(path) - 1
|
||||||
|
}
|
||||||
|
return vollen, path[0 : len(path)-1] // chop off trailing separator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// glob searches for files matching pattern in the directory dir
|
||||||
|
// and appends them to matches. If the directory cannot be
|
||||||
|
// opened, it returns the existing matches. New matches are
|
||||||
|
// added in lexicographical order.
|
||||||
|
func glob(dir, pattern string, matches []string) (m []string, e error) {
|
||||||
|
m = matches
|
||||||
|
fi, err := Stat(dir)
|
||||||
|
if err != nil {
|
||||||
|
return // ignore I/O error
|
||||||
|
}
|
||||||
|
if !fi.IsDir() {
|
||||||
|
return // ignore I/O error
|
||||||
|
}
|
||||||
|
|
||||||
|
list, err := ReadDir(dir)
|
||||||
|
if err != nil {
|
||||||
|
return // ignore I/O error
|
||||||
|
}
|
||||||
|
|
||||||
|
var names []string
|
||||||
|
for _, info := range list {
|
||||||
|
names = append(names, info.Name())
|
||||||
|
}
|
||||||
|
sort.Strings(names)
|
||||||
|
|
||||||
|
for _, n := range names {
|
||||||
|
matched, err := filepath.Match(pattern, n)
|
||||||
|
if err != nil {
|
||||||
|
return m, err
|
||||||
|
}
|
||||||
|
if matched {
|
||||||
|
m = append(m, filepath.Join(dir, n))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// hasMeta reports whether path contains any of the magic characters
|
||||||
|
// recognized by filepath.Match.
|
||||||
|
func hasMeta(path string) bool {
|
||||||
|
magicChars := `*?[`
|
||||||
|
if runtime.GOOS != "windows" {
|
||||||
|
magicChars = `*?[\`
|
||||||
|
}
|
||||||
|
return strings.ContainsAny(path, magicChars)
|
||||||
|
}
|
1094
libgo/go/cmd/go/internal/fsys/fsys_test.go
Normal file
1094
libgo/go/cmd/go/internal/fsys/fsys_test.go
Normal file
File diff suppressed because it is too large
Load Diff
@ -8,11 +8,11 @@ package generate
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/parser"
|
"go/parser"
|
||||||
"go/token"
|
"go/token"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@ -160,7 +160,7 @@ func init() {
|
|||||||
CmdGenerate.Flag.StringVar(&generateRunFlag, "run", "", "")
|
CmdGenerate.Flag.StringVar(&generateRunFlag, "run", "", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func runGenerate(cmd *base.Command, args []string) {
|
func runGenerate(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
load.IgnoreImports = true
|
load.IgnoreImports = true
|
||||||
|
|
||||||
if generateRunFlag != "" {
|
if generateRunFlag != "" {
|
||||||
@ -175,7 +175,7 @@ func runGenerate(cmd *base.Command, args []string) {
|
|||||||
|
|
||||||
// Even if the arguments are .go files, this loop suffices.
|
// Even if the arguments are .go files, this loop suffices.
|
||||||
printed := false
|
printed := false
|
||||||
for _, pkg := range load.PackagesAndErrors(args) {
|
for _, pkg := range load.PackagesAndErrors(ctx, args) {
|
||||||
if modload.Enabled() && pkg.Module != nil && !pkg.Module.Main {
|
if modload.Enabled() && pkg.Module != nil && !pkg.Module.Main {
|
||||||
if !printed {
|
if !printed {
|
||||||
fmt.Fprintf(os.Stderr, "go: not generating in packages in dependency modules\n")
|
fmt.Fprintf(os.Stderr, "go: not generating in packages in dependency modules\n")
|
||||||
@ -200,7 +200,7 @@ func runGenerate(cmd *base.Command, args []string) {
|
|||||||
|
|
||||||
// generate runs the generation directives for a single file.
|
// generate runs the generation directives for a single file.
|
||||||
func generate(absFile string) bool {
|
func generate(absFile string) bool {
|
||||||
src, err := ioutil.ReadFile(absFile)
|
src, err := os.ReadFile(absFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("generate: %s", err)
|
log.Fatalf("generate: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
package get
|
package get
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -17,8 +18,11 @@ import (
|
|||||||
"cmd/go/internal/load"
|
"cmd/go/internal/load"
|
||||||
"cmd/go/internal/search"
|
"cmd/go/internal/search"
|
||||||
"cmd/go/internal/str"
|
"cmd/go/internal/str"
|
||||||
|
"cmd/go/internal/vcs"
|
||||||
"cmd/go/internal/web"
|
"cmd/go/internal/web"
|
||||||
"cmd/go/internal/work"
|
"cmd/go/internal/work"
|
||||||
|
|
||||||
|
"golang.org/x/mod/module"
|
||||||
)
|
)
|
||||||
|
|
||||||
var CmdGet = &base.Command{
|
var CmdGet = &base.Command{
|
||||||
@ -41,6 +45,10 @@ before resolving dependencies or building the code.
|
|||||||
|
|
||||||
The -insecure flag permits fetching from repositories and resolving
|
The -insecure flag permits fetching from repositories and resolving
|
||||||
custom domains using insecure schemes such as HTTP. Use with caution.
|
custom domains using insecure schemes such as HTTP. Use with caution.
|
||||||
|
This flag is deprecated and will be removed in a future version of go.
|
||||||
|
The GOINSECURE environment variable should be used instead, since it
|
||||||
|
provides control over which packages may be retrieved using an insecure
|
||||||
|
scheme. See 'go help environment' for details.
|
||||||
|
|
||||||
The -t flag instructs get to also download the packages required to build
|
The -t flag instructs get to also download the packages required to build
|
||||||
the tests for the specified packages.
|
the tests for the specified packages.
|
||||||
@ -102,17 +110,15 @@ var (
|
|||||||
getT = CmdGet.Flag.Bool("t", false, "")
|
getT = CmdGet.Flag.Bool("t", false, "")
|
||||||
getU = CmdGet.Flag.Bool("u", false, "")
|
getU = CmdGet.Flag.Bool("u", false, "")
|
||||||
getFix = CmdGet.Flag.Bool("fix", false, "")
|
getFix = CmdGet.Flag.Bool("fix", false, "")
|
||||||
|
|
||||||
Insecure bool
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
work.AddBuildFlags(CmdGet, work.OmitModFlag|work.OmitModCommonFlags)
|
work.AddBuildFlags(CmdGet, work.OmitModFlag|work.OmitModCommonFlags)
|
||||||
CmdGet.Run = runGet // break init loop
|
CmdGet.Run = runGet // break init loop
|
||||||
CmdGet.Flag.BoolVar(&Insecure, "insecure", Insecure, "")
|
CmdGet.Flag.BoolVar(&cfg.Insecure, "insecure", cfg.Insecure, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func runGet(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 get: modules not implemented")
|
||||||
@ -123,6 +129,9 @@ func runGet(cmd *base.Command, args []string) {
|
|||||||
if *getF && !*getU {
|
if *getF && !*getU {
|
||||||
base.Fatalf("go get: cannot use -f flag without -u")
|
base.Fatalf("go get: cannot use -f flag without -u")
|
||||||
}
|
}
|
||||||
|
if cfg.Insecure {
|
||||||
|
fmt.Fprintf(os.Stderr, "go get: -insecure flag is deprecated; see 'go help get' for details\n")
|
||||||
|
}
|
||||||
|
|
||||||
// Disable any prompting for passwords by Git.
|
// Disable any prompting for passwords by Git.
|
||||||
// Only has an effect for 2.3.0 or later, but avoiding
|
// Only has an effect for 2.3.0 or later, but avoiding
|
||||||
@ -171,17 +180,18 @@ func runGet(cmd *base.Command, args []string) {
|
|||||||
// everything.
|
// everything.
|
||||||
load.ClearPackageCache()
|
load.ClearPackageCache()
|
||||||
|
|
||||||
pkgs := load.PackagesForBuild(args)
|
pkgs := load.PackagesAndErrors(ctx, args)
|
||||||
|
load.CheckPackageErrors(pkgs)
|
||||||
|
|
||||||
// Phase 3. Install.
|
// Phase 3. Install.
|
||||||
if *getD {
|
if *getD {
|
||||||
// Download only.
|
// Download only.
|
||||||
// Check delayed until now so that importPaths
|
// Check delayed until now so that downloadPaths
|
||||||
// and packagesForBuild have a chance to print errors.
|
// and CheckPackageErrors have a chance to print errors.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
work.InstallPackages(args, pkgs)
|
work.InstallPackages(ctx, args, pkgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// downloadPaths prepares the list of paths to pass to download.
|
// downloadPaths prepares the list of paths to pass to download.
|
||||||
@ -245,9 +255,9 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int)
|
|||||||
load1 := func(path string, mode int) *load.Package {
|
load1 := func(path string, mode int) *load.Package {
|
||||||
if parent == nil {
|
if parent == nil {
|
||||||
mode := 0 // don't do module or vendor resolution
|
mode := 0 // don't do module or vendor resolution
|
||||||
return load.LoadImport(path, base.Cwd, nil, stk, nil, mode)
|
return load.LoadImport(context.TODO(), path, base.Cwd, nil, stk, nil, mode)
|
||||||
}
|
}
|
||||||
return load.LoadImport(path, parent.Dir, parent, stk, nil, mode|load.ResolveModule)
|
return load.LoadImport(context.TODO(), path, parent.Dir, parent, stk, nil, mode|load.ResolveModule)
|
||||||
}
|
}
|
||||||
|
|
||||||
p := load1(arg, mode)
|
p := load1(arg, mode)
|
||||||
@ -402,17 +412,12 @@ 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 (
|
||||||
vcs *vcsCmd
|
vcsCmd *vcs.Cmd
|
||||||
repo, rootPath string
|
repo, rootPath string
|
||||||
err error
|
err error
|
||||||
blindRepo bool // set if the repo has unusual configuration
|
blindRepo bool // set if the repo has unusual configuration
|
||||||
)
|
)
|
||||||
|
|
||||||
security := web.SecureOnly
|
|
||||||
if Insecure {
|
|
||||||
security = web.Insecure
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
||||||
// actually a wildcard pattern.
|
// actually a wildcard pattern.
|
||||||
// Trim the path at the element containing the first wildcard,
|
// Trim the path at the element containing the first wildcard,
|
||||||
@ -426,22 +431,26 @@ func downloadPackage(p *load.Package) error {
|
|||||||
}
|
}
|
||||||
importPrefix = importPrefix[:slash]
|
importPrefix = importPrefix[:slash]
|
||||||
}
|
}
|
||||||
if err := CheckImportPath(importPrefix); err != nil {
|
if err := module.CheckImportPath(importPrefix); err != nil {
|
||||||
return fmt.Errorf("%s: invalid import path: %v", p.ImportPath, err)
|
return fmt.Errorf("%s: invalid import path: %v", p.ImportPath, err)
|
||||||
}
|
}
|
||||||
|
security := web.SecureOnly
|
||||||
|
if cfg.Insecure || module.MatchPrefixPatterns(cfg.GOINSECURE, importPrefix) {
|
||||||
|
security = web.Insecure
|
||||||
|
}
|
||||||
|
|
||||||
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.
|
||||||
vcs, rootPath, err = vcsFromDir(p.Dir, p.Internal.Build.SrcRoot)
|
vcsCmd, rootPath, err = vcs.FromDir(p.Dir, p.Internal.Build.SrcRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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.
|
||||||
if *getU && vcs.remoteRepo != nil {
|
if *getU && vcsCmd.RemoteRepo != nil {
|
||||||
dir := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath))
|
dir := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath))
|
||||||
remote, err := vcs.remoteRepo(vcs, dir)
|
remote, err := vcsCmd.RemoteRepo(vcsCmd, dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Proceed anyway. The package is present; we likely just don't understand
|
// Proceed anyway. The package is present; we likely just don't understand
|
||||||
// the repo configuration (e.g. unusual remote protocol).
|
// the repo configuration (e.g. unusual remote protocol).
|
||||||
@ -449,10 +458,10 @@ func downloadPackage(p *load.Package) error {
|
|||||||
}
|
}
|
||||||
repo = remote
|
repo = remote
|
||||||
if !*getF && err == nil {
|
if !*getF && err == nil {
|
||||||
if rr, err := RepoRootForImportPath(importPrefix, IgnoreMod, security); err == nil {
|
if rr, err := vcs.RepoRootForImportPath(importPrefix, vcs.IgnoreMod, security); err == nil {
|
||||||
repo := rr.Repo
|
repo := rr.Repo
|
||||||
if rr.vcs.resolveRepo != nil {
|
if rr.VCS.ResolveRepo != nil {
|
||||||
resolved, err := rr.vcs.resolveRepo(rr.vcs, dir, repo)
|
resolved, err := rr.VCS.ResolveRepo(rr.VCS, dir, repo)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
repo = resolved
|
repo = resolved
|
||||||
}
|
}
|
||||||
@ -466,13 +475,13 @@ func downloadPackage(p *load.Package) error {
|
|||||||
} else {
|
} else {
|
||||||
// Analyze the import path to determine the version control system,
|
// Analyze the import path to determine the version control system,
|
||||||
// repository, and the import path for the root of the repository.
|
// repository, and the import path for the root of the repository.
|
||||||
rr, err := RepoRootForImportPath(importPrefix, IgnoreMod, security)
|
rr, err := vcs.RepoRootForImportPath(importPrefix, vcs.IgnoreMod, security)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
vcs, repo, rootPath = rr.vcs, rr.Repo, rr.Root
|
vcsCmd, repo, rootPath = rr.VCS, rr.Repo, rr.Root
|
||||||
}
|
}
|
||||||
if !blindRepo && !vcs.isSecure(repo) && !Insecure {
|
if !blindRepo && !vcsCmd.IsSecure(repo) && security != web.Insecure {
|
||||||
return fmt.Errorf("cannot download, %v uses insecure protocol", repo)
|
return fmt.Errorf("cannot download, %v uses insecure protocol", repo)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -495,7 +504,7 @@ func downloadPackage(p *load.Package) error {
|
|||||||
}
|
}
|
||||||
root := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath))
|
root := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath))
|
||||||
|
|
||||||
if err := checkNestedVCS(vcs, root, p.Internal.Build.SrcRoot); err != nil {
|
if err := vcs.CheckNested(vcsCmd, root, p.Internal.Build.SrcRoot); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -511,7 +520,7 @@ func downloadPackage(p *load.Package) error {
|
|||||||
|
|
||||||
// Check that this is an appropriate place for the repo to be checked out.
|
// Check that this is an appropriate place for the repo to be checked out.
|
||||||
// The target directory must either not exist or have a repo checked out already.
|
// The target directory must either not exist or have a repo checked out already.
|
||||||
meta := filepath.Join(root, "."+vcs.cmd)
|
meta := filepath.Join(root, "."+vcsCmd.Cmd)
|
||||||
if _, err := os.Stat(meta); err != nil {
|
if _, err := os.Stat(meta); err != nil {
|
||||||
// Metadata file or directory does not exist. Prepare to checkout new copy.
|
// Metadata file or directory does not exist. Prepare to checkout new copy.
|
||||||
// Some version control tools require the target directory not to exist.
|
// Some version control tools require the target directory not to exist.
|
||||||
@ -532,12 +541,12 @@ func downloadPackage(p *load.Package) error {
|
|||||||
fmt.Fprintf(os.Stderr, "created GOPATH=%s; see 'go help gopath'\n", p.Internal.Build.Root)
|
fmt.Fprintf(os.Stderr, "created GOPATH=%s; see 'go help gopath'\n", p.Internal.Build.Root)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = vcs.create(root, repo); err != nil {
|
if err = vcsCmd.Create(root, repo); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Metadata directory does exist; download incremental updates.
|
// Metadata directory does exist; download incremental updates.
|
||||||
if err = vcs.download(root); err != nil {
|
if err = vcsCmd.Download(root); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -546,12 +555,12 @@ func downloadPackage(p *load.Package) error {
|
|||||||
// Do not show tag sync in -n; it's noise more than anything,
|
// Do not show tag sync in -n; it's noise more than anything,
|
||||||
// and since we're not running commands, no tag will be found.
|
// and since we're not running commands, no tag will be found.
|
||||||
// But avoid printing nothing.
|
// But avoid printing nothing.
|
||||||
fmt.Fprintf(os.Stderr, "# cd %s; %s sync/update\n", root, vcs.cmd)
|
fmt.Fprintf(os.Stderr, "# cd %s; %s sync/update\n", root, vcsCmd.Cmd)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select and sync to appropriate version of the repository.
|
// Select and sync to appropriate version of the repository.
|
||||||
tags, err := vcs.tags(root)
|
tags, err := vcsCmd.Tags(root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -559,7 +568,7 @@ func downloadPackage(p *load.Package) error {
|
|||||||
if i := strings.Index(vers, " "); i >= 0 {
|
if i := strings.Index(vers, " "); i >= 0 {
|
||||||
vers = vers[:i]
|
vers = vers[:i]
|
||||||
}
|
}
|
||||||
if err := vcs.tagSync(root, selectTag(vers, tags)); err != nil {
|
if err := vcsCmd.TagSync(root, selectTag(vers, tags)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,192 +0,0 @@
|
|||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package get
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"unicode"
|
|
||||||
"unicode/utf8"
|
|
||||||
)
|
|
||||||
|
|
||||||
// The following functions are copied verbatim from golang.org/x/mod/module/module.go,
|
|
||||||
// with a change to additionally reject Windows short-names,
|
|
||||||
// and one to accept arbitrary letters (golang.org/issue/29101).
|
|
||||||
//
|
|
||||||
// TODO(bcmills): After the call site for this function is backported,
|
|
||||||
// consolidate this back down to a single copy.
|
|
||||||
//
|
|
||||||
// NOTE: DO NOT MERGE THESE UNTIL WE DECIDE ABOUT ARBITRARY LETTERS IN MODULE MODE.
|
|
||||||
|
|
||||||
// CheckImportPath checks that an import path is valid.
|
|
||||||
func CheckImportPath(path string) error {
|
|
||||||
if err := checkPath(path, false); err != nil {
|
|
||||||
return fmt.Errorf("malformed import path %q: %v", path, err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// checkPath checks that a general path is valid.
|
|
||||||
// It returns an error describing why but not mentioning path.
|
|
||||||
// Because these checks apply to both module paths and import paths,
|
|
||||||
// the caller is expected to add the "malformed ___ path %q: " prefix.
|
|
||||||
// fileName indicates whether the final element of the path is a file name
|
|
||||||
// (as opposed to a directory name).
|
|
||||||
func checkPath(path string, fileName bool) error {
|
|
||||||
if !utf8.ValidString(path) {
|
|
||||||
return fmt.Errorf("invalid UTF-8")
|
|
||||||
}
|
|
||||||
if path == "" {
|
|
||||||
return fmt.Errorf("empty string")
|
|
||||||
}
|
|
||||||
if path[0] == '-' {
|
|
||||||
return fmt.Errorf("leading dash")
|
|
||||||
}
|
|
||||||
if strings.Contains(path, "//") {
|
|
||||||
return fmt.Errorf("double slash")
|
|
||||||
}
|
|
||||||
if path[len(path)-1] == '/' {
|
|
||||||
return fmt.Errorf("trailing slash")
|
|
||||||
}
|
|
||||||
elemStart := 0
|
|
||||||
for i, r := range path {
|
|
||||||
if r == '/' {
|
|
||||||
if err := checkElem(path[elemStart:i], fileName); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
elemStart = i + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err := checkElem(path[elemStart:], fileName); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// checkElem checks whether an individual path element is valid.
|
|
||||||
// fileName indicates whether the element is a file name (not a directory name).
|
|
||||||
func checkElem(elem string, fileName bool) error {
|
|
||||||
if elem == "" {
|
|
||||||
return fmt.Errorf("empty path element")
|
|
||||||
}
|
|
||||||
if strings.Count(elem, ".") == len(elem) {
|
|
||||||
return fmt.Errorf("invalid path element %q", elem)
|
|
||||||
}
|
|
||||||
if elem[0] == '.' && !fileName {
|
|
||||||
return fmt.Errorf("leading dot in path element")
|
|
||||||
}
|
|
||||||
if elem[len(elem)-1] == '.' {
|
|
||||||
return fmt.Errorf("trailing dot in path element")
|
|
||||||
}
|
|
||||||
|
|
||||||
charOK := pathOK
|
|
||||||
if fileName {
|
|
||||||
charOK = fileNameOK
|
|
||||||
}
|
|
||||||
for _, r := range elem {
|
|
||||||
if !charOK(r) {
|
|
||||||
return fmt.Errorf("invalid char %q", r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Windows disallows a bunch of path elements, sadly.
|
|
||||||
// See https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file
|
|
||||||
short := elem
|
|
||||||
if i := strings.Index(short, "."); i >= 0 {
|
|
||||||
short = short[:i]
|
|
||||||
}
|
|
||||||
for _, bad := range badWindowsNames {
|
|
||||||
if strings.EqualFold(bad, short) {
|
|
||||||
return fmt.Errorf("disallowed path element %q", elem)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reject path components that look like Windows short-names.
|
|
||||||
// Those usually end in a tilde followed by one or more ASCII digits.
|
|
||||||
if tilde := strings.LastIndexByte(short, '~'); tilde >= 0 && tilde < len(short)-1 {
|
|
||||||
suffix := short[tilde+1:]
|
|
||||||
suffixIsDigits := true
|
|
||||||
for _, r := range suffix {
|
|
||||||
if r < '0' || r > '9' {
|
|
||||||
suffixIsDigits = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if suffixIsDigits {
|
|
||||||
return fmt.Errorf("trailing tilde and digits in path element")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// pathOK reports whether r can appear in an import path element.
|
|
||||||
//
|
|
||||||
// NOTE: This function DIVERGES from module mode pathOK by accepting Unicode letters.
|
|
||||||
func pathOK(r rune) bool {
|
|
||||||
if r < utf8.RuneSelf {
|
|
||||||
return r == '+' || r == '-' || r == '.' || r == '_' || r == '~' ||
|
|
||||||
'0' <= r && r <= '9' ||
|
|
||||||
'A' <= r && r <= 'Z' ||
|
|
||||||
'a' <= r && r <= 'z'
|
|
||||||
}
|
|
||||||
return unicode.IsLetter(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
// fileNameOK reports whether r can appear in a file name.
|
|
||||||
// For now we allow all Unicode letters but otherwise limit to pathOK plus a few more punctuation characters.
|
|
||||||
// If we expand the set of allowed characters here, we have to
|
|
||||||
// work harder at detecting potential case-folding and normalization collisions.
|
|
||||||
// See note about "safe encoding" below.
|
|
||||||
func fileNameOK(r rune) bool {
|
|
||||||
if r < utf8.RuneSelf {
|
|
||||||
// Entire set of ASCII punctuation, from which we remove characters:
|
|
||||||
// ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~
|
|
||||||
// We disallow some shell special characters: " ' * < > ? ` |
|
|
||||||
// (Note that some of those are disallowed by the Windows file system as well.)
|
|
||||||
// We also disallow path separators / : and \ (fileNameOK is only called on path element characters).
|
|
||||||
// We allow spaces (U+0020) in file names.
|
|
||||||
const allowed = "!#$%&()+,-.=@[]^_{}~ "
|
|
||||||
if '0' <= r && r <= '9' || 'A' <= r && r <= 'Z' || 'a' <= r && r <= 'z' {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
for i := 0; i < len(allowed); i++ {
|
|
||||||
if rune(allowed[i]) == r {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// It may be OK to add more ASCII punctuation here, but only carefully.
|
|
||||||
// For example Windows disallows < > \, and macOS disallows :, so we must not allow those.
|
|
||||||
return unicode.IsLetter(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
// badWindowsNames are the reserved file path elements on Windows.
|
|
||||||
// See https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file
|
|
||||||
var badWindowsNames = []string{
|
|
||||||
"CON",
|
|
||||||
"PRN",
|
|
||||||
"AUX",
|
|
||||||
"NUL",
|
|
||||||
"COM1",
|
|
||||||
"COM2",
|
|
||||||
"COM3",
|
|
||||||
"COM4",
|
|
||||||
"COM5",
|
|
||||||
"COM6",
|
|
||||||
"COM7",
|
|
||||||
"COM8",
|
|
||||||
"COM9",
|
|
||||||
"LPT1",
|
|
||||||
"LPT2",
|
|
||||||
"LPT3",
|
|
||||||
"LPT4",
|
|
||||||
"LPT5",
|
|
||||||
"LPT6",
|
|
||||||
"LPT7",
|
|
||||||
"LPT8",
|
|
||||||
"LPT9",
|
|
||||||
}
|
|
@ -526,7 +526,7 @@ General-purpose environment variables:
|
|||||||
Comma-separated list of glob patterns (in the syntax of Go's path.Match)
|
Comma-separated list of glob patterns (in the syntax of Go's path.Match)
|
||||||
of module path prefixes that should always be fetched directly
|
of module path prefixes that should always be fetched directly
|
||||||
or that should not be compared against the checksum database.
|
or that should not be compared against the checksum database.
|
||||||
See 'go help module-private'.
|
See 'go help private'.
|
||||||
GOROOT
|
GOROOT
|
||||||
The root of the go tree.
|
The root of the go tree.
|
||||||
GOSUMDB
|
GOSUMDB
|
||||||
@ -582,8 +582,8 @@ Architecture-specific environment variables:
|
|||||||
For GOARCH=arm, the ARM architecture for which to compile.
|
For GOARCH=arm, the ARM architecture for which to compile.
|
||||||
Valid values are 5, 6, 7.
|
Valid values are 5, 6, 7.
|
||||||
GO386
|
GO386
|
||||||
For GOARCH=386, the floating point instruction set.
|
For GOARCH=386, how to implement floating point instructions.
|
||||||
Valid values are 387, sse2.
|
Valid values are sse2 (default), softfloat.
|
||||||
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.
|
||||||
@ -632,6 +632,8 @@ Additional information available from 'go env' but not read from the environment
|
|||||||
If module-aware mode is disabled, GOMOD will be the empty string.
|
If module-aware mode is disabled, GOMOD will be the empty string.
|
||||||
GOTOOLDIR
|
GOTOOLDIR
|
||||||
The directory where the go tools (compile, cover, doc, etc...) are installed.
|
The directory where the go tools (compile, cover, doc, etc...) are installed.
|
||||||
|
GOVERSION
|
||||||
|
The version of the installed Go tree, as reported by runtime.Version.
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -838,6 +840,9 @@ in addition to android tags and files.
|
|||||||
Using GOOS=illumos matches build tags and files as for GOOS=solaris
|
Using GOOS=illumos matches build tags and files as for GOOS=solaris
|
||||||
in addition to illumos tags and files.
|
in addition to illumos tags and files.
|
||||||
|
|
||||||
|
Using GOOS=ios matches build tags and files as for GOOS=darwin
|
||||||
|
in addition to ios tags and files.
|
||||||
|
|
||||||
To keep a file from being considered for the build:
|
To keep a file from being considered for the build:
|
||||||
|
|
||||||
// +build ignore
|
// +build ignore
|
||||||
|
@ -141,6 +141,9 @@ func matchTag(name string, tags map[string]bool, want bool) bool {
|
|||||||
if name == "solaris" {
|
if name == "solaris" {
|
||||||
have = have || tags["illumos"]
|
have = have || tags["illumos"]
|
||||||
}
|
}
|
||||||
|
if name == "darwin" {
|
||||||
|
have = have || tags["ios"]
|
||||||
|
}
|
||||||
return have == want
|
return have == want
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,6 +161,7 @@ func matchTag(name string, tags map[string]bool, want bool) bool {
|
|||||||
// Exceptions:
|
// Exceptions:
|
||||||
// if GOOS=android, then files with GOOS=linux are also matched.
|
// if GOOS=android, then files with GOOS=linux are also matched.
|
||||||
// if GOOS=illumos, then files with GOOS=solaris are also matched.
|
// if GOOS=illumos, then files with GOOS=solaris are also matched.
|
||||||
|
// if GOOS=ios, then files with GOOS=darwin are also matched.
|
||||||
//
|
//
|
||||||
// If tags["*"] is true, then MatchFile will consider all possible
|
// If tags["*"] is true, then MatchFile will consider all possible
|
||||||
// GOOS and GOARCH to be available and will consequently
|
// GOOS and GOARCH to be available and will consequently
|
||||||
@ -208,6 +212,7 @@ var KnownOS = map[string]bool{
|
|||||||
"freebsd": true,
|
"freebsd": true,
|
||||||
"hurd": true,
|
"hurd": true,
|
||||||
"illumos": true,
|
"illumos": true,
|
||||||
|
"ios": true,
|
||||||
"js": true,
|
"js": true,
|
||||||
"linux": true,
|
"linux": true,
|
||||||
"nacl": true, // legacy; don't remove
|
"nacl": true, // legacy; don't remove
|
||||||
|
@ -198,7 +198,7 @@ func (r *importReader) readImport(imports *[]string) {
|
|||||||
r.readString(imports)
|
r.readString(imports)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadComments is like ioutil.ReadAll, except that it only reads the leading
|
// ReadComments is like io.ReadAll, except that it only reads the leading
|
||||||
// block of comments in the file.
|
// block of comments in the file.
|
||||||
func ReadComments(f io.Reader) ([]byte, error) {
|
func ReadComments(f io.Reader) ([]byte, error) {
|
||||||
r := &importReader{b: bufio.NewReader(f)}
|
r := &importReader{b: bufio.NewReader(f)}
|
||||||
@ -210,7 +210,7 @@ func ReadComments(f io.Reader) ([]byte, error) {
|
|||||||
return r.buf, r.err
|
return r.buf, r.err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadImports is like ioutil.ReadAll, except that it expects a Go file as input
|
// ReadImports is like io.ReadAll, except that it expects a Go file as input
|
||||||
// and stops reading the input once the imports have completed.
|
// and stops reading the input once the imports have completed.
|
||||||
func ReadImports(f io.Reader, reportSyntaxError bool, imports *[]string) ([]byte, error) {
|
func ReadImports(f io.Reader, reportSyntaxError bool, imports *[]string) ([]byte, error) {
|
||||||
r := &importReader{b: bufio.NewReader(f)}
|
r := &importReader{b: bufio.NewReader(f)}
|
||||||
|
@ -6,16 +6,17 @@ package imports
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/fs"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"cmd/go/internal/fsys"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ScanDir(dir string, tags map[string]bool) ([]string, []string, error) {
|
func ScanDir(dir string, tags map[string]bool) ([]string, []string, error) {
|
||||||
infos, err := ioutil.ReadDir(dir)
|
infos, err := fsys.ReadDir(dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@ -25,14 +26,14 @@ func ScanDir(dir string, tags map[string]bool) ([]string, []string, error) {
|
|||||||
|
|
||||||
// If the directory entry is a symlink, stat it to obtain the info for the
|
// If the directory entry is a symlink, stat it to obtain the info for the
|
||||||
// link target instead of the link itself.
|
// link target instead of the link itself.
|
||||||
if info.Mode()&os.ModeSymlink != 0 {
|
if info.Mode()&fs.ModeSymlink != 0 {
|
||||||
info, err = os.Stat(filepath.Join(dir, name))
|
info, err = fsys.Stat(filepath.Join(dir, name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue // Ignore broken symlinks.
|
continue // Ignore broken symlinks.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if info.Mode().IsRegular() && !strings.HasPrefix(name, "_") && strings.HasSuffix(name, ".go") && MatchFile(name, tags) {
|
if info.Mode().IsRegular() && !strings.HasPrefix(name, "_") && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") && MatchFile(name, tags) {
|
||||||
files = append(files, filepath.Join(dir, name))
|
files = append(files, filepath.Join(dir, name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -49,7 +50,7 @@ func scanFiles(files []string, tags map[string]bool, explicitFiles bool) ([]stri
|
|||||||
numFiles := 0
|
numFiles := 0
|
||||||
Files:
|
Files:
|
||||||
for _, name := range files {
|
for _, name := range files {
|
||||||
r, err := os.Open(name)
|
r, err := fsys.Open(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ package imports
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"internal/testenv"
|
"internal/testenv"
|
||||||
"io/ioutil"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
@ -57,7 +57,7 @@ func TestScan(t *testing.T) {
|
|||||||
func TestScanDir(t *testing.T) {
|
func TestScanDir(t *testing.T) {
|
||||||
testenv.MustHaveGoBuild(t)
|
testenv.MustHaveGoBuild(t)
|
||||||
|
|
||||||
dirs, err := ioutil.ReadDir("testdata")
|
dirs, err := os.ReadDir("testdata")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -66,7 +66,7 @@ func TestScanDir(t *testing.T) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
t.Run(dir.Name(), func(t *testing.T) {
|
t.Run(dir.Name(), func(t *testing.T) {
|
||||||
tagsData, err := ioutil.ReadFile(filepath.Join("testdata", dir.Name(), "tags.txt"))
|
tagsData, err := os.ReadFile(filepath.Join("testdata", dir.Name(), "tags.txt"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error reading tags: %v", err)
|
t.Fatalf("error reading tags: %v", err)
|
||||||
}
|
}
|
||||||
@ -75,7 +75,7 @@ func TestScanDir(t *testing.T) {
|
|||||||
tags[t] = true
|
tags[t] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
wantData, err := ioutil.ReadFile(filepath.Join("testdata", dir.Name(), "want.txt"))
|
wantData, err := os.ReadFile(filepath.Join("testdata", dir.Name(), "want.txt"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error reading want: %v", err)
|
t.Fatalf("error reading want: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -4,17 +4,23 @@
|
|||||||
|
|
||||||
package imports
|
package imports
|
||||||
|
|
||||||
import "cmd/go/internal/cfg"
|
import (
|
||||||
|
"cmd/go/internal/cfg"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
var tags map[string]bool
|
var (
|
||||||
|
tags map[string]bool
|
||||||
|
tagsOnce sync.Once
|
||||||
|
)
|
||||||
|
|
||||||
// Tags returns a set of build tags that are true for the target platform.
|
// Tags returns a set of build tags that are true for the target platform.
|
||||||
// It includes GOOS, GOARCH, the compiler, possibly "cgo",
|
// It includes GOOS, GOARCH, the compiler, possibly "cgo",
|
||||||
// release tags like "go1.13", and user-specified build tags.
|
// release tags like "go1.13", and user-specified build tags.
|
||||||
func Tags() map[string]bool {
|
func Tags() map[string]bool {
|
||||||
if tags == nil {
|
tagsOnce.Do(func() {
|
||||||
tags = loadTags()
|
tags = loadTags()
|
||||||
}
|
})
|
||||||
return tags
|
return tags
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,14 +42,17 @@ func loadTags() map[string]bool {
|
|||||||
return tags
|
return tags
|
||||||
}
|
}
|
||||||
|
|
||||||
var anyTags map[string]bool
|
var (
|
||||||
|
anyTags map[string]bool
|
||||||
|
anyTagsOnce sync.Once
|
||||||
|
)
|
||||||
|
|
||||||
// AnyTags returns a special set of build tags that satisfy nearly all
|
// AnyTags returns a special set of build tags that satisfy nearly all
|
||||||
// build tag expressions. Only "ignore" and malformed build tag requirements
|
// build tag expressions. Only "ignore" and malformed build tag requirements
|
||||||
// are considered false.
|
// are considered false.
|
||||||
func AnyTags() map[string]bool {
|
func AnyTags() map[string]bool {
|
||||||
if anyTags == nil {
|
anyTagsOnce.Do(func() {
|
||||||
anyTags = map[string]bool{"*": true}
|
anyTags = map[string]bool{"*": true}
|
||||||
}
|
})
|
||||||
return anyTags
|
return anyTags
|
||||||
}
|
}
|
||||||
|
3
libgo/go/cmd/go/internal/imports/testdata/android/.h.go
vendored
Normal file
3
libgo/go/cmd/go/internal/imports/testdata/android/.h.go
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
package android
|
||||||
|
|
||||||
|
import _ "h"
|
3
libgo/go/cmd/go/internal/imports/testdata/illumos/.h.go
vendored
Normal file
3
libgo/go/cmd/go/internal/imports/testdata/illumos/.h.go
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
package android
|
||||||
|
|
||||||
|
import _ "h"
|
@ -8,7 +8,9 @@ package list
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
@ -19,6 +21,7 @@ import (
|
|||||||
"cmd/go/internal/cache"
|
"cmd/go/internal/cache"
|
||||||
"cmd/go/internal/cfg"
|
"cmd/go/internal/cfg"
|
||||||
"cmd/go/internal/load"
|
"cmd/go/internal/load"
|
||||||
|
"cmd/go/internal/modinfo"
|
||||||
"cmd/go/internal/modload"
|
"cmd/go/internal/modload"
|
||||||
"cmd/go/internal/str"
|
"cmd/go/internal/str"
|
||||||
"cmd/go/internal/work"
|
"cmd/go/internal/work"
|
||||||
@ -63,26 +66,28 @@ to -f '{{.ImportPath}}'. The struct being passed to the template is:
|
|||||||
BinaryOnly bool // binary-only package (no longer supported)
|
BinaryOnly bool // binary-only package (no longer supported)
|
||||||
ForTest string // package is only for use in named test
|
ForTest string // package is only for use in named test
|
||||||
Export string // file containing export data (when using -export)
|
Export string // file containing export data (when using -export)
|
||||||
|
BuildID string // build ID of the compiled package (when using -export)
|
||||||
Module *Module // info about package's containing module, if any (can be nil)
|
Module *Module // info about package's containing module, if any (can be nil)
|
||||||
Match []string // command-line patterns matching this package
|
Match []string // command-line patterns matching this package
|
||||||
DepOnly bool // package is only a dependency, not explicitly listed
|
DepOnly bool // package is only a dependency, not explicitly listed
|
||||||
|
|
||||||
// Source files
|
// Source files
|
||||||
GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
|
GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
|
||||||
CgoFiles []string // .go source files that import "C"
|
CgoFiles []string // .go source files that import "C"
|
||||||
CompiledGoFiles []string // .go files presented to compiler (when using -compiled)
|
CompiledGoFiles []string // .go files presented to compiler (when using -compiled)
|
||||||
IgnoredGoFiles []string // .go source files ignored due to build constraints
|
IgnoredGoFiles []string // .go source files ignored due to build constraints
|
||||||
CFiles []string // .c source files
|
IgnoredOtherFiles []string // non-.go source files ignored due to build constraints
|
||||||
CXXFiles []string // .cc, .cxx and .cpp source files
|
CFiles []string // .c source files
|
||||||
MFiles []string // .m source files
|
CXXFiles []string // .cc, .cxx and .cpp source files
|
||||||
HFiles []string // .h, .hh, .hpp and .hxx source files
|
MFiles []string // .m source files
|
||||||
FFiles []string // .f, .F, .for and .f90 Fortran source files
|
HFiles []string // .h, .hh, .hpp and .hxx source files
|
||||||
SFiles []string // .s source files
|
FFiles []string // .f, .F, .for and .f90 Fortran source files
|
||||||
SwigFiles []string // .swig files
|
SFiles []string // .s source files
|
||||||
SwigCXXFiles []string // .swigcxx files
|
SwigFiles []string // .swig files
|
||||||
SysoFiles []string // .syso object files to add to archive
|
SwigCXXFiles []string // .swigcxx files
|
||||||
TestGoFiles []string // _test.go files in package
|
SysoFiles []string // .syso object files to add to archive
|
||||||
XTestGoFiles []string // _test.go files outside package
|
TestGoFiles []string // _test.go files in package
|
||||||
|
XTestGoFiles []string // _test.go files outside package
|
||||||
|
|
||||||
// Cgo directives
|
// Cgo directives
|
||||||
CgoCFLAGS []string // cgo: flags for C compiler
|
CgoCFLAGS []string // cgo: flags for C compiler
|
||||||
@ -213,6 +218,7 @@ applied to a Go struct, but now a Module struct:
|
|||||||
Dir string // directory holding files for this module, if any
|
Dir string // directory holding files for this module, if any
|
||||||
GoMod string // path to go.mod file used when loading this module, if any
|
GoMod string // path to go.mod file used when loading this module, if any
|
||||||
GoVersion string // go version used in module
|
GoVersion string // go version used in module
|
||||||
|
Retracted string // retraction information, if any (with -retracted or -u)
|
||||||
Error *ModuleError // error loading module
|
Error *ModuleError // error loading module
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,14 +250,16 @@ the replaced source code.)
|
|||||||
The -u flag adds information about available upgrades.
|
The -u flag adds information about available upgrades.
|
||||||
When the latest version of a given module is newer than
|
When the latest version of a given module is newer than
|
||||||
the current one, list -u sets the Module's Update field
|
the current one, list -u sets the Module's Update field
|
||||||
to information about the newer module.
|
to information about the newer module. list -u will also set
|
||||||
|
the module's Retracted field if the current version is retracted.
|
||||||
The Module's String method indicates an available upgrade by
|
The Module's String method indicates an available upgrade by
|
||||||
formatting the newer version in brackets after the current version.
|
formatting the newer version in brackets after the current version.
|
||||||
|
If a version is retracted, the string "(retracted)" will follow it.
|
||||||
For example, 'go list -m -u all' might print:
|
For example, 'go list -m -u all' might print:
|
||||||
|
|
||||||
my/main/module
|
my/main/module
|
||||||
golang.org/x/text v0.3.0 [v0.4.0] => /tmp/text
|
golang.org/x/text v0.3.0 [v0.4.0] => /tmp/text
|
||||||
rsc.io/pdf v0.1.1 [v0.1.2]
|
rsc.io/pdf v0.1.1 (retracted) [v0.1.2]
|
||||||
|
|
||||||
(For tools, 'go list -m -u -json all' may be more convenient to parse.)
|
(For tools, 'go list -m -u -json all' may be more convenient to parse.)
|
||||||
|
|
||||||
@ -261,6 +269,14 @@ to semantic versioning, earliest to latest. The flag also changes
|
|||||||
the default output format to display the module path followed by the
|
the default output format to display the module path followed by the
|
||||||
space-separated version list.
|
space-separated version list.
|
||||||
|
|
||||||
|
The -retracted flag causes list to report information about retracted
|
||||||
|
module versions. When -retracted is used with -f or -json, the Retracted
|
||||||
|
field will be set to a string explaining why the version was retracted.
|
||||||
|
The string is taken from comments on the retract directive in the
|
||||||
|
module's go.mod file. When -retracted is used with -versions, retracted
|
||||||
|
versions are listed together with unretracted versions. The -retracted
|
||||||
|
flag may be used with or without -m.
|
||||||
|
|
||||||
The arguments to list -m are interpreted as a list of modules, not packages.
|
The arguments to list -m are interpreted as a list of modules, not packages.
|
||||||
The main module is the module containing the current directory.
|
The main module is the module containing the current directory.
|
||||||
The active modules are the main module and its dependencies.
|
The active modules are the main module and its dependencies.
|
||||||
@ -294,23 +310,24 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
listCompiled = CmdList.Flag.Bool("compiled", false, "")
|
listCompiled = CmdList.Flag.Bool("compiled", false, "")
|
||||||
listDeps = CmdList.Flag.Bool("deps", false, "")
|
listDeps = CmdList.Flag.Bool("deps", false, "")
|
||||||
listE = CmdList.Flag.Bool("e", false, "")
|
listE = CmdList.Flag.Bool("e", false, "")
|
||||||
listExport = CmdList.Flag.Bool("export", false, "")
|
listExport = CmdList.Flag.Bool("export", false, "")
|
||||||
listFmt = CmdList.Flag.String("f", "", "")
|
listFmt = CmdList.Flag.String("f", "", "")
|
||||||
listFind = CmdList.Flag.Bool("find", false, "")
|
listFind = CmdList.Flag.Bool("find", false, "")
|
||||||
listJson = CmdList.Flag.Bool("json", false, "")
|
listJson = CmdList.Flag.Bool("json", false, "")
|
||||||
listM = CmdList.Flag.Bool("m", false, "")
|
listM = CmdList.Flag.Bool("m", false, "")
|
||||||
listU = CmdList.Flag.Bool("u", false, "")
|
listRetracted = CmdList.Flag.Bool("retracted", false, "")
|
||||||
listTest = CmdList.Flag.Bool("test", false, "")
|
listTest = CmdList.Flag.Bool("test", false, "")
|
||||||
listVersions = CmdList.Flag.Bool("versions", false, "")
|
listU = CmdList.Flag.Bool("u", false, "")
|
||||||
|
listVersions = CmdList.Flag.Bool("versions", false, "")
|
||||||
)
|
)
|
||||||
|
|
||||||
var nl = []byte{'\n'}
|
var nl = []byte{'\n'}
|
||||||
|
|
||||||
func runList(cmd *base.Command, args []string) {
|
func runList(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
modload.LoadTests = *listTest
|
load.ModResolveTests = *listTest
|
||||||
work.BuildInit()
|
work.BuildInit()
|
||||||
out := newTrackingWriter(os.Stdout)
|
out := newTrackingWriter(os.Stdout)
|
||||||
defer out.w.Flush()
|
defer out.w.Flush()
|
||||||
@ -348,7 +365,7 @@ func runList(cmd *base.Command, args []string) {
|
|||||||
fm := template.FuncMap{
|
fm := template.FuncMap{
|
||||||
"join": strings.Join,
|
"join": strings.Join,
|
||||||
"context": context,
|
"context": context,
|
||||||
"module": modload.ModuleInfo,
|
"module": func(path string) *modinfo.ModulePublic { return modload.ModuleInfo(ctx, path) },
|
||||||
}
|
}
|
||||||
tmpl, err := template.New("main").Funcs(fm).Parse(*listFmt)
|
tmpl, err := template.New("main").Funcs(fm).Parse(*listFmt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -365,6 +382,16 @@ func runList(cmd *base.Command, args []string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
modload.Init()
|
||||||
|
if *listRetracted {
|
||||||
|
if cfg.BuildMod == "vendor" {
|
||||||
|
base.Fatalf("go list -retracted cannot be used when vendoring is enabled")
|
||||||
|
}
|
||||||
|
if !modload.Enabled() {
|
||||||
|
base.Fatalf("go list -retracted can only be used in module-aware mode")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if *listM {
|
if *listM {
|
||||||
// Module mode.
|
// Module mode.
|
||||||
if *listCompiled {
|
if *listCompiled {
|
||||||
@ -388,7 +415,7 @@ func runList(cmd *base.Command, args []string) {
|
|||||||
base.Fatalf("go list -m: not using modules")
|
base.Fatalf("go list -m: not using modules")
|
||||||
}
|
}
|
||||||
|
|
||||||
modload.InitMod() // Parses go.mod and sets cfg.BuildMod.
|
modload.LoadModFile(ctx) // Parses go.mod and sets cfg.BuildMod.
|
||||||
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 list -m: can't %s using the vendor directory\n\t(Use -mod=mod or -mod=readonly to bypass.)"
|
||||||
|
|
||||||
@ -412,9 +439,7 @@ func runList(cmd *base.Command, args []string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
modload.LoadBuildList()
|
mods := modload.ListModules(ctx, args, *listU, *listVersions, *listRetracted)
|
||||||
|
|
||||||
mods := modload.ListModules(args, *listU, *listVersions)
|
|
||||||
if !*listE {
|
if !*listE {
|
||||||
for _, m := range mods {
|
for _, m := range mods {
|
||||||
if m.Error != nil {
|
if m.Error != nil {
|
||||||
@ -446,11 +471,18 @@ func runList(cmd *base.Command, args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
load.IgnoreImports = *listFind
|
load.IgnoreImports = *listFind
|
||||||
var pkgs []*load.Package
|
pkgs := load.PackagesAndErrors(ctx, args)
|
||||||
if *listE {
|
if !*listE {
|
||||||
pkgs = load.PackagesAndErrors(args)
|
w := 0
|
||||||
} else {
|
for _, pkg := range pkgs {
|
||||||
pkgs = load.Packages(args)
|
if pkg.Error != nil {
|
||||||
|
base.Errorf("%v", pkg.Error)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
pkgs[w] = pkg
|
||||||
|
w++
|
||||||
|
}
|
||||||
|
pkgs = pkgs[:w]
|
||||||
base.ExitIfErrors()
|
base.ExitIfErrors()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -476,9 +508,9 @@ func runList(cmd *base.Command, args []string) {
|
|||||||
var pmain, ptest, pxtest *load.Package
|
var pmain, ptest, pxtest *load.Package
|
||||||
var err error
|
var err error
|
||||||
if *listE {
|
if *listE {
|
||||||
pmain, ptest, pxtest = load.TestPackagesAndErrors(p, nil)
|
pmain, ptest, pxtest = load.TestPackagesAndErrors(ctx, p, nil)
|
||||||
} else {
|
} else {
|
||||||
pmain, ptest, pxtest, err = load.TestPackagesFor(p, nil)
|
pmain, ptest, pxtest, err = load.TestPackagesFor(ctx, p, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Errorf("can't load test package: %s", err)
|
base.Errorf("can't load test package: %s", err)
|
||||||
}
|
}
|
||||||
@ -520,7 +552,7 @@ func runList(cmd *base.Command, args []string) {
|
|||||||
// Note that -deps is applied after -test,
|
// Note that -deps is applied after -test,
|
||||||
// so that you only get descriptions of tests for the things named
|
// so that you only get descriptions of tests for the things named
|
||||||
// explicitly on the command line, not for all dependencies.
|
// explicitly on the command line, not for all dependencies.
|
||||||
pkgs = load.PackageList(pkgs)
|
pkgs = loadPackageList(pkgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do we need to run a build to gather information?
|
// Do we need to run a build to gather information?
|
||||||
@ -538,13 +570,15 @@ func runList(cmd *base.Command, args []string) {
|
|||||||
a.Deps = append(a.Deps, b.AutoAction(work.ModeInstall, work.ModeInstall, p))
|
a.Deps = append(a.Deps, b.AutoAction(work.ModeInstall, work.ModeInstall, p))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
b.Do(a)
|
b.Do(ctx, a)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, p := range pkgs {
|
for _, p := range pkgs {
|
||||||
// Show vendor-expanded paths in listing
|
// Show vendor-expanded paths in listing
|
||||||
p.TestImports = p.Resolve(p.TestImports)
|
p.TestImports = p.Resolve(p.TestImports)
|
||||||
p.XTestImports = p.Resolve(p.XTestImports)
|
p.XTestImports = p.Resolve(p.XTestImports)
|
||||||
|
p.TestEmbedFiles = p.ResolveEmbed(p.TestEmbedPatterns)
|
||||||
|
p.XTestEmbedFiles = p.ResolveEmbed(p.XTestEmbedPatterns)
|
||||||
p.DepOnly = !cmdline[p]
|
p.DepOnly = !cmdline[p]
|
||||||
|
|
||||||
if *listCompiled {
|
if *listCompiled {
|
||||||
@ -555,7 +589,7 @@ func runList(cmd *base.Command, args []string) {
|
|||||||
if *listTest {
|
if *listTest {
|
||||||
all := pkgs
|
all := pkgs
|
||||||
if !*listDeps {
|
if !*listDeps {
|
||||||
all = load.PackageList(pkgs)
|
all = loadPackageList(pkgs)
|
||||||
}
|
}
|
||||||
// Update import paths to distinguish the real package p
|
// Update import paths to distinguish the real package p
|
||||||
// from p recompiled for q.test.
|
// from p recompiled for q.test.
|
||||||
@ -605,6 +639,55 @@ func runList(cmd *base.Command, args []string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(golang.org/issue/40676): This mechanism could be extended to support
|
||||||
|
// -u without -m.
|
||||||
|
if *listRetracted {
|
||||||
|
// Load retractions for modules that provide packages that will be printed.
|
||||||
|
// TODO(golang.org/issue/40775): Packages from the same module refer to
|
||||||
|
// distinct ModulePublic instance. It would be nice if they could all point
|
||||||
|
// to the same instance. This would require additional global state in
|
||||||
|
// modload.loaded, so that should be refactored first. For now, we update
|
||||||
|
// all instances.
|
||||||
|
modToArg := make(map[*modinfo.ModulePublic]string)
|
||||||
|
argToMods := make(map[string][]*modinfo.ModulePublic)
|
||||||
|
var args []string
|
||||||
|
addModule := func(mod *modinfo.ModulePublic) {
|
||||||
|
if mod.Version == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
arg := fmt.Sprintf("%s@%s", mod.Path, mod.Version)
|
||||||
|
if argToMods[arg] == nil {
|
||||||
|
args = append(args, arg)
|
||||||
|
}
|
||||||
|
argToMods[arg] = append(argToMods[arg], mod)
|
||||||
|
modToArg[mod] = arg
|
||||||
|
}
|
||||||
|
for _, p := range pkgs {
|
||||||
|
if p.Module == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
addModule(p.Module)
|
||||||
|
if p.Module.Replace != nil {
|
||||||
|
addModule(p.Module.Replace)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(args) > 0 {
|
||||||
|
listU := false
|
||||||
|
listVersions := false
|
||||||
|
rmods := modload.ListModules(ctx, args, listU, listVersions, *listRetracted)
|
||||||
|
for i, arg := range args {
|
||||||
|
rmod := rmods[i]
|
||||||
|
for _, mod := range argToMods[arg] {
|
||||||
|
mod.Retracted = rmod.Retracted
|
||||||
|
if rmod.Error != nil && mod.Error == nil {
|
||||||
|
mod.Error = rmod.Error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Record non-identity import mappings in p.ImportMap.
|
// Record non-identity import mappings in p.ImportMap.
|
||||||
for _, p := range pkgs {
|
for _, p := range pkgs {
|
||||||
for i, srcPath := range p.Internal.RawImports {
|
for i, srcPath := range p.Internal.RawImports {
|
||||||
@ -623,6 +706,23 @@ func runList(cmd *base.Command, args []string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// loadPackageList is like load.PackageList, but prints error messages and exits
|
||||||
|
// with nonzero status if listE is not set and any package in the expanded list
|
||||||
|
// has errors.
|
||||||
|
func loadPackageList(roots []*load.Package) []*load.Package {
|
||||||
|
pkgs := load.PackageList(roots)
|
||||||
|
|
||||||
|
if !*listE {
|
||||||
|
for _, pkg := range pkgs {
|
||||||
|
if pkg.Error != nil {
|
||||||
|
base.Errorf("%v", pkg.Error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pkgs
|
||||||
|
}
|
||||||
|
|
||||||
// TrackingWriter tracks the last byte written on every write so
|
// TrackingWriter tracks the last byte written on every write so
|
||||||
// we can avoid printing a newline if one was already written or
|
// we can avoid printing a newline if one was already written or
|
||||||
// if there is no output at all.
|
// if there is no output at all.
|
||||||
|
@ -7,14 +7,16 @@ package load
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/build"
|
"go/build"
|
||||||
"go/scanner"
|
"go/scanner"
|
||||||
"go/token"
|
"go/token"
|
||||||
"io/ioutil"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
pathpkg "path"
|
pathpkg "path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
@ -26,25 +28,14 @@ import (
|
|||||||
|
|
||||||
"cmd/go/internal/base"
|
"cmd/go/internal/base"
|
||||||
"cmd/go/internal/cfg"
|
"cmd/go/internal/cfg"
|
||||||
|
"cmd/go/internal/fsys"
|
||||||
"cmd/go/internal/modinfo"
|
"cmd/go/internal/modinfo"
|
||||||
|
"cmd/go/internal/modload"
|
||||||
"cmd/go/internal/par"
|
"cmd/go/internal/par"
|
||||||
"cmd/go/internal/search"
|
"cmd/go/internal/search"
|
||||||
"cmd/go/internal/str"
|
"cmd/go/internal/str"
|
||||||
)
|
"cmd/go/internal/trace"
|
||||||
|
"cmd/internal/sys"
|
||||||
var (
|
|
||||||
// module initialization hook; never nil, no-op if module use is disabled
|
|
||||||
ModInit func()
|
|
||||||
|
|
||||||
// module hooks; nil if module use is disabled
|
|
||||||
ModBinDir func() string // return effective bin directory
|
|
||||||
ModLookup func(parentPath string, parentIsStd bool, path string) (dir, realPath string, err error) // lookup effective meaning of import
|
|
||||||
ModPackageModuleInfo func(path string) *modinfo.ModulePublic // return module info for Package struct
|
|
||||||
ModImportPaths func(args []string) []*search.Match // expand import paths
|
|
||||||
ModPackageBuildInfo func(main string, deps []string) string // return module info to embed in binary
|
|
||||||
ModInfoProg func(info string, isgccgo bool) []byte // wrap module info in .go code for binary
|
|
||||||
ModImportFromFiles func([]string) // update go.mod to add modules for imports in these files
|
|
||||||
ModDirImportPath func(string) string // return effective import path for directory
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var IgnoreImports bool // control whether we ignore imports in packages
|
var IgnoreImports bool // control whether we ignore imports in packages
|
||||||
@ -70,6 +61,7 @@ type PackagePublic struct {
|
|||||||
ConflictDir string `json:",omitempty"` // Dir is hidden by this other directory
|
ConflictDir string `json:",omitempty"` // Dir is hidden by this other directory
|
||||||
ForTest string `json:",omitempty"` // package is only for use in named test
|
ForTest string `json:",omitempty"` // package is only for use in named test
|
||||||
Export string `json:",omitempty"` // file containing export data (set by go list -export)
|
Export string `json:",omitempty"` // file containing export data (set by go list -export)
|
||||||
|
BuildID string `json:",omitempty"` // build ID of the compiled package (set by go list -export)
|
||||||
Module *modinfo.ModulePublic `json:",omitempty"` // info about package's module, if any
|
Module *modinfo.ModulePublic `json:",omitempty"` // info about package's module, if any
|
||||||
Match []string `json:",omitempty"` // command-line patterns matching this package
|
Match []string `json:",omitempty"` // command-line patterns matching this package
|
||||||
Goroot bool `json:",omitempty"` // is this package found in the Go root?
|
Goroot bool `json:",omitempty"` // is this package found in the Go root?
|
||||||
@ -87,19 +79,24 @@ type PackagePublic struct {
|
|||||||
// Source files
|
// Source files
|
||||||
// If you add to this list you MUST add to p.AllFiles (below) too.
|
// If you add to this list you MUST add to p.AllFiles (below) too.
|
||||||
// Otherwise file name security lists will not apply to any new additions.
|
// Otherwise file name security lists will not apply to any new additions.
|
||||||
GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
|
GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
|
||||||
CgoFiles []string `json:",omitempty"` // .go source files that import "C"
|
CgoFiles []string `json:",omitempty"` // .go source files that import "C"
|
||||||
CompiledGoFiles []string `json:",omitempty"` // .go output from running cgo on CgoFiles
|
CompiledGoFiles []string `json:",omitempty"` // .go output from running cgo on CgoFiles
|
||||||
IgnoredGoFiles []string `json:",omitempty"` // .go source files ignored due to build constraints
|
IgnoredGoFiles []string `json:",omitempty"` // .go source files ignored due to build constraints
|
||||||
CFiles []string `json:",omitempty"` // .c source files
|
IgnoredOtherFiles []string `json:",omitempty"` // non-.go source files ignored due to build constraints
|
||||||
CXXFiles []string `json:",omitempty"` // .cc, .cpp and .cxx source files
|
CFiles []string `json:",omitempty"` // .c source files
|
||||||
MFiles []string `json:",omitempty"` // .m source files
|
CXXFiles []string `json:",omitempty"` // .cc, .cpp and .cxx source files
|
||||||
HFiles []string `json:",omitempty"` // .h, .hh, .hpp and .hxx source files
|
MFiles []string `json:",omitempty"` // .m source files
|
||||||
FFiles []string `json:",omitempty"` // .f, .F, .for and .f90 Fortran source files
|
HFiles []string `json:",omitempty"` // .h, .hh, .hpp and .hxx source files
|
||||||
SFiles []string `json:",omitempty"` // .s source files
|
FFiles []string `json:",omitempty"` // .f, .F, .for and .f90 Fortran source files
|
||||||
SwigFiles []string `json:",omitempty"` // .swig files
|
SFiles []string `json:",omitempty"` // .s source files
|
||||||
SwigCXXFiles []string `json:",omitempty"` // .swigcxx files
|
SwigFiles []string `json:",omitempty"` // .swig files
|
||||||
SysoFiles []string `json:",omitempty"` // .syso system object files added to package
|
SwigCXXFiles []string `json:",omitempty"` // .swigcxx files
|
||||||
|
SysoFiles []string `json:",omitempty"` // .syso system object files added to package
|
||||||
|
|
||||||
|
// Embedded files
|
||||||
|
EmbedPatterns []string `json:",omitempty"` // //go:embed patterns
|
||||||
|
EmbedFiles []string `json:",omitempty"` // files and directories matched by EmbedPatterns
|
||||||
|
|
||||||
// Cgo directives
|
// Cgo directives
|
||||||
CgoCFLAGS []string `json:",omitempty"` // cgo: flags for C compiler
|
CgoCFLAGS []string `json:",omitempty"` // cgo: flags for C compiler
|
||||||
@ -122,10 +119,14 @@ type PackagePublic struct {
|
|||||||
// Test information
|
// Test information
|
||||||
// If you add to this list you MUST add to p.AllFiles (below) too.
|
// If you add to this list you MUST add to p.AllFiles (below) too.
|
||||||
// Otherwise file name security lists will not apply to any new additions.
|
// Otherwise file name security lists will not apply to any new additions.
|
||||||
TestGoFiles []string `json:",omitempty"` // _test.go files in package
|
TestGoFiles []string `json:",omitempty"` // _test.go files in package
|
||||||
TestImports []string `json:",omitempty"` // imports from TestGoFiles
|
TestImports []string `json:",omitempty"` // imports from TestGoFiles
|
||||||
XTestGoFiles []string `json:",omitempty"` // _test.go files outside package
|
TestEmbedPatterns []string `json:",omitempty"` // //go:embed patterns
|
||||||
XTestImports []string `json:",omitempty"` // imports from XTestGoFiles
|
TestEmbedFiles []string `json:",omitempty"` // //files matched by EmbedPatterns
|
||||||
|
XTestGoFiles []string `json:",omitempty"` // _test.go files outside package
|
||||||
|
XTestImports []string `json:",omitempty"` // imports from XTestGoFiles
|
||||||
|
XTestEmbedPatterns []string `json:",omitempty"` // //go:embed patterns
|
||||||
|
XTestEmbedFiles []string `json:",omitempty"` // //files matched by EmbedPatterns
|
||||||
}
|
}
|
||||||
|
|
||||||
// AllFiles returns the names of all the files considered for the package.
|
// AllFiles returns the names of all the files considered for the package.
|
||||||
@ -134,11 +135,12 @@ type PackagePublic struct {
|
|||||||
// The go/build package filtered others out (like foo_wrongGOARCH.s)
|
// The go/build package filtered others out (like foo_wrongGOARCH.s)
|
||||||
// and that's OK.
|
// and that's OK.
|
||||||
func (p *Package) AllFiles() []string {
|
func (p *Package) AllFiles() []string {
|
||||||
return str.StringList(
|
files := str.StringList(
|
||||||
p.GoFiles,
|
p.GoFiles,
|
||||||
p.CgoFiles,
|
p.CgoFiles,
|
||||||
// no p.CompiledGoFiles, because they are from GoFiles or generated by us
|
// no p.CompiledGoFiles, because they are from GoFiles or generated by us
|
||||||
p.IgnoredGoFiles,
|
p.IgnoredGoFiles,
|
||||||
|
p.IgnoredOtherFiles,
|
||||||
p.CFiles,
|
p.CFiles,
|
||||||
p.CXXFiles,
|
p.CXXFiles,
|
||||||
p.MFiles,
|
p.MFiles,
|
||||||
@ -151,6 +153,27 @@ func (p *Package) AllFiles() []string {
|
|||||||
p.TestGoFiles,
|
p.TestGoFiles,
|
||||||
p.XTestGoFiles,
|
p.XTestGoFiles,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// EmbedFiles may overlap with the other files.
|
||||||
|
// Dedup, but delay building the map as long as possible.
|
||||||
|
// Only files in the current directory (no slash in name)
|
||||||
|
// need to be checked against the files variable above.
|
||||||
|
var have map[string]bool
|
||||||
|
for _, file := range p.EmbedFiles {
|
||||||
|
if !strings.Contains(file, "/") {
|
||||||
|
if have == nil {
|
||||||
|
have = make(map[string]bool)
|
||||||
|
for _, file := range files {
|
||||||
|
have[file] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if have[file] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
files = append(files, file)
|
||||||
|
}
|
||||||
|
return files
|
||||||
}
|
}
|
||||||
|
|
||||||
// Desc returns the package "description", for use in b.showOutput.
|
// Desc returns the package "description", for use in b.showOutput.
|
||||||
@ -180,6 +203,7 @@ type PackageInternal struct {
|
|||||||
GobinSubdir bool // install target would be subdir of GOBIN
|
GobinSubdir bool // install target would be subdir of GOBIN
|
||||||
BuildInfo string // add this info to package main
|
BuildInfo string // add this info to package main
|
||||||
TestmainGo *[]byte // content for _testmain.go
|
TestmainGo *[]byte // content for _testmain.go
|
||||||
|
Embed map[string][]string // //go:embed comment mapping
|
||||||
|
|
||||||
Asmflags []string // -asmflags for this package
|
Asmflags []string // -asmflags for this package
|
||||||
Gcflags []string // -gcflags for this package
|
Gcflags []string // -gcflags for this package
|
||||||
@ -197,7 +221,7 @@ type NoGoError struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *NoGoError) Error() string {
|
func (e *NoGoError) Error() string {
|
||||||
if len(e.Package.constraintIgnoredGoFiles()) > 0 {
|
if len(e.Package.IgnoredGoFiles) > 0 {
|
||||||
// Go files exist, but they were ignored due to build constraints.
|
// Go files exist, but they were ignored due to build constraints.
|
||||||
return "build constraints exclude all Go files in " + e.Package.Dir
|
return "build constraints exclude all Go files in " + e.Package.Dir
|
||||||
}
|
}
|
||||||
@ -260,8 +284,8 @@ func (p *Package) setLoadPackageDataError(err error, path string, stk *ImportSta
|
|||||||
// package's source files themselves (scanner errors).
|
// package's source files themselves (scanner errors).
|
||||||
//
|
//
|
||||||
// TODO(matloob): Perhaps make each of those the errors in the first group
|
// TODO(matloob): Perhaps make each of those the errors in the first group
|
||||||
// (including modload.ImportMissingError, and the corresponding
|
// (including modload.ImportMissingError, ImportMissingSumError, and the
|
||||||
// "cannot find package %q in any of" GOPATH-mode error
|
// corresponding "cannot find package %q in any of" GOPATH-mode error
|
||||||
// produced in build.(*Context).Import; modload.AmbiguousImportError,
|
// produced in build.(*Context).Import; modload.AmbiguousImportError,
|
||||||
// and modload.PackageNotInModuleError; and the malformed module path errors
|
// and modload.PackageNotInModuleError; and the malformed module path errors
|
||||||
// produced in golang.org/x/mod/module.CheckMod) implement an interface
|
// produced in golang.org/x/mod/module.CheckMod) implement an interface
|
||||||
@ -342,6 +366,7 @@ func (p *Package) copyBuild(pp *build.Package) {
|
|||||||
p.GoFiles = pp.GoFiles
|
p.GoFiles = pp.GoFiles
|
||||||
p.CgoFiles = pp.CgoFiles
|
p.CgoFiles = pp.CgoFiles
|
||||||
p.IgnoredGoFiles = pp.IgnoredGoFiles
|
p.IgnoredGoFiles = pp.IgnoredGoFiles
|
||||||
|
p.IgnoredOtherFiles = pp.IgnoredOtherFiles
|
||||||
p.CFiles = pp.CFiles
|
p.CFiles = pp.CFiles
|
||||||
p.CXXFiles = pp.CXXFiles
|
p.CXXFiles = pp.CXXFiles
|
||||||
p.MFiles = pp.MFiles
|
p.MFiles = pp.MFiles
|
||||||
@ -371,6 +396,9 @@ func (p *Package) copyBuild(pp *build.Package) {
|
|||||||
p.TestImports = nil
|
p.TestImports = nil
|
||||||
p.XTestImports = nil
|
p.XTestImports = nil
|
||||||
}
|
}
|
||||||
|
p.EmbedPatterns = pp.EmbedPatterns
|
||||||
|
p.TestEmbedPatterns = pp.TestEmbedPatterns
|
||||||
|
p.XTestEmbedPatterns = pp.XTestEmbedPatterns
|
||||||
}
|
}
|
||||||
|
|
||||||
// A PackageError describes an error loading information about a package.
|
// A PackageError describes an error loading information about a package.
|
||||||
@ -432,13 +460,17 @@ type ImportPathError interface {
|
|||||||
ImportPath() string
|
ImportPath() string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ ImportPathError = (*importError)(nil)
|
||||||
|
_ ImportPathError = (*modload.ImportMissingError)(nil)
|
||||||
|
_ ImportPathError = (*modload.ImportMissingSumError)(nil)
|
||||||
|
)
|
||||||
|
|
||||||
type importError struct {
|
type importError struct {
|
||||||
importPath string
|
importPath string
|
||||||
err error // created with fmt.Errorf
|
err error // created with fmt.Errorf
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ ImportPathError = (*importError)(nil)
|
|
||||||
|
|
||||||
func ImportErrorf(path, format string, args ...interface{}) ImportPathError {
|
func ImportErrorf(path, format string, args ...interface{}) 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) {
|
||||||
@ -551,7 +583,7 @@ func ReloadPackageNoFlags(arg string, stk *ImportStack) *Package {
|
|||||||
})
|
})
|
||||||
packageDataCache.Delete(p.ImportPath)
|
packageDataCache.Delete(p.ImportPath)
|
||||||
}
|
}
|
||||||
return LoadImport(arg, base.Cwd, nil, stk, nil, 0)
|
return LoadImport(context.TODO(), arg, base.Cwd, nil, stk, nil, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// dirToImportPath returns the pseudo-import path we use for a package
|
// dirToImportPath returns the pseudo-import path we use for a package
|
||||||
@ -603,11 +635,11 @@ const (
|
|||||||
// LoadImport does not set tool flags and should only be used by
|
// LoadImport does not set tool flags and should only be used by
|
||||||
// this package, as part of a bigger load operation, and by GOPATH-based "go get".
|
// this package, as part of a bigger load operation, and by GOPATH-based "go get".
|
||||||
// TODO(rsc): When GOPATH-based "go get" is removed, unexport this function.
|
// TODO(rsc): When GOPATH-based "go get" is removed, unexport this function.
|
||||||
func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) *Package {
|
func LoadImport(ctx context.Context, path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) *Package {
|
||||||
return loadImport(nil, path, srcDir, parent, stk, importPos, mode)
|
return loadImport(ctx, nil, path, srcDir, parent, stk, importPos, mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadImport(pre *preload, path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) *Package {
|
func loadImport(ctx context.Context, pre *preload, path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) *Package {
|
||||||
if path == "" {
|
if path == "" {
|
||||||
panic("LoadImport called with empty package path")
|
panic("LoadImport called with empty package path")
|
||||||
}
|
}
|
||||||
@ -655,7 +687,7 @@ func loadImport(pre *preload, path, srcDir string, parent *Package, stk *ImportS
|
|||||||
// Load package.
|
// Load package.
|
||||||
// loadPackageData may return bp != nil even if an error occurs,
|
// loadPackageData may return bp != nil even if an error occurs,
|
||||||
// in order to return partial information.
|
// in order to return partial information.
|
||||||
p.load(path, stk, importPos, bp, err)
|
p.load(ctx, path, stk, importPos, bp, err)
|
||||||
|
|
||||||
if !cfg.ModulesEnabled && path != cleanImport(path) {
|
if !cfg.ModulesEnabled && path != cleanImport(path) {
|
||||||
p.Error = &PackageError{
|
p.Error = &PackageError{
|
||||||
@ -751,7 +783,7 @@ func loadPackageData(path, parentPath, parentDir, parentRoot string, parentIsStd
|
|||||||
// For vendored imports, it is the expanded form.
|
// For vendored imports, it is the expanded form.
|
||||||
//
|
//
|
||||||
// Note that when modules are enabled, local import paths are normally
|
// Note that when modules are enabled, local import paths are normally
|
||||||
// canonicalized by modload.ImportPaths before now. However, if there's an
|
// canonicalized by modload.LoadPackages before now. However, if there's an
|
||||||
// error resolving a local path, it will be returned untransformed
|
// error resolving a local path, it will be returned untransformed
|
||||||
// so that 'go list -e' reports something useful.
|
// so that 'go list -e' reports something useful.
|
||||||
importKey := importSpec{
|
importKey := importSpec{
|
||||||
@ -768,7 +800,7 @@ func loadPackageData(path, parentPath, parentDir, parentRoot string, parentIsStd
|
|||||||
r.dir = filepath.Join(parentDir, path)
|
r.dir = filepath.Join(parentDir, path)
|
||||||
r.path = dirToImportPath(r.dir)
|
r.path = dirToImportPath(r.dir)
|
||||||
} else if cfg.ModulesEnabled {
|
} else if cfg.ModulesEnabled {
|
||||||
r.dir, r.path, r.err = ModLookup(parentPath, parentIsStd, path)
|
r.dir, r.path, r.err = modload.Lookup(parentPath, parentIsStd, path)
|
||||||
} else if mode&ResolveImport != 0 {
|
} else if mode&ResolveImport != 0 {
|
||||||
// We do our own path resolution, because we want to
|
// We do our own path resolution, because we want to
|
||||||
// find out the key to use in packageCache without the
|
// find out the key to use in packageCache without the
|
||||||
@ -799,7 +831,7 @@ func loadPackageData(path, parentPath, parentDir, parentRoot string, parentIsStd
|
|||||||
}
|
}
|
||||||
data.p, data.err = cfg.BuildContext.ImportDir(r.dir, buildMode)
|
data.p, data.err = cfg.BuildContext.ImportDir(r.dir, buildMode)
|
||||||
if data.p.Root == "" && cfg.ModulesEnabled {
|
if data.p.Root == "" && cfg.ModulesEnabled {
|
||||||
if info := ModPackageModuleInfo(path); info != nil {
|
if info := modload.PackageModuleInfo(path); info != nil {
|
||||||
data.p.Root = info.Dir
|
data.p.Root = info.Dir
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -825,7 +857,7 @@ func loadPackageData(path, parentPath, parentDir, parentRoot string, parentIsStd
|
|||||||
if cfg.GOBIN != "" {
|
if cfg.GOBIN != "" {
|
||||||
data.p.BinDir = cfg.GOBIN
|
data.p.BinDir = cfg.GOBIN
|
||||||
} else if cfg.ModulesEnabled {
|
} else if cfg.ModulesEnabled {
|
||||||
data.p.BinDir = ModBinDir()
|
data.p.BinDir = modload.BinDir()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -893,8 +925,8 @@ var preloadWorkerCount = runtime.GOMAXPROCS(0)
|
|||||||
// to ensure preload goroutines are no longer active. This is necessary
|
// to ensure preload goroutines are no longer active. This is necessary
|
||||||
// because of global mutable state that cannot safely be read and written
|
// because of global mutable state that cannot safely be read and written
|
||||||
// concurrently. In particular, packageDataCache may be cleared by "go get"
|
// concurrently. In particular, packageDataCache may be cleared by "go get"
|
||||||
// in GOPATH mode, and modload.loaded (accessed via ModLookup) may be
|
// in GOPATH mode, and modload.loaded (accessed via modload.Lookup) may be
|
||||||
// modified by modload.ImportPaths (ModImportPaths).
|
// modified by modload.LoadPackages.
|
||||||
type preload struct {
|
type preload struct {
|
||||||
cancel chan struct{}
|
cancel chan struct{}
|
||||||
sema chan struct{}
|
sema chan struct{}
|
||||||
@ -961,6 +993,12 @@ func (pre *preload) preloadImports(imports []string, parent *build.Package) {
|
|||||||
// loadPackageData have completed. The preloader will not make any new calls
|
// loadPackageData have completed. The preloader will not make any new calls
|
||||||
// to loadPackageData.
|
// to loadPackageData.
|
||||||
func (pre *preload) flush() {
|
func (pre *preload) flush() {
|
||||||
|
// flush is usually deferred.
|
||||||
|
// Don't hang program waiting for workers on panic.
|
||||||
|
if v := recover(); v != nil {
|
||||||
|
panic(v)
|
||||||
|
}
|
||||||
|
|
||||||
close(pre.cancel)
|
close(pre.cancel)
|
||||||
for i := 0; i < preloadWorkerCount; i++ {
|
for i := 0; i < preloadWorkerCount; i++ {
|
||||||
pre.sema <- struct{}{}
|
pre.sema <- struct{}{}
|
||||||
@ -980,7 +1018,7 @@ 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() interface{} {
|
||||||
fi, err := os.Stat(path)
|
fi, err := fsys.Stat(path)
|
||||||
return err == nil && fi.IsDir()
|
return err == nil && fi.IsDir()
|
||||||
}).(bool)
|
}).(bool)
|
||||||
}
|
}
|
||||||
@ -1004,7 +1042,7 @@ func ResolveImportPath(parent *Package, path string) (found string) {
|
|||||||
|
|
||||||
func resolveImportPath(path, parentPath, parentDir, parentRoot string, parentIsStd bool) (found string) {
|
func resolveImportPath(path, parentPath, parentDir, parentRoot string, parentIsStd bool) (found string) {
|
||||||
if cfg.ModulesEnabled {
|
if cfg.ModulesEnabled {
|
||||||
if _, p, e := ModLookup(parentPath, parentIsStd, path); e == nil {
|
if _, p, e := modload.Lookup(parentPath, parentIsStd, path); e == nil {
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
return path
|
return path
|
||||||
@ -1108,7 +1146,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() interface{} {
|
||||||
data, err := ioutil.ReadFile(filepath.Join(dir, "go.mod"))
|
data, err := os.ReadFile(filepath.Join(dir, "go.mod"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@ -1257,9 +1295,9 @@ HaveGoMod:
|
|||||||
// Otherwise it is not possible to vendor just a/b/c and still import the
|
// Otherwise it is not possible to vendor just a/b/c and still import the
|
||||||
// non-vendored a/b. See golang.org/issue/13832.
|
// non-vendored a/b. See golang.org/issue/13832.
|
||||||
func hasGoFiles(dir string) bool {
|
func hasGoFiles(dir string) bool {
|
||||||
fis, _ := ioutil.ReadDir(dir)
|
files, _ := os.ReadDir(dir)
|
||||||
for _, fi := range fis {
|
for _, f := range files {
|
||||||
if !fi.IsDir() && strings.HasSuffix(fi.Name(), ".go") {
|
if !f.IsDir() && strings.HasSuffix(f.Name(), ".go") {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1373,7 +1411,7 @@ func disallowInternal(srcDir string, importer *Package, importerPath string, p *
|
|||||||
// 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 module, this will resolve to ".",
|
||||||
// which is not a prefix of any valid module.
|
// which is not a prefix of any valid module.
|
||||||
importerPath = ModDirImportPath(importer.Dir)
|
importerPath = modload.DirImportPath(importer.Dir)
|
||||||
}
|
}
|
||||||
parentOfInternal := p.ImportPath[:i]
|
parentOfInternal := p.ImportPath[:i]
|
||||||
if str.HasPathPrefix(importerPath, parentOfInternal) {
|
if str.HasPathPrefix(importerPath, parentOfInternal) {
|
||||||
@ -1595,7 +1633,7 @@ func (p *Package) DefaultExecName() string {
|
|||||||
// load populates p using information from bp, err, which should
|
// load populates p using information from bp, err, which should
|
||||||
// be the result of calling build.Context.Import.
|
// be the result of calling build.Context.Import.
|
||||||
// stk contains the import stack, not including path itself.
|
// stk contains the import stack, not including path itself.
|
||||||
func (p *Package) load(path string, stk *ImportStack, importPos []token.Position, bp *build.Package, err error) {
|
func (p *Package) load(ctx context.Context, path string, stk *ImportStack, importPos []token.Position, bp *build.Package, err error) {
|
||||||
p.copyBuild(bp)
|
p.copyBuild(bp)
|
||||||
|
|
||||||
// The localPrefix is the path we interpret ./ imports relative to.
|
// The localPrefix is the path we interpret ./ imports relative to.
|
||||||
@ -1631,6 +1669,11 @@ func (p *Package) load(path string, stk *ImportStack, importPos []token.Position
|
|||||||
p.setLoadPackageDataError(err, path, stk, importPos)
|
p.setLoadPackageDataError(err, path, stk, importPos)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.EmbedFiles, p.Internal.Embed, err = p.resolveEmbed(p.EmbedPatterns)
|
||||||
|
if err != nil {
|
||||||
|
setError(err)
|
||||||
|
}
|
||||||
|
|
||||||
useBindir := p.Name == "main"
|
useBindir := p.Name == "main"
|
||||||
if !p.Standard {
|
if !p.Standard {
|
||||||
switch cfg.BuildBuildmode {
|
switch cfg.BuildBuildmode {
|
||||||
@ -1656,7 +1699,7 @@ func (p *Package) load(path string, stk *ImportStack, importPos []token.Position
|
|||||||
elem = full
|
elem = full
|
||||||
}
|
}
|
||||||
if p.Internal.Build.BinDir == "" && cfg.ModulesEnabled {
|
if p.Internal.Build.BinDir == "" && cfg.ModulesEnabled {
|
||||||
p.Internal.Build.BinDir = ModBinDir()
|
p.Internal.Build.BinDir = modload.BinDir()
|
||||||
}
|
}
|
||||||
if p.Internal.Build.BinDir != "" {
|
if p.Internal.Build.BinDir != "" {
|
||||||
// Install to GOBIN or bin of GOPATH entry.
|
// Install to GOBIN or bin of GOPATH entry.
|
||||||
@ -1690,7 +1733,7 @@ func (p *Package) load(path string, stk *ImportStack, importPos []token.Position
|
|||||||
// not work for any package that lacks a Target — such as a non-main
|
// not work for any package that lacks a Target — such as a non-main
|
||||||
// package in module mode. We should probably fix that.
|
// package in module mode. We should probably fix that.
|
||||||
shlibnamefile := p.Target[:len(p.Target)-2] + ".shlibname"
|
shlibnamefile := p.Target[:len(p.Target)-2] + ".shlibname"
|
||||||
shlib, err := ioutil.ReadFile(shlibnamefile)
|
shlib, err := os.ReadFile(shlibnamefile)
|
||||||
if err != nil && !os.IsNotExist(err) {
|
if err != nil && !os.IsNotExist(err) {
|
||||||
base.Fatalf("reading shlibname: %v", err)
|
base.Fatalf("reading shlibname: %v", err)
|
||||||
}
|
}
|
||||||
@ -1804,7 +1847,7 @@ func (p *Package) load(path string, stk *ImportStack, importPos []token.Position
|
|||||||
if path == "C" {
|
if path == "C" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
p1 := LoadImport(path, p.Dir, p, stk, p.Internal.Build.ImportPos[path], ResolveImport)
|
p1 := LoadImport(ctx, path, p.Dir, p, stk, p.Internal.Build.ImportPos[path], ResolveImport)
|
||||||
|
|
||||||
path = p1.ImportPath
|
path = p1.ImportPath
|
||||||
importPaths[i] = path
|
importPaths[i] = path
|
||||||
@ -1865,13 +1908,169 @@ func (p *Package) load(path string, stk *ImportStack, importPos []token.Position
|
|||||||
if p.Internal.CmdlineFiles {
|
if p.Internal.CmdlineFiles {
|
||||||
mainPath = "command-line-arguments"
|
mainPath = "command-line-arguments"
|
||||||
}
|
}
|
||||||
p.Module = ModPackageModuleInfo(mainPath)
|
p.Module = modload.PackageModuleInfo(mainPath)
|
||||||
if p.Name == "main" && len(p.DepsErrors) == 0 {
|
if p.Name == "main" && len(p.DepsErrors) == 0 {
|
||||||
p.Internal.BuildInfo = ModPackageBuildInfo(mainPath, p.Deps)
|
p.Internal.BuildInfo = modload.PackageBuildInfo(mainPath, p.Deps)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ResolveEmbed resolves //go:embed patterns and returns only the file list.
|
||||||
|
// For use by go list to compute p.TestEmbedFiles and p.XTestEmbedFiles.
|
||||||
|
func (p *Package) ResolveEmbed(patterns []string) []string {
|
||||||
|
files, _, _ := p.resolveEmbed(patterns)
|
||||||
|
return files
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolveEmbed resolves //go:embed patterns to precise file lists.
|
||||||
|
// It sets files to the list of unique files matched (for go list),
|
||||||
|
// and it sets pmap to the more precise mapping from
|
||||||
|
// patterns to files.
|
||||||
|
// TODO(rsc): All these messages need position information for better error reports.
|
||||||
|
func (p *Package) resolveEmbed(patterns []string) (files []string, pmap map[string][]string, err error) {
|
||||||
|
pmap = make(map[string][]string)
|
||||||
|
have := make(map[string]int)
|
||||||
|
dirOK := make(map[string]bool)
|
||||||
|
pid := 0 // pattern ID, to allow reuse of have map
|
||||||
|
for _, pattern := range patterns {
|
||||||
|
pid++
|
||||||
|
|
||||||
|
// Check pattern is valid for //go:embed.
|
||||||
|
if _, err := path.Match(pattern, ""); err != nil || !validEmbedPattern(pattern) {
|
||||||
|
return nil, nil, fmt.Errorf("pattern %s: invalid pattern syntax", pattern)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Glob to find matches.
|
||||||
|
match, err := fsys.Glob(p.Dir + string(filepath.Separator) + filepath.FromSlash(pattern))
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("pattern %s: %v", pattern, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter list of matches down to the ones that will still exist when
|
||||||
|
// the directory is packaged up as a module. (If p.Dir is in the module cache,
|
||||||
|
// only those files exist already, but if p.Dir is in the current module,
|
||||||
|
// then there may be other things lying around, like symbolic links or .git directories.)
|
||||||
|
var list []string
|
||||||
|
for _, file := range match {
|
||||||
|
rel := filepath.ToSlash(file[len(p.Dir)+1:]) // file, relative to p.Dir
|
||||||
|
|
||||||
|
what := "file"
|
||||||
|
info, err := fsys.Lstat(file)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
if info.IsDir() {
|
||||||
|
what = "directory"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that directories along path do not begin a new module
|
||||||
|
// (do not contain a go.mod).
|
||||||
|
for dir := file; len(dir) > len(p.Dir)+1 && !dirOK[dir]; dir = filepath.Dir(dir) {
|
||||||
|
if _, err := fsys.Stat(filepath.Join(dir, "go.mod")); err == nil {
|
||||||
|
return nil, nil, fmt.Errorf("pattern %s: cannot embed %s %s: in different module", pattern, what, rel)
|
||||||
|
}
|
||||||
|
if dir != file {
|
||||||
|
if info, err := fsys.Lstat(dir); err == nil && !info.IsDir() {
|
||||||
|
return nil, nil, fmt.Errorf("pattern %s: cannot embed %s %s: in non-directory %s", pattern, what, rel, dir[len(p.Dir)+1:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dirOK[dir] = true
|
||||||
|
if elem := filepath.Base(dir); isBadEmbedName(elem) {
|
||||||
|
if dir == file {
|
||||||
|
return nil, nil, fmt.Errorf("pattern %s: cannot embed %s %s: invalid name %s", pattern, what, rel, elem)
|
||||||
|
} else {
|
||||||
|
return nil, nil, fmt.Errorf("pattern %s: cannot embed %s %s: in invalid directory %s", pattern, what, rel, elem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
default:
|
||||||
|
return nil, nil, fmt.Errorf("pattern %s: cannot embed irregular file %s", pattern, rel)
|
||||||
|
|
||||||
|
case info.Mode().IsRegular():
|
||||||
|
if have[rel] != pid {
|
||||||
|
have[rel] = pid
|
||||||
|
list = append(list, rel)
|
||||||
|
}
|
||||||
|
|
||||||
|
case info.IsDir():
|
||||||
|
// Gather all files in the named directory, stopping at module boundaries
|
||||||
|
// and ignoring files that wouldn't be packaged into a module.
|
||||||
|
count := 0
|
||||||
|
err := fsys.Walk(file, func(path string, info os.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rel := filepath.ToSlash(path[len(p.Dir)+1:])
|
||||||
|
name := info.Name()
|
||||||
|
if path != file && (isBadEmbedName(name) || name[0] == '.' || name[0] == '_') {
|
||||||
|
// Ignore bad names, assuming they won't go into modules.
|
||||||
|
// Also avoid hidden files that user may not know about.
|
||||||
|
// See golang.org/issue/42328.
|
||||||
|
if info.IsDir() {
|
||||||
|
return fs.SkipDir
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if info.IsDir() {
|
||||||
|
if _, err := fsys.Stat(filepath.Join(path, "go.mod")); err == nil {
|
||||||
|
return filepath.SkipDir
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if !info.Mode().IsRegular() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
count++
|
||||||
|
if have[rel] != pid {
|
||||||
|
have[rel] = pid
|
||||||
|
list = append(list, rel)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
if count == 0 {
|
||||||
|
return nil, nil, fmt.Errorf("pattern %s: cannot embed directory %s: contains no embeddable files", pattern, rel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(list) == 0 {
|
||||||
|
return nil, nil, fmt.Errorf("pattern %s: no matching files found", pattern)
|
||||||
|
}
|
||||||
|
sort.Strings(list)
|
||||||
|
pmap[pattern] = list
|
||||||
|
}
|
||||||
|
|
||||||
|
for file := range have {
|
||||||
|
files = append(files, file)
|
||||||
|
}
|
||||||
|
sort.Strings(files)
|
||||||
|
return files, pmap, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validEmbedPattern(pattern string) bool {
|
||||||
|
return pattern != "." && fs.ValidPath(pattern)
|
||||||
|
}
|
||||||
|
|
||||||
|
// isBadEmbedName reports whether name is the base name of a file that
|
||||||
|
// can't or won't be included in modules and therefore shouldn't be treated
|
||||||
|
// as existing for embedding.
|
||||||
|
func isBadEmbedName(name string) bool {
|
||||||
|
switch name {
|
||||||
|
// Empty string should be impossible but make it bad.
|
||||||
|
case "":
|
||||||
|
return true
|
||||||
|
// Version control directories won't be present in module.
|
||||||
|
case ".bzr", ".hg", ".git", ".svn":
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// collectDeps populates p.Deps and p.DepsErrors by iterating over
|
// collectDeps populates p.Deps and p.DepsErrors by iterating over
|
||||||
// p.Internal.Imports.
|
// p.Internal.Imports.
|
||||||
//
|
//
|
||||||
@ -1959,37 +2158,40 @@ func LinkerDeps(p *Package) []string {
|
|||||||
// externalLinkingForced reports whether external linking is being
|
// externalLinkingForced reports whether external linking is being
|
||||||
// forced even for programs that do not use cgo.
|
// forced even for programs that do not use cgo.
|
||||||
func externalLinkingForced(p *Package) bool {
|
func externalLinkingForced(p *Package) bool {
|
||||||
|
if !cfg.BuildContext.CgoEnabled {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// Some targets must use external linking even inside GOROOT.
|
// Some targets must use external linking even inside GOROOT.
|
||||||
switch cfg.BuildContext.GOOS {
|
switch cfg.BuildContext.GOOS {
|
||||||
case "android":
|
case "android":
|
||||||
if cfg.BuildContext.GOARCH != "arm64" {
|
if cfg.BuildContext.GOARCH != "arm64" {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
case "darwin":
|
case "ios":
|
||||||
if cfg.BuildContext.GOARCH == "arm64" {
|
return true
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !cfg.BuildContext.CgoEnabled {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// Currently build modes c-shared, pie (on systems that do not
|
// Currently build modes c-shared, pie (on systems that do not
|
||||||
// support PIE with internal linking mode (currently all
|
// support PIE with internal linking mode (currently all
|
||||||
// systems: issue #18968)), plugin, and -linkshared force
|
// systems: issue #18968)), plugin, and -linkshared force
|
||||||
// external linking mode, as of course does
|
// external linking mode, as of course does
|
||||||
// -ldflags=-linkmode=external. External linking mode forces
|
// -ldflags=-linkmode=external. External linking mode forces
|
||||||
// an import of runtime/cgo.
|
// an import of runtime/cgo.
|
||||||
pieCgo := cfg.BuildBuildmode == "pie"
|
// If there are multiple -linkmode options, the last one wins.
|
||||||
|
pieCgo := cfg.BuildBuildmode == "pie" && !sys.InternalLinkPIESupported(cfg.BuildContext.GOOS, cfg.BuildContext.GOARCH)
|
||||||
linkmodeExternal := false
|
linkmodeExternal := false
|
||||||
if p != nil {
|
if p != nil {
|
||||||
ldflags := BuildLdflags.For(p)
|
ldflags := BuildLdflags.For(p)
|
||||||
for i, a := range ldflags {
|
for i := len(ldflags) - 1; i >= 0; i-- {
|
||||||
if a == "-linkmode=external" {
|
a := ldflags[i]
|
||||||
linkmodeExternal = true
|
if a == "-linkmode=external" ||
|
||||||
}
|
a == "-linkmode" && i+1 < len(ldflags) && ldflags[i+1] == "external" {
|
||||||
if a == "-linkmode" && i+1 < len(ldflags) && ldflags[i+1] == "external" {
|
|
||||||
linkmodeExternal = true
|
linkmodeExternal = true
|
||||||
|
break
|
||||||
|
} else if a == "-linkmode=internal" ||
|
||||||
|
a == "-linkmode" && i+1 < len(ldflags) && ldflags[i+1] == "internal" {
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2024,22 +2226,7 @@ func (p *Package) InternalXGoFiles() []string {
|
|||||||
// using absolute paths. "Possibly relevant" means that files are not excluded
|
// using absolute paths. "Possibly relevant" means that files are not excluded
|
||||||
// due to build tags, but files with names beginning with . or _ are still excluded.
|
// due to build tags, but files with names beginning with . or _ are still excluded.
|
||||||
func (p *Package) InternalAllGoFiles() []string {
|
func (p *Package) InternalAllGoFiles() []string {
|
||||||
return p.mkAbs(str.StringList(p.constraintIgnoredGoFiles(), p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles))
|
return p.mkAbs(str.StringList(p.IgnoredGoFiles, p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles))
|
||||||
}
|
|
||||||
|
|
||||||
// constraintIgnoredGoFiles returns the list of Go files ignored for reasons
|
|
||||||
// other than having a name beginning with '.' or '_'.
|
|
||||||
func (p *Package) constraintIgnoredGoFiles() []string {
|
|
||||||
if len(p.IgnoredGoFiles) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
files := make([]string, 0, len(p.IgnoredGoFiles))
|
|
||||||
for _, f := range p.IgnoredGoFiles {
|
|
||||||
if f != "" && f[0] != '.' && f[0] != '_' {
|
|
||||||
files = append(files, f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return files
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// usesSwig reports whether the package needs to run SWIG.
|
// usesSwig reports whether the package needs to run SWIG.
|
||||||
@ -2077,7 +2264,7 @@ func PackageList(roots []*Package) []*Package {
|
|||||||
// TestPackageList returns the list of packages in the dag rooted at roots
|
// TestPackageList returns the list of packages in the dag rooted at roots
|
||||||
// as visited in a depth-first post-order traversal, including the test
|
// as visited in a depth-first post-order traversal, including the test
|
||||||
// imports of the roots. This ignores errors in test packages.
|
// imports of the roots. This ignores errors in test packages.
|
||||||
func TestPackageList(roots []*Package) []*Package {
|
func TestPackageList(ctx context.Context, roots []*Package) []*Package {
|
||||||
seen := map[*Package]bool{}
|
seen := map[*Package]bool{}
|
||||||
all := []*Package{}
|
all := []*Package{}
|
||||||
var walk func(*Package)
|
var walk func(*Package)
|
||||||
@ -2093,7 +2280,7 @@ func TestPackageList(roots []*Package) []*Package {
|
|||||||
}
|
}
|
||||||
walkTest := func(root *Package, path string) {
|
walkTest := func(root *Package, path string) {
|
||||||
var stk ImportStack
|
var stk ImportStack
|
||||||
p1 := LoadImport(path, root.Dir, root, &stk, root.Internal.Build.TestImportPos[path], ResolveImport)
|
p1 := LoadImport(ctx, path, root.Dir, root, &stk, root.Internal.Build.TestImportPos[path], ResolveImport)
|
||||||
if p1.Error == nil {
|
if p1.Error == nil {
|
||||||
walk(p1)
|
walk(p1)
|
||||||
}
|
}
|
||||||
@ -2116,36 +2303,35 @@ func TestPackageList(roots []*Package) []*Package {
|
|||||||
// TODO(jayconrod): delete this function and set flags automatically
|
// TODO(jayconrod): delete this function and set flags automatically
|
||||||
// in LoadImport instead.
|
// in LoadImport instead.
|
||||||
func LoadImportWithFlags(path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) *Package {
|
func LoadImportWithFlags(path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) *Package {
|
||||||
p := LoadImport(path, srcDir, parent, stk, importPos, mode)
|
p := LoadImport(context.TODO(), path, srcDir, parent, stk, importPos, mode)
|
||||||
setToolFlags(p)
|
setToolFlags(p)
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
// Packages returns the packages named by the
|
// ModResolveTests indicates whether calls to the module loader should also
|
||||||
// command line arguments 'args'. If a named package
|
// resolve test dependencies of the requested packages.
|
||||||
// cannot be loaded at all (for example, if the directory does not exist),
|
//
|
||||||
// then packages prints an error and does not include that
|
// If ModResolveTests is true, then the module loader needs to resolve test
|
||||||
// package in the results. However, if errors occur trying
|
// dependencies at the same time as packages; otherwise, the test dependencies
|
||||||
// to load dependencies of a named package, the named
|
// of those packages could be missing, and resolving those missing dependencies
|
||||||
// package is still returned, with p.Incomplete = true
|
// could change the selected versions of modules that provide other packages.
|
||||||
// and details in p.DepsErrors.
|
//
|
||||||
func Packages(args []string) []*Package {
|
// TODO(#40775): Change this from a global variable to an explicit function
|
||||||
var pkgs []*Package
|
// argument where needed.
|
||||||
for _, pkg := range PackagesAndErrors(args) {
|
var ModResolveTests bool
|
||||||
if pkg.Error != nil {
|
|
||||||
base.Errorf("%v", pkg.Error)
|
// PackagesAndErrors returns the packages named by the command line arguments
|
||||||
continue
|
// 'patterns'. If a named package cannot be loaded, PackagesAndErrors returns
|
||||||
}
|
// a *Package with the Error field describing the failure. If errors are found
|
||||||
pkgs = append(pkgs, pkg)
|
// loading imported packages, the DepsErrors field is set. The Incomplete field
|
||||||
}
|
// may be set as well.
|
||||||
return pkgs
|
//
|
||||||
}
|
// To obtain a flat list of packages, use PackageList.
|
||||||
|
// To report errors loading packages, use ReportPackageErrors.
|
||||||
|
func PackagesAndErrors(ctx context.Context, patterns []string) []*Package {
|
||||||
|
ctx, span := trace.StartSpan(ctx, "load.PackagesAndErrors")
|
||||||
|
defer span.Done()
|
||||||
|
|
||||||
// PackagesAndErrors is like 'packages' but returns a
|
|
||||||
// *Package for every argument, even the ones that
|
|
||||||
// cannot be loaded at all.
|
|
||||||
// The packages that fail to load will have p.Error != nil.
|
|
||||||
func PackagesAndErrors(patterns []string) []*Package {
|
|
||||||
for _, p := range patterns {
|
for _, p := range patterns {
|
||||||
// Listing is only supported with all patterns referring to either:
|
// Listing is only supported with all patterns referring to either:
|
||||||
// - Files that are part of the same directory.
|
// - Files that are part of the same directory.
|
||||||
@ -2153,13 +2339,24 @@ func PackagesAndErrors(patterns []string) []*Package {
|
|||||||
if strings.HasSuffix(p, ".go") {
|
if strings.HasSuffix(p, ".go") {
|
||||||
// We need to test whether the path is an actual Go file and not a
|
// We need to test whether the path is an actual Go file and not a
|
||||||
// package path or pattern ending in '.go' (see golang.org/issue/34653).
|
// package path or pattern ending in '.go' (see golang.org/issue/34653).
|
||||||
if fi, err := os.Stat(p); err == nil && !fi.IsDir() {
|
if fi, err := fsys.Stat(p); err == nil && !fi.IsDir() {
|
||||||
return []*Package{GoFilesPackage(patterns)}
|
return []*Package{GoFilesPackage(ctx, patterns)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
matches := ImportPaths(patterns)
|
var matches []*search.Match
|
||||||
|
if modload.Init(); cfg.ModulesEnabled {
|
||||||
|
loadOpts := modload.PackageOpts{
|
||||||
|
ResolveMissingImports: true,
|
||||||
|
LoadTests: ModResolveTests,
|
||||||
|
SilenceErrors: true,
|
||||||
|
}
|
||||||
|
matches, _ = modload.LoadPackages(ctx, loadOpts, patterns...)
|
||||||
|
} else {
|
||||||
|
matches = search.ImportPaths(patterns)
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
pkgs []*Package
|
pkgs []*Package
|
||||||
stk ImportStack
|
stk ImportStack
|
||||||
@ -2175,7 +2372,7 @@ func PackagesAndErrors(patterns []string) []*Package {
|
|||||||
if pkg == "" {
|
if pkg == "" {
|
||||||
panic(fmt.Sprintf("ImportPaths returned empty package for pattern %s", m.Pattern()))
|
panic(fmt.Sprintf("ImportPaths returned empty package for pattern %s", m.Pattern()))
|
||||||
}
|
}
|
||||||
p := loadImport(pre, pkg, base.Cwd, nil, &stk, nil, 0)
|
p := loadImport(ctx, pre, pkg, base.Cwd, nil, &stk, nil, 0)
|
||||||
p.Match = append(p.Match, m.Pattern())
|
p.Match = append(p.Match, m.Pattern())
|
||||||
p.Internal.CmdlinePkg = true
|
p.Internal.CmdlinePkg = true
|
||||||
if m.IsLiteral() {
|
if m.IsLiteral() {
|
||||||
@ -2220,27 +2417,9 @@ func PackagesAndErrors(patterns []string) []*Package {
|
|||||||
return pkgs
|
return pkgs
|
||||||
}
|
}
|
||||||
|
|
||||||
func setToolFlags(pkgs ...*Package) {
|
// CheckPackageErrors prints errors encountered loading pkgs and their
|
||||||
for _, p := range PackageList(pkgs) {
|
// dependencies, then exits with a non-zero status if any errors were found.
|
||||||
p.Internal.Asmflags = BuildAsmflags.For(p)
|
func CheckPackageErrors(pkgs []*Package) {
|
||||||
p.Internal.Gcflags = BuildGcflags.For(p)
|
|
||||||
p.Internal.Ldflags = BuildLdflags.For(p)
|
|
||||||
p.Internal.Gccgoflags = BuildGccgoflags.For(p)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ImportPaths(args []string) []*search.Match {
|
|
||||||
if ModInit(); cfg.ModulesEnabled {
|
|
||||||
return ModImportPaths(args)
|
|
||||||
}
|
|
||||||
return search.ImportPaths(args)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PackagesForBuild is like Packages but exits
|
|
||||||
// if any of the packages or their dependencies have errors
|
|
||||||
// (cannot be built).
|
|
||||||
func PackagesForBuild(args []string) []*Package {
|
|
||||||
pkgs := PackagesAndErrors(args)
|
|
||||||
printed := map[*PackageError]bool{}
|
printed := map[*PackageError]bool{}
|
||||||
for _, pkg := range pkgs {
|
for _, pkg := range pkgs {
|
||||||
if pkg.Error != nil {
|
if pkg.Error != nil {
|
||||||
@ -2275,15 +2454,22 @@ func PackagesForBuild(args []string) []*Package {
|
|||||||
seen[pkg.ImportPath] = true
|
seen[pkg.ImportPath] = true
|
||||||
}
|
}
|
||||||
base.ExitIfErrors()
|
base.ExitIfErrors()
|
||||||
|
}
|
||||||
|
|
||||||
return pkgs
|
func setToolFlags(pkgs ...*Package) {
|
||||||
|
for _, p := range PackageList(pkgs) {
|
||||||
|
p.Internal.Asmflags = BuildAsmflags.For(p)
|
||||||
|
p.Internal.Gcflags = BuildGcflags.For(p)
|
||||||
|
p.Internal.Ldflags = BuildLdflags.For(p)
|
||||||
|
p.Internal.Gccgoflags = BuildGccgoflags.For(p)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GoFilesPackage creates a package for building a collection of Go files
|
// GoFilesPackage creates a package for building a collection of Go files
|
||||||
// (typically named on the command line). The target is named p.a for
|
// (typically named on the command line). The target is named p.a for
|
||||||
// package p or named after the first Go file for package main.
|
// package p or named after the first Go file for package main.
|
||||||
func GoFilesPackage(gofiles []string) *Package {
|
func GoFilesPackage(ctx context.Context, gofiles []string) *Package {
|
||||||
ModInit()
|
modload.Init()
|
||||||
|
|
||||||
for _, f := range gofiles {
|
for _, f := range gofiles {
|
||||||
if !strings.HasSuffix(f, ".go") {
|
if !strings.HasSuffix(f, ".go") {
|
||||||
@ -2306,10 +2492,10 @@ func GoFilesPackage(gofiles []string) *Package {
|
|||||||
// to make it look like this is a standard package or
|
// to make it look like this is a standard package or
|
||||||
// command directory. So that local imports resolve
|
// command directory. So that local imports resolve
|
||||||
// consistently, the files must all be in the same directory.
|
// consistently, the files must all be in the same directory.
|
||||||
var dirent []os.FileInfo
|
var dirent []fs.FileInfo
|
||||||
var dir string
|
var dir string
|
||||||
for _, file := range gofiles {
|
for _, file := range gofiles {
|
||||||
fi, err := os.Stat(file)
|
fi, err := fsys.Stat(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf("%s", err)
|
base.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
@ -2327,10 +2513,10 @@ func GoFilesPackage(gofiles []string) *Package {
|
|||||||
}
|
}
|
||||||
dirent = append(dirent, fi)
|
dirent = append(dirent, fi)
|
||||||
}
|
}
|
||||||
ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dirent, nil }
|
ctxt.ReadDir = func(string) ([]fs.FileInfo, error) { return dirent, nil }
|
||||||
|
|
||||||
if cfg.ModulesEnabled {
|
if cfg.ModulesEnabled {
|
||||||
ModImportFromFiles(gofiles)
|
modload.ImportFromFiles(ctx, gofiles)
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
@ -2346,7 +2532,7 @@ func GoFilesPackage(gofiles []string) *Package {
|
|||||||
pkg := new(Package)
|
pkg := new(Package)
|
||||||
pkg.Internal.Local = true
|
pkg.Internal.Local = true
|
||||||
pkg.Internal.CmdlineFiles = true
|
pkg.Internal.CmdlineFiles = true
|
||||||
pkg.load("command-line-arguments", &stk, nil, bp, err)
|
pkg.load(ctx, "command-line-arguments", &stk, nil, bp, err)
|
||||||
pkg.Internal.LocalPrefix = dirToImportPath(dir)
|
pkg.Internal.LocalPrefix = dirToImportPath(dir)
|
||||||
pkg.ImportPath = "command-line-arguments"
|
pkg.ImportPath = "command-line-arguments"
|
||||||
pkg.Target = ""
|
pkg.Target = ""
|
||||||
@ -2358,7 +2544,7 @@ func GoFilesPackage(gofiles []string) *Package {
|
|||||||
if cfg.GOBIN != "" {
|
if cfg.GOBIN != "" {
|
||||||
pkg.Target = filepath.Join(cfg.GOBIN, exe)
|
pkg.Target = filepath.Join(cfg.GOBIN, exe)
|
||||||
} else if cfg.ModulesEnabled {
|
} else if cfg.ModulesEnabled {
|
||||||
pkg.Target = filepath.Join(ModBinDir(), exe)
|
pkg.Target = filepath.Join(modload.BinDir(), exe)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ package load
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"cmd/go/internal/str"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
@ -20,6 +20,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"cmd/go/internal/str"
|
||||||
|
"cmd/go/internal/trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
var TestMainDeps = []string{
|
var TestMainDeps = []string{
|
||||||
@ -42,8 +45,8 @@ type TestCover struct {
|
|||||||
// TestPackagesFor is like TestPackagesAndErrors but it returns
|
// TestPackagesFor is like TestPackagesAndErrors but it returns
|
||||||
// an error if the test packages or their dependencies have errors.
|
// an error if the test packages or their dependencies have errors.
|
||||||
// Only test packages without errors are returned.
|
// Only test packages without errors are returned.
|
||||||
func TestPackagesFor(p *Package, cover *TestCover) (pmain, ptest, pxtest *Package, err error) {
|
func TestPackagesFor(ctx context.Context, p *Package, cover *TestCover) (pmain, ptest, pxtest *Package, err error) {
|
||||||
pmain, ptest, pxtest = TestPackagesAndErrors(p, cover)
|
pmain, ptest, pxtest = TestPackagesAndErrors(ctx, p, cover)
|
||||||
for _, p1 := range []*Package{ptest, pxtest, pmain} {
|
for _, p1 := range []*Package{ptest, pxtest, pmain} {
|
||||||
if p1 == nil {
|
if p1 == nil {
|
||||||
// pxtest may be nil
|
// pxtest may be nil
|
||||||
@ -89,7 +92,10 @@ func TestPackagesFor(p *Package, cover *TestCover) (pmain, ptest, pxtest *Packag
|
|||||||
//
|
//
|
||||||
// The caller is expected to have checked that len(p.TestGoFiles)+len(p.XTestGoFiles) > 0,
|
// The caller is expected to have checked that len(p.TestGoFiles)+len(p.XTestGoFiles) > 0,
|
||||||
// or else there's no point in any of this.
|
// or else there's no point in any of this.
|
||||||
func TestPackagesAndErrors(p *Package, cover *TestCover) (pmain, ptest, pxtest *Package) {
|
func TestPackagesAndErrors(ctx context.Context, p *Package, cover *TestCover) (pmain, ptest, pxtest *Package) {
|
||||||
|
ctx, span := trace.StartSpan(ctx, "load.TestPackagesAndErrors")
|
||||||
|
defer span.Done()
|
||||||
|
|
||||||
pre := newPreload()
|
pre := newPreload()
|
||||||
defer pre.flush()
|
defer pre.flush()
|
||||||
allImports := append([]string{}, p.TestImports...)
|
allImports := append([]string{}, p.TestImports...)
|
||||||
@ -99,10 +105,11 @@ func TestPackagesAndErrors(p *Package, cover *TestCover) (pmain, ptest, pxtest *
|
|||||||
var ptestErr, pxtestErr *PackageError
|
var ptestErr, pxtestErr *PackageError
|
||||||
var imports, ximports []*Package
|
var imports, ximports []*Package
|
||||||
var stk ImportStack
|
var stk ImportStack
|
||||||
|
var testEmbed, xtestEmbed map[string][]string
|
||||||
stk.Push(p.ImportPath + " (test)")
|
stk.Push(p.ImportPath + " (test)")
|
||||||
rawTestImports := str.StringList(p.TestImports)
|
rawTestImports := str.StringList(p.TestImports)
|
||||||
for i, path := range p.TestImports {
|
for i, path := range p.TestImports {
|
||||||
p1 := loadImport(pre, path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], ResolveImport)
|
p1 := loadImport(ctx, pre, path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], ResolveImport)
|
||||||
if str.Contains(p1.Deps, p.ImportPath) || p1.ImportPath == p.ImportPath {
|
if str.Contains(p1.Deps, p.ImportPath) || p1.ImportPath == p.ImportPath {
|
||||||
// Same error that loadPackage returns (via reusePackage) in pkg.go.
|
// Same error that loadPackage returns (via reusePackage) in pkg.go.
|
||||||
// Can't change that code, because that code is only for loading the
|
// Can't change that code, because that code is only for loading the
|
||||||
@ -116,12 +123,21 @@ func TestPackagesAndErrors(p *Package, cover *TestCover) (pmain, ptest, pxtest *
|
|||||||
p.TestImports[i] = p1.ImportPath
|
p.TestImports[i] = p1.ImportPath
|
||||||
imports = append(imports, p1)
|
imports = append(imports, p1)
|
||||||
}
|
}
|
||||||
|
var err error
|
||||||
|
p.TestEmbedFiles, testEmbed, err = p.resolveEmbed(p.TestEmbedPatterns)
|
||||||
|
if err != nil && ptestErr == nil {
|
||||||
|
ptestErr = &PackageError{
|
||||||
|
ImportStack: stk.Copy(),
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
stk.Pop()
|
stk.Pop()
|
||||||
|
|
||||||
stk.Push(p.ImportPath + "_test")
|
stk.Push(p.ImportPath + "_test")
|
||||||
pxtestNeedsPtest := false
|
pxtestNeedsPtest := false
|
||||||
rawXTestImports := str.StringList(p.XTestImports)
|
rawXTestImports := str.StringList(p.XTestImports)
|
||||||
for i, path := range p.XTestImports {
|
for i, path := range p.XTestImports {
|
||||||
p1 := loadImport(pre, path, p.Dir, p, &stk, p.Internal.Build.XTestImportPos[path], ResolveImport)
|
p1 := loadImport(ctx, pre, path, p.Dir, p, &stk, p.Internal.Build.XTestImportPos[path], ResolveImport)
|
||||||
if p1.ImportPath == p.ImportPath {
|
if p1.ImportPath == p.ImportPath {
|
||||||
pxtestNeedsPtest = true
|
pxtestNeedsPtest = true
|
||||||
} else {
|
} else {
|
||||||
@ -129,6 +145,13 @@ func TestPackagesAndErrors(p *Package, cover *TestCover) (pmain, ptest, pxtest *
|
|||||||
}
|
}
|
||||||
p.XTestImports[i] = p1.ImportPath
|
p.XTestImports[i] = p1.ImportPath
|
||||||
}
|
}
|
||||||
|
p.XTestEmbedFiles, xtestEmbed, err = p.resolveEmbed(p.XTestEmbedPatterns)
|
||||||
|
if err != nil && pxtestErr == nil {
|
||||||
|
pxtestErr = &PackageError{
|
||||||
|
ImportStack: stk.Copy(),
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
stk.Pop()
|
stk.Pop()
|
||||||
|
|
||||||
// Test package.
|
// Test package.
|
||||||
@ -168,6 +191,14 @@ func TestPackagesAndErrors(p *Package, cover *TestCover) (pmain, ptest, pxtest *
|
|||||||
m[k] = append(m[k], v...)
|
m[k] = append(m[k], v...)
|
||||||
}
|
}
|
||||||
ptest.Internal.Build.ImportPos = m
|
ptest.Internal.Build.ImportPos = m
|
||||||
|
if testEmbed == nil && len(p.Internal.Embed) > 0 {
|
||||||
|
testEmbed = map[string][]string{}
|
||||||
|
}
|
||||||
|
for k, v := range p.Internal.Embed {
|
||||||
|
testEmbed[k] = v
|
||||||
|
}
|
||||||
|
ptest.Internal.Embed = testEmbed
|
||||||
|
ptest.EmbedFiles = str.StringList(p.EmbedFiles, p.TestEmbedFiles)
|
||||||
ptest.collectDeps()
|
ptest.collectDeps()
|
||||||
} else {
|
} else {
|
||||||
ptest = p
|
ptest = p
|
||||||
@ -185,7 +216,9 @@ func TestPackagesAndErrors(p *Package, cover *TestCover) (pmain, ptest, pxtest *
|
|||||||
GoFiles: p.XTestGoFiles,
|
GoFiles: p.XTestGoFiles,
|
||||||
Imports: p.XTestImports,
|
Imports: p.XTestImports,
|
||||||
ForTest: p.ImportPath,
|
ForTest: p.ImportPath,
|
||||||
|
Module: p.Module,
|
||||||
Error: pxtestErr,
|
Error: pxtestErr,
|
||||||
|
EmbedFiles: p.XTestEmbedFiles,
|
||||||
},
|
},
|
||||||
Internal: PackageInternal{
|
Internal: PackageInternal{
|
||||||
LocalPrefix: p.Internal.LocalPrefix,
|
LocalPrefix: p.Internal.LocalPrefix,
|
||||||
@ -199,6 +232,7 @@ func TestPackagesAndErrors(p *Package, cover *TestCover) (pmain, ptest, pxtest *
|
|||||||
Gcflags: p.Internal.Gcflags,
|
Gcflags: p.Internal.Gcflags,
|
||||||
Ldflags: p.Internal.Ldflags,
|
Ldflags: p.Internal.Ldflags,
|
||||||
Gccgoflags: p.Internal.Gccgoflags,
|
Gccgoflags: p.Internal.Gccgoflags,
|
||||||
|
Embed: xtestEmbed,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if pxtestNeedsPtest {
|
if pxtestNeedsPtest {
|
||||||
@ -216,6 +250,7 @@ func TestPackagesAndErrors(p *Package, cover *TestCover) (pmain, ptest, pxtest *
|
|||||||
ImportPath: p.ImportPath + ".test",
|
ImportPath: p.ImportPath + ".test",
|
||||||
Root: p.Root,
|
Root: p.Root,
|
||||||
Imports: str.StringList(TestMainDeps),
|
Imports: str.StringList(TestMainDeps),
|
||||||
|
Module: p.Module,
|
||||||
},
|
},
|
||||||
Internal: PackageInternal{
|
Internal: PackageInternal{
|
||||||
Build: &build.Package{Name: "main"},
|
Build: &build.Package{Name: "main"},
|
||||||
@ -238,7 +273,7 @@ func TestPackagesAndErrors(p *Package, cover *TestCover) (pmain, ptest, pxtest *
|
|||||||
if dep == ptest.ImportPath {
|
if dep == ptest.ImportPath {
|
||||||
pmain.Internal.Imports = append(pmain.Internal.Imports, ptest)
|
pmain.Internal.Imports = append(pmain.Internal.Imports, ptest)
|
||||||
} else {
|
} else {
|
||||||
p1 := loadImport(pre, dep, "", nil, &stk, nil, 0)
|
p1 := loadImport(ctx, pre, dep, "", nil, &stk, nil, 0)
|
||||||
pmain.Internal.Imports = append(pmain.Internal.Imports, p1)
|
pmain.Internal.Imports = append(pmain.Internal.Imports, p1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ package filelock
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -24,7 +25,7 @@ type File interface {
|
|||||||
Fd() uintptr
|
Fd() uintptr
|
||||||
|
|
||||||
// Stat returns the FileInfo structure describing file.
|
// Stat returns the FileInfo structure describing file.
|
||||||
Stat() (os.FileInfo, error)
|
Stat() (fs.FileInfo, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock places an advisory write lock on the file, blocking until it can be
|
// Lock places an advisory write lock on the file, blocking until it can be
|
||||||
@ -87,7 +88,7 @@ var ErrNotSupported = errors.New("operation not supported")
|
|||||||
// underlyingError returns the underlying error for known os error types.
|
// underlyingError returns the underlying error for known os error types.
|
||||||
func underlyingError(err error) error {
|
func underlyingError(err error) error {
|
||||||
switch err := err.(type) {
|
switch err := err.(type) {
|
||||||
case *os.PathError:
|
case *fs.PathError:
|
||||||
return err.Err
|
return err.Err
|
||||||
case *os.LinkError:
|
case *os.LinkError:
|
||||||
return err.Err
|
return err.Err
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// 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.
|
||||||
|
|
||||||
// +build aix solaris
|
// +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
|
||||||
@ -12,17 +12,14 @@
|
|||||||
// Most platforms provide some alternative API, such as an 'flock' system call
|
// Most platforms provide some alternative API, such as an 'flock' system call
|
||||||
// or an F_OFD_SETLK command for 'fcntl', that allows for better concurrency and
|
// or an F_OFD_SETLK command for 'fcntl', that allows for better concurrency and
|
||||||
// does not require per-inode bookkeeping in the application.
|
// does not require per-inode bookkeeping in the application.
|
||||||
//
|
|
||||||
// TODO(golang.org/issue/35618): add a syscall.Flock binding for Illumos and
|
|
||||||
// switch it over to use filelock_unix.go.
|
|
||||||
|
|
||||||
package filelock
|
package filelock
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
|
"io/fs"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
@ -66,7 +63,7 @@ func lock(f File, lt lockType) (err error) {
|
|||||||
mu.Lock()
|
mu.Lock()
|
||||||
if i, dup := inodes[f]; dup && i != ino {
|
if i, dup := inodes[f]; dup && i != ino {
|
||||||
mu.Unlock()
|
mu.Unlock()
|
||||||
return &os.PathError{
|
return &fs.PathError{
|
||||||
Op: lt.String(),
|
Op: lt.String(),
|
||||||
Path: f.Name(),
|
Path: f.Name(),
|
||||||
Err: errors.New("inode for file changed since last Lock or RLock"),
|
Err: errors.New("inode for file changed since last Lock or RLock"),
|
||||||
@ -157,7 +154,7 @@ func lock(f File, lt lockType) (err error) {
|
|||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
unlock(f)
|
unlock(f)
|
||||||
return &os.PathError{
|
return &fs.PathError{
|
||||||
Op: lt.String(),
|
Op: lt.String(),
|
||||||
Path: f.Name(),
|
Path: f.Name(),
|
||||||
Err: err,
|
Err: err,
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
package filelock
|
package filelock
|
||||||
|
|
||||||
import "os"
|
import "io/fs"
|
||||||
|
|
||||||
type lockType int8
|
type lockType int8
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func lock(f File, lt lockType) error {
|
func lock(f File, lt lockType) error {
|
||||||
return &os.PathError{
|
return &fs.PathError{
|
||||||
Op: lt.String(),
|
Op: lt.String(),
|
||||||
Path: f.Name(),
|
Path: f.Name(),
|
||||||
Err: ErrNotSupported,
|
Err: ErrNotSupported,
|
||||||
@ -24,7 +24,7 @@ func lock(f File, lt lockType) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func unlock(f File) error {
|
func unlock(f File) error {
|
||||||
return &os.PathError{
|
return &fs.PathError{
|
||||||
Op: "Unlock",
|
Op: "Unlock",
|
||||||
Path: f.Name(),
|
Path: f.Name(),
|
||||||
Err: ErrNotSupported,
|
Err: ErrNotSupported,
|
||||||
|
@ -6,9 +6,7 @@
|
|||||||
|
|
||||||
package filelock
|
package filelock
|
||||||
|
|
||||||
import (
|
import "io/fs"
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
type lockType int8
|
type lockType int8
|
||||||
|
|
||||||
@ -18,7 +16,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func lock(f File, lt lockType) error {
|
func lock(f File, lt lockType) error {
|
||||||
return &os.PathError{
|
return &fs.PathError{
|
||||||
Op: lt.String(),
|
Op: lt.String(),
|
||||||
Path: f.Name(),
|
Path: f.Name(),
|
||||||
Err: ErrNotSupported,
|
Err: ErrNotSupported,
|
||||||
@ -26,7 +24,7 @@ func lock(f File, lt lockType) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func unlock(f File) error {
|
func unlock(f File) error {
|
||||||
return &os.PathError{
|
return &fs.PathError{
|
||||||
Op: "Unlock",
|
Op: "Unlock",
|
||||||
Path: f.Name(),
|
Path: f.Name(),
|
||||||
Err: ErrNotSupported,
|
Err: ErrNotSupported,
|
||||||
|
@ -9,7 +9,6 @@ package filelock_test
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"internal/testenv"
|
"internal/testenv"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -51,9 +50,9 @@ func mustTempFile(t *testing.T) (f *os.File, remove func()) {
|
|||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
base := filepath.Base(t.Name())
|
base := filepath.Base(t.Name())
|
||||||
f, err := ioutil.TempFile("", base)
|
f, err := os.CreateTemp("", base)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`ioutil.TempFile("", %q) = %v`, base, err)
|
t.Fatalf(`os.CreateTemp("", %q) = %v`, base, err)
|
||||||
}
|
}
|
||||||
t.Logf("fd %d = %s", f.Fd(), f.Name())
|
t.Logf("fd %d = %s", f.Fd(), f.Name())
|
||||||
|
|
||||||
@ -161,7 +160,7 @@ func TestRLockExcludesOnlyLock(t *testing.T) {
|
|||||||
|
|
||||||
doUnlockTF := false
|
doUnlockTF := false
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "aix", "illumos", "solaris":
|
case "aix", "solaris":
|
||||||
// When using POSIX locks (as on Solaris), we can't safely read-lock the
|
// When using POSIX locks (as on Solaris), we can't safely read-lock the
|
||||||
// same inode through two different descriptors at the same time: when the
|
// same inode through two different descriptors at the same time: when the
|
||||||
// first descriptor is closed, the second descriptor would still be open but
|
// first descriptor is closed, the second descriptor would still be open but
|
||||||
|
@ -2,12 +2,12 @@
|
|||||||
// 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.
|
||||||
|
|
||||||
// +build darwin dragonfly freebsd hurd linux netbsd openbsd
|
// +build darwin dragonfly freebsd hurd illumos linux netbsd openbsd
|
||||||
|
|
||||||
package filelock
|
package filelock
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"io/fs"
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ func lock(f File, lt lockType) (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &os.PathError{
|
return &fs.PathError{
|
||||||
Op: lt.String(),
|
Op: lt.String(),
|
||||||
Path: f.Name(),
|
Path: f.Name(),
|
||||||
Err: err,
|
Err: err,
|
||||||
|
@ -8,7 +8,7 @@ package filelock
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"internal/syscall/windows"
|
"internal/syscall/windows"
|
||||||
"os"
|
"io/fs"
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ func lock(f File, lt lockType) error {
|
|||||||
|
|
||||||
err := windows.LockFileEx(syscall.Handle(f.Fd()), uint32(lt), reserved, allBytes, allBytes, ol)
|
err := windows.LockFileEx(syscall.Handle(f.Fd()), uint32(lt), reserved, allBytes, allBytes, ol)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &os.PathError{
|
return &fs.PathError{
|
||||||
Op: lt.String(),
|
Op: lt.String(),
|
||||||
Path: f.Name(),
|
Path: f.Name(),
|
||||||
Err: err,
|
Err: err,
|
||||||
@ -47,7 +47,7 @@ func unlock(f File) error {
|
|||||||
ol := new(syscall.Overlapped)
|
ol := new(syscall.Overlapped)
|
||||||
err := windows.UnlockFileEx(syscall.Handle(f.Fd()), reserved, allBytes, allBytes, ol)
|
err := windows.UnlockFileEx(syscall.Handle(f.Fd()), reserved, allBytes, allBytes, ol)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &os.PathError{
|
return &fs.PathError{
|
||||||
Op: "Unlock",
|
Op: "Unlock",
|
||||||
Path: f.Name(),
|
Path: f.Name(),
|
||||||
Err: err,
|
Err: err,
|
||||||
|
@ -9,7 +9,7 @@ package lockedfile
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
)
|
)
|
||||||
@ -35,7 +35,7 @@ type osFile struct {
|
|||||||
// OpenFile is like os.OpenFile, but returns a locked file.
|
// OpenFile is like os.OpenFile, but returns a locked file.
|
||||||
// If flag includes os.O_WRONLY or os.O_RDWR, the file is write-locked;
|
// If flag includes os.O_WRONLY or os.O_RDWR, the file is write-locked;
|
||||||
// otherwise, it is read-locked.
|
// otherwise, it is read-locked.
|
||||||
func OpenFile(name string, flag int, perm os.FileMode) (*File, error) {
|
func OpenFile(name string, flag int, perm fs.FileMode) (*File, error) {
|
||||||
var (
|
var (
|
||||||
f = new(File)
|
f = new(File)
|
||||||
err error
|
err error
|
||||||
@ -82,10 +82,10 @@ func Edit(name string) (*File, error) {
|
|||||||
// non-nil error.
|
// non-nil error.
|
||||||
func (f *File) Close() error {
|
func (f *File) Close() error {
|
||||||
if f.closed {
|
if f.closed {
|
||||||
return &os.PathError{
|
return &fs.PathError{
|
||||||
Op: "close",
|
Op: "close",
|
||||||
Path: f.Name(),
|
Path: f.Name(),
|
||||||
Err: os.ErrClosed,
|
Err: fs.ErrClosed,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f.closed = true
|
f.closed = true
|
||||||
@ -103,12 +103,12 @@ func Read(name string) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
return ioutil.ReadAll(f)
|
return io.ReadAll(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write opens the named file (creating it with the given permissions if needed),
|
// Write opens the named file (creating it with the given permissions if needed),
|
||||||
// then write-locks it and overwrites it with the given content.
|
// then write-locks it and overwrites it with the given content.
|
||||||
func Write(name string, content io.Reader, perm os.FileMode) (err error) {
|
func Write(name string, content io.Reader, perm fs.FileMode) (err error) {
|
||||||
f, err := OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
|
f, err := OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -135,7 +135,7 @@ func Transform(name string, t func([]byte) ([]byte, error)) (err error) {
|
|||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
old, err := ioutil.ReadAll(f)
|
old, err := io.ReadAll(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -7,18 +7,20 @@
|
|||||||
package lockedfile
|
package lockedfile
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"cmd/go/internal/fsys"
|
||||||
"cmd/go/internal/lockedfile/internal/filelock"
|
"cmd/go/internal/lockedfile/internal/filelock"
|
||||||
)
|
)
|
||||||
|
|
||||||
func openFile(name string, flag int, perm os.FileMode) (*os.File, error) {
|
func openFile(name string, flag int, perm fs.FileMode) (*os.File, error) {
|
||||||
// On BSD systems, we could add the O_SHLOCK or O_EXLOCK flag to the OpenFile
|
// On BSD systems, we could add the O_SHLOCK or O_EXLOCK flag to the OpenFile
|
||||||
// call instead of locking separately, but we have to support separate locking
|
// call instead of locking separately, but we have to support separate locking
|
||||||
// calls for Linux and Windows anyway, so it's simpler to use that approach
|
// calls for Linux and Windows anyway, so it's simpler to use that approach
|
||||||
// consistently.
|
// consistently.
|
||||||
|
|
||||||
f, err := os.OpenFile(name, flag&^os.O_TRUNC, perm)
|
f, err := fsys.OpenFile(name, flag&^os.O_TRUNC, perm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,13 @@
|
|||||||
package lockedfile
|
package lockedfile
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io/fs"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"cmd/go/internal/fsys"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Opening an exclusive-use file returns an error.
|
// Opening an exclusive-use file returns an error.
|
||||||
@ -41,7 +44,7 @@ func isLocked(err error) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func openFile(name string, flag int, perm os.FileMode) (*os.File, error) {
|
func openFile(name string, flag int, perm fs.FileMode) (*os.File, error) {
|
||||||
// Plan 9 uses a mode bit instead of explicit lock/unlock syscalls.
|
// Plan 9 uses a mode bit instead of explicit lock/unlock syscalls.
|
||||||
//
|
//
|
||||||
// Per http://man.cat-v.org/plan_9/5/stat: “Exclusive use files may be open
|
// Per http://man.cat-v.org/plan_9/5/stat: “Exclusive use files may be open
|
||||||
@ -55,9 +58,9 @@ func openFile(name string, flag int, perm os.FileMode) (*os.File, error) {
|
|||||||
// If the file was unpacked or created by some other program, it might not
|
// If the file was unpacked or created by some other program, it might not
|
||||||
// have the ModeExclusive bit set. Set it before we call OpenFile, so that we
|
// have the ModeExclusive bit set. Set it before we call OpenFile, so that we
|
||||||
// can be confident that a successful OpenFile implies exclusive use.
|
// can be confident that a successful OpenFile implies exclusive use.
|
||||||
if fi, err := os.Stat(name); err == nil {
|
if fi, err := fsys.Stat(name); err == nil {
|
||||||
if fi.Mode()&os.ModeExclusive == 0 {
|
if fi.Mode()&fs.ModeExclusive == 0 {
|
||||||
if err := os.Chmod(name, fi.Mode()|os.ModeExclusive); err != nil {
|
if err := os.Chmod(name, fi.Mode()|fs.ModeExclusive); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -68,7 +71,7 @@ func openFile(name string, flag int, perm os.FileMode) (*os.File, error) {
|
|||||||
nextSleep := 1 * time.Millisecond
|
nextSleep := 1 * time.Millisecond
|
||||||
const maxSleep = 500 * time.Millisecond
|
const maxSleep = 500 * time.Millisecond
|
||||||
for {
|
for {
|
||||||
f, err := os.OpenFile(name, flag, perm|os.ModeExclusive)
|
f, err := fsys.OpenFile(name, flag, perm|fs.ModeExclusive)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return f, nil
|
return f, nil
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,6 @@ package lockedfile_test
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"internal/testenv"
|
"internal/testenv"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -23,7 +22,7 @@ import (
|
|||||||
func mustTempDir(t *testing.T) (dir string, remove func()) {
|
func mustTempDir(t *testing.T) (dir string, remove func()) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
dir, err := ioutil.TempDir("", filepath.Base(t.Name()))
|
dir, err := os.MkdirTemp("", filepath.Base(t.Name()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -155,8 +154,8 @@ func TestCanLockExistingFile(t *testing.T) {
|
|||||||
defer remove()
|
defer remove()
|
||||||
path := filepath.Join(dir, "existing.txt")
|
path := filepath.Join(dir, "existing.txt")
|
||||||
|
|
||||||
if err := ioutil.WriteFile(path, []byte("ok"), 0777); err != nil {
|
if err := os.WriteFile(path, []byte("ok"), 0777); err != nil {
|
||||||
t.Fatalf("ioutil.WriteFile: %v", err)
|
t.Fatalf("os.WriteFile: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
f, err := lockedfile.Edit(path)
|
f, err := lockedfile.Edit(path)
|
||||||
@ -201,7 +200,7 @@ func TestSpuriousEDEADLK(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer b.Close()
|
defer b.Close()
|
||||||
|
|
||||||
if err := ioutil.WriteFile(filepath.Join(dir, "locked"), []byte("ok"), 0666); err != nil {
|
if err := os.WriteFile(filepath.Join(dir, "locked"), []byte("ok"), 0666); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,15 +5,15 @@
|
|||||||
package modcmd
|
package modcmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
"cmd/go/internal/base"
|
"cmd/go/internal/base"
|
||||||
"cmd/go/internal/cfg"
|
"cmd/go/internal/cfg"
|
||||||
"cmd/go/internal/modfetch"
|
"cmd/go/internal/modfetch"
|
||||||
"cmd/go/internal/modload"
|
"cmd/go/internal/modload"
|
||||||
"cmd/go/internal/par"
|
|
||||||
"cmd/go/internal/work"
|
|
||||||
|
|
||||||
"golang.org/x/mod/module"
|
"golang.org/x/mod/module"
|
||||||
)
|
)
|
||||||
@ -63,7 +63,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, "")
|
||||||
work.AddModCommonFlags(cmdDownload)
|
base.AddModCommonFlags(&cmdDownload.Flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
type moduleJSON struct {
|
type moduleJSON struct {
|
||||||
@ -78,56 +78,27 @@ type moduleJSON struct {
|
|||||||
GoModSum string `json:",omitempty"`
|
GoModSum string `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDownload(cmd *base.Command, args []string) {
|
func runDownload(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
// Check whether modules are enabled and whether we're in a module.
|
// Check whether modules are enabled and whether we're in a module.
|
||||||
if cfg.Getenv("GO111MODULE") == "off" {
|
modload.ForceUseModules = true
|
||||||
base.Fatalf("go: modules disabled by GO111MODULE=off; see 'go help modules'")
|
|
||||||
}
|
|
||||||
if !modload.HasModRoot() && len(args) == 0 {
|
if !modload.HasModRoot() && len(args) == 0 {
|
||||||
base.Fatalf("go mod download: no modules specified (see 'go help mod download')")
|
base.Fatalf("go mod download: no modules specified (see 'go help mod download')")
|
||||||
}
|
}
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
args = []string{"all"}
|
args = []string{"all"}
|
||||||
} else if modload.HasModRoot() {
|
} else if modload.HasModRoot() {
|
||||||
modload.InitMod() // to fill Target
|
modload.LoadModFile(ctx) // to fill Target
|
||||||
targetAtLatest := modload.Target.Path + "@latest"
|
|
||||||
targetAtUpgrade := modload.Target.Path + "@upgrade"
|
targetAtUpgrade := modload.Target.Path + "@upgrade"
|
||||||
targetAtPatch := modload.Target.Path + "@patch"
|
targetAtPatch := modload.Target.Path + "@patch"
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
switch arg {
|
switch arg {
|
||||||
case modload.Target.Path, targetAtLatest, targetAtUpgrade, targetAtPatch:
|
case modload.Target.Path, targetAtUpgrade, targetAtPatch:
|
||||||
os.Stderr.WriteString("go mod download: skipping argument " + arg + " that resolves to the main module\n")
|
os.Stderr.WriteString("go mod download: skipping argument " + arg + " that resolves to the main module\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var mods []*moduleJSON
|
downloadModule := func(m *moduleJSON) {
|
||||||
var work par.Work
|
|
||||||
listU := false
|
|
||||||
listVersions := false
|
|
||||||
for _, info := range modload.ListModules(args, listU, listVersions) {
|
|
||||||
if info.Replace != nil {
|
|
||||||
info = info.Replace
|
|
||||||
}
|
|
||||||
if info.Version == "" && info.Error == nil {
|
|
||||||
// main module or module replaced with file path.
|
|
||||||
// Nothing to download.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
m := &moduleJSON{
|
|
||||||
Path: info.Path,
|
|
||||||
Version: info.Version,
|
|
||||||
}
|
|
||||||
mods = append(mods, m)
|
|
||||||
if info.Error != nil {
|
|
||||||
m.Error = info.Error.Err
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
work.Add(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
work.Do(10, func(item interface{}) {
|
|
||||||
m := item.(*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)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -145,24 +116,60 @@ func runDownload(cmd *base.Command, args []string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
mod := module.Version{Path: m.Path, Version: m.Version}
|
mod := module.Version{Path: m.Path, Version: m.Version}
|
||||||
m.Zip, err = modfetch.DownloadZip(mod)
|
m.Zip, err = modfetch.DownloadZip(ctx, mod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
m.Error = err.Error()
|
m.Error = err.Error()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
m.Sum = modfetch.Sum(mod)
|
m.Sum = modfetch.Sum(mod)
|
||||||
m.Dir, err = modfetch.Download(mod)
|
m.Dir, err = modfetch.Download(ctx, mod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
m.Error = err.Error()
|
m.Error = err.Error()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
|
var mods []*moduleJSON
|
||||||
|
listU := false
|
||||||
|
listVersions := false
|
||||||
|
listRetractions := false
|
||||||
|
type token struct{}
|
||||||
|
sem := make(chan token, runtime.GOMAXPROCS(0))
|
||||||
|
for _, info := range modload.ListModules(ctx, args, listU, listVersions, listRetractions) {
|
||||||
|
if info.Replace != nil {
|
||||||
|
info = info.Replace
|
||||||
|
}
|
||||||
|
if info.Version == "" && info.Error == nil {
|
||||||
|
// main module or module replaced with file path.
|
||||||
|
// Nothing to download.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
m := &moduleJSON{
|
||||||
|
Path: info.Path,
|
||||||
|
Version: info.Version,
|
||||||
|
}
|
||||||
|
mods = append(mods, m)
|
||||||
|
if info.Error != nil {
|
||||||
|
m.Error = info.Error.Err
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sem <- token{}
|
||||||
|
go func() {
|
||||||
|
downloadModule(m)
|
||||||
|
<-sem
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill semaphore channel to wait for goroutines to finish.
|
||||||
|
for n := cap(sem); n > 0; n-- {
|
||||||
|
sem <- token{}
|
||||||
|
}
|
||||||
|
|
||||||
if *downloadJSON {
|
if *downloadJSON {
|
||||||
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("%v", err)
|
base.Fatalf("go mod download: %v", err)
|
||||||
}
|
}
|
||||||
os.Stdout.Write(append(b, '\n'))
|
os.Stdout.Write(append(b, '\n'))
|
||||||
if m.Error != "" {
|
if m.Error != "" {
|
||||||
@ -172,9 +179,12 @@ func runDownload(cmd *base.Command, args []string) {
|
|||||||
} else {
|
} else {
|
||||||
for _, m := range mods {
|
for _, m := range mods {
|
||||||
if m.Error != "" {
|
if m.Error != "" {
|
||||||
base.Errorf("%s", m.Error)
|
base.Errorf("go mod download: %v", m.Error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
base.ExitIfErrors()
|
base.ExitIfErrors()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update go.mod and especially go.sum if needed.
|
||||||
|
modload.WriteGoMod()
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ package modcmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -18,7 +19,6 @@ import (
|
|||||||
"cmd/go/internal/lockedfile"
|
"cmd/go/internal/lockedfile"
|
||||||
"cmd/go/internal/modfetch"
|
"cmd/go/internal/modfetch"
|
||||||
"cmd/go/internal/modload"
|
"cmd/go/internal/modload"
|
||||||
"cmd/go/internal/work"
|
|
||||||
|
|
||||||
"golang.org/x/mod/modfile"
|
"golang.org/x/mod/modfile"
|
||||||
"golang.org/x/mod/module"
|
"golang.org/x/mod/module"
|
||||||
@ -67,9 +67,14 @@ The -dropreplace=old[@v] flag drops a replacement of the given
|
|||||||
module path and version pair. If the @v is omitted, a replacement without
|
module path and version pair. If the @v is omitted, a replacement without
|
||||||
a version on the left side is dropped.
|
a version on the left side is dropped.
|
||||||
|
|
||||||
|
The -retract=version and -dropretract=version flags add and drop a
|
||||||
|
retraction on the given version. The version may be a single version
|
||||||
|
like "v1.2.3" or a closed interval like "[v1.1.0,v1.1.9]". Note that
|
||||||
|
-retract=version is a no-op if that retraction already exists.
|
||||||
|
|
||||||
The -require, -droprequire, -exclude, -dropexclude, -replace,
|
The -require, -droprequire, -exclude, -dropexclude, -replace,
|
||||||
and -dropreplace editing flags may be repeated, and the changes
|
-dropreplace, -retract, and -dropretract editing flags may be repeated,
|
||||||
are applied in the order given.
|
and the changes are applied in the order given.
|
||||||
|
|
||||||
The -go=version flag sets the expected Go language version.
|
The -go=version flag sets the expected Go language version.
|
||||||
|
|
||||||
@ -103,6 +108,15 @@ writing it back to go.mod. The JSON output corresponds to these Go types:
|
|||||||
New Module
|
New Module
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Retract struct {
|
||||||
|
Low string
|
||||||
|
High string
|
||||||
|
Rationale string
|
||||||
|
}
|
||||||
|
|
||||||
|
Retract entries representing a single version (not an interval) will have
|
||||||
|
the "Low" and "High" fields set to the same value.
|
||||||
|
|
||||||
Note that this only describes the go.mod file itself, not other modules
|
Note that this only describes the go.mod file itself, not other modules
|
||||||
referred to indirectly. For the full set of modules available to a build,
|
referred to indirectly. For the full set of modules available to a build,
|
||||||
use 'go list -m -json all'.
|
use 'go list -m -json all'.
|
||||||
@ -136,12 +150,14 @@ func init() {
|
|||||||
cmdEdit.Flag.Var(flagFunc(flagDropReplace), "dropreplace", "")
|
cmdEdit.Flag.Var(flagFunc(flagDropReplace), "dropreplace", "")
|
||||||
cmdEdit.Flag.Var(flagFunc(flagReplace), "replace", "")
|
cmdEdit.Flag.Var(flagFunc(flagReplace), "replace", "")
|
||||||
cmdEdit.Flag.Var(flagFunc(flagDropExclude), "dropexclude", "")
|
cmdEdit.Flag.Var(flagFunc(flagDropExclude), "dropexclude", "")
|
||||||
|
cmdEdit.Flag.Var(flagFunc(flagRetract), "retract", "")
|
||||||
|
cmdEdit.Flag.Var(flagFunc(flagDropRetract), "dropretract", "")
|
||||||
|
|
||||||
work.AddModCommonFlags(cmdEdit)
|
base.AddModCommonFlags(&cmdEdit.Flag)
|
||||||
base.AddBuildFlagsNX(&cmdEdit.Flag)
|
base.AddBuildFlagsNX(&cmdEdit.Flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runEdit(cmd *base.Command, args []string) {
|
func runEdit(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
anyFlags :=
|
anyFlags :=
|
||||||
*editModule != "" ||
|
*editModule != "" ||
|
||||||
*editGo != "" ||
|
*editGo != "" ||
|
||||||
@ -251,12 +267,7 @@ func parsePathVersion(flag, arg string) (path, version string) {
|
|||||||
base.Fatalf("go mod: -%s=%s: invalid path: %v", flag, arg, err)
|
base.Fatalf("go mod: -%s=%s: invalid path: %v", flag, arg, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't call modfile.CheckPathVersion, because that insists
|
if !allowedVersionArg(version) {
|
||||||
// on versions being in semver form, but here we want to allow
|
|
||||||
// versions like "master" or "1234abcdef", which the go command will resolve
|
|
||||||
// the next time it runs (or during -fix).
|
|
||||||
// Even so, we need to make sure the version is a valid token.
|
|
||||||
if modfile.MustQuote(version) {
|
|
||||||
base.Fatalf("go mod: -%s=%s: invalid version %q", flag, arg, version)
|
base.Fatalf("go mod: -%s=%s: invalid version %q", flag, arg, version)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,12 +299,48 @@ func parsePathVersionOptional(adj, arg string, allowDirPath bool) (path, version
|
|||||||
return path, version, fmt.Errorf("invalid %s path: %v", adj, err)
|
return path, version, fmt.Errorf("invalid %s path: %v", adj, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if path != arg && modfile.MustQuote(version) {
|
if path != arg && !allowedVersionArg(version) {
|
||||||
return path, version, fmt.Errorf("invalid %s version: %q", adj, version)
|
return path, version, fmt.Errorf("invalid %s version: %q", adj, version)
|
||||||
}
|
}
|
||||||
return path, version, nil
|
return path, version, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parseVersionInterval parses a single version like "v1.2.3" or a closed
|
||||||
|
// interval like "[v1.2.3,v1.4.5]". Note that a single version has the same
|
||||||
|
// representation as an interval with equal upper and lower bounds: both
|
||||||
|
// Low and High are set.
|
||||||
|
func parseVersionInterval(arg string) (modfile.VersionInterval, error) {
|
||||||
|
if !strings.HasPrefix(arg, "[") {
|
||||||
|
if !allowedVersionArg(arg) {
|
||||||
|
return modfile.VersionInterval{}, fmt.Errorf("invalid version: %q", arg)
|
||||||
|
}
|
||||||
|
return modfile.VersionInterval{Low: arg, High: arg}, nil
|
||||||
|
}
|
||||||
|
if !strings.HasSuffix(arg, "]") {
|
||||||
|
return modfile.VersionInterval{}, fmt.Errorf("invalid version interval: %q", arg)
|
||||||
|
}
|
||||||
|
s := arg[1 : len(arg)-1]
|
||||||
|
i := strings.Index(s, ",")
|
||||||
|
if i < 0 {
|
||||||
|
return modfile.VersionInterval{}, fmt.Errorf("invalid version interval: %q", arg)
|
||||||
|
}
|
||||||
|
low := strings.TrimSpace(s[:i])
|
||||||
|
high := strings.TrimSpace(s[i+1:])
|
||||||
|
if !allowedVersionArg(low) || !allowedVersionArg(high) {
|
||||||
|
return modfile.VersionInterval{}, fmt.Errorf("invalid version interval: %q", arg)
|
||||||
|
}
|
||||||
|
return modfile.VersionInterval{Low: low, High: high}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// allowedVersionArg returns whether a token may be used as a version in go.mod.
|
||||||
|
// We don't call modfile.CheckPathVersion, because that insists on versions
|
||||||
|
// being in semver form, but here we want to allow versions like "master" or
|
||||||
|
// "1234abcdef", which the go command will resolve the next time it runs (or
|
||||||
|
// during -fix). Even so, we need to make sure the version is a valid token.
|
||||||
|
func allowedVersionArg(arg string) bool {
|
||||||
|
return !modfile.MustQuote(arg)
|
||||||
|
}
|
||||||
|
|
||||||
// flagRequire implements the -require flag.
|
// flagRequire implements the -require flag.
|
||||||
func flagRequire(arg string) {
|
func flagRequire(arg string) {
|
||||||
path, version := parsePathVersion("require", arg)
|
path, version := parsePathVersion("require", arg)
|
||||||
@ -376,6 +423,32 @@ func flagDropReplace(arg string) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// flagRetract implements the -retract flag.
|
||||||
|
func flagRetract(arg string) {
|
||||||
|
vi, err := parseVersionInterval(arg)
|
||||||
|
if err != nil {
|
||||||
|
base.Fatalf("go mod: -retract=%s: %v", arg, err)
|
||||||
|
}
|
||||||
|
edits = append(edits, func(f *modfile.File) {
|
||||||
|
if err := f.AddRetract(vi, ""); err != nil {
|
||||||
|
base.Fatalf("go mod: -retract=%s: %v", arg, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// flagDropRetract implements the -dropretract flag.
|
||||||
|
func flagDropRetract(arg string) {
|
||||||
|
vi, err := parseVersionInterval(arg)
|
||||||
|
if err != nil {
|
||||||
|
base.Fatalf("go mod: -dropretract=%s: %v", arg, err)
|
||||||
|
}
|
||||||
|
edits = append(edits, func(f *modfile.File) {
|
||||||
|
if err := f.DropRetract(vi); err != nil {
|
||||||
|
base.Fatalf("go mod: -dropretract=%s: %v", arg, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// fileJSON is the -json output data structure.
|
// fileJSON is the -json output data structure.
|
||||||
type fileJSON struct {
|
type fileJSON struct {
|
||||||
Module module.Version
|
Module module.Version
|
||||||
@ -383,6 +456,7 @@ type fileJSON struct {
|
|||||||
Require []requireJSON
|
Require []requireJSON
|
||||||
Exclude []module.Version
|
Exclude []module.Version
|
||||||
Replace []replaceJSON
|
Replace []replaceJSON
|
||||||
|
Retract []retractJSON
|
||||||
}
|
}
|
||||||
|
|
||||||
type requireJSON struct {
|
type requireJSON struct {
|
||||||
@ -396,6 +470,12 @@ type replaceJSON struct {
|
|||||||
New module.Version
|
New module.Version
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type retractJSON struct {
|
||||||
|
Low string `json:",omitempty"`
|
||||||
|
High string `json:",omitempty"`
|
||||||
|
Rationale string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// editPrintJSON prints the -json output.
|
// editPrintJSON prints the -json output.
|
||||||
func editPrintJSON(modFile *modfile.File) {
|
func editPrintJSON(modFile *modfile.File) {
|
||||||
var f fileJSON
|
var f fileJSON
|
||||||
@ -414,6 +494,9 @@ func editPrintJSON(modFile *modfile.File) {
|
|||||||
for _, r := range modFile.Replace {
|
for _, r := range modFile.Replace {
|
||||||
f.Replace = append(f.Replace, replaceJSON{r.Old, r.New})
|
f.Replace = append(f.Replace, replaceJSON{r.Old, r.New})
|
||||||
}
|
}
|
||||||
|
for _, r := range modFile.Retract {
|
||||||
|
f.Retract = append(f.Retract, retractJSON{r.Low, r.High, r.Rationale})
|
||||||
|
}
|
||||||
data, err := json.MarshalIndent(&f, "", "\t")
|
data, err := json.MarshalIndent(&f, "", "\t")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf("go: internal error: %v", err)
|
base.Fatalf("go: internal error: %v", err)
|
||||||
|
@ -8,14 +8,12 @@ package modcmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"context"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"cmd/go/internal/base"
|
"cmd/go/internal/base"
|
||||||
"cmd/go/internal/cfg"
|
|
||||||
"cmd/go/internal/modload"
|
"cmd/go/internal/modload"
|
||||||
"cmd/go/internal/par"
|
|
||||||
"cmd/go/internal/work"
|
|
||||||
|
|
||||||
"golang.org/x/mod/module"
|
"golang.org/x/mod/module"
|
||||||
)
|
)
|
||||||
@ -33,22 +31,16 @@ path@version, except for the main module, which has no @version suffix.
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
work.AddModCommonFlags(cmdGraph)
|
base.AddModCommonFlags(&cmdGraph.Flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runGraph(cmd *base.Command, args []string) {
|
func runGraph(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
base.Fatalf("go mod graph: graph takes no arguments")
|
base.Fatalf("go mod graph: graph takes no arguments")
|
||||||
}
|
}
|
||||||
// Checks go mod expected behavior
|
modload.ForceUseModules = true
|
||||||
if !modload.Enabled() {
|
modload.RootMode = modload.NeedRoot
|
||||||
if cfg.Getenv("GO111MODULE") == "off" {
|
modload.LoadAllModules(ctx)
|
||||||
base.Fatalf("go: modules disabled by GO111MODULE=off; see 'go help modules'")
|
|
||||||
} else {
|
|
||||||
base.Fatalf("go: cannot find main module; see 'go help modules'")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
modload.LoadBuildList()
|
|
||||||
|
|
||||||
reqs := modload.MinReqs()
|
reqs := modload.MinReqs()
|
||||||
format := func(m module.Version) string {
|
format := func(m module.Version) string {
|
||||||
@ -58,23 +50,25 @@ func runGraph(cmd *base.Command, args []string) {
|
|||||||
return m.Path + "@" + m.Version
|
return m.Path + "@" + m.Version
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: using par.Work only to manage work queue.
|
|
||||||
// No parallelism here, so no locking.
|
|
||||||
var out []string
|
var out []string
|
||||||
var deps int // index in out where deps start
|
var deps int // index in out where deps start
|
||||||
var work par.Work
|
seen := map[module.Version]bool{modload.Target: true}
|
||||||
work.Add(modload.Target)
|
queue := []module.Version{modload.Target}
|
||||||
work.Do(1, func(item interface{}) {
|
for len(queue) > 0 {
|
||||||
m := item.(module.Version)
|
var m module.Version
|
||||||
|
m, queue = queue[0], queue[1:]
|
||||||
list, _ := reqs.Required(m)
|
list, _ := reqs.Required(m)
|
||||||
for _, r := range list {
|
for _, r := range list {
|
||||||
work.Add(r)
|
if !seen[r] {
|
||||||
|
queue = append(queue, r)
|
||||||
|
seen[r] = true
|
||||||
|
}
|
||||||
out = append(out, format(m)+" "+format(r)+"\n")
|
out = append(out, format(m)+" "+format(r)+"\n")
|
||||||
}
|
}
|
||||||
if m == modload.Target {
|
if m == modload.Target {
|
||||||
deps = len(out)
|
deps = len(out)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
sort.Slice(out[deps:], func(i, j int) bool {
|
sort.Slice(out[deps:], func(i, j int) bool {
|
||||||
return out[deps+i][0] < out[deps+j][0]
|
return out[deps+i][0] < out[deps+j][0]
|
||||||
|
@ -9,46 +9,41 @@ package modcmd
|
|||||||
import (
|
import (
|
||||||
"cmd/go/internal/base"
|
"cmd/go/internal/base"
|
||||||
"cmd/go/internal/modload"
|
"cmd/go/internal/modload"
|
||||||
"cmd/go/internal/work"
|
"context"
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var cmdInit = &base.Command{
|
var cmdInit = &base.Command{
|
||||||
UsageLine: "go mod init [module]",
|
UsageLine: "go mod init [module]",
|
||||||
Short: "initialize new module in current directory",
|
Short: "initialize new module in current directory",
|
||||||
Long: `
|
Long: `
|
||||||
Init initializes and writes a new go.mod to the current directory,
|
Init initializes and writes a new go.mod file in the current directory, in
|
||||||
in effect creating a new module rooted at the current directory.
|
effect creating a new module rooted at the current directory. The go.mod file
|
||||||
The file go.mod must not already exist.
|
must not already exist.
|
||||||
If possible, init will guess the module path from import comments
|
|
||||||
(see 'go help importpath') or from version control configuration.
|
Init accepts one optional argument, the module path for the new module. If the
|
||||||
To override this guess, supply the module path as an argument.
|
module path argument is omitted, init will attempt to infer the module path
|
||||||
`,
|
using import comments in .go files, vendoring tool configuration files (like
|
||||||
|
Gopkg.lock), and the current directory (if in GOPATH).
|
||||||
|
|
||||||
|
If a configuration file for a vendoring tool is present, init will attempt to
|
||||||
|
import module requirements from it.
|
||||||
|
`,
|
||||||
Run: runInit,
|
Run: runInit,
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
work.AddModCommonFlags(cmdInit)
|
base.AddModCommonFlags(&cmdInit.Flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runInit(cmd *base.Command, args []string) {
|
func runInit(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
modload.CmdModInit = true
|
|
||||||
if len(args) > 1 {
|
if len(args) > 1 {
|
||||||
base.Fatalf("go mod init: too many arguments")
|
base.Fatalf("go mod init: too many arguments")
|
||||||
}
|
}
|
||||||
|
var modPath string
|
||||||
if len(args) == 1 {
|
if len(args) == 1 {
|
||||||
modload.CmdModModule = args[0]
|
modPath = args[0]
|
||||||
}
|
}
|
||||||
if os.Getenv("GO111MODULE") == "off" {
|
|
||||||
base.Fatalf("go mod init: modules disabled by GO111MODULE=off; see 'go help modules'")
|
modload.ForceUseModules = true
|
||||||
}
|
modload.CreateModFile(ctx, modPath) // does all the hard work
|
||||||
modFilePath := modload.ModFilePath()
|
|
||||||
if _, err := os.Stat(modFilePath); err == nil {
|
|
||||||
base.Fatalf("go mod init: go.mod already exists")
|
|
||||||
}
|
|
||||||
if strings.Contains(modload.CmdModModule, "@") {
|
|
||||||
base.Fatalf("go mod init: module path must not contain '@'")
|
|
||||||
}
|
|
||||||
modload.InitMod() // does all the hard work
|
|
||||||
}
|
}
|
||||||
|
@ -9,15 +9,13 @@ package modcmd
|
|||||||
import (
|
import (
|
||||||
"cmd/go/internal/base"
|
"cmd/go/internal/base"
|
||||||
"cmd/go/internal/cfg"
|
"cmd/go/internal/cfg"
|
||||||
"cmd/go/internal/modfetch"
|
"cmd/go/internal/imports"
|
||||||
"cmd/go/internal/modload"
|
"cmd/go/internal/modload"
|
||||||
"cmd/go/internal/work"
|
"context"
|
||||||
|
|
||||||
"golang.org/x/mod/module"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var cmdTidy = &base.Command{
|
var cmdTidy = &base.Command{
|
||||||
UsageLine: "go mod tidy [-v]",
|
UsageLine: "go mod tidy [-e] [-v]",
|
||||||
Short: "add missing and remove unused modules",
|
Short: "add missing and remove unused modules",
|
||||||
Long: `
|
Long: `
|
||||||
Tidy makes sure go.mod matches the source code in the module.
|
Tidy makes sure go.mod matches the source code in the module.
|
||||||
@ -28,55 +26,47 @@ to go.sum and removes any unnecessary ones.
|
|||||||
|
|
||||||
The -v flag causes tidy to print information about removed modules
|
The -v flag causes tidy to print information about removed modules
|
||||||
to standard error.
|
to standard error.
|
||||||
|
|
||||||
|
The -e flag causes tidy to attempt to proceed despite errors
|
||||||
|
encountered while loading packages.
|
||||||
`,
|
`,
|
||||||
|
Run: runTidy,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var tidyE bool // if true, report errors but proceed anyway.
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
cmdTidy.Run = runTidy // break init cycle
|
|
||||||
cmdTidy.Flag.BoolVar(&cfg.BuildV, "v", false, "")
|
cmdTidy.Flag.BoolVar(&cfg.BuildV, "v", false, "")
|
||||||
work.AddModCommonFlags(cmdTidy)
|
cmdTidy.Flag.BoolVar(&tidyE, "e", false, "")
|
||||||
|
base.AddModCommonFlags(&cmdTidy.Flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runTidy(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 mod tidy: no arguments allowed")
|
||||||
}
|
}
|
||||||
|
|
||||||
modload.LoadALL()
|
// Tidy aims to make 'go test' reproducible for any package in 'all', so we
|
||||||
|
// need to include test dependencies. For modules that specify go 1.15 or
|
||||||
|
// earlier this is a no-op (because 'all' saturates transitive test
|
||||||
|
// dependencies).
|
||||||
|
//
|
||||||
|
// However, with lazy loading (go 1.16+) 'all' includes only the packages that
|
||||||
|
// are transitively imported by the main module, not the test dependencies of
|
||||||
|
// those packages. In order to make 'go test' reproducible for the packages
|
||||||
|
// that are in 'all' but outside of the main module, we must explicitly
|
||||||
|
// request that their test dependencies be included.
|
||||||
|
modload.ForceUseModules = true
|
||||||
|
modload.RootMode = modload.NeedRoot
|
||||||
|
|
||||||
|
modload.LoadPackages(ctx, modload.PackageOpts{
|
||||||
|
Tags: imports.AnyTags(),
|
||||||
|
ResolveMissingImports: true,
|
||||||
|
LoadTests: true,
|
||||||
|
AllowErrors: tidyE,
|
||||||
|
}, "all")
|
||||||
|
|
||||||
modload.TidyBuildList()
|
modload.TidyBuildList()
|
||||||
modTidyGoSum() // updates memory copy; WriteGoMod on next line flushes it out
|
modload.TrimGoSum()
|
||||||
modload.WriteGoMod()
|
modload.WriteGoMod()
|
||||||
}
|
}
|
||||||
|
|
||||||
// modTidyGoSum resets the go.sum file content
|
|
||||||
// to be exactly what's needed for the current go.mod.
|
|
||||||
func modTidyGoSum() {
|
|
||||||
// Assuming go.sum already has at least enough from the successful load,
|
|
||||||
// we only have to tell modfetch what needs keeping.
|
|
||||||
reqs := modload.Reqs()
|
|
||||||
keep := make(map[module.Version]bool)
|
|
||||||
replaced := make(map[module.Version]bool)
|
|
||||||
var walk func(module.Version)
|
|
||||||
walk = func(m module.Version) {
|
|
||||||
// If we build using a replacement module, keep the sum for the replacement,
|
|
||||||
// since that's the code we'll actually use during a build.
|
|
||||||
//
|
|
||||||
// TODO(golang.org/issue/29182): Perhaps we should keep both sums, and the
|
|
||||||
// sums for both sets of transitive requirements.
|
|
||||||
r := modload.Replacement(m)
|
|
||||||
if r.Path == "" {
|
|
||||||
keep[m] = true
|
|
||||||
} else {
|
|
||||||
keep[r] = true
|
|
||||||
replaced[m] = true
|
|
||||||
}
|
|
||||||
list, _ := reqs.Required(m)
|
|
||||||
for _, r := range list {
|
|
||||||
if !keep[r] && !replaced[r] {
|
|
||||||
walk(r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
walk(modload.Target)
|
|
||||||
modfetch.TrimGoSum(keep)
|
|
||||||
}
|
|
||||||
|
@ -6,9 +6,10 @@ package modcmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
@ -16,16 +17,16 @@ import (
|
|||||||
|
|
||||||
"cmd/go/internal/base"
|
"cmd/go/internal/base"
|
||||||
"cmd/go/internal/cfg"
|
"cmd/go/internal/cfg"
|
||||||
|
"cmd/go/internal/fsys"
|
||||||
"cmd/go/internal/imports"
|
"cmd/go/internal/imports"
|
||||||
"cmd/go/internal/modload"
|
"cmd/go/internal/modload"
|
||||||
"cmd/go/internal/work"
|
|
||||||
|
|
||||||
"golang.org/x/mod/module"
|
"golang.org/x/mod/module"
|
||||||
"golang.org/x/mod/semver"
|
"golang.org/x/mod/semver"
|
||||||
)
|
)
|
||||||
|
|
||||||
var cmdVendor = &base.Command{
|
var cmdVendor = &base.Command{
|
||||||
UsageLine: "go mod vendor [-v]",
|
UsageLine: "go mod vendor [-e] [-v]",
|
||||||
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
|
||||||
@ -34,20 +35,35 @@ It does not include test code for vendored packages.
|
|||||||
|
|
||||||
The -v flag causes vendor to print the names of vendored
|
The -v flag causes vendor to print the names of vendored
|
||||||
modules and packages to standard error.
|
modules and packages to standard error.
|
||||||
|
|
||||||
|
The -e flag causes vendor to attempt to proceed despite errors
|
||||||
|
encountered while loading packages.
|
||||||
`,
|
`,
|
||||||
Run: runVendor,
|
Run: runVendor,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var vendorE bool // if true, report errors but proceed anyway
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
cmdVendor.Flag.BoolVar(&cfg.BuildV, "v", false, "")
|
cmdVendor.Flag.BoolVar(&cfg.BuildV, "v", false, "")
|
||||||
work.AddModCommonFlags(cmdVendor)
|
cmdVendor.Flag.BoolVar(&vendorE, "e", false, "")
|
||||||
|
base.AddModCommonFlags(&cmdVendor.Flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runVendor(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 mod vendor: vendor takes no arguments")
|
||||||
}
|
}
|
||||||
pkgs := modload.LoadVendor()
|
modload.ForceUseModules = true
|
||||||
|
modload.RootMode = modload.NeedRoot
|
||||||
|
|
||||||
|
loadOpts := modload.PackageOpts{
|
||||||
|
Tags: imports.AnyTags(),
|
||||||
|
ResolveMissingImports: true,
|
||||||
|
UseVendorAll: true,
|
||||||
|
AllowErrors: vendorE,
|
||||||
|
}
|
||||||
|
_, pkgs := modload.LoadPackages(ctx, loadOpts, "all")
|
||||||
|
|
||||||
vdir := filepath.Join(modload.ModRoot(), "vendor")
|
vdir := filepath.Join(modload.ModRoot(), "vendor")
|
||||||
if err := os.RemoveAll(vdir); err != nil {
|
if err := os.RemoveAll(vdir); err != nil {
|
||||||
@ -57,7 +73,7 @@ func runVendor(cmd *base.Command, args []string) {
|
|||||||
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 == modload.Target {
|
if m.Path == "" || m == modload.Target {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
modpkgs[m] = append(modpkgs[m], pkg)
|
modpkgs[m] = append(modpkgs[m], pkg)
|
||||||
@ -75,28 +91,38 @@ func runVendor(cmd *base.Command, args []string) {
|
|||||||
includeAllReplacements = true
|
includeAllReplacements = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var vendorMods []module.Version
|
||||||
|
for m := range isExplicit {
|
||||||
|
vendorMods = append(vendorMods, m)
|
||||||
|
}
|
||||||
|
for m := range modpkgs {
|
||||||
|
if !isExplicit[m] {
|
||||||
|
vendorMods = append(vendorMods, m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.Sort(vendorMods)
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
for _, m := range modload.BuildList()[1:] {
|
for _, m := range vendorMods {
|
||||||
if pkgs := modpkgs[m]; len(pkgs) > 0 || isExplicit[m] {
|
line := moduleLine(m, modload.Replacement(m))
|
||||||
line := moduleLine(m, modload.Replacement(m))
|
buf.WriteString(line)
|
||||||
buf.WriteString(line)
|
if cfg.BuildV {
|
||||||
|
os.Stderr.WriteString(line)
|
||||||
|
}
|
||||||
|
if isExplicit[m] {
|
||||||
|
buf.WriteString("## explicit\n")
|
||||||
if cfg.BuildV {
|
if cfg.BuildV {
|
||||||
os.Stderr.WriteString(line)
|
os.Stderr.WriteString("## explicit\n")
|
||||||
}
|
}
|
||||||
if isExplicit[m] {
|
}
|
||||||
buf.WriteString("## explicit\n")
|
pkgs := modpkgs[m]
|
||||||
if cfg.BuildV {
|
sort.Strings(pkgs)
|
||||||
os.Stderr.WriteString("## explicit\n")
|
for _, pkg := range pkgs {
|
||||||
}
|
fmt.Fprintf(&buf, "%s\n", pkg)
|
||||||
}
|
if cfg.BuildV {
|
||||||
sort.Strings(pkgs)
|
fmt.Fprintf(os.Stderr, "%s\n", pkg)
|
||||||
for _, pkg := range pkgs {
|
|
||||||
fmt.Fprintf(&buf, "%s\n", pkg)
|
|
||||||
if cfg.BuildV {
|
|
||||||
fmt.Fprintf(os.Stderr, "%s\n", pkg)
|
|
||||||
}
|
|
||||||
vendorPkg(vdir, pkg)
|
|
||||||
}
|
}
|
||||||
|
vendorPkg(vdir, pkg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,7 +154,7 @@ func runVendor(cmd *base.Command, args []string) {
|
|||||||
base.Fatalf("go mod vendor: %v", err)
|
base.Fatalf("go mod vendor: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ioutil.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 mod vendor: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -217,7 +243,7 @@ var metaPrefixes = []string{
|
|||||||
}
|
}
|
||||||
|
|
||||||
// matchMetadata reports whether info is a metadata file.
|
// matchMetadata reports whether info is a metadata file.
|
||||||
func matchMetadata(dir string, info os.FileInfo) bool {
|
func matchMetadata(dir string, info fs.DirEntry) bool {
|
||||||
name := info.Name()
|
name := info.Name()
|
||||||
for _, p := range metaPrefixes {
|
for _, p := range metaPrefixes {
|
||||||
if strings.HasPrefix(name, p) {
|
if strings.HasPrefix(name, p) {
|
||||||
@ -228,12 +254,12 @@ func matchMetadata(dir string, info os.FileInfo) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// matchPotentialSourceFile reports whether info may be relevant to a build operation.
|
// matchPotentialSourceFile reports whether info may be relevant to a build operation.
|
||||||
func matchPotentialSourceFile(dir string, info os.FileInfo) bool {
|
func matchPotentialSourceFile(dir string, info fs.DirEntry) bool {
|
||||||
if strings.HasSuffix(info.Name(), "_test.go") {
|
if strings.HasSuffix(info.Name(), "_test.go") {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if strings.HasSuffix(info.Name(), ".go") {
|
if strings.HasSuffix(info.Name(), ".go") {
|
||||||
f, err := os.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 mod vendor: %v", err)
|
||||||
}
|
}
|
||||||
@ -254,8 +280,8 @@ func matchPotentialSourceFile(dir string, info os.FileInfo) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// copyDir copies all regular files satisfying match(info) from src to dst.
|
// copyDir copies all regular files satisfying match(info) from src to dst.
|
||||||
func copyDir(dst, src string, match func(dir string, info os.FileInfo) bool) {
|
func copyDir(dst, src string, match func(dir string, info fs.DirEntry) bool) {
|
||||||
files, err := ioutil.ReadDir(src)
|
files, err := os.ReadDir(src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf("go mod vendor: %v", err)
|
base.Fatalf("go mod vendor: %v", err)
|
||||||
}
|
}
|
||||||
@ -263,7 +289,7 @@ func copyDir(dst, src string, match func(dir string, info os.FileInfo) bool) {
|
|||||||
base.Fatalf("go mod vendor: %v", err)
|
base.Fatalf("go mod vendor: %v", err)
|
||||||
}
|
}
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
if file.IsDir() || !file.Mode().IsRegular() || !match(src, file) {
|
if file.IsDir() || !file.Type().IsRegular() || !match(src, file) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
r, err := os.Open(filepath.Join(src, file.Name()))
|
r, err := os.Open(filepath.Join(src, file.Name()))
|
||||||
|
@ -6,17 +6,16 @@ package modcmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"cmd/go/internal/base"
|
"cmd/go/internal/base"
|
||||||
"cmd/go/internal/cfg"
|
|
||||||
"cmd/go/internal/modfetch"
|
"cmd/go/internal/modfetch"
|
||||||
"cmd/go/internal/modload"
|
"cmd/go/internal/modload"
|
||||||
"cmd/go/internal/work"
|
|
||||||
|
|
||||||
"golang.org/x/mod/module"
|
"golang.org/x/mod/module"
|
||||||
"golang.org/x/mod/sumdb/dirhash"
|
"golang.org/x/mod/sumdb/dirhash"
|
||||||
@ -37,29 +36,23 @@ non-zero status.
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
work.AddModCommonFlags(cmdVerify)
|
base.AddModCommonFlags(&cmdVerify.Flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runVerify(cmd *base.Command, args []string) {
|
func runVerify(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
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 mod verify: verify takes no arguments")
|
||||||
}
|
}
|
||||||
// Checks go mod expected behavior
|
modload.ForceUseModules = true
|
||||||
if !modload.Enabled() || !modload.HasModRoot() {
|
modload.RootMode = modload.NeedRoot
|
||||||
if cfg.Getenv("GO111MODULE") == "off" {
|
|
||||||
base.Fatalf("go: modules disabled by GO111MODULE=off; see 'go help modules'")
|
|
||||||
} else {
|
|
||||||
base.Fatalf("go: cannot find main module; see 'go help modules'")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only verify up to GOMAXPROCS zips at once.
|
// Only verify up to GOMAXPROCS zips at once.
|
||||||
type token struct{}
|
type token struct{}
|
||||||
sem := make(chan token, runtime.GOMAXPROCS(0))
|
sem := make(chan token, runtime.GOMAXPROCS(0))
|
||||||
|
|
||||||
// Use a slice of result channels, so that the output is deterministic.
|
// Use a slice of result channels, so that the output is deterministic.
|
||||||
mods := modload.LoadBuildList()[1:]
|
mods := modload.LoadAllModules(ctx)[1:]
|
||||||
errsChans := make([]<-chan []error, len(mods))
|
errsChans := make([]<-chan []error, len(mods))
|
||||||
|
|
||||||
for i, mod := range mods {
|
for i, mod := range mods {
|
||||||
@ -93,10 +86,10 @@ func verifyMod(mod module.Version) []error {
|
|||||||
_, zipErr = os.Stat(zip)
|
_, zipErr = os.Stat(zip)
|
||||||
}
|
}
|
||||||
dir, dirErr := modfetch.DownloadDir(mod)
|
dir, dirErr := modfetch.DownloadDir(mod)
|
||||||
data, err := ioutil.ReadFile(zip + "hash")
|
data, err := os.ReadFile(zip + "hash")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if zipErr != nil && errors.Is(zipErr, os.ErrNotExist) &&
|
if zipErr != nil && errors.Is(zipErr, fs.ErrNotExist) &&
|
||||||
dirErr != nil && errors.Is(dirErr, os.ErrNotExist) {
|
dirErr != nil && errors.Is(dirErr, fs.ErrNotExist) {
|
||||||
// Nothing downloaded yet. Nothing to verify.
|
// Nothing downloaded yet. Nothing to verify.
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -105,7 +98,7 @@ func verifyMod(mod module.Version) []error {
|
|||||||
}
|
}
|
||||||
h := string(bytes.TrimSpace(data))
|
h := string(bytes.TrimSpace(data))
|
||||||
|
|
||||||
if zipErr != nil && errors.Is(zipErr, os.ErrNotExist) {
|
if zipErr != nil && errors.Is(zipErr, fs.ErrNotExist) {
|
||||||
// ok
|
// ok
|
||||||
} else {
|
} else {
|
||||||
hZ, err := dirhash.HashZip(zip, dirhash.DefaultHash)
|
hZ, err := dirhash.HashZip(zip, dirhash.DefaultHash)
|
||||||
@ -116,7 +109,7 @@ func verifyMod(mod module.Version) []error {
|
|||||||
errs = append(errs, fmt.Errorf("%s %s: zip has been modified (%v)", mod.Path, mod.Version, zip))
|
errs = append(errs, fmt.Errorf("%s %s: zip has been modified (%v)", mod.Path, mod.Version, zip))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if dirErr != nil && errors.Is(dirErr, os.ErrNotExist) {
|
if dirErr != nil && errors.Is(dirErr, fs.ErrNotExist) {
|
||||||
// ok
|
// ok
|
||||||
} else {
|
} else {
|
||||||
hD, err := dirhash.HashDir(dir, mod.Path+"@"+mod.Version, dirhash.DefaultHash)
|
hD, err := dirhash.HashDir(dir, mod.Path+"@"+mod.Version, dirhash.DefaultHash)
|
||||||
|
@ -5,12 +5,13 @@
|
|||||||
package modcmd
|
package modcmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"cmd/go/internal/base"
|
"cmd/go/internal/base"
|
||||||
|
"cmd/go/internal/imports"
|
||||||
"cmd/go/internal/modload"
|
"cmd/go/internal/modload"
|
||||||
"cmd/go/internal/work"
|
|
||||||
|
|
||||||
"golang.org/x/mod/module"
|
"golang.org/x/mod/module"
|
||||||
)
|
)
|
||||||
@ -57,25 +58,33 @@ var (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
cmdWhy.Run = runWhy // break init cycle
|
cmdWhy.Run = runWhy // break init cycle
|
||||||
work.AddModCommonFlags(cmdWhy)
|
base.AddModCommonFlags(&cmdWhy.Flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runWhy(cmd *base.Command, args []string) {
|
func runWhy(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
loadALL := modload.LoadALL
|
modload.ForceUseModules = true
|
||||||
if *whyVendor {
|
modload.RootMode = modload.NeedRoot
|
||||||
loadALL = modload.LoadVendor
|
|
||||||
|
loadOpts := modload.PackageOpts{
|
||||||
|
Tags: imports.AnyTags(),
|
||||||
|
LoadTests: !*whyVendor,
|
||||||
|
SilenceErrors: true,
|
||||||
|
UseVendorAll: *whyVendor,
|
||||||
}
|
}
|
||||||
|
|
||||||
if *whyM {
|
if *whyM {
|
||||||
listU := false
|
listU := false
|
||||||
listVersions := false
|
listVersions := false
|
||||||
|
listRetractions := false
|
||||||
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 mod why: module query not allowed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mods := modload.ListModules(args, listU, listVersions)
|
mods := modload.ListModules(ctx, args, listU, listVersions, listRetractions)
|
||||||
byModule := make(map[module.Version][]string)
|
byModule := make(map[module.Version][]string)
|
||||||
for _, path := range loadALL() {
|
_, pkgs := modload.LoadPackages(ctx, loadOpts, "all")
|
||||||
|
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] = append(byModule[m], path)
|
||||||
@ -104,8 +113,11 @@ func runWhy(cmd *base.Command, args []string) {
|
|||||||
sep = "\n"
|
sep = "\n"
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
matches := modload.ImportPaths(args) // resolve to packages
|
// Resolve to packages.
|
||||||
loadALL() // rebuild graph, from main module (not from named packages)
|
matches, _ := modload.LoadPackages(ctx, loadOpts, args...)
|
||||||
|
|
||||||
|
modload.LoadPackages(ctx, loadOpts, "all") // rebuild graph, from main module (not from named packages)
|
||||||
|
|
||||||
sep := ""
|
sep := ""
|
||||||
for _, m := range matches {
|
for _, m := range matches {
|
||||||
for _, path := range m.Pkgs {
|
for _, path := range m.Pkgs {
|
||||||
|
@ -7,13 +7,12 @@ package modconv
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"cmd/go/internal/base"
|
"cmd/go/internal/base"
|
||||||
"cmd/go/internal/modfetch"
|
"cmd/go/internal/modfetch"
|
||||||
"cmd/go/internal/par"
|
|
||||||
|
|
||||||
"golang.org/x/mod/modfile"
|
"golang.org/x/mod/modfile"
|
||||||
"golang.org/x/mod/module"
|
"golang.org/x/mod/module"
|
||||||
@ -42,46 +41,54 @@ func ConvertLegacyConfig(f *modfile.File, file string, data []byte) error {
|
|||||||
|
|
||||||
// Convert requirements block, which may use raw SHA1 hashes as versions,
|
// Convert requirements block, which may use raw SHA1 hashes as versions,
|
||||||
// to valid semver requirement list, respecting major versions.
|
// to valid semver requirement list, respecting major versions.
|
||||||
var (
|
versions := make([]module.Version, len(mf.Require))
|
||||||
work par.Work
|
replace := make(map[string]*modfile.Replace)
|
||||||
mu sync.Mutex
|
|
||||||
need = make(map[string]string)
|
|
||||||
replace = make(map[string]*modfile.Replace)
|
|
||||||
)
|
|
||||||
|
|
||||||
for _, r := range mf.Replace {
|
for _, r := range mf.Replace {
|
||||||
replace[r.New.Path] = r
|
replace[r.New.Path] = r
|
||||||
replace[r.Old.Path] = r
|
replace[r.Old.Path] = r
|
||||||
}
|
}
|
||||||
for _, r := range mf.Require {
|
|
||||||
|
type token struct{}
|
||||||
|
sem := make(chan token, runtime.GOMAXPROCS(0))
|
||||||
|
for i, r := range mf.Require {
|
||||||
m := r.Mod
|
m := r.Mod
|
||||||
if m.Path == "" {
|
if m.Path == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if re, ok := replace[m.Path]; ok {
|
if re, ok := replace[m.Path]; ok {
|
||||||
work.Add(re.New)
|
m = re.New
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
work.Add(r.Mod)
|
sem <- token{}
|
||||||
|
go func(i int, m module.Version) {
|
||||||
|
defer func() { <-sem }()
|
||||||
|
repo, info, err := modfetch.ImportRepoRev(m.Path, m.Version)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "go: converting %s: stat %s@%s: %v\n", base.ShortPath(file), m.Path, m.Version, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
path := repo.ModulePath()
|
||||||
|
versions[i].Path = path
|
||||||
|
versions[i].Version = info.Version
|
||||||
|
}(i, m)
|
||||||
|
}
|
||||||
|
// Fill semaphore channel to wait for all tasks to finish.
|
||||||
|
for n := cap(sem); n > 0; n-- {
|
||||||
|
sem <- token{}
|
||||||
}
|
}
|
||||||
|
|
||||||
work.Do(10, func(item interface{}) {
|
need := map[string]string{}
|
||||||
r := item.(module.Version)
|
for _, v := range versions {
|
||||||
repo, info, err := modfetch.ImportRepoRev(r.Path, r.Version)
|
if v.Path == "" {
|
||||||
if err != nil {
|
continue
|
||||||
fmt.Fprintf(os.Stderr, "go: converting %s: stat %s@%s: %v\n", base.ShortPath(file), r.Path, r.Version, err)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
mu.Lock()
|
|
||||||
path := repo.ModulePath()
|
|
||||||
// Don't use semver.Max here; need to preserve +incompatible suffix.
|
// Don't use semver.Max here; need to preserve +incompatible suffix.
|
||||||
if v, ok := need[path]; !ok || semver.Compare(v, info.Version) < 0 {
|
if needv, ok := need[v.Path]; !ok || semver.Compare(needv, v.Version) < 0 {
|
||||||
need[path] = info.Version
|
need[v.Path] = v.Version
|
||||||
}
|
}
|
||||||
mu.Unlock()
|
}
|
||||||
})
|
paths := make([]string, 0, len(need))
|
||||||
|
|
||||||
var paths []string
|
|
||||||
for path := range need {
|
for path := range need {
|
||||||
paths = append(paths, path)
|
paths = append(paths, path)
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,9 @@ package modconv
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"internal/testenv"
|
"internal/testenv"
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@ -36,7 +36,7 @@ func testMain(m *testing.M) int {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
dir, err := ioutil.TempDir("", "modconv-test-")
|
dir, err := os.MkdirTemp("", "modconv-test-")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -146,6 +146,8 @@ func TestConvertLegacyConfig(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(strings.ReplaceAll(tt.path, "/", "_")+"_"+tt.vers, func(t *testing.T) {
|
t.Run(strings.ReplaceAll(tt.path, "/", "_")+"_"+tt.vers, func(t *testing.T) {
|
||||||
f, err := modfile.Parse("golden", []byte(tt.gomod), nil)
|
f, err := modfile.Parse("golden", []byte(tt.gomod), nil)
|
||||||
@ -157,14 +159,14 @@ func TestConvertLegacyConfig(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dir, err := modfetch.Download(module.Version{Path: tt.path, Version: tt.vers})
|
dir, err := modfetch.Download(ctx, module.Version{Path: tt.path, Version: tt.vers})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for name := range Converters {
|
for name := range Converters {
|
||||||
file := filepath.Join(dir, name)
|
file := filepath.Join(dir, name)
|
||||||
data, err := ioutil.ReadFile(file)
|
data, err := os.ReadFile(file)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
f := new(modfile.File)
|
f := new(modfile.File)
|
||||||
f.AddModuleStmt(tt.path)
|
f.AddModuleStmt(tt.path)
|
||||||
|
@ -7,7 +7,7 @@ package modconv
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
@ -42,7 +42,7 @@ func Test(t *testing.T) {
|
|||||||
if Converters[extMap[ext]] == nil {
|
if Converters[extMap[ext]] == nil {
|
||||||
t.Fatalf("Converters[%q] == nil", extMap[ext])
|
t.Fatalf("Converters[%q] == nil", extMap[ext])
|
||||||
}
|
}
|
||||||
data, err := ioutil.ReadFile(test)
|
data, err := os.ReadFile(test)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -50,7 +50,7 @@ func Test(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
want, err := ioutil.ReadFile(test[:len(test)-len(ext)] + ".out")
|
want, err := os.ReadFile(test[:len(test)-len(ext)] + ".out")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
@ -10,10 +10,11 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"cmd/go/internal/base"
|
"cmd/go/internal/base"
|
||||||
"cmd/go/internal/cfg"
|
"cmd/go/internal/cfg"
|
||||||
@ -59,7 +60,7 @@ func CachePath(m module.Version, suffix string) (string, error) {
|
|||||||
|
|
||||||
// DownloadDir returns the directory to which m should have been downloaded.
|
// DownloadDir returns the directory to which m should have been downloaded.
|
||||||
// An error will be returned if the module path or version cannot be escaped.
|
// An error will be returned if the module path or version cannot be escaped.
|
||||||
// An error satisfying errors.Is(err, os.ErrNotExist) will be returned
|
// An error satisfying errors.Is(err, fs.ErrNotExist) will be returned
|
||||||
// along with the directory if the directory does not exist or if the directory
|
// along with the directory if the directory does not exist or if the directory
|
||||||
// is not completely populated.
|
// is not completely populated.
|
||||||
func DownloadDir(m module.Version) (string, error) {
|
func DownloadDir(m module.Version) (string, error) {
|
||||||
@ -106,14 +107,14 @@ func DownloadDir(m module.Version) (string, error) {
|
|||||||
// DownloadDirPartialError is returned by DownloadDir if a module directory
|
// DownloadDirPartialError is returned by DownloadDir if a module directory
|
||||||
// exists but was not completely populated.
|
// exists but was not completely populated.
|
||||||
//
|
//
|
||||||
// DownloadDirPartialError is equivalent to os.ErrNotExist.
|
// DownloadDirPartialError is equivalent to fs.ErrNotExist.
|
||||||
type DownloadDirPartialError struct {
|
type DownloadDirPartialError struct {
|
||||||
Dir string
|
Dir string
|
||||||
Err error
|
Err error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *DownloadDirPartialError) Error() string { return fmt.Sprintf("%s: %v", e.Dir, e.Err) }
|
func (e *DownloadDirPartialError) Error() string { return fmt.Sprintf("%s: %v", e.Dir, e.Err) }
|
||||||
func (e *DownloadDirPartialError) Is(err error) bool { return err == os.ErrNotExist }
|
func (e *DownloadDirPartialError) Is(err error) bool { return err == fs.ErrNotExist }
|
||||||
|
|
||||||
// lockVersion locks a file within the module cache that guards the downloading
|
// lockVersion locks a file within the module cache that guards the downloading
|
||||||
// and extraction of the zipfile for the given module version.
|
// and extraction of the zipfile for the given module version.
|
||||||
@ -155,16 +156,30 @@ func SideLock() (unlock func(), err error) {
|
|||||||
type cachingRepo struct {
|
type cachingRepo struct {
|
||||||
path string
|
path string
|
||||||
cache par.Cache // cache for all operations
|
cache par.Cache // cache for all operations
|
||||||
r Repo
|
|
||||||
|
once sync.Once
|
||||||
|
initRepo func() (Repo, error)
|
||||||
|
r Repo
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCachingRepo(r Repo) *cachingRepo {
|
func newCachingRepo(path string, initRepo func() (Repo, error)) *cachingRepo {
|
||||||
return &cachingRepo{
|
return &cachingRepo{
|
||||||
r: r,
|
path: path,
|
||||||
path: r.ModulePath(),
|
initRepo: initRepo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *cachingRepo) repo() Repo {
|
||||||
|
r.once.Do(func() {
|
||||||
|
var err error
|
||||||
|
r.r, err = r.initRepo()
|
||||||
|
if err != nil {
|
||||||
|
r.r = errRepo{r.path, err}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return r.r
|
||||||
|
}
|
||||||
|
|
||||||
func (r *cachingRepo) ModulePath() string {
|
func (r *cachingRepo) ModulePath() string {
|
||||||
return r.path
|
return r.path
|
||||||
}
|
}
|
||||||
@ -175,7 +190,7 @@ func (r *cachingRepo) Versions(prefix string) ([]string, error) {
|
|||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
c := r.cache.Do("versions:"+prefix, func() interface{} {
|
c := r.cache.Do("versions:"+prefix, func() interface{} {
|
||||||
list, err := r.r.Versions(prefix)
|
list, err := r.repo().Versions(prefix)
|
||||||
return cached{list, err}
|
return cached{list, err}
|
||||||
}).(cached)
|
}).(cached)
|
||||||
|
|
||||||
@ -197,7 +212,7 @@ func (r *cachingRepo) Stat(rev string) (*RevInfo, error) {
|
|||||||
return cachedInfo{info, nil}
|
return cachedInfo{info, nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
info, err = r.r.Stat(rev)
|
info, err = r.repo().Stat(rev)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// If we resolved, say, 1234abcde to v0.0.0-20180604122334-1234abcdef78,
|
// If we resolved, say, 1234abcde to v0.0.0-20180604122334-1234abcdef78,
|
||||||
// then save the information under the proper version, for future use.
|
// then save the information under the proper version, for future use.
|
||||||
@ -224,7 +239,7 @@ func (r *cachingRepo) Stat(rev string) (*RevInfo, error) {
|
|||||||
|
|
||||||
func (r *cachingRepo) Latest() (*RevInfo, error) {
|
func (r *cachingRepo) Latest() (*RevInfo, error) {
|
||||||
c := r.cache.Do("latest:", func() interface{} {
|
c := r.cache.Do("latest:", func() interface{} {
|
||||||
info, err := r.r.Latest()
|
info, err := r.repo().Latest()
|
||||||
|
|
||||||
// Save info for likely future Stat call.
|
// Save info for likely future Stat call.
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -258,7 +273,7 @@ func (r *cachingRepo) GoMod(version string) ([]byte, error) {
|
|||||||
return cached{text, nil}
|
return cached{text, nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
text, err = r.r.GoMod(version)
|
text, err = r.repo().GoMod(version)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if err := checkGoMod(r.path, version, text); err != nil {
|
if err := checkGoMod(r.path, version, text); err != nil {
|
||||||
return cached{text, err}
|
return cached{text, err}
|
||||||
@ -277,26 +292,11 @@ func (r *cachingRepo) GoMod(version string) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *cachingRepo) Zip(dst io.Writer, version string) error {
|
func (r *cachingRepo) Zip(dst io.Writer, version string) error {
|
||||||
return r.r.Zip(dst, version)
|
return r.repo().Zip(dst, version)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stat is like Lookup(path).Stat(rev) but avoids the
|
// InfoFile is like Lookup(path).Stat(version) but returns the name of the file
|
||||||
// repository path resolution in Lookup if the result is
|
// containing the cached information.
|
||||||
// already cached on local disk.
|
|
||||||
func Stat(proxy, path, rev string) (*RevInfo, error) {
|
|
||||||
_, info, err := readDiskStat(path, rev)
|
|
||||||
if err == nil {
|
|
||||||
return info, nil
|
|
||||||
}
|
|
||||||
repo, err := Lookup(proxy, path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return repo.Stat(rev)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InfoFile is like Stat but returns the name of the file containing
|
|
||||||
// the cached information.
|
|
||||||
func InfoFile(path, version string) (string, error) {
|
func InfoFile(path, version string) (string, error) {
|
||||||
if !semver.IsValid(version) {
|
if !semver.IsValid(version) {
|
||||||
return "", fmt.Errorf("invalid version %q", version)
|
return "", fmt.Errorf("invalid version %q", version)
|
||||||
@ -307,10 +307,7 @@ func InfoFile(path, version string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
err := TryProxies(func(proxy string) error {
|
err := TryProxies(func(proxy string) error {
|
||||||
repo, err := Lookup(proxy, path)
|
_, err := Lookup(proxy, path).Stat(version)
|
||||||
if err == nil {
|
|
||||||
_, err = repo.Stat(version)
|
|
||||||
}
|
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -336,11 +333,7 @@ func GoMod(path, rev string) ([]byte, error) {
|
|||||||
rev = info.Version
|
rev = info.Version
|
||||||
} else {
|
} else {
|
||||||
err := TryProxies(func(proxy string) error {
|
err := TryProxies(func(proxy string) error {
|
||||||
repo, err := Lookup(proxy, path)
|
info, err := Lookup(proxy, path).Stat(rev)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
info, err := repo.Stat(rev)
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
rev = info.Version
|
rev = info.Version
|
||||||
}
|
}
|
||||||
@ -357,11 +350,8 @@ func GoMod(path, rev string) ([]byte, error) {
|
|||||||
return data, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err = TryProxies(func(proxy string) error {
|
err = TryProxies(func(proxy string) (err error) {
|
||||||
repo, err := Lookup(proxy, path)
|
data, err = Lookup(proxy, path).GoMod(rev)
|
||||||
if err == nil {
|
|
||||||
data, err = repo.GoMod(rev)
|
|
||||||
}
|
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
return data, err
|
return data, err
|
||||||
@ -492,7 +482,7 @@ func readDiskStatByHash(path, rev string) (file string, info *RevInfo, err error
|
|||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
if strings.HasSuffix(name, suffix) {
|
if strings.HasSuffix(name, suffix) {
|
||||||
v := strings.TrimSuffix(name, ".info")
|
v := strings.TrimSuffix(name, ".info")
|
||||||
if IsPseudoVersion(v) && semver.Max(maxVersion, v) == v {
|
if IsPseudoVersion(v) && semver.Compare(v, maxVersion) > 0 {
|
||||||
maxVersion = v
|
maxVersion = v
|
||||||
file, info, err = readDiskStat(path, strings.TrimSuffix(name, ".info"))
|
file, info, err = readDiskStat(path, strings.TrimSuffix(name, ".info"))
|
||||||
}
|
}
|
||||||
@ -607,7 +597,7 @@ func rewriteVersionList(dir string) {
|
|||||||
}
|
}
|
||||||
defer unlock()
|
defer unlock()
|
||||||
|
|
||||||
infos, err := ioutil.ReadDir(dir)
|
infos, err := os.ReadDir(dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -5,14 +5,13 @@
|
|||||||
package modfetch
|
package modfetch
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestWriteDiskCache(t *testing.T) {
|
func TestWriteDiskCache(t *testing.T) {
|
||||||
tmpdir, err := ioutil.TempDir("", "go-writeCache-test-")
|
tmpdir, err := os.MkdirTemp("", "go-writeCache-test-")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ import (
|
|||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -79,9 +79,8 @@ type Repo interface {
|
|||||||
ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser, err error)
|
ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser, err error)
|
||||||
|
|
||||||
// RecentTag returns the most recent tag on rev or one of its predecessors
|
// RecentTag returns the most recent tag on rev or one of its predecessors
|
||||||
// with the given prefix and major version.
|
// with the given prefix. allowed may be used to filter out unwanted versions.
|
||||||
// An empty major string matches any major version.
|
RecentTag(rev, prefix string, allowed func(string) bool) (tag string, err error)
|
||||||
RecentTag(rev, prefix, major string) (tag string, err error)
|
|
||||||
|
|
||||||
// DescendsFrom reports whether rev or any of its ancestors has the given tag.
|
// DescendsFrom reports whether rev or any of its ancestors has the given tag.
|
||||||
//
|
//
|
||||||
@ -106,7 +105,7 @@ type FileRev struct {
|
|||||||
Err error // error if any; os.IsNotExist(Err)==true if rev exists but file does not exist in that rev
|
Err error // error if any; os.IsNotExist(Err)==true if rev exists but file does not exist in that rev
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnknownRevisionError is an error equivalent to os.ErrNotExist, but for a
|
// UnknownRevisionError is an error equivalent to fs.ErrNotExist, but for a
|
||||||
// revision rather than a file.
|
// revision rather than a file.
|
||||||
type UnknownRevisionError struct {
|
type UnknownRevisionError struct {
|
||||||
Rev string
|
Rev string
|
||||||
@ -116,10 +115,10 @@ func (e *UnknownRevisionError) Error() string {
|
|||||||
return "unknown revision " + e.Rev
|
return "unknown revision " + e.Rev
|
||||||
}
|
}
|
||||||
func (UnknownRevisionError) Is(err error) bool {
|
func (UnknownRevisionError) Is(err error) bool {
|
||||||
return err == os.ErrNotExist
|
return err == fs.ErrNotExist
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrNoCommits is an error equivalent to os.ErrNotExist indicating that a given
|
// ErrNoCommits is an error equivalent to fs.ErrNotExist indicating that a given
|
||||||
// repository or module contains no commits.
|
// repository or module contains no commits.
|
||||||
var ErrNoCommits error = noCommitsError{}
|
var ErrNoCommits error = noCommitsError{}
|
||||||
|
|
||||||
@ -129,7 +128,7 @@ func (noCommitsError) Error() string {
|
|||||||
return "no commits"
|
return "no commits"
|
||||||
}
|
}
|
||||||
func (noCommitsError) Is(err error) bool {
|
func (noCommitsError) Is(err error) bool {
|
||||||
return err == os.ErrNotExist
|
return err == fs.ErrNotExist
|
||||||
}
|
}
|
||||||
|
|
||||||
// AllHex reports whether the revision rev is entirely lower-case hexadecimal digits.
|
// AllHex reports whether the revision rev is entirely lower-case hexadecimal digits.
|
||||||
@ -189,7 +188,7 @@ func WorkDir(typ, name string) (dir, lockfile string, err error) {
|
|||||||
}
|
}
|
||||||
defer unlock()
|
defer unlock()
|
||||||
|
|
||||||
data, err := ioutil.ReadFile(dir + ".info")
|
data, err := os.ReadFile(dir + ".info")
|
||||||
info, err2 := os.Stat(dir)
|
info, err2 := os.Stat(dir)
|
||||||
if err == nil && err2 == nil && info.IsDir() {
|
if err == nil && err2 == nil && info.IsDir() {
|
||||||
// Info file and directory both already exist: reuse.
|
// Info file and directory both already exist: reuse.
|
||||||
@ -211,7 +210,7 @@ func WorkDir(typ, name string) (dir, lockfile string, err error) {
|
|||||||
if err := os.MkdirAll(dir, 0777); err != nil {
|
if err := os.MkdirAll(dir, 0777); err != nil {
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
if err := ioutil.WriteFile(dir+".info", []byte(key), 0666); err != nil {
|
if err := os.WriteFile(dir+".info", []byte(key), 0666); err != nil {
|
||||||
os.RemoveAll(dir)
|
os.RemoveAll(dir)
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
@ -264,6 +263,9 @@ func RunWithStdin(dir string, stdin io.Reader, cmdline ...interface{}) ([]byte,
|
|||||||
}
|
}
|
||||||
|
|
||||||
cmd := str.StringList(cmdline...)
|
cmd := str.StringList(cmdline...)
|
||||||
|
if os.Getenv("TESTGOVCS") == "panic" {
|
||||||
|
panic(fmt.Sprintf("use of vcs: %v", cmd))
|
||||||
|
}
|
||||||
if cfg.BuildX {
|
if cfg.BuildX {
|
||||||
text := new(strings.Builder)
|
text := new(strings.Builder)
|
||||||
if dir != "" {
|
if dir != "" {
|
||||||
|
@ -9,7 +9,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/fs"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@ -34,13 +34,13 @@ func LocalGitRepo(remote string) (Repo, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// A notExistError wraps another error to retain its original text
|
// A notExistError wraps another error to retain its original text
|
||||||
// but makes it opaquely equivalent to os.ErrNotExist.
|
// but makes it opaquely equivalent to fs.ErrNotExist.
|
||||||
type notExistError struct {
|
type notExistError struct {
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e notExistError) Error() string { return e.err.Error() }
|
func (e notExistError) Error() string { return e.err.Error() }
|
||||||
func (notExistError) Is(err error) bool { return err == os.ErrNotExist }
|
func (notExistError) Is(err error) bool { return err == fs.ErrNotExist }
|
||||||
|
|
||||||
const gitWorkDirType = "git3"
|
const gitWorkDirType = "git3"
|
||||||
|
|
||||||
@ -188,7 +188,7 @@ func (r *gitRepo) loadRefs() {
|
|||||||
// For HTTP and HTTPS, that's easy to detect: we'll try to fetch the URL
|
// For HTTP and HTTPS, that's easy to detect: we'll try to fetch the URL
|
||||||
// ourselves and see what code it serves.
|
// ourselves and see what code it serves.
|
||||||
if u, err := url.Parse(r.remoteURL); err == nil && (u.Scheme == "http" || u.Scheme == "https") {
|
if u, err := url.Parse(r.remoteURL); err == nil && (u.Scheme == "http" || u.Scheme == "https") {
|
||||||
if _, err := web.GetBytes(u); errors.Is(err, os.ErrNotExist) {
|
if _, err := web.GetBytes(u); errors.Is(err, fs.ErrNotExist) {
|
||||||
gitErr = notExistError{gitErr}
|
gitErr = notExistError{gitErr}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -505,7 +505,7 @@ func (r *gitRepo) ReadFile(rev, file string, maxSize int64) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
out, err := Run(r.dir, "git", "cat-file", "blob", info.Name+":"+file)
|
out, err := Run(r.dir, "git", "cat-file", "blob", info.Name+":"+file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, os.ErrNotExist
|
return nil, fs.ErrNotExist
|
||||||
}
|
}
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
@ -629,9 +629,9 @@ func (r *gitRepo) readFileRevs(tags []string, file string, fileMap map[string]*F
|
|||||||
case "tag", "commit":
|
case "tag", "commit":
|
||||||
switch fileType {
|
switch fileType {
|
||||||
default:
|
default:
|
||||||
f.Err = &os.PathError{Path: tag + ":" + file, Op: "read", Err: fmt.Errorf("unexpected non-blob type %q", fileType)}
|
f.Err = &fs.PathError{Path: tag + ":" + file, Op: "read", Err: fmt.Errorf("unexpected non-blob type %q", fileType)}
|
||||||
case "missing":
|
case "missing":
|
||||||
f.Err = &os.PathError{Path: tag + ":" + file, Op: "read", Err: os.ErrNotExist}
|
f.Err = &fs.PathError{Path: tag + ":" + file, Op: "read", Err: fs.ErrNotExist}
|
||||||
case "blob":
|
case "blob":
|
||||||
f.Data = fileData
|
f.Data = fileData
|
||||||
}
|
}
|
||||||
@ -644,7 +644,7 @@ func (r *gitRepo) readFileRevs(tags []string, file string, fileMap map[string]*F
|
|||||||
return missing, nil
|
return missing, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *gitRepo) RecentTag(rev, prefix, major string) (tag string, err error) {
|
func (r *gitRepo) RecentTag(rev, prefix string, allowed func(string) bool) (tag string, err error) {
|
||||||
info, err := r.Stat(rev)
|
info, err := r.Stat(rev)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@ -680,7 +680,10 @@ func (r *gitRepo) RecentTag(rev, prefix, major string) (tag string, err error) {
|
|||||||
// NOTE: Do not replace the call to semver.Compare with semver.Max.
|
// NOTE: Do not replace the call to semver.Compare with semver.Max.
|
||||||
// We want to return the actual tag, not a canonicalized version of it,
|
// We want to return the actual tag, not a canonicalized version of it,
|
||||||
// and semver.Max currently canonicalizes (see golang.org/issue/32700).
|
// and semver.Max currently canonicalizes (see golang.org/issue/32700).
|
||||||
if c := semver.Canonical(semtag); c != "" && strings.HasPrefix(semtag, c) && (major == "" || semver.Major(c) == major) && semver.Compare(semtag, highest) > 0 {
|
if c := semver.Canonical(semtag); c == "" || !strings.HasPrefix(semtag, c) || !allowed(semtag) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if semver.Compare(semtag, highest) > 0 {
|
||||||
highest = semtag
|
highest = semtag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -823,12 +826,12 @@ func (r *gitRepo) ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser,
|
|||||||
archive, err := Run(r.dir, "git", "-c", "core.autocrlf=input", "-c", "core.eol=lf", "archive", "--format=zip", "--prefix=prefix/", info.Name, args)
|
archive, err := Run(r.dir, "git", "-c", "core.autocrlf=input", "-c", "core.eol=lf", "archive", "--format=zip", "--prefix=prefix/", info.Name, args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if bytes.Contains(err.(*RunError).Stderr, []byte("did not match any files")) {
|
if bytes.Contains(err.(*RunError).Stderr, []byte("did not match any files")) {
|
||||||
return nil, os.ErrNotExist
|
return nil, fs.ErrNotExist
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return ioutil.NopCloser(bytes.NewReader(archive)), nil
|
return io.NopCloser(bytes.NewReader(archive)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensureGitAttributes makes sure export-subst and export-ignore features are
|
// ensureGitAttributes makes sure export-subst and export-ignore features are
|
||||||
@ -859,7 +862,7 @@ func ensureGitAttributes(repoDir string) (err error) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
b, err := ioutil.ReadAll(f)
|
b, err := io.ReadAll(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,8 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"internal/testenv"
|
"internal/testenv"
|
||||||
"io/ioutil"
|
"io"
|
||||||
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@ -52,7 +53,7 @@ func testMain(m *testing.M) int {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
dir, err := ioutil.TempDir("", "gitrepo-test-")
|
dir, err := os.MkdirTemp("", "gitrepo-test-")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -210,7 +211,7 @@ var readFileTests = []struct {
|
|||||||
repo: gitrepo1,
|
repo: gitrepo1,
|
||||||
rev: "v2.3.4",
|
rev: "v2.3.4",
|
||||||
file: "another.txt",
|
file: "another.txt",
|
||||||
err: os.ErrNotExist.Error(),
|
err: fs.ErrNotExist.Error(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -432,7 +433,7 @@ func TestReadZip(t *testing.T) {
|
|||||||
if tt.err != "" {
|
if tt.err != "" {
|
||||||
t.Fatalf("ReadZip: no error, wanted %v", tt.err)
|
t.Fatalf("ReadZip: no error, wanted %v", tt.err)
|
||||||
}
|
}
|
||||||
zipdata, err := ioutil.ReadAll(rc)
|
zipdata, err := io.ReadAll(rc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
@ -115,7 +115,7 @@ func main() {
|
|||||||
fmt.Fprintf(os.Stderr, "?%s\n", err)
|
fmt.Fprintf(os.Stderr, "?%s\n", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
data, err := ioutil.ReadAll(rc)
|
data, err := io.ReadAll(rc)
|
||||||
rc.Close()
|
rc.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "?%s\n", err)
|
fmt.Fprintf(os.Stderr, "?%s\n", err)
|
||||||
@ -123,7 +123,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if f[3] != "-" {
|
if f[3] != "-" {
|
||||||
if err := ioutil.WriteFile(f[3], data, 0666); err != nil {
|
if err := os.WriteFile(f[3], data, 0666); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "?%s\n", err)
|
fmt.Fprintf(os.Stderr, "?%s\n", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user