Run ``svn diff`` and extract changed line ranges per file. Args: repo_root: Absolute path to the SVN working copy root. rev_range: Optional SVN revision range in ``rXXX:HEAD`` format. When *None*, diffs the working copy against BASE (local changes). Returns:
(
repo_root: str,
rev_range: str | None = None,
)
| 69 | |
| 70 | |
| 71 | def parse_svn_diff_ranges( |
| 72 | repo_root: str, |
| 73 | rev_range: str | None = None, |
| 74 | ) -> dict[str, list[tuple[int, int]]]: |
| 75 | """Run ``svn diff`` and extract changed line ranges per file. |
| 76 | |
| 77 | Args: |
| 78 | repo_root: Absolute path to the SVN working copy root. |
| 79 | rev_range: Optional SVN revision range in ``rXXX:HEAD`` format. |
| 80 | When *None*, diffs the working copy against BASE (local changes). |
| 81 | |
| 82 | Returns: |
| 83 | Mapping of file paths to lists of ``(start_line, end_line)`` tuples. |
| 84 | Returns an empty dict on error. |
| 85 | """ |
| 86 | cmd = ["svn", "diff", "--non-interactive"] |
| 87 | if rev_range: |
| 88 | if not _SAFE_SVN_REV.match(rev_range): |
| 89 | logger.warning("Invalid SVN revision range rejected: %s", rev_range) |
| 90 | return {} |
| 91 | cmd.extend(["-r", rev_range]) |
| 92 | try: |
| 93 | result = subprocess.run( |
| 94 | cmd, |
| 95 | capture_output=True, |
| 96 | stdin=subprocess.DEVNULL, |
| 97 | text=True, |
| 98 | encoding="utf-8", |
| 99 | errors="replace", |
| 100 | cwd=repo_root, |
| 101 | timeout=_GIT_TIMEOUT, |
| 102 | ) |
| 103 | if result.returncode != 0: |
| 104 | logger.warning("svn diff failed (rc=%d): %s", result.returncode, result.stderr[:200]) |
| 105 | return {} |
| 106 | except (OSError, subprocess.SubprocessError) as exc: |
| 107 | logger.warning("svn diff error: %s", exc) |
| 108 | return {} |
| 109 | |
| 110 | return _parse_unified_diff(result.stdout) |
| 111 | |
| 112 | |
| 113 | def parse_diff_ranges( |
no test coverage detected