"cmd/go/internal/cache"
"cmd/go/internal/cfg"
"cmd/go/internal/robustio"
- "cmd/go/internal/work"
"cmd/internal/sys"
)
}`)
testStr := "test test test test test \n\\ "
var buf bytes.Buffer
- for buf.Len() < work.ArgLengthForResponseFile+1 {
+ for buf.Len() < sys.ExecArgLengthLimit+1 {
buf.WriteString(testStr)
}
tg.run("run", "-ldflags", fmt.Sprintf(`-X "main.extern=%s"`, buf.String()), tg.path("main.go"))
"fmt"
"os"
"path/filepath"
- "runtime"
- "sync"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/modload"
- "cmd/internal/str"
+ "cmd/internal/sys"
)
func init() {
func runFmt(ctx context.Context, cmd *base.Command, args []string) {
printed := false
gofmt := gofmtPath()
- procs := runtime.GOMAXPROCS(0)
- var wg sync.WaitGroup
- wg.Add(procs)
- fileC := make(chan string, 2*procs)
- for i := 0; i < procs; i++ {
- go func() {
- defer wg.Done()
- for file := range fileC {
- base.Run(str.StringList(gofmt, "-l", "-w", file))
- }
- }()
- }
+
+ gofmtArgs := []string{gofmt, "-l", "-w"}
+ gofmtArgLen := len(gofmt) + len(" -l -w")
+
+ baseGofmtArgs := len(gofmtArgs)
+ baseGofmtArgLen := gofmtArgLen
+
for _, pkg := range load.PackagesAndErrors(ctx, load.PackageOpts{}, args) {
if modload.Enabled() && pkg.Module != nil && !pkg.Module.Main {
if !printed {
// not to packages in subdirectories.
files := base.RelPaths(pkg.InternalAllGoFiles())
for _, file := range files {
- fileC <- file
+ gofmtArgs = append(gofmtArgs, file)
+ gofmtArgLen += 1 + len(file) // plus separator
+ if gofmtArgLen >= sys.ExecArgLengthLimit {
+ base.Run(gofmtArgs)
+ gofmtArgs = gofmtArgs[:baseGofmtArgs]
+ gofmtArgLen = baseGofmtArgLen
+ }
}
}
- close(fileC)
- wg.Wait()
+ if len(gofmtArgs) > baseGofmtArgs {
+ base.Run(gofmtArgs)
+ }
}
func gofmtPath() string {
"cmd/go/internal/modload"
"cmd/go/internal/trace"
"cmd/internal/str"
+ "cmd/internal/sys"
)
// actionList returns the list of actions in the dag rooted at root
return cleanup
}
-// Windows has a limit of 32 KB arguments. To be conservative and not worry
-// about whether that includes spaces or not, just use 30 KB. Darwin's limit is
-// less clear. The OS claims 256KB, but we've seen failures with arglen as
-// small as 50KB.
-const ArgLengthForResponseFile = (30 << 10)
-
func useResponseFile(path string, argLen int) bool {
// Unless the program uses objabi.Flagparse, which understands
// response files, don't use response files.
return false
}
- if argLen > ArgLengthForResponseFile {
+ if argLen > sys.ExecArgLengthLimit {
return true
}
import (
"bytes"
"cmd/internal/objabi"
+ "cmd/internal/sys"
"fmt"
"math/rand"
"testing"
}
t.Parallel()
- nRunes := ArgLengthForResponseFile + 100
+ nRunes := sys.ExecArgLengthLimit + 100
rBuffer := make([]rune, nRunes)
buf := bytes.NewBuffer([]byte(string(rBuffer)))
for i := 0; i < 50; i++ {
// Generate a random string of runes.
buf.Reset()
- for buf.Len() < ArgLengthForResponseFile+1 {
+ for buf.Len() < sys.ExecArgLengthLimit+1 {
var r rune
for {
r = rune(rng.Intn(utf8.MaxRune + 1))
--- /dev/null
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sys
+
+// ExecArgLengthLimit is the number of bytes we can safely
+// pass as arguments to an exec.Command.
+//
+// Windows has a limit of 32 KB. To be conservative and not worry about whether
+// that includes spaces or not, just use 30 KB. Darwin's limit is less clear.
+// The OS claims 256KB, but we've seen failures with arglen as small as 50KB.
+const ExecArgLengthLimit = (30 << 10)