TUN-9016: update go to 1.24

## Summary

Update several moving parts of cloudflared build system:

* use goboring 1.24.2 in cfsetup
* update linter and fix lint issues
* update packages namely **quic-go and net**
* install script for macos
* update docker files to use go 1.24.1
* remove usage of cloudflare-go
* pin golang linter

Closes TUN-9016
This commit is contained in:
Luis Neto
2025-06-06 09:05:49 +00:00
parent e144eac2af
commit 96ce66bd30
585 changed files with 23572 additions and 21356 deletions

14
vendor/go.uber.org/automaxprocs/.codecov.yml generated vendored Normal file
View File

@@ -0,0 +1,14 @@
coverage:
range: 80..100
round: down
precision: 2
status:
project: # measuring the overall project coverage
default: # context, you can create multiple ones with custom titles
enabled: yes # must be yes|true to enable this status
target: 90% # specify the target coverage for each commit status
# option: "auto" (must increase from parent commit or pull request base)
# option: "X%" a static target percentage to hit
if_not_found: success # if parent is not found report status as success, error, or failure
if_ci_failed: error # if ci fails report status as success, error, or failure

33
vendor/go.uber.org/automaxprocs/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,33 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
vendor
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
*.pprof
*.out
*.log
coverage.txt
/bin
cover.out
cover.html

52
vendor/go.uber.org/automaxprocs/CHANGELOG.md generated vendored Normal file
View File

@@ -0,0 +1,52 @@
# Changelog
## v1.6.0 (2024-07-24)
- Add RoundQuotaFunc option that allows configuration of rounding
behavior for floating point CPU quota.
## v1.5.3 (2023-07-19)
- Fix mountinfo parsing when super options have fields with spaces.
- Fix division by zero while parsing cgroups.
## v1.5.2 (2023-03-16)
- Support child control cgroups
- Fix file descriptor leak
- Update dependencies
## v1.5.1 (2022-04-06)
- Fix cgroups v2 mountpoint detection.
## v1.5.0 (2022-04-05)
- Add support for cgroups v2.
Thanks to @emadolsky for their contribution to this release.
## v1.4.0 (2021-02-01)
- Support colons in cgroup names.
- Remove linters from runtime dependencies.
## v1.3.0 (2020-01-23)
- Migrate to Go modules.
## v1.2.0 (2018-02-22)
- Fixed quota clamping to always round down rather than up; Rather than
guaranteeing constant throttling at saturation, instead assume that the
fractional CPU was added as a hedge for factors outside of Go's scheduler.
## v1.1.0 (2017-11-10)
- Log the new value of `GOMAXPROCS` rather than the current value.
- Make logs more explicit about whether `GOMAXPROCS` was modified or not.
- Allow customization of the minimum `GOMAXPROCS`, and modify default from 2 to 1.
## v1.0.0 (2017-08-09)
- Initial release.

75
vendor/go.uber.org/automaxprocs/CODE_OF_CONDUCT.md generated vendored Normal file
View File

