first commit
This commit is contained in:
307
backend/app/services/project_analyzer.py
Normal file
307
backend/app/services/project_analyzer.py
Normal file
@@ -0,0 +1,307 @@
|
||||
"""项目分析服务,用于分析算法仓库的结构和特性"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import json
|
||||
from typing import Dict, List, Optional, Any
|
||||
|
||||
|
||||
class ProjectAnalyzer:
|
||||
"""项目分析服务"""
|
||||
|
||||
def analyze_project(self, repo_path: str) -> Dict[str, Any]:
|
||||
"""分析项目结构和特性
|
||||
|
||||
Args:
|
||||
repo_path: 仓库路径
|
||||
|
||||
Returns:
|
||||
包含项目分析结果的字典
|
||||
"""
|
||||
try:
|
||||
# 1. 识别项目类型
|
||||
project_type = self._detect_project_type(repo_path)
|
||||
|
||||
# 2. 分析依赖
|
||||
dependencies = self._analyze_dependencies(repo_path, project_type)
|
||||
|
||||
# 3. 识别入口点
|
||||
entry_point = self._detect_entry_point(repo_path, project_type)
|
||||
|
||||
# 4. 分析API模式
|
||||
api_pattern = self._detect_api_pattern(repo_path, project_type)
|
||||
|
||||
# 5. 分析项目结构
|
||||
structure = self._analyze_structure(repo_path)
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"project_type": project_type,
|
||||
"dependencies": dependencies,
|
||||
"entry_point": entry_point,
|
||||
"api_pattern": api_pattern,
|
||||
"structure": structure,
|
||||
"error": None
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
"success": False,
|
||||
"error": str(e),
|
||||
"project_type": None,
|
||||
"dependencies": None,
|
||||
"entry_point": None,
|
||||
"api_pattern": None,
|
||||
"structure": None
|
||||
}
|
||||
|
||||
def _detect_project_type(self, repo_path: str) -> Optional[str]:
|
||||
"""检测项目类型
|
||||
|
||||
Args:
|
||||
repo_path: 仓库路径
|
||||
|
||||
Returns:
|
||||
项目类型,如 "python", "java", "nodejs" 等
|
||||
"""
|
||||
# 检查Python项目
|
||||
if os.path.exists(os.path.join(repo_path, "requirements.txt")) or \
|
||||
os.path.exists(os.path.join(repo_path, "pyproject.toml")) or \
|
||||
any(file.endswith(".py") for file in os.listdir(repo_path)):
|
||||
return "python"
|
||||
|
||||
# 检查Java项目
|
||||
if os.path.exists(os.path.join(repo_path, "pom.xml")) or \
|
||||
os.path.exists(os.path.join(repo_path, "build.gradle")) or \
|
||||
os.path.exists(os.path.join(repo_path, "src")):
|
||||
return "java"
|
||||
|
||||
# 检查Node.js项目
|
||||
if os.path.exists(os.path.join(repo_path, "package.json")):
|
||||
return "nodejs"
|
||||
|
||||
# 检查其他项目类型
|
||||
if os.path.exists(os.path.join(repo_path, "CMakeLists.txt")):
|
||||
return "c++"
|
||||
|
||||
return None
|
||||
|
||||
def _analyze_dependencies(self, repo_path: str, project_type: Optional[str]) -> List[str]:
|
||||
"""分析项目依赖
|
||||
|
||||
Args:
|
||||
repo_path: 仓库路径
|
||||
project_type: 项目类型
|
||||
|
||||
Returns:
|
||||
依赖列表
|
||||
"""
|
||||
dependencies = []
|
||||
|
||||
if project_type == "python":
|
||||
# 分析requirements.txt
|
||||
req_file = os.path.join(repo_path, "requirements.txt")
|
||||
if os.path.exists(req_file):
|
||||
with open(req_file, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if line and not line.startswith("#"):
|
||||
dependencies.append(line)
|
||||
|
||||
# 分析pyproject.toml
|
||||
pyproject_file = os.path.join(repo_path, "pyproject.toml")
|
||||
if os.path.exists(pyproject_file):
|
||||
with open(pyproject_file, "r", encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
# 简单解析依赖部分
|
||||
if "[dependencies]" in content:
|
||||
dep_section = content.split("[dependencies]")[1].split("[")[0]
|
||||
for line in dep_section.strip().split("\n"):
|
||||
line = line.strip()
|
||||
if line and not line.startswith("#"):
|
||||
dependencies.append(line)
|
||||
|
||||
elif project_type == "java":
|
||||
# 分析pom.xml
|
||||
pom_file = os.path.join(repo_path, "pom.xml")
|
||||
if os.path.exists(pom_file):
|
||||
with open(pom_file, "r", encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
# 简单解析依赖
|
||||
for match in re.finditer(r'<dependency>.*?</dependency>', content, re.DOTALL):
|
||||
dep = match.group(0)
|
||||
group_id = re.search(r'<groupId>(.*?)</groupId>', dep)
|
||||
artifact_id = re.search(r'<artifactId>(.*?)</artifactId>', dep)
|
||||
version = re.search(r'<version>(.*?)</version>', dep)
|
||||
if group_id and artifact_id:
|
||||
dep_str = f"{group_id.group(1)}:{artifact_id.group(1)}"
|
||||
if version:
|
||||
dep_str += f":{version.group(1)}"
|
||||
dependencies.append(dep_str)
|
||||
|
||||
elif project_type == "nodejs":
|
||||
# 分析package.json
|
||||
package_file = os.path.join(repo_path, "package.json")
|
||||
if os.path.exists(package_file):
|
||||
with open(package_file, "r", encoding="utf-8") as f:
|
||||
package_data = json.load(f)
|
||||
if "dependencies" in package_data:
|
||||
for dep, version in package_data["dependencies"].items():
|
||||
dependencies.append(f"{dep}@{version}")
|
||||
if "devDependencies" in package_data:
|
||||
for dep, version in package_data["devDependencies"].items():
|
||||
dependencies.append(f"{dep}@{version} (dev)")
|
||||
|
||||
return dependencies
|
||||
|
||||
def _detect_entry_point(self, repo_path: str, project_type: Optional[str]) -> Optional[str]:
|
||||
"""检测项目入口点
|
||||
|
||||
Args:
|
||||
repo_path: 仓库路径
|
||||
project_type: 项目类型
|
||||
|
||||
Returns:
|
||||
入口点路径或函数名
|
||||
"""
|
||||
if project_type == "python":
|
||||
# 查找主要的Python文件
|
||||
main_files = ["main.py", "app.py", "run.py", "server.py"]
|
||||
for file in main_files:
|
||||
file_path = os.path.join(repo_path, file)
|
||||
if os.path.exists(file_path):
|
||||
return file
|
||||
|
||||
# 查找包含__main__.py的包
|
||||
for root, dirs, files in os.walk(repo_path):
|
||||
if "__main__.py" in files:
|
||||
return os.path.relpath(os.path.join(root, "__main__.py"), repo_path)
|
||||
|
||||
# 查找包含main函数的文件
|
||||
for root, dirs, files in os.walk(repo_path):
|
||||
for file in files:
|
||||
if file.endswith(".py"):
|
||||
file_path = os.path.join(root, file)
|
||||
try:
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
if "def main(" in content:
|
||||
return os.path.relpath(file_path, repo_path)
|
||||
except:
|
||||
pass
|
||||
|
||||
elif project_type == "java":
|
||||
# 查找包含main方法的Java文件
|
||||
for root, dirs, files in os.walk(repo_path):
|
||||
for file in files:
|
||||
if file.endswith(".java"):
|
||||
file_path = os.path.join(root, file)
|
||||
try:
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
if "public static void main(String[] args)" in content:
|
||||
return os.path.relpath(file_path, repo_path)
|
||||
except:
|
||||
pass
|
||||
|
||||
elif project_type == "nodejs":
|
||||
# 检查package.json中的main字段
|
||||
package_file = os.path.join(repo_path, "package.json")
|
||||
if os.path.exists(package_file):
|
||||
with open(package_file, "r", encoding="utf-8") as f:
|
||||
try:
|
||||
package_data = json.load(f)
|
||||
if "main" in package_data:
|
||||
return package_data["main"]
|
||||
elif "scripts" in package_data and "start" in package_data["scripts"]:
|
||||
return f"package.json (start: {package_data['scripts']['start']})"
|
||||
except:
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
def _detect_api_pattern(self, repo_path: str, project_type: Optional[str]) -> Optional[str]:
|
||||
"""检测API模式
|
||||
|
||||
Args:
|
||||
repo_path: 仓库路径
|
||||
project_type: 项目类型
|
||||
|
||||
Returns:
|
||||
API模式,如 "fastapi", "flask", "express" 等
|
||||
"""
|
||||
if project_type == "python":
|
||||
# 检查FastAPI
|
||||
for root, dirs, files in os.walk(repo_path):
|
||||
for file in files:
|
||||
if file.endswith(".py"):
|
||||
file_path = os.path.join(root, file)
|
||||
try:
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
if "from fastapi import" in content or "import fastapi" in content:
|
||||
return "fastapi"
|
||||
elif "from flask import" in content or "import flask" in content:
|
||||
return "flask"
|
||||
elif "from django import" in content or "import django" in content:
|
||||
return "django"
|
||||
except:
|
||||
pass
|
||||
|
||||
elif project_type == "nodejs":
|
||||
# 检查Express
|
||||
package_file = os.path.join(repo_path, "package.json")
|
||||
if os.path.exists(package_file):
|
||||
with open(package_file, "r", encoding="utf-8") as f:
|
||||
try:
|
||||
package_data = json.load(f)
|
||||
dependencies = package_data.get("dependencies", {})
|
||||
if "express" in dependencies:
|
||||
return "express"
|
||||
elif "koa" in dependencies:
|
||||
return "koa"
|
||||
elif "nestjs" in dependencies:
|
||||
return "nestjs"
|
||||
except:
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
def _analyze_structure(self, repo_path: str) -> Dict[str, Any]:
|
||||
"""分析项目结构
|
||||
|
||||
Args:
|
||||
repo_path: 仓库路径
|
||||
|
||||
Returns:
|
||||
项目结构字典
|
||||
"""
|
||||
structure = {
|
||||
"files": [],
|
||||
"directories": [],
|
||||
"size": 0
|
||||
}
|
||||
|
||||
for root, dirs, files in os.walk(repo_path):
|
||||
# 排除隐藏目录和文件
|
||||
dirs[:] = [d for d in dirs if not d.startswith(".")]
|
||||
files = [f for f in files if not f.startswith(".")]
|
||||
|
||||
# 添加目录
|
||||
for dir_name in dirs:
|
||||
dir_path = os.path.join(root, dir_name)
|
||||
structure["directories"].append(os.path.relpath(dir_path, repo_path))
|
||||
|
||||
# 添加文件
|
||||
for file_name in files:
|
||||
file_path = os.path.join(root, file_name)
|
||||
try:
|
||||
file_size = os.path.getsize(file_path)
|
||||
structure["files"].append({
|
||||
"path": os.path.relpath(file_path, repo_path),
|
||||
"size": file_size
|
||||
})
|
||||
structure["size"] += file_size
|
||||
except:
|
||||
pass
|
||||
|
||||
return structure
|
||||
Reference in New Issue
Block a user