mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-10 23:11:36 +08:00
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
|
||||
merge done from the gofrontend repository.
|
||||
|
@ -101,7 +101,7 @@ MOSTLYCLEANFILES = \
|
||||
|
||||
mostlyclean-local:
|
||||
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
|
||||
|
||||
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
|
||||
rm -rf check-go-dir cmd_go-testlog
|
||||
$(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 -r $(cmdsrcdir)/go/internal check-go-dir/src/cmd/go/
|
||||
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
|
||||
# here too will catch more problems.
|
||||
check-runtime: go$(EXEEXT) $(noinst_PROGRAMS) check-head check-gccgo check-gcc
|
||||
rm -rf check-runtime-dir runtime-testlog
|
||||
$(MKDIR_P) check-runtime-dir
|
||||
rm -f runtime-testlog
|
||||
@abs_libgodir=`cd $(libgodir) && $(PWD_COMMAND)`; \
|
||||
LD_LIBRARY_PATH=`echo $${abs_libgodir}/.libs:$${LD_LIBRARY_PATH} | sed 's,::*,:,g;s,^:*,,;s,:*$$,,'`; \
|
||||
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
|
||||
rm -rf cgo-test-dir cgo-testlog
|
||||
$(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/
|
||||
@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
|
||||
@ -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
|
||||
rm -rf carchive-test-dir carchive-testlog
|
||||
$(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/
|
||||
@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
|
||||
@ -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
|
||||
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
|
||||
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)/internal/objabi check-vet-dir/src/cmd/internal
|
||||
cp $(libgodir)/objabi.go check-vet-dir/src/cmd/internal/objabi/
|
||||
|
@ -703,8 +703,8 @@ distclean-generic:
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
@NATIVE_FALSE@uninstall-local:
|
||||
@NATIVE_FALSE@install-exec-local:
|
||||
@NATIVE_FALSE@uninstall-local:
|
||||
clean: clean-am
|
||||
|
||||
clean-am: clean-binPROGRAMS clean-generic clean-noinstPROGRAMS \
|
||||
@ -814,7 +814,7 @@ s-zdefaultcc: Makefile
|
||||
|
||||
mostlyclean-local:
|
||||
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
|
||||
|
||||
@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@ rm -rf check-go-dir cmd_go-testlog
|
||||
@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 -r $(cmdsrcdir)/go/internal check-go-dir/src/cmd/go/
|
||||
@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
|
||||
# here too will catch more problems.
|
||||
@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@ $(MKDIR_P) check-runtime-dir
|
||||
@NATIVE_TRUE@ rm -f runtime-testlog
|
||||
@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@ 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@ rm -rf cgo-test-dir cgo-testlog
|
||||
@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@ @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
|
||||
@ -941,6 +946,7 @@ mostlyclean-local:
|
||||
@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@ $(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@ @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
|
||||
@ -954,6 +960,11 @@ mostlyclean-local:
|
||||
@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@ $(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)/internal/objabi check-vet-dir/src/cmd/internal
|
||||
@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
|
||||
last merge done from the master library sources.
|
||||
|
@ -775,6 +775,7 @@ libgo_go_objs = \
|
||||
syscall/errno.lo \
|
||||
syscall/signame.lo \
|
||||
syscall/wait.lo \
|
||||
os/dir_gccgo_c.lo \
|
||||
$(golangorg_x_net_lif_lo) \
|
||||
$(golangorg_x_net_route_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)
|
||||
|
||||
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_get = $(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_mvs = $(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_vcs = $(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_internal_buildid = $(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
|
||||
@ -1122,6 +1128,11 @@ syscall/wait.lo: go/syscall/wait.c runtime.inc
|
||||
@$(MKDIR_P) syscall
|
||||
$(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/cpu_gccgo.lo: go/internal/cpu/cpu_gccgo.c runtime.inc
|
||||
@$(MKDIR_P) internal/cpu
|
||||
|
@ -224,7 +224,7 @@ LTLIBRARIES = $(toolexeclib_LTLIBRARIES)
|
||||
am__DEPENDENCIES_3 = $(addsuffix .lo,$(PACKAGES)) \
|
||||
internal/bytealg/bytealg.lo reflect/makefunc_ffi_c.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 \
|
||||
runtime/internal/atomic_c.lo sync/atomic_c.lo \
|
||||
internal/cpu/cpu_gccgo.lo $(am__DEPENDENCIES_2)
|
||||
@ -940,6 +940,7 @@ libgo_go_objs = \
|
||||
syscall/errno.lo \
|
||||
syscall/signame.lo \
|
||||
syscall/wait.lo \
|
||||
os/dir_gccgo_c.lo \
|
||||
$(golangorg_x_net_lif_lo) \
|
||||
$(golangorg_x_net_route_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_user = os_user_linknames.go
|
||||
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_get = $(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_mvs = $(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_vcs = $(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_internal_buildid = $(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 =
|
||||
|
||||
@ -3009,6 +3014,11 @@ syscall/wait.lo: go/syscall/wait.c runtime.inc
|
||||
@$(MKDIR_P) syscall
|
||||
$(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/cpu_gccgo.lo: go/internal/cpu/cpu_gccgo.c runtime.inc
|
||||
@$(MKDIR_P) internal/cpu
|
||||
|
@ -1 +1 @@
|
||||
go1.15.6
|
||||
go1.16beta1
|
||||
|
@ -3,6 +3,7 @@ archive/zip
|
||||
bufio
|
||||
bytes
|
||||
cmd/go/internal/cache
|
||||
cmd/go/internal/fsys
|
||||
cmd/go/internal/generate
|
||||
cmd/go/internal/get
|
||||
cmd/go/internal/imports
|
||||
@ -16,8 +17,10 @@ cmd/go/internal/modload
|
||||
cmd/go/internal/mvs
|
||||
cmd/go/internal/par
|
||||
cmd/go/internal/search
|
||||
cmd/go/internal/str
|
||||
cmd/go/internal/test
|
||||
cmd/go/internal/txtar
|
||||
cmd/go/internal/vcs
|
||||
cmd/go/internal/work
|
||||
cmd/internal/buildid
|
||||
cmd/internal/edit
|
||||
@ -113,6 +116,7 @@ internal/trace
|
||||
internal/unsafeheader
|
||||
internal/xcoff
|
||||
io
|
||||
io/fs
|
||||
io/ioutil
|
||||
log
|
||||
log/syslog
|
||||
@ -155,6 +159,7 @@ runtime/debug
|
||||
runtime/internal/atomic
|
||||
runtime/internal/math
|
||||
runtime/internal/sys
|
||||
runtime/metrics
|
||||
runtime/pprof
|
||||
runtime/trace
|
||||
sort
|
||||
@ -164,6 +169,7 @@ sync
|
||||
sync/atomic
|
||||
syscall
|
||||
testing
|
||||
testing/fstest
|
||||
testing/iotest
|
||||
testing/quick
|
||||
text/scanner
|
||||
|
@ -36,6 +36,10 @@
|
||||
/* Define to 1 if you have the `cosl' function. */
|
||||
#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. */
|
||||
#undef HAVE_DLFCN_H
|
||||
|
||||
@ -159,6 +163,9 @@
|
||||
/* Define to 1 if you have the `mknodat' function. */
|
||||
#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. */
|
||||
#undef HAVE_NETINET_ICMP6_H
|
||||
|
||||
@ -249,6 +256,9 @@
|
||||
/* Define to 1 if you have the `strsignal' function. */
|
||||
#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 */
|
||||
#undef HAVE_STRUCT_EXCEPTION
|
||||
|
||||
@ -261,6 +271,10 @@
|
||||
/* Define to 1 if you have the <syscall.h> header file. */
|
||||
#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. */
|
||||
#undef HAVE_SYS_EPOLL_H
|
||||
|
||||
@ -279,6 +293,10 @@
|
||||
/* Define to 1 if you have the <sys/mount.h> header file. */
|
||||
#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. */
|
||||
#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_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
|
||||
# -------------------------------------------
|
||||
# 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"
|
||||
|
||||
|
||||
libtool_VERSION=18:0:0
|
||||
libtool_VERSION=19:0:0
|
||||
|
||||
|
||||
# Default to --enable-multilib
|
||||
@ -11497,7 +11554,7 @@ else
|
||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 11500 "configure"
|
||||
#line 11557 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@ -11603,7 +11660,7 @@ else
|
||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 11606 "configure"
|
||||
#line 11663 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@ -13923,7 +13980,7 @@ go_include="-include"
|
||||
# All known GOOS values. This is the union of all operating systems
|
||||
# supported by the gofrontend and all operating systems supported by
|
||||
# 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_freebsd=no
|
||||
@ -15287,6 +15344,195 @@ else
|
||||
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
|
||||
do :
|
||||
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_HEADER(config.h)
|
||||
|
||||
libtool_VERSION=18:0:0
|
||||
libtool_VERSION=19:0:0
|
||||
AC_SUBST(libtool_VERSION)
|
||||
|
||||
AM_ENABLE_MULTILIB(, ..)
|
||||
@ -167,7 +167,7 @@ AC_SUBST(go_include)
|
||||
# All known GOOS values. This is the union of all operating systems
|
||||
# supported by the gofrontend and all operating systems supported by
|
||||
# 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_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_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_TYPE_OFF_T
|
||||
AC_CHECK_TYPES([loff_t])
|
||||
|
@ -13,8 +13,8 @@ package tar
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"math"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"strconv"
|
||||
@ -525,12 +525,12 @@ func (h Header) allowedFormats() (format Format, paxHdrs map[string]string, err
|
||||
return format, paxHdrs, err
|
||||
}
|
||||
|
||||
// FileInfo returns an os.FileInfo for the Header.
|
||||
func (h *Header) FileInfo() os.FileInfo {
|
||||
// FileInfo returns an fs.FileInfo for the Header.
|
||||
func (h *Header) FileInfo() fs.FileInfo {
|
||||
return headerFileInfo{h}
|
||||
}
|
||||
|
||||
// headerFileInfo implements os.FileInfo.
|
||||
// headerFileInfo implements fs.FileInfo.
|
||||
type headerFileInfo struct {
|
||||
h *Header
|
||||
}
|
||||
@ -549,57 +549,57 @@ func (fi headerFileInfo) Name() string {
|
||||
}
|
||||
|
||||
// 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.
|
||||
mode = os.FileMode(fi.h.Mode).Perm()
|
||||
mode = fs.FileMode(fi.h.Mode).Perm()
|
||||
|
||||
// Set setuid, setgid and sticky bits.
|
||||
if fi.h.Mode&c_ISUID != 0 {
|
||||
mode |= os.ModeSetuid
|
||||
mode |= fs.ModeSetuid
|
||||
}
|
||||
if fi.h.Mode&c_ISGID != 0 {
|
||||
mode |= os.ModeSetgid
|
||||
mode |= fs.ModeSetgid
|
||||
}
|
||||
if fi.h.Mode&c_ISVTX != 0 {
|
||||
mode |= os.ModeSticky
|
||||
mode |= fs.ModeSticky
|
||||
}
|
||||
|
||||
// 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:
|
||||
mode |= os.ModeDir
|
||||
mode |= fs.ModeDir
|
||||
case c_ISFIFO:
|
||||
mode |= os.ModeNamedPipe
|
||||
mode |= fs.ModeNamedPipe
|
||||
case c_ISLNK:
|
||||
mode |= os.ModeSymlink
|
||||
mode |= fs.ModeSymlink
|
||||
case c_ISBLK:
|
||||
mode |= os.ModeDevice
|
||||
mode |= fs.ModeDevice
|
||||
case c_ISCHR:
|
||||
mode |= os.ModeDevice
|
||||
mode |= os.ModeCharDevice
|
||||
mode |= fs.ModeDevice
|
||||
mode |= fs.ModeCharDevice
|
||||
case c_ISSOCK:
|
||||
mode |= os.ModeSocket
|
||||
mode |= fs.ModeSocket
|
||||
}
|
||||
|
||||
switch fi.h.Typeflag {
|
||||
case TypeSymlink:
|
||||
mode |= os.ModeSymlink
|
||||
mode |= fs.ModeSymlink
|
||||
case TypeChar:
|
||||
mode |= os.ModeDevice
|
||||
mode |= os.ModeCharDevice
|
||||
mode |= fs.ModeDevice
|
||||
mode |= fs.ModeCharDevice
|
||||
case TypeBlock:
|
||||
mode |= os.ModeDevice
|
||||
mode |= fs.ModeDevice
|
||||
case TypeDir:
|
||||
mode |= os.ModeDir
|
||||
mode |= fs.ModeDir
|
||||
case TypeFifo:
|
||||
mode |= os.ModeNamedPipe
|
||||
mode |= fs.ModeNamedPipe
|
||||
}
|
||||
|
||||
return mode
|
||||
}
|
||||
|
||||
// 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 (
|
||||
// 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 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
|
||||
// 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 {
|
||||
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():
|
||||
h.Typeflag = TypeDir
|
||||
h.Name += "/"
|
||||
case fm&os.ModeSymlink != 0:
|
||||
case fm&fs.ModeSymlink != 0:
|
||||
h.Typeflag = TypeSymlink
|
||||
h.Linkname = link
|
||||
case fm&os.ModeDevice != 0:
|
||||
if fm&os.ModeCharDevice != 0 {
|
||||
case fm&fs.ModeDevice != 0:
|
||||
if fm&fs.ModeCharDevice != 0 {
|
||||
h.Typeflag = TypeChar
|
||||
} else {
|
||||
h.Typeflag = TypeBlock
|
||||
}
|
||||
case fm&os.ModeNamedPipe != 0:
|
||||
case fm&fs.ModeNamedPipe != 0:
|
||||
h.Typeflag = TypeFifo
|
||||
case fm&os.ModeSocket != 0:
|
||||
case fm&fs.ModeSocket != 0:
|
||||
return nil, fmt.Errorf("archive/tar: sockets not supported")
|
||||
default:
|
||||
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
|
||||
}
|
||||
if fm&os.ModeSetgid != 0 {
|
||||
if fm&fs.ModeSetgid != 0 {
|
||||
h.Mode |= c_ISGID
|
||||
}
|
||||
if fm&os.ModeSticky != 0 {
|
||||
if fm&fs.ModeSticky != 0 {
|
||||
h.Mode |= c_ISVTX
|
||||
}
|
||||
// If possible, populate additional fields from OS-specific
|
||||
|
@ -7,7 +7,6 @@ package tar
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@ -104,7 +103,7 @@ func (tr *Reader) next() (*Header, error) {
|
||||
continue // This is a meta header affecting the next header
|
||||
case TypeGNULongName, TypeGNULongLink:
|
||||
format.mayOnlyBe(FormatGNU)
|
||||
realname, err := ioutil.ReadAll(tr)
|
||||
realname, err := io.ReadAll(tr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -294,7 +293,7 @@ func mergePAX(hdr *Header, paxHdrs map[string]string) (err error) {
|
||||
// parsePAX parses PAX headers.
|
||||
// If an extended header (type 'x') is invalid, ErrHeader is returned
|
||||
func parsePAX(r io.Reader) (map[string]string, error) {
|
||||
buf, err := ioutil.ReadAll(r)
|
||||
buf, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
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 {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"os"
|
||||
"path"
|
||||
@ -773,7 +772,7 @@ func TestReadTruncation(t *testing.T) {
|
||||
"testdata/pax-path-hdr.tar",
|
||||
"testdata/sparse-formats.tar",
|
||||
} {
|
||||
buf, err := ioutil.ReadFile(p)
|
||||
buf, err := os.ReadFile(p)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
@ -865,7 +864,7 @@ func TestReadTruncation(t *testing.T) {
|
||||
}
|
||||
cnt++
|
||||
if s2 == "manual" {
|
||||
if _, err = tr.writeTo(ioutil.Discard); err != nil {
|
||||
if _, err = tr.writeTo(io.Discard); err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
package tar
|
||||
|
||||
import (
|
||||
"os"
|
||||
"io/fs"
|
||||
"os/user"
|
||||
"runtime"
|
||||
"strconv"
|
||||
@ -23,7 +23,7 @@ func init() {
|
||||
// The downside is that renaming uname or gname by the OS never takes effect.
|
||||
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)
|
||||
if !ok {
|
||||
return nil
|
||||
@ -71,7 +71,7 @@ func statUnix(fi os.FileInfo, h *Header) error {
|
||||
minor := uint32((dev & 0x00000000000000ff) >> 0)
|
||||
minor |= uint32((dev & 0x00000ffffff00000) >> 12)
|
||||
h.Devmajor, h.Devminor = int64(major), int64(minor)
|
||||
case "darwin":
|
||||
case "darwin", "ios":
|
||||
// Copied from golang.org/x/sys/unix/dev_darwin.go.
|
||||
major := uint32((dev >> 24) & 0xff)
|
||||
minor := uint32(dev & 0xffffff)
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"io/fs"
|
||||
"math"
|
||||
"os"
|
||||
"path"
|
||||
@ -262,7 +262,7 @@ func TestFileInfoHeaderDir(t *testing.T) {
|
||||
func TestFileInfoHeaderSymlink(t *testing.T) {
|
||||
testenv.MustHaveSymlink(t)
|
||||
|
||||
tmpdir, err := ioutil.TempDir("", "TestFileInfoHeaderSymlink")
|
||||
tmpdir, err := os.MkdirTemp("", "TestFileInfoHeaderSymlink")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -327,7 +327,7 @@ func TestRoundTrip(t *testing.T) {
|
||||
if !reflect.DeepEqual(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 {
|
||||
t.Fatalf("Read: %v", err)
|
||||
}
|
||||
@ -338,7 +338,7 @@ func TestRoundTrip(t *testing.T) {
|
||||
|
||||
type headerRoundTripTest struct {
|
||||
h *Header
|
||||
fm os.FileMode
|
||||
fm fs.FileMode
|
||||
}
|
||||
|
||||
func TestHeaderRoundTrip(t *testing.T) {
|
||||
@ -361,7 +361,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
||||
ModTime: time.Unix(1360600852, 0),
|
||||
Typeflag: TypeSymlink,
|
||||
},
|
||||
fm: 0777 | os.ModeSymlink,
|
||||
fm: 0777 | fs.ModeSymlink,
|
||||
}, {
|
||||
// character device node.
|
||||
h: &Header{
|
||||
@ -371,7 +371,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
||||
ModTime: time.Unix(1360578951, 0),
|
||||
Typeflag: TypeChar,
|
||||
},
|
||||
fm: 0666 | os.ModeDevice | os.ModeCharDevice,
|
||||
fm: 0666 | fs.ModeDevice | fs.ModeCharDevice,
|
||||
}, {
|
||||
// block device node.
|
||||
h: &Header{
|
||||
@ -381,7 +381,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
||||
ModTime: time.Unix(1360578954, 0),
|
||||
Typeflag: TypeBlock,
|
||||
},
|
||||
fm: 0660 | os.ModeDevice,
|
||||
fm: 0660 | fs.ModeDevice,
|
||||
}, {
|
||||
// directory.
|
||||
h: &Header{
|
||||
@ -391,7 +391,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
||||
ModTime: time.Unix(1360601116, 0),
|
||||
Typeflag: TypeDir,
|
||||
},
|
||||
fm: 0755 | os.ModeDir,
|
||||
fm: 0755 | fs.ModeDir,
|
||||
}, {
|
||||
// fifo node.
|
||||
h: &Header{
|
||||
@ -401,7 +401,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
||||
ModTime: time.Unix(1360578949, 0),
|
||||
Typeflag: TypeFifo,
|
||||
},
|
||||
fm: 0600 | os.ModeNamedPipe,
|
||||
fm: 0600 | fs.ModeNamedPipe,
|
||||
}, {
|
||||
// setuid.
|
||||
h: &Header{
|
||||
@ -411,7 +411,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
||||
ModTime: time.Unix(1355405093, 0),
|
||||
Typeflag: TypeReg,
|
||||
},
|
||||
fm: 0755 | os.ModeSetuid,
|
||||
fm: 0755 | fs.ModeSetuid,
|
||||
}, {
|
||||
// setguid.
|
||||
h: &Header{
|
||||
@ -421,7 +421,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
||||
ModTime: time.Unix(1360602346, 0),
|
||||
Typeflag: TypeReg,
|
||||
},
|
||||
fm: 0750 | os.ModeSetgid,
|
||||
fm: 0750 | fs.ModeSetgid,
|
||||
}, {
|
||||
// sticky.
|
||||
h: &Header{
|
||||
@ -431,7 +431,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
||||
ModTime: time.Unix(1360602540, 0),
|
||||
Typeflag: TypeReg,
|
||||
},
|
||||
fm: 0600 | os.ModeSticky,
|
||||
fm: 0600 | fs.ModeSticky,
|
||||
}, {
|
||||
// hard link.
|
||||
h: &Header{
|
||||
@ -804,9 +804,9 @@ func Benchmark(b *testing.B) {
|
||||
b.Run(v.label, func(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
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.
|
||||
tw := NewWriter(ioutil.Discard)
|
||||
tw := NewWriter(io.Discard)
|
||||
for _, file := range v.files {
|
||||
if err := tw.WriteHeader(file.hdr); err != nil {
|
||||
b.Errorf("unexpected WriteHeader error: %v", err)
|
||||
@ -844,7 +844,7 @@ func Benchmark(b *testing.B) {
|
||||
if _, err := tr.Next(); err != nil {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
@ -520,7 +519,7 @@ func TestWriter(t *testing.T) {
|
||||
}
|
||||
|
||||
if v.file != "" {
|
||||
want, err := ioutil.ReadFile(v.file)
|
||||
want, err := os.ReadFile(v.file)
|
||||
if err != nil {
|
||||
t.Fatalf("ReadFile() = %v, want nil", err)
|
||||
}
|
||||
|
@ -11,7 +11,12 @@ import (
|
||||
"hash"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -21,18 +26,28 @@ var (
|
||||
ErrChecksum = errors.New("zip: checksum error")
|
||||
)
|
||||
|
||||
// A Reader serves content from a ZIP archive.
|
||||
type Reader struct {
|
||||
r io.ReaderAt
|
||||
File []*File
|
||||
Comment string
|
||||
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 {
|
||||
f *os.File
|
||||
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 {
|
||||
FileHeader
|
||||
zip *Reader
|
||||
@ -187,6 +202,10 @@ type checksumReader struct {
|
||||
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) {
|
||||
if r.err != nil {
|
||||
return 0, r.err
|
||||
@ -607,3 +626,173 @@ func (b *readBuf) sub(n int) readBuf {
|
||||
*b = (*b)[n:]
|
||||
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"
|
||||
"internal/obscuretestdata"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
"testing/fstest"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -30,7 +31,7 @@ type ZipTest struct {
|
||||
|
||||
type ZipTestFile struct {
|
||||
Name string
|
||||
Mode os.FileMode
|
||||
Mode fs.FileMode
|
||||
NonUTF8 bool
|
||||
ModTime time.Time
|
||||
Modified time.Time
|
||||
@ -107,7 +108,7 @@ var tests = []ZipTest{
|
||||
Name: "symlink",
|
||||
Content: []byte("../target"),
|
||||
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/",
|
||||
Content: []byte{},
|
||||
Modified: time.Date(2011, 12, 8, 10, 8, 6, 0, time.UTC),
|
||||
Mode: os.ModeDir | 0777,
|
||||
Mode: fs.ModeDir | 0777,
|
||||
},
|
||||
{
|
||||
Name: "readonly",
|
||||
@ -179,7 +180,7 @@ var tests = []ZipTest{
|
||||
Name: "dir/empty/",
|
||||
Content: []byte{},
|
||||
Modified: time.Date(2011, 12, 8, 10, 8, 6, 0, timeZone(0)),
|
||||
Mode: os.ModeDir | 0777,
|
||||
Mode: fs.ModeDir | 0777,
|
||||
},
|
||||
{
|
||||
Name: "readonly",
|
||||
@ -627,7 +628,7 @@ func readTestFile(t *testing.T, zt ZipTest, ft ZipTestFile, f *File) {
|
||||
var c []byte
|
||||
if ft.Content != nil {
|
||||
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)
|
||||
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()
|
||||
if want == 0 {
|
||||
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) {
|
||||
data, err := ioutil.ReadFile(filepath.Join("testdata", fileName))
|
||||
data, err := os.ReadFile(filepath.Join("testdata", fileName))
|
||||
if err != nil {
|
||||
panic("Error reading " + fileName + ": " + err.Error())
|
||||
}
|
||||
@ -790,17 +791,17 @@ func returnRecursiveZip() (r io.ReaderAt, size int64) {
|
||||
//
|
||||
// func main() {
|
||||
// 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)
|
||||
// }
|
||||
//
|
||||
// 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)
|
||||
// }
|
||||
//
|
||||
// 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)
|
||||
// }
|
||||
// }
|
||||
@ -928,7 +929,7 @@ func returnBigZipBytes() (r io.ReaderAt, size int64) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
b, err = ioutil.ReadAll(f)
|
||||
b, err = io.ReadAll(f)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -985,7 +986,7 @@ func TestIssue10957(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
if f.UncompressedSize64 < 1e6 {
|
||||
n, err := io.Copy(ioutil.Discard, r)
|
||||
n, err := io.Copy(io.Discard, r)
|
||||
if i == 3 && err != io.ErrUnexpectedEOF {
|
||||
t.Errorf("File[3] error = %v; want io.ErrUnexpectedEOF", err)
|
||||
}
|
||||
@ -1027,7 +1028,7 @@ func TestIssue11146(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = ioutil.ReadAll(r)
|
||||
_, err = io.ReadAll(r)
|
||||
if err != io.ErrUnexpectedEOF {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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"
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"sync"
|
||||
)
|
||||
|
||||
@ -111,7 +110,7 @@ func init() {
|
||||
compressors.Store(Store, Compressor(func(w io.Writer) (io.WriteCloser, error) { return &nopCloser{w}, nil }))
|
||||
compressors.Store(Deflate, Compressor(func(w io.Writer) (io.WriteCloser, error) { return newFlateWriter(w), nil }))
|
||||
|
||||
decompressors.Store(Store, Decompressor(ioutil.NopCloser))
|
||||
decompressors.Store(Store, Decompressor(io.NopCloser))
|
||||
decompressors.Store(Deflate, Decompressor(newFlateReader))
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ fields must be used instead.
|
||||
package zip
|
||||
|
||||
import (
|
||||
"os"
|
||||
"io/fs"
|
||||
"path"
|
||||
"time"
|
||||
)
|
||||
@ -137,12 +137,12 @@ type FileHeader struct {
|
||||
ExternalAttrs uint32 // Meaning depends on CreatorVersion
|
||||
}
|
||||
|
||||
// FileInfo returns an os.FileInfo for the FileHeader.
|
||||
func (h *FileHeader) FileInfo() os.FileInfo {
|
||||
// FileInfo returns an fs.FileInfo for the FileHeader.
|
||||
func (h *FileHeader) FileInfo() fs.FileInfo {
|
||||
return headerFileInfo{h}
|
||||
}
|
||||
|
||||
// headerFileInfo implements os.FileInfo.
|
||||
// headerFileInfo implements fs.FileInfo.
|
||||
type headerFileInfo struct {
|
||||
fh *FileHeader
|
||||
}
|
||||
@ -161,17 +161,20 @@ func (fi headerFileInfo) ModTime() time.Time {
|
||||
}
|
||||
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) Info() (fs.FileInfo, error) { return fi, nil }
|
||||
|
||||
// FileInfoHeader creates a partially-populated FileHeader from an
|
||||
// os.FileInfo.
|
||||
// Because os.FileInfo's Name method returns only the base name of
|
||||
// fs.FileInfo.
|
||||
// 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
|
||||
// of the returned header to provide the full path name of the file.
|
||||
// If compression is desired, callers should set the FileHeader.Method
|
||||
// field; it is unset by default.
|
||||
func FileInfoHeader(fi os.FileInfo) (*FileHeader, error) {
|
||||
func FileInfoHeader(fi fs.FileInfo) (*FileHeader, error) {
|
||||
size := fi.Size()
|
||||
fh := &FileHeader{
|
||||
Name: fi.Name(),
|
||||
@ -280,7 +283,7 @@ const (
|
||||
)
|
||||
|
||||
// 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 {
|
||||
case creatorUnix, creatorMacOSX:
|
||||
mode = unixModeToFileMode(h.ExternalAttrs >> 16)
|
||||
@ -288,18 +291,18 @@ func (h *FileHeader) Mode() (mode os.FileMode) {
|
||||
mode = msdosModeToFileMode(h.ExternalAttrs)
|
||||
}
|
||||
if len(h.Name) > 0 && h.Name[len(h.Name)-1] == '/' {
|
||||
mode |= os.ModeDir
|
||||
mode |= fs.ModeDir
|
||||
}
|
||||
return mode
|
||||
}
|
||||
|
||||
// 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.ExternalAttrs = fileModeToUnixMode(mode) << 16
|
||||
|
||||
// set MSDOS attributes too, as the original zip does.
|
||||
if mode&os.ModeDir != 0 {
|
||||
if mode&fs.ModeDir != 0 {
|
||||
h.ExternalAttrs |= msdosDir
|
||||
}
|
||||
if mode&0200 == 0 {
|
||||
@ -312,9 +315,9 @@ func (h *FileHeader) isZip64() bool {
|
||||
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 {
|
||||
mode = os.ModeDir | 0777
|
||||
mode = fs.ModeDir | 0777
|
||||
} else {
|
||||
mode = 0666
|
||||
}
|
||||
@ -324,64 +327,64 @@ func msdosModeToFileMode(m uint32) (mode os.FileMode) {
|
||||
return mode
|
||||
}
|
||||
|
||||
func fileModeToUnixMode(mode os.FileMode) uint32 {
|
||||
func fileModeToUnixMode(mode fs.FileMode) uint32 {
|
||||
var m uint32
|
||||
switch mode & os.ModeType {
|
||||
switch mode & fs.ModeType {
|
||||
default:
|
||||
m = s_IFREG
|
||||
case os.ModeDir:
|
||||
case fs.ModeDir:
|
||||
m = s_IFDIR
|
||||
case os.ModeSymlink:
|
||||
case fs.ModeSymlink:
|
||||
m = s_IFLNK
|
||||
case os.ModeNamedPipe:
|
||||
case fs.ModeNamedPipe:
|
||||
m = s_IFIFO
|
||||
case os.ModeSocket:
|
||||
case fs.ModeSocket:
|
||||
m = s_IFSOCK
|
||||
case os.ModeDevice:
|
||||
if mode&os.ModeCharDevice != 0 {
|
||||
case fs.ModeDevice:
|
||||
if mode&fs.ModeCharDevice != 0 {
|
||||
m = s_IFCHR
|
||||
} else {
|
||||
m = s_IFBLK
|
||||
}
|
||||
}
|
||||
if mode&os.ModeSetuid != 0 {
|
||||
if mode&fs.ModeSetuid != 0 {
|
||||
m |= s_ISUID
|
||||
}
|
||||
if mode&os.ModeSetgid != 0 {
|
||||
if mode&fs.ModeSetgid != 0 {
|
||||
m |= s_ISGID
|
||||
}
|
||||
if mode&os.ModeSticky != 0 {
|
||||
if mode&fs.ModeSticky != 0 {
|
||||
m |= s_ISVTX
|
||||
}
|
||||
return m | uint32(mode&0777)
|
||||
}
|
||||
|
||||
func unixModeToFileMode(m uint32) os.FileMode {
|
||||
mode := os.FileMode(m & 0777)
|
||||
func unixModeToFileMode(m uint32) fs.FileMode {
|
||||
mode := fs.FileMode(m & 0777)
|
||||
switch m & s_IFMT {
|
||||
case s_IFBLK:
|
||||
mode |= os.ModeDevice
|
||||
mode |= fs.ModeDevice
|
||||
case s_IFCHR:
|
||||
mode |= os.ModeDevice | os.ModeCharDevice
|
||||
mode |= fs.ModeDevice | fs.ModeCharDevice
|
||||
case s_IFDIR:
|
||||
mode |= os.ModeDir
|
||||
mode |= fs.ModeDir
|
||||
case s_IFIFO:
|
||||
mode |= os.ModeNamedPipe
|
||||
mode |= fs.ModeNamedPipe
|
||||
case s_IFLNK:
|
||||
mode |= os.ModeSymlink
|
||||
mode |= fs.ModeSymlink
|
||||
case s_IFREG:
|
||||
// nothing to do
|
||||
case s_IFSOCK:
|
||||
mode |= os.ModeSocket
|
||||
mode |= fs.ModeSocket
|
||||
}
|
||||
if m&s_ISGID != 0 {
|
||||
mode |= os.ModeSetgid
|
||||
mode |= fs.ModeSetgid
|
||||
}
|
||||
if m&s_ISUID != 0 {
|
||||
mode |= os.ModeSetuid
|
||||
mode |= fs.ModeSetuid
|
||||
}
|
||||
if m&s_ISVTX != 0 {
|
||||
mode |= os.ModeSticky
|
||||
mode |= fs.ModeSticky
|
||||
}
|
||||
return mode
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"io/fs"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strings"
|
||||
@ -23,7 +23,7 @@ type WriteTest struct {
|
||||
Name string
|
||||
Data []byte
|
||||
Method uint16
|
||||
Mode os.FileMode
|
||||
Mode fs.FileMode
|
||||
}
|
||||
|
||||
var writeTests = []WriteTest{
|
||||
@ -43,19 +43,19 @@ var writeTests = []WriteTest{
|
||||
Name: "setuid",
|
||||
Data: []byte("setuid file"),
|
||||
Method: Deflate,
|
||||
Mode: 0755 | os.ModeSetuid,
|
||||
Mode: 0755 | fs.ModeSetuid,
|
||||
},
|
||||
{
|
||||
Name: "setgid",
|
||||
Data: []byte("setgid file"),
|
||||
Method: Deflate,
|
||||
Mode: 0755 | os.ModeSetgid,
|
||||
Mode: 0755 | fs.ModeSetgid,
|
||||
},
|
||||
{
|
||||
Name: "symlink",
|
||||
Data: []byte("../link/target"),
|
||||
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)
|
||||
}
|
||||
|
||||
want, err := ioutil.ReadFile("testdata/time-go.zip")
|
||||
want, err := os.ReadFile("testdata/time-go.zip")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected ReadFile error: %v", err)
|
||||
}
|
||||
@ -301,7 +301,7 @@ func TestWriterFlush(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWriterDir(t *testing.T) {
|
||||
w := NewWriter(ioutil.Discard)
|
||||
w := NewWriter(io.Discard)
|
||||
dw, err := w.Create("dir/")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@ -380,7 +380,7 @@ func testReadFile(t *testing.T, f *File, wt *WriteTest) {
|
||||
if err != nil {
|
||||
t.Fatal("opening:", err)
|
||||
}
|
||||
b, err := ioutil.ReadAll(rc)
|
||||
b, err := io.ReadAll(rc)
|
||||
if err != nil {
|
||||
t.Fatal("reading:", err)
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ import (
|
||||
"hash"
|
||||
"internal/testenv"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
@ -620,7 +619,7 @@ func testZip64(t testing.TB, size int64) *rleBuffer {
|
||||
t.Fatal("read:", err)
|
||||
}
|
||||
}
|
||||
gotEnd, err := ioutil.ReadAll(rc)
|
||||
gotEnd, err := io.ReadAll(rc)
|
||||
if err != nil {
|
||||
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).
|
||||
// The complete result is equal to
|
||||
// `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.
|
||||
func (b *Reader) collectFragments(delim byte) (fullBuffers [][]byte, finalFragment []byte, totalLen int, err error) {
|
||||
var frag []byte
|
||||
|
@ -10,7 +10,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
"testing/iotest"
|
||||
@ -147,7 +146,7 @@ func TestReader(t *testing.T) {
|
||||
for i := 0; i < len(texts)-1; i++ {
|
||||
texts[i] = str + "\n"
|
||||
all += texts[i]
|
||||
str += string(rune(i)%26 + 'a')
|
||||
str += string(rune(i%26 + 'a'))
|
||||
}
|
||||
texts[len(texts)-1] = all
|
||||
|
||||
@ -886,7 +885,7 @@ func TestReadEmptyBuffer(t *testing.T) {
|
||||
|
||||
func TestLinesAfterRead(t *testing.T) {
|
||||
l := NewReaderSize(bytes.NewReader([]byte("foo")), minReadBufferSize)
|
||||
_, err := ioutil.ReadAll(l)
|
||||
_, err := io.ReadAll(l)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
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.
|
||||
type writeCountingDiscard int
|
||||
|
||||
@ -1300,7 +1299,7 @@ func TestReaderReset(t *testing.T) {
|
||||
t.Errorf("buf = %q; want foo", buf)
|
||||
}
|
||||
r.Reset(strings.NewReader("bar bar"))
|
||||
all, err := ioutil.ReadAll(r)
|
||||
all, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -1645,13 +1644,13 @@ func BenchmarkReaderWriteToOptimal(b *testing.B) {
|
||||
buf := make([]byte, bufSize)
|
||||
r := bytes.NewReader(buf)
|
||||
srcReader := NewReaderSize(onlyReader{r}, 1<<10)
|
||||
if _, ok := ioutil.Discard.(io.ReaderFrom); !ok {
|
||||
b.Fatal("ioutil.Discard doesn't support ReaderFrom")
|
||||
if _, ok := io.Discard.(io.ReaderFrom); !ok {
|
||||
b.Fatal("io.Discard doesn't support ReaderFrom")
|
||||
}
|
||||
for i := 0; i < b.N; i++ {
|
||||
r.Seek(0, io.SeekStart)
|
||||
srcReader.Reset(onlyReader{r})
|
||||
n, err := srcReader.WriteTo(ioutil.Discard)
|
||||
n, err := srcReader.WriteTo(io.Discard)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@ -1722,7 +1721,7 @@ func BenchmarkReaderEmpty(b *testing.B) {
|
||||
str := strings.Repeat("x", 16<<10)
|
||||
for i := 0; i < b.N; i++ {
|
||||
br := NewReader(strings.NewReader(str))
|
||||
n, err := io.Copy(ioutil.Discard, br)
|
||||
n, err := io.Copy(io.Discard, br)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@ -1737,7 +1736,7 @@ func BenchmarkWriterEmpty(b *testing.B) {
|
||||
str := strings.Repeat("x", 1<<10)
|
||||
bs := []byte(str)
|
||||
for i := 0; i < b.N; i++ {
|
||||
bw := NewWriter(ioutil.Discard)
|
||||
bw := NewWriter(io.Discard)
|
||||
bw.Flush()
|
||||
bw.WriteByte('a')
|
||||
bw.Flush()
|
||||
@ -1752,7 +1751,7 @@ func BenchmarkWriterEmpty(b *testing.B) {
|
||||
|
||||
func BenchmarkWriterFlush(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
bw := NewWriter(ioutil.Discard)
|
||||
bw := NewWriter(io.Discard)
|
||||
str := strings.Repeat("x", 50)
|
||||
for i := 0; i < b.N; i++ {
|
||||
bw.WriteString(str)
|
||||
|
@ -30,6 +30,13 @@ func ExampleBuffer_reader() {
|
||||
// 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() {
|
||||
var b bytes.Buffer
|
||||
b.Grow(64)
|
||||
|
@ -8,7 +8,6 @@ import (
|
||||
. "bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
@ -235,7 +234,7 @@ func TestReaderCopyNothing(t *testing.T) {
|
||||
type justWriter struct {
|
||||
io.Writer
|
||||
}
|
||||
discard := justWriter{ioutil.Discard} // hide ReadFrom
|
||||
discard := justWriter{io.Discard} // hide ReadFrom
|
||||
|
||||
var with, withOut nErr
|
||||
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.
|
||||
func TestReaderLenSize(t *testing.T) {
|
||||
r := NewReader([]byte("abc"))
|
||||
io.CopyN(ioutil.Discard, r, 1)
|
||||
io.CopyN(io.Discard, r, 1)
|
||||
if r.Len() != 2 {
|
||||
t.Errorf("Len = %d; want 2", r.Len())
|
||||
}
|
||||
@ -268,7 +267,7 @@ func TestReaderReset(t *testing.T) {
|
||||
if err := r.UnreadRune(); err == nil {
|
||||
t.Errorf("UnreadRune: expected error, got nil")
|
||||
}
|
||||
buf, err := ioutil.ReadAll(r)
|
||||
buf, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
t.Errorf("ReadAll: unexpected error: %v", err)
|
||||
}
|
||||
@ -314,7 +313,7 @@ func TestReaderZero(t *testing.T) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -22,21 +22,6 @@ func usage() {
|
||||
|
||||
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() {
|
||||
log.SetPrefix("buildid: ")
|
||||
log.SetFlags(0)
|
||||
@ -63,12 +48,12 @@ func main() {
|
||||
log.Fatal(err)
|
||||
}
|
||||
matches, hash, err := buildid.FindAndHash(f, id, 0)
|
||||
f.Close()
|
||||
if err != nil {
|
||||
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) {
|
||||
log.Fatalf("%s: build ID length mismatch %q vs %q", file, id, newID)
|
||||
}
|
||||
@ -77,7 +62,7 @@ func main() {
|
||||
return
|
||||
}
|
||||
|
||||
f, err = os.OpenFile(file, os.O_WRONLY, 0)
|
||||
f, err = os.OpenFile(file, os.O_RDWR, 0)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ import (
|
||||
"go/scanner"
|
||||
"go/token"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -44,14 +43,7 @@ func sourceLine(n ast.Node) int {
|
||||
// attached to the import "C" comment, a list of references to C.xxx,
|
||||
// a list of exported functions, and the actual AST, to be rewritten and
|
||||
// printed.
|
||||
func (f *File) ParseGo(name string, src []byte) {
|
||||
// Create absolute path for file, so that it will be used in error
|
||||
// messages and recorded in debug line number information.
|
||||
// This matches the rest of the toolchain. See golang.org/issue/5122.
|
||||
if aname, err := filepath.Abs(name); err == nil {
|
||||
name = aname
|
||||
}
|
||||
|
||||
func (f *File) ParseGo(abspath string, src []byte) {
|
||||
// Two different parses: once with comments, once without.
|
||||
// The printer is not good enough at printing comments in the
|
||||
// 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.
|
||||
// In cgo mode, we ignore ast2 and just apply edits directly
|
||||
// the text behind ast1. In godefs mode we modify and print ast2.
|
||||
ast1 := parse(name, src, parser.ParseComments)
|
||||
ast2 := parse(name, src, 0)
|
||||
ast1 := parse(abspath, src, parser.ParseComments)
|
||||
ast2 := parse(abspath, src, 0)
|
||||
|
||||
f.Package = ast1.Name.Name
|
||||
f.Name = make(map[string]*Name)
|
||||
@ -88,7 +80,7 @@ func (f *File) ParseGo(name string, src []byte) {
|
||||
cg = d.Doc
|
||||
}
|
||||
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 += "#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
|
||||
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
|
||||
it is expected to work. It is disabled by default when
|
||||
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:
|
||||
|
||||
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; }
|
||||
void _cgo_release_context(uintptr_t ctxt) { }
|
||||
char* _cgo_topofstack(void) { return (char*)0; }
|
||||
|
@ -316,7 +316,7 @@ func (p *Package) guessKinds(f *File) []*Name {
|
||||
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.
|
||||
s := n.C[:len(n.C)-3] + "GetTypeID"
|
||||
n := &Name{Go: s, C: s}
|
||||
@ -387,7 +387,18 @@ func (p *Package) guessKinds(f *File) []*Name {
|
||||
fmt.Fprintf(&b, "#line 1 \"completed\"\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 == "" {
|
||||
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
|
||||
// the errors that gcc prints. That is, this function expects
|
||||
// gcc to fail.
|
||||
func (p *Package) gccErrors(stdin []byte) string {
|
||||
func (p *Package) gccErrors(stdin []byte, extraArgs ...string) string {
|
||||
// TODO(rsc): require failure
|
||||
args := p.gccCmd()
|
||||
|
||||
// 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 {
|
||||
if !strings.HasPrefix(arg, "-O") {
|
||||
nargs = append(nargs, arg)
|
||||
}
|
||||
}
|
||||
|
||||
// Force -O0 optimization but keep the trailing "-" at the end.
|
||||
nargs = append(nargs, "-O0")
|
||||
nl := len(nargs)
|
||||
nargs[nl-2], nargs[nl-1] = nargs[nl-1], nargs[nl-2]
|
||||
// Force -O0 optimization and append extra arguments, but keep the
|
||||
// trailing "-" at the end.
|
||||
li := len(nargs) - 1
|
||||
last := nargs[li]
|
||||
nargs[li] = "-O0"
|
||||
nargs = append(nargs, extraArgs...)
|
||||
nargs = append(nargs, last)
|
||||
|
||||
if *debugGcc {
|
||||
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
|
||||
size := t.Size
|
||||
talign := t.Align
|
||||
if f.BitSize > 0 {
|
||||
switch f.BitSize {
|
||||
case 8, 16, 32, 64:
|
||||
default:
|
||||
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 f.BitOffset > 0 || f.BitSize > 0 {
|
||||
// The layout of bitfields is implementation defined,
|
||||
// so we don't know how they correspond to Go fields
|
||||
// even if they are aligned at byte boundaries.
|
||||
continue
|
||||
}
|
||||
|
||||
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
|
||||
// there exists a corresponding GetTypeID function.
|
||||
// See comment below for details about the bad pointers.
|
||||
if goos != "darwin" {
|
||||
if goos != "darwin" && goos != "ios" {
|
||||
return false
|
||||
}
|
||||
s := dt.Name
|
||||
|
@ -16,7 +16,7 @@ import (
|
||||
)
|
||||
|
||||
// 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
|
||||
|
||||
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 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 trimpath = flag.String("trimpath", "", "applies supplied rewrites or trims prefixes to recorded source file paths")
|
||||
|
||||
var goarch, goos string
|
||||
|
||||
func main() {
|
||||
@ -326,6 +328,13 @@ func main() {
|
||||
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)
|
||||
if err != nil {
|
||||
fatalf("%s", err)
|
||||
@ -334,6 +343,10 @@ func main() {
|
||||
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.Edit = edit.NewBuffer(b)
|
||||
f.ParseGo(input, b)
|
||||
@ -371,7 +384,7 @@ func main() {
|
||||
p.PackagePath = f.Package
|
||||
p.Record(f)
|
||||
if *godefs {
|
||||
os.Stdout.WriteString(p.godefs(f, input))
|
||||
os.Stdout.WriteString(p.godefs(f))
|
||||
} else {
|
||||
p.writeOutput(f, input)
|
||||
}
|
||||
|
@ -64,14 +64,14 @@ func (p *Package) writeDefs() {
|
||||
// Write C main file for using gcc to resolve imports.
|
||||
fmt.Fprintf(fm, "int main() { return 0; }\n")
|
||||
if *importRuntimeCgo {
|
||||
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, 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, "void _cgo_release_context(__SIZE_TYPE__ ctxt) { }\n")
|
||||
fmt.Fprintf(fm, "char* _cgo_topofstack(void) { return (char*)0; }\n")
|
||||
} else {
|
||||
// If we're not importing runtime/cgo, we *are* runtime/cgo,
|
||||
// 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, "void _cgo_release_context(__SIZE_TYPE__);\n")
|
||||
}
|
||||
@ -251,6 +251,7 @@ func (p *Package) writeDefs() {
|
||||
if err != nil {
|
||||
fatalf("%s", err)
|
||||
}
|
||||
defer fgcch.Close()
|
||||
_, err = io.Copy(fexp, fgcch)
|
||||
if err != nil {
|
||||
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 \"-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 void _cgo_release_context(__SIZE_TYPE__);\n\n")
|
||||
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 {
|
||||
fn := exp.Func
|
||||
|
||||
// Construct a gcc struct matching the gc argument and
|
||||
// result frame. The gcc struct will be compiled with
|
||||
// __attribute__((packed)) so all padding must be accounted
|
||||
// for explicitly.
|
||||
// Construct a struct that will be used to communicate
|
||||
// arguments from C to Go. The C and Go definitions
|
||||
// just have to agree. The gcc struct will be compiled
|
||||
// with __attribute__((packed)) so all padding must be
|
||||
// accounted for explicitly.
|
||||
ctype := "struct {\n"
|
||||
gotype := new(bytes.Buffer)
|
||||
fmt.Fprintf(gotype, "struct {\n")
|
||||
off := int64(0)
|
||||
npad := 0
|
||||
if fn.Recv != nil {
|
||||
t := p.cgoType(fn.Recv.List[0].Type)
|
||||
ctype += fmt.Sprintf("\t\t%s recv;\n", t.C)
|
||||
argField := func(typ ast.Expr, namePat string, args ...interface{}) {
|
||||
name := fmt.Sprintf(namePat, args...)
|
||||
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
|
||||
}
|
||||
if fn.Recv != nil {
|
||||
argField(fn.Recv.List[0].Type, "recv")
|
||||
}
|
||||
fntype := fn.Type
|
||||
forFieldList(fntype.Params,
|
||||
func(i int, aname string, atype ast.Expr) {
|
||||
t := p.cgoType(atype)
|
||||
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
|
||||
argField(atype, "p%d", i)
|
||||
})
|
||||
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,
|
||||
func(i int, aname string, atype ast.Expr) {
|
||||
t := p.cgoType(atype)
|
||||
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
|
||||
argField(atype, "r%d", i)
|
||||
})
|
||||
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" {
|
||||
ctype += "\t\tchar unused;\n" // avoid empty struct
|
||||
}
|
||||
ctype += "\t}"
|
||||
fmt.Fprintf(gotype, "\t}")
|
||||
|
||||
// Get the return type of the wrapper function
|
||||
// compiled by gcc.
|
||||
@ -966,7 +956,11 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
s += p.cgoType(fn.Recv.List[0].Type).C.String()
|
||||
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(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, "\n%s\n", s)
|
||||
fmt.Fprintf(fgcc, "{\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) {
|
||||
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")
|
||||
|
||||
// Build the wrapper function compiled by cmd/compile.
|
||||
goname := "_cgoexpwrap" + cPrefix + "_"
|
||||
if fn.Recv != nil {
|
||||
goname += fn.Recv.List[0].Names[0].Name + "_"
|
||||
}
|
||||
goname += exp.Func.Name.Name
|
||||
// This unpacks the argument struct above and calls the Go function.
|
||||
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: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, "//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(fgo2, "func _cgoexp%s_%s(a *%s) {\n", cPrefix, exp.ExpName, gotype)
|
||||
|
||||
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" {
|
||||
fmt.Fprint(fgo2, " (")
|
||||
// Write results back to frame.
|
||||
fmt.Fprintf(fgo2, "\t")
|
||||
forFieldList(fntype.Results,
|
||||
func(i int, aname string, atype ast.Expr) {
|
||||
if i > 0 {
|
||||
fmt.Fprint(fgo2, ", ")
|
||||
fmt.Fprintf(fgo2, ", ")
|
||||
}
|
||||
fmt.Fprintf(fgo2, "r%d ", i)
|
||||
printer.Fprint(fgo2, fset, atype)
|
||||
fmt.Fprintf(fgo2, "a.r%d", i)
|
||||
})
|
||||
fmt.Fprint(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 ")
|
||||
fmt.Fprintf(fgo2, " = ")
|
||||
}
|
||||
if fn.Recv != nil {
|
||||
fmt.Fprintf(fgo2, "recv.")
|
||||
fmt.Fprintf(fgo2, "a.recv.")
|
||||
}
|
||||
fmt.Fprintf(fgo2, "%s(", exp.Func.Name)
|
||||
forFieldList(fntype.Params,
|
||||
@ -1105,9 +1056,20 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||
if i > 0 {
|
||||
fmt.Fprint(fgo2, ", ")
|
||||
}
|
||||
fmt.Fprintf(fgo2, "p%d", i)
|
||||
fmt.Fprintf(fgo2, "a.p%d", i)
|
||||
})
|
||||
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")
|
||||
}
|
||||
|
||||
@ -1604,9 +1566,6 @@ const goProlog = `
|
||||
//go:linkname _cgo_runtime_cgocall runtime.cgocall
|
||||
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
|
||||
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
|
||||
// module-get module-aware go get
|
||||
// module-auth module authentication using go.sum
|
||||
// module-private module configuration for non-public modules
|
||||
// packages package lists and patterns
|
||||
// private configuration for downloading non-public code
|
||||
// testflag testing flags
|
||||
// testfunc testing functions
|
||||
// vcs controlling version control with GOVCS
|
||||
//
|
||||
// Use "go help <topic>" for more information about that topic.
|
||||
//
|
||||
@ -71,7 +72,7 @@
|
||||
//
|
||||
// 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,
|
||||
// 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
|
||||
// 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,
|
||||
// then any resulting executables will be written to that directory.
|
||||
// in the last two paragraphs. If the named output is an existing directory or
|
||||
// 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 is deprecated. Compiled packages are cached automatically.
|
||||
//
|
||||
// The build flags are shared by the build, clean, get, install, list, run,
|
||||
// and test commands:
|
||||
@ -161,6 +164,17 @@
|
||||
// directory, but it is not accessed. When -modfile is specified, an
|
||||
// alternate go.sum file is also used: its path is derived from the
|
||||
// -modfile flag by trimming the ".mod" extension and appending ".sum".
|
||||
// -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
|
||||
// install and load all packages from dir instead of the usual locations.
|
||||
// For example, when building with a non-standard configuration,
|
||||
@ -616,15 +630,15 @@
|
||||
// dependency should be removed entirely, downgrading or removing modules
|
||||
// depending on it as needed.
|
||||
//
|
||||
// The version suffix @latest explicitly requests the latest minor release of the
|
||||
// module named by the given path. The suffix @upgrade is like @latest but
|
||||
// The version suffix @latest explicitly requests the latest minor release of
|
||||
// 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
|
||||
// pre-release version newer than the latest released version. The suffix
|
||||
// @patch requests the latest patch release: the latest released version
|
||||
// with the same major and minor version numbers as the currently 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
|
||||
// are equivalent to @latest.
|
||||
// at a newer version. If the path is not already required, @upgrade is
|
||||
// equivalent to @latest, and @patch is disallowed.
|
||||
//
|
||||
// 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
|
||||
@ -661,14 +675,27 @@
|
||||
// this automatically as well.
|
||||
//
|
||||
// The -insecure flag permits fetching from repositories and resolving
|
||||
// custom domains using insecure schemes such as HTTP. Use with caution. The
|
||||
// GOINSECURE environment variable is usually a better alternative, since it
|
||||
// provides control over which modules may be retrieved using an insecure scheme.
|
||||
// See 'go help environment' for details.
|
||||
// custom domains using insecure schemes such as HTTP, and also bypassess
|
||||
// module sum validation using the checksum database. Use with caution.
|
||||
// This flag is deprecated and will be removed in a future version of go.
|
||||
// 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 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
|
||||
// Go source code in the module's root directory), then the install step
|
||||
// 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
|
||||
// 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
|
||||
// current directory, if any. In particular, 'go get -u' and
|
||||
// 'go get -u=patch' update all the dependencies of that package.
|
||||
@ -706,7 +729,7 @@
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// go install [-i] [build flags] [packages]
|
||||
// go install [build flags] [packages]
|
||||
//
|
||||
// Install compiles and installs the packages named by the import paths.
|
||||
//
|
||||
@ -715,11 +738,39 @@
|
||||
// environment variable is not set. Executables in $GOROOT
|
||||
// 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
|
||||
// directory $GOPATH/pkg/$GOOS_$GOARCH. When module-aware mode is enabled,
|
||||
// other packages are built and cached but not installed.
|
||||
//
|
||||
// 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 specifying packages, see 'go help packages'.
|
||||
@ -766,26 +817,28 @@
|
||||
// BinaryOnly bool // binary-only package (no longer supported)
|
||||
// ForTest string // package is only for use in named test
|
||||
// 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)
|
||||
// Match []string // command-line patterns matching this package
|
||||
// DepOnly bool // package is only a dependency, not explicitly listed
|
||||
//
|
||||
// // Source files
|
||||
// GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
|
||||
// CgoFiles []string // .go source files that import "C"
|
||||
// CompiledGoFiles []string // .go files presented to compiler (when using -compiled)
|
||||
// IgnoredGoFiles []string // .go source files ignored due to build constraints
|
||||
// CFiles []string // .c source files
|
||||
// CXXFiles []string // .cc, .cxx and .cpp source files
|
||||
// MFiles []string // .m source files
|
||||
// HFiles []string // .h, .hh, .hpp and .hxx source files
|
||||
// FFiles []string // .f, .F, .for and .f90 Fortran source files
|
||||
// SFiles []string // .s source files
|
||||
// SwigFiles []string // .swig files
|
||||
// SwigCXXFiles []string // .swigcxx files
|
||||
// SysoFiles []string // .syso object files to add to archive
|
||||
// TestGoFiles []string // _test.go files in package
|
||||
// XTestGoFiles []string // _test.go files outside package
|
||||
// GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
|
||||
// CgoFiles []string // .go source files that import "C"
|
||||
// CompiledGoFiles []string // .go files presented to compiler (when using -compiled)
|
||||
// IgnoredGoFiles []string // .go source files ignored due to build constraints
|
||||
// IgnoredOtherFiles []string // non-.go source files ignored due to build constraints
|
||||
// CFiles []string // .c source files
|
||||
// CXXFiles []string // .cc, .cxx and .cpp source files
|
||||
// MFiles []string // .m source files
|
||||
// HFiles []string // .h, .hh, .hpp and .hxx source files
|
||||
// FFiles []string // .f, .F, .for and .f90 Fortran source files
|
||||
// SFiles []string // .s source files
|
||||
// SwigFiles []string // .swig files
|
||||
// SwigCXXFiles []string // .swigcxx files
|
||||
// SysoFiles []string // .syso object files to add to archive
|
||||
// TestGoFiles []string // _test.go files in package
|
||||
// XTestGoFiles []string // _test.go files outside package
|
||||
//
|
||||
// // Cgo directives
|
||||
// CgoCFLAGS []string // cgo: flags for C compiler
|
||||
@ -916,6 +969,7 @@
|
||||
// Dir string // directory holding files for 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
|
||||
// Retracted string // retraction information, if any (with -retracted or -u)
|
||||
// Error *ModuleError // error loading module
|
||||
// }
|
||||
//
|
||||
@ -947,14 +1001,16 @@
|
||||
// The -u flag adds information about available upgrades.
|
||||
// When the latest version of a given module is newer than
|
||||
// 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
|
||||
// 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:
|
||||
//
|
||||
// my/main/module
|
||||
// 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.)
|
||||
//
|
||||
@ -964,6 +1020,14 @@
|
||||
// the default output format to display the module path followed by the
|
||||
// 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 main module is the module containing the current directory.
|
||||
// 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
|
||||
// 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,
|
||||
// and -dropreplace editing flags may be repeated, and the changes
|
||||
// are applied in the order given.
|
||||
// -dropreplace, -retract, and -dropretract editing flags may be repeated,
|
||||
// and the changes are applied in the order given.
|
||||
//
|
||||
// The -go=version flag sets the expected Go language version.
|
||||
//
|
||||
@ -1136,6 +1205,15 @@
|
||||
// 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
|
||||
// referred to indirectly. For the full set of modules available to a build,
|
||||
// use 'go list -m -json all'.
|
||||
@ -1163,19 +1241,24 @@
|
||||
//
|
||||
// go mod init [module]
|
||||
//
|
||||
// Init initializes and writes a new go.mod to the current directory,
|
||||
// in effect creating a new module rooted at the current directory.
|
||||
// The file go.mod must not already exist.
|
||||
// If possible, init will guess the module path from import comments
|
||||
// (see 'go help importpath') or from version control configuration.
|
||||
// To override this guess, supply the module path as an argument.
|
||||
// Init initializes and writes a new go.mod file in the current directory, in
|
||||
// effect creating a new module rooted at the current directory. The go.mod file
|
||||
// must not already exist.
|
||||
//
|
||||
// Init accepts one optional argument, the module path for the new module. If the
|
||||
// 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
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// go mod tidy [-v]
|
||||
// go mod tidy [-e] [-v]
|
||||
//
|
||||
// Tidy makes sure go.mod matches the source code in the module.
|
||||
// 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
|
||||
// to standard error.
|
||||
//
|
||||
// The -e flag causes tidy to attempt to proceed despite errors
|
||||
// encountered while loading packages.
|
||||
//
|
||||
//
|
||||
// Make vendored copy of dependencies
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// go mod vendor [-v]
|
||||
// go mod vendor [-e] [-v]
|
||||
//
|
||||
// Vendor resets the main module's vendor directory to include all 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
|
||||
// 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
|
||||
//
|
||||
@ -1388,6 +1477,7 @@
|
||||
// -i
|
||||
// Install packages that are dependencies of the test.
|
||||
// Do not run the test.
|
||||
// The -i flag is deprecated. Compiled packages are cached automatically.
|
||||
//
|
||||
// -json
|
||||
// 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
|
||||
// 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:
|
||||
//
|
||||
// // +build ignore
|
||||
@ -1733,7 +1826,7 @@
|
||||
// Comma-separated list of glob patterns (in the syntax of Go's path.Match)
|
||||
// of module path prefixes that should always be fetched directly
|
||||
// or that should not be compared against the checksum database.
|
||||
// See 'go help module-private'.
|
||||
// See 'go help private'.
|
||||
// GOROOT
|
||||
// The root of the go tree.
|
||||
// GOSUMDB
|
||||
@ -1789,8 +1882,8 @@
|
||||
// For GOARCH=arm, the ARM architecture for which to compile.
|
||||
// Valid values are 5, 6, 7.
|
||||
// GO386
|
||||
// For GOARCH=386, the floating point instruction set.
|
||||
// Valid values are 387, sse2.
|
||||
// For GOARCH=386, how to implement floating point instructions.
|
||||
// Valid values are sse2 (default), softfloat.
|
||||
// GOMIPS
|
||||
// For GOARCH=mips{,le}, whether to use floating point instructions.
|
||||
// Valid values are hardfloat (default), softfloat.
|
||||
@ -1839,6 +1932,8 @@
|
||||
// If module-aware mode is disabled, GOMOD will be the empty string.
|
||||
// GOTOOLDIR
|
||||
// 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
|
||||
@ -1894,21 +1989,23 @@
|
||||
// require new/thing/v2 v2.3.4
|
||||
// exclude old/thing v1.2.3
|
||||
// replace bad/thing v1.4.5 => good/thing v1.4.5
|
||||
// retract v1.5.6
|
||||
//
|
||||
// The verbs are
|
||||
// module, to define the module path;
|
||||
// go, to set the expected language version;
|
||||
// require, to require a particular module at a given version or later;
|
||||
// exclude, to exclude a particular module version from use; and
|
||||
// replace, to replace a module version with a different module version.
|
||||
// exclude, to exclude a particular module version from use;
|
||||
// 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
|
||||
// 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,
|
||||
// like in Go imports:
|
||||
//
|
||||
// require (
|
||||
// new/thing v2.3.4
|
||||
// new/thing/v2 v2.3.4
|
||||
// old/thing v1.2.3
|
||||
// )
|
||||
//
|
||||
@ -2146,6 +2243,10 @@
|
||||
//
|
||||
// The -insecure flag permits fetching from repositories and resolving
|
||||
// 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 tests for the specified packages.
|
||||
@ -2556,72 +2657,63 @@
|
||||
//
|
||||
// Maintaining module requirements
|
||||
//
|
||||
// The go.mod file is meant to be readable and editable by both
|
||||
// programmers and tools. The go command itself automatically updates the go.mod file
|
||||
// to maintain a standard formatting and the accuracy of require statements.
|
||||
// The go.mod file is meant to be readable and editable by both programmers and
|
||||
// tools. Most updates to dependencies can be performed using "go get" and
|
||||
// "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
|
||||
// containing that import and add the latest version of that module
|
||||
// to go.mod automatically. In most cases, therefore, it suffices to
|
||||
// add an import to source code and run 'go build', 'go test', or even 'go list':
|
||||
// as part of analyzing the package, the go command will discover
|
||||
// and resolve the import and update the go.mod file.
|
||||
// The "go get" command updates go.mod to change the module versions used in a
|
||||
// build. An upgrade of one module may imply upgrading others, and similarly a
|
||||
// downgrade of one module may imply downgrading others. The "go get" command
|
||||
// makes these implied changes as well. See "go help module-get".
|
||||
//
|
||||
// Any go command can determine that a module requirement is
|
||||
// missing and must be added, even when considering only a single
|
||||
// package from the module. On the other hand, determining that a module requirement
|
||||
// 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.
|
||||
// The "go mod" command provides other functionality for use in maintaining
|
||||
// and understanding modules and go.mod files. See "go help mod", particularly
|
||||
// "go help mod tidy" and "go help mod edit".
|
||||
//
|
||||
// As part of maintaining the require statements in go.mod, the go command
|
||||
// tracks which ones provide packages imported directly by the current module
|
||||
// and which ones provide packages only used indirectly by other module
|
||||
// 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
|
||||
// direct requirements. Indirect requirements only arise when using modules
|
||||
// that fail to state some of their own dependencies or when explicitly
|
||||
// upgrading a module's dependencies ahead of its own stated requirements.
|
||||
//
|
||||
// Because of this automatic maintenance, the information in go.mod is an
|
||||
// up-to-date, readable description of the build.
|
||||
// The -mod build flag provides additional control over the updating and use of
|
||||
// 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
|
||||
// build. An upgrade of one module may imply upgrading others, and similarly a
|
||||
// downgrade of one module may imply downgrading others. The 'go get' command
|
||||
// makes these implied changes as well. If go.mod is edited directly, commands
|
||||
// like 'go build' or 'go list' will assume that an upgrade is intended and
|
||||
// automatically make any implied upgrades and update go.mod to reflect them.
|
||||
// If invoked with -mod=readonly (the default in most situations), the go command
|
||||
// reports an error if a package named on the command line or an imported package
|
||||
// is not provided by any module in the build list computed from the main module's
|
||||
// requirements. The go command also reports an error if a module's checksum is
|
||||
// missing from go.sum (see Module downloading and verification). Either go.mod or
|
||||
// go.sum must be updated in these situations.
|
||||
//
|
||||
// The 'go mod' command provides other functionality for use in maintaining
|
||||
// and understanding modules and go.mod files. See 'go help mod'.
|
||||
//
|
||||
// The -mod build flag provides additional control over updating and use of go.mod.
|
||||
//
|
||||
// If invoked with -mod=readonly, the go command is disallowed from the implicit
|
||||
// automatic updating of go.mod described above. Instead, it fails when any changes
|
||||
// to go.mod are needed. This setting is most useful to check that go.mod does
|
||||
// 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=mod, the go command automatically updates go.mod and
|
||||
// go.sum, fixing inconsistencies and adding missing requirements and checksums
|
||||
// as needed. If the go command finds an unfamiliar import, it looks up the
|
||||
// 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
|
||||
// source code and run "go build", "go test", or even "go list" with -mod=mod:
|
||||
// as part of analyzing the package, the go command will resolve the import and
|
||||
// update the go.mod file.
|
||||
//
|
||||
// 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
|
||||
// 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
|
||||
// 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.
|
||||
//
|
||||
// If invoked with -mod=mod, the go command loads modules from the module cache
|
||||
// even if there is a vendor directory present.
|
||||
// If the go command is not invoked with a -mod flag, and the vendor directory
|
||||
// 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
|
||||
// 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.
|
||||
// Note that neither "go get" nor the "go mod" subcommands accept the -mod flag.
|
||||
//
|
||||
// Pseudo-versions
|
||||
//
|
||||
@ -2806,7 +2898,7 @@
|
||||
// followed by a pipe character, indicating it is safe to fall back on any error.
|
||||
//
|
||||
// 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
|
||||
// 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
|
||||
// downloads for all modules. A better way to bypass the checksum database
|
||||
// for specific modules is to use the GOPRIVATE or GONOSUMDB environment
|
||||
// variables. See 'go help module-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.
|
||||
// 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.
|
||||
@ -3061,6 +3108,56 @@
|
||||
// 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
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//
|
||||
// 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
|
||||
|
@ -9,13 +9,14 @@ import (
|
||||
"debug/elf"
|
||||
"debug/macho"
|
||||
"debug/pe"
|
||||
"encoding/binary"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/format"
|
||||
"internal/race"
|
||||
"internal/testenv"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"io/fs"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
@ -30,77 +31,42 @@ import (
|
||||
"cmd/go/internal/cache"
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/robustio"
|
||||
"cmd/go/internal/work"
|
||||
"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 (
|
||||
canRun = true // whether we can run go or ./testgo
|
||||
canRace = false // whether we can run the race detector
|
||||
canCgo = false // whether we can use cgo
|
||||
canMSan = false // whether we can run the memory sanitizer
|
||||
|
||||
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) {
|
||||
if testing.Short() {
|
||||
// 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") {
|
||||
return
|
||||
}
|
||||
t.Helper()
|
||||
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
|
||||
// build from this process's current GOROOT, but run from a different
|
||||
// (temp) directory.
|
||||
@ -134,7 +100,7 @@ func TestMain(m *testing.M) {
|
||||
|
||||
// Run with a temporary TMPDIR to check that the tests don't
|
||||
// leave anything behind.
|
||||
topTmpdir, err := ioutil.TempDir("", "cmd-go-test-")
|
||||
topTmpdir, err := os.MkdirTemp("", "cmd-go-test-")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@ -143,7 +109,7 @@ func TestMain(m *testing.M) {
|
||||
}
|
||||
os.Setenv(tempEnvName(), topTmpdir)
|
||||
|
||||
dir, err := ioutil.TempDir(topTmpdir, "tmpdir")
|
||||
dir, err := os.MkdirTemp(topTmpdir, "tmpdir")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@ -153,7 +119,7 @@ func TestMain(m *testing.M) {
|
||||
}
|
||||
|
||||
testGOCACHE = cache.DefaultDir()
|
||||
if canRun {
|
||||
if testenv.HasGoBuild() {
|
||||
testBin = filepath.Join(testTmpDir, "testbin")
|
||||
if err := os.Mkdir(testBin, 0777); err != nil {
|
||||
log.Fatal(err)
|
||||
@ -224,7 +190,7 @@ func TestMain(m *testing.M) {
|
||||
cmd.Stderr = new(strings.Builder)
|
||||
if out, err := cmd.Output(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "running testgo failed: %v\n%s", err, cmd.Stderr)
|
||||
canRun = false
|
||||
os.Exit(2)
|
||||
} else {
|
||||
canCgo, err = strconv.ParseBool(strings.TrimSpace(string(out)))
|
||||
if err != nil {
|
||||
@ -324,10 +290,7 @@ func skipIfGccgo(t *testing.T, msg string) {
|
||||
func testgo(t *testing.T) *testgoData {
|
||||
t.Helper()
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
if skipExternal {
|
||||
t.Skipf("skipping external tests on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
testenv.SkipIfShortAndSlow(t)
|
||||
|
||||
return &testgoData{t: t}
|
||||
}
|
||||
@ -416,9 +379,6 @@ func (tg *testgoData) goTool() string {
|
||||
// returning exit status.
|
||||
func (tg *testgoData) doRun(args []string) error {
|
||||
tg.t.Helper()
|
||||
if !canRun {
|
||||
panic("testgoData.doRun called but canRun false")
|
||||
}
|
||||
if tg.inParallel {
|
||||
for _, arg := range args {
|
||||
if strings.HasPrefix(arg, "testdata") || strings.HasPrefix(arg, "./testdata") {
|
||||
@ -656,7 +616,7 @@ func (tg *testgoData) makeTempdir() {
|
||||
tg.t.Helper()
|
||||
if tg.tempdir == "" {
|
||||
var err error
|
||||
tg.tempdir, err = ioutil.TempDir("", "gotest")
|
||||
tg.tempdir, err = os.MkdirTemp("", "gotest")
|
||||
tg.must(err)
|
||||
}
|
||||
}
|
||||
@ -673,7 +633,7 @@ func (tg *testgoData) tempFile(path, contents string) {
|
||||
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.
|
||||
@ -814,7 +774,7 @@ func (tg *testgoData) cleanup() {
|
||||
func removeAll(dir string) error {
|
||||
// module cache has 0444 directories;
|
||||
// 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
|
||||
// due to permission errors: they may also be unreadable directories.
|
||||
if err != nil || info.IsDir() {
|
||||
@ -860,8 +820,8 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
|
||||
} {
|
||||
srcdir := filepath.Join(testGOROOT, copydir)
|
||||
tg.tempDir(filepath.Join("goroot", copydir))
|
||||
err := filepath.Walk(srcdir,
|
||||
func(path string, info os.FileInfo, err error) error {
|
||||
err := filepath.WalkDir(srcdir,
|
||||
func(path string, info fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -873,13 +833,13 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
|
||||
return err
|
||||
}
|
||||
dest := filepath.Join("goroot", copydir, srcrel)
|
||||
data, err := ioutil.ReadFile(path)
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tg.tempFile(dest, string(data))
|
||||
if err := os.Chmod(tg.path(dest), info.Mode()|0200); err != nil {
|
||||
return err
|
||||
if strings.Contains(copydir, filepath.Join("pkg", "tool")) {
|
||||
os.Chmod(tg.path(dest), 0777)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@ -890,18 +850,18 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
|
||||
tg.setenv("GOROOT", tg.path("goroot"))
|
||||
|
||||
addVar := func(name string, idx int) (restore func()) {
|
||||
data, err := ioutil.ReadFile(name)
|
||||
data, err := os.ReadFile(name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
old := data
|
||||
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)
|
||||
}
|
||||
tg.sleep()
|
||||
return func() {
|
||||
if err := ioutil.WriteFile(name, old, 0666); err != nil {
|
||||
if err := os.WriteFile(name, old, 0666); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@ -1237,6 +1197,18 @@ func TestGoListExport(t *testing.T) {
|
||||
if _, err := os.Stat(file); err != nil {
|
||||
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.
|
||||
@ -1394,6 +1366,30 @@ func TestLdflagsArgumentsWithSpacesIssue3941(t *testing.T) {
|
||||
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) {
|
||||
skipIfGccgo(t, "gccgo has no standard packages")
|
||||
tooSlow(t)
|
||||
@ -1914,6 +1910,18 @@ func TestGoEnv(t *testing.T) {
|
||||
tg.grepStdout("gcc", "CC not found")
|
||||
tg.run("env", "GOGCCFLAGS")
|
||||
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 (
|
||||
@ -2019,7 +2027,7 @@ func main() {
|
||||
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)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -2058,7 +2066,7 @@ func TestBuildmodePIE(t *testing.T) {
|
||||
|
||||
platform := fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
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",
|
||||
"freebsd/amd64",
|
||||
"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 {
|
||||
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:
|
||||
panic("unreachable")
|
||||
}
|
||||
@ -2658,7 +2698,7 @@ echo $* >>`+tg.path("pkg-config.out"))
|
||||
tg.setenv("GOPATH", tg.path("."))
|
||||
tg.setenv("PKG_CONFIG", tg.path("pkg-config.sh"))
|
||||
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)
|
||||
out = bytes.TrimSpace(out)
|
||||
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
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
package main_test
|
||||
|
||||
import (
|
||||
"internal/testenv"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@ -17,16 +15,18 @@ import (
|
||||
)
|
||||
|
||||
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 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer robustio.RemoveAll(tmp)
|
||||
|
||||
file := filepath.Join(tmp, "a.go")
|
||||
err = ioutil.WriteFile(file, []byte{}, 0644)
|
||||
err = os.WriteFile(file, []byte{}, 0644)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -38,7 +38,7 @@ func TestAbsolutePath(t *testing.T) {
|
||||
|
||||
noVolume := file[len(filepath.VolumeName(file)):]
|
||||
wrongPath := filepath.Join(dir, noVolume)
|
||||
cmd := exec.Command(testenv.GoToolPath(t), "build", noVolume)
|
||||
cmd := exec.Command(tg.goTool(), "build", noVolume)
|
||||
cmd.Dir = dir
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err == nil {
|
||||
|
@ -6,7 +6,7 @@ package main_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"cmd/go/internal/help"
|
||||
@ -23,7 +23,7 @@ func TestDocsUpToDate(t *testing.T) {
|
||||
buf := new(bytes.Buffer)
|
||||
// Match the command in mkalldocs.sh that generates alldocs.go.
|
||||
help.Help(buf, []string{"documentation"})
|
||||
data, err := ioutil.ReadFile("alldocs.go")
|
||||
data, err := os.ReadFile("alldocs.go")
|
||||
if err != nil {
|
||||
t.Fatalf("error reading alldocs.go: %v", err)
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ package main_test
|
||||
import (
|
||||
"internal/testenv"
|
||||
"os/exec"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@ -15,20 +16,27 @@ import (
|
||||
// the benchmark if any changes were done.
|
||||
func BenchmarkExecGoEnv(b *testing.B) {
|
||||
testenv.MustHaveExec(b)
|
||||
b.StopTimer()
|
||||
gotool, err := testenv.GoTool()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
for i := 0; i < b.N; i++ {
|
||||
cmd := exec.Command(gotool, "env", "GOARCH")
|
||||
|
||||
b.StartTimer()
|
||||
err := cmd.Run()
|
||||
b.StopTimer()
|
||||
// We collect extra metrics.
|
||||
var n, userTime, systemTime int64
|
||||
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
b.ResetTimer()
|
||||
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
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
@ -99,7 +98,7 @@ func readNetrc() {
|
||||
return
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadFile(path)
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
netrcErr = err
|
||||
|
@ -7,6 +7,7 @@
|
||||
package base
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
@ -24,7 +25,7 @@ import (
|
||||
type Command struct {
|
||||
// Run runs the command.
|
||||
// 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.
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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,
|
||||
func (c *Command) LongName() string {
|
||||
name := c.UsageLine
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"flag"
|
||||
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/fsys"
|
||||
"cmd/go/internal/str"
|
||||
)
|
||||
|
||||
@ -28,13 +29,43 @@ func (v *StringsFlag) String() string {
|
||||
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.
|
||||
func AddBuildFlagsNX(flags *flag.FlagSet) {
|
||||
flags.BoolVar(&cfg.BuildN, "n", false, "")
|
||||
flags.BoolVar(&cfg.BuildX, "x", false, "")
|
||||
}
|
||||
|
||||
// AddLoadFlags adds the -mod build flag to the flag set.
|
||||
func AddLoadFlags(flags *flag.FlagSet) {
|
||||
flags.StringVar(&cfg.BuildMod, "mod", "", "")
|
||||
// AddModFlag adds the -mod build flag to the flag set.
|
||||
func AddModFlag(flags *flag.FlagSet) {
|
||||
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"
|
||||
)
|
||||
|
||||
var (
|
||||
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
|
||||
}
|
||||
var goflags []string // cached $GOFLAGS list; can be -x or --x form
|
||||
|
||||
// GOFLAGS returns the flags from $GOFLAGS.
|
||||
// The list can be assumed to contain one string per flag,
|
||||
@ -38,22 +30,12 @@ func InitGOFLAGS() {
|
||||
return
|
||||
}
|
||||
|
||||
// Build list of all flags for all commands.
|
||||
// If no command has that flag, then we report the problem.
|
||||
// This catches typos while still letting users record flags in GOFLAGS
|
||||
// that only apply to a subset of go commands.
|
||||
// Commands using CustomFlags can report their flag names
|
||||
// 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
|
||||
})
|
||||
goflags = strings.Fields(cfg.Getenv("GOFLAGS"))
|
||||
if len(goflags) == 0 {
|
||||
// nothing to do; avoid work on later InitGOFLAGS call
|
||||
goflags = []string{}
|
||||
return
|
||||
}
|
||||
walkFlags(Go)
|
||||
|
||||
// Ignore bad flag in go env and go bug, because
|
||||
// they are what people reach for when debugging
|
||||
@ -61,11 +43,6 @@ func InitGOFLAGS() {
|
||||
// (Both will show the GOFLAGS setting if let succeed.)
|
||||
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.
|
||||
// To set flag arguments use -x=value instead of -x value.
|
||||
// For boolean flags, -x is fine instead of -x=true.
|
||||
@ -85,7 +62,7 @@ func InitGOFLAGS() {
|
||||
if i := strings.Index(name, "="); i >= 0 {
|
||||
name = name[:i]
|
||||
}
|
||||
if !knownFlag[name] {
|
||||
if !hasFlag(Go, name) {
|
||||
if hideErrors {
|
||||
continue
|
||||
}
|
||||
@ -115,7 +92,11 @@ func SetFromGOFLAGS(flags *flag.FlagSet) {
|
||||
}
|
||||
for _, goflag := range goflags {
|
||||
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
|
||||
}
|
||||
if strings.HasPrefix(name, "--") {
|
||||
|
@ -15,7 +15,7 @@ var Interrupted = make(chan struct{})
|
||||
|
||||
// processSignals setups signal handler.
|
||||
func processSignals() {
|
||||
sig := make(chan os.Signal)
|
||||
sig := make(chan os.Signal, 1)
|
||||
signal.Notify(sig, signalsToIgnore...)
|
||||
go func() {
|
||||
<-sig
|
||||
|
@ -7,9 +7,9 @@ package bug
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
urlpkg "net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
@ -37,7 +37,7 @@ func init() {
|
||||
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 {
|
||||
base.Fatalf("go bug: bug takes no arguments")
|
||||
}
|
||||
@ -104,7 +104,7 @@ func printGoDetails(w io.Writer) {
|
||||
|
||||
func printOSDetails(w io.Writer) {
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
case "darwin", "ios":
|
||||
printCmdOut(w, "uname -v: ", "uname", "-v")
|
||||
printCmdOut(w, "", "sw_vers")
|
||||
case "linux":
|
||||
@ -116,7 +116,7 @@ func printOSDetails(w io.Writer) {
|
||||
case "illumos", "solaris":
|
||||
// Be sure to use the OS-supplied uname, in "/usr/bin":
|
||||
printCmdOut(w, "uname -srv: ", "/usr/bin/uname", "-srv")
|
||||
out, err := ioutil.ReadFile("/etc/release")
|
||||
out, err := os.ReadFile("/etc/release")
|
||||
if err == nil {
|
||||
fmt.Fprintf(w, "/etc/release: %s\n", out)
|
||||
} else {
|
||||
@ -176,7 +176,7 @@ func printGlibcVersion(w io.Writer) {
|
||||
src := []byte(`int main() {}`)
|
||||
srcfile := filepath.Join(tempdir, "go-bug.c")
|
||||
outfile := filepath.Join(tempdir, "go-bug")
|
||||
err := ioutil.WriteFile(srcfile, src, 0644)
|
||||
err := os.WriteFile(srcfile, src, 0644)
|
||||
if err != nil {
|
||||
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"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
@ -54,7 +54,7 @@ func Open(dir string) (*Cache, error) {
|
||||
return nil, err
|
||||
}
|
||||
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++ {
|
||||
name := filepath.Join(dir, fmt.Sprintf("%02x", i))
|
||||
@ -238,7 +238,7 @@ func (c *Cache) GetBytes(id ActionID) ([]byte, Entry, error) {
|
||||
if err != nil {
|
||||
return nil, entry, err
|
||||
}
|
||||
data, _ := ioutil.ReadFile(c.OutputFile(entry.OutputID))
|
||||
data, _ := os.ReadFile(c.OutputFile(entry.OutputID))
|
||||
if sha256.Sum256(data) != entry.OutputID {
|
||||
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.
|
||||
// (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
|
||||
// of the same content to the same file is idempotent, and does not — even
|
||||
// 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"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
@ -20,7 +19,7 @@ func init() {
|
||||
}
|
||||
|
||||
func TestBasic(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "cachetest-")
|
||||
dir, err := os.MkdirTemp("", "cachetest-")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -65,7 +64,7 @@ func TestBasic(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGrowth(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "cachetest-")
|
||||
dir, err := os.MkdirTemp("", "cachetest-")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -118,7 +117,7 @@ func TestVerifyPanic(t *testing.T) {
|
||||
t.Fatal("initEnv did not set verify")
|
||||
}
|
||||
|
||||
dir, err := ioutil.TempDir("", "cachetest-")
|
||||
dir, err := os.MkdirTemp("", "cachetest-")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -151,7 +150,7 @@ func dummyID(x int) [HashSize]byte {
|
||||
}
|
||||
|
||||
func TestCacheTrim(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "cachetest-")
|
||||
dir, err := os.MkdirTemp("", "cachetest-")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -207,7 +206,7 @@ func TestCacheTrim(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
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 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -220,7 +219,7 @@ func TestCacheTrim(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
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 {
|
||||
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 (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
@ -49,7 +48,7 @@ func initDefaultCache() {
|
||||
}
|
||||
if _, err := os.Stat(filepath.Join(dir, "README")); err != nil {
|
||||
// Best effort.
|
||||
ioutil.WriteFile(filepath.Join(dir, "README"), []byte(cacheREADME), 0666)
|
||||
os.WriteFile(filepath.Join(dir, "README"), []byte(cacheREADME), 0666)
|
||||
}
|
||||
|
||||
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 (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
@ -28,7 +27,7 @@ func TestHash(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 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -11,13 +11,15 @@ import (
|
||||
"fmt"
|
||||
"go/build"
|
||||
"internal/cfg"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"cmd/go/internal/fsys"
|
||||
|
||||
"cmd/internal/objabi"
|
||||
)
|
||||
|
||||
@ -27,7 +29,8 @@ var (
|
||||
BuildBuildmode string // -buildmode flag
|
||||
BuildContext = defaultContext()
|
||||
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
|
||||
BuildLinkshared bool // -linkshared flag
|
||||
BuildMSan bool // -msan flag
|
||||
@ -48,9 +51,12 @@ var (
|
||||
ModCacheRW bool // -modcacherw flag
|
||||
ModFile string // -modfile flag
|
||||
|
||||
Insecure bool // -insecure flag
|
||||
|
||||
CmdName string // "build", "install", "list", "mod tidy", etc.
|
||||
|
||||
DebugActiongraph string // -debug-actiongraph flag (undocumented, unstable)
|
||||
DebugTrace string // -debug-trace flag
|
||||
)
|
||||
|
||||
func defaultContext() build.Context {
|
||||
@ -100,6 +106,15 @@ func defaultContext() build.Context {
|
||||
// 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
|
||||
}
|
||||
|
||||
@ -171,7 +186,7 @@ func initEnvCache() {
|
||||
if file == "" {
|
||||
return
|
||||
}
|
||||
data, err := ioutil.ReadFile(file)
|
||||
data, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -252,6 +267,7 @@ var (
|
||||
GONOPROXY = envOr("GONOPROXY", GOPRIVATE)
|
||||
GONOSUMDB = envOr("GONOSUMDB", GOPRIVATE)
|
||||
GOINSECURE = Getenv("GOINSECURE")
|
||||
GOVCS = Getenv("GOVCS")
|
||||
)
|
||||
|
||||
var SumdbDir = gopathDir("pkg/sumdb")
|
||||
|
@ -6,8 +6,9 @@
|
||||
package clean
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
@ -105,7 +106,7 @@ func init() {
|
||||
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
|
||||
// either the flags and arguments explicitly imply a package,
|
||||
// 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 {
|
||||
for _, pkg := range load.PackagesAndErrors(args) {
|
||||
for _, pkg := range load.PackagesAndErrors(ctx, args) {
|
||||
clean(pkg)
|
||||
}
|
||||
}
|
||||
@ -171,7 +172,7 @@ func runClean(cmd *base.Command, args []string) {
|
||||
f, err := lockedfile.Edit(filepath.Join(dir, "testexpire.txt"))
|
||||
if err == nil {
|
||||
now := time.Now().UnixNano()
|
||||
buf, _ := ioutil.ReadAll(f)
|
||||
buf, _ := io.ReadAll(f)
|
||||
prev, _ := strconv.ParseInt(strings.TrimSpace(string(buf)), 10, 64)
|
||||
if now > prev {
|
||||
if err = f.Truncate(0); err == nil {
|
||||
@ -242,7 +243,7 @@ func clean(p *load.Package) {
|
||||
base.Errorf("%v", p.Error)
|
||||
return
|
||||
}
|
||||
dirs, err := ioutil.ReadDir(p.Dir)
|
||||
dirs, err := os.ReadDir(p.Dir)
|
||||
if err != nil {
|
||||
base.Errorf("go clean %s: %v", p.Dir, err)
|
||||
return
|
||||
@ -274,6 +275,8 @@ func clean(p *load.Package) {
|
||||
allRemove = append(allRemove,
|
||||
elem,
|
||||
elem+".exe",
|
||||
p.DefaultExecName(),
|
||||
p.DefaultExecName()+".exe",
|
||||
)
|
||||
}
|
||||
|
||||
@ -281,16 +284,28 @@ func clean(p *load.Package) {
|
||||
allRemove = append(allRemove,
|
||||
elem+".test",
|
||||
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.
|
||||
for _, dir := range dirs {
|
||||
name := dir.Name()
|
||||
if packageFile[name] {
|
||||
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
|
||||
// in "package main", and therefore capable of building
|
||||
// to an executable file.
|
||||
|
@ -8,6 +8,7 @@ package doc
|
||||
import (
|
||||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/cfg"
|
||||
"context"
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
|
@ -6,10 +6,10 @@
|
||||
package envcmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
@ -20,6 +20,7 @@ import (
|
||||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/cache"
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/fsys"
|
||||
"cmd/go/internal/load"
|
||||
"cmd/go/internal/modload"
|
||||
"cmd/go/internal/work"
|
||||
@ -62,9 +63,6 @@ var (
|
||||
)
|
||||
|
||||
func MkEnv() []cfg.EnvVar {
|
||||
var b work.Builder
|
||||
b.Init()
|
||||
|
||||
envFile, _ := cfg.EnvFile()
|
||||
env := []cfg.EnvVar{
|
||||
{Name: "GO111MODULE", Value: cfg.Getenv("GO111MODULE")},
|
||||
@ -88,6 +86,8 @@ func MkEnv() []cfg.EnvVar {
|
||||
{Name: "GOSUMDB", Value: cfg.GOSUMDB},
|
||||
{Name: "GOTMPDIR", Value: cfg.Getenv("GOTMPDIR")},
|
||||
{Name: "GOTOOLDIR", Value: base.ToolDir},
|
||||
{Name: "GOVCS", Value: cfg.GOVCS},
|
||||
{Name: "GOVERSION", Value: runtime.Version()},
|
||||
}
|
||||
|
||||
if work.GccgoBin != "" {
|
||||
@ -186,7 +186,7 @@ func argKey(arg string) string {
|
||||
return arg[:i]
|
||||
}
|
||||
|
||||
func runEnv(cmd *base.Command, args []string) {
|
||||
func runEnv(ctx context.Context, cmd *base.Command, args []string) {
|
||||
if *envJson && *envU {
|
||||
base.Fatalf("go env: cannot use -json with -u")
|
||||
}
|
||||
@ -199,12 +199,26 @@ func runEnv(cmd *base.Command, args []string) {
|
||||
env := cfg.CmdEnv
|
||||
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?
|
||||
// Only if we're listing all environment variables ("go env")
|
||||
// or the variables being requested are in the extra list.
|
||||
needCostly := true
|
||||
if len(args) > 0 {
|
||||
needCostly := false
|
||||
if *envU || *envW {
|
||||
// We're overwriting or removing default settings,
|
||||
// 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
|
||||
checkCostly:
|
||||
for _, arg := range args {
|
||||
switch argKey(arg) {
|
||||
case "CGO_CFLAGS",
|
||||
@ -215,6 +229,7 @@ func runEnv(cmd *base.Command, args []string) {
|
||||
"PKG_CONFIG",
|
||||
"GOGCCFLAGS":
|
||||
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)
|
||||
return
|
||||
}
|
||||
@ -377,7 +399,7 @@ func getOrigEnv(key string) string {
|
||||
|
||||
func checkEnvWrite(key, val string) error {
|
||||
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)
|
||||
case "GOENV":
|
||||
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 != "" {
|
||||
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) {
|
||||
@ -424,7 +451,7 @@ func updateEnvFile(add map[string]string, del map[string]bool) {
|
||||
if file == "" {
|
||||
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) {
|
||||
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, ""))
|
||||
err = ioutil.WriteFile(file, data, 0666)
|
||||
err = os.WriteFile(file, data, 0666)
|
||||
if err != nil {
|
||||
// Try creating directory.
|
||||
os.MkdirAll(filepath.Dir(file), 0777)
|
||||
err = ioutil.WriteFile(file, data, 0666)
|
||||
err = os.WriteFile(file, data, 0666)
|
||||
if err != nil {
|
||||
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.
|
||||
// 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) {
|
||||
sort.Slice(lines, func(i, j int) bool {
|
||||
return lineToKey(lines[i]) < lineToKey(lines[j])
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"cmd/go/internal/load"
|
||||
"cmd/go/internal/modload"
|
||||
"cmd/go/internal/str"
|
||||
"context"
|
||||
"fmt"
|
||||
"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
|
||||
for _, pkg := range load.Packages(args) {
|
||||
for _, pkg := range pkgs {
|
||||
if modload.Enabled() && pkg.Module != nil && !pkg.Module.Main {
|
||||
if !printed {
|
||||
fmt.Fprintf(os.Stderr, "go: not fixing packages in dependency modules\n")
|
||||
|
@ -6,6 +6,7 @@
|
||||
package fmtcmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
@ -22,7 +23,8 @@ import (
|
||||
|
||||
func init() {
|
||||
base.AddBuildFlagsNX(&CmdFmt.Flag)
|
||||
base.AddLoadFlags(&CmdFmt.Flag)
|
||||
base.AddModFlag(&CmdFmt.Flag)
|
||||
base.AddModCommonFlags(&CmdFmt.Flag)
|
||||
}
|
||||
|
||||
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
|
||||
gofmt := gofmtPath()
|
||||
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 !printed {
|
||||
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 (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
@ -160,7 +160,7 @@ func init() {
|
||||
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
|
||||
|
||||
if generateRunFlag != "" {
|
||||
@ -175,7 +175,7 @@ func runGenerate(cmd *base.Command, args []string) {
|
||||
|
||||
// Even if the arguments are .go files, this loop suffices.
|
||||
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 !printed {
|
||||
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.
|
||||
func generate(absFile string) bool {
|
||||
src, err := ioutil.ReadFile(absFile)
|
||||
src, err := os.ReadFile(absFile)
|
||||
if err != nil {
|
||||
log.Fatalf("generate: %s", err)
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
package get
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@ -17,8 +18,11 @@ import (
|
||||
"cmd/go/internal/load"
|
||||
"cmd/go/internal/search"
|
||||
"cmd/go/internal/str"
|
||||
"cmd/go/internal/vcs"
|
||||
"cmd/go/internal/web"
|
||||
"cmd/go/internal/work"
|
||||
|
||||
"golang.org/x/mod/module"
|
||||
)
|
||||
|
||||
var CmdGet = &base.Command{
|
||||
@ -41,6 +45,10 @@ before resolving dependencies or building the code.
|
||||
|
||||
The -insecure flag permits fetching from repositories and resolving
|
||||
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 tests for the specified packages.
|
||||
@ -102,17 +110,15 @@ var (
|
||||
getT = CmdGet.Flag.Bool("t", false, "")
|
||||
getU = CmdGet.Flag.Bool("u", false, "")
|
||||
getFix = CmdGet.Flag.Bool("fix", false, "")
|
||||
|
||||
Insecure bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
work.AddBuildFlags(CmdGet, work.OmitModFlag|work.OmitModCommonFlags)
|
||||
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 {
|
||||
// Should not happen: main.go should install the separate module-enabled get code.
|
||||
base.Fatalf("go get: modules not implemented")
|
||||
@ -123,6 +129,9 @@ func runGet(cmd *base.Command, args []string) {
|
||||
if *getF && !*getU {
|
||||
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.
|
||||
// Only has an effect for 2.3.0 or later, but avoiding
|
||||
@ -171,17 +180,18 @@ func runGet(cmd *base.Command, args []string) {
|
||||
// everything.
|
||||
load.ClearPackageCache()
|
||||
|
||||
pkgs := load.PackagesForBuild(args)
|
||||
pkgs := load.PackagesAndErrors(ctx, args)
|
||||
load.CheckPackageErrors(pkgs)
|
||||
|
||||
// Phase 3. Install.
|
||||
if *getD {
|
||||
// Download only.
|
||||
// Check delayed until now so that importPaths
|
||||
// and packagesForBuild have a chance to print errors.
|
||||
// Check delayed until now so that downloadPaths
|
||||
// and CheckPackageErrors have a chance to print errors.
|
||||
return
|
||||
}
|
||||
|
||||
work.InstallPackages(args, pkgs)
|
||||
work.InstallPackages(ctx, args, pkgs)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
if parent == nil {
|
||||
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)
|
||||
@ -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.
|
||||
func downloadPackage(p *load.Package) error {
|
||||
var (
|
||||
vcs *vcsCmd
|
||||
vcsCmd *vcs.Cmd
|
||||
repo, rootPath string
|
||||
err error
|
||||
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
|
||||
// actually a wildcard pattern.
|
||||
// Trim the path at the element containing the first wildcard,
|
||||
@ -426,22 +431,26 @@ func downloadPackage(p *load.Package) error {
|
||||
}
|
||||
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)
|
||||
}
|
||||
security := web.SecureOnly
|
||||
if cfg.Insecure || module.MatchPrefixPatterns(cfg.GOINSECURE, importPrefix) {
|
||||
security = web.Insecure
|
||||
}
|
||||
|
||||
if p.Internal.Build.SrcRoot != "" {
|
||||
// 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 {
|
||||
return err
|
||||
}
|
||||
repo = "<local>" // should be unused; make distinctive
|
||||
|
||||
// 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))
|
||||
remote, err := vcs.remoteRepo(vcs, dir)
|
||||
remote, err := vcsCmd.RemoteRepo(vcsCmd, dir)
|
||||
if err != nil {
|
||||
// Proceed anyway. The package is present; we likely just don't understand
|
||||
// the repo configuration (e.g. unusual remote protocol).
|
||||
@ -449,10 +458,10 @@ func downloadPackage(p *load.Package) error {
|
||||
}
|
||||
repo = remote
|
||||
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
|
||||
if rr.vcs.resolveRepo != nil {
|
||||
resolved, err := rr.vcs.resolveRepo(rr.vcs, dir, repo)
|
||||
if rr.VCS.ResolveRepo != nil {
|
||||
resolved, err := rr.VCS.ResolveRepo(rr.VCS, dir, repo)
|
||||
if err == nil {
|
||||
repo = resolved
|
||||
}
|
||||
@ -466,13 +475,13 @@ func downloadPackage(p *load.Package) error {
|
||||
} else {
|
||||
// Analyze the import path to determine the version control system,
|
||||
// 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 {
|
||||
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)
|
||||
}
|
||||
|
||||
@ -495,7 +504,7 @@ func downloadPackage(p *load.Package) error {
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
@ -511,7 +520,7 @@ func downloadPackage(p *load.Package) error {
|
||||
|
||||
// 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.
|
||||
meta := filepath.Join(root, "."+vcs.cmd)
|
||||
meta := filepath.Join(root, "."+vcsCmd.Cmd)
|
||||
if _, err := os.Stat(meta); err != nil {
|
||||
// Metadata file or directory does not exist. Prepare to checkout new copy.
|
||||
// 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)
|
||||
}
|
||||
|
||||
if err = vcs.create(root, repo); err != nil {
|
||||
if err = vcsCmd.Create(root, repo); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// Metadata directory does exist; download incremental updates.
|
||||
if err = vcs.download(root); err != nil {
|
||||
if err = vcsCmd.Download(root); err != nil {
|
||||
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,
|
||||
// and since we're not running commands, no tag will be found.
|
||||
// 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
|
||||
}
|
||||
|
||||
// Select and sync to appropriate version of the repository.
|
||||
tags, err := vcs.tags(root)
|
||||
tags, err := vcsCmd.Tags(root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -559,7 +568,7 @@ func downloadPackage(p *load.Package) error {
|
||||
if i := strings.Index(vers, " "); i >= 0 {
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
of module path prefixes that should always be fetched directly
|
||||
or that should not be compared against the checksum database.
|
||||
See 'go help module-private'.
|
||||
See 'go help private'.
|
||||
GOROOT
|
||||
The root of the go tree.
|
||||
GOSUMDB
|
||||
@ -582,8 +582,8 @@ Architecture-specific environment variables:
|
||||
For GOARCH=arm, the ARM architecture for which to compile.
|
||||
Valid values are 5, 6, 7.
|
||||
GO386
|
||||
For GOARCH=386, the floating point instruction set.
|
||||
Valid values are 387, sse2.
|
||||
For GOARCH=386, how to implement floating point instructions.
|
||||
Valid values are sse2 (default), softfloat.
|
||||
GOMIPS
|
||||
For GOARCH=mips{,le}, whether to use floating point instructions.
|
||||
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.
|
||||
GOTOOLDIR
|
||||
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
|
||||
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:
|
||||
|
||||
// +build ignore
|
||||
|
@ -141,6 +141,9 @@ func matchTag(name string, tags map[string]bool, want bool) bool {
|
||||
if name == "solaris" {
|
||||
have = have || tags["illumos"]
|
||||
}
|
||||
if name == "darwin" {
|
||||
have = have || tags["ios"]
|
||||
}
|
||||
return have == want
|
||||
}
|
||||
|
||||
@ -158,6 +161,7 @@ func matchTag(name string, tags map[string]bool, want bool) bool {
|
||||
// Exceptions:
|
||||
// if GOOS=android, then files with GOOS=linux 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
|
||||
// GOOS and GOARCH to be available and will consequently
|
||||
@ -208,6 +212,7 @@ var KnownOS = map[string]bool{
|
||||
"freebsd": true,
|
||||
"hurd": true,
|
||||
"illumos": true,
|
||||
"ios": true,
|
||||
"js": true,
|
||||
"linux": true,
|
||||
"nacl": true, // legacy; don't remove
|
||||
|
@ -198,7 +198,7 @@ func (r *importReader) readImport(imports *[]string) {
|
||||
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.
|
||||
func ReadComments(f io.Reader) ([]byte, error) {
|
||||
r := &importReader{b: bufio.NewReader(f)}
|
||||
@ -210,7 +210,7 @@ func ReadComments(f io.Reader) ([]byte, error) {
|
||||
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.
|
||||
func ReadImports(f io.Reader, reportSyntaxError bool, imports *[]string) ([]byte, error) {
|
||||
r := &importReader{b: bufio.NewReader(f)}
|
||||
|
@ -6,16 +6,17 @@ package imports
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"io/fs"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"cmd/go/internal/fsys"
|
||||
)
|
||||
|
||||
func ScanDir(dir string, tags map[string]bool) ([]string, []string, error) {
|
||||
infos, err := ioutil.ReadDir(dir)
|
||||
infos, err := fsys.ReadDir(dir)
|
||||
if err != nil {
|
||||
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
|
||||
// link target instead of the link itself.
|
||||
if info.Mode()&os.ModeSymlink != 0 {
|
||||
info, err = os.Stat(filepath.Join(dir, name))
|
||||
if info.Mode()&fs.ModeSymlink != 0 {
|
||||
info, err = fsys.Stat(filepath.Join(dir, name))
|
||||
if err != nil {
|
||||
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))
|
||||
}
|
||||
}
|
||||
@ -49,7 +50,7 @@ func scanFiles(files []string, tags map[string]bool, explicitFiles bool) ([]stri
|
||||
numFiles := 0
|
||||
Files:
|
||||
for _, name := range files {
|
||||
r, err := os.Open(name)
|
||||
r, err := fsys.Open(name)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ package imports
|
||||
import (
|
||||
"bytes"
|
||||
"internal/testenv"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
@ -57,7 +57,7 @@ func TestScan(t *testing.T) {
|
||||
func TestScanDir(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
dirs, err := ioutil.ReadDir("testdata")
|
||||
dirs, err := os.ReadDir("testdata")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -66,7 +66,7 @@ func TestScanDir(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
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 {
|
||||
t.Fatalf("error reading tags: %v", err)
|
||||
}
|
||||
@ -75,7 +75,7 @@ func TestScanDir(t *testing.T) {
|
||||
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 {
|
||||
t.Fatalf("error reading want: %v", err)
|
||||
}
|
||||
|
@ -4,17 +4,23 @@
|
||||
|
||||
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.
|
||||
// It includes GOOS, GOARCH, the compiler, possibly "cgo",
|
||||
// release tags like "go1.13", and user-specified build tags.
|
||||
func Tags() map[string]bool {
|
||||
if tags == nil {
|
||||
tagsOnce.Do(func() {
|
||||
tags = loadTags()
|
||||
}
|
||||
})
|
||||
return tags
|
||||
}
|
||||
|
||||
@ -36,14 +42,17 @@ func loadTags() map[string]bool {
|
||||
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
|
||||
// build tag expressions. Only "ignore" and malformed build tag requirements
|
||||
// are considered false.
|
||||
func AnyTags() map[string]bool {
|
||||
if anyTags == nil {
|
||||
anyTagsOnce.Do(func() {
|
||||
anyTags = map[string]bool{"*": true}
|
||||
}
|
||||
})
|
||||
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 (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sort"
|
||||
@ -19,6 +21,7 @@ import (
|
||||
"cmd/go/internal/cache"
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/load"
|
||||
"cmd/go/internal/modinfo"
|
||||
"cmd/go/internal/modload"
|
||||
"cmd/go/internal/str"
|
||||
"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)
|
||||
ForTest string // package is only for use in named test
|
||||
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)
|
||||
Match []string // command-line patterns matching this package
|
||||
DepOnly bool // package is only a dependency, not explicitly listed
|
||||
|
||||
// Source files
|
||||
GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
|
||||
CgoFiles []string // .go source files that import "C"
|
||||
CompiledGoFiles []string // .go files presented to compiler (when using -compiled)
|
||||
IgnoredGoFiles []string // .go source files ignored due to build constraints
|
||||
CFiles []string // .c source files
|
||||
CXXFiles []string // .cc, .cxx and .cpp source files
|
||||
MFiles []string // .m source files
|
||||
HFiles []string // .h, .hh, .hpp and .hxx source files
|
||||
FFiles []string // .f, .F, .for and .f90 Fortran source files
|
||||
SFiles []string // .s source files
|
||||
SwigFiles []string // .swig files
|
||||
SwigCXXFiles []string // .swigcxx files
|
||||
SysoFiles []string // .syso object files to add to archive
|
||||
TestGoFiles []string // _test.go files in package
|
||||
XTestGoFiles []string // _test.go files outside package
|
||||
GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
|
||||
CgoFiles []string // .go source files that import "C"
|
||||
CompiledGoFiles []string // .go files presented to compiler (when using -compiled)
|
||||
IgnoredGoFiles []string // .go source files ignored due to build constraints
|
||||
IgnoredOtherFiles []string // non-.go source files ignored due to build constraints
|
||||
CFiles []string // .c source files
|
||||
CXXFiles []string // .cc, .cxx and .cpp source files
|
||||
MFiles []string // .m source files
|
||||
HFiles []string // .h, .hh, .hpp and .hxx source files
|
||||
FFiles []string // .f, .F, .for and .f90 Fortran source files
|
||||
SFiles []string // .s source files
|
||||
SwigFiles []string // .swig files
|
||||
SwigCXXFiles []string // .swigcxx files
|
||||
SysoFiles []string // .syso object files to add to archive
|
||||
TestGoFiles []string // _test.go files in package
|
||||
XTestGoFiles []string // _test.go files outside package
|
||||
|
||||
// Cgo directives
|
||||
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
|
||||
GoMod string // path to go.mod file used when loading this module, if any
|
||||
GoVersion string // go version used in module
|
||||
Retracted string // retraction information, if any (with -retracted or -u)
|
||||
Error *ModuleError // error loading module
|
||||
}
|
||||
|
||||
@ -244,14 +250,16 @@ the replaced source code.)
|
||||
The -u flag adds information about available upgrades.
|
||||
When the latest version of a given module is newer than
|
||||
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
|
||||
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:
|
||||
|
||||
my/main/module
|
||||
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.)
|
||||
|
||||
@ -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
|
||||
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 main module is the module containing the current directory.
|
||||
The active modules are the main module and its dependencies.
|
||||
@ -294,23 +310,24 @@ func init() {
|
||||
}
|
||||
|
||||
var (
|
||||
listCompiled = CmdList.Flag.Bool("compiled", false, "")
|
||||
listDeps = CmdList.Flag.Bool("deps", false, "")
|
||||
listE = CmdList.Flag.Bool("e", false, "")
|
||||
listExport = CmdList.Flag.Bool("export", false, "")
|
||||
listFmt = CmdList.Flag.String("f", "", "")
|
||||
listFind = CmdList.Flag.Bool("find", false, "")
|
||||
listJson = CmdList.Flag.Bool("json", false, "")
|
||||
listM = CmdList.Flag.Bool("m", false, "")
|
||||
listU = CmdList.Flag.Bool("u", false, "")
|
||||
listTest = CmdList.Flag.Bool("test", false, "")
|
||||
listVersions = CmdList.Flag.Bool("versions", false, "")
|
||||
listCompiled = CmdList.Flag.Bool("compiled", false, "")
|
||||
listDeps = CmdList.Flag.Bool("deps", false, "")
|
||||
listE = CmdList.Flag.Bool("e", false, "")
|
||||
listExport = CmdList.Flag.Bool("export", false, "")
|
||||
listFmt = CmdList.Flag.String("f", "", "")
|
||||
listFind = CmdList.Flag.Bool("find", false, "")
|
||||
listJson = CmdList.Flag.Bool("json", false, "")
|
||||
listM = CmdList.Flag.Bool("m", false, "")
|
||||
listRetracted = CmdList.Flag.Bool("retracted", false, "")
|
||||
listTest = CmdList.Flag.Bool("test", false, "")
|
||||
listU = CmdList.Flag.Bool("u", false, "")
|
||||
listVersions = CmdList.Flag.Bool("versions", false, "")
|
||||
)
|
||||
|
||||
var nl = []byte{'\n'}
|
||||
|
||||
func runList(cmd *base.Command, args []string) {
|
||||
modload.LoadTests = *listTest
|
||||
func runList(ctx context.Context, cmd *base.Command, args []string) {
|
||||
load.ModResolveTests = *listTest
|
||||
work.BuildInit()
|
||||
out := newTrackingWriter(os.Stdout)
|
||||
defer out.w.Flush()
|
||||
@ -348,7 +365,7 @@ func runList(cmd *base.Command, args []string) {
|
||||
fm := template.FuncMap{
|
||||
"join": strings.Join,
|
||||
"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)
|
||||
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 {
|
||||
// Module mode.
|
||||
if *listCompiled {
|
||||
@ -388,7 +415,7 @@ func runList(cmd *base.Command, args []string) {
|
||||
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" {
|
||||
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(args, *listU, *listVersions)
|
||||
mods := modload.ListModules(ctx, args, *listU, *listVersions, *listRetracted)
|
||||
if !*listE {
|
||||
for _, m := range mods {
|
||||
if m.Error != nil {
|
||||
@ -446,11 +471,18 @@ func runList(cmd *base.Command, args []string) {
|
||||
}
|
||||
|
||||
load.IgnoreImports = *listFind
|
||||
var pkgs []*load.Package
|
||||
if *listE {
|
||||
pkgs = load.PackagesAndErrors(args)
|
||||
} else {
|
||||
pkgs = load.Packages(args)
|
||||
pkgs := load.PackagesAndErrors(ctx, args)
|
||||
if !*listE {
|
||||
w := 0
|
||||
for _, pkg := range pkgs {
|
||||
if pkg.Error != nil {
|
||||
base.Errorf("%v", pkg.Error)
|
||||
continue
|
||||
}
|
||||
pkgs[w] = pkg
|
||||
w++
|
||||
}
|
||||
pkgs = pkgs[:w]
|
||||
base.ExitIfErrors()
|
||||
}
|
||||
|
||||
@ -476,9 +508,9 @@ func runList(cmd *base.Command, args []string) {
|
||||
var pmain, ptest, pxtest *load.Package
|
||||
var err error
|
||||
if *listE {
|
||||
pmain, ptest, pxtest = load.TestPackagesAndErrors(p, nil)
|
||||
pmain, ptest, pxtest = load.TestPackagesAndErrors(ctx, p, nil)
|
||||
} else {
|
||||
pmain, ptest, pxtest, err = load.TestPackagesFor(p, nil)
|
||||
pmain, ptest, pxtest, err = load.TestPackagesFor(ctx, p, nil)
|
||||
if err != nil {
|
||||
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,
|
||||
// so that you only get descriptions of tests for the things named
|
||||
// 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?
|
||||
@ -538,13 +570,15 @@ func runList(cmd *base.Command, args []string) {
|
||||
a.Deps = append(a.Deps, b.AutoAction(work.ModeInstall, work.ModeInstall, p))
|
||||
}
|
||||
}
|
||||
b.Do(a)
|
||||
b.Do(ctx, a)
|
||||
}
|
||||
|
||||
for _, p := range pkgs {
|
||||
// Show vendor-expanded paths in listing
|
||||
p.TestImports = p.Resolve(p.TestImports)
|
||||
p.XTestImports = p.Resolve(p.XTestImports)
|
||||
p.TestEmbedFiles = p.ResolveEmbed(p.TestEmbedPatterns)
|
||||
p.XTestEmbedFiles = p.ResolveEmbed(p.XTestEmbedPatterns)
|
||||
p.DepOnly = !cmdline[p]
|
||||
|
||||
if *listCompiled {
|
||||
@ -555,7 +589,7 @@ func runList(cmd *base.Command, args []string) {
|
||||
if *listTest {
|
||||
all := pkgs
|
||||
if !*listDeps {
|
||||
all = load.PackageList(pkgs)
|
||||
all = loadPackageList(pkgs)
|
||||
}
|
||||
// Update import paths to distinguish the real package p
|
||||
// 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.
|
||||
for _, p := range pkgs {
|
||||
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
|
||||
// we can avoid printing a newline if one was already written or
|
||||
// if there is no output at all.
|
||||
|
@ -7,14 +7,16 @@ package load
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"go/scanner"
|
||||
"go/token"
|
||||
"io/ioutil"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path"
|
||||
pathpkg "path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
@ -26,25 +28,14 @@ import (
|
||||
|
||||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/fsys"
|
||||
"cmd/go/internal/modinfo"
|
||||
"cmd/go/internal/modload"
|
||||
"cmd/go/internal/par"
|
||||
"cmd/go/internal/search"
|
||||
"cmd/go/internal/str"
|
||||
)
|
||||
|
||||
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
|
||||
"cmd/go/internal/trace"
|
||||
"cmd/internal/sys"
|
||||
)
|
||||
|
||||
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
|
||||
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)
|
||||
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
|
||||
Match []string `json:",omitempty"` // command-line patterns matching this package
|
||||
Goroot bool `json:",omitempty"` // is this package found in the Go root?
|
||||
@ -87,19 +79,24 @@ type PackagePublic struct {
|
||||
// Source files
|
||||
// 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.
|
||||
GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
|
||||
CgoFiles []string `json:",omitempty"` // .go source files that import "C"
|
||||
CompiledGoFiles []string `json:",omitempty"` // .go output from running cgo on CgoFiles
|
||||
IgnoredGoFiles []string `json:",omitempty"` // .go source files ignored due to build constraints
|
||||
CFiles []string `json:",omitempty"` // .c source files
|
||||
CXXFiles []string `json:",omitempty"` // .cc, .cpp and .cxx source files
|
||||
MFiles []string `json:",omitempty"` // .m source files
|
||||
HFiles []string `json:",omitempty"` // .h, .hh, .hpp and .hxx source files
|
||||
FFiles []string `json:",omitempty"` // .f, .F, .for and .f90 Fortran source files
|
||||
SFiles []string `json:",omitempty"` // .s source files
|
||||
SwigFiles []string `json:",omitempty"` // .swig files
|
||||
SwigCXXFiles []string `json:",omitempty"` // .swigcxx files
|
||||
SysoFiles []string `json:",omitempty"` // .syso system object files added to package
|
||||
GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
|
||||
CgoFiles []string `json:",omitempty"` // .go source files that import "C"
|
||||
CompiledGoFiles []string `json:",omitempty"` // .go output from running cgo on CgoFiles
|
||||
IgnoredGoFiles []string `json:",omitempty"` // .go source files ignored due to build constraints
|
||||
IgnoredOtherFiles []string `json:",omitempty"` // non-.go source files ignored due to build constraints
|
||||
CFiles []string `json:",omitempty"` // .c source files
|
||||
CXXFiles []string `json:",omitempty"` // .cc, .cpp and .cxx source files
|
||||
MFiles []string `json:",omitempty"` // .m source files
|
||||
HFiles []string `json:",omitempty"` // .h, .hh, .hpp and .hxx source files
|
||||
FFiles []string `json:",omitempty"` // .f, .F, .for and .f90 Fortran source files
|
||||
SFiles []string `json:",omitempty"` // .s source files
|
||||
SwigFiles []string `json:",omitempty"` // .swig files
|
||||
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
|
||||
CgoCFLAGS []string `json:",omitempty"` // cgo: flags for C compiler
|
||||
@ -122,10 +119,14 @@ type PackagePublic struct {
|
||||
// Test information
|
||||
// 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.
|
||||
TestGoFiles []string `json:",omitempty"` // _test.go files in package
|
||||
TestImports []string `json:",omitempty"` // imports from TestGoFiles
|
||||
XTestGoFiles []string `json:",omitempty"` // _test.go files outside package
|
||||
XTestImports []string `json:",omitempty"` // imports from XTestGoFiles
|
||||
TestGoFiles []string `json:",omitempty"` // _test.go files in package
|
||||
TestImports []string `json:",omitempty"` // imports from TestGoFiles
|
||||
TestEmbedPatterns []string `json:",omitempty"` // //go:embed patterns
|
||||
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.
|
||||
@ -134,11 +135,12 @@ type PackagePublic struct {
|
||||
// The go/build package filtered others out (like foo_wrongGOARCH.s)
|
||||
// and that's OK.
|
||||
func (p *Package) AllFiles() []string {
|
||||
return str.StringList(
|
||||
files := str.StringList(
|
||||
p.GoFiles,
|
||||
p.CgoFiles,
|
||||
// no p.CompiledGoFiles, because they are from GoFiles or generated by us
|
||||
p.IgnoredGoFiles,
|
||||
p.IgnoredOtherFiles,
|
||||
p.CFiles,
|
||||
p.CXXFiles,
|
||||
p.MFiles,
|
||||
@ -151,6 +153,27 @@ func (p *Package) AllFiles() []string {
|
||||
p.TestGoFiles,
|
||||
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.
|
||||
@ -180,6 +203,7 @@ type PackageInternal struct {
|
||||
GobinSubdir bool // install target would be subdir of GOBIN
|
||||
BuildInfo string // add this info to package main
|
||||
TestmainGo *[]byte // content for _testmain.go
|
||||
Embed map[string][]string // //go:embed comment mapping
|
||||
|
||||
Asmflags []string // -asmflags for this package
|
||||
Gcflags []string // -gcflags for this package
|
||||
@ -197,7 +221,7 @@ type NoGoError struct {
|
||||
}
|
||||
|
||||
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.
|
||||
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).
|
||||
//
|
||||
// TODO(matloob): Perhaps make each of those the errors in the first group
|
||||
// (including modload.ImportMissingError, and the corresponding
|
||||
// "cannot find package %q in any of" GOPATH-mode error
|
||||
// (including modload.ImportMissingError, ImportMissingSumError, and the
|
||||
// corresponding "cannot find package %q in any of" GOPATH-mode error
|
||||
// produced in build.(*Context).Import; modload.AmbiguousImportError,
|
||||
// and modload.PackageNotInModuleError; and the malformed module path errors
|
||||
// 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.CgoFiles = pp.CgoFiles
|
||||
p.IgnoredGoFiles = pp.IgnoredGoFiles
|
||||
p.IgnoredOtherFiles = pp.IgnoredOtherFiles
|
||||
p.CFiles = pp.CFiles
|
||||
p.CXXFiles = pp.CXXFiles
|
||||
p.MFiles = pp.MFiles
|
||||
@ -371,6 +396,9 @@ func (p *Package) copyBuild(pp *build.Package) {
|
||||
p.TestImports = 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.
|
||||
@ -432,13 +460,17 @@ type ImportPathError interface {
|
||||
ImportPath() string
|
||||
}
|
||||
|
||||
var (
|
||||
_ ImportPathError = (*importError)(nil)
|
||||
_ ImportPathError = (*modload.ImportMissingError)(nil)
|
||||
_ ImportPathError = (*modload.ImportMissingSumError)(nil)
|
||||
)
|
||||
|
||||
type importError struct {
|
||||
importPath string
|
||||
err error // created with fmt.Errorf
|
||||
}
|
||||
|
||||
var _ ImportPathError = (*importError)(nil)
|
||||
|
||||
func ImportErrorf(path, format string, args ...interface{}) ImportPathError {
|
||||
err := &importError{importPath: path, err: fmt.Errorf(format, args...)}
|
||||
if errStr := err.Error(); !strings.Contains(errStr, path) {
|
||||
@ -551,7 +583,7 @@ func ReloadPackageNoFlags(arg string, stk *ImportStack) *Package {
|
||||
})
|
||||
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
|
||||
@ -603,11 +635,11 @@ const (
|
||||
// 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".
|
||||
// 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 {
|
||||
return loadImport(nil, path, srcDir, parent, stk, importPos, mode)
|
||||
func LoadImport(ctx context.Context, path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) *Package {
|
||||
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 == "" {
|
||||
panic("LoadImport called with empty package path")
|
||||
}
|
||||
@ -655,7 +687,7 @@ func loadImport(pre *preload, path, srcDir string, parent *Package, stk *ImportS
|
||||
// Load package.
|
||||
// loadPackageData may return bp != nil even if an error occurs,
|
||||
// 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) {
|
||||
p.Error = &PackageError{
|
||||
@ -751,7 +783,7 @@ func loadPackageData(path, parentPath, parentDir, parentRoot string, parentIsStd
|
||||
// For vendored imports, it is the expanded form.
|
||||
//
|
||||
// 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
|
||||
// so that 'go list -e' reports something useful.
|
||||
importKey := importSpec{
|
||||
@ -768,7 +800,7 @@ func loadPackageData(path, parentPath, parentDir, parentRoot string, parentIsStd
|
||||
r.dir = filepath.Join(parentDir, path)
|
||||
r.path = dirToImportPath(r.dir)
|
||||
} 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 {
|
||||
// We do our own path resolution, because we want to
|
||||
// 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)
|
||||
if data.p.Root == "" && cfg.ModulesEnabled {
|
||||
if info := ModPackageModuleInfo(path); info != nil {
|
||||
if info := modload.PackageModuleInfo(path); info != nil {
|
||||
data.p.Root = info.Dir
|
||||
}
|
||||
}
|
||||
@ -825,7 +857,7 @@ func loadPackageData(path, parentPath, parentDir, parentRoot string, parentIsStd
|
||||
if cfg.GOBIN != "" {
|
||||
data.p.BinDir = cfg.GOBIN
|
||||
} 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
|
||||
// because of global mutable state that cannot safely be read and written
|
||||
// concurrently. In particular, packageDataCache may be cleared by "go get"
|
||||
// in GOPATH mode, and modload.loaded (accessed via ModLookup) may be
|
||||
// modified by modload.ImportPaths (ModImportPaths).
|
||||
// in GOPATH mode, and modload.loaded (accessed via modload.Lookup) may be
|
||||
// modified by modload.LoadPackages.
|
||||
type preload struct {
|
||||
cancel 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
|
||||
// to loadPackageData.
|
||||
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)
|
||||
for i := 0; i < preloadWorkerCount; i++ {
|
||||
pre.sema <- struct{}{}
|
||||
@ -980,7 +1018,7 @@ var isDirCache par.Cache
|
||||
|
||||
func isDir(path string) bool {
|
||||
return isDirCache.Do(path, func() interface{} {
|
||||
fi, err := os.Stat(path)
|
||||
fi, err := fsys.Stat(path)
|
||||
return err == nil && fi.IsDir()
|
||||
}).(bool)
|
||||
}
|
||||
@ -1004,7 +1042,7 @@ func ResolveImportPath(parent *Package, path string) (found string) {
|
||||
|
||||
func resolveImportPath(path, parentPath, parentDir, parentRoot string, parentIsStd bool) (found string) {
|
||||
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 path
|
||||
@ -1108,7 +1146,7 @@ var (
|
||||
// goModPath returns the module path in the go.mod in dir, if any.
|
||||
func goModPath(dir string) (path string) {
|
||||
return goModPathCache.Do(dir, func() interface{} {
|
||||
data, err := ioutil.ReadFile(filepath.Join(dir, "go.mod"))
|
||||
data, err := os.ReadFile(filepath.Join(dir, "go.mod"))
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
@ -1257,9 +1295,9 @@ HaveGoMod:
|
||||
// Otherwise it is not possible to vendor just a/b/c and still import the
|
||||
// non-vendored a/b. See golang.org/issue/13832.
|
||||
func hasGoFiles(dir string) bool {
|
||||
fis, _ := ioutil.ReadDir(dir)
|
||||
for _, fi := range fis {
|
||||
if !fi.IsDir() && strings.HasSuffix(fi.Name(), ".go") {
|
||||
files, _ := os.ReadDir(dir)
|
||||
for _, f := range files {
|
||||
if !f.IsDir() && strings.HasSuffix(f.Name(), ".go") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -1373,7 +1411,7 @@ func disallowInternal(srcDir string, importer *Package, importerPath string, p *
|
||||
// directory containing them.
|
||||
// If the directory is outside the main module, this will resolve to ".",
|
||||
// which is not a prefix of any valid module.
|
||||
importerPath = ModDirImportPath(importer.Dir)
|
||||
importerPath = modload.DirImportPath(importer.Dir)
|
||||
}
|
||||
parentOfInternal := p.ImportPath[:i]
|
||||
if str.HasPathPrefix(importerPath, parentOfInternal) {
|
||||
@ -1595,7 +1633,7 @@ func (p *Package) DefaultExecName() string {
|
||||
// load populates p using information from bp, err, which should
|
||||
// be the result of calling build.Context.Import.
|
||||
// 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)
|
||||
|
||||
// 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.EmbedFiles, p.Internal.Embed, err = p.resolveEmbed(p.EmbedPatterns)
|
||||
if err != nil {
|
||||
setError(err)
|
||||
}
|
||||
|
||||
useBindir := p.Name == "main"
|
||||
if !p.Standard {
|
||||
switch cfg.BuildBuildmode {
|
||||
@ -1656,7 +1699,7 @@ func (p *Package) load(path string, stk *ImportStack, importPos []token.Position
|
||||
elem = full
|
||||
}
|
||||
if p.Internal.Build.BinDir == "" && cfg.ModulesEnabled {
|
||||
p.Internal.Build.BinDir = ModBinDir()
|
||||
p.Internal.Build.BinDir = modload.BinDir()
|
||||
}
|
||||
if p.Internal.Build.BinDir != "" {
|
||||
// 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
|
||||
// package in module mode. We should probably fix that.
|
||||
shlibnamefile := p.Target[:len(p.Target)-2] + ".shlibname"
|
||||
shlib, err := ioutil.ReadFile(shlibnamefile)
|
||||
shlib, err := os.ReadFile(shlibnamefile)
|
||||
if err != nil && !os.IsNotExist(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" {
|
||||
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
|
||||
importPaths[i] = path
|
||||
@ -1865,13 +1908,169 @@ func (p *Package) load(path string, stk *ImportStack, importPos []token.Position
|
||||
if p.Internal.CmdlineFiles {
|
||||
mainPath = "command-line-arguments"
|
||||
}
|
||||
p.Module = ModPackageModuleInfo(mainPath)
|
||||
p.Module = modload.PackageModuleInfo(mainPath)
|
||||
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
|
||||
// p.Internal.Imports.
|
||||
//
|
||||
@ -1959,37 +2158,40 @@ func LinkerDeps(p *Package) []string {
|
||||
// externalLinkingForced reports whether external linking is being
|
||||
// forced even for programs that do not use cgo.
|
||||
func externalLinkingForced(p *Package) bool {
|
||||
if !cfg.BuildContext.CgoEnabled {
|
||||
return false
|
||||
}
|
||||
|
||||
// Some targets must use external linking even inside GOROOT.
|
||||
switch cfg.BuildContext.GOOS {
|
||||
case "android":
|
||||
if cfg.BuildContext.GOARCH != "arm64" {
|
||||
return true
|
||||
}
|
||||
case "darwin":
|
||||
if cfg.BuildContext.GOARCH == "arm64" {
|
||||
return true
|
||||
}
|
||||
case "ios":
|
||||
return true
|
||||
}
|
||||
|
||||
if !cfg.BuildContext.CgoEnabled {
|
||||
return false
|
||||
}
|
||||
// Currently build modes c-shared, pie (on systems that do not
|
||||
// support PIE with internal linking mode (currently all
|
||||
// systems: issue #18968)), plugin, and -linkshared force
|
||||
// external linking mode, as of course does
|
||||
// -ldflags=-linkmode=external. External linking mode forces
|
||||
// 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
|
||||
if p != nil {
|
||||
ldflags := BuildLdflags.For(p)
|
||||
for i, a := range ldflags {
|
||||
if a == "-linkmode=external" {
|
||||
linkmodeExternal = true
|
||||
}
|
||||
if a == "-linkmode" && i+1 < len(ldflags) && ldflags[i+1] == "external" {
|
||||
for i := len(ldflags) - 1; i >= 0; i-- {
|
||||
a := ldflags[i]
|
||||
if a == "-linkmode=external" ||
|
||||
a == "-linkmode" && i+1 < len(ldflags) && ldflags[i+1] == "external" {
|
||||
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
|
||||
// due to build tags, but files with names beginning with . or _ are still excluded.
|
||||
func (p *Package) InternalAllGoFiles() []string {
|
||||
return p.mkAbs(str.StringList(p.constraintIgnoredGoFiles(), 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
|
||||
return p.mkAbs(str.StringList(p.IgnoredGoFiles, p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles))
|
||||
}
|
||||
|
||||
// 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
|
||||
// as visited in a depth-first post-order traversal, including the test
|
||||
// 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{}
|
||||
all := []*Package{}
|
||||
var walk func(*Package)
|
||||
@ -2093,7 +2280,7 @@ func TestPackageList(roots []*Package) []*Package {
|
||||
}
|
||||
walkTest := func(root *Package, path string) {
|
||||
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 {
|
||||
walk(p1)
|
||||
}
|
||||
@ -2116,36 +2303,35 @@ func TestPackageList(roots []*Package) []*Package {
|
||||
// TODO(jayconrod): delete this function and set flags automatically
|
||||
// in LoadImport instead.
|
||||
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)
|
||||
return p
|
||||
}
|
||||
|
||||
// Packages returns the packages named by the
|
||||
// command line arguments 'args'. If a named package
|
||||
// cannot be loaded at all (for example, if the directory does not exist),
|
||||
// then packages prints an error and does not include that
|
||||
// package in the results. However, if errors occur trying
|
||||
// to load dependencies of a named package, the named
|
||||
// package is still returned, with p.Incomplete = true
|
||||
// and details in p.DepsErrors.
|
||||
func Packages(args []string) []*Package {
|
||||
var pkgs []*Package
|
||||
for _, pkg := range PackagesAndErrors(args) {
|
||||
if pkg.Error != nil {
|
||||
base.Errorf("%v", pkg.Error)
|
||||
continue
|
||||
}
|
||||
pkgs = append(pkgs, pkg)
|
||||
}
|
||||
return pkgs
|
||||
}
|
||||
// ModResolveTests indicates whether calls to the module loader should also
|
||||
// resolve test dependencies of the requested packages.
|
||||
//
|
||||
// If ModResolveTests is true, then the module loader needs to resolve test
|
||||
// dependencies at the same time as packages; otherwise, the test dependencies
|
||||
// of those packages could be missing, and resolving those missing dependencies
|
||||
// could change the selected versions of modules that provide other packages.
|
||||
//
|
||||
// TODO(#40775): Change this from a global variable to an explicit function
|
||||
// argument where needed.
|
||||
var ModResolveTests bool
|
||||
|
||||
// PackagesAndErrors returns the packages named by the command line arguments
|
||||
// 'patterns'. If a named package cannot be loaded, PackagesAndErrors returns
|
||||
// a *Package with the Error field describing the failure. If errors are found
|
||||
// loading imported packages, the DepsErrors field is set. The Incomplete field
|
||||
// may be set as well.
|
||||
//
|
||||
// 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 {
|
||||
// Listing is only supported with all patterns referring to either:
|
||||
// - Files that are part of the same directory.
|
||||
@ -2153,13 +2339,24 @@ func PackagesAndErrors(patterns []string) []*Package {
|
||||
if strings.HasSuffix(p, ".go") {
|
||||
// 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).
|
||||
if fi, err := os.Stat(p); err == nil && !fi.IsDir() {
|
||||
return []*Package{GoFilesPackage(patterns)}
|
||||
if fi, err := fsys.Stat(p); err == nil && !fi.IsDir() {
|
||||
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 (
|
||||
pkgs []*Package
|
||||
stk ImportStack
|
||||
@ -2175,7 +2372,7 @@ func PackagesAndErrors(patterns []string) []*Package {
|
||||
if pkg == "" {
|
||||
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.Internal.CmdlinePkg = true
|
||||
if m.IsLiteral() {
|
||||
@ -2220,27 +2417,9 @@ func PackagesAndErrors(patterns []string) []*Package {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
// CheckPackageErrors prints errors encountered loading pkgs and their
|
||||
// dependencies, then exits with a non-zero status if any errors were found.
|
||||
func CheckPackageErrors(pkgs []*Package) {
|
||||
printed := map[*PackageError]bool{}
|
||||
for _, pkg := range pkgs {
|
||||
if pkg.Error != nil {
|
||||
@ -2275,15 +2454,22 @@ func PackagesForBuild(args []string) []*Package {
|
||||
seen[pkg.ImportPath] = true
|
||||
}
|
||||
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
|
||||
// (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.
|
||||
func GoFilesPackage(gofiles []string) *Package {
|
||||
ModInit()
|
||||
func GoFilesPackage(ctx context.Context, gofiles []string) *Package {
|
||||
modload.Init()
|
||||
|
||||
for _, f := range gofiles {
|
||||
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
|
||||
// command directory. So that local imports resolve
|
||||
// consistently, the files must all be in the same directory.
|
||||
var dirent []os.FileInfo
|
||||
var dirent []fs.FileInfo
|
||||
var dir string
|
||||
for _, file := range gofiles {
|
||||
fi, err := os.Stat(file)
|
||||
fi, err := fsys.Stat(file)
|
||||
if err != nil {
|
||||
base.Fatalf("%s", err)
|
||||
}
|
||||
@ -2327,10 +2513,10 @@ func GoFilesPackage(gofiles []string) *Package {
|
||||
}
|
||||
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 {
|
||||
ModImportFromFiles(gofiles)
|
||||
modload.ImportFromFiles(ctx, gofiles)
|
||||
}
|
||||
|
||||
var err error
|
||||
@ -2346,7 +2532,7 @@ func GoFilesPackage(gofiles []string) *Package {
|
||||
pkg := new(Package)
|
||||
pkg.Internal.Local = 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.ImportPath = "command-line-arguments"
|
||||
pkg.Target = ""
|
||||
@ -2358,7 +2544,7 @@ func GoFilesPackage(gofiles []string) *Package {
|
||||
if cfg.GOBIN != "" {
|
||||
pkg.Target = filepath.Join(cfg.GOBIN, exe)
|
||||
} else if cfg.ModulesEnabled {
|
||||
pkg.Target = filepath.Join(ModBinDir(), exe)
|
||||
pkg.Target = filepath.Join(modload.BinDir(), exe)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ package load
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmd/go/internal/str"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
@ -20,6 +20,9 @@ import (
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"cmd/go/internal/str"
|
||||
"cmd/go/internal/trace"
|
||||
)
|
||||
|
||||
var TestMainDeps = []string{
|
||||
@ -42,8 +45,8 @@ type TestCover struct {
|
||||
// TestPackagesFor is like TestPackagesAndErrors but it returns
|
||||
// an error if the test packages or their dependencies have errors.
|
||||
// Only test packages without errors are returned.
|
||||
func TestPackagesFor(p *Package, cover *TestCover) (pmain, ptest, pxtest *Package, err error) {
|
||||
pmain, ptest, pxtest = TestPackagesAndErrors(p, cover)
|
||||
func TestPackagesFor(ctx context.Context, p *Package, cover *TestCover) (pmain, ptest, pxtest *Package, err error) {
|
||||
pmain, ptest, pxtest = TestPackagesAndErrors(ctx, p, cover)
|
||||
for _, p1 := range []*Package{ptest, pxtest, pmain} {
|
||||
if p1 == 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,
|
||||
// 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()
|
||||
defer pre.flush()
|
||||
allImports := append([]string{}, p.TestImports...)
|
||||
@ -99,10 +105,11 @@ func TestPackagesAndErrors(p *Package, cover *TestCover) (pmain, ptest, pxtest *
|
||||
var ptestErr, pxtestErr *PackageError
|
||||
var imports, ximports []*Package
|
||||
var stk ImportStack
|
||||
var testEmbed, xtestEmbed map[string][]string
|
||||
stk.Push(p.ImportPath + " (test)")
|
||||
rawTestImports := str.StringList(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 {
|
||||
// Same error that loadPackage returns (via reusePackage) in pkg.go.
|
||||
// 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
|
||||
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.Push(p.ImportPath + "_test")
|
||||
pxtestNeedsPtest := false
|
||||
rawXTestImports := str.StringList(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 {
|
||||
pxtestNeedsPtest = true
|
||||
} else {
|
||||
@ -129,6 +145,13 @@ func TestPackagesAndErrors(p *Package, cover *TestCover) (pmain, ptest, pxtest *
|
||||
}
|
||||
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()
|
||||
|
||||
// Test package.
|
||||
@ -168,6 +191,14 @@ func TestPackagesAndErrors(p *Package, cover *TestCover) (pmain, ptest, pxtest *
|
||||
m[k] = append(m[k], v...)
|
||||
}
|
||||
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()
|
||||
} else {
|
||||
ptest = p
|
||||
@ -185,7 +216,9 @@ func TestPackagesAndErrors(p *Package, cover *TestCover) (pmain, ptest, pxtest *
|
||||
GoFiles: p.XTestGoFiles,
|
||||
Imports: p.XTestImports,
|
||||
ForTest: p.ImportPath,
|
||||
Module: p.Module,
|
||||
Error: pxtestErr,
|
||||
EmbedFiles: p.XTestEmbedFiles,
|
||||
},
|
||||
Internal: PackageInternal{
|
||||
LocalPrefix: p.Internal.LocalPrefix,
|
||||
@ -199,6 +232,7 @@ func TestPackagesAndErrors(p *Package, cover *TestCover) (pmain, ptest, pxtest *
|
||||
Gcflags: p.Internal.Gcflags,
|
||||
Ldflags: p.Internal.Ldflags,
|
||||
Gccgoflags: p.Internal.Gccgoflags,
|
||||
Embed: xtestEmbed,
|
||||
},
|
||||
}
|
||||
if pxtestNeedsPtest {
|
||||
@ -216,6 +250,7 @@ func TestPackagesAndErrors(p *Package, cover *TestCover) (pmain, ptest, pxtest *
|
||||
ImportPath: p.ImportPath + ".test",
|
||||
Root: p.Root,
|
||||
Imports: str.StringList(TestMainDeps),
|
||||
Module: p.Module,
|
||||
},
|
||||
Internal: PackageInternal{
|
||||
Build: &build.Package{Name: "main"},
|
||||
@ -238,7 +273,7 @@ func TestPackagesAndErrors(p *Package, cover *TestCover) (pmain, ptest, pxtest *
|
||||
if dep == ptest.ImportPath {
|
||||
pmain.Internal.Imports = append(pmain.Internal.Imports, ptest)
|
||||
} 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)
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ package filelock
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
)
|
||||
|
||||
@ -24,7 +25,7 @@ type File interface {
|
||||
Fd() uintptr
|
||||
|
||||
// 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
|
||||
@ -87,7 +88,7 @@ var ErrNotSupported = errors.New("operation not supported")
|
||||
// underlyingError returns the underlying error for known os error types.
|
||||
func underlyingError(err error) error {
|
||||
switch err := err.(type) {
|
||||
case *os.PathError:
|
||||
case *fs.PathError:
|
||||
return err.Err
|
||||
case *os.LinkError:
|
||||
return err.Err
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build aix solaris
|
||||
// +build aix solaris,!illumos
|
||||
|
||||
// This code implements the filelock API using POSIX 'fcntl' locks, which attach
|
||||
// to an (inode, process) pair rather than a file descriptor. To avoid unlocking
|
||||
@ -12,17 +12,14 @@
|
||||
// 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
|
||||
// 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
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"io/fs"
|
||||
"math/rand"
|
||||
"os"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
@ -66,7 +63,7 @@ func lock(f File, lt lockType) (err error) {
|
||||
mu.Lock()
|
||||
if i, dup := inodes[f]; dup && i != ino {
|
||||
mu.Unlock()
|
||||
return &os.PathError{
|
||||
return &fs.PathError{
|
||||
Op: lt.String(),
|
||||
Path: f.Name(),
|
||||
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 {
|
||||
unlock(f)
|
||||
return &os.PathError{
|
||||
return &fs.PathError{
|
||||
Op: lt.String(),
|
||||
Path: f.Name(),
|
||||
Err: err,
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
package filelock
|
||||
|
||||
import "os"
|
||||
import "io/fs"
|
||||
|
||||
type lockType int8
|
||||
|
||||
@ -16,7 +16,7 @@ const (
|
||||
)
|
||||
|
||||
func lock(f File, lt lockType) error {
|
||||
return &os.PathError{
|
||||
return &fs.PathError{
|
||||
Op: lt.String(),
|
||||
Path: f.Name(),
|
||||
Err: ErrNotSupported,
|
||||
@ -24,7 +24,7 @@ func lock(f File, lt lockType) error {
|
||||
}
|
||||
|
||||
func unlock(f File) error {
|
||||
return &os.PathError{
|
||||
return &fs.PathError{
|
||||
Op: "Unlock",
|
||||
Path: f.Name(),
|
||||
Err: ErrNotSupported,
|
||||
|
@ -6,9 +6,7 @@
|
||||
|
||||
package filelock
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
import "io/fs"
|
||||
|
||||
type lockType int8
|
||||
|
||||
@ -18,7 +16,7 @@ const (
|
||||
)
|
||||
|
||||
func lock(f File, lt lockType) error {
|
||||
return &os.PathError{
|
||||
return &fs.PathError{
|
||||
Op: lt.String(),
|
||||
Path: f.Name(),
|
||||
Err: ErrNotSupported,
|
||||
@ -26,7 +24,7 @@ func lock(f File, lt lockType) error {
|
||||
}
|
||||
|
||||
func unlock(f File) error {
|
||||
return &os.PathError{
|
||||
return &fs.PathError{
|
||||
Op: "Unlock",
|
||||
Path: f.Name(),
|
||||
Err: ErrNotSupported,
|
||||
|
@ -9,7 +9,6 @@ package filelock_test
|
||||
import (
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@ -51,9 +50,9 @@ func mustTempFile(t *testing.T) (f *os.File, remove func()) {
|
||||
t.Helper()
|
||||
|
||||
base := filepath.Base(t.Name())
|
||||
f, err := ioutil.TempFile("", base)
|
||||
f, err := os.CreateTemp("", base)
|
||||
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())
|
||||
|
||||
@ -161,7 +160,7 @@ func TestRLockExcludesOnlyLock(t *testing.T) {
|
||||
|
||||
doUnlockTF := false
|
||||
switch runtime.GOOS {
|
||||
case "aix", "illumos", "solaris":
|
||||
case "aix", "solaris":
|
||||
// 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
|
||||
// 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
|
||||
// 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
|
||||
|
||||
import (
|
||||
"os"
|
||||
"io/fs"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
@ -26,7 +26,7 @@ func lock(f File, lt lockType) (err error) {
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return &os.PathError{
|
||||
return &fs.PathError{
|
||||
Op: lt.String(),
|
||||
Path: f.Name(),
|
||||
Err: err,
|
||||
|
@ -8,7 +8,7 @@ package filelock
|
||||
|
||||
import (
|
||||
"internal/syscall/windows"
|
||||
"os"
|
||||
"io/fs"
|
||||
"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)
|
||||
if err != nil {
|
||||
return &os.PathError{
|
||||
return &fs.PathError{
|
||||
Op: lt.String(),
|
||||
Path: f.Name(),
|
||||
Err: err,
|
||||
@ -47,7 +47,7 @@ func unlock(f File) error {
|
||||
ol := new(syscall.Overlapped)
|
||||
err := windows.UnlockFileEx(syscall.Handle(f.Fd()), reserved, allBytes, allBytes, ol)
|
||||
if err != nil {
|
||||
return &os.PathError{
|
||||
return &fs.PathError{
|
||||
Op: "Unlock",
|
||||
Path: f.Name(),
|
||||
Err: err,
|
||||
|
@ -9,7 +9,7 @@ package lockedfile
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"io/fs"
|
||||
"os"
|
||||
"runtime"
|
||||
)
|
||||
@ -35,7 +35,7 @@ type osFile struct {
|
||||
// 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;
|
||||
// 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 (
|
||||
f = new(File)
|
||||
err error
|
||||
@ -82,10 +82,10 @@ func Edit(name string) (*File, error) {
|
||||
// non-nil error.
|
||||
func (f *File) Close() error {
|
||||
if f.closed {
|
||||
return &os.PathError{
|
||||
return &fs.PathError{
|
||||
Op: "close",
|
||||
Path: f.Name(),
|
||||
Err: os.ErrClosed,
|
||||
Err: fs.ErrClosed,
|
||||
}
|
||||
}
|
||||
f.closed = true
|
||||
@ -103,12 +103,12 @@ func Read(name string) ([]byte, error) {
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
return ioutil.ReadAll(f)
|
||||
return io.ReadAll(f)
|
||||
}
|
||||
|
||||
// Write opens the named file (creating it with the given permissions if needed),
|
||||
// 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)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -135,7 +135,7 @@ func Transform(name string, t func([]byte) ([]byte, error)) (err error) {
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
old, err := ioutil.ReadAll(f)
|
||||
old, err := io.ReadAll(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -7,18 +7,20 @@
|
||||
package lockedfile
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"os"
|
||||
|
||||
"cmd/go/internal/fsys"
|
||||
"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
|
||||
// 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
|
||||
// consistently.
|
||||
|
||||
f, err := os.OpenFile(name, flag&^os.O_TRUNC, perm)
|
||||
f, err := fsys.OpenFile(name, flag&^os.O_TRUNC, perm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -7,10 +7,13 @@
|
||||
package lockedfile
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"cmd/go/internal/fsys"
|
||||
)
|
||||
|
||||
// Opening an exclusive-use file returns an error.
|
||||
@ -41,7 +44,7 @@ func isLocked(err error) bool {
|
||||
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.
|
||||
//
|
||||
// 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
|
||||
// have the ModeExclusive bit set. Set it before we call OpenFile, so that we
|
||||
// can be confident that a successful OpenFile implies exclusive use.
|
||||
if fi, err := os.Stat(name); err == nil {
|
||||
if fi.Mode()&os.ModeExclusive == 0 {
|
||||
if err := os.Chmod(name, fi.Mode()|os.ModeExclusive); err != nil {
|
||||
if fi, err := fsys.Stat(name); err == nil {
|
||||
if fi.Mode()&fs.ModeExclusive == 0 {
|
||||
if err := os.Chmod(name, fi.Mode()|fs.ModeExclusive); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@ -68,7 +71,7 @@ func openFile(name string, flag int, perm os.FileMode) (*os.File, error) {
|
||||
nextSleep := 1 * time.Millisecond
|
||||
const maxSleep = 500 * time.Millisecond
|
||||
for {
|
||||
f, err := os.OpenFile(name, flag, perm|os.ModeExclusive)
|
||||
f, err := fsys.OpenFile(name, flag, perm|fs.ModeExclusive)
|
||||
if err == nil {
|
||||
return f, nil
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ package lockedfile_test
|
||||
import (
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@ -23,7 +22,7 @@ import (
|
||||
func mustTempDir(t *testing.T) (dir string, remove func()) {
|
||||
t.Helper()
|
||||
|
||||
dir, err := ioutil.TempDir("", filepath.Base(t.Name()))
|
||||
dir, err := os.MkdirTemp("", filepath.Base(t.Name()))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -155,8 +154,8 @@ func TestCanLockExistingFile(t *testing.T) {
|
||||
defer remove()
|
||||
path := filepath.Join(dir, "existing.txt")
|
||||
|
||||
if err := ioutil.WriteFile(path, []byte("ok"), 0777); err != nil {
|
||||
t.Fatalf("ioutil.WriteFile: %v", err)
|
||||
if err := os.WriteFile(path, []byte("ok"), 0777); err != nil {
|
||||
t.Fatalf("os.WriteFile: %v", err)
|
||||
}
|
||||
|
||||
f, err := lockedfile.Edit(path)
|
||||
@ -201,7 +200,7 @@ func TestSpuriousEDEADLK(t *testing.T) {
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -5,15 +5,15 @@
|
||||
package modcmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/modfetch"
|
||||
"cmd/go/internal/modload"
|
||||
"cmd/go/internal/par"
|
||||
"cmd/go/internal/work"
|
||||
|
||||
"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.
|
||||
cmdDownload.Flag.BoolVar(&cfg.BuildX, "x", false, "")
|
||||
work.AddModCommonFlags(cmdDownload)
|
||||
base.AddModCommonFlags(&cmdDownload.Flag)
|
||||
}
|
||||
|
||||
type moduleJSON struct {
|
||||
@ -78,56 +78,27 @@ type moduleJSON struct {
|
||||
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.
|
||||
if cfg.Getenv("GO111MODULE") == "off" {
|
||||
base.Fatalf("go: modules disabled by GO111MODULE=off; see 'go help modules'")
|
||||
}
|
||||
modload.ForceUseModules = true
|
||||
if !modload.HasModRoot() && len(args) == 0 {
|
||||
base.Fatalf("go mod download: no modules specified (see 'go help mod download')")
|
||||
}
|
||||
if len(args) == 0 {
|
||||
args = []string{"all"}
|
||||
} else if modload.HasModRoot() {
|
||||
modload.InitMod() // to fill Target
|
||||
targetAtLatest := modload.Target.Path + "@latest"
|
||||
modload.LoadModFile(ctx) // to fill Target
|
||||
targetAtUpgrade := modload.Target.Path + "@upgrade"
|
||||
targetAtPatch := modload.Target.Path + "@patch"
|
||||
for _, arg := range args {
|
||||
switch arg {
|
||||
case modload.Target.Path, 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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var mods []*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)
|
||||
downloadModule := func(m *moduleJSON) {
|
||||
var err error
|
||||
m.Info, err = modfetch.InfoFile(m.Path, m.Version)
|
||||
if err != nil {
|
||||
@ -145,24 +116,60 @@ func runDownload(cmd *base.Command, args []string) {
|
||||
return
|
||||
}
|
||||
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 {
|
||||
m.Error = err.Error()
|
||||
return
|
||||
}
|
||||
m.Sum = modfetch.Sum(mod)
|
||||
m.Dir, err = modfetch.Download(mod)
|
||||
m.Dir, err = modfetch.Download(ctx, mod)
|
||||
if err != nil {
|
||||
m.Error = err.Error()
|
||||
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 {
|
||||
for _, m := range mods {
|
||||
b, err := json.MarshalIndent(m, "", "\t")
|
||||
if err != nil {
|
||||
base.Fatalf("%v", err)
|
||||
base.Fatalf("go mod download: %v", err)
|
||||
}
|
||||
os.Stdout.Write(append(b, '\n'))
|
||||
if m.Error != "" {
|
||||
@ -172,9 +179,12 @@ func runDownload(cmd *base.Command, args []string) {
|
||||
} else {
|
||||
for _, m := range mods {
|
||||
if m.Error != "" {
|
||||
base.Errorf("%s", m.Error)
|
||||
base.Errorf("go mod download: %v", m.Error)
|
||||
}
|
||||
}
|
||||
base.ExitIfErrors()
|
||||
}
|
||||
|
||||
// Update go.mod and especially go.sum if needed.
|
||||
modload.WriteGoMod()
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ package modcmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@ -18,7 +19,6 @@ import (
|
||||
"cmd/go/internal/lockedfile"
|
||||
"cmd/go/internal/modfetch"
|
||||
"cmd/go/internal/modload"
|
||||
"cmd/go/internal/work"
|
||||
|
||||
"golang.org/x/mod/modfile"
|
||||
"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
|
||||
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,
|
||||
and -dropreplace editing flags may be repeated, and the changes
|
||||
are applied in the order given.
|
||||
-dropreplace, -retract, and -dropretract editing flags may be repeated,
|
||||
and the changes are applied in the order given.
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
referred to indirectly. For the full set of modules available to a build,
|
||||
use 'go list -m -json all'.
|
||||
@ -136,12 +150,14 @@ func init() {
|
||||
cmdEdit.Flag.Var(flagFunc(flagDropReplace), "dropreplace", "")
|
||||
cmdEdit.Flag.Var(flagFunc(flagReplace), "replace", "")
|
||||
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)
|
||||
}
|
||||
|
||||
func runEdit(cmd *base.Command, args []string) {
|
||||
func runEdit(ctx context.Context, cmd *base.Command, args []string) {
|
||||
anyFlags :=
|
||||
*editModule != "" ||
|
||||
*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)
|
||||
}
|
||||
|
||||
// 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.
|
||||
if modfile.MustQuote(version) {
|
||||
if !allowedVersionArg(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)
|
||||
}
|
||||
}
|
||||
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, 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.
|
||||
func flagRequire(arg string) {
|
||||
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.
|
||||
type fileJSON struct {
|
||||
Module module.Version
|
||||
@ -383,6 +456,7 @@ type fileJSON struct {
|
||||
Require []requireJSON
|
||||
Exclude []module.Version
|
||||
Replace []replaceJSON
|
||||
Retract []retractJSON
|
||||
}
|
||||
|
||||
type requireJSON struct {
|
||||
@ -396,6 +470,12 @@ type replaceJSON struct {
|
||||
New module.Version
|
||||
}
|
||||
|
||||
type retractJSON struct {
|
||||
Low string `json:",omitempty"`
|
||||
High string `json:",omitempty"`
|
||||
Rationale string `json:",omitempty"`
|
||||
}
|
||||
|
||||
// editPrintJSON prints the -json output.
|
||||
func editPrintJSON(modFile *modfile.File) {
|
||||
var f fileJSON
|
||||
@ -414,6 +494,9 @@ func editPrintJSON(modFile *modfile.File) {
|
||||
for _, r := range modFile.Replace {
|
||||
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")
|
||||
if err != nil {
|
||||
base.Fatalf("go: internal error: %v", err)
|
||||
|
@ -8,14 +8,12 @@ package modcmd
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/modload"
|
||||
"cmd/go/internal/par"
|
||||
"cmd/go/internal/work"
|
||||
|
||||
"golang.org/x/mod/module"
|
||||
)
|
||||
@ -33,22 +31,16 @@ path@version, except for the main module, which has no @version suffix.
|
||||
}
|
||||
|
||||
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 {
|
||||
base.Fatalf("go mod graph: graph takes no arguments")
|
||||
}
|
||||
// Checks go mod expected behavior
|
||||
if !modload.Enabled() {
|
||||
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'")
|
||||
}
|
||||
}
|
||||
modload.LoadBuildList()
|
||||
modload.ForceUseModules = true
|
||||
modload.RootMode = modload.NeedRoot
|
||||
modload.LoadAllModules(ctx)
|
||||
|
||||
reqs := modload.MinReqs()
|
||||
format := func(m module.Version) string {
|
||||
@ -58,23 +50,25 @@ func runGraph(cmd *base.Command, args []string) {
|
||||
return m.Path + "@" + m.Version
|
||||
}
|
||||
|
||||
// Note: using par.Work only to manage work queue.
|
||||
// No parallelism here, so no locking.
|
||||
var out []string
|
||||
var deps int // index in out where deps start
|
||||
var work par.Work
|
||||
work.Add(modload.Target)
|
||||
work.Do(1, func(item interface{}) {
|
||||
m := item.(module.Version)
|
||||
seen := map[module.Version]bool{modload.Target: true}
|
||||
queue := []module.Version{modload.Target}
|
||||
for len(queue) > 0 {
|
||||
var m module.Version
|
||||
m, queue = queue[0], queue[1:]
|
||||
list, _ := reqs.Required(m)
|
||||
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")
|
||||
}
|
||||
if m == modload.Target {
|
||||
deps = len(out)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
sort.Slice(out[deps:], func(i, j int) bool {
|
||||
return out[deps+i][0] < out[deps+j][0]
|
||||
|
@ -9,46 +9,41 @@ package modcmd
|
||||
import (
|
||||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/modload"
|
||||
"cmd/go/internal/work"
|
||||
"os"
|
||||
"strings"
|
||||
"context"
|
||||
)
|
||||
|
||||
var cmdInit = &base.Command{
|
||||
UsageLine: "go mod init [module]",
|
||||
Short: "initialize new module in current directory",
|
||||
Long: `
|
||||
Init initializes and writes a new go.mod to the current directory,
|
||||
in effect creating a new module rooted at the current directory.
|
||||
The file go.mod must not already exist.
|
||||
If possible, init will guess the module path from import comments
|
||||
(see 'go help importpath') or from version control configuration.
|
||||
To override this guess, supply the module path as an argument.
|
||||
`,
|
||||
Init initializes and writes a new go.mod file in the current directory, in
|
||||
effect creating a new module rooted at the current directory. The go.mod file
|
||||
must not already exist.
|
||||
|
||||
Init accepts one optional argument, the module path for the new module. If the
|
||||
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,
|
||||
}
|
||||
|
||||
func init() {
|
||||
work.AddModCommonFlags(cmdInit)
|
||||
base.AddModCommonFlags(&cmdInit.Flag)
|
||||
}
|
||||
|
||||
func runInit(cmd *base.Command, args []string) {
|
||||
modload.CmdModInit = true
|
||||
func runInit(ctx context.Context, cmd *base.Command, args []string) {
|
||||
if len(args) > 1 {
|
||||
base.Fatalf("go mod init: too many arguments")
|
||||
}
|
||||
var modPath string
|
||||
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'")
|
||||
}
|
||||
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
|
||||
|
||||
modload.ForceUseModules = true
|
||||
modload.CreateModFile(ctx, modPath) // does all the hard work
|
||||
}
|
||||
|
@ -9,15 +9,13 @@ package modcmd
|
||||
import (
|
||||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/modfetch"
|
||||
"cmd/go/internal/imports"
|
||||
"cmd/go/internal/modload"
|
||||
"cmd/go/internal/work"
|
||||
|
||||
"golang.org/x/mod/module"
|
||||
"context"
|
||||
)
|
||||
|
||||
var cmdTidy = &base.Command{
|
||||
UsageLine: "go mod tidy [-v]",
|
||||
UsageLine: "go mod tidy [-e] [-v]",
|
||||
Short: "add missing and remove unused modules",
|
||||
Long: `
|
||||
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
|
||||
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() {
|
||||
cmdTidy.Run = runTidy // break init cycle
|
||||
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 {
|
||||
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()
|
||||
modTidyGoSum() // updates memory copy; WriteGoMod on next line flushes it out
|
||||
modload.TrimGoSum()
|
||||
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 (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
@ -16,16 +17,16 @@ import (
|
||||
|
||||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/fsys"
|
||||
"cmd/go/internal/imports"
|
||||
"cmd/go/internal/modload"
|
||||
"cmd/go/internal/work"
|
||||
|
||||
"golang.org/x/mod/module"
|
||||
"golang.org/x/mod/semver"
|
||||
)
|
||||
|
||||
var cmdVendor = &base.Command{
|
||||
UsageLine: "go mod vendor [-v]",
|
||||
UsageLine: "go mod vendor [-e] [-v]",
|
||||
Short: "make vendored copy of dependencies",
|
||||
Long: `
|
||||
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
|
||||
modules and packages to standard error.
|
||||
|
||||
The -e flag causes vendor to attempt to proceed despite errors
|
||||
encountered while loading packages.
|
||||
`,
|
||||
Run: runVendor,
|
||||
}
|
||||
|
||||
var vendorE bool // if true, report errors but proceed anyway
|
||||
|
||||
func init() {
|
||||
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 {
|
||||
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")
|
||||
if err := os.RemoveAll(vdir); err != nil {
|
||||
@ -57,7 +73,7 @@ func runVendor(cmd *base.Command, args []string) {
|
||||
modpkgs := make(map[module.Version][]string)
|
||||
for _, pkg := range pkgs {
|
||||
m := modload.PackageModule(pkg)
|
||||
if m == modload.Target {
|
||||
if m.Path == "" || m == modload.Target {
|
||||
continue
|
||||
}
|
||||
modpkgs[m] = append(modpkgs[m], pkg)
|
||||
@ -75,28 +91,38 @@ func runVendor(cmd *base.Command, args []string) {
|
||||
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
|
||||
for _, m := range modload.BuildList()[1:] {
|
||||
if pkgs := modpkgs[m]; len(pkgs) > 0 || isExplicit[m] {
|
||||
line := moduleLine(m, modload.Replacement(m))
|
||||
buf.WriteString(line)
|
||||
for _, m := range vendorMods {
|
||||
line := moduleLine(m, modload.Replacement(m))
|
||||
buf.WriteString(line)
|
||||
if cfg.BuildV {
|
||||
os.Stderr.WriteString(line)
|
||||
}
|
||||
if isExplicit[m] {
|
||||
buf.WriteString("## explicit\n")
|
||||
if cfg.BuildV {
|
||||
os.Stderr.WriteString(line)
|
||||
os.Stderr.WriteString("## explicit\n")
|
||||
}
|
||||
if isExplicit[m] {
|
||||
buf.WriteString("## explicit\n")
|
||||
if cfg.BuildV {
|
||||
os.Stderr.WriteString("## explicit\n")
|
||||
}
|
||||
}
|
||||
sort.Strings(pkgs)
|
||||
for _, pkg := range pkgs {
|
||||
fmt.Fprintf(&buf, "%s\n", pkg)
|
||||
if cfg.BuildV {
|
||||
fmt.Fprintf(os.Stderr, "%s\n", pkg)
|
||||
}
|
||||
vendorPkg(vdir, pkg)
|
||||
}
|
||||
pkgs := modpkgs[m]
|
||||
sort.Strings(pkgs)
|
||||
for _, pkg := range pkgs {
|
||||
fmt.Fprintf(&buf, "%s\n", pkg)
|
||||
if cfg.BuildV {
|
||||
fmt.Fprintf(os.Stderr, "%s\n", pkg)
|
||||
}
|
||||
vendorPkg(vdir, pkg)
|
||||
}
|
||||
}
|
||||
|
||||
@ -128,7 +154,7 @@ func runVendor(cmd *base.Command, args []string) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -217,7 +243,7 @@ var metaPrefixes = []string{
|
||||
}
|
||||
|
||||
// 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()
|
||||
for _, p := range metaPrefixes {
|
||||
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.
|
||||
func matchPotentialSourceFile(dir string, info os.FileInfo) bool {
|
||||
func matchPotentialSourceFile(dir string, info fs.DirEntry) bool {
|
||||
if strings.HasSuffix(info.Name(), "_test.go") {
|
||||
return false
|
||||
}
|
||||
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 {
|
||||
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.
|
||||
func copyDir(dst, src string, match func(dir string, info os.FileInfo) bool) {
|
||||
files, err := ioutil.ReadDir(src)
|
||||
func copyDir(dst, src string, match func(dir string, info fs.DirEntry) bool) {
|
||||
files, err := os.ReadDir(src)
|
||||
if err != nil {
|
||||
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)
|
||||
}
|
||||
for _, file := range files {
|
||||
if file.IsDir() || !file.Mode().IsRegular() || !match(src, file) {
|
||||
if file.IsDir() || !file.Type().IsRegular() || !match(src, file) {
|
||||
continue
|
||||
}
|
||||
r, err := os.Open(filepath.Join(src, file.Name()))
|
||||
|
@ -6,17 +6,16 @@ package modcmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io/fs"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/modfetch"
|
||||
"cmd/go/internal/modload"
|
||||
"cmd/go/internal/work"
|
||||
|
||||
"golang.org/x/mod/module"
|
||||
"golang.org/x/mod/sumdb/dirhash"
|
||||
@ -37,29 +36,23 @@ non-zero status.
|
||||
}
|
||||
|
||||
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 {
|
||||
// NOTE(rsc): Could take a module pattern.
|
||||
base.Fatalf("go mod verify: verify takes no arguments")
|
||||
}
|
||||
// Checks go mod expected behavior
|
||||
if !modload.Enabled() || !modload.HasModRoot() {
|
||||
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'")
|
||||
}
|
||||
}
|
||||
modload.ForceUseModules = true
|
||||
modload.RootMode = modload.NeedRoot
|
||||
|
||||
// Only verify up to GOMAXPROCS zips at once.
|
||||
type token struct{}
|
||||
sem := make(chan token, runtime.GOMAXPROCS(0))
|
||||
|
||||
// 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))
|
||||
|
||||
for i, mod := range mods {
|
||||
@ -93,10 +86,10 @@ func verifyMod(mod module.Version) []error {
|
||||
_, zipErr = os.Stat(zip)
|
||||
}
|
||||
dir, dirErr := modfetch.DownloadDir(mod)
|
||||
data, err := ioutil.ReadFile(zip + "hash")
|
||||
data, err := os.ReadFile(zip + "hash")
|
||||
if err != nil {
|
||||
if zipErr != nil && errors.Is(zipErr, os.ErrNotExist) &&
|
||||
dirErr != nil && errors.Is(dirErr, os.ErrNotExist) {
|
||||
if zipErr != nil && errors.Is(zipErr, fs.ErrNotExist) &&
|
||||
dirErr != nil && errors.Is(dirErr, fs.ErrNotExist) {
|
||||
// Nothing downloaded yet. Nothing to verify.
|
||||
return nil
|
||||
}
|
||||
@ -105,7 +98,7 @@ func verifyMod(mod module.Version) []error {
|
||||
}
|
||||
h := string(bytes.TrimSpace(data))
|
||||
|
||||
if zipErr != nil && errors.Is(zipErr, os.ErrNotExist) {
|
||||
if zipErr != nil && errors.Is(zipErr, fs.ErrNotExist) {
|
||||
// ok
|
||||
} else {
|
||||
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))
|
||||
}
|
||||
}
|
||||
if dirErr != nil && errors.Is(dirErr, os.ErrNotExist) {
|
||||
if dirErr != nil && errors.Is(dirErr, fs.ErrNotExist) {
|
||||
// ok
|
||||
} else {
|
||||
hD, err := dirhash.HashDir(dir, mod.Path+"@"+mod.Version, dirhash.DefaultHash)
|
||||
|
@ -5,12 +5,13 @@
|
||||
package modcmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/imports"
|
||||
"cmd/go/internal/modload"
|
||||
"cmd/go/internal/work"
|
||||
|
||||
"golang.org/x/mod/module"
|
||||
)
|
||||
@ -57,25 +58,33 @@ var (
|
||||
|
||||
func init() {
|
||||
cmdWhy.Run = runWhy // break init cycle
|
||||
work.AddModCommonFlags(cmdWhy)
|
||||
base.AddModCommonFlags(&cmdWhy.Flag)
|
||||
}
|
||||
|
||||
func runWhy(cmd *base.Command, args []string) {
|
||||
loadALL := modload.LoadALL
|
||||
if *whyVendor {
|
||||
loadALL = modload.LoadVendor
|
||||
func runWhy(ctx context.Context, cmd *base.Command, args []string) {
|
||||
modload.ForceUseModules = true
|
||||
modload.RootMode = modload.NeedRoot
|
||||
|
||||
loadOpts := modload.PackageOpts{
|
||||
Tags: imports.AnyTags(),
|
||||
LoadTests: !*whyVendor,
|
||||
SilenceErrors: true,
|
||||
UseVendorAll: *whyVendor,
|
||||
}
|
||||
|
||||
if *whyM {
|
||||
listU := false
|
||||
listVersions := false
|
||||
listRetractions := false
|
||||
for _, arg := range args {
|
||||
if strings.Contains(arg, "@") {
|
||||
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)
|
||||
for _, path := range loadALL() {
|
||||
_, pkgs := modload.LoadPackages(ctx, loadOpts, "all")
|
||||
for _, path := range pkgs {
|
||||
m := modload.PackageModule(path)
|
||||
if m.Path != "" {
|
||||
byModule[m] = append(byModule[m], path)
|
||||
@ -104,8 +113,11 @@ func runWhy(cmd *base.Command, args []string) {
|
||||
sep = "\n"
|
||||
}
|
||||
} else {
|
||||
matches := modload.ImportPaths(args) // resolve to packages
|
||||
loadALL() // rebuild graph, from main module (not from named packages)
|
||||
// Resolve to packages.
|
||||
matches, _ := modload.LoadPackages(ctx, loadOpts, args...)
|
||||
|
||||
modload.LoadPackages(ctx, loadOpts, "all") // rebuild graph, from main module (not from named packages)
|
||||
|
||||
sep := ""
|
||||
for _, m := range matches {
|
||||
for _, path := range m.Pkgs {
|
||||
|
@ -7,13 +7,12 @@ package modconv
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/modfetch"
|
||||
"cmd/go/internal/par"
|
||||
|
||||
"golang.org/x/mod/modfile"
|
||||
"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,
|
||||
// to valid semver requirement list, respecting major versions.
|
||||
var (
|
||||
work par.Work
|
||||
mu sync.Mutex
|
||||
need = make(map[string]string)
|
||||
replace = make(map[string]*modfile.Replace)
|
||||
)
|
||||
versions := make([]module.Version, len(mf.Require))
|
||||
replace := make(map[string]*modfile.Replace)
|
||||
|
||||
for _, r := range mf.Replace {
|
||||
replace[r.New.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
|
||||
if m.Path == "" {
|
||||
continue
|
||||
}
|
||||
if re, ok := replace[m.Path]; ok {
|
||||
work.Add(re.New)
|
||||
continue
|
||||
m = re.New
|
||||
}
|
||||
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{}) {
|
||||
r := item.(module.Version)
|
||||
repo, info, err := modfetch.ImportRepoRev(r.Path, r.Version)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "go: converting %s: stat %s@%s: %v\n", base.ShortPath(file), r.Path, r.Version, err)
|
||||
return
|
||||
need := map[string]string{}
|
||||
for _, v := range versions {
|
||||
if v.Path == "" {
|
||||
continue
|
||||
}
|
||||
mu.Lock()
|
||||
path := repo.ModulePath()
|
||||
// Don't use semver.Max here; need to preserve +incompatible suffix.
|
||||
if v, ok := need[path]; !ok || semver.Compare(v, info.Version) < 0 {
|
||||
need[path] = info.Version
|
||||
if needv, ok := need[v.Path]; !ok || semver.Compare(needv, v.Version) < 0 {
|
||||
need[v.Path] = v.Version
|
||||
}
|
||||
mu.Unlock()
|
||||
})
|
||||
|
||||
var paths []string
|
||||
}
|
||||
paths := make([]string, 0, len(need))
|
||||
for path := range need {
|
||||
paths = append(paths, path)
|
||||
}
|
||||
|
@ -6,9 +6,9 @@ package modconv
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
@ -36,7 +36,7 @@ func testMain(m *testing.M) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
dir, err := ioutil.TempDir("", "modconv-test-")
|
||||
dir, err := os.MkdirTemp("", "modconv-test-")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@ -146,6 +146,8 @@ func TestConvertLegacyConfig(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(strings.ReplaceAll(tt.path, "/", "_")+"_"+tt.vers, func(t *testing.T) {
|
||||
f, err := modfile.Parse("golden", []byte(tt.gomod), nil)
|
||||
@ -157,14 +159,14 @@ func TestConvertLegacyConfig(t *testing.T) {
|
||||
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 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for name := range Converters {
|
||||
file := filepath.Join(dir, name)
|
||||
data, err := ioutil.ReadFile(file)
|
||||
data, err := os.ReadFile(file)
|
||||
if err == nil {
|
||||
f := new(modfile.File)
|
||||
f.AddModuleStmt(tt.path)
|
||||
|
@ -7,7 +7,7 @@ package modconv
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
@ -42,7 +42,7 @@ func Test(t *testing.T) {
|
||||
if Converters[extMap[ext]] == nil {
|
||||
t.Fatalf("Converters[%q] == nil", extMap[ext])
|
||||
}
|
||||
data, err := ioutil.ReadFile(test)
|
||||
data, err := os.ReadFile(test)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -50,7 +50,7 @@ func Test(t *testing.T) {
|
||||
if err != nil {
|
||||
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 {
|
||||
t.Error(err)
|
||||
}
|
||||
|
@ -10,10 +10,11 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"cmd/go/internal/base"
|
||||
"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.
|
||||
// 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
|
||||
// is not completely populated.
|
||||
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
|
||||
// exists but was not completely populated.
|
||||
//
|
||||
// DownloadDirPartialError is equivalent to os.ErrNotExist.
|
||||
// DownloadDirPartialError is equivalent to fs.ErrNotExist.
|
||||
type DownloadDirPartialError struct {
|
||||
Dir string
|
||||
Err error
|
||||
}
|
||||
|
||||
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
|
||||
// and extraction of the zipfile for the given module version.
|
||||
@ -155,16 +156,30 @@ func SideLock() (unlock func(), err error) {
|
||||
type cachingRepo struct {
|
||||
path string
|
||||
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{
|
||||
r: r,
|
||||
path: r.ModulePath(),
|
||||
path: path,
|
||||
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 {
|
||||
return r.path
|
||||
}
|
||||
@ -175,7 +190,7 @@ func (r *cachingRepo) Versions(prefix string) ([]string, error) {
|
||||
err error
|
||||
}
|
||||
c := r.cache.Do("versions:"+prefix, func() interface{} {
|
||||
list, err := r.r.Versions(prefix)
|
||||
list, err := r.repo().Versions(prefix)
|
||||
return cached{list, err}
|
||||
}).(cached)
|
||||
|
||||
@ -197,7 +212,7 @@ func (r *cachingRepo) Stat(rev string) (*RevInfo, error) {
|
||||
return cachedInfo{info, nil}
|
||||
}
|
||||
|
||||
info, err = r.r.Stat(rev)
|
||||
info, err = r.repo().Stat(rev)
|
||||
if err == nil {
|
||||
// If we resolved, say, 1234abcde to v0.0.0-20180604122334-1234abcdef78,
|
||||
// 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) {
|
||||
c := r.cache.Do("latest:", func() interface{} {
|
||||
info, err := r.r.Latest()
|
||||
info, err := r.repo().Latest()
|
||||
|
||||
// Save info for likely future Stat call.
|
||||
if err == nil {
|
||||
@ -258,7 +273,7 @@ func (r *cachingRepo) GoMod(version string) ([]byte, error) {
|
||||
return cached{text, nil}
|
||||
}
|
||||
|
||||
text, err = r.r.GoMod(version)
|
||||
text, err = r.repo().GoMod(version)
|
||||
if err == nil {
|
||||
if err := checkGoMod(r.path, version, text); err != nil {
|
||||
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 {
|
||||
return r.r.Zip(dst, version)
|
||||
return r.repo().Zip(dst, version)
|
||||
}
|
||||
|
||||
// Stat is like Lookup(path).Stat(rev) but avoids the
|
||||
// repository path resolution in Lookup if the result is
|
||||
// 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.
|
||||
// InfoFile is like Lookup(path).Stat(version) but returns the name of the file
|
||||
// containing the cached information.
|
||||
func InfoFile(path, version string) (string, error) {
|
||||
if !semver.IsValid(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 {
|
||||
repo, err := Lookup(proxy, path)
|
||||
if err == nil {
|
||||
_, err = repo.Stat(version)
|
||||
}
|
||||
_, err := Lookup(proxy, path).Stat(version)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
@ -336,11 +333,7 @@ func GoMod(path, rev string) ([]byte, error) {
|
||||
rev = info.Version
|
||||
} else {
|
||||
err := TryProxies(func(proxy string) error {
|
||||
repo, err := Lookup(proxy, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
info, err := repo.Stat(rev)
|
||||
info, err := Lookup(proxy, path).Stat(rev)
|
||||
if err == nil {
|
||||
rev = info.Version
|
||||
}
|
||||
@ -357,11 +350,8 @@ func GoMod(path, rev string) ([]byte, error) {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
err = TryProxies(func(proxy string) error {
|
||||
repo, err := Lookup(proxy, path)
|
||||
if err == nil {
|
||||
data, err = repo.GoMod(rev)
|
||||
}
|
||||
err = TryProxies(func(proxy string) (err error) {
|
||||
data, err = Lookup(proxy, path).GoMod(rev)
|
||||
return err
|
||||
})
|
||||
return data, err
|
||||
@ -492,7 +482,7 @@ func readDiskStatByHash(path, rev string) (file string, info *RevInfo, err error
|
||||
for _, name := range names {
|
||||
if strings.HasSuffix(name, suffix) {
|
||||
v := strings.TrimSuffix(name, ".info")
|
||||
if IsPseudoVersion(v) && semver.Max(maxVersion, v) == v {
|
||||
if IsPseudoVersion(v) && semver.Compare(v, maxVersion) > 0 {
|
||||
maxVersion = v
|
||||
file, info, err = readDiskStat(path, strings.TrimSuffix(name, ".info"))
|
||||
}
|
||||
@ -607,7 +597,7 @@ func rewriteVersionList(dir string) {
|
||||
}
|
||||
defer unlock()
|
||||
|
||||
infos, err := ioutil.ReadDir(dir)
|
||||
infos, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -5,14 +5,13 @@
|
||||
package modfetch
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestWriteDiskCache(t *testing.T) {
|
||||
tmpdir, err := ioutil.TempDir("", "go-writeCache-test-")
|
||||
tmpdir, err := os.MkdirTemp("", "go-writeCache-test-")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import (
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"io/fs"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@ -79,9 +79,8 @@ type Repo interface {
|
||||
ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser, err error)
|
||||
|
||||
// RecentTag returns the most recent tag on rev or one of its predecessors
|
||||
// with the given prefix and major version.
|
||||
// An empty major string matches any major version.
|
||||
RecentTag(rev, prefix, major string) (tag string, err error)
|
||||
// with the given prefix. allowed may be used to filter out unwanted versions.
|
||||
RecentTag(rev, prefix string, allowed func(string) bool) (tag string, err error)
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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.
|
||||
type UnknownRevisionError struct {
|
||||
Rev string
|
||||
@ -116,10 +115,10 @@ func (e *UnknownRevisionError) Error() string {
|
||||
return "unknown revision " + e.Rev
|
||||
}
|
||||
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.
|
||||
var ErrNoCommits error = noCommitsError{}
|
||||
|
||||
@ -129,7 +128,7 @@ func (noCommitsError) Error() string {
|
||||
return "no commits"
|
||||
}
|
||||
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.
|
||||
@ -189,7 +188,7 @@ func WorkDir(typ, name string) (dir, lockfile string, err error) {
|
||||
}
|
||||
defer unlock()
|
||||
|
||||
data, err := ioutil.ReadFile(dir + ".info")
|
||||
data, err := os.ReadFile(dir + ".info")
|
||||
info, err2 := os.Stat(dir)
|
||||
if err == nil && err2 == nil && info.IsDir() {
|
||||
// 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 {
|
||||
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)
|
||||
return "", "", err
|
||||
}
|
||||
@ -264,6 +263,9 @@ func RunWithStdin(dir string, stdin io.Reader, cmdline ...interface{}) ([]byte,
|
||||
}
|
||||
|
||||
cmd := str.StringList(cmdline...)
|
||||
if os.Getenv("TESTGOVCS") == "panic" {
|
||||
panic(fmt.Sprintf("use of vcs: %v", cmd))
|
||||
}
|
||||
if cfg.BuildX {
|
||||
text := new(strings.Builder)
|
||||
if dir != "" {
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"io/fs"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
@ -34,13 +34,13 @@ func LocalGitRepo(remote string) (Repo, error) {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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"
|
||||
|
||||
@ -188,7 +188,7 @@ func (r *gitRepo) loadRefs() {
|
||||
// For HTTP and HTTPS, that's easy to detect: we'll try to fetch the URL
|
||||
// ourselves and see what code it serves.
|
||||
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}
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
if err != nil {
|
||||
return nil, os.ErrNotExist
|
||||
return nil, fs.ErrNotExist
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
@ -629,9 +629,9 @@ func (r *gitRepo) readFileRevs(tags []string, file string, fileMap map[string]*F
|
||||
case "tag", "commit":
|
||||
switch fileType {
|
||||
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":
|
||||
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":
|
||||
f.Data = fileData
|
||||
}
|
||||
@ -644,7 +644,7 @@ func (r *gitRepo) readFileRevs(tags []string, file string, fileMap map[string]*F
|
||||
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)
|
||||
if err != nil {
|
||||
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.
|
||||
// We want to return the actual tag, not a canonicalized version of it,
|
||||
// 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
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
if err != nil {
|
||||
if bytes.Contains(err.(*RunError).Stderr, []byte("did not match any files")) {
|
||||
return nil, os.ErrNotExist
|
||||
return nil, fs.ErrNotExist
|
||||
}
|
||||
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
|
||||
@ -859,7 +862,7 @@ func ensureGitAttributes(repoDir string) (err error) {
|
||||
}
|
||||
}()
|
||||
|
||||
b, err := ioutil.ReadAll(f)
|
||||
b, err := io.ReadAll(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -10,7 +10,8 @@ import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"io/fs"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
@ -52,7 +53,7 @@ func testMain(m *testing.M) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
dir, err := ioutil.TempDir("", "gitrepo-test-")
|
||||
dir, err := os.MkdirTemp("", "gitrepo-test-")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@ -210,7 +211,7 @@ var readFileTests = []struct {
|
||||
repo: gitrepo1,
|
||||
rev: "v2.3.4",
|
||||
file: "another.txt",
|
||||
err: os.ErrNotExist.Error(),
|
||||
err: fs.ErrNotExist.Error(),
|
||||
},
|
||||
}
|
||||
|
||||
@ -432,7 +433,7 @@ func TestReadZip(t *testing.T) {
|
||||
if tt.err != "" {
|
||||
t.Fatalf("ReadZip: no error, wanted %v", tt.err)
|
||||
}
|
||||
zipdata, err := ioutil.ReadAll(rc)
|
||||
zipdata, err := io.ReadAll(rc)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
@ -115,7 +115,7 @@ func main() {
|
||||
fmt.Fprintf(os.Stderr, "?%s\n", err)
|
||||
continue
|
||||
}
|
||||
data, err := ioutil.ReadAll(rc)
|
||||
data, err := io.ReadAll(rc)
|
||||
rc.Close()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "?%s\n", err)
|
||||
@ -123,7 +123,7 @@ func main() {
|
||||
}
|
||||
|
||||
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)
|
||||
continue
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user