|
|
|
|
|
|
|
import asyncio |
|
import shutil |
|
from pathlib import Path |
|
|
|
import typer |
|
|
|
from metagpt.actions.rebuild_class_view import RebuildClassView |
|
from metagpt.actions.rebuild_sequence_view import RebuildSequenceView |
|
from metagpt.context import Context |
|
from metagpt.llm import LLM |
|
from metagpt.logs import logger |
|
from metagpt.utils.git_repository import GitRepository |
|
from metagpt.utils.project_repo import ProjectRepo |
|
|
|
app = typer.Typer(add_completion=False, pretty_exceptions_show_locals=False) |
|
|
|
|
|
@app.command("", help="Python project reverse engineering.") |
|
def startup( |
|
project_root: str = typer.Argument( |
|
default="", |
|
help="Specify the root directory of the existing project for reverse engineering.", |
|
), |
|
output_dir: str = typer.Option(default="", help="Specify the output directory path for reverse engineering."), |
|
): |
|
package_root = Path(project_root) |
|
if not package_root.exists(): |
|
raise FileNotFoundError(f"{project_root} not exists") |
|
if not _is_python_package_root(package_root): |
|
raise FileNotFoundError(f'There are no "*.py" files under "{project_root}".') |
|
init_file = package_root / "__init__.py" |
|
init_file_exists = init_file.exists() |
|
if not init_file_exists: |
|
init_file.touch() |
|
|
|
if not output_dir: |
|
output_dir = package_root / "../reverse_engineering_output" |
|
logger.info(f"output dir:{output_dir}") |
|
try: |
|
asyncio.run(reverse_engineering(package_root, Path(output_dir))) |
|
finally: |
|
if not init_file_exists: |
|
init_file.unlink(missing_ok=True) |
|
tmp_dir = package_root / "__dot__" |
|
if tmp_dir.exists(): |
|
shutil.rmtree(tmp_dir, ignore_errors=True) |
|
|
|
|
|
def _is_python_package_root(package_root: Path) -> bool: |
|
for file_path in package_root.iterdir(): |
|
if file_path.is_file(): |
|
if file_path.suffix == ".py": |
|
return True |
|
return False |
|
|
|
|
|
async def reverse_engineering(package_root: Path, output_dir: Path): |
|
ctx = Context() |
|
ctx.git_repo = GitRepository(output_dir) |
|
ctx.repo = ProjectRepo(ctx.git_repo) |
|
action = RebuildClassView(name="ReverseEngineering", i_context=str(package_root), llm=LLM(), context=ctx) |
|
await action.run() |
|
|
|
action = RebuildSequenceView(name="ReverseEngineering", llm=LLM(), context=ctx) |
|
await action.run() |
|
|
|
|
|
if __name__ == "__main__": |
|
app() |
|
|