@@ -0,0 +1,75 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age,
body size, disability, ethnicity, gender identity and expression, level of
experience, nationality, personal appearance, race, religion, or sexual
identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an
appointed representative at an online or offline event. Representation of a
project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at oss-conduct@uber.com. The project
team will review and investigate all complaints, and will respond in a way
that it deems appropriate to the circumstances. The project team is obligated
to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 1.4, available at
[http://contributor-covenant.org/version/1/4][version].
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

81
vendor/go.uber.org/automaxprocs/CONTRIBUTING.md generated vendored Normal file
View File

@@ -0,0 +1,81 @@
# Contributing
We'd love your help improving this package!
If you'd like to add new exported APIs, please [open an issue][open-issue]
describing your proposal — discussing API changes ahead of time makes
pull request review much smoother. In your issue, pull request, and any other
communications, please remember to treat your fellow contributors with
respect! We take our [code of conduct](CODE_OF_CONDUCT.md) seriously.
Note that you'll need to sign [Uber's Contributor License Agreement][cla]
before we can accept any of your contributions. If necessary, a bot will remind
you to accept the CLA when you open your pull request.
## Setup
[Fork][fork], then clone the repository:
```
mkdir -p $GOPATH/src/go.uber.org
cd $GOPATH/src/go.uber.org
git clone git@github.com:your_github_username/automaxprocs.git
cd automaxprocs
git remote add upstream https://github.com/uber-go/automaxprocs.git
git fetch upstream
```
Install the test dependencies:
```
make dependencies
```
Make sure that the tests and the linters pass:
```
make test
make lint
```
If you're not using the minor version of Go specified in the Makefile's
`LINTABLE_MINOR_VERSIONS` variable, `make lint` doesn't do anything. This is
fine, but it means that you'll only discover lint failures after you open your
pull request.
## Making Changes
Start by creating a new branch for your changes:
```
cd $GOPATH/src/go.uber.org/automaxprocs
git checkout master
git fetch upstream
git rebase upstream/master
git checkout -b cool_new_feature
```
Make your changes, then ensure that `make lint` and `make test` still pass. If
you're satisfied with your changes, push them to your fork.
```
git push origin cool_new_feature
```
Then use the GitHub UI to open a pull request.
At this point, you're waiting on us to review your changes. We *try* to respond
to issues and pull requests within a few business days, and we may suggest some
improvements or alternatives. Once your changes are approved, one of the
project maintainers will merge them.
We're much more likely to approve your changes if you:
* Add tests for new functionality.
* Write a [good commit message][commit-message].
* Maintain backward compatibility.
[fork]: https://github.com/uber-go/automaxprocs/fork
[open-issue]: https://github.com/uber-go/automaxprocs/issues/new
[cla]: https://cla-assistant.io/uber-go/automaxprocs
[commit-message]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html

46
vendor/go.uber.org/automaxprocs/Makefile generated vendored Normal file
View File

@@ -0,0 +1,46 @@
export GOBIN ?= $(shell pwd)/bin
GO_FILES := $(shell \
find . '(' -path '*/.*' -o -path './vendor' ')' -prune \
-o -name '*.go' -print | cut -b3-)
GOLINT = $(GOBIN)/golint
STATICCHECK = $(GOBIN)/staticcheck
.PHONY: build
build:
go build ./...
.PHONY: install
install:
go mod download
.PHONY: test
test:
go test -race ./...
.PHONY: cover
cover:
go test -coverprofile=cover.out -covermode=atomic -coverpkg=./... ./...
go tool cover -html=cover.out -o cover.html
$(GOLINT): tools/go.mod
cd tools && go install golang.org/x/lint/golint
$(STATICCHECK): tools/go.mod
cd tools && go install honnef.co/go/tools/cmd/staticcheck@2023.1.2
.PHONY: lint
lint: $(GOLINT) $(STATICCHECK)
@rm -rf lint.log
@echo "Checking gofmt"
@gofmt -d -s $(GO_FILES) 2>&1 | tee lint.log
@echo "Checking go vet"
@go vet ./... 2>&1 | tee -a lint.log
@echo "Checking golint"
@$(GOLINT) ./... | tee -a lint.log
@echo "Checking staticcheck"
@$(STATICCHECK) ./... 2>&1 | tee -a lint.log
@echo "Checking for license headers..."
@./.build/check_license.sh | tee -a lint.log
@[ ! -s lint.log ]

71
vendor/go.uber.org/automaxprocs/README.md generated vendored Normal file
View File

