Skip to content

Commit 634fb4a

Browse files
committed
Make incremental analysis
Cache linting results. Reanalyze only changed packages and packages tree depending on them. Fixes: #768
1 parent ca6effb commit 634fb4a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+907
-419
lines changed

.golangci.yml

+13-1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ linters-settings:
4343
disabled-checks:
4444
- wrapperFunc
4545
- dupImport # https://github.com/go-critic/go-critic/issues/845
46+
- ifElseChain
47+
- octalLiteral
4648
funlen:
4749
lines: 100
4850
statements: 50
@@ -95,7 +97,17 @@ linters:
9597
run:
9698
skip-dirs:
9799
- test/testdata_etc
98-
- internal/(cache|renameio|robustio)
100+
skip-files:
101+
- internal/cache/.*_test.go
102+
103+
issues:
104+
exclude-rules:
105+
- path: internal/(cache|renameio)/
106+
linters:
107+
- lll
108+
- gochecknoinits
109+
- gocyclo
110+
- funlen
99111

100112
# golangci.com configuration
101113
# https://github.com/golangci/golangci/wiki/Configuration

README.md

+13-1
Original file line numberDiff line numberDiff line change
@@ -945,6 +945,8 @@ linters-settings:
945945
disabled-checks:
946946
- wrapperFunc
947947
- dupImport # https://github.com/go-critic/go-critic/issues/845
948+
- ifElseChain
949+
- octalLiteral
948950
funlen:
949951
lines: 100
950952
statements: 50
@@ -997,7 +999,17 @@ linters:
997999
run:
9981000
skip-dirs:
9991001
- test/testdata_etc
1000-
- internal/(cache|renameio|robustio)
1002+
skip-files:
1003+
- internal/cache/.*_test.go
1004+
1005+
issues:
1006+
exclude-rules:
1007+
- path: internal/(cache|renameio)/
1008+
linters:
1009+
- lll
1010+
- gochecknoinits
1011+
- gocyclo
1012+
- funlen
10011013
10021014
# golangci.com configuration
10031015
# https://github.com/golangci/golangci/wiki/Configuration

internal/cache/cache.go

+84-39
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212
"bytes"
1313
"crypto/sha256"
1414
"encoding/hex"
15-
"errors"
1615
"fmt"
1716
"io"
1817
"io/ioutil"
@@ -22,6 +21,8 @@ import (
2221
"strings"
2322
"time"
2423

24+
"github.com/pkg/errors"
25+
2526
"github.com/golangci/golangci-lint/internal/renameio"
2627
)
2728

