mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-20 20:31:37 -05:00
refactor: enhance Git fallback strategy in edit processing
- Improved logging within the applyGitFallback function to provide clearer insights during the commit and cherry-pick processes. - Streamlined error handling to ensure more informative console outputs when operations fail. - Maintained consistent formatting and indentation for better readability and maintainability of the code. - Ensured temporary directory cleanup is handled correctly in all scenarios, preventing potential resource leaks.
This commit is contained in:
@@ -134,125 +134,118 @@ export function applyDMP(hunk: Hunk, content: string[], matchPosition: number):
|
|||||||
|
|
||||||
// Git fallback strategy that works with full content
|
// Git fallback strategy that works with full content
|
||||||
async function applyGitFallback(hunk: Hunk, content: string[]): Promise<EditResult> {
|
async function applyGitFallback(hunk: Hunk, content: string[]): Promise<EditResult> {
|
||||||
let tmpDir: tmp.DirResult | undefined;
|
let tmpDir: tmp.DirResult | undefined;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Create temporary directory
|
tmpDir = tmp.dirSync({ unsafeCleanup: true });
|
||||||
tmpDir = tmp.dirSync({ unsafeCleanup: true });
|
const git: SimpleGit = simpleGit(tmpDir.name);
|
||||||
const git: SimpleGit = simpleGit(tmpDir.name);
|
|
||||||
|
await git.init();
|
||||||
// Initialize git repo
|
await git.addConfig('user.name', 'Temp');
|
||||||
await git.init();
|
await git.addConfig('user.email', 'temp@example.com');
|
||||||
await git.addConfig('user.name', 'Temp');
|
|
||||||
await git.addConfig('user.email', 'temp@example.com');
|
|
||||||
|
|
||||||
const filePath = path.join(tmpDir.name, 'file.txt');
|
const filePath = path.join(tmpDir.name, 'file.txt');
|
||||||
|
|
||||||
// Build the search text (context + removals)
|
const searchLines = hunk.changes
|
||||||
const searchLines = hunk.changes
|
.filter(change => change.type === 'context' || change.type === 'remove')
|
||||||
.filter(change => change.type === 'context' || change.type === 'remove')
|
.map(change => change.originalLine || (change.indent + change.content));
|
||||||
.map(change => change.originalLine || (change.indent + change.content));
|
|
||||||
|
const replaceLines = hunk.changes
|
||||||
// Build the replace text (context + additions)
|
.filter(change => change.type === 'context' || change.type === 'add')
|
||||||
const replaceLines = hunk.changes
|
.map(change => change.originalLine || (change.indent + change.content));
|
||||||
.filter(change => change.type === 'context' || change.type === 'add')
|
|
||||||
.map(change => change.originalLine || (change.indent + change.content));
|
|
||||||
|
|
||||||
const searchText = searchLines.join('\n');
|
const searchText = searchLines.join('\n');
|
||||||
const replaceText = replaceLines.join('\n');
|
const replaceText = replaceLines.join('\n');
|
||||||
const originalText = content.join('\n');
|
const originalText = content.join('\n');
|
||||||
|
|
||||||
// Strategy 1: O->S->R, cherry-pick R onto O
|
try {
|
||||||
try {
|
fs.writeFileSync(filePath, originalText);
|
||||||
// Original commit - use full file content
|
await git.add('file.txt');
|
||||||
fs.writeFileSync(filePath, originalText);
|
const originalCommit = await git.commit('original');
|
||||||
await git.add('file.txt');
|
console.log('Strategy 1 - Original commit:', originalCommit.commit);
|
||||||
const originalCommit = await git.commit('original');
|
|
||||||
|
|
||||||
// Search commit - just the search text
|
fs.writeFileSync(filePath, searchText);
|
||||||
fs.writeFileSync(filePath, searchText);
|
await git.add('file.txt');
|
||||||
await git.add('file.txt');
|
const searchCommit1 = await git.commit('search');
|
||||||
await git.commit('search');
|
console.log('Strategy 1 - Search commit:', searchCommit1.commit);
|
||||||
|
|
||||||
// Replace commit - just the replace text
|
fs.writeFileSync(filePath, replaceText);
|
||||||
fs.writeFileSync(filePath, replaceText);
|
await git.add('file.txt');
|
||||||
await git.add('file.txt');
|
const replaceCommit = await git.commit('replace');
|
||||||
const replaceCommit = await git.commit('replace');
|
console.log('Strategy 1 - Replace commit:', replaceCommit.commit);
|
||||||
|
|
||||||
// Go back to original and cherry-pick
|
console.log('Strategy 1 - Attempting checkout of:', originalCommit.commit);
|
||||||
await git.checkout(originalCommit.commit);
|
await git.raw(['checkout', originalCommit.commit]);
|
||||||
try {
|
try {
|
||||||
await git.raw(['cherry-pick', '--minimal', replaceCommit.commit]);
|
console.log('Strategy 1 - Attempting cherry-pick of:', replaceCommit.commit);
|
||||||
|
await git.raw(['cherry-pick', '--minimal', replaceCommit.commit]);
|
||||||
// Read result
|
|
||||||
const newText = fs.readFileSync(filePath, 'utf-8');
|
const newText = fs.readFileSync(filePath, 'utf-8');
|
||||||
const newLines = newText.split('\n');
|
const newLines = newText.split('\n');
|
||||||
return {
|
return {
|
||||||
confidence: 1,
|
confidence: 1,
|
||||||
result: newLines,
|
result: newLines,
|
||||||
strategy: 'git-fallback'
|
strategy: 'git-fallback'
|
||||||
};
|
};
|
||||||
} catch (cherryPickError) {
|
} catch (cherryPickError) {
|
||||||
console.log('Strategy 1 failed with merge conflict');
|
console.error('Strategy 1 failed with merge conflict');
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('Strategy 1 failed:', error);
|
console.error('Strategy 1 failed:', error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strategy 2: S->R, S->O, cherry-pick R onto O
|
try {
|
||||||
try {
|
await git.init();
|
||||||
// Reset repo
|
await git.addConfig('user.name', 'Temp');
|
||||||
await git.init();
|
await git.addConfig('user.email', 'temp@example.com');
|
||||||
await git.addConfig('user.name', 'Temp');
|
|
||||||
await git.addConfig('user.email', 'temp@example.com');
|
|
||||||
|
|
||||||
// Search commit - just the search text
|
fs.writeFileSync(filePath, searchText);
|
||||||
fs.writeFileSync(filePath, searchText);
|
await git.add('file.txt');
|
||||||
await git.add('file.txt');
|
const searchCommit = await git.commit('search');
|
||||||
const searchCommit = await git.commit('search');
|
const searchHash = searchCommit.commit.replace(/^HEAD /, '');
|
||||||
|
console.log('Strategy 2 - Search commit:', searchHash);
|
||||||
|
|
||||||
// Replace commit - just the replace text
|
fs.writeFileSync(filePath, replaceText);
|
||||||
fs.writeFileSync(filePath, replaceText);
|
await git.add('file.txt');
|
||||||
await git.add('file.txt');
|
const replaceCommit = await git.commit('replace');
|
||||||
const replaceCommit = await git.commit('replace');
|
const replaceHash = replaceCommit.commit.replace(/^HEAD /, '');
|
||||||
|
console.log('Strategy 2 - Replace commit:', replaceHash);
|
||||||
|
|
||||||
// Go back to search and create original with full file content
|
console.log('Strategy 2 - Attempting checkout of:', searchHash);
|
||||||
await git.checkout(searchCommit.commit);
|
await git.raw(['checkout', searchHash]);
|
||||||
fs.writeFileSync(filePath, originalText);
|
fs.writeFileSync(filePath, originalText);
|
||||||
await git.add('file.txt');
|
await git.add('file.txt');
|
||||||
await git.commit('original');
|
const originalCommit2 = await git.commit('original');
|
||||||
|
console.log('Strategy 2 - Original commit:', originalCommit2.commit);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Cherry-pick replace onto original
|
console.log('Strategy 2 - Attempting cherry-pick of:', replaceHash);
|
||||||
await git.raw(['cherry-pick', '--minimal', replaceCommit.commit]);
|
await git.raw(['cherry-pick', '--minimal', replaceHash]);
|
||||||
|
|
||||||
// Read result
|
const newText = fs.readFileSync(filePath, 'utf-8');
|
||||||
const newText = fs.readFileSync(filePath, 'utf-8');
|
const newLines = newText.split('\n');
|
||||||
const newLines = newText.split('\n');
|
return {
|
||||||
return {
|
confidence: 1,
|
||||||
confidence: 1,
|
result: newLines,
|
||||||
result: newLines,
|
strategy: 'git-fallback'
|
||||||
strategy: 'git-fallback'
|
};
|
||||||
};
|
} catch (cherryPickError) {
|
||||||
} catch (cherryPickError) {
|
console.error('Strategy 2 failed with merge conflict');
|
||||||
console.log('Strategy 2 failed with merge conflict');
|
}
|
||||||
}
|
} catch (error) {
|
||||||
} catch (error) {
|
console.error('Strategy 2 failed:', error);
|
||||||
console.log('Strategy 2 failed:', error);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// If both strategies fail, return no confidence
|
console.error('Git fallback failed');
|
||||||
console.log('Git fallback failed');
|
return { confidence: 0, result: content, strategy: 'git-fallback' };
|
||||||
return { confidence: 0, result: content, strategy: 'git-fallback' };
|
} catch (error) {
|
||||||
} catch (error) {
|
console.error('Git fallback strategy failed:', error);
|
||||||
console.log('Git fallback strategy failed:', error);
|
return { confidence: 0, result: content, strategy: 'git-fallback' };
|
||||||
return { confidence: 0, result: content, strategy: 'git-fallback' };
|
} finally {
|
||||||
} finally {
|
if (tmpDir) {
|
||||||
// Clean up temporary directory
|
tmpDir.removeCallback();
|
||||||
if (tmpDir) {
|
}
|
||||||
tmpDir.removeCallback();
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Main edit function that tries strategies sequentially
|
// Main edit function that tries strategies sequentially
|
||||||
|
|||||||
Reference in New Issue
Block a user