@@ -0,0 +1,71 @@
# automaxprocs [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov]
Automatically set `GOMAXPROCS` to match Linux container CPU quota.
## Installation
`go get -u go.uber.org/automaxprocs`
## Quick Start
```go
import _ "go.uber.org/automaxprocs"
func main() {
// Your application logic here.
}
```
# Performance
Data measured from Uber's internal load balancer. We ran the load balancer with 200% CPU quota (i.e., 2 cores):
| GOMAXPROCS | RPS | P50 (ms) | P99.9 (ms) |
| ------------------ | --------- | -------- | ---------- |
| 1 | 28,893.18 | 1.46 | 19.70 |
| 2 (equal to quota) | 44,715.07 | 0.84 | 26.38 |
| 3 | 44,212.93 | 0.66 | 30.07 |
| 4 | 41,071.15 | 0.57 | 42.94 |
| 8 | 33,111.69 | 0.43 | 64.32 |
| Default (24) | 22,191.40 | 0.45 | 76.19 |
When `GOMAXPROCS` is increased above the CPU quota, we see P50 decrease slightly, but see significant increases to P99. We also see that the total RPS handled also decreases.
When `GOMAXPROCS` is higher than the CPU quota allocated, we also saw significant throttling:
```
$ cat /sys/fs/cgroup/cpu,cpuacct/system.slice/[...]/cpu.stat
nr_periods 42227334
nr_throttled 131923
throttled_time 88613212216618
```
Once `GOMAXPROCS` was reduced to match the CPU quota, we saw no CPU throttling.
## Development Status: Stable
All APIs are finalized, and no breaking changes will be made in the 1.x series
of releases. Users of semver-aware dependency management systems should pin
automaxprocs to `^1`.
## Contributing
We encourage and support an active, healthy community of contributors —
including you! Details are in the [contribution guide](CONTRIBUTING.md) and
the [code of conduct](CODE_OF_CONDUCT.md). The automaxprocs maintainers keep
an eye on issues and pull requests, but you can also report any negative
conduct to oss-conduct@uber.com. That email list is a private, safe space;
even the automaxprocs maintainers don't have access, so don't hesitate to hold
us to a high standard.
<hr>
Released under the [MIT License](LICENSE).
[doc-img]: https://godoc.org/go.uber.org/automaxprocs?status.svg
[doc]: https://godoc.org/go.uber.org/automaxprocs
[ci-img]: https://github.com/uber-go/automaxprocs/actions/workflows/go.yml/badge.svg
[ci]: https://github.com/uber-go/automaxprocs/actions/workflows/go.yml
[cov-img]: https://codecov.io/gh/uber-go/automaxprocs/branch/master/graph/badge.svg
[cov]: https://codecov.io/gh/uber-go/automaxprocs

33
vendor/go.uber.org/automaxprocs/automaxprocs.go generated vendored Normal file
View File

@@ -0,0 +1,33 @@
// Copyright (c) 2017 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// Package automaxprocs automatically sets GOMAXPROCS to match the Linux
// container CPU quota, if any.
package automaxprocs // import "go.uber.org/automaxprocs"
import (
"log"
"go.uber.org/automaxprocs/maxprocs"
)
func init() {
maxprocs.Set(maxprocs.Logger(log.Printf))
}

View File

@@ -18,6 +18,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//go:build linux
// +build linux
package cgroups

View File

