Skip to content

Commit 4604969

Browse files
committed
fix(progress): report polyglot analysis per file
1 parent a30afb6 commit 4604969

4 files changed

Lines changed: 79 additions & 5 deletions

File tree

internal/build/build.go

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,12 @@ func RunWithCache(ctx context.Context, root string, cfg config.Config, progress
8484
}
8585
progress(Progress{Stage: stage, Path: unit.files[0].Path, Completed: completed, Total: len(scanResult.Files)})
8686
}
87-
analysis, err := analyzeWithCache(ctx, cache, analyzerIdentity(language, cfg), unit.name, analyzer, scanResult.Root, unit.files, status)
87+
fileProgress := func(path string, unitCompleted int) {
88+
if progress != nil {
89+
progress(Progress{Stage: "Analyzing " + language, Path: path, Completed: completed + unitCompleted, Total: len(scanResult.Files)})
90+
}
91+
}
92+
analysis, err := analyzeWithCache(ctx, cache, analyzerIdentity(language, cfg), unit.name, analyzer, scanResult.Root, unit.files, status, fileProgress)
8893
if err != nil {
8994
return Result{}, err
9095
}
@@ -141,7 +146,7 @@ func boolString(value bool) string {
141146
return "false"
142147
}
143148

144-
func analyzeWithCache(ctx context.Context, cache *analysisCache, identity, unit string, analyzer lang.Analyzer, root string, files []scan.File, status func(cached bool)) (*lang.AnalysisResult, error) {
149+
func analyzeWithCache(ctx context.Context, cache *analysisCache, identity, unit string, analyzer lang.Analyzer, root string, files []scan.File, status func(cached bool), fileProgress func(path string, completed int)) (*lang.AnalysisResult, error) {
145150
if err := ctx.Err(); err != nil {
146151
return nil, err
147152
}
@@ -155,7 +160,7 @@ func analyzeWithCache(ctx context.Context, cache *analysisCache, identity, unit
155160
return result, nil
156161
}
157162
status(false)
158-
result, err := analyzer.Analyze(ctx, root, files)
163+
result, err := analyze(ctx, analyzer, root, files, fileProgress)
159164
if err != nil {
160165
return nil, err
161166
}
@@ -165,10 +170,17 @@ func analyzeWithCache(ctx context.Context, cache *analysisCache, identity, unit
165170
return result, nil
166171
}
167172
status(false)
168-
result, err := analyzer.Analyze(ctx, root, files)
173+
result, err := analyze(ctx, analyzer, root, files, fileProgress)
169174
return result, err
170175
}
171176

177+
func analyze(ctx context.Context, analyzer lang.Analyzer, root string, files []scan.File, progress func(path string, completed int)) (*lang.AnalysisResult, error) {
178+
if progressive, ok := analyzer.(lang.ProgressAnalyzer); ok {
179+
return progressive.AnalyzeWithProgress(ctx, root, files, progress)
180+
}
181+
return analyzer.Analyze(ctx, root, files)
182+
}
183+
172184
func addFileTopology(builder *graph.Builder, scanResult scan.Result) {
173185
builder.AddNode(graph.Node{ID: graph.DirID("."), Kind: graph.NodeDir, Name: ".", Path: ".", Meta: topologyMeta(".")})
174186
builder.AddEdge(graph.Edge{Kind: graph.EdgeContains, From: graph.RepoID(), To: graph.DirID("."), Meta: topologyMeta(".")})

internal/build/build_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,51 @@ func TestRunBuildsAndCanDisablePolyglotGraph(t *testing.T) {
8888
}
8989
}
9090

91+
func TestRunReportsPerFilePolyglotProgress(t *testing.T) {
92+
root := t.TempDir()
93+
for _, name := range []string{"App.swift", "Feature.swift"} {
94+
if err := os.WriteFile(filepath.Join(root, name), []byte("func run() {}\n"), 0o644); err != nil {
95+
t.Fatal(err)
96+
}
97+
}
98+
cfg := config.Default()
99+
cfg.Analysis.Go = false
100+
cfg.Analysis.Documents = false
101+
cfg.Analysis.Schemas = false
102+
var events []Progress
103+
_, err := RunWithProgress(context.Background(), root, cfg, func(event Progress) {
104+
if event.Stage == "Analyzing swift" {
105+
events = append(events, event)
106+
}
107+
})
108+
if err != nil {
109+
t.Fatal(err)
110+
}
111+
if len(events) < 3 {
112+
t.Fatalf("Swift progress events = %#v, want start, per-file, and completion events", events)
113+
}
114+
want := []struct {
115+
path string
116+
completed int
117+
}{
118+
{path: "App.swift", completed: 0},
119+
{path: "Feature.swift", completed: 1},
120+
{path: "Feature.swift", completed: 2},
121+
}
122+
for _, expected := range want {
123+
found := false
124+
for _, event := range events {
125+
if event.Path == expected.path && event.Completed == expected.completed && event.Total == 2 {
126+
found = true
127+
break
128+
}
129+
}
130+
if !found {
131+
t.Errorf("missing progress path=%q completed=%d in %#v", expected.path, expected.completed, events)
132+
}
133+
}
134+
}
135+
91136
func TestRunWithCacheReusesAndInvalidatesMarkdownFilesIndependently(t *testing.T) {
92137
root := t.TempDir()
93138
for name, content := range map[string]string{

internal/lang/analyzer.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,10 @@ type Analyzer interface {
1818
Extensions() []string
1919
Analyze(ctx context.Context, root string, files []scan.File) (*AnalysisResult, error)
2020
}
21+
22+
// ProgressAnalyzer reports the file currently being analyzed while preserving
23+
// a language-wide analysis unit for cross-file relationship resolution.
24+
type ProgressAnalyzer interface {
25+
Analyzer
26+
AnalyzeWithProgress(ctx context.Context, root string, files []scan.File, progress func(path string, completed int)) (*AnalysisResult, error)
27+
}

internal/lang/treeanalyzer/analyzer.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,19 @@ type reference struct {
104104
}
105105

106106
func (a *Analyzer) Analyze(ctx context.Context, _ string, files []scan.File) (*lang.AnalysisResult, error) {
107+
return a.AnalyzeWithProgress(ctx, "", files, nil)
108+
}
109+
110+
func (a *Analyzer) AnalyzeWithProgress(ctx context.Context, _ string, files []scan.File, progress func(path string, completed int)) (*lang.AnalysisResult, error) {
107111
result := &lang.AnalysisResult{}
108112
parsed := make([]parsedFile, 0, len(files))
109-
for _, file := range files {
113+
for i, file := range files {
110114
if err := ctx.Err(); err != nil {
111115
return nil, err
112116
}
117+
if progress != nil {
118+
progress(file.Path, i)
119+
}
113120
entry := entryForFile(a.language, file.Path)
114121
if entry == nil || entry.Language == nil {
115122
continue
@@ -121,6 +128,9 @@ func (a *Analyzer) Analyze(ctx context.Context, _ string, files []scan.File) (*l
121128
}
122129
parsed = append(parsed, pf)
123130
}
131+
if progress != nil && len(files) > 0 {
132+
progress(files[len(files)-1].Path, len(files))
133+
}
124134

125135
emitDefinitions(parsed, result)
126136
emitReferences(parsed, result)

0 commit comments

Comments
 (0)