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:
Ian Lance Taylor 2020-12-23 09:57:37 -08:00
parent 0696141107
commit cfcbb4227f
1189 changed files with 67672 additions and 31085 deletions

View File

@ -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.

View File

@ -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/

View File

@ -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/

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -1 +1 @@
go1.15.6
go1.16beta1

View File

@ -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

View File

@ -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
View File

@ -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`

View File

@ -10,7 +10,7 @@ AC_INIT(package-unused, version-unused,, libgo)
AC_CONFIG_SRCDIR(Makefile.am)
AC_CONFIG_HEADER(config.h)
libtool_VERSION=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])

View File

@ -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

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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)

View File

@ -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)
}
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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))
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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)
}
}

View File

@ -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)
}

View File

@ -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"
}

View File

@ -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; }

View File

@ -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

View File

@ -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")

View File

@ -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)
}

View File

@ -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
View 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
)

View File

@ -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

View File

@ -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"

View File

@ -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 {

View File

@ -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)
}

View File

@ -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")
}

View File

@ -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

View File

@ -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

View File

@ -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", "", "")
}

View File

@ -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, "--") {

View File

@ -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

View File

@ -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
}

View File

@ -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.

View File

@ -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)
}

View File

@ -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)

View File

@ -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)
}

View File

@ -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")

View File

@ -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.

View 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)
}

View File

@ -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])

View File

@ -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")

View File

@ -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")

View 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)
}

File diff suppressed because it is too large Load Diff

View File

@ -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)
}

View File

@ -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
}

View File

@ -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",
}

View File

@ -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

View File

@ -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

View File

@ -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)}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -0,0 +1,3 @@
package android
import _ "h"

View File

@ -0,0 +1,3 @@
package android
import _ "h"

View File

@ -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.

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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

View File

@ -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,

View File

@ -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,

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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()
}

View File

@ -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)

View File

@ -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]

View File

@ -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
}

View File

@ -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)
}

View File

@ -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()))

View File

@ -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)

View File

@ -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 {

View File

@ -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)
}

View File

@ -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)

View File

@ -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)
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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 != "" {

View File

@ -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
}

View File

@ -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)
}

View File

@ -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