open-code-review/internal/tool/file_read_diff.go
kite 363d971916 fix(tool): make Registry and DiffMap concurrency-safe via freeze semantics
Registry was a plain map alias and DiffMap a shared map[string]string,
both relying on implicit write-before-read ordering with no compile-time
safety. Refactor Registry into an encapsulated struct with Freeze() that
panics on post-freeze writes, and wrap DiffMap as an immutable value type
with defensive copy on construction. Move DiffMap injection to before
filterDiffs to preserve the original behavior of exposing all file diffs.
2026-06-06 19:41:11 +08:00

71 lines
1.7 KiB
Go

package tool
import (
"context"
"strings"
)
// DiffMap is a read-only snapshot of parsed diffs, keyed by file path.
// Safe for concurrent reads after construction via NewDiffMap.
type DiffMap struct {
m map[string]string
}
// NewDiffMap creates a frozen, read-only DiffMap from a plain map.
func NewDiffMap(m map[string]string) DiffMap {
cp := make(map[string]string, len(m))
for k, v := range m {
cp[k] = v
}
return DiffMap{m: cp}
}
// Get returns the diff text for path.
func (d DiffMap) Get(path string) (string, bool) {
v, ok := d.m[path]
return v, ok
}
// FileReadDiffProvider retrieves diff content by file path from an already-parsed diff set.
type FileReadDiffProvider struct {
diffMap DiffMap
}
func NewFileReadDiff(dm DiffMap) *FileReadDiffProvider {
return &FileReadDiffProvider{diffMap: dm}
}
// SetDiffMap replaces the diff snapshot. Must be called before concurrent access begins.
func (p *FileReadDiffProvider) SetDiffMap(dm DiffMap) {
p.diffMap = dm
}
func (p *FileReadDiffProvider) Tool() Tool { return FileReadDiff }
func (p *FileReadDiffProvider) Execute(_ context.Context, args map[string]any) (string, error) {
pathArray, _ := args["path_array"].([]any)
if len(pathArray) == 0 {
return "Error: no files found", nil
}
var sb strings.Builder
for _, item := range pathArray {
path, ok := item.(string)
if !ok {
continue
}
if d, exists := p.diffMap.Get(path); exists {
sb.WriteString("==== FILE: ")
sb.WriteString(path)
sb.WriteString(" ====\n")
sb.WriteString(d)
sb.WriteString("\n")
}
}
result := sb.String()
if result == "" {
return "Error: diff not found for the requested paths", nil
}
return result, nil
}