|
2 | 2 | from __future__ import annotations |
3 | 3 |
|
4 | 4 | import ast |
| 5 | +import json |
| 6 | +import subprocess |
5 | 7 | from itertools import chain |
| 8 | +from pathlib import Path |
6 | 9 | from typing import TYPE_CHECKING, Optional |
7 | 10 |
|
8 | 11 | import libcst as cst |
|
14 | 17 | from codeflash.models.models import FunctionParent |
15 | 18 |
|
16 | 19 | if TYPE_CHECKING: |
17 | | - from pathlib import Path |
18 | | - |
19 | 20 | from libcst.helpers import ModuleNameAndPackage |
20 | 21 |
|
21 | 22 | from codeflash.discovery.functions_to_optimize import FunctionToOptimize |
22 | | - from codeflash.models.models import FunctionSource |
| 23 | + from codeflash.models.models import FunctionSource, ImpactMetrics |
23 | 24 |
|
24 | 25 |
|
25 | 26 | class GlobalAssignmentCollector(cst.CSTVisitor): |
@@ -748,3 +749,85 @@ def find_preexisting_objects(source_code: str) -> set[tuple[str, tuple[FunctionP |
748 | 749 | if isinstance(cnode, (ast.FunctionDef, ast.AsyncFunctionDef)): |
749 | 750 | preexisting_objects.add((cnode.name, (FunctionParent(node.name, "ClassDef"),))) |
750 | 751 | return preexisting_objects |
| 752 | + |
| 753 | + |
| 754 | +def search_with_ripgrep(pattern: str, path: str = ".") -> dict[str, list[tuple[int, str]]]: |
| 755 | + """Use ripgrep to search for a pattern in the repository. |
| 756 | +
|
| 757 | + Args: |
| 758 | + pattern: The pattern to search for |
| 759 | + path: The directory to search in (default: current directory) |
| 760 | +
|
| 761 | + Returns: |
| 762 | + Dictionary with filepaths as keys and list of (line_no, content) tuples as values |
| 763 | +
|
| 764 | + """ |
| 765 | + # Run ripgrep with JSON output for easier parsing |
| 766 | + # -n: Show line numbers |
| 767 | + # --json: Output in JSON format |
| 768 | + # --no-heading: Don't group matches by file |
| 769 | + path = str(Path.cwd()) |
| 770 | + cmd = [ |
| 771 | + "rg", |
| 772 | + "-n", |
| 773 | + "--json", |
| 774 | + pattern, |
| 775 | + path, |
| 776 | + "-g", |
| 777 | + "!/Users/aseemsaxena/Downloads/codeflash_dev/codeflash/code_to_optimize/tests/**", |
| 778 | + ] |
| 779 | + print(" ".join(cmd)) |
| 780 | + # Parse the JSON output |
| 781 | + matches_dict = {} |
| 782 | + try: |
| 783 | + result = subprocess.run( |
| 784 | + cmd, |
| 785 | + capture_output=True, |
| 786 | + text=True, |
| 787 | + check=False, # Don't raise exception on non-zero return |
| 788 | + ) |
| 789 | + |
| 790 | + if result.returncode not in [0, 1]: # 0 = matches found, 1 = no matches |
| 791 | + print(f"Error running ripgrep: {result.stderr}") |
| 792 | + return {} |
| 793 | + |
| 794 | + for line in result.stdout.strip().split("\n"): |
| 795 | + if not line: |
| 796 | + continue |
| 797 | + |
| 798 | + try: |
| 799 | + json_obj = json.loads(line) |
| 800 | + |
| 801 | + # We're only interested in match objects |
| 802 | + if json_obj.get("type") == "match": |
| 803 | + data = json_obj.get("data", {}) |
| 804 | + file_path = data.get("path", {}).get("text", "") |
| 805 | + line_number = data.get("line_number") |
| 806 | + line_content = data.get("lines", {}).get("text", "").rstrip("\n") |
| 807 | + |
| 808 | + if file_path and line_number: |
| 809 | + if file_path not in matches_dict: |
| 810 | + matches_dict[file_path] = [] |
| 811 | + matches_dict[file_path].append((line_number, line_content)) |
| 812 | + |
| 813 | + except json.JSONDecodeError: |
| 814 | + continue |
| 815 | + |
| 816 | + except FileNotFoundError: |
| 817 | + print("Error: ripgrep (rg) is not installed or not in PATH") |
| 818 | + return {} |
| 819 | + except Exception as e: |
| 820 | + print(f"Unexpected error: {e}") |
| 821 | + return {} |
| 822 | + return matches_dict |
| 823 | + |
| 824 | + |
| 825 | +def get_opt_impact_metrics(file_path: Path, qualified_name: str, project_root: Path, tests_root: Path) -> ImpactMetrics: |
| 826 | + # grep for function / use rg (respects gitignore) |
| 827 | + # SAFE_GREP_EXECUTABLE command |
| 828 | + # ast visitor for occurances and loop occurances |
| 829 | + # radon lib for complexity metrics |
| 830 | + print(file_path, qualified_name, project_root, tests_root) |
| 831 | + |
| 832 | + # grep windows alternative |
| 833 | + return 0 |
0 commit comments