import difflib import os import subprocess import tempfile from ..ui.diff_display import display_diff, get_diff_stats def apply_patch(filepath, patch_content, db_conn=None): """Apply a patch to a file. Args: filepath: Path to the file to patch. patch_content: The patch content as a string. db_conn: Database connection (optional). Returns: Dict with status and output. """ try: path = os.path.expanduser(filepath) if db_conn: from pr.tools.database import db_get read_status = db_get("read:" + path, db_conn) if read_status.get("status") != "success" or read_status.get("value") != "true": return { "status": "error", "error": "File must be read before writing. Please read the file first.", } # Write patch to temp file with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".patch") as f: f.write(patch_content) patch_file = f.name # Run patch command result = subprocess.run( ["patch", path, patch_file], capture_output=True, text=True, cwd=os.path.dirname(path), ) os.unlink(patch_file) if result.returncode == 0: return {"status": "success", "output": result.stdout.strip()} else: return {"status": "error", "error": result.stderr.strip()} except Exception as e: return {"status": "error", "error": str(e)} def create_diff( file1, file2, fromfile="file1", tofile="file2", visual=False, format_type="unified" ): """Create a unified diff between two files. Args: file1: Path to the first file. file2: Path to the second file. fromfile: Label for the first file. tofile: Label for the second file. visual: Whether to include visual diff. format_type: Diff format type. Returns: Dict with status and diff content. """ try: path1 = os.path.expanduser(file1) path2 = os.path.expanduser(file2) with open(path1) as f1, open(path2) as f2: content1 = f1.read() content2 = f2.read() if visual: visual_diff = display_diff(content1, content2, fromfile, format_type) stats = get_diff_stats(content1, content2) lines1 = content1.splitlines(keepends=True) lines2 = content2.splitlines(keepends=True) plain_diff = list( difflib.unified_diff(lines1, lines2, fromfile=fromfile, tofile=tofile) ) return { "status": "success", "diff": "".join(plain_diff), "visual_diff": visual_diff, "stats": stats, } else: lines1 = content1.splitlines(keepends=True) lines2 = content2.splitlines(keepends=True) diff = list(difflib.unified_diff(lines1, lines2, fromfile=fromfile, tofile=tofile)) return {"status": "success", "diff": "".join(diff)} except Exception as e: return {"status": "error", "error": str(e)} def display_file_diff(filepath1, filepath2, format_type="unified", context_lines=3): try: path1 = os.path.expanduser(filepath1) path2 = os.path.expanduser(filepath2) with open(path1) as f1: old_content = f1.read() with open(path2) as f2: new_content = f2.read() visual_diff = display_diff(old_content, new_content, filepath1, format_type) stats = get_diff_stats(old_content, new_content) return {"status": "success", "visual_diff": visual_diff, "stats": stats} except Exception as e: return {"status": "error", "error": str(e)} def display_content_diff(old_content, new_content, filename="file", format_type="unified"): try: visual_diff = display_diff(old_content, new_content, filename, format_type) stats = get_diff_stats(old_content, new_content) return {"status": "success", "visual_diff": visual_diff, "stats": stats} except Exception as e: return {"status": "error", "error": str(e)}