@@ -144,47 +145,56 @@ func (c *Cache) get(id ActionID) (Entry, error) {
144145
missing := func() (Entry, error) {
145146
return Entry{}, errMissing
146147
}
147-
f, err := os.Open(c.fileName(id, "a"))
148+
failed := func(err error) (Entry, error) {
149+
return Entry{}, err
150+
}
151+
fileName := c.fileName(id, "a")
152+
f, err := os.Open(fileName)
148153
if err != nil {
149-
return missing()
154+
if os.IsNotExist(err) {
155+
return missing()
156+
}
157+
return failed(err)
150158
}
151159
defer f.Close()
152160
entry := make([]byte, entrySize+1) // +1 to detect whether f is too long
153-
if n, err := io.ReadFull(f, entry); n != entrySize || err != io.ErrUnexpectedEOF {
154-
return missing()
161+
if n, readErr := io.ReadFull(f, entry); n != entrySize || readErr != io.ErrUnexpectedEOF {
162+
return failed(fmt.Errorf("read %d/%d bytes from %s with error %s", n, entrySize, fileName, readErr))
155163
}
156164
if entry[0] != 'v' || entry[1] != '1' || entry[2] != ' ' || entry[3+hexSize] != ' ' || entry[3+hexSize+1+hexSize] != ' ' || entry[3+hexSize+1+hexSize+1+20] != ' ' || entry[entrySize-1] != '\n' {
157-
return missing()
165+
return failed(fmt.Errorf("bad data in %s", fileName))
158166
}
159167
eid, entry := entry[3:3+hexSize], entry[3+hexSize:]
160168
eout, entry := entry[1:1+hexSize], entry[1+hexSize:]
161169
esize, entry := entry[1:1+20], entry[1+20:]
162-
etime, entry := entry[1:1+20], entry[1+20:]
170+
etime := entry[1 : 1+20]
163171
var buf [HashSize]byte
164-
if _, err := hex.Decode(buf[:], eid); err != nil || buf != id {
165-
return missing()
172+
if _, err = hex.Decode(buf[:], eid); err != nil || buf != id {
173+
return failed(errors.Wrapf(err, "failed to hex decode eid data in %s", fileName))
166174
}
167-
if _, err := hex.Decode(buf[:], eout); err != nil {
168-
return missing()
175+
if _, err = hex.Decode(buf[:], eout); err != nil {
176+
return failed(errors.Wrapf(err, "failed to hex decode eout data in %s", fileName))
169177
}
170178
i := 0
171179
for i < len(esize) && esize[i] == ' ' {
172180
i++
173181
}
174182
size, err := strconv.ParseInt(string(esize[i:]), 10, 64)
175183
if err != nil || size < 0 {
176-
return missing()
184+
return failed(fmt.Errorf("failed to parse esize int from %s with error %s", fileName, err))
177185
}
178186
i = 0
179187
for i < len(etime) && etime[i] == ' ' {
180188
i++
181189
}
182190
tm, err := strconv.ParseInt(string(etime[i:]), 10, 64)
183191
if err != nil || tm < 0 {
184-
return missing()
192+
return failed(fmt.Errorf("failed to parse etime int from %s with error %s", fileName, err))
185193
}
186194

187-
c.used(c.fileName(id, "a"))
195+
if err = c.used(fileName); err != nil {
196+
return failed(errors.Wrapf(err, "failed to mark %s as used", fileName))
197+
}
188198

189199
return Entry{buf, size, time.Unix(0, tm)}, nil
190200
}
@@ -196,7 +206,12 @@ func (c *Cache) GetFile(id ActionID) (file string, entry Entry, err error) {
196206
if err != nil {
197207
return "", Entry{}, err
198208
}
199-
file = c.OutputFile(entry.OutputID)
209+
210+
file, err = c.OutputFile(entry.OutputID)
211+
if err != nil {
212+
return "", Entry{}, err
213+
}
214+
200215
info, err := os.Stat(file)
201216
if err != nil || info.Size() != entry.Size {
202217
return "", Entry{}, errMissing
@@ -212,18 +227,29 @@ func (c *Cache) GetBytes(id ActionID) ([]byte, Entry, error) {
212227
if err != nil {
213228
return nil, entry, err
214229
}
215-
data, _ := ioutil.ReadFile(c.OutputFile(entry.OutputID))
230+
outputFile, err := c.OutputFile(entry.OutputID)
231+
if err != nil {
232+
return nil, entry, err
233+
}
234+
235+
data, err := ioutil.ReadFile(outputFile)
236+
if err != nil {
237+
return nil, entry, err
238+
}
239+
216240
if sha256.Sum256(data) != entry.OutputID {
217241
return nil, entry, errMissing
218242
}
219243
return data, entry, nil
220244
}
221245

222246
// OutputFile returns the name of the cache file storing output with the given OutputID.
223-
func (c *Cache) OutputFile(out OutputID) string {
247+
func (c *Cache) OutputFile(out OutputID) (string, error) {
224248
file := c.fileName(out, "d")
225-
c.used(file)
226-
return file
249+
if err := c.used(file); err != nil {
250+
return "", err
251+
}
252+
return file, nil
227253
}
228254

229255
// Time constants for cache expiration.
@@ -253,12 +279,21 @@ const (
253279
// mtime is more than an hour old. This heuristic eliminates
254280
// nearly all of the mtime updates that would otherwise happen,
255281
// while still keeping the mtimes useful for cache trimming.
256-
func (c *Cache) used(file string) {
282+
func (c *Cache) used(file string) error {
257283
info, err := os.Stat(file)
258-
if err == nil && c.now().Sub(info.ModTime()) < mtimeInterval {
259-
return
284+
if err != nil {
285+
return errors.Wrapf(err, "failed to stat file %s", file)
260286
}
261-
os.Chtimes(file, c.now(), c.now())
287+
288+
if c.now().Sub(info.ModTime()) < mtimeInterval {
289+
return nil
290+
}
291+
292+
if err := os.Chtimes(file, c.now(), c.now()); err != nil {
293+
return errors.Wrapf(err, "failed to change time of file %s", file)
294+
}
295+
296+
return nil
262297
}
263298

264299
// Trim removes old cache entries that are likely not to be reused.
@@ -285,7 +320,7 @@ func (c *Cache) Trim() {
285320

286321
// Ignore errors from here: if we don't write the complete timestamp, the
287322
// cache will appear older than it is, and we'll trim it again next time.
288-
renameio.WriteFile(filepath.Join(c.dir, "trim.txt"), []byte(fmt.Sprintf("%d", now.Unix())), 0666)
323+
_ = renameio.WriteFile(filepath.Join(c.dir, "trim.txt"), []byte(fmt.Sprintf("%d", now.Unix())), 0666)
289324
}
290325

291326
// trimSubdir trims a single cache subdirectory.
@@ -367,7 +402,9 @@ func (c *Cache) putIndexEntry(id ActionID, out OutputID, size int64, allowVerify
367402
os.Remove(file)
368403
return err
369404
}
370-
os.Chtimes(file, c.now(), c.now()) // mainly for tests
405+
if err = os.Chtimes(file, c.now(), c.now()); err != nil { // mainly for tests
406+
return errors.Wrapf(err, "failed to change time of file %s", file)
407+
}
371408

372409
return nil
373410
}
@@ -421,9 +458,12 @@ func (c *Cache) copyFile(file io.ReadSeeker, out OutputID, size int64) error {
421458
info, err := os.Stat(name)
422459
if err == nil && info.Size() == size {
423460
// Check hash.
424-
if f, err := os.Open(name); err == nil {
461+
if f, openErr := os.Open(name); openErr == nil {
425462
h := sha256.New()
426-
io.Copy(h, f)
463+
if _, copyErr := io.Copy(h, f); copyErr != nil {
464+
return errors.Wrap(copyErr, "failed to copy to sha256")
465+
}
466+
427467
f.Close()
428468
var out2 OutputID
429469
h.Sum(out2[:0])
@@ -456,44 +496,49 @@ func (c *Cache) copyFile(file io.ReadSeeker, out OutputID, size int64) error {
456496
// before returning, to avoid leaving bad bytes in the file.
457497

458498
// Copy file to f, but also into h to double-check hash.
459-
if _, err := file.Seek(0, 0); err != nil {
460-
f.Truncate(0)
499+
if _, err = file.Seek(0, 0); err != nil {
500+
_ = f.Truncate(0)
461501
return err
462502
}
463503
h := sha256.New()
464504
w := io.MultiWriter(f, h)
465-
if _, err := io.CopyN(w, file, size-1); err != nil {
466-
f.Truncate(0)
505+
if _, err = io.CopyN(w, file, size-1); err != nil {
506+
_ = f.Truncate(0)
467507
return err
468508
}
469509
// Check last byte before writing it; writing it will make the size match
470510
// what other processes expect to find and might cause them to start
471511
// using the file.
472512
buf := make([]byte, 1)
473-
if _, err := file.Read(buf); err != nil {
474-
f.Truncate(0)
513+
if _, err = file.Read(buf); err != nil {
514+
_ = f.Truncate(0)
475515
return err
476516
}
477-
h.Write(buf)
517+
if n, wErr := h.Write(buf); n != len(buf) {
518+
return fmt.Errorf("wrote to hash %d/%d bytes with error %s", n, len(buf), wErr)
519+
}
520+
478521
sum := h.Sum(nil)
479522
if !bytes.Equal(sum, out[:]) {
480-
f.Truncate(0)
523+
_ = f.Truncate(0)
481524
return fmt.Errorf("file content changed underfoot")
482525
}
483526

484527
// Commit cache file entry.
485-
if _, err := f.Write(buf); err != nil {
486-
f.Truncate(0)
528+
if _, err = f.Write(buf); err != nil {
529+
_ = f.Truncate(0)
487530
return err
488531
}
489-
if err := f.Close(); err != nil {
532+
if err = f.Close(); err != nil {
490533
// Data might not have been written,
491534
// but file may look like it is the right size.
492535
// To be extra careful, remove cached file.
493536
os.Remove(name)
494537
return err
495538
}
496-
os.Chtimes(name, c.now(), c.now()) // mainly for tests
539+
if err = os.Chtimes(name, c.now(), c.now()); err != nil { // mainly for tests
540+
return errors.Wrapf(err, "failed to change time of file %s", name)
541+
}
497542

498543
return nil
499544
}

internal/cache/default.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ func initDefaultCache() {
3939
}
4040
if _, err := os.Stat(filepath.Join(dir, "README")); err != nil {
4141
// Best effort.
42-
ioutil.WriteFile(filepath.Join(dir, "README"), []byte(cacheREADME), 0666)
42+
if wErr := ioutil.WriteFile(filepath.Join(dir, "README"), []byte(cacheREADME), 0666); wErr != nil {
43+
log.Fatalf("Failed to write README file to cache dir %s: %s", dir, err)
44+
}
4345
}
4446

4547
c, err := Open(dir)

internal/cache/hash.go

+18-8
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,19 @@ func SetSalt(b []byte) {
4242

4343
// Subkey returns an action ID corresponding to mixing a parent
4444
// action ID with a string description of the subkey.
45-
func Subkey(parent ActionID, desc string) ActionID {
45+
func Subkey(parent ActionID, desc string) (ActionID, error) {
4646
h := sha256.New()
47-
h.Write([]byte("subkey:"))
48-
h.Write(parent[:])
49-
h.Write([]byte(desc))
47+
const subkeyPrefix = "subkey:"
48+
if n, err := h.Write([]byte(subkeyPrefix)); n != len(subkeyPrefix) {
49+
return ActionID{}, fmt.Errorf("wrote %d/%d bytes of subkey prefix with error %s", n, len(subkeyPrefix), err)
50+
}
51+
if n, err := h.Write(parent[:]); n != len(parent) {
52+
return ActionID{}, fmt.Errorf("wrote %d/%d bytes of parent with error %s", n, len(parent), err)
53+
}
54+
if n, err := h.Write([]byte(desc)); n != len(desc) {
55+
return ActionID{}, fmt.Errorf("wrote %d/%d bytes of desc with error %s", n, len(desc), err)
56+
}
57+
5058
var out ActionID
5159
h.Sum(out[:0])
5260
if debugHash {
@@ -57,21 +65,23 @@ func Subkey(parent ActionID, desc string) ActionID {
5765
hashDebug.m[out] = fmt.Sprintf("subkey %x %q", parent, desc)
5866
hashDebug.Unlock()
5967
}
60-
return out
68+
return out, nil
6169
}
6270

6371
// NewHash returns a new Hash.
6472
// The caller is expected to Write data to it and then call Sum.
65-
func NewHash(name string) *Hash {
73+
func NewHash(name string) (*Hash, error) {
6674
h := &Hash{h: sha256.New(), name: name}
6775
if debugHash {
6876
fmt.Fprintf(os.Stderr, "HASH[%s]\n", h.name)
6977
}
70-
h.Write(hashSalt)
78+
if n, err := h.Write(hashSalt); n != len(hashSalt) {
79+
return nil, fmt.Errorf("wrote %d/%d bytes of hash salt with error %s", n, len(hashSalt), err)
80+
}
7181
if verify {
7282
h.buf = new(bytes.Buffer)
7383
}
74-
return h
84+
return h, nil
7585
}
7686

7787
// Write writes data to the running hash.

internal/cache/hash_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ func TestHash(t *testing.T) {
1818
hashSalt = oldSalt
1919
}()
2020

21-
h := NewHash("alice")
21+
h, _ := NewHash("alice")
2222
h.Write([]byte("hello world"))
2323
sum := fmt.Sprintf("%x", h.Sum())
2424
want := "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"

0 commit comments

Comments
 (0)