@@ -5,10 +5,10 @@ import (
5
5
"context"
6
6
"crypto/sha256"
7
7
"encoding/json"
8
- "fmt"
9
8
"io"
10
9
"os"
11
10
"path/filepath"
11
+ "strings"
12
12
"time"
13
13
14
14
"github.com/fatih/color"
@@ -31,8 +31,9 @@ import (
31
31
)
32
32
33
33
type Executor struct {
34
- rootCmd * cobra.Command
35
- runCmd * cobra.Command
34
+ rootCmd * cobra.Command
35
+ runCmd * cobra.Command
36
+ lintersCmd * cobra.Command
36
37
37
38
exitCode int
38
39
version , commit , date string
@@ -55,6 +56,7 @@ type Executor struct {
55
56
}
56
57
57
58
func NewExecutor (version , commit , date string ) * Executor {
59
+ startedAt := time .Now ()
58
60
e := & Executor {
59
61
cfg : config .NewDefault (),
60
62
version : version ,
@@ -66,9 +68,6 @@ func NewExecutor(version, commit, date string) *Executor {
66
68
67
69
e .debugf ("Starting execution..." )
68
70
e .log = report .NewLogWrapper (logutils .NewStderrLog ("" ), & e .reportData )
69
- if ok := e .acquireFileLock (); ! ok {
70
- e .log .Fatalf ("Parallel golangci-lint is running" )
71
- }
72
71
73
72
// to setup log level early we need to parse config from command line extra time to
74
73
// find `-v` option
@@ -121,6 +120,7 @@ func NewExecutor(version, commit, date string) *Executor {
121
120
122
121
// Slice options must be explicitly set for proper merging of config and command-line options.
123
122
fixSlicesFlags (e .runCmd .Flags ())
123
+ fixSlicesFlags (e .lintersCmd .Flags ())
124
124
125
125
e .EnabledLintersSet = lintersdb .NewEnabledSet (e .DBManager ,
126
126
lintersdb .NewValidator (e .DBManager ), e .log .Child ("lintersdb" ), e .cfg )
@@ -139,7 +139,7 @@ func NewExecutor(version, commit, date string) *Executor {
139
139
if err = e .initHashSalt (version ); err != nil {
140
140
e .log .Fatalf ("Failed to init hash salt: %s" , err )
141
141
}
142
- e .debugf ("Initialized executor" )
142
+ e .debugf ("Initialized executor in %s" , time . Since ( startedAt ) )
143
143
return e
144
144
}
145
145
@@ -191,27 +191,39 @@ func computeBinarySalt(version string) ([]byte, error) {
191
191
}
192
192
193
193
func computeConfigSalt (cfg * config.Config ) ([]byte , error ) {
194
- configBytes , err := json .Marshal (cfg )
194
+ // We don't hash all config fields to reduce meaningless cache
195
+ // invalidations. At least, it has a huge impact on tests speed.
196
+
197
+ lintersSettingsBytes , err := json .Marshal (cfg .LintersSettings )
195
198
if err != nil {
196
- return nil , errors .Wrap (err , "failed to json marshal config" )
199
+ return nil , errors .Wrap (err , "failed to json marshal config linter settings " )
197
200
}
198
201
202
+ var configData bytes.Buffer
203
+ configData .WriteString ("linters-settings=" )
204
+ configData .Write (lintersSettingsBytes )
205
+ configData .WriteString ("\n build-tags=%s" + strings .Join (cfg .Run .BuildTags , "," ))
206
+
199
207
h := sha256 .New ()
200
- if n , err := h .Write (configBytes ); n != len (configBytes ) {
201
- return nil , fmt .Errorf ("failed to hash config bytes: wrote %d/%d bytes, error: %s" , n , len (configBytes ), err )
202
- }
208
+ h .Write (configData .Bytes ()) //nolint:errcheck
203
209
return h .Sum (nil ), nil
204
210
}
205
211
206
212
func (e * Executor ) acquireFileLock () bool {
213
+ if e .cfg .Run .AllowParallelRunners {
214
+ e .debugf ("Parallel runners are allowed, no locking" )
215
+ return true
216
+ }
217
+
207
218
lockFile := filepath .Join (os .TempDir (), "golangci-lint.lock" )
208
219
e .debugf ("Locking on file %s..." , lockFile )
209
220
f := flock .New (lockFile )
210
- ctx , finish := context .WithTimeout (context .Background (), time .Minute )
221
+ const totalTimeout = 5 * time .Second
222
+ const retryDelay = time .Second
223
+ ctx , finish := context .WithTimeout (context .Background (), totalTimeout )
211
224
defer finish ()
212
225
213
- timeout := time .Second * 3
214
- if ok , _ := f .TryLockContext (ctx , timeout ); ! ok {
226
+ if ok , _ := f .TryLockContext (ctx , retryDelay ); ! ok {
215
227
return false
216
228
}
217
229
@@ -220,6 +232,10 @@ func (e *Executor) acquireFileLock() bool {
220
232
}
221
233
222
234
func (e * Executor ) releaseFileLock () {
235
+ if e .cfg .Run .AllowParallelRunners {
236
+ return
237
+ }
238
+
223
239
if err := e .flock .Unlock (); err != nil {
224
240
e .debugf ("Failed to unlock on file: %s" , err )
225
241
}
0 commit comments