Skip to content

Commit 04330a3

Browse files
committed
feat: add stats output similar to treefmt.rs
Signed-off-by: Brian McGee <[email protected]>
1 parent 8e23c86 commit 04330a3

File tree

5 files changed

+134
-43
lines changed

5 files changed

+134
-43
lines changed

cache/cache.go

+10-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import (
1111
"runtime"
1212
"time"
1313

14+
"git.numtide.com/numtide/treefmt/stats"
15+
1416
"git.numtide.com/numtide/treefmt/format"
1517
"git.numtide.com/numtide/treefmt/walk"
1618

@@ -33,9 +35,10 @@ type Entry struct {
3335
}
3436

3537
var (
36-
db *bolt.DB
38+
db *bolt.DB
39+
logger *log.Logger
40+
3741
ReadBatchSize = 1024 * runtime.NumCPU()
38-
logger *log.Logger
3942
)
4043

4144
// Open creates an instance of bolt.DB for a given treeRoot path.
@@ -234,11 +237,14 @@ func ChangeSet(ctx context.Context, walker walk.Walker, pathsCh chan<- string) e
234237

235238
changedOrNew := cached == nil || !(cached.Modified == info.ModTime() && cached.Size == info.Size())
236239

240+
stats.Add(stats.Traversed, 1)
237241
if !changedOrNew {
238242
// no change
239243
return nil
240244
}
241245

246+
stats.Add(stats.Emitted, 1)
247+
242248
// pass on the path
243249
select {
244250
case <-ctx.Done():
@@ -293,6 +299,8 @@ func Update(treeRoot string, paths []string) (int, error) {
293299
continue
294300
}
295301

302+
stats.Add(stats.Formatted, 1)
303+
296304
entry := Entry{
297305
Size: pathInfo.Size(),
298306
Modified: pathInfo.ModTime(),

cli/format.go

+10-4
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ import (
1414
"sort"
1515
"strings"
1616
"syscall"
17-
"time"
1817

1918
"git.numtide.com/numtide/treefmt/format"
19+
"git.numtide.com/numtide/treefmt/stats"
2020
"github.com/gobwas/glob"
2121

2222
"git.numtide.com/numtide/treefmt/cache"
@@ -32,7 +32,6 @@ const (
3232
)
3333

3434
var (
35-
start time.Time
3635
globalExcludes []glob.Glob
3736
formatters map[string]*format.Formatter
3837
pipelines map[string]*format.Pipeline
@@ -43,7 +42,7 @@ var (
4342
)
4443

4544
func (f *Format) Run() (err error) {
46-
start = time.Now()
45+
stats.Init()
4746

4847
Cli.Configure()
4948

@@ -196,6 +195,8 @@ func walkFilesystem(ctx context.Context) func() error {
196195
default:
197196
// ignore symlinks and directories
198197
if !(info.IsDir() || info.Mode()&os.ModeSymlink == os.ModeSymlink) {
198+
stats.Add(stats.Traversed, 1)
199+
stats.Add(stats.Emitted, 1)
199200
pathsCh <- path
200201
}
201202
return nil
@@ -257,7 +258,7 @@ func updateCache(ctx context.Context) func() error {
257258
return ErrFailOnChange
258259
}
259260

260-
fmt.Printf("%v files changed in %v\n", changes, time.Now().Sub(start))
261+
stats.Print()
261262
return nil
262263
}
263264
}
@@ -322,12 +323,17 @@ func applyFormatters(ctx context.Context) func() error {
322323
}()
323324

324325
for path := range pathsCh {
326+
var matched bool
325327
for key, pipeline := range pipelines {
326328
if !pipeline.Wants(path) {
327329
continue
328330
}
331+
matched = true
329332
tryApply(key, path)
330333
}
334+
if matched {
335+
stats.Add(stats.Matched, 1)
336+
}
331337
}
332338

333339
// flush any partial batches which remain

cli/format_test.go

+36-37
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package cli
22

33
import (
44
"bufio"
5-
"fmt"
65
"os"
76
"os/exec"
87
"path"
@@ -68,19 +67,19 @@ func TestSpecifyingFormatters(t *testing.T) {
6867

6968
out, err := cmd(t, "-c", "--config-file", configPath, "--tree-root", tempDir)
7069
as.NoError(err)
71-
as.Contains(string(out), "3 files changed")
70+
assertFormatted(t, as, out, 3)
7271

7372
out, err = cmd(t, "-c", "--config-file", configPath, "--tree-root", tempDir, "--formatters", "elm,nix")
7473
as.NoError(err)
75-
as.Contains(string(out), "2 files changed")
74+
assertFormatted(t, as, out, 2)
7675

7776
out, err = cmd(t, "-c", "--config-file", configPath, "--tree-root", tempDir, "--formatters", "ruby,nix")
7877
as.NoError(err)
79-
as.Contains(string(out), "2 files changed")
78+
assertFormatted(t, as, out, 2)
8079

8180
out, err = cmd(t, "-c", "--config-file", configPath, "--tree-root", tempDir, "--formatters", "nix")
8281
as.NoError(err)
83-
as.Contains(string(out), "1 files changed")
82+
assertFormatted(t, as, out, 1)
8483

8584
// test bad names
8685

@@ -110,23 +109,23 @@ func TestIncludesAndExcludes(t *testing.T) {
110109
test.WriteConfig(t, configPath, cfg)
111110
out, err := cmd(t, "-c", "--config-file", configPath, "--tree-root", tempDir)
112111
as.NoError(err)
113-
as.Contains(string(out), fmt.Sprintf("%d files changed", 31))
112+
assertFormatted(t, as, out, 31)
114113

115114
// globally exclude nix files
116115
cfg.Global.Excludes = []string{"*.nix"}
117116

118117
test.WriteConfig(t, configPath, cfg)
119118
out, err = cmd(t, "-c", "--config-file", configPath, "--tree-root", tempDir)
120119
as.NoError(err)
121-
as.Contains(string(out), fmt.Sprintf("%d files changed", 30))
120+
assertFormatted(t, as, out, 30)
122121

123122
// add haskell files to the global exclude
124123
cfg.Global.Excludes = []string{"*.nix", "*.hs"}
125124

126125
test.WriteConfig(t, configPath, cfg)
127126
out, err = cmd(t, "-c", "--config-file", configPath, "--tree-root", tempDir)
128127
as.NoError(err)
129-
as.Contains(string(out), fmt.Sprintf("%d files changed", 24))
128+
assertFormatted(t, as, out, 24)
130129

131130
echo := cfg.Formatters["echo"]
132131

@@ -136,31 +135,31 @@ func TestIncludesAndExcludes(t *testing.T) {
136135
test.WriteConfig(t, configPath, cfg)
137136
out, err = cmd(t, "-c", "--config-file", configPath, "--tree-root", tempDir)
138137
as.NoError(err)
139-
as.Contains(string(out), fmt.Sprintf("%d files changed", 22))
138+
assertFormatted(t, as, out, 22)
140139

141140
// remove go files from the echo formatter
142141
echo.Excludes = []string{"*.py", "*.go"}
143142

144143
test.WriteConfig(t, configPath, cfg)
145144
out, err = cmd(t, "-c", "--config-file", configPath, "--tree-root", tempDir)
146145
as.NoError(err)
147-
as.Contains(string(out), fmt.Sprintf("%d files changed", 21))
146+
assertFormatted(t, as, out, 21)
148147

149148
// adjust the includes for echo to only include elm files
150149
echo.Includes = []string{"*.elm"}
151150

152151
test.WriteConfig(t, configPath, cfg)
153152
out, err = cmd(t, "-c", "--config-file", configPath, "--tree-root", tempDir)
154153
as.NoError(err)
155-
as.Contains(string(out), fmt.Sprintf("%d files changed", 1))
154+
assertFormatted(t, as, out, 1)
156155

157156
// add js files to echo formatter
158157
echo.Includes = []string{"*.elm", "*.js"}
159158

160159
test.WriteConfig(t, configPath, cfg)
161160
out, err = cmd(t, "-c", "--config-file", configPath, "--tree-root", tempDir)
162161
as.NoError(err)
163-
as.Contains(string(out), fmt.Sprintf("%d files changed", 2))
162+
assertFormatted(t, as, out, 2)
164163
}
165164

166165
func TestCache(t *testing.T) {
@@ -182,34 +181,34 @@ func TestCache(t *testing.T) {
182181
test.WriteConfig(t, configPath, cfg)
183182
out, err := cmd(t, "--config-file", configPath, "--tree-root", tempDir)
184183
as.NoError(err)
185-
as.Contains(string(out), fmt.Sprintf("%d files changed", 31))
184+
assertFormatted(t, as, out, 31)
186185

187186
out, err = cmd(t, "--config-file", configPath, "--tree-root", tempDir)
188187
as.NoError(err)
189-
as.Contains(string(out), "0 files changed")
188+
assertFormatted(t, as, out, 0)
190189

191190
// clear cache
192191
out, err = cmd(t, "--config-file", configPath, "--tree-root", tempDir, "-c")
193192
as.NoError(err)
194-
as.Contains(string(out), fmt.Sprintf("%d files changed", 31))
193+
assertFormatted(t, as, out, 31)
195194

196195
out, err = cmd(t, "--config-file", configPath, "--tree-root", tempDir)
197196
as.NoError(err)
198-
as.Contains(string(out), "0 files changed")
197+
assertFormatted(t, as, out, 0)
199198

200199
// clear cache
201200
out, err = cmd(t, "--config-file", configPath, "--tree-root", tempDir, "-c")
202201
as.NoError(err)
203-
as.Contains(string(out), fmt.Sprintf("%d files changed", 31))
202+
assertFormatted(t, as, out, 31)
204203

205204
out, err = cmd(t, "--config-file", configPath, "--tree-root", tempDir)
206205
as.NoError(err)
207-
as.Contains(string(out), "0 files changed")
206+
assertFormatted(t, as, out, 0)
208207

209208
// no cache
210209
out, err = cmd(t, "--config-file", configPath, "--tree-root", tempDir, "--no-cache")
211210
as.NoError(err)
212-
as.Contains(string(out), fmt.Sprintf("%d files changed", 31))
211+
assertStats(t, as, out, 31, 31, 31, 0)
213212
}
214213

215214
func TestChangeWorkingDirectory(t *testing.T) {
@@ -243,7 +242,7 @@ func TestChangeWorkingDirectory(t *testing.T) {
243242
// this should fail if the working directory hasn't been changed first
244243
out, err := cmd(t, "-C", tempDir)
245244
as.NoError(err)
246-
as.Contains(string(out), fmt.Sprintf("%d files changed", 31))
245+
assertFormatted(t, as, out, 31)
247246
}
248247

249248
func TestFailOnChange(t *testing.T) {
@@ -307,31 +306,31 @@ func TestBustCacheOnFormatterChange(t *testing.T) {
307306
args := []string{"--config-file", configPath, "--tree-root", tempDir}
308307
out, err := cmd(t, args...)
309308
as.NoError(err)
310-
as.Contains(string(out), fmt.Sprintf("%d files changed", 3))
309+
assertFormatted(t, as, out, 3)
311310

312311
// tweak mod time of elm formatter
313312
as.NoError(test.RecreateSymlink(t, binPath+"/"+"elm-format"))
314313

315314
out, err = cmd(t, args...)
316315
as.NoError(err)
317-
as.Contains(string(out), fmt.Sprintf("%d files changed", 3))
316+
assertFormatted(t, as, out, 3)
318317

319318
// check cache is working
320319
out, err = cmd(t, args...)
321320
as.NoError(err)
322-
as.Contains(string(out), "0 files changed")
321+
assertFormatted(t, as, out, 0)
323322

324323
// tweak mod time of python formatter
325324
as.NoError(test.RecreateSymlink(t, binPath+"/"+"black"))
326325

327326
out, err = cmd(t, args...)
328327
as.NoError(err)
329-
as.Contains(string(out), fmt.Sprintf("%d files changed", 3))
328+
assertFormatted(t, as, out, 3)
330329

331330
// check cache is working
332331
out, err = cmd(t, args...)
333332
as.NoError(err)
334-
as.Contains(string(out), "0 files changed")
333+
assertFormatted(t, as, out, 0)
335334

336335
// add go formatter
337336
cfg.Formatters["go"] = &config2.Formatter{
@@ -343,38 +342,38 @@ func TestBustCacheOnFormatterChange(t *testing.T) {
343342

344343
out, err = cmd(t, args...)
345344
as.NoError(err)
346-
as.Contains(string(out), fmt.Sprintf("%d files changed", 4))
345+
assertFormatted(t, as, out, 4)
347346

348347
// check cache is working
349348
out, err = cmd(t, args...)
350349
as.NoError(err)
351-
as.Contains(string(out), "0 files changed")
350+
assertFormatted(t, as, out, 0)
352351

353352
// remove python formatter
354353
delete(cfg.Formatters, "python")
355354
test.WriteConfig(t, configPath, cfg)
356355

357356
out, err = cmd(t, args...)
358357
as.NoError(err)
359-
as.Contains(string(out), fmt.Sprintf("%d files changed", 2))
358+
assertFormatted(t, as, out, 2)
360359

361360
// check cache is working
362361
out, err = cmd(t, args...)
363362
as.NoError(err)
364-
as.Contains(string(out), "0 files changed")
363+
assertFormatted(t, as, out, 0)
365364

366365
// remove elm formatter
367366
delete(cfg.Formatters, "elm")
368367
test.WriteConfig(t, configPath, cfg)
369368

370369
out, err = cmd(t, args...)
371370
as.NoError(err)
372-
as.Contains(string(out), fmt.Sprintf("%d files changed", 1))
371+
assertFormatted(t, as, out, 1)
373372

374373
// check cache is working
375374
out, err = cmd(t, args...)
376375
as.NoError(err)
377-
as.Contains(string(out), "0 files changed")
376+
assertFormatted(t, as, out, 0)
378377
}
379378

380379
func TestGitWorktree(t *testing.T) {
@@ -408,10 +407,10 @@ func TestGitWorktree(t *testing.T) {
408407
wt, err := repo.Worktree()
409408
as.NoError(err, "failed to get git worktree")
410409

411-
run := func(changed int) {
410+
run := func(formatted int) {
412411
out, err := cmd(t, "-c", "--config-file", configPath, "--tree-root", tempDir)
413412
as.NoError(err)
414-
as.Contains(string(out), fmt.Sprintf("%d files changed", changed))
413+
assertFormatted(t, as, out, formatted)
415414
}
416415

417416
// run before adding anything to the worktree
@@ -429,7 +428,7 @@ func TestGitWorktree(t *testing.T) {
429428
// walk with filesystem instead of git
430429
out, err := cmd(t, "-c", "--config-file", configPath, "--tree-root", tempDir, "--walk", "filesystem")
431430
as.NoError(err)
432-
as.Contains(string(out), fmt.Sprintf("%d files changed", 59))
431+
assertFormatted(t, as, out, 59)
433432
}
434433

435434
func TestPathsArg(t *testing.T) {
@@ -464,12 +463,12 @@ func TestPathsArg(t *testing.T) {
464463
// without any path args
465464
out, err := cmd(t, "-C", tempDir)
466465
as.NoError(err)
467-
as.Contains(string(out), fmt.Sprintf("%d files changed", 31))
466+
assertFormatted(t, as, out, 31)
468467

469468
// specify some explicit paths
470469
out, err = cmd(t, "-C", tempDir, "-c", "elm/elm.json", "haskell/Nested/Foo.hs")
471470
as.NoError(err)
472-
as.Contains(string(out), fmt.Sprintf("%d files changed", 2))
471+
assertFormatted(t, as, out, 2)
473472

474473
// specify a bad path
475474
out, err = cmd(t, "-C", tempDir, "-c", "elm/elm.json", "haskell/Nested/Bar.hs")
@@ -529,7 +528,7 @@ go/main.go
529528

530529
out, err := cmd(t, "-C", tempDir, "--stdin")
531530
as.NoError(err)
532-
as.Contains(string(out), fmt.Sprintf("%d files changed", 3))
531+
assertFormatted(t, as, out, 3)
533532
}
534533

535534
func TestDeterministicOrderingInPipeline(t *testing.T) {

0 commit comments

Comments
 (0)