Update module golang.org/x/tools to v0.18.0

Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
This commit is contained in:
renovate[bot] 2024-02-25 14:34:17 +00:00 committed by GitHub
parent ea3221a862
commit 53b5fc781f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
52 changed files with 930 additions and 414 deletions

View File

@ -6,7 +6,7 @@ require (
github.com/cpuguy83/go-md2man/v2 v2.0.3 github.com/cpuguy83/go-md2man/v2 v2.0.3
github.com/onsi/ginkgo/v2 v2.14.0 github.com/onsi/ginkgo/v2 v2.14.0
github.com/vbatts/git-validation v1.2.1 github.com/vbatts/git-validation v1.2.1
golang.org/x/tools v0.17.0 golang.org/x/tools v0.18.0
) )
require ( require (
@ -19,6 +19,6 @@ require (
github.com/mattn/go-isatty v0.0.17 // indirect github.com/mattn/go-isatty v0.0.17 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect github.com/sirupsen/logrus v1.8.1 // indirect
golang.org/x/mod v0.14.0 // indirect golang.org/x/mod v0.15.0 // indirect
golang.org/x/sys v0.15.0 // indirect golang.org/x/sys v0.17.0 // indirect
) )

View File

@ -40,18 +40,18 @@ github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/vbatts/git-validation v1.2.1 h1:O26LKWEtBOfnxKT/SAiFCAcQglKwyuZEKSq6AevpWJ4= github.com/vbatts/git-validation v1.2.1 h1:O26LKWEtBOfnxKT/SAiFCAcQglKwyuZEKSq6AevpWJ4=
github.com/vbatts/git-validation v1.2.1/go.mod h1:isqpXnI2IUKUhoYIsHg5tDmtiEXoA7KJRVsAc4+XoYw= github.com/vbatts/git-validation v1.2.1/go.mod h1:isqpXnI2IUKUhoYIsHg5tDmtiEXoA7KJRVsAc4+XoYw=
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -248,6 +248,7 @@ struct ltchars {
#include <linux/module.h> #include <linux/module.h>
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/netfilter/nfnetlink.h> #include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nf_tables.h>
#include <linux/netlink.h> #include <linux/netlink.h>
#include <linux/net_namespace.h> #include <linux/net_namespace.h>
#include <linux/nfc.h> #include <linux/nfc.h>
@ -283,10 +284,6 @@ struct ltchars {
#include <asm/termbits.h> #include <asm/termbits.h>
#endif #endif
#ifndef MSG_FASTOPEN
#define MSG_FASTOPEN 0x20000000
#endif
#ifndef PTRACE_GETREGS #ifndef PTRACE_GETREGS
#define PTRACE_GETREGS 0xc #define PTRACE_GETREGS 0xc
#endif #endif
@ -295,14 +292,6 @@ struct ltchars {
#define PTRACE_SETREGS 0xd #define PTRACE_SETREGS 0xd
#endif #endif
#ifndef SOL_NETLINK
#define SOL_NETLINK 270
#endif
#ifndef SOL_SMC
#define SOL_SMC 286
#endif
#ifdef SOL_BLUETOOTH #ifdef SOL_BLUETOOTH
// SPARC includes this in /usr/include/sparc64-linux-gnu/bits/socket.h // SPARC includes this in /usr/include/sparc64-linux-gnu/bits/socket.h
// but it is already in bluetooth_linux.go // but it is already in bluetooth_linux.go
@ -319,10 +308,23 @@ struct ltchars {
#undef TIPC_WAIT_FOREVER #undef TIPC_WAIT_FOREVER
#define TIPC_WAIT_FOREVER 0xffffffff #define TIPC_WAIT_FOREVER 0xffffffff
// Copied from linux/l2tp.h // Copied from linux/netfilter/nf_nat.h
// Including linux/l2tp.h here causes conflicts between linux/in.h // Including linux/netfilter/nf_nat.h here causes conflicts between linux/in.h
// and netinet/in.h included via net/route.h above. // and netinet/in.h.
#define IPPROTO_L2TP 115 #define NF_NAT_RANGE_MAP_IPS (1 << 0)
#define NF_NAT_RANGE_PROTO_SPECIFIED (1 << 1)
#define NF_NAT_RANGE_PROTO_RANDOM (1 << 2)
#define NF_NAT_RANGE_PERSISTENT (1 << 3)
#define NF_NAT_RANGE_PROTO_RANDOM_FULLY (1 << 4)
#define NF_NAT_RANGE_PROTO_OFFSET (1 << 5)
#define NF_NAT_RANGE_NETMAP (1 << 6)
#define NF_NAT_RANGE_PROTO_RANDOM_ALL \
(NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PROTO_RANDOM_FULLY)
#define NF_NAT_RANGE_MASK \
(NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED | \
NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PERSISTENT | \
NF_NAT_RANGE_PROTO_RANDOM_FULLY | NF_NAT_RANGE_PROTO_OFFSET | \
NF_NAT_RANGE_NETMAP)
// Copied from linux/hid.h. // Copied from linux/hid.h.
// Keep in sync with the size of the referenced fields. // Keep in sync with the size of the referenced fields.
@ -582,7 +584,7 @@ ccflags="$@"
$2 ~ /^KEY_(SPEC|REQKEY_DEFL)_/ || $2 ~ /^KEY_(SPEC|REQKEY_DEFL)_/ ||
$2 ~ /^KEYCTL_/ || $2 ~ /^KEYCTL_/ ||
$2 ~ /^PERF_/ || $2 ~ /^PERF_/ ||
$2 ~ /^SECCOMP_MODE_/ || $2 ~ /^SECCOMP_/ ||
$2 ~ /^SEEK_/ || $2 ~ /^SEEK_/ ||
$2 ~ /^SCHED_/ || $2 ~ /^SCHED_/ ||
$2 ~ /^SPLICE_/ || $2 ~ /^SPLICE_/ ||
@ -603,6 +605,9 @@ ccflags="$@"
$2 ~ /^FSOPT_/ || $2 ~ /^FSOPT_/ ||
$2 ~ /^WDIO[CFS]_/ || $2 ~ /^WDIO[CFS]_/ ||
$2 ~ /^NFN/ || $2 ~ /^NFN/ ||
$2 !~ /^NFT_META_IIFTYPE/ &&
$2 ~ /^NFT_/ ||
$2 ~ /^NF_NAT_/ ||
$2 ~ /^XDP_/ || $2 ~ /^XDP_/ ||
$2 ~ /^RWF_/ || $2 ~ /^RWF_/ ||
$2 ~ /^(HDIO|WIN|SMART)_/ || $2 ~ /^(HDIO|WIN|SMART)_/ ||

View File

@ -1785,6 +1785,8 @@ const (
LANDLOCK_ACCESS_FS_REMOVE_FILE = 0x20 LANDLOCK_ACCESS_FS_REMOVE_FILE = 0x20
LANDLOCK_ACCESS_FS_TRUNCATE = 0x4000 LANDLOCK_ACCESS_FS_TRUNCATE = 0x4000
LANDLOCK_ACCESS_FS_WRITE_FILE = 0x2 LANDLOCK_ACCESS_FS_WRITE_FILE = 0x2
LANDLOCK_ACCESS_NET_BIND_TCP = 0x1
LANDLOCK_ACCESS_NET_CONNECT_TCP = 0x2
LANDLOCK_CREATE_RULESET_VERSION = 0x1 LANDLOCK_CREATE_RULESET_VERSION = 0x1
LINUX_REBOOT_CMD_CAD_OFF = 0x0 LINUX_REBOOT_CMD_CAD_OFF = 0x0
LINUX_REBOOT_CMD_CAD_ON = 0x89abcdef LINUX_REBOOT_CMD_CAD_ON = 0x89abcdef
@ -2127,6 +2129,60 @@ const (
NFNL_SUBSYS_QUEUE = 0x3 NFNL_SUBSYS_QUEUE = 0x3
NFNL_SUBSYS_ULOG = 0x4 NFNL_SUBSYS_ULOG = 0x4
NFS_SUPER_MAGIC = 0x6969 NFS_SUPER_MAGIC = 0x6969
NFT_CHAIN_FLAGS = 0x7
NFT_CHAIN_MAXNAMELEN = 0x100
NFT_CT_MAX = 0x17
NFT_DATA_RESERVED_MASK = 0xffffff00
NFT_DATA_VALUE_MAXLEN = 0x40
NFT_EXTHDR_OP_MAX = 0x4
NFT_FIB_RESULT_MAX = 0x3
NFT_INNER_MASK = 0xf
NFT_LOGLEVEL_MAX = 0x8
NFT_NAME_MAXLEN = 0x100
NFT_NG_MAX = 0x1
NFT_OBJECT_CONNLIMIT = 0x5
NFT_OBJECT_COUNTER = 0x1
NFT_OBJECT_CT_EXPECT = 0x9
NFT_OBJECT_CT_HELPER = 0x3
NFT_OBJECT_CT_TIMEOUT = 0x7
NFT_OBJECT_LIMIT = 0x4
NFT_OBJECT_MAX = 0xa
NFT_OBJECT_QUOTA = 0x2
NFT_OBJECT_SECMARK = 0x8
NFT_OBJECT_SYNPROXY = 0xa
NFT_OBJECT_TUNNEL = 0x6
NFT_OBJECT_UNSPEC = 0x0
NFT_OBJ_MAXNAMELEN = 0x100
NFT_OSF_MAXGENRELEN = 0x10
NFT_QUEUE_FLAG_BYPASS = 0x1
NFT_QUEUE_FLAG_CPU_FANOUT = 0x2
NFT_QUEUE_FLAG_MASK = 0x3
NFT_REG32_COUNT = 0x10
NFT_REG32_SIZE = 0x4
NFT_REG_MAX = 0x4
NFT_REG_SIZE = 0x10
NFT_REJECT_ICMPX_MAX = 0x3
NFT_RT_MAX = 0x4
NFT_SECMARK_CTX_MAXLEN = 0x100
NFT_SET_MAXNAMELEN = 0x100
NFT_SOCKET_MAX = 0x3
NFT_TABLE_F_MASK = 0x3
NFT_TABLE_MAXNAMELEN = 0x100
NFT_TRACETYPE_MAX = 0x3
NFT_TUNNEL_F_MASK = 0x7
NFT_TUNNEL_MAX = 0x1
NFT_TUNNEL_MODE_MAX = 0x2
NFT_USERDATA_MAXLEN = 0x100
NFT_XFRM_KEY_MAX = 0x6
NF_NAT_RANGE_MAP_IPS = 0x1
NF_NAT_RANGE_MASK = 0x7f
NF_NAT_RANGE_NETMAP = 0x40
NF_NAT_RANGE_PERSISTENT = 0x8
NF_NAT_RANGE_PROTO_OFFSET = 0x20
NF_NAT_RANGE_PROTO_RANDOM = 0x4
NF_NAT_RANGE_PROTO_RANDOM_ALL = 0x14
NF_NAT_RANGE_PROTO_RANDOM_FULLY = 0x10
NF_NAT_RANGE_PROTO_SPECIFIED = 0x2
NILFS_SUPER_MAGIC = 0x3434 NILFS_SUPER_MAGIC = 0x3434
NL0 = 0x0 NL0 = 0x0
NL1 = 0x100 NL1 = 0x100
@ -2411,6 +2467,7 @@ const (
PR_MCE_KILL_GET = 0x22 PR_MCE_KILL_GET = 0x22
PR_MCE_KILL_LATE = 0x0 PR_MCE_KILL_LATE = 0x0
PR_MCE_KILL_SET = 0x1 PR_MCE_KILL_SET = 0x1
PR_MDWE_NO_INHERIT = 0x2
PR_MDWE_REFUSE_EXEC_GAIN = 0x1 PR_MDWE_REFUSE_EXEC_GAIN = 0x1
PR_MPX_DISABLE_MANAGEMENT = 0x2c PR_MPX_DISABLE_MANAGEMENT = 0x2c
PR_MPX_ENABLE_MANAGEMENT = 0x2b PR_MPX_ENABLE_MANAGEMENT = 0x2b
@ -2615,8 +2672,9 @@ const (
RTAX_FEATURES = 0xc RTAX_FEATURES = 0xc
RTAX_FEATURE_ALLFRAG = 0x8 RTAX_FEATURE_ALLFRAG = 0x8
RTAX_FEATURE_ECN = 0x1 RTAX_FEATURE_ECN = 0x1
RTAX_FEATURE_MASK = 0xf RTAX_FEATURE_MASK = 0x1f
RTAX_FEATURE_SACK = 0x2 RTAX_FEATURE_SACK = 0x2
RTAX_FEATURE_TCP_USEC_TS = 0x10
RTAX_FEATURE_TIMESTAMP = 0x4 RTAX_FEATURE_TIMESTAMP = 0x4
RTAX_HOPLIMIT = 0xa RTAX_HOPLIMIT = 0xa
RTAX_INITCWND = 0xb RTAX_INITCWND = 0xb
@ -2859,9 +2917,38 @@ const (
SCM_RIGHTS = 0x1 SCM_RIGHTS = 0x1
SCM_TIMESTAMP = 0x1d SCM_TIMESTAMP = 0x1d
SC_LOG_FLUSH = 0x100000 SC_LOG_FLUSH = 0x100000
SECCOMP_ADDFD_FLAG_SEND = 0x2
SECCOMP_ADDFD_FLAG_SETFD = 0x1
SECCOMP_FILTER_FLAG_LOG = 0x2
SECCOMP_FILTER_FLAG_NEW_LISTENER = 0x8
SECCOMP_FILTER_FLAG_SPEC_ALLOW = 0x4
SECCOMP_FILTER_FLAG_TSYNC = 0x1
SECCOMP_FILTER_FLAG_TSYNC_ESRCH = 0x10
SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV = 0x20
SECCOMP_GET_ACTION_AVAIL = 0x2
SECCOMP_GET_NOTIF_SIZES = 0x3
SECCOMP_IOCTL_NOTIF_RECV = 0xc0502100
SECCOMP_IOCTL_NOTIF_SEND = 0xc0182101
SECCOMP_IOC_MAGIC = '!'
SECCOMP_MODE_DISABLED = 0x0 SECCOMP_MODE_DISABLED = 0x0
SECCOMP_MODE_FILTER = 0x2 SECCOMP_MODE_FILTER = 0x2
SECCOMP_MODE_STRICT = 0x1 SECCOMP_MODE_STRICT = 0x1
SECCOMP_RET_ACTION = 0x7fff0000
SECCOMP_RET_ACTION_FULL = 0xffff0000
SECCOMP_RET_ALLOW = 0x7fff0000
SECCOMP_RET_DATA = 0xffff
SECCOMP_RET_ERRNO = 0x50000
SECCOMP_RET_KILL = 0x0
SECCOMP_RET_KILL_PROCESS = 0x80000000
SECCOMP_RET_KILL_THREAD = 0x0
SECCOMP_RET_LOG = 0x7ffc0000
SECCOMP_RET_TRACE = 0x7ff00000
SECCOMP_RET_TRAP = 0x30000
SECCOMP_RET_USER_NOTIF = 0x7fc00000
SECCOMP_SET_MODE_FILTER = 0x1
SECCOMP_SET_MODE_STRICT = 0x0
SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP = 0x1
SECCOMP_USER_NOTIF_FLAG_CONTINUE = 0x1
SECRETMEM_MAGIC = 0x5345434d SECRETMEM_MAGIC = 0x5345434d
SECURITYFS_MAGIC = 0x73636673 SECURITYFS_MAGIC = 0x73636673
SEEK_CUR = 0x1 SEEK_CUR = 0x1
@ -3021,6 +3108,7 @@ const (
SOL_TIPC = 0x10f SOL_TIPC = 0x10f
SOL_TLS = 0x11a SOL_TLS = 0x11a
SOL_UDP = 0x11 SOL_UDP = 0x11
SOL_VSOCK = 0x11f
SOL_X25 = 0x106 SOL_X25 = 0x106
SOL_XDP = 0x11b SOL_XDP = 0x11b
SOMAXCONN = 0x1000 SOMAXCONN = 0x1000

View File

@ -281,6 +281,9 @@ const (
SCM_TIMESTAMPNS = 0x23 SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29 SCM_WIFI_STATUS = 0x29
SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103
SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102
SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104
SFD_CLOEXEC = 0x80000 SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800 SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905 SIOCATMARK = 0x8905

View File

@ -282,6 +282,9 @@ const (
SCM_TIMESTAMPNS = 0x23 SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29 SCM_WIFI_STATUS = 0x29
SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103
SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102
SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104
SFD_CLOEXEC = 0x80000 SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800 SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905 SIOCATMARK = 0x8905

View File

@ -288,6 +288,9 @@ const (
SCM_TIMESTAMPNS = 0x23 SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29 SCM_WIFI_STATUS = 0x29
SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103
SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102
SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104
SFD_CLOEXEC = 0x80000 SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800 SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905 SIOCATMARK = 0x8905

View File

@ -278,6 +278,9 @@ const (
SCM_TIMESTAMPNS = 0x23 SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29 SCM_WIFI_STATUS = 0x29
SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103
SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102
SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104
SFD_CLOEXEC = 0x80000 SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800 SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905 SIOCATMARK = 0x8905

View File

@ -275,6 +275,9 @@ const (
SCM_TIMESTAMPNS = 0x23 SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29 SCM_WIFI_STATUS = 0x29
SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103
SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102
SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104
SFD_CLOEXEC = 0x80000 SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800 SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905 SIOCATMARK = 0x8905

View File

@ -281,6 +281,9 @@ const (
SCM_TIMESTAMPNS = 0x23 SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29 SCM_WIFI_STATUS = 0x29
SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x80000 SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x80 SFD_NONBLOCK = 0x80
SIOCATMARK = 0x40047307 SIOCATMARK = 0x40047307

View File

@ -281,6 +281,9 @@ const (
SCM_TIMESTAMPNS = 0x23 SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29 SCM_WIFI_STATUS = 0x29
SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x80000 SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x80 SFD_NONBLOCK = 0x80
SIOCATMARK = 0x40047307 SIOCATMARK = 0x40047307

View File

@ -281,6 +281,9 @@ const (
SCM_TIMESTAMPNS = 0x23 SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29 SCM_WIFI_STATUS = 0x29
SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x80000 SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x80 SFD_NONBLOCK = 0x80
SIOCATMARK = 0x40047307 SIOCATMARK = 0x40047307

View File

@ -281,6 +281,9 @@ const (
SCM_TIMESTAMPNS = 0x23 SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29 SCM_WIFI_STATUS = 0x29
SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x80000 SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x80 SFD_NONBLOCK = 0x80
SIOCATMARK = 0x40047307 SIOCATMARK = 0x40047307

View File

@ -336,6 +336,9 @@ const (
SCM_TIMESTAMPNS = 0x23 SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29 SCM_WIFI_STATUS = 0x29
SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x80000 SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800 SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905 SIOCATMARK = 0x8905

View File

@ -340,6 +340,9 @@ const (
SCM_TIMESTAMPNS = 0x23 SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29 SCM_WIFI_STATUS = 0x29
SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x80000 SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800 SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905 SIOCATMARK = 0x8905

View File

@ -340,6 +340,9 @@ const (
SCM_TIMESTAMPNS = 0x23 SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29 SCM_WIFI_STATUS = 0x29
SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x80000 SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800 SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905 SIOCATMARK = 0x8905

View File

@ -272,6 +272,9 @@ const (
SCM_TIMESTAMPNS = 0x23 SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29 SCM_WIFI_STATUS = 0x29
SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103
SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102
SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104
SFD_CLOEXEC = 0x80000 SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800 SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905 SIOCATMARK = 0x8905

View File

@ -344,6 +344,9 @@ const (
SCM_TIMESTAMPNS = 0x23 SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29 SCM_WIFI_STATUS = 0x29
SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103
SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102
SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104
SFD_CLOEXEC = 0x80000 SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800 SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905 SIOCATMARK = 0x8905

View File

@ -335,6 +335,9 @@ const (
SCM_TIMESTAMPNS = 0x21 SCM_TIMESTAMPNS = 0x21
SCM_TXTIME = 0x3f SCM_TXTIME = 0x3f
SCM_WIFI_STATUS = 0x25 SCM_WIFI_STATUS = 0x25
SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x400000 SFD_CLOEXEC = 0x400000
SFD_NONBLOCK = 0x4000 SFD_NONBLOCK = 0x4000
SF_FP = 0x38 SF_FP = 0x38

View File

@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so" //go:cgo_import_dynamic libc_unveil unveil "libc.so"

View File

@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so" //go:cgo_import_dynamic libc_unveil unveil "libc.so"

View File

@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so" //go:cgo_import_dynamic libc_unveil unveil "libc.so"

View File

@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so" //go:cgo_import_dynamic libc_unveil unveil "libc.so"

View File

@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so" //go:cgo_import_dynamic libc_unveil unveil "libc.so"

View File

@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so" //go:cgo_import_dynamic libc_unveil unveil "libc.so"

View File

@ -2297,5 +2297,3 @@ func unveil(path *byte, flags *byte) (err error) {
var libc_unveil_trampoline_addr uintptr var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so" //go:cgo_import_dynamic libc_unveil unveil "libc.so"

View File

@ -448,4 +448,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 450 SYS_SET_MEMPOLICY_HOME_NODE = 450
SYS_CACHESTAT = 451 SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452 SYS_FCHMODAT2 = 452
SYS_MAP_SHADOW_STACK = 453
SYS_FUTEX_WAKE = 454
SYS_FUTEX_WAIT = 455
SYS_FUTEX_REQUEUE = 456
) )

View File

@ -371,4 +371,7 @@ const (
SYS_CACHESTAT = 451 SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452 SYS_FCHMODAT2 = 452
SYS_MAP_SHADOW_STACK = 453 SYS_MAP_SHADOW_STACK = 453
SYS_FUTEX_WAKE = 454
SYS_FUTEX_WAIT = 455
SYS_FUTEX_REQUEUE = 456
) )

View File

@ -412,4 +412,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 450 SYS_SET_MEMPOLICY_HOME_NODE = 450
SYS_CACHESTAT = 451 SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452 SYS_FCHMODAT2 = 452
SYS_MAP_SHADOW_STACK = 453
SYS_FUTEX_WAKE = 454
SYS_FUTEX_WAIT = 455
SYS_FUTEX_REQUEUE = 456
) )

View File

@ -315,4 +315,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 450 SYS_SET_MEMPOLICY_HOME_NODE = 450
SYS_CACHESTAT = 451 SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452 SYS_FCHMODAT2 = 452
SYS_MAP_SHADOW_STACK = 453
SYS_FUTEX_WAKE = 454
SYS_FUTEX_WAIT = 455
SYS_FUTEX_REQUEUE = 456
) )

View File

@ -309,4 +309,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 450 SYS_SET_MEMPOLICY_HOME_NODE = 450
SYS_CACHESTAT = 451 SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452 SYS_FCHMODAT2 = 452
SYS_MAP_SHADOW_STACK = 453
SYS_FUTEX_WAKE = 454
SYS_FUTEX_WAIT = 455
SYS_FUTEX_REQUEUE = 456
) )

View File

@ -432,4 +432,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 4450 SYS_SET_MEMPOLICY_HOME_NODE = 4450
SYS_CACHESTAT = 4451 SYS_CACHESTAT = 4451
SYS_FCHMODAT2 = 4452 SYS_FCHMODAT2 = 4452
SYS_MAP_SHADOW_STACK = 4453
SYS_FUTEX_WAKE = 4454
SYS_FUTEX_WAIT = 4455
SYS_FUTEX_REQUEUE = 4456
) )

View File

@ -362,4 +362,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 5450 SYS_SET_MEMPOLICY_HOME_NODE = 5450
SYS_CACHESTAT = 5451 SYS_CACHESTAT = 5451
SYS_FCHMODAT2 = 5452 SYS_FCHMODAT2 = 5452
SYS_MAP_SHADOW_STACK = 5453
SYS_FUTEX_WAKE = 5454
SYS_FUTEX_WAIT = 5455
SYS_FUTEX_REQUEUE = 5456
) )

View File

@ -362,4 +362,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 5450 SYS_SET_MEMPOLICY_HOME_NODE = 5450
SYS_CACHESTAT = 5451 SYS_CACHESTAT = 5451
SYS_FCHMODAT2 = 5452 SYS_FCHMODAT2 = 5452
SYS_MAP_SHADOW_STACK = 5453
SYS_FUTEX_WAKE = 5454
SYS_FUTEX_WAIT = 5455
SYS_FUTEX_REQUEUE = 5456
) )

View File

@ -432,4 +432,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 4450 SYS_SET_MEMPOLICY_HOME_NODE = 4450
SYS_CACHESTAT = 4451 SYS_CACHESTAT = 4451
SYS_FCHMODAT2 = 4452 SYS_FCHMODAT2 = 4452
SYS_MAP_SHADOW_STACK = 4453
SYS_FUTEX_WAKE = 4454
SYS_FUTEX_WAIT = 4455
SYS_FUTEX_REQUEUE = 4456
) )

View File

@ -439,4 +439,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 450 SYS_SET_MEMPOLICY_HOME_NODE = 450
SYS_CACHESTAT = 451 SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452 SYS_FCHMODAT2 = 452
SYS_MAP_SHADOW_STACK = 453
SYS_FUTEX_WAKE = 454
SYS_FUTEX_WAIT = 455
SYS_FUTEX_REQUEUE = 456
) )

View File

@ -411,4 +411,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 450 SYS_SET_MEMPOLICY_HOME_NODE = 450
SYS_CACHESTAT = 451 SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452 SYS_FCHMODAT2 = 452
SYS_MAP_SHADOW_STACK = 453
SYS_FUTEX_WAKE = 454
SYS_FUTEX_WAIT = 455
SYS_FUTEX_REQUEUE = 456
) )

View File

@ -411,4 +411,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 450 SYS_SET_MEMPOLICY_HOME_NODE = 450
SYS_CACHESTAT = 451 SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452 SYS_FCHMODAT2 = 452
SYS_MAP_SHADOW_STACK = 453
SYS_FUTEX_WAKE = 454
SYS_FUTEX_WAIT = 455
SYS_FUTEX_REQUEUE = 456
) )

View File

@ -316,4 +316,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 450 SYS_SET_MEMPOLICY_HOME_NODE = 450
SYS_CACHESTAT = 451 SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452 SYS_FCHMODAT2 = 452
SYS_MAP_SHADOW_STACK = 453
SYS_FUTEX_WAKE = 454
SYS_FUTEX_WAIT = 455
SYS_FUTEX_REQUEUE = 456
) )

View File

@ -377,4 +377,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 450 SYS_SET_MEMPOLICY_HOME_NODE = 450
SYS_CACHESTAT = 451 SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452 SYS_FCHMODAT2 = 452
SYS_MAP_SHADOW_STACK = 453
SYS_FUTEX_WAKE = 454
SYS_FUTEX_WAIT = 455
SYS_FUTEX_REQUEUE = 456
) )