@@ -18,6 +18,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//go:build linux
// +build linux
package cgroups
@@ -109,8 +110,8 @@ func (cg CGroups) CPUQuota() (float64, bool, error) {
}
cfsPeriodUs, err := cpuCGroup.readInt(_cgroupCPUCFSPeriodUsParam)
if err != nil {
return -1, false, err
if defined := cfsPeriodUs > 0; err != nil || !defined {
return -1, defined, err
}
return float64(cfsQuotaUs) / float64(cfsPeriodUs), true, nil

View File

@@ -0,0 +1,176 @@
// Copyright (c) 2022 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//go:build linux
// +build linux
package cgroups
import (
"bufio"
"errors"
"fmt"
"io"
"os"
"path"
"strconv"
"strings"
)
const (
// _cgroupv2CPUMax is the file name for the CGroup-V2 CPU max and period
// parameter.
_cgroupv2CPUMax = "cpu.max"
// _cgroupFSType is the Linux CGroup-V2 file system type used in
// `/proc/$PID/mountinfo`.
_cgroupv2FSType = "cgroup2"
_cgroupv2MountPoint = "/sys/fs/cgroup"
_cgroupV2CPUMaxDefaultPeriod = 100000
_cgroupV2CPUMaxQuotaMax = "max"
)
const (
_cgroupv2CPUMaxQuotaIndex = iota
_cgroupv2CPUMaxPeriodIndex
)
// ErrNotV2 indicates that the system is not using cgroups2.
var ErrNotV2 = errors.New("not using cgroups2")
// CGroups2 provides access to cgroups data for systems using cgroups2.
type CGroups2 struct {
mountPoint string
groupPath string
cpuMaxFile string
}
// NewCGroups2ForCurrentProcess builds a CGroups2 for the current process.
//
// This returns ErrNotV2 if the system is not using cgroups2.
func NewCGroups2ForCurrentProcess() (*CGroups2, error) {
return newCGroups2From(_procPathMountInfo, _procPathCGroup)
}
func newCGroups2From(mountInfoPath, procPathCGroup string) (*CGroups2, error) {
isV2, err := isCGroupV2(mountInfoPath)
if err != nil {
return nil, err
}
if !isV2 {
return nil, ErrNotV2
}
subsystems, err := parseCGroupSubsystems(procPathCGroup)
if err != nil {
return nil, err
}
// Find v2 subsystem by looking for the `0` id
var v2subsys *CGroupSubsys
for _, subsys := range subsystems {
if subsys.ID == 0 {
v2subsys = subsys
break
}
}
if v2subsys == nil {
return nil, ErrNotV2
}
return &CGroups2{
mountPoint: _cgroupv2MountPoint,
groupPath: v2subsys.Name,
cpuMaxFile: _cgroupv2CPUMax,
}, nil
}
func isCGroupV2(procPathMountInfo string) (bool, error) {
var (
isV2 bool
newMountPoint = func(mp *MountPoint) error {
isV2 = isV2 || (mp.FSType == _cgroupv2FSType && mp.MountPoint == _cgroupv2MountPoint)
return nil
}
)
if err := parseMountInfo(procPathMountInfo, newMountPoint); err != nil {
return false, err
}
return isV2, nil
}
// CPUQuota returns the CPU quota applied with the CPU cgroup2 controller.
// It is a result of reading cpu quota and period from cpu.max file.
// It will return `cpu.max / cpu.period`. If cpu.max is set to max, it returns
// (-1, false, nil)
func (cg *CGroups2) CPUQuota() (float64, bool, error) {
cpuMaxParams, err := os.Open(path.Join(cg.mountPoint, cg.groupPath, cg.cpuMaxFile))
if err != nil {
if os.IsNotExist(err) {
return -1, false, nil
}
return -1, false, err
}
defer cpuMaxParams.Close()
scanner := bufio.NewScanner(cpuMaxParams)
if scanner.Scan() {
fields := strings.Fields(scanner.Text())
if len(fields) == 0 || len(fields) > 2 {
return -1, false, fmt.Errorf("invalid format")
}
if fields[_cgroupv2CPUMaxQuotaIndex] == _cgroupV2CPUMaxQuotaMax {
return -1, false, nil
}
max, err := strconv.Atoi(fields[_cgroupv2CPUMaxQuotaIndex])
if err != nil {
return -1, false, err
}
var period int
if len(fields) == 1 {
period = _cgroupV2CPUMaxDefaultPeriod
} else {
period, err = strconv.Atoi(fields[_cgroupv2CPUMaxPeriodIndex])
if err != nil {
return -1, false, err
}
if period == 0 {
return -1, false, errors.New("zero value for period is not allowed")
}
}
return float64(max) / float64(period), true, nil
}
if err := scanner.Err(); err != nil {
return -1, false, err
}
return 0, false, io.ErrUnexpectedEOF
}

View File

@@ -18,6 +18,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//go:build linux
// +build linux
package cgroups

View File

@@ -18,6 +18,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//go:build linux
// +build linux
package cgroups
@@ -94,8 +95,12 @@ func NewMountPointFromLine(line string) (*MountPoint, error) {
for i, field := range fields[_miFieldIDOptionalFields:] {
if field == _mountInfoOptionalFieldsSep {
// End of optional fields.
fsTypeStart := _miFieldIDOptionalFields + i + 1
// Now we know where the optional fields end, split the line again with a
// limit to avoid issues with spaces in super options as present on WSL.
fields = strings.SplitN(line, _mountInfoSep, fsTypeStart+_miFieldCountSecondHalf)
if len(fields) != fsTypeStart+_miFieldCountSecondHalf {
return nil, mountPointFormatInvalidError{line}
}

View File

@@ -18,6 +18,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//go:build linux
// +build linux
package cgroups

View File

@@ -18,20 +18,25 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//go:build linux
// +build linux
package runtime
import (
"math"
"errors"
cg "go.uber.org/automaxprocs/internal/cgroups"
)
// CPUQuotaToGOMAXPROCS converts the CPU quota applied to the calling process
// to a valid GOMAXPROCS value.
func CPUQuotaToGOMAXPROCS(minValue int) (int, CPUQuotaStatus, error) {
cgroups, err := cg.NewCGroupsForCurrentProcess()
// to a valid GOMAXPROCS value. The quota is converted from float to int using round.
// If round == nil, DefaultRoundFunc is used.
func CPUQuotaToGOMAXPROCS(minValue int, round func(v float64) int) (int, CPUQuotaStatus, error) {
if round == nil {
round = DefaultRoundFunc
}
cgroups, err := _newQueryer()
if err != nil {
return -1, CPUQuotaUndefined, err
}
@@ -41,9 +46,30 @@ func CPUQuotaToGOMAXPROCS(minValue int) (int, CPUQuotaStatus, error) {
return -1, CPUQuotaUndefined, err
}
maxProcs := int(math.Floor(quota))
maxProcs := round(quota)
if minValue > 0 && maxProcs < minValue {
return minValue, CPUQuotaMinUsed, nil
}
return maxProcs, CPUQuotaUsed, nil
}
type queryer interface {
CPUQuota() (float64, bool, error)
}
var (
_newCgroups2 = cg.NewCGroups2ForCurrentProcess
_newCgroups = cg.NewCGroupsForCurrentProcess
_newQueryer = newQueryer
)
func newQueryer() (queryer, error) {
cgroups, err := _newCgroups2()
if err == nil {
return cgroups, nil
}
if errors.Is(err, cg.ErrNotV2) {
return _newCgroups()
}
return nil, err
}

View File

@@ -18,6 +18,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//go:build !linux
// +build !linux
package runtime
@@ -25,6 +26,6 @@ package runtime
// CPUQuotaToGOMAXPROCS converts the CPU quota applied to the calling process
// to a valid GOMAXPROCS value. This is Linux-specific and not supported in the
// current OS.
func CPUQuotaToGOMAXPROCS(_ int) (int, CPUQuotaStatus, error) {
func CPUQuotaToGOMAXPROCS(_ int, _ func(v float64) int) (int, CPUQuotaStatus, error) {
return -1, CPUQuotaUndefined, nil
}

View File

@@ -20,6 +20,8 @@
package runtime
import "math"
// CPUQuotaStatus presents the status of how CPU quota is used
type CPUQuotaStatus int
@@ -28,6 +30,11 @@ const (
CPUQuotaUndefined CPUQuotaStatus = iota
// CPUQuotaUsed is returned when a valid CPU quota can be used
CPUQuotaUsed
// CPUQuotaMinUsed is return when CPU quota is smaller than the min value
// CPUQuotaMinUsed is returned when CPU quota is smaller than the min value
CPUQuotaMinUsed
)
// DefaultRoundFunc is the default function to convert CPU quota from float to int. It rounds the value down (floor).
func DefaultRoundFunc(v float64) int {
return int(math.Floor(v))
}

View File

@@ -37,9 +37,10 @@ func currentMaxProcs() int {
}
type config struct {
printf func(string, ...interface{})
procs func(int) (int, iruntime.CPUQuotaStatus, error)
minGOMAXPROCS int
printf func(string, ...interface{})
procs func(int, func(v float64) int) (int, iruntime.CPUQuotaStatus, error)
minGOMAXPROCS int
roundQuotaFunc func(v float64) int
}
func (c *config) log(fmt string, args ...interface{}) {
@@ -71,6 +72,13 @@ func Min(n int) Option {
})
}
// RoundQuotaFunc sets the function that will be used to covert the CPU quota from float to int.
func RoundQuotaFunc(rf func(v float64) int) Option {
return optionFunc(func(cfg *config) {
cfg.roundQuotaFunc = rf
})
}
type optionFunc func(*config)
func (of optionFunc) apply(cfg *config) { of(cfg) }
@@ -82,8 +90,9 @@ func (of optionFunc) apply(cfg *config) { of(cfg) }
// configured CPU quota.
func Set(opts ...Option) (func(), error) {
cfg := &config{
procs: iruntime.CPUQuotaToGOMAXPROCS,
minGOMAXPROCS: 1,
procs: iruntime.CPUQuotaToGOMAXPROCS,
roundQuotaFunc: iruntime.DefaultRoundFunc,
minGOMAXPROCS: 1,
}
for _, o := range opts {
o.apply(cfg)
@@ -96,13 +105,13 @@ func Set(opts ...Option) (func(), error) {
// Honor the GOMAXPROCS environment variable if present. Otherwise, amend
// `runtime.GOMAXPROCS()` with the current process' CPU quota if the OS is
// Linux, and guarantee a minimum value of 1. The minimum guaranteed value
// can be overriden using `maxprocs.Min()`.
// can be overridden using `maxprocs.Min()`.
if max, exists := os.LookupEnv(_maxProcsKey); exists {
cfg.log("maxprocs: Honoring GOMAXPROCS=%q as set in environment", max)
return undoNoop, nil
}
maxProcs, status, err := cfg.procs(cfg.minGOMAXPROCS)
maxProcs, status, err := cfg.procs(cfg.minGOMAXPROCS, cfg.roundQuotaFunc)
if err != nil {
return undoNoop, err
}

View File

@@ -21,4 +21,4 @@
package maxprocs
// Version is the current package version.
const Version = "1.4.0"
const Version = "1.6.0"

View File

@@ -393,8 +393,8 @@ func (g *generator) Generate(pkg *model.Package, outputPkgName string, outputPac
// try base0, base1, ...
pkgName := base
if _, ok := definedImports[base]; ok {
pkgName = definedImports[base]
if _, ok := definedImports[pth]; ok {
pkgName = definedImports[pth]
}
i := 0
@@ -758,6 +758,17 @@ func (g *generator) GenerateMockReturnCallMethod(intf *model.Interface, m *model
return nil
}
// nameExistsAsPackage returns true if the name exists as a package name.
// This is used to avoid name collisions when generating mock method arguments.
func (g *generator) nameExistsAsPackage(name string) bool {
for _, symbolName := range g.packageMap {
if symbolName == name {
return true
}
}
return false
}
func (g *generator) getArgNames(m *model.Method, in bool) []string {
var params []*model.Parameter
if in {
@@ -766,16 +777,19 @@ func (g *generator) getArgNames(m *model.Method, in bool) []string {
params = m.Out
}
argNames := make([]string, len(params))
for i, p := range params {
name := p.Name
if name == "" || name == "_" {
if name == "" || name == "_" || g.nameExistsAsPackage(name) {
name = fmt.Sprintf("arg%d", i)
}
argNames[i] = name
}
if m.Variadic != nil && in {
name := m.Variadic.Name
if name == "" {
if name == "" || g.nameExistsAsPackage(name) {
name = fmt.Sprintf("arg%d", len(params))
}
argNames = append(argNames, name)

View File

@@ -4,6 +4,7 @@ import (
"errors"
"flag"
"fmt"
"go/ast"
"go/types"
"strings"
@@ -17,6 +18,20 @@ var (
type packageModeParser struct {
pkgName string
// Mapping from underlying types to aliases used within the package source.
//
// We prefer to use aliases used in the source rather than underlying type names
// as those may be unexported or internal.
// TODO(joaks): Once mock is Go1.23+ only, we can remove this
// as the casing for types.Alias will automatically handle this
// in all cases.
aliasReplacements map[types.Type]aliasReplacement
}
type aliasReplacement struct {
name string
pkg string
}
func (p *packageModeParser) parsePackage(packageName string, ifaces []string) (*model.Package, error) {
@@ -27,6 +42,8 @@ func (p *packageModeParser) parsePackage(packageName string, ifaces []string) (*
return nil, fmt.Errorf("load package: %w", err)
}
p.buildAliasReplacements(pkg)
interfaces, err := p.extractInterfacesFromPackage(pkg, ifaces)
if err != nil {
return nil, fmt.Errorf("extract interfaces from package: %w", err)
@@ -39,6 +56,90 @@ func (p *packageModeParser) parsePackage(packageName string, ifaces []string) (*
}, nil
}
// buildAliasReplacements finds and records any references to aliases
// within the given package's source.
// These aliases will be preferred when parsing types
// over the underlying name counterparts, as those may be unexported / internal.
//
// If a type has more than one alias within the source package,
// the latest one to be inspected will be the one used for mapping.
// This is fine, since all aliases and their underlying types are interchangeable
// from a type-checking standpoint.
func (p *packageModeParser) buildAliasReplacements(pkg *packages.Package) {
p.aliasReplacements = make(map[types.Type]aliasReplacement)
// checkIdent checks if the given identifier exists
// in the given package as an alias, and adds it to
// the alias replacements map if so.
checkIdent := func(pkg *types.Package, ident string) bool {
scope := pkg.Scope()
if scope == nil {
return true
}
obj := scope.Lookup(ident)
if obj == nil {
return true
}
objTypeName, ok := obj.(*types.TypeName)
if !ok {
return true
}
if !objTypeName.IsAlias() {
return true
}
typ := objTypeName.Type()
if typ == nil {
return true
}
p.aliasReplacements[typ] = aliasReplacement{
name: objTypeName.Name(),
pkg: pkg.Path(),
}
return false
}
for _, f := range pkg.Syntax {
fileScope, ok := pkg.TypesInfo.Scopes[f]
if !ok {
continue
}
ast.Inspect(f, func(node ast.Node) bool {
// Simple identifiers: check if it is an alias
// from the source package.
if ident, ok := node.(*ast.Ident); ok {
return checkIdent(pkg.Types, ident.String())
}
// Selector expressions: check if it is an alias
// from the package represented by the qualifier.
selExpr, ok := node.(*ast.SelectorExpr)
if !ok {
return true
}
x, sel := selExpr.X, selExpr.Sel
xident, ok := x.(*ast.Ident)
if !ok {
return true
}
xObj := fileScope.Lookup(xident.String())
pkgName, ok := xObj.(*types.PkgName)
if !ok {
return true
}
xPkg := pkgName.Imported()
if xPkg == nil {
return true
}
return checkIdent(xPkg, sel.String())
})
}
}
func (p *packageModeParser) loadPackage(packageName string) (*packages.Package, error) {
var buildFlagsSet []string
if *buildFlags != "" {
@@ -46,7 +147,7 @@ func (p *packageModeParser) loadPackage(packageName string) (*packages.Package,
}
cfg := &packages.Config{
Mode: packages.NeedDeps | packages.NeedImports | packages.NeedTypes | packages.NeedTypesInfo | packages.NeedEmbedFiles,
Mode: packages.NeedDeps | packages.NeedImports | packages.NeedTypes | packages.NeedTypesInfo | packages.NeedEmbedFiles | packages.LoadSyntax,
BuildFlags: buildFlagsSet,
}
pkgs, err := packages.Load(cfg, packageName)
@@ -193,17 +294,26 @@ func (p *packageModeParser) parseType(t types.Type) (model.Type, error) {
return sig, nil
case *types.Named, *types.Alias:
object := t.(interface{ Obj() *types.TypeName })
name := object.Obj().Name()
var pkg string
if object.Obj().Pkg() != nil {
pkg = object.Obj().Pkg().Path()
}
// If there was an alias to this type used somewhere in the source,
// use that alias instead of the underlying type,
// since the underlying type might be unexported.
if alias, ok := p.aliasReplacements[t]; ok {
name = alias.name
pkg = alias.pkg
}
// TypeArgs method not available for aliases in go1.22
genericType, ok := t.(interface{ TypeArgs() *types.TypeList })
if !ok || genericType.TypeArgs() == nil {
return &model.NamedType{
Package: pkg,
Type: object.Obj().Name(),
Type: name,
}, nil
}
@@ -220,7 +330,7 @@ func (p *packageModeParser) parseType(t types.Type) (model.Type, error) {
return &model.NamedType{
Package: pkg,
Type: object.Obj().Name(),
Type: name,
TypeParams: typeParams,
}, nil
case *types.Interface: