Skip to content

Commit 9410ac1

Browse files
committed
chore: sync with go1.24.1
1 parent 161776b commit 9410ac1

25 files changed

+395
-463
lines changed

internal/cache/cache_test.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ func TestCache_buildKey(t *testing.T) {
9393
actionID, err := pkgCache.buildKey(pkg, HashModeNeedAllDeps, "")
9494
require.NoError(t, err)
9595

96-
assert.Equal(t, "f32bf1bf010aa9b570e081c64ec9e22e17aafa1e822990ba952905ec5fdf8d9d", fmt.Sprintf("%x", actionID))
96+
assert.Equal(t, "4db1e9671b1800244a938e1aabe6db77495a5dff82acb434ab435eaabff59372", fmt.Sprintf("%x", actionID))
9797
}
9898

9999
func TestCache_pkgActionID(t *testing.T) {
@@ -104,7 +104,7 @@ func TestCache_pkgActionID(t *testing.T) {
104104
actionID, err := pkgCache.pkgActionID(pkg, HashModeNeedAllDeps)
105105
require.NoError(t, err)
106106

107-
assert.Equal(t, "f690f05acd1024386ae912d9ad9c04080523b9a899f6afe56ab3108d88215c1d", fmt.Sprintf("%x", actionID))
107+
assert.Equal(t, "6ab6e6fea09b9390f266880ab504e267ea12b76b14a783013843effb1d7d31a5", fmt.Sprintf("%x", actionID))
108108
}
109109

110110
func TestCache_packageHash_load(t *testing.T) {
@@ -128,7 +128,7 @@ func TestCache_packageHash_store(t *testing.T) {
128128
hash, err := pkgCache.packageHash(pkg, HashModeNeedAllDeps)
129129
require.NoError(t, err)
130130

131-
assert.Equal(t, "9c602ef861197b6807e82c99caa7c4042eb03c1a92886303fb02893744355131", hash)
131+
assert.Equal(t, "11d5b95830a3d86ad6dcac15b0adb46f686a30f1633cc1b74f7133d093da7979", hash)
132132

133133
results, ok := pkgCache.pkgHashes.Load(pkg)
134134
require.True(t, ok)
@@ -137,9 +137,9 @@ func TestCache_packageHash_store(t *testing.T) {
137137

138138
require.Len(t, hashRes, 3)
139139

140-
assert.Equal(t, "8978e3d76c6f99e9663558d7147a7790f229a676804d1fde706a611898547b74", hashRes[HashModeNeedOnlySelf])
141-
assert.Equal(t, "b1aef902a0619b5cbfc2d6e2e91a73dd58dd448e58274b2d7a5ff8efd97aefa4", hashRes[HashModeNeedDirectDeps])
142-
assert.Equal(t, "9c602ef861197b6807e82c99caa7c4042eb03c1a92886303fb02893744355131", hashRes[HashModeNeedAllDeps])
140+
assert.Equal(t, "855344dcd4884d73c77e2eede91270d871e18b57aeb170007b5c682b39e52c96", hashRes[HashModeNeedOnlySelf])
141+
assert.Equal(t, "f1288ac9e75477e1ed42c06ba7d78213ed3cc52799c01a4f695bc54cd4e8a698", hashRes[HashModeNeedDirectDeps])
142+
assert.Equal(t, "11d5b95830a3d86ad6dcac15b0adb46f686a30f1633cc1b74f7133d093da7979", hashRes[HashModeNeedAllDeps])
143143
}
144144

145145
func TestCache_computeHash(t *testing.T) {
@@ -152,7 +152,7 @@ func TestCache_computeHash(t *testing.T) {
152152

153153
require.Len(t, results, 3)
154154

155-
assert.Equal(t, "8978e3d76c6f99e9663558d7147a7790f229a676804d1fde706a611898547b74", results[HashModeNeedOnlySelf])
156-
assert.Equal(t, "b1aef902a0619b5cbfc2d6e2e91a73dd58dd448e58274b2d7a5ff8efd97aefa4", results[HashModeNeedDirectDeps])
157-
assert.Equal(t, "9c602ef861197b6807e82c99caa7c4042eb03c1a92886303fb02893744355131", results[HashModeNeedAllDeps])
155+
assert.Equal(t, "855344dcd4884d73c77e2eede91270d871e18b57aeb170007b5c682b39e52c96", results[HashModeNeedOnlySelf])
156+
assert.Equal(t, "f1288ac9e75477e1ed42c06ba7d78213ed3cc52799c01a4f695bc54cd4e8a698", results[HashModeNeedDirectDeps])
157+
assert.Equal(t, "11d5b95830a3d86ad6dcac15b0adb46f686a30f1633cc1b74f7133d093da7979", results[HashModeNeedAllDeps])
158158
}

internal/go/base/error_notunix.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright 2023 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
//go:build !unix
6+
7+
package base
8+
9+
func IsETXTBSY(err error) bool {
10+
// syscall.ETXTBSY is only meaningful on Unix platforms.
11+
return false
12+
}

internal/go/base/error_unix.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2023 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
//go:build unix
6+
7+
package base
8+
9+
import (
10+
"errors"
11+
"syscall"
12+
)
13+
14+
func IsETXTBSY(err error) bool {
15+
return errors.Is(err, syscall.ETXTBSY)
16+
}

internal/go/base/readme.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# quoted
2+
3+
Extracted from `go/src/cmd/go/internal/base/` (related to `cache`).
4+
5+
Only the function `IsETXTBSY` is extracted.
6+
7+
## History
8+
9+
- https://github.com/golangci/golangci-lint/pull/xx
10+
- sync go1.24.1

internal/go/cache/cache.go

Lines changed: 97 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@ import (
2323
"time"
2424

2525
"github.com/rogpeppe/go-internal/lockedfile"
26+
"github.com/rogpeppe/go-internal/robustio"
2627

28+
"github.com/golangci/golangci-lint/v2/internal/go/base"
2729
"github.com/golangci/golangci-lint/v2/internal/go/mmap"
28-
"github.com/golangci/golangci-lint/v2/internal/go/robustio"
2930
)
3031

3132
// An ActionID is a cache action key, the hash of a complete description of a
@@ -41,8 +42,8 @@ type Cache interface {
4142
// Get returns the cache entry for the provided ActionID.
4243
// On miss, the error type should be of type *entryNotFoundError.
4344
//
44-
// After a success call to Get, OutputFile(Entry.OutputID) must
45-
// exist on disk for until Close is called (at the end of the process).
45+
// After a successful call to Get, OutputFile(Entry.OutputID) must
46+
// exist on disk until Close is called (at the end of the process).
4647
Get(ActionID) (Entry, error)
4748

4849
// Put adds an item to the cache.
@@ -53,14 +54,14 @@ type Cache interface {
5354
// As a special case, if the ReadSeeker is of type noVerifyReadSeeker,
5455
// the verification from GODEBUG=goverifycache=1 is skipped.
5556
//
56-
// After a success call to Get, OutputFile(Entry.OutputID) must
57-
// exist on disk for until Close is called (at the end of the process).
57+
// After a successful call to Put, OutputFile(OutputID) must
58+
// exist on disk until Close is called (at the end of the process).
5859
Put(ActionID, io.ReadSeeker) (_ OutputID, size int64, _ error)
5960

6061
// Close is called at the end of the go process. Implementations can do
6162
// cache cleanup work at this phase, or wait for and report any errors from
62-
// background cleanup work started earlier. Any cache trimming should in one
63-
// process should not violate cause the invariants of this interface to be
63+
// background cleanup work started earlier. Any cache trimming in one
64+
// process should not cause the invariants of this interface to be
6465
// violated in another process. Namely, a cache trim from one process should
6566
// not delete an ObjectID from disk that was recently Get or Put from
6667
// another process. As a rule of thumb, don't trim things used in the last
@@ -105,7 +106,7 @@ func Open(dir string) (*DiskCache, error) {
105106
}
106107
for i := 0; i < 256; i++ {
107108
name := filepath.Join(dir, fmt.Sprintf("%02x", i))
108-
if err := os.MkdirAll(name, 0744); err != nil {
109+
if err := os.MkdirAll(name, 0o777); err != nil {
109110
return nil, err
110111
}
111112
}
@@ -161,13 +162,13 @@ var errVerifyMode = errors.New("gocacheverify=1")
161162
var DebugTest = false
162163

163164
// func init() { initEnv() }
164-
165+
//
165166
// var (
166167
// gocacheverify = godebug.New("gocacheverify")
167168
// gocachehash = godebug.New("gocachehash")
168169
// gocachetest = godebug.New("gocachetest")
169170
// )
170-
171+
//
171172
// func initEnv() {
172173
// if gocacheverify.Value() == "1" {
173174
// gocacheverify.IncNonDefault()
@@ -258,10 +259,7 @@ func (c *DiskCache) get(id ActionID) (Entry, error) {
258259
return missing(errors.New("negative timestamp"))
259260
}
260261

261-
err = c.used(c.fileName(id, "a"))
262-
if err != nil {
263-
return Entry{}, fmt.Errorf("failed to mark %s as used: %w", c.fileName(id, "a"), err)
264-
}
262+
c.markUsed(c.fileName(id, "a"))
265263

266264
return Entry{buf, size, time.Unix(0, tm)}, nil
267265
}
@@ -305,25 +303,35 @@ func GetBytes(c Cache, id ActionID) ([]byte, Entry, error) {
305303
// GetMmap looks up the action ID in the cache and returns
306304
// the corresponding output bytes.
307305
// GetMmap should only be used for data that can be expected to fit in memory.
308-
func GetMmap(c Cache, id ActionID) ([]byte, Entry, error) {
306+
func GetMmap(c Cache, id ActionID) ([]byte, Entry, bool, error) {
309307
entry, err := c.Get(id)
310308
if err != nil {
311-
return nil, entry, err
309+
return nil, entry, false, err
312310
}
313-
md, err := mmap.Mmap(c.OutputFile(entry.OutputID))
311+
md, opened, err := mmap.Mmap(c.OutputFile(entry.OutputID))
314312
if err != nil {
315-
return nil, Entry{}, err
313+
return nil, Entry{}, opened, err
316314
}
317315
if int64(len(md.Data)) != entry.Size {
318-
return nil, Entry{}, &entryNotFoundError{Err: errors.New("file incomplete")}
316+
return nil, Entry{}, true, &entryNotFoundError{Err: errors.New("file incomplete")}
319317
}
320-
return md.Data, entry, nil
318+
return md.Data, entry, true, nil
321319
}
322320

323321
// OutputFile returns the name of the cache file storing output with the given OutputID.
324322
func (c *DiskCache) OutputFile(out OutputID) string {
325323
file := c.fileName(out, "d")
326-
c.used(file)
324+
isDir := c.markUsed(file)
325+
if isDir { // => cached executable
326+
entries, err := os.ReadDir(file)
327+
if err != nil {
328+
return fmt.Sprintf("DO NOT USE - missing binary cache entry: %v", err)
329+
}
330+
if len(entries) != 1 {
331+
return "DO NOT USE - invalid binary cache entry"
332+
}
333+
return filepath.Join(file, entries[0].Name())
334+
}
327335
return file
328336
}
329337

@@ -345,7 +353,7 @@ const (
345353
trimLimit = 5 * 24 * time.Hour
346354
)
347355

348-
// used makes a best-effort attempt to update mtime on file,
356+
// markUsed makes a best-effort attempt to update mtime on file,
349357
// so that mtime reflects cache access time.
350358
//
351359
// Because the reflection only needs to be approximate,
@@ -354,25 +362,17 @@ const (
354362
// mtime is more than an hour old. This heuristic eliminates
355363
// nearly all of the mtime updates that would otherwise happen,
356364
// while still keeping the mtimes useful for cache trimming.
357-
func (c *DiskCache) used(file string) error {
365+
//
366+
// markUsed reports whether the file is a directory (an executable cache entry).
367+
func (c *DiskCache) markUsed(file string) (isDir bool) {
358368
info, err := os.Stat(file)
359-
if err == nil && c.now().Sub(info.ModTime()) < mtimeInterval {
360-
return nil
361-
}
362-
363369
if err != nil {
364-
if os.IsNotExist(err) {
365-
return &entryNotFoundError{Err: err}
366-
}
367-
return &entryNotFoundError{Err: fmt.Errorf("failed to stat file %s: %w", file, err)}
370+
return false
368371
}
369-
370-
err = os.Chtimes(file, c.now(), c.now())
371-
if err != nil {
372-
return fmt.Errorf("failed to change time of file %s: %w", file, err)
372+
if now := c.now(); now.Sub(info.ModTime()) >= mtimeInterval {
373+
os.Chtimes(file, now, now)
373374
}
374-
375-
return nil
375+
return info.IsDir()
376376
}
377377

378378
func (c *DiskCache) Close() error { return c.Trim() }
@@ -410,7 +410,7 @@ func (c *DiskCache) Trim() error {
410410
// cache will appear older than it is, and we'll trim it again next time.
411411
var b bytes.Buffer
412412
fmt.Fprintf(&b, "%d", now.Unix())
413-
if err := lockedfile.Write(filepath.Join(c.dir, "trim.txt"), &b, 0666); err != nil {
413+
if err := lockedfile.Write(filepath.Join(c.dir, "trim.txt"), &b, 0o666); err != nil {
414414
return err
415415
}
416416

@@ -439,6 +439,10 @@ func (c *DiskCache) trimSubdir(subdir string, cutoff time.Time) {
439439
entry := filepath.Join(subdir, name)
440440
info, err := os.Stat(entry)
441441
if err == nil && info.ModTime().Before(cutoff) {
442+
if info.IsDir() { // executable cache entry
443+
os.RemoveAll(entry)
444+
continue
445+
}
442446
os.Remove(entry)
443447
}
444448
}
@@ -471,7 +475,7 @@ func (c *DiskCache) putIndexEntry(id ActionID, out OutputID, size int64, allowVe
471475

472476
// Copy file to cache directory.
473477
mode := os.O_WRONLY | os.O_CREATE
474-
f, err := os.OpenFile(file, mode, 0666)
478+
f, err := os.OpenFile(file, mode, 0o666)
475479
if err != nil {
476480
return err
477481
}
@@ -517,7 +521,21 @@ func (c *DiskCache) Put(id ActionID, file io.ReadSeeker) (OutputID, int64, error
517521
if isNoVerify {
518522
file = wrapper.ReadSeeker
519523
}
520-
return c.put(id, file, !isNoVerify)
524+
return c.put(id, "", file, !isNoVerify)
525+
}
526+
527+
// PutExecutable is used to store the output as the output for the action ID into a
528+
// file with the given base name, with the executable mode bit set.
529+
// It may read file twice. The content of file must not change between the two passes.
530+
func (c *DiskCache) PutExecutable(id ActionID, name string, file io.ReadSeeker) (OutputID, int64, error) {
531+
if name == "" {
532+
panic("PutExecutable called without a name")
533+
}
534+
wrapper, isNoVerify := file.(noVerifyReadSeeker)
535+
if isNoVerify {
536+
file = wrapper.ReadSeeker
537+
}
538+
return c.put(id, name, file, !isNoVerify)
521539
}
522540

523541
// PutNoVerify is like Put but disables the verify check
@@ -528,7 +546,7 @@ func PutNoVerify(c Cache, id ActionID, file io.ReadSeeker) (OutputID, int64, err
528546
return c.Put(id, noVerifyReadSeeker{file})
529547
}
530548

531-
func (c *DiskCache) put(id ActionID, file io.ReadSeeker, allowVerify bool) (OutputID, int64, error) {
549+
func (c *DiskCache) put(id ActionID, executableName string, file io.ReadSeeker, allowVerify bool) (OutputID, int64, error) {
532550
// Compute output ID.
533551
h := sha256.New()
534552
if _, err := file.Seek(0, 0); err != nil {
@@ -542,7 +560,11 @@ func (c *DiskCache) put(id ActionID, file io.ReadSeeker, allowVerify bool) (Outp
542560
h.Sum(out[:0])
543561

544562
// Copy to cached output file (if not already present).
545-
if err := c.copyFile(file, out, size); err != nil {
563+
fileMode := fs.FileMode(0o666)
564+
if executableName != "" {
565+
fileMode = 0o777
566+
}
567+
if err := c.copyFile(file, executableName, out, size, fileMode); err != nil {
546568
return out, size, err
547569
}
548570

@@ -558,9 +580,33 @@ func PutBytes(c Cache, id ActionID, data []byte) error {
558580

559581
// copyFile copies file into the cache, expecting it to have the given
560582
// output ID and size, if that file is not present already.
561-
func (c *DiskCache) copyFile(file io.ReadSeeker, out OutputID, size int64) error {
562-
name := c.fileName(out, "d")
583+
func (c *DiskCache) copyFile(file io.ReadSeeker, executableName string, out OutputID, size int64, perm os.FileMode) error {
584+
name := c.fileName(out, "d") // TODO(matloob): use a different suffix for the executable cache?
563585
info, err := os.Stat(name)
586+
if executableName != "" {
587+
// This is an executable file. The file at name won't hold the output itself, but will
588+
// be a directory that holds the output, named according to executableName. Check to see
589+
// if the directory already exists, and if it does not, create it. Then reset name
590+
// to the name we want the output written to.
591+
if err != nil {
592+
if !os.IsNotExist(err) {
593+
return err
594+
}
595+
if err := os.Mkdir(name, 0o777); err != nil {
596+
return err
597+
}
598+
if info, err = os.Stat(name); err != nil {
599+
return err
600+
}
601+
}
602+
if !info.IsDir() {
603+
return errors.New("internal error: invalid binary cache entry: not a directory")
604+
}
605+
606+
// directory exists. now set name to the inner file
607+
name = filepath.Join(name, executableName)
608+
info, err = os.Stat(name)
609+
}
564610
if err == nil && info.Size() == size {
565611
// Check hash.
566612
if f, err := os.Open(name); err == nil {
@@ -585,8 +631,14 @@ func (c *DiskCache) copyFile(file io.ReadSeeker, out OutputID, size int64) error
585631
if err == nil && info.Size() > size { // shouldn't happen but fix in case
586632
mode |= os.O_TRUNC
587633
}
588-
f, err := os.OpenFile(name, mode, 0666)
634+
f, err := os.OpenFile(name, mode, perm)
589635
if err != nil {
636+
if base.IsETXTBSY(err) {
637+
// This file is being used by an executable. It must have
638+
// already been written by another go process and then run.
639+
// return without an error.
640+
return nil
641+
}
590642
return err
591643
}
592644
defer f.Close()

0 commit comments

Comments
 (0)