View File

@ -390,4 +390,8 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 450 SYS_SET_MEMPOLICY_HOME_NODE = 450
SYS_CACHESTAT = 451 SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452 SYS_FCHMODAT2 = 452
SYS_MAP_SHADOW_STACK = 453
SYS_FUTEX_WAKE = 454
SYS_FUTEX_WAIT = 455
SYS_FUTEX_REQUEUE = 456
) )

View File

@ -174,7 +174,8 @@ type FscryptPolicyV2 struct {
Contents_encryption_mode uint8 Contents_encryption_mode uint8
Filenames_encryption_mode uint8 Filenames_encryption_mode uint8
Flags uint8 Flags uint8
_ [4]uint8 Log2_data_unit_size uint8
_ [3]uint8
Master_key_identifier [16]uint8 Master_key_identifier [16]uint8
} }
@ -509,6 +510,9 @@ type TCPInfo struct {
Snd_wnd uint32 Snd_wnd uint32
Rcv_wnd uint32 Rcv_wnd uint32
Rehash uint32 Rehash uint32
Total_rto uint16
Total_rto_recoveries uint16
Total_rto_time uint32
} }
type CanFilter struct { type CanFilter struct {
@ -551,7 +555,7 @@ const (
SizeofIPv6MTUInfo = 0x20 SizeofIPv6MTUInfo = 0x20
SizeofICMPv6Filter = 0x20 SizeofICMPv6Filter = 0x20
SizeofUcred = 0xc SizeofUcred = 0xc
SizeofTCPInfo = 0xf0 SizeofTCPInfo = 0xf8
SizeofCanFilter = 0x8 SizeofCanFilter = 0x8
SizeofTCPRepairOpt = 0x8 SizeofTCPRepairOpt = 0x8
) )
@ -3399,7 +3403,7 @@ const (
DEVLINK_PORT_FN_ATTR_STATE = 0x2 DEVLINK_PORT_FN_ATTR_STATE = 0x2
DEVLINK_PORT_FN_ATTR_OPSTATE = 0x3 DEVLINK_PORT_FN_ATTR_OPSTATE = 0x3
DEVLINK_PORT_FN_ATTR_CAPS = 0x4 DEVLINK_PORT_FN_ATTR_CAPS = 0x4
DEVLINK_PORT_FUNCTION_ATTR_MAX = 0x4 DEVLINK_PORT_FUNCTION_ATTR_MAX = 0x5
) )
type FsverityDigest struct { type FsverityDigest struct {
@ -4184,6 +4188,7 @@ const (
type LandlockRulesetAttr struct { type LandlockRulesetAttr struct {
Access_fs uint64 Access_fs uint64
Access_net uint64
} }
type LandlockPathBeneathAttr struct { type LandlockPathBeneathAttr struct {
@ -5134,7 +5139,7 @@ const (
NL80211_FREQUENCY_ATTR_GO_CONCURRENT = 0xf NL80211_FREQUENCY_ATTR_GO_CONCURRENT = 0xf
NL80211_FREQUENCY_ATTR_INDOOR_ONLY = 0xe NL80211_FREQUENCY_ATTR_INDOOR_ONLY = 0xe
NL80211_FREQUENCY_ATTR_IR_CONCURRENT = 0xf NL80211_FREQUENCY_ATTR_IR_CONCURRENT = 0xf
NL80211_FREQUENCY_ATTR_MAX = 0x1b NL80211_FREQUENCY_ATTR_MAX = 0x1c
NL80211_FREQUENCY_ATTR_MAX_TX_POWER = 0x6 NL80211_FREQUENCY_ATTR_MAX_TX_POWER = 0x6
NL80211_FREQUENCY_ATTR_NO_10MHZ = 0x11 NL80211_FREQUENCY_ATTR_NO_10MHZ = 0x11
NL80211_FREQUENCY_ATTR_NO_160MHZ = 0xc NL80211_FREQUENCY_ATTR_NO_160MHZ = 0xc
@ -5547,7 +5552,7 @@ const (
NL80211_REGDOM_TYPE_CUSTOM_WORLD = 0x2 NL80211_REGDOM_TYPE_CUSTOM_WORLD = 0x2
NL80211_REGDOM_TYPE_INTERSECTION = 0x3 NL80211_REGDOM_TYPE_INTERSECTION = 0x3
NL80211_REGDOM_TYPE_WORLD = 0x1 NL80211_REGDOM_TYPE_WORLD = 0x1
NL80211_REG_RULE_ATTR_MAX = 0x7 NL80211_REG_RULE_ATTR_MAX = 0x8
NL80211_REKEY_DATA_AKM = 0x4 NL80211_REKEY_DATA_AKM = 0x4
NL80211_REKEY_DATA_KCK = 0x2 NL80211_REKEY_DATA_KCK = 0x2
NL80211_REKEY_DATA_KEK = 0x1 NL80211_REKEY_DATA_KEK = 0x1

View File

@ -37,14 +37,17 @@ func (token Token) Environ(inheritExisting bool) (env []string, err error) {
return nil, err return nil, err
} }
defer DestroyEnvironmentBlock(block) defer DestroyEnvironmentBlock(block)
blockp := unsafe.Pointer(block) size := unsafe.Sizeof(*block)
for { for *block != 0 {
entry := UTF16PtrToString((*uint16)(blockp)) // find NUL terminator
if len(entry) == 0 { end := unsafe.Pointer(block)
break for *(*uint16)(end) != 0 {
end = unsafe.Add(end, size)
} }
env = append(env, entry)
blockp = unsafe.Add(blockp, 2*(len(entry)+1)) entry := unsafe.Slice(block, (uintptr(end)-uintptr(unsafe.Pointer(block)))/size)
env = append(env, UTF16ToString(entry))
block = (*uint16)(unsafe.Add(end, size))
} }
return env, nil return env, nil
} }

View File

@ -125,8 +125,7 @@ func UTF16PtrToString(p *uint16) string {
for ptr := unsafe.Pointer(p); *(*uint16)(ptr) != 0; n++ { for ptr := unsafe.Pointer(p); *(*uint16)(ptr) != 0; n++ {
ptr = unsafe.Pointer(uintptr(ptr) + unsafe.Sizeof(*p)) ptr = unsafe.Pointer(uintptr(ptr) + unsafe.Sizeof(*p))
} }
return UTF16ToString(unsafe.Slice(p, n))
return string(utf16.Decode(unsafe.Slice(p, n)))
} }
func Getpagesize() int { return 4096 } func Getpagesize() int { return 4096 }
@ -194,6 +193,7 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys GetComputerName(buf *uint16, n *uint32) (err error) = GetComputerNameW //sys GetComputerName(buf *uint16, n *uint32) (err error) = GetComputerNameW
//sys GetComputerNameEx(nametype uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW //sys GetComputerNameEx(nametype uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW
//sys SetEndOfFile(handle Handle) (err error) //sys SetEndOfFile(handle Handle) (err error)
//sys SetFileValidData(handle Handle, validDataLength int64) (err error)
//sys GetSystemTimeAsFileTime(time *Filetime) //sys GetSystemTimeAsFileTime(time *Filetime)
//sys GetSystemTimePreciseAsFileTime(time *Filetime) //sys GetSystemTimePreciseAsFileTime(time *Filetime)
//sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) [failretval==0xffffffff] //sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) [failretval==0xffffffff]

View File

@ -342,6 +342,7 @@ var (
procSetDefaultDllDirectories = modkernel32.NewProc("SetDefaultDllDirectories") procSetDefaultDllDirectories = modkernel32.NewProc("SetDefaultDllDirectories")
procSetDllDirectoryW = modkernel32.NewProc("SetDllDirectoryW") procSetDllDirectoryW = modkernel32.NewProc("SetDllDirectoryW")
procSetEndOfFile = modkernel32.NewProc("SetEndOfFile") procSetEndOfFile = modkernel32.NewProc("SetEndOfFile")
procSetFileValidData = modkernel32.NewProc("SetFileValidData")
procSetEnvironmentVariableW = modkernel32.NewProc("SetEnvironmentVariableW") procSetEnvironmentVariableW = modkernel32.NewProc("SetEnvironmentVariableW")
procSetErrorMode = modkernel32.NewProc("SetErrorMode") procSetErrorMode = modkernel32.NewProc("SetErrorMode")
procSetEvent = modkernel32.NewProc("SetEvent") procSetEvent = modkernel32.NewProc("SetEvent")
@ -2988,6 +2989,14 @@ func SetEndOfFile(handle Handle) (err error) {
return return
} }
func SetFileValidData(handle Handle, validDataLength int64) (err error) {
r1, _, e1 := syscall.Syscall(procSetFileValidData.Addr(), 2, uintptr(handle), uintptr(validDataLength), 0)
if r1 == 0 {
err = errnoErr(e1)
}
return
}
func SetEnvironmentVariable(name *uint16, value *uint16) (err error) { func SetEnvironmentVariable(name *uint16, value *uint16) (err error) {
r1, _, e1 := syscall.Syscall(procSetEnvironmentVariableW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), 0) r1, _, e1 := syscall.Syscall(procSetEnvironmentVariableW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), 0)
if r1 == 0 { if r1 == 0 {

View File

@ -9,11 +9,13 @@ package gopathwalk
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"io"
"io/fs" "io/fs"
"log"
"os" "os"
"path/filepath" "path/filepath"
"runtime"
"strings" "strings"
"sync"
"time" "time"
) )
@ -21,8 +23,13 @@ import (
type Options struct { type Options struct {
// If Logf is non-nil, debug logging is enabled through this function. // If Logf is non-nil, debug logging is enabled through this function.
Logf func(format string, args ...interface{}) Logf func(format string, args ...interface{})
// Search module caches. Also disables legacy goimports ignore rules. // Search module caches. Also disables legacy goimports ignore rules.
ModulesEnabled bool ModulesEnabled bool
// Maximum number of concurrent calls to user-provided callbacks,
// or 0 for GOMAXPROCS.
Concurrency int
} }
// RootType indicates the type of a Root. // RootType indicates the type of a Root.
@ -43,19 +50,28 @@ type Root struct {
Type RootType Type RootType
} }
// Walk walks Go source directories ($GOROOT, $GOPATH, etc) to find packages. // Walk concurrently walks Go source directories ($GOROOT, $GOPATH, etc) to find packages.
//
// For each package found, add will be called with the absolute // For each package found, add will be called with the absolute
// paths of the containing source directory and the package directory. // paths of the containing source directory and the package directory.
//
// Unlike filepath.WalkDir, Walk follows symbolic links
// (while guarding against cycles).
func Walk(roots []Root, add func(root Root, dir string), opts Options) { func Walk(roots []Root, add func(root Root, dir string), opts Options) {
WalkSkip(roots, add, func(Root, string) bool { return false }, opts) WalkSkip(roots, add, func(Root, string) bool { return false }, opts)
} }
// WalkSkip walks Go source directories ($GOROOT, $GOPATH, etc) to find packages. // WalkSkip concurrently walks Go source directories ($GOROOT, $GOPATH, etc) to
// find packages.
//
// For each package found, add will be called with the absolute // For each package found, add will be called with the absolute
// paths of the containing source directory and the package directory. // paths of the containing source directory and the package directory.
// For each directory that will be scanned, skip will be called // For each directory that will be scanned, skip will be called
// with the absolute paths of the containing source directory and the directory. // with the absolute paths of the containing source directory and the directory.
// If skip returns false on a directory it will be processed. // If skip returns false on a directory it will be processed.
//
// Unlike filepath.WalkDir, WalkSkip follows symbolic links
// (while guarding against cycles).
func WalkSkip(roots []Root, add func(root Root, dir string), skip func(root Root, dir string) bool, opts Options) { func WalkSkip(roots []Root, add func(root Root, dir string), skip func(root Root, dir string) bool, opts Options) {
for _, root := range roots { for _, root := range roots {
walkDir(root, add, skip, opts) walkDir(root, add, skip, opts)
@ -64,46 +80,52 @@ func WalkSkip(roots []Root, add func(root Root, dir string), skip func(root Root
// walkDir creates a walker and starts fastwalk with this walker. // walkDir creates a walker and starts fastwalk with this walker.
func walkDir(root Root, add func(Root, string), skip func(root Root, dir string) bool, opts Options) { func walkDir(root Root, add func(Root, string), skip func(root Root, dir string) bool, opts Options) {
if _, err := os.Stat(root.Path); os.IsNotExist(err) { if opts.Logf == nil {
if opts.Logf != nil { opts.Logf = func(format string, args ...interface{}) {}
opts.Logf("skipping nonexistent directory: %v", root.Path)
} }
if _, err := os.Stat(root.Path); os.IsNotExist(err) {
opts.Logf("skipping nonexistent directory: %v", root.Path)
return return
} }
start := time.Now() start := time.Now()
if opts.Logf != nil {
opts.Logf("scanning %s", root.Path) opts.Logf("scanning %s", root.Path)
}
concurrency := opts.Concurrency
if concurrency == 0 {
// The walk be either CPU-bound or I/O-bound, depending on what the
// caller-supplied add function does and the details of the user's platform
// and machine. Rather than trying to fine-tune the concurrency level for a
// specific environment, we default to GOMAXPROCS: it is likely to be a good
// choice for a CPU-bound add function, and if it is instead I/O-bound, then
// dealing with I/O saturation is arguably the job of the kernel and/or
// runtime. (Oversaturating I/O seems unlikely to harm performance as badly
// as failing to saturate would.)
concurrency = runtime.GOMAXPROCS(0)
}
w := &walker{ w := &walker{
root: root, root: root,
add: add, add: add,
skip: skip, skip: skip,
opts: opts, opts: opts,
added: make(map[string]bool), sem: make(chan struct{}, concurrency),
} }
w.init() w.init()
// Add a trailing path separator to cause filepath.WalkDir to traverse symlinks. w.sem <- struct{}{}
path := root.Path path := root.Path
if len(path) == 0 { if path == "" {
path = "." + string(filepath.Separator) path = "."
} else if !os.IsPathSeparator(path[len(path)-1]) {
path = path + string(filepath.Separator)
} }
if fi, err := os.Lstat(path); err == nil {
w.walk(path, nil, fs.FileInfoToDirEntry(fi))
} else {
w.opts.Logf("scanning directory %v: %v", root.Path, err)
}
<-w.sem
w.walking.Wait()
if err := filepath.WalkDir(path, w.walk); err != nil {
logf := opts.Logf
if logf == nil {
logf = log.Printf
}
logf("scanning directory %v: %v", root.Path, err)
}
if opts.Logf != nil {
opts.Logf("scanned %s in %v", root.Path, time.Since(start)) opts.Logf("scanned %s in %v", root.Path, time.Since(start))
} }
}
// walker is the callback for fastwalk.Walk. // walker is the callback for fastwalk.Walk.
type walker struct { type walker struct {
@ -112,10 +134,18 @@ type walker struct {
skip func(Root, string) bool // The callback that will be invoked for every dir. dir is skipped if it returns true. skip func(Root, string) bool // The callback that will be invoked for every dir. dir is skipped if it returns true.
opts Options // Options passed to Walk by the user. opts Options // Options passed to Walk by the user.
pathSymlinks []os.FileInfo walking sync.WaitGroup
sem chan struct{} // Channel of semaphore tokens; send to acquire, receive to release.
ignoredDirs []string ignoredDirs []string
added map[string]bool added sync.Map // map[string]bool
}
// A symlinkList is a linked list of os.FileInfos for parent directories
// reached via symlinks.
type symlinkList struct {
info os.FileInfo
prev *symlinkList
} }
// init initializes the walker based on its Options // init initializes the walker based on its Options
@ -132,11 +162,9 @@ func (w *walker) init() {
for _, p := range ignoredPaths { for _, p := range ignoredPaths {
full := filepath.Join(w.root.Path, p) full := filepath.Join(w.root.Path, p)
w.ignoredDirs = append(w.ignoredDirs, full) w.ignoredDirs = append(w.ignoredDirs, full)
if w.opts.Logf != nil {
w.opts.Logf("Directory added to ignore list: %s", full) w.opts.Logf("Directory added to ignore list: %s", full)
} }
} }
}
// getIgnoredDirs reads an optional config file at <path>/.goimportsignore // getIgnoredDirs reads an optional config file at <path>/.goimportsignore
// of relative directories to ignore when scanning for go files. // of relative directories to ignore when scanning for go files.
@ -144,13 +172,11 @@ func (w *walker) init() {
func (w *walker) getIgnoredDirs(path string) []string { func (w *walker) getIgnoredDirs(path string) []string {
file := filepath.Join(path, ".goimportsignore") file := filepath.Join(path, ".goimportsignore")
slurp, err := os.ReadFile(file) slurp, err := os.ReadFile(file)
if w.opts.Logf != nil {
if err != nil { if err != nil {
w.opts.Logf("%v", err) w.opts.Logf("%v", err)
} else { } else {
w.opts.Logf("Read %s", file) w.opts.Logf("Read %s", file)
} }
}
if err != nil { if err != nil {
return nil return nil
} }
@ -183,63 +209,22 @@ func (w *walker) shouldSkipDir(dir string) bool {
// walk walks through the given path. // walk walks through the given path.
// //
// Errors are logged if w.opts.Logf is non-nil, but otherwise ignored: // Errors are logged if w.opts.Logf is non-nil, but otherwise ignored.
// walk returns only nil or fs.SkipDir. func (w *walker) walk(path string, pathSymlinks *symlinkList, d fs.DirEntry) {
func (w *walker) walk(path string, d fs.DirEntry, err error) error {
if err != nil {
// We have no way to report errors back through Walk or WalkSkip,
// so just log and ignore them.
if w.opts.Logf != nil {
w.opts.Logf("%v", err)
}
if d == nil {
// Nothing more to do: the error prevents us from knowing
// what path even represents.
return nil
}
}
if d.Type().IsRegular() {
if !strings.HasSuffix(path, ".go") {
return nil
}
dir := filepath.Dir(path)
if dir == w.root.Path && (w.root.Type == RootGOROOT || w.root.Type == RootGOPATH) {
// Doesn't make sense to have regular files
// directly in your $GOPATH/src or $GOROOT/src.
return nil
}
if !w.added[dir] {
w.add(w.root, dir)
w.added[dir] = true
}
return nil
}
if d.IsDir() {
base := filepath.Base(path)
if base == "" || base[0] == '.' || base[0] == '_' ||
base == "testdata" ||
(w.root.Type == RootGOROOT && w.opts.ModulesEnabled && base == "vendor") ||
(!w.opts.ModulesEnabled && base == "node_modules") {
return fs.SkipDir
}
if w.shouldSkipDir(path) {
return fs.SkipDir
}
return nil
}
if d.Type()&os.ModeSymlink != 0 { if d.Type()&os.ModeSymlink != 0 {
// Walk the symlink's target rather than the symlink itself.
//
// (Note that os.Stat, unlike the lower-lever os.Readlink,
// follows arbitrarily many layers of symlinks, so it will eventually
// reach either a non-symlink or a nonexistent target.)
//
// TODO(bcmills): 'go list all' itself ignores symlinks within GOROOT/src // TODO(bcmills): 'go list all' itself ignores symlinks within GOROOT/src
// and GOPATH/src. Do we really need to traverse them here? If so, why? // and GOPATH/src. Do we really need to traverse them here? If so, why?
fi, err := os.Stat(path) fi, err := os.Stat(path)
if err != nil || !fi.IsDir() { if err != nil {
// Not a directory. Just walk the file (or broken link) and be done. w.opts.Logf("%v", err)
return w.walk(path, fs.FileInfoToDirEntry(fi), err) return
} }
// Avoid walking symlink cycles: if we have already followed a symlink to // Avoid walking symlink cycles: if we have already followed a symlink to
@ -249,83 +234,104 @@ func (w *walker) walk(path string, d fs.DirEntry, err error) error {
// the number of extra stat calls we make if we *don't* encounter a cycle. // the number of extra stat calls we make if we *don't* encounter a cycle.
// Since we don't actually expect to encounter symlink cycles in practice, // Since we don't actually expect to encounter symlink cycles in practice,
// this seems like the right tradeoff. // this seems like the right tradeoff.
for _, parent := range w.pathSymlinks { for parent := pathSymlinks; parent != nil; parent = parent.prev {
if os.SameFile(fi, parent) { if os.SameFile(fi, parent.info) {
return nil return
} }
} }
w.pathSymlinks = append(w.pathSymlinks, fi) pathSymlinks = &symlinkList{
defer func() { info: fi,
w.pathSymlinks = w.pathSymlinks[:len(w.pathSymlinks)-1] prev: pathSymlinks,
}() }
d = fs.FileInfoToDirEntry(fi)
// On some platforms the OS (or the Go os package) sometimes fails to
// resolve directory symlinks before a trailing slash
// (even though POSIX requires it to do so).
//
// On macOS that failure may be caused by a known libc/kernel bug;
// see https://go.dev/issue/59586.
//
// On Windows before Go 1.21, it may be caused by a bug in
// os.Lstat (fixed in https://go.dev/cl/463177).
//
// Since we need to handle this explicitly on broken platforms anyway,
// it is simplest to just always do that and not rely on POSIX pathname
// resolution to walk the directory (such as by calling WalkDir with
// a trailing slash appended to the path).
//
// Instead, we make a sequence of walk calls — directly and through
// recursive calls to filepath.WalkDir — simulating what WalkDir would do
// if the symlink were a regular directory.
// First we call walk on the path as a directory
// (instead of a symlink).
err = w.walk(path, fs.FileInfoToDirEntry(fi), nil)
if err == fs.SkipDir {
return nil
} else if err != nil {
// This should be impossible, but handle it anyway in case
// walk is changed to return other errors.
return err
} }
// Now read the directory and walk its entries. if d.Type().IsRegular() {
ents, err := os.ReadDir(path) if !strings.HasSuffix(path, ".go") {
return
}
dir := filepath.Dir(path)
if dir == w.root.Path && (w.root.Type == RootGOROOT || w.root.Type == RootGOPATH) {
// Doesn't make sense to have regular files
// directly in your $GOPATH/src or $GOROOT/src.
//
// TODO(bcmills): there are many levels of directory within
// RootModuleCache where this also wouldn't make sense,
// Can we generalize this to any directory without a corresponding
// import path?
return
}
if _, dup := w.added.LoadOrStore(dir, true); !dup {
w.add(w.root, dir)
}
}
if !d.IsDir() {
return
}
base := filepath.Base(path)
if base == "" || base[0] == '.' || base[0] == '_' ||
base == "testdata" ||
(w.root.Type == RootGOROOT && w.opts.ModulesEnabled && base == "vendor") ||
(!w.opts.ModulesEnabled && base == "node_modules") ||
w.shouldSkipDir(path) {
return
}
// Read the directory and walk its entries.
f, err := os.Open(path)
if err != nil { if err != nil {
// Report the ReadDir error, as filepath.WalkDir would do. w.opts.Logf("%v", err)
err = w.walk(path, fs.FileInfoToDirEntry(fi), err) return
if err == fs.SkipDir {
return nil
} else if err != nil {
return err // Again, should be impossible.
} }
// Fall through and iterate over whatever entries we did manage to get. defer f.Close()
for {
// We impose an arbitrary limit on the number of ReadDir results per
// directory to limit the amount of memory consumed for stale or upcoming
// directory entries. The limit trades off CPU (number of syscalls to read
// the whole directory) against RAM (reachable directory entries other than
// the one currently being processed).
//
// Since we process the directories recursively, we will end up maintaining
// a slice of entries for each level of the directory tree.
// (Compare https://go.dev/issue/36197.)
ents, err := f.ReadDir(1024)
if err != nil {
if err != io.EOF {
w.opts.Logf("%v", err)
}
break
} }
for _, d := range ents { for _, d := range ents {
nextPath := filepath.Join(path, d.Name()) nextPath := filepath.Join(path, d.Name())
if d.IsDir() { if d.IsDir() {
// We want to walk the whole directory tree rooted at nextPath, select {
// not just the single entry for the directory. case w.sem <- struct{}{}:
err := filepath.WalkDir(nextPath, w.walk) // Got a new semaphore token, so we can traverse the directory concurrently.
if err != nil && w.opts.Logf != nil { d := d
w.opts.Logf("%v", err) w.walking.Add(1)
go func() {
defer func() {
<-w.sem
w.walking.Done()
}()
w.walk(nextPath, pathSymlinks, d)
}()
continue
default:
// No tokens available, so traverse serially.
} }
} else {
err := w.walk(nextPath, d, nil)
if err == fs.SkipDir {
// Skip the rest of the entries in the parent directory of nextPath
// (that is, path itself).
break
} else if err != nil {
return err // Again, should be impossible.
}
}
}
return nil
} }
// Not a file, regular directory, or symlink; skip. w.walk(nextPath, pathSymlinks, d)
return nil }
}
} }

View File

@ -13,6 +13,7 @@ import (
"go/build" "go/build"
"go/parser" "go/parser"
"go/token" "go/token"
"go/types"
"io/fs" "io/fs"
"io/ioutil" "io/ioutil"
"os" "os"
@ -700,20 +701,21 @@ func ScoreImportPaths(ctx context.Context, env *ProcessEnv, paths []string) (map
return result, nil return result, nil
} }
func PrimeCache(ctx context.Context, env *ProcessEnv) error { func PrimeCache(ctx context.Context, resolver Resolver) error {
// Fully scan the disk for directories, but don't actually read any Go files. // Fully scan the disk for directories, but don't actually read any Go files.
callback := &scanCallback{ callback := &scanCallback{
rootFound: func(gopathwalk.Root) bool { rootFound: func(root gopathwalk.Root) bool {
return true // See getCandidatePkgs: walking GOROOT is apparently expensive and
// unnecessary.
return root.Type != gopathwalk.RootGOROOT
}, },
dirFound: func(pkg *pkg) bool { dirFound: func(pkg *pkg) bool {
return false return false
}, },
packageNameLoaded: func(pkg *pkg) bool { // packageNameLoaded and exportsLoaded must never be called.
return false
},
} }
return getCandidatePkgs(ctx, callback, "", "", env)
return resolver.scan(ctx, callback)
} }
func candidateImportName(pkg *pkg) string { func candidateImportName(pkg *pkg) string {
@ -827,16 +829,45 @@ func GetPackageExports(ctx context.Context, wrapped func(PackageExport), searchP
return getCandidatePkgs(ctx, callback, filename, filePkg, env) return getCandidatePkgs(ctx, callback, filename, filePkg, env)
} }
var requiredGoEnvVars = []string{"GO111MODULE", "GOFLAGS", "GOINSECURE", "GOMOD", "GOMODCACHE", "GONOPROXY", "GONOSUMDB", "GOPATH", "GOPROXY", "GOROOT", "GOSUMDB", "GOWORK"} // TODO(rfindley): we should depend on GOOS and GOARCH, to provide accurate
// imports when doing cross-platform development.
var requiredGoEnvVars = []string{
"GO111MODULE",
"GOFLAGS",
"GOINSECURE",
"GOMOD",
"GOMODCACHE",
"GONOPROXY",
"GONOSUMDB",
"GOPATH",
"GOPROXY",
"GOROOT",
"GOSUMDB",
"GOWORK",
}
// ProcessEnv contains environment variables and settings that affect the use of // ProcessEnv contains environment variables and settings that affect the use of
// the go command, the go/build package, etc. // the go command, the go/build package, etc.
//
// ...a ProcessEnv *also* overwrites its Env along with derived state in the
// form of the resolver. And because it is lazily initialized, an env may just
// be broken and unusable, but there is no way for the caller to detect that:
// all queries will just fail.
//
// TODO(rfindley): refactor this package so that this type (perhaps renamed to
// just Env or Config) is an immutable configuration struct, to be exchanged
// for an initialized object via a constructor that returns an error. Perhaps
// the signature should be `func NewResolver(*Env) (*Resolver, error)`, where
// resolver is a concrete type used for resolving imports. Via this
// refactoring, we can avoid the need to call ProcessEnv.init and
// ProcessEnv.GoEnv everywhere, and implicitly fix all the places where this
// these are misused. Also, we'd delegate the caller the decision of how to
// handle a broken environment.
type ProcessEnv struct { type ProcessEnv struct {
GocmdRunner *gocommand.Runner GocmdRunner *gocommand.Runner
BuildFlags []string BuildFlags []string
ModFlag string ModFlag string
ModFile string
// SkipPathInScan returns true if the path should be skipped from scans of // SkipPathInScan returns true if the path should be skipped from scans of
// the RootCurrentModule root type. The function argument is a clean, // the RootCurrentModule root type. The function argument is a clean,
@ -846,7 +877,7 @@ type ProcessEnv struct {
// Env overrides the OS environment, and can be used to specify // Env overrides the OS environment, and can be used to specify
// GOPROXY, GO111MODULE, etc. PATH cannot be set here, because // GOPROXY, GO111MODULE, etc. PATH cannot be set here, because
// exec.Command will not honor it. // exec.Command will not honor it.
// Specifying all of RequiredGoEnvVars avoids a call to `go env`. // Specifying all of requiredGoEnvVars avoids a call to `go env`.
Env map[string]string Env map[string]string
WorkingDir string WorkingDir string
@ -854,9 +885,17 @@ type ProcessEnv struct {
// If Logf is non-nil, debug logging is enabled through this function. // If Logf is non-nil, debug logging is enabled through this function.
Logf func(format string, args ...interface{}) Logf func(format string, args ...interface{})
initialized bool // If set, ModCache holds a shared cache of directory info to use across
// multiple ProcessEnvs.
ModCache *DirInfoCache
initialized bool // see TODO above
// resolver and resolverErr are lazily evaluated (see GetResolver).
// This is unclean, but see the big TODO in the docstring for ProcessEnv
// above: for now, we can't be sure that the ProcessEnv is fully initialized.
resolver Resolver resolver Resolver
resolverErr error
} }
func (e *ProcessEnv) goEnv() (map[string]string, error) { func (e *ProcessEnv) goEnv() (map[string]string, error) {
@ -936,20 +975,31 @@ func (e *ProcessEnv) env() []string {
} }
func (e *ProcessEnv) GetResolver() (Resolver, error) { func (e *ProcessEnv) GetResolver() (Resolver, error) {
if e.resolver != nil {
return e.resolver, nil
}
if err := e.init(); err != nil { if err := e.init(); err != nil {
return nil, err return nil, err
} }
if e.resolver == nil && e.resolverErr == nil {
// TODO(rfindley): we should only use a gopathResolver here if the working
// directory is actually *in* GOPATH. (I seem to recall an open gopls issue
// for this behavior, but I can't find it).
//
// For gopls, we can optionally explicitly choose a resolver type, since we
// already know the view type.
if len(e.Env["GOMOD"]) == 0 && len(e.Env["GOWORK"]) == 0 { if len(e.Env["GOMOD"]) == 0 && len(e.Env["GOWORK"]) == 0 {
e.resolver = newGopathResolver(e) e.resolver = newGopathResolver(e)
return e.resolver, nil } else {
e.resolver, e.resolverErr = newModuleResolver(e, e.ModCache)
} }
e.resolver = newModuleResolver(e)
return e.resolver, nil
} }
return e.resolver, e.resolverErr
}
// buildContext returns the build.Context to use for matching files.
//
// TODO(rfindley): support dynamic GOOS, GOARCH here, when doing cross-platform
// development.
func (e *ProcessEnv) buildContext() (*build.Context, error) { func (e *ProcessEnv) buildContext() (*build.Context, error) {
ctx := build.Default ctx := build.Default
goenv, err := e.goEnv() goenv, err := e.goEnv()
@ -1029,15 +1079,23 @@ func addStdlibCandidates(pass *pass, refs references) error {
type Resolver interface { type Resolver interface {
// loadPackageNames loads the package names in importPaths. // loadPackageNames loads the package names in importPaths.
loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) loadPackageNames(importPaths []string, srcDir string) (map[string]string, error)
// scan works with callback to search for packages. See scanCallback for details. // scan works with callback to search for packages. See scanCallback for details.
scan(ctx context.Context, callback *scanCallback) error scan(ctx context.Context, callback *scanCallback) error
// loadExports returns the set of exported symbols in the package at dir. // loadExports returns the set of exported symbols in the package at dir.
// loadExports may be called concurrently. // loadExports may be called concurrently.
loadExports(ctx context.Context, pkg *pkg, includeTest bool) (string, []string, error) loadExports(ctx context.Context, pkg *pkg, includeTest bool) (string, []string, error)
// scoreImportPath returns the relevance for an import path. // scoreImportPath returns the relevance for an import path.
scoreImportPath(ctx context.Context, path string) float64 scoreImportPath(ctx context.Context, path string) float64
ClearForNewScan() // ClearForNewScan returns a new Resolver based on the receiver that has
// cleared its internal caches of directory contents.
//
// The new resolver should be primed and then set via
// [ProcessEnv.UpdateResolver].
ClearForNewScan() Resolver
} }
// A scanCallback controls a call to scan and receives its results. // A scanCallback controls a call to scan and receives its results.
@ -1120,7 +1178,7 @@ func addExternalCandidates(ctx context.Context, pass *pass, refs references, fil
go func(pkgName string, symbols map[string]bool) { go func(pkgName string, symbols map[string]bool) {
defer wg.Done() defer wg.Done()
found, err := findImport(ctx, pass, found[pkgName], pkgName, symbols, filename) found, err := findImport(ctx, pass, found[pkgName], pkgName, symbols)
if err != nil { if err != nil {
firstErrOnce.Do(func() { firstErrOnce.Do(func() {
@ -1151,6 +1209,17 @@ func addExternalCandidates(ctx context.Context, pass *pass, refs references, fil
}() }()
for result := range results { for result := range results {
// Don't offer completions that would shadow predeclared
// names, such as github.com/coreos/etcd/error.
if types.Universe.Lookup(result.pkg.name) != nil { // predeclared
// Ideally we would skip this candidate only
// if the predeclared name is actually
// referenced by the file, but that's a lot
// trickier to compute and would still create
// an import that is likely to surprise the
// user before long.
continue
}
pass.addCandidate(result.imp, result.pkg) pass.addCandidate(result.imp, result.pkg)
} }
return firstErr return firstErr
@ -1193,31 +1262,22 @@ func ImportPathToAssumedName(importPath string) string {
type gopathResolver struct { type gopathResolver struct {
env *ProcessEnv env *ProcessEnv
walked bool walked bool
cache *dirInfoCache cache *DirInfoCache
scanSema chan struct{} // scanSema prevents concurrent scans. scanSema chan struct{} // scanSema prevents concurrent scans.
} }
func newGopathResolver(env *ProcessEnv) *gopathResolver { func newGopathResolver(env *ProcessEnv) *gopathResolver {
r := &gopathResolver{ r := &gopathResolver{
env: env, env: env,
cache: &dirInfoCache{ cache: NewDirInfoCache(),
dirs: map[string]*directoryPackageInfo{},
listeners: map[*int]cacheListener{},
},
scanSema: make(chan struct{}, 1), scanSema: make(chan struct{}, 1),
} }
r.scanSema <- struct{}{} r.scanSema <- struct{}{}
return r return r
} }
func (r *gopathResolver) ClearForNewScan() { func (r *gopathResolver) ClearForNewScan() Resolver {
<-r.scanSema return newGopathResolver(r.env)
r.cache = &dirInfoCache{
dirs: map[string]*directoryPackageInfo{},
listeners: map[*int]cacheListener{},
}
r.walked = false
r.scanSema <- struct{}{}
} }
func (r *gopathResolver) loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) { func (r *gopathResolver) loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) {
@ -1538,7 +1598,7 @@ func loadExportsFromFiles(ctx context.Context, env *ProcessEnv, dir string, incl
// findImport searches for a package with the given symbols. // findImport searches for a package with the given symbols.
// If no package is found, findImport returns ("", false, nil) // If no package is found, findImport returns ("", false, nil)
func findImport(ctx context.Context, pass *pass, candidates []pkgDistance, pkgName string, symbols map[string]bool, filename string) (*pkg, error) { func findImport(ctx context.Context, pass *pass, candidates []pkgDistance, pkgName string, symbols map[string]bool) (*pkg, error) {
// Sort the candidates by their import package length, // Sort the candidates by their import package length,
// assuming that shorter package names are better than long // assuming that shorter package names are better than long
// ones. Note that this sorts by the de-vendored name, so // ones. Note that this sorts by the de-vendored name, so

View File

@ -236,7 +236,7 @@ func parse(fset *token.FileSet, filename string, src []byte, opt *Options) (*ast
src = src[:len(src)-len("}\n")] src = src[:len(src)-len("}\n")]
// Gofmt has also indented the function body one level. // Gofmt has also indented the function body one level.
// Remove that indent. // Remove that indent.
src = bytes.Replace(src, []byte("\n\t"), []byte("\n"), -1) src = bytes.ReplaceAll(src, []byte("\n\t"), []byte("\n"))
return matchSpace(orig, src) return matchSpace(orig, src)
} }
return file, adjust, nil return file, adjust, nil

View File

@ -23,49 +23,88 @@ import (
"golang.org/x/tools/internal/gopathwalk" "golang.org/x/tools/internal/gopathwalk"
) )
// ModuleResolver implements resolver for modules using the go command as little // Notes(rfindley): ModuleResolver appears to be heavily optimized for scanning
// as feasible. // as fast as possible, which is desirable for a call to goimports from the
// command line, but it doesn't work as well for gopls, where it suffers from
// slow startup (golang/go#44863) and intermittent hanging (golang/go#59216),
// both caused by populating the cache, albeit in slightly different ways.
//
// A high level list of TODOs:
// - Optimize the scan itself, as there is some redundancy statting and
// reading go.mod files.
// - Invert the relationship between ProcessEnv and Resolver (see the
// docstring of ProcessEnv).
// - Make it easier to use an external resolver implementation.
//
// Smaller TODOs are annotated in the code below.
// ModuleResolver implements the Resolver interface for a workspace using
// modules.
//
// A goal of the ModuleResolver is to invoke the Go command as little as
// possible. To this end, it runs the Go command only for listing module
// information (i.e. `go list -m -e -json ...`). Package scanning, the process
// of loading package information for the modules, is implemented internally
// via the scan method.
//
// It has two types of state: the state derived from the go command, which
// is populated by init, and the state derived from scans, which is populated
// via scan. A root is considered scanned if it has been walked to discover
// directories. However, if the scan did not require additional information
// from the directory (such as package name or exports), the directory
// information itself may be partially populated. It will be lazily filled in
// as needed by scans, using the scanCallback.
type ModuleResolver struct { type ModuleResolver struct {
env *ProcessEnv env *ProcessEnv
moduleCacheDir string
dummyVendorMod *gocommand.ModuleJSON // If vendoring is enabled, the pseudo-module that represents the /vendor directory.
roots []gopathwalk.Root
scanSema chan struct{} // scanSema prevents concurrent scans and guards scannedRoots.
scannedRoots map[gopathwalk.Root]bool
initialized bool // Module state, populated during construction
mains []*gocommand.ModuleJSON dummyVendorMod *gocommand.ModuleJSON // if vendoring is enabled, a pseudo-module to represent the /vendor directory
mainByDir map[string]*gocommand.ModuleJSON moduleCacheDir string // GOMODCACHE, inferred from GOPATH if unset
modsByModPath []*gocommand.ModuleJSON // All modules, ordered by # of path components in module Path... roots []gopathwalk.Root // roots to scan, in approximate order of importance
modsByDir []*gocommand.ModuleJSON // ...or number of path components in their Dir. mains []*gocommand.ModuleJSON // main modules
mainByDir map[string]*gocommand.ModuleJSON // module information by dir, to join with roots
modsByModPath []*gocommand.ModuleJSON // all modules, ordered by # of path components in their module path
modsByDir []*gocommand.ModuleJSON // ...or by the number of path components in their Dir.
// moduleCacheCache stores information about the module cache. // Scanning state, populated by scan
moduleCacheCache *dirInfoCache
otherCache *dirInfoCache // scanSema prevents concurrent scans, and guards scannedRoots and the cache
// fields below (though the caches themselves are concurrency safe).
// Receive to acquire, send to release.
scanSema chan struct{}
scannedRoots map[gopathwalk.Root]bool // if true, root has been walked
// Caches of directory info, populated by scans and scan callbacks
//
// moduleCacheCache stores cached information about roots in the module
// cache, which are immutable and therefore do not need to be invalidated.
//
// otherCache stores information about all other roots (even GOROOT), which
// may change.
moduleCacheCache *DirInfoCache
otherCache *DirInfoCache
} }
func newModuleResolver(e *ProcessEnv) *ModuleResolver { // newModuleResolver returns a new module-aware goimports resolver.
//
// Note: use caution when modifying this constructor: changes must also be
// reflected in ModuleResolver.ClearForNewScan.
func newModuleResolver(e *ProcessEnv, moduleCacheCache *DirInfoCache) (*ModuleResolver, error) {
r := &ModuleResolver{ r := &ModuleResolver{
env: e, env: e,
scanSema: make(chan struct{}, 1), scanSema: make(chan struct{}, 1),
} }
r.scanSema <- struct{}{} r.scanSema <- struct{}{} // release
return r
}
func (r *ModuleResolver) init() error {
if r.initialized {
return nil
}
goenv, err := r.env.goEnv() goenv, err := r.env.goEnv()
if err != nil { if err != nil {
return err return nil, err
} }
// TODO(rfindley): can we refactor to share logic with r.env.invokeGo?
inv := gocommand.Invocation{ inv := gocommand.Invocation{
BuildFlags: r.env.BuildFlags, BuildFlags: r.env.BuildFlags,
ModFlag: r.env.ModFlag, ModFlag: r.env.ModFlag,
ModFile: r.env.ModFile,
Env: r.env.env(), Env: r.env.env(),
Logf: r.env.Logf, Logf: r.env.Logf,
WorkingDir: r.env.WorkingDir, WorkingDir: r.env.WorkingDir,
@ -77,9 +116,12 @@ func (r *ModuleResolver) init() error {
// Module vendor directories are ignored in workspace mode: // Module vendor directories are ignored in workspace mode:
// https://go.googlesource.com/proposal/+/master/design/45713-workspace.md // https://go.googlesource.com/proposal/+/master/design/45713-workspace.md
if len(r.env.Env["GOWORK"]) == 0 { if len(r.env.Env["GOWORK"]) == 0 {
// TODO(rfindley): VendorEnabled runs the go command to get GOFLAGS, but
// they should be available from the ProcessEnv. Can we avoid the redundant
// invocation?
vendorEnabled, mainModVendor, err = gocommand.VendorEnabled(context.TODO(), inv, r.env.GocmdRunner) vendorEnabled, mainModVendor, err = gocommand.VendorEnabled(context.TODO(), inv, r.env.GocmdRunner)
if err != nil { if err != nil {
return err return nil, err
} }
} }
@ -100,19 +142,14 @@ func (r *ModuleResolver) init() error {
// GO111MODULE=on. Other errors are fatal. // GO111MODULE=on. Other errors are fatal.
if err != nil { if err != nil {
if errMsg := err.Error(); !strings.Contains(errMsg, "working directory is not part of a module") && !strings.Contains(errMsg, "go.mod file not found") { if errMsg := err.Error(); !strings.Contains(errMsg, "working directory is not part of a module") && !strings.Contains(errMsg, "go.mod file not found") {
return err return nil, err
} }
} }
} }
if gmc := r.env.Env["GOMODCACHE"]; gmc != "" { r.moduleCacheDir = gomodcacheForEnv(goenv)
r.moduleCacheDir = gmc if r.moduleCacheDir == "" {
} else { return nil, fmt.Errorf("cannot resolve GOMODCACHE")
gopaths := filepath.SplitList(goenv["GOPATH"])
if len(gopaths) == 0 {
return fmt.Errorf("empty GOPATH")
}
r.moduleCacheDir = filepath.Join(gopaths[0], "/pkg/mod")
} }
sort.Slice(r.modsByModPath, func(i, j int) bool { sort.Slice(r.modsByModPath, func(i, j int) bool {
@ -141,7 +178,11 @@ func (r *ModuleResolver) init() error {
} else { } else {
addDep := func(mod *gocommand.ModuleJSON) { addDep := func(mod *gocommand.ModuleJSON) {
if mod.Replace == nil { if mod.Replace == nil {
// This is redundant with the cache, but we'll skip it cheaply enough. // This is redundant with the cache, but we'll skip it cheaply enough
// when we encounter it in the module cache scan.
//
// Including it at a lower index in r.roots than the module cache dir
// helps prioritize matches from within existing dependencies.
r.roots = append(r.roots, gopathwalk.Root{Path: mod.Dir, Type: gopathwalk.RootModuleCache}) r.roots = append(r.roots, gopathwalk.Root{Path: mod.Dir, Type: gopathwalk.RootModuleCache})
} else { } else {
r.roots = append(r.roots, gopathwalk.Root{Path: mod.Dir, Type: gopathwalk.RootOther}) r.roots = append(r.roots, gopathwalk.Root{Path: mod.Dir, Type: gopathwalk.RootOther})
@ -158,24 +199,40 @@ func (r *ModuleResolver) init() error {
addDep(mod) addDep(mod)
} }
} }
// If provided, share the moduleCacheCache.
//
// TODO(rfindley): The module cache is immutable. However, the loaded
// exports do depend on GOOS and GOARCH. Fortunately, the
// ProcessEnv.buildContext does not adjust these from build.DefaultContext
// (even though it should). So for now, this is OK to share, but we need to
// add logic for handling GOOS/GOARCH.
r.moduleCacheCache = moduleCacheCache
r.roots = append(r.roots, gopathwalk.Root{Path: r.moduleCacheDir, Type: gopathwalk.RootModuleCache}) r.roots = append(r.roots, gopathwalk.Root{Path: r.moduleCacheDir, Type: gopathwalk.RootModuleCache})
} }
r.scannedRoots = map[gopathwalk.Root]bool{} r.scannedRoots = map[gopathwalk.Root]bool{}
if r.moduleCacheCache == nil { if r.moduleCacheCache == nil {
r.moduleCacheCache = &dirInfoCache{ r.moduleCacheCache = NewDirInfoCache()
dirs: map[string]*directoryPackageInfo{},
listeners: map[*int]cacheListener{},
} }
r.otherCache = NewDirInfoCache()
return r, nil
} }
if r.otherCache == nil {
r.otherCache = &dirInfoCache{ // gomodcacheForEnv returns the GOMODCACHE value to use based on the given env
dirs: map[string]*directoryPackageInfo{}, // map, which must have GOMODCACHE and GOPATH populated.
listeners: map[*int]cacheListener{}, //
// TODO(rfindley): this is defensive refactoring.
// 1. Is this even relevant anymore? Can't we just read GOMODCACHE.
// 2. Use this to separate module cache scanning from other scanning.
func gomodcacheForEnv(goenv map[string]string) string {
if gmc := goenv["GOMODCACHE"]; gmc != "" {
return gmc
} }
gopaths := filepath.SplitList(goenv["GOPATH"])
if len(gopaths) == 0 {
return ""
} }
r.initialized = true return filepath.Join(gopaths[0], "/pkg/mod")
return nil
} }
func (r *ModuleResolver) initAllMods() error { func (r *ModuleResolver) initAllMods() error {
@ -206,30 +263,82 @@ func (r *ModuleResolver) initAllMods() error {
return nil return nil
} }
func (r *ModuleResolver) ClearForNewScan() { // ClearForNewScan invalidates the last scan.
<-r.scanSema //
r.scannedRoots = map[gopathwalk.Root]bool{} // It preserves the set of roots, but forgets about the set of directories.
r.otherCache = &dirInfoCache{ // Though it forgets the set of module cache directories, it remembers their
dirs: map[string]*directoryPackageInfo{}, // contents, since they are assumed to be immutable.
listeners: map[*int]cacheListener{}, func (r *ModuleResolver) ClearForNewScan() Resolver {
} <-r.scanSema // acquire r, to guard scannedRoots
r.scanSema <- struct{}{} r2 := &ModuleResolver{
}
func (r *ModuleResolver) ClearForNewMod() {
<-r.scanSema
*r = ModuleResolver{
env: r.env, env: r.env,
dummyVendorMod: r.dummyVendorMod,
moduleCacheDir: r.moduleCacheDir,
roots: r.roots,
mains: r.mains,
mainByDir: r.mainByDir,
modsByModPath: r.modsByModPath,
scanSema: make(chan struct{}, 1),
scannedRoots: make(map[gopathwalk.Root]bool),
otherCache: NewDirInfoCache(),
moduleCacheCache: r.moduleCacheCache, moduleCacheCache: r.moduleCacheCache,
otherCache: r.otherCache,
scanSema: r.scanSema,
} }
r.init() r2.scanSema <- struct{}{} // r2 must start released
r.scanSema <- struct{}{} // Invalidate root scans. We don't need to invalidate module cache roots,
// because they are immutable.
// (We don't support a use case where GOMODCACHE is cleaned in the middle of
// e.g. a gopls session: the user must restart gopls to get accurate
// imports.)
//
// Scanning for new directories in GOMODCACHE should be handled elsewhere,
// via a call to ScanModuleCache.
for _, root := range r.roots {
if root.Type == gopathwalk.RootModuleCache && r.scannedRoots[root] {
r2.scannedRoots[root] = true
}
}
r.scanSema <- struct{}{} // release r
return r2
} }
// findPackage returns the module and directory that contains the package at // ClearModuleInfo invalidates resolver state that depends on go.mod file
// the given import path, or returns nil, "" if no module is in scope. // contents (essentially, the output of go list -m -json ...).
//
// Notably, it does not forget directory contents, which are reset
// asynchronously via ClearForNewScan.
//
// If the ProcessEnv is a GOPATH environment, ClearModuleInfo is a no op.
//
// TODO(rfindley): move this to a new env.go, consolidating ProcessEnv methods.
func (e *ProcessEnv) ClearModuleInfo() {
if r, ok := e.resolver.(*ModuleResolver); ok {
resolver, resolverErr := newModuleResolver(e, e.ModCache)
if resolverErr == nil {
<-r.scanSema // acquire (guards caches)
resolver.moduleCacheCache = r.moduleCacheCache
resolver.otherCache = r.otherCache
r.scanSema <- struct{}{} // release
}
e.resolver = resolver
e.resolverErr = resolverErr
}
}
// UpdateResolver sets the resolver for the ProcessEnv to use in imports
// operations. Only for use with the result of [Resolver.ClearForNewScan].
//
// TODO(rfindley): this awkward API is a result of the (arguably) inverted
// relationship between configuration and state described in the doc comment
// for [ProcessEnv].
func (e *ProcessEnv) UpdateResolver(r Resolver) {
e.resolver = r
e.resolverErr = nil
}
// findPackage returns the module and directory from within the main modules
// and their dependencies that contains the package at the given import path,
// or returns nil, "" if no module is in scope.
func (r *ModuleResolver) findPackage(importPath string) (*gocommand.ModuleJSON, string) { func (r *ModuleResolver) findPackage(importPath string) (*gocommand.ModuleJSON, string) {
// This can't find packages in the stdlib, but that's harmless for all // This can't find packages in the stdlib, but that's harmless for all
// the existing code paths. // the existing code paths.
@ -295,10 +404,6 @@ func (r *ModuleResolver) cacheStore(info directoryPackageInfo) {
} }
} }
func (r *ModuleResolver) cacheKeys() []string {
return append(r.moduleCacheCache.Keys(), r.otherCache.Keys()...)
}
// cachePackageName caches the package name for a dir already in the cache. // cachePackageName caches the package name for a dir already in the cache.
func (r *ModuleResolver) cachePackageName(info directoryPackageInfo) (string, error) { func (r *ModuleResolver) cachePackageName(info directoryPackageInfo) (string, error) {
if info.rootType == gopathwalk.RootModuleCache { if info.rootType == gopathwalk.RootModuleCache {
@ -367,8 +472,7 @@ func (r *ModuleResolver) dirIsNestedModule(dir string, mod *gocommand.ModuleJSON
return modDir != mod.Dir return modDir != mod.Dir
} }
func (r *ModuleResolver) modInfo(dir string) (modDir string, modName string) { func readModName(modFile string) string {
readModName := func(modFile string) string {
modBytes, err := os.ReadFile(modFile) modBytes, err := os.ReadFile(modFile)
if err != nil { if err != nil {
return "" return ""
@ -376,6 +480,7 @@ func (r *ModuleResolver) modInfo(dir string) (modDir string, modName string) {
return modulePath(modBytes) return modulePath(modBytes)
} }
func (r *ModuleResolver) modInfo(dir string) (modDir, modName string) {
if r.dirInModuleCache(dir) { if r.dirInModuleCache(dir) {
if matches := modCacheRegexp.FindStringSubmatch(dir); len(matches) == 3 { if matches := modCacheRegexp.FindStringSubmatch(dir); len(matches) == 3 {
index := strings.Index(dir, matches[1]+"@"+matches[2]) index := strings.Index(dir, matches[1]+"@"+matches[2])
@ -409,11 +514,9 @@ func (r *ModuleResolver) dirInModuleCache(dir string) bool {
} }
func (r *ModuleResolver) loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) { func (r *ModuleResolver) loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) {
if err := r.init(); err != nil {
return nil, err
}
names := map[string]string{} names := map[string]string{}
for _, path := range importPaths { for _, path := range importPaths {
// TODO(rfindley): shouldn't this use the dirInfoCache?
_, packageDir := r.findPackage(path) _, packageDir := r.findPackage(path)
if packageDir == "" { if packageDir == "" {
continue continue
@ -431,10 +534,6 @@ func (r *ModuleResolver) scan(ctx context.Context, callback *scanCallback) error
ctx, done := event.Start(ctx, "imports.ModuleResolver.scan") ctx, done := event.Start(ctx, "imports.ModuleResolver.scan")
defer done() defer done()
if err := r.init(); err != nil {
return err
}
processDir := func(info directoryPackageInfo) { processDir := func(info directoryPackageInfo) {
// Skip this directory if we were not able to get the package information successfully. // Skip this directory if we were not able to get the package information successfully.
if scanned, err := info.reachedStatus(directoryScanned); !scanned || err != nil { if scanned, err := info.reachedStatus(directoryScanned); !scanned || err != nil {
@ -444,18 +543,18 @@ func (r *ModuleResolver) scan(ctx context.Context, callback *scanCallback) error
if err != nil { if err != nil {
return return
} }
if !callback.dirFound(pkg) { if !callback.dirFound(pkg) {
return return
} }
pkg.packageName, err = r.cachePackageName(info) pkg.packageName, err = r.cachePackageName(info)
if err != nil { if err != nil {
return return
} }
if !callback.packageNameLoaded(pkg) { if !callback.packageNameLoaded(pkg) {
return return
} }
_, exports, err := r.loadExports(ctx, pkg, false) _, exports, err := r.loadExports(ctx, pkg, false)
if err != nil { if err != nil {
return return
@ -494,7 +593,6 @@ func (r *ModuleResolver) scan(ctx context.Context, callback *scanCallback) error
return packageScanned return packageScanned
} }
// Add anything new to the cache, and process it if we're still listening.
add := func(root gopathwalk.Root, dir string) { add := func(root gopathwalk.Root, dir string) {
r.cacheStore(r.scanDirForPackage(root, dir)) r.cacheStore(r.scanDirForPackage(root, dir))
} }
@ -509,9 +607,9 @@ func (r *ModuleResolver) scan(ctx context.Context, callback *scanCallback) error
select { select {
case <-ctx.Done(): case <-ctx.Done():
return return
case <-r.scanSema: case <-r.scanSema: // acquire
} }
defer func() { r.scanSema <- struct{}{} }() defer func() { r.scanSema <- struct{}{} }() // release
// We have the lock on r.scannedRoots, and no other scans can run. // We have the lock on r.scannedRoots, and no other scans can run.
for _, root := range roots { for _, root := range roots {
if ctx.Err() != nil { if ctx.Err() != nil {
@ -613,9 +711,6 @@ func (r *ModuleResolver) canonicalize(info directoryPackageInfo) (*pkg, error) {
} }
func (r *ModuleResolver) loadExports(ctx context.Context, pkg *pkg, includeTest bool) (string, []string, error) { func (r *ModuleResolver) loadExports(ctx context.Context, pkg *pkg, includeTest bool) (string, []string, error) {
if err := r.init(); err != nil {
return "", nil, err
}
if info, ok := r.cacheLoad(pkg.dir); ok && !includeTest { if info, ok := r.cacheLoad(pkg.dir); ok && !includeTest {
return r.cacheExports(ctx, r.env, info) return r.cacheExports(ctx, r.env, info)
} }

View File

@ -7,8 +7,12 @@ package imports
import ( import (
"context" "context"
"fmt" "fmt"
"path"
"path/filepath"
"strings"
"sync" "sync"
"golang.org/x/mod/module"
"golang.org/x/tools/internal/gopathwalk" "golang.org/x/tools/internal/gopathwalk"
) )
@ -39,6 +43,8 @@ const (
exportsLoaded exportsLoaded
) )
// directoryPackageInfo holds (possibly incomplete) information about packages
// contained in a given directory.
type directoryPackageInfo struct { type directoryPackageInfo struct {
// status indicates the extent to which this struct has been filled in. // status indicates the extent to which this struct has been filled in.
status directoryPackageStatus status directoryPackageStatus
@ -63,7 +69,10 @@ type directoryPackageInfo struct {
packageName string // the package name, as declared in the source. packageName string // the package name, as declared in the source.
// Set when status >= exportsLoaded. // Set when status >= exportsLoaded.
// TODO(rfindley): it's hard to see this, but exports depend implicitly on
// the default build context GOOS and GOARCH.
//
// We can make this explicit, and key exports by GOOS, GOARCH.
exports []string exports []string
} }
@ -79,7 +88,7 @@ func (info *directoryPackageInfo) reachedStatus(target directoryPackageStatus) (
return true, nil return true, nil
} }
// dirInfoCache is a concurrency safe map for storing information about // DirInfoCache is a concurrency-safe map for storing information about
// directories that may contain packages. // directories that may contain packages.
// //
// The information in this cache is built incrementally. Entries are initialized in scan. // The information in this cache is built incrementally. Entries are initialized in scan.
@ -92,21 +101,26 @@ func (info *directoryPackageInfo) reachedStatus(target directoryPackageStatus) (
// The information in the cache is not expected to change for the cache's // The information in the cache is not expected to change for the cache's
// lifetime, so there is no protection against competing writes. Users should // lifetime, so there is no protection against competing writes. Users should
// take care not to hold the cache across changes to the underlying files. // take care not to hold the cache across changes to the underlying files.
// type DirInfoCache struct {
// TODO(suzmue): consider other concurrency strategies and data structures (RWLocks, sync.Map, etc)
type dirInfoCache struct {
mu sync.Mutex mu sync.Mutex
// dirs stores information about packages in directories, keyed by absolute path. // dirs stores information about packages in directories, keyed by absolute path.
dirs map[string]*directoryPackageInfo dirs map[string]*directoryPackageInfo
listeners map[*int]cacheListener listeners map[*int]cacheListener
} }
func NewDirInfoCache() *DirInfoCache {
return &DirInfoCache{
dirs: make(map[string]*directoryPackageInfo),
listeners: make(map[*int]cacheListener),
}
}
type cacheListener func(directoryPackageInfo) type cacheListener func(directoryPackageInfo)
// ScanAndListen calls listener on all the items in the cache, and on anything // ScanAndListen calls listener on all the items in the cache, and on anything
// newly added. The returned stop function waits for all in-flight callbacks to // newly added. The returned stop function waits for all in-flight callbacks to
// finish and blocks new ones. // finish and blocks new ones.
func (d *dirInfoCache) ScanAndListen(ctx context.Context, listener cacheListener) func() { func (d *DirInfoCache) ScanAndListen(ctx context.Context, listener cacheListener) func() {
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
// Flushing out all the callbacks is tricky without knowing how many there // Flushing out all the callbacks is tricky without knowing how many there
@ -162,8 +176,10 @@ func (d *dirInfoCache) ScanAndListen(ctx context.Context, listener cacheListener
} }
// Store stores the package info for dir. // Store stores the package info for dir.
func (d *dirInfoCache) Store(dir string, info directoryPackageInfo) { func (d *DirInfoCache) Store(dir string, info directoryPackageInfo) {
d.mu.Lock() d.mu.Lock()
// TODO(rfindley, golang/go#59216): should we overwrite an existing entry?
// That seems incorrect as the cache should be idempotent.
_, old := d.dirs[dir] _, old := d.dirs[dir]
d.dirs[dir] = &info d.dirs[dir] = &info
var listeners []cacheListener var listeners []cacheListener
@ -180,7 +196,7 @@ func (d *dirInfoCache) Store(dir string, info directoryPackageInfo) {
} }
// Load returns a copy of the directoryPackageInfo for absolute directory dir. // Load returns a copy of the directoryPackageInfo for absolute directory dir.
func (d *dirInfoCache) Load(dir string) (directoryPackageInfo, bool) { func (d *DirInfoCache) Load(dir string) (directoryPackageInfo, bool) {
d.mu.Lock() d.mu.Lock()
defer d.mu.Unlock() defer d.mu.Unlock()
info, ok := d.dirs[dir] info, ok := d.dirs[dir]
@ -191,7 +207,7 @@ func (d *dirInfoCache) Load(dir string) (directoryPackageInfo, bool) {
} }
// Keys returns the keys currently present in d. // Keys returns the keys currently present in d.
func (d *dirInfoCache) Keys() (keys []string) { func (d *DirInfoCache) Keys() (keys []string) {
d.mu.Lock() d.mu.Lock()
defer d.mu.Unlock() defer d.mu.Unlock()
for key := range d.dirs { for key := range d.dirs {
@ -200,7 +216,7 @@ func (d *dirInfoCache) Keys() (keys []string) {
return keys return keys
} }
func (d *dirInfoCache) CachePackageName(info directoryPackageInfo) (string, error) { func (d *DirInfoCache) CachePackageName(info directoryPackageInfo) (string, error) {
if loaded, err := info.reachedStatus(nameLoaded); loaded { if loaded, err := info.reachedStatus(nameLoaded); loaded {
return info.packageName, err return info.packageName, err
} }
@ -213,7 +229,7 @@ func (d *dirInfoCache) CachePackageName(info directoryPackageInfo) (string, erro
return info.packageName, info.err return info.packageName, info.err
} }
func (d *dirInfoCache) CacheExports(ctx context.Context, env *ProcessEnv, info directoryPackageInfo) (string, []string, error) { func (d *DirInfoCache) CacheExports(ctx context.Context, env *ProcessEnv, info directoryPackageInfo) (string, []string, error) {
if reached, _ := info.reachedStatus(exportsLoaded); reached { if reached, _ := info.reachedStatus(exportsLoaded); reached {
return info.packageName, info.exports, info.err return info.packageName, info.exports, info.err
} }
@ -234,3 +250,81 @@ func (d *dirInfoCache) CacheExports(ctx context.Context, env *ProcessEnv, info d
d.Store(info.dir, info) d.Store(info.dir, info)
return info.packageName, info.exports, info.err return info.packageName, info.exports, info.err
} }
// ScanModuleCache walks the given directory, which must be a GOMODCACHE value,
// for directory package information, storing the results in cache.
func ScanModuleCache(dir string, cache *DirInfoCache, logf func(string, ...any)) {
// Note(rfindley): it's hard to see, but this function attempts to implement
// just the side effects on cache of calling PrimeCache with a ProcessEnv
// that has the given dir as its GOMODCACHE.
//
// Teasing out the control flow, we see that we can avoid any handling of
// vendor/ and can infer module info entirely from the path, simplifying the
// logic here.
root := gopathwalk.Root{
Path: filepath.Clean(dir),
Type: gopathwalk.RootModuleCache,
}
directoryInfo := func(root gopathwalk.Root, dir string) directoryPackageInfo {
// This is a copy of ModuleResolver.scanDirForPackage, trimmed down to
// logic that applies to a module cache directory.
subdir := ""
if dir != root.Path {
subdir = dir[len(root.Path)+len("/"):]
}
matches := modCacheRegexp.FindStringSubmatch(subdir)
if len(matches) == 0 {
return directoryPackageInfo{
status: directoryScanned,
err: fmt.Errorf("invalid module cache path: %v", subdir),
}
}
modPath, err := module.UnescapePath(filepath.ToSlash(matches[1]))
if err != nil {
if logf != nil {
logf("decoding module cache path %q: %v", subdir, err)
}
return directoryPackageInfo{
status: directoryScanned,
err: fmt.Errorf("decoding module cache path %q: %v", subdir, err),
}
}
importPath := path.Join(modPath, filepath.ToSlash(matches[3]))
index := strings.Index(dir, matches[1]+"@"+matches[2])
modDir := filepath.Join(dir[:index], matches[1]+"@"+matches[2])
modName := readModName(filepath.Join(modDir, "go.mod"))
return directoryPackageInfo{
status: directoryScanned,
dir: dir,
rootType: root.Type,
nonCanonicalImportPath: importPath,
moduleDir: modDir,
moduleName: modName,
}
}
add := func(root gopathwalk.Root, dir string) {
info := directoryInfo(root, dir)
cache.Store(info.dir, info)
}
skip := func(_ gopathwalk.Root, dir string) bool {
// Skip directories that have already been scanned.
//
// Note that gopathwalk only adds "package" directories, which must contain
// a .go file, and all such package directories in the module cache are
// immutable. So if we can load a dir, it can be skipped.
info, ok := cache.Load(dir)
if !ok {
return false
}
packageScanned, _ := info.reachedStatus(directoryScanned)
return packageScanned
}
gopathwalk.WalkSkip([]gopathwalk.Root{root}, add, skip, gopathwalk.Options{Logf: logf, ModulesEnabled: true})
}

View File

@ -151,6 +151,7 @@ var stdlib = map[string][]string{
"cmp": { "cmp": {
"Compare", "Compare",
"Less", "Less",
"Or",
"Ordered", "Ordered",
}, },
"compress/bzip2": { "compress/bzip2": {
@ -632,6 +633,8 @@ var stdlib = map[string][]string{
"NameMismatch", "NameMismatch",
"NewCertPool", "NewCertPool",
"NotAuthorizedToSign", "NotAuthorizedToSign",
"OID",
"OIDFromInts",
"PEMCipher", "PEMCipher",
"PEMCipher3DES", "PEMCipher3DES",
"PEMCipherAES128", "PEMCipherAES128",
@ -706,6 +709,7 @@ var stdlib = map[string][]string{
"LevelWriteCommitted", "LevelWriteCommitted",
"Named", "Named",
"NamedArg", "NamedArg",
"Null",
"NullBool", "NullBool",
"NullByte", "NullByte",
"NullFloat64", "NullFloat64",
@ -1921,6 +1925,7 @@ var stdlib = map[string][]string{
"R_LARCH_32", "R_LARCH_32",
"R_LARCH_32_PCREL", "R_LARCH_32_PCREL",
"R_LARCH_64", "R_LARCH_64",
"R_LARCH_64_PCREL",
"R_LARCH_ABS64_HI12", "R_LARCH_ABS64_HI12",
"R_LARCH_ABS64_LO20", "R_LARCH_ABS64_LO20",
"R_LARCH_ABS_HI20", "R_LARCH_ABS_HI20",
@ -1928,12 +1933,17 @@ var stdlib = map[string][]string{
"R_LARCH_ADD16", "R_LARCH_ADD16",
"R_LARCH_ADD24", "R_LARCH_ADD24",
"R_LARCH_ADD32", "R_LARCH_ADD32",
"R_LARCH_ADD6",
"R_LARCH_ADD64", "R_LARCH_ADD64",
"R_LARCH_ADD8", "R_LARCH_ADD8",
"R_LARCH_ADD_ULEB128",
"R_LARCH_ALIGN",
"R_LARCH_B16", "R_LARCH_B16",
"R_LARCH_B21", "R_LARCH_B21",
"R_LARCH_B26", "R_LARCH_B26",
"R_LARCH_CFA",
"R_LARCH_COPY", "R_LARCH_COPY",
"R_LARCH_DELETE",
"R_LARCH_GNU_VTENTRY", "R_LARCH_GNU_VTENTRY",
"R_LARCH_GNU_VTINHERIT", "R_LARCH_GNU_VTINHERIT",
"R_LARCH_GOT64_HI12", "R_LARCH_GOT64_HI12",
@ -1953,6 +1963,7 @@ var stdlib = map[string][]string{
"R_LARCH_PCALA64_LO20", "R_LARCH_PCALA64_LO20",
"R_LARCH_PCALA_HI20", "R_LARCH_PCALA_HI20",
"R_LARCH_PCALA_LO12", "R_LARCH_PCALA_LO12",
"R_LARCH_PCREL20_S2",
"R_LARCH_RELATIVE", "R_LARCH_RELATIVE",
"R_LARCH_RELAX", "R_LARCH_RELAX",
"R_LARCH_SOP_ADD", "R_LARCH_SOP_ADD",
@ -1983,8 +1994,10 @@ var stdlib = map[string][]string{
"R_LARCH_SUB16", "R_LARCH_SUB16",
"R_LARCH_SUB24", "R_LARCH_SUB24",
"R_LARCH_SUB32", "R_LARCH_SUB32",
"R_LARCH_SUB6",
"R_LARCH_SUB64", "R_LARCH_SUB64",
"R_LARCH_SUB8", "R_LARCH_SUB8",
"R_LARCH_SUB_ULEB128",
"R_LARCH_TLS_DTPMOD32", "R_LARCH_TLS_DTPMOD32",
"R_LARCH_TLS_DTPMOD64", "R_LARCH_TLS_DTPMOD64",
"R_LARCH_TLS_DTPREL32", "R_LARCH_TLS_DTPREL32",
@ -2035,6 +2048,7 @@ var stdlib = map[string][]string{
"R_MIPS_LO16", "R_MIPS_LO16",
"R_MIPS_NONE", "R_MIPS_NONE",
"R_MIPS_PC16", "R_MIPS_PC16",
"R_MIPS_PC32",
"R_MIPS_PJUMP", "R_MIPS_PJUMP",
"R_MIPS_REL16", "R_MIPS_REL16",
"R_MIPS_REL32", "R_MIPS_REL32",
@ -2952,6 +2966,8 @@ var stdlib = map[string][]string{
"RegisterName", "RegisterName",
}, },
"encoding/hex": { "encoding/hex": {
"AppendDecode",
"AppendEncode",
"Decode", "Decode",
"DecodeString", "DecodeString",
"DecodedLen", "DecodedLen",
@ -3233,6 +3249,7 @@ var stdlib = map[string][]string{
"TypeSpec", "TypeSpec",
"TypeSwitchStmt", "TypeSwitchStmt",
"UnaryExpr", "UnaryExpr",
"Unparen",
"ValueSpec", "ValueSpec",
"Var", "Var",
"Visitor", "Visitor",
@ -3492,6 +3509,7 @@ var stdlib = map[string][]string{
"XOR_ASSIGN", "XOR_ASSIGN",
}, },
"go/types": { "go/types": {
"Alias",
"ArgumentError", "ArgumentError",
"Array", "Array",
"AssertableTo", "AssertableTo",
@ -3559,6 +3577,7 @@ var stdlib = map[string][]string{
"MethodVal", "MethodVal",
"MissingMethod", "MissingMethod",
"Named", "Named",
"NewAlias",
"NewArray", "NewArray",
"NewChan", "NewChan",
"NewChecker", "NewChecker",
@ -3627,6 +3646,7 @@ var stdlib = map[string][]string{
"Uint64", "Uint64",
"Uint8", "Uint8",
"Uintptr", "Uintptr",
"Unalias",
"Union", "Union",
"Universe", "Universe",
"Unsafe", "Unsafe",
@ -3643,6 +3663,11 @@ var stdlib = map[string][]string{
"WriteSignature", "WriteSignature",
"WriteType", "WriteType",
}, },
"go/version": {
"Compare",
"IsValid",
"Lang",
},
"hash": { "hash": {
"Hash", "Hash",
"Hash32", "Hash32",
@ -4078,6 +4103,7 @@ var stdlib = map[string][]string{
"NewTextHandler", "NewTextHandler",
"Record", "Record",
"SetDefault", "SetDefault",
"SetLogLoggerLevel",
"Source", "Source",
"SourceKey", "SourceKey",
"String", "String",
@ -4367,6 +4393,35 @@ var stdlib = map[string][]string{
"Uint64", "Uint64",
"Zipf", "Zipf",
}, },
"math/rand/v2": {
"ChaCha8",
"ExpFloat64",
"Float32",
"Float64",
"Int",
"Int32",
"Int32N",
"Int64",
"Int64N",
"IntN",
"N",
"New",
"NewChaCha8",
"NewPCG",
"NewZipf",
"NormFloat64",
"PCG",
"Perm",
"Rand",
"Shuffle",
"Source",
"Uint32",
"Uint32N",
"Uint64",
"Uint64N",
"UintN",
"Zipf",
},
"mime": { "mime": {
"AddExtensionType", "AddExtensionType",
"BEncoding", "BEncoding",
@ -4540,6 +4595,7 @@ var stdlib = map[string][]string{
"FS", "FS",
"File", "File",
"FileServer", "FileServer",
"FileServerFS",
"FileSystem", "FileSystem",
"Flusher", "Flusher",
"Get", "Get",
@ -4566,6 +4622,7 @@ var stdlib = map[string][]string{
"MethodPut", "MethodPut",
"MethodTrace", "MethodTrace",
"NewFileTransport", "NewFileTransport",
"NewFileTransportFS",
"NewRequest", "NewRequest",
"NewRequestWithContext", "NewRequestWithContext",
"NewResponseController", "NewResponseController",
@ -4599,6 +4656,7 @@ var stdlib = map[string][]string{
"Serve", "Serve",
"ServeContent", "ServeContent",
"ServeFile", "ServeFile",
"ServeFileFS",
"ServeMux", "ServeMux",
"ServeTLS", "ServeTLS",
"Server", "Server",
@ -5106,6 +5164,7 @@ var stdlib = map[string][]string{
"StructTag", "StructTag",
"Swapper", "Swapper",
"Type", "Type",
"TypeFor",
"TypeOf", "TypeOf",
"Uint", "Uint",
"Uint16", "Uint16",
@ -5342,6 +5401,7 @@ var stdlib = map[string][]string{
"CompactFunc", "CompactFunc",
"Compare", "Compare",
"CompareFunc", "CompareFunc",
"Concat",
"Contains", "Contains",
"ContainsFunc", "ContainsFunc",
"Delete", "Delete",
@ -10824,6 +10884,7 @@ var stdlib = map[string][]string{
"Value", "Value",
}, },
"testing/slogtest": { "testing/slogtest": {
"Run",
"TestHandler", "TestHandler",
}, },
"text/scanner": { "text/scanner": {

View File

@ -56,16 +56,16 @@ github.com/vbatts/git-validation/rules/dco
github.com/vbatts/git-validation/rules/messageregexp github.com/vbatts/git-validation/rules/messageregexp
github.com/vbatts/git-validation/rules/shortsubject github.com/vbatts/git-validation/rules/shortsubject
github.com/vbatts/git-validation/validate github.com/vbatts/git-validation/validate
# golang.org/x/mod v0.14.0 # golang.org/x/mod v0.15.0
## explicit; go 1.18 ## explicit; go 1.18
golang.org/x/mod/internal/lazyregexp golang.org/x/mod/internal/lazyregexp
golang.org/x/mod/module golang.org/x/mod/module
golang.org/x/mod/semver golang.org/x/mod/semver
# golang.org/x/sys v0.15.0 # golang.org/x/sys v0.17.0
## explicit; go 1.18 ## explicit; go 1.18
golang.org/x/sys/unix golang.org/x/sys/unix
golang.org/x/sys/windows golang.org/x/sys/windows
# golang.org/x/tools v0.17.0 # golang.org/x/tools v0.18.0
## explicit; go 1.18 ## explicit; go 1.18
golang.org/x/tools/cmd/goimports golang.org/x/tools/cmd/goimports
golang.org/x/tools/go/ast/astutil golang.org/x/tools/go/ast/astutil