(path string, hunks []diffHunk)
| 170 | } |
| 171 | |
| 172 | func (e *Engine) applyHunksToFile(path string, hunks []diffHunk) error { |
| 173 | content, err := os.ReadFile(path) //#nosec G304 -- path supplied by user/agent through validated tool surface (boundary check upstream) |
| 174 | if err != nil { |
| 175 | return fmt.Errorf("erro leitura: %w", err) |
| 176 | } |
| 177 | text := strings.ReplaceAll(string(content), "\r\n", "\n") |
| 178 | lines := strings.Split(text, "\n") |
| 179 | trailingNewline := strings.HasSuffix(text, "\n") |
| 180 | |
| 181 | offset := 0 |
| 182 | for _, h := range hunks { |
| 183 | idx := h.oldStart - 1 + offset |
| 184 | if idx < 0 || idx > len(lines) { |
| 185 | return fmt.Errorf("hunk fora do range do arquivo: %s", path) |
| 186 | } |
| 187 | |
| 188 | cur := idx |
| 189 | newChunk := make([]string, 0, len(h.lines)) |
| 190 | for _, dl := range h.lines { |
| 191 | switch dl.kind { |
| 192 | case ' ': |
| 193 | if cur >= len(lines) || lines[cur] != dl.text { |
| 194 | return fmt.Errorf("hunk mismatch no arquivo %s", path) |
| 195 | } |
| 196 | newChunk = append(newChunk, lines[cur]) |
| 197 | cur++ |
| 198 | case '-': |
| 199 | if cur >= len(lines) || lines[cur] != dl.text { |
| 200 | return fmt.Errorf("hunk mismatch no arquivo %s", path) |
| 201 | } |
| 202 | cur++ |
| 203 | case '+': |
| 204 | newChunk = append(newChunk, dl.text) |
| 205 | } |
| 206 | } |
| 207 | |
| 208 | lines = append(lines[:idx], append(newChunk, lines[cur:]...)...) |
| 209 | offset += len(newChunk) - (cur - idx) |
| 210 | } |
| 211 | |
| 212 | newText := strings.Join(lines, "\n") |
| 213 | if trailingNewline && !strings.HasSuffix(newText, "\n") { |
| 214 | newText += "\n" |
| 215 | } |
| 216 | |
| 217 | _ = createBackup(path) |
| 218 | if err := os.WriteFile(path, []byte(newText), 0600); err != nil { //#nosec G703 -- path validated by engine.validatePath / SensitiveReadPaths.IsReadAllowed |
| 219 | return fmt.Errorf("erro escrita: %w", err) |
| 220 | } |
| 221 | e.printf("✅ Diff aplicado em '%s'.\n", path) |
| 222 | return nil |
| 223 | } |
no test coverage detected