mirror of
https://github.com/LeoYeAI/openclaw-master-skills.git
synced 2026-08-14 00:48:08 +00:00
149 lines
5.6 KiB
Python
149 lines
5.6 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Code Analysis Module for Technical Insight Skill
|
|
Analyzes GitHub repositories and extracts architectural information
|
|
"""
|
|
|
|
import os
|
|
import json
|
|
import subprocess
|
|
from typing import Dict, List, Any
|
|
|
|
class CodeAnalyzer:
|
|
def __init__(self, repo_url: str, output_dir: str):
|
|
self.repo_url = repo_url
|
|
self.output_dir = output_dir
|
|
self.repo_name = repo_url.split('/')[-1].replace('.git', '')
|
|
self.local_path = os.path.join('/tmp', self.repo_name)
|
|
|
|
def clone_repository(self):
|
|
"""Clone the repository for analysis"""
|
|
if os.path.exists(self.local_path):
|
|
subprocess.run(['rm', '-rf', self.local_path], check=True)
|
|
subprocess.run(['git', 'clone', '--depth=1', self.repo_url, self.local_path], check=True)
|
|
|
|
def analyze_structure(self) -> Dict[str, Any]:
|
|
"""Analyze repository structure and extract components"""
|
|
components = []
|
|
dependencies = {}
|
|
|
|
# Walk through the repository
|
|
for root, dirs, files in os.walk(self.local_path):
|
|
# Skip common non-source directories
|
|
dirs[:] = [d for d in dirs if not d.startswith('.') and d not in ['node_modules', '__pycache__', 'build', 'dist']]
|
|
|
|
for file in files:
|
|
if file.endswith(('.py', '.js', '.ts', '.go', '.java', '.cpp', '.h')):
|
|
file_path = os.path.join(root, file)
|
|
relative_path = os.path.relpath(file_path, self.local_path)
|
|
|
|
# Extract component info
|
|
component_info = self._extract_component_info(file_path, relative_path)
|
|
if component_info:
|
|
components.append(component_info)
|
|
|
|
return {
|
|
'components': components,
|
|
'dependencies': dependencies,
|
|
'repo_info': {
|
|
'url': self.repo_url,
|
|
'name': self.repo_name
|
|
}
|
|
}
|
|
|
|
def _extract_component_info(self, file_path: str, relative_path: str) -> Dict[str, Any]:
|
|
"""Extract component information from a source file"""
|
|
try:
|
|
with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
|
|
content = f.read()
|
|
|
|
# Basic metrics
|
|
lines = len(content.split('\n'))
|
|
imports = self._extract_imports(content, file_path)
|
|
|
|
return {
|
|
'file_path': relative_path,
|
|
'lines_of_code': lines,
|
|
'imports': imports,
|
|
'complexity': self._estimate_complexity(content),
|
|
'language': self._detect_language(file_path)
|
|
}
|
|
except Exception as e:
|
|
return None
|
|
|
|
def _extract_imports(self, content: str, file_path: str) -> List[str]:
|
|
"""Extract import statements from source code"""
|
|
imports = []
|
|
language = self._detect_language(file_path)
|
|
|
|
if language == 'python':
|
|
for line in content.split('\n'):
|
|
if line.strip().startswith('import ') or line.strip().startswith('from '):
|
|
imports.append(line.strip())
|
|
elif language in ['javascript', 'typescript']:
|
|
for line in content.split('\n'):
|
|
if 'require(' in line or 'import ' in line:
|
|
imports.append(line.strip())
|
|
# Add more languages as needed
|
|
|
|
return imports
|
|
|
|
def _estimate_complexity(self, content: str) -> int:
|
|
"""Estimate code complexity (simplified)"""
|
|
# Count control flow statements as a proxy for complexity
|
|
complexity_keywords = ['if', 'else', 'for', 'while', 'switch', 'case', 'try', 'catch']
|
|
complexity = 0
|
|
for keyword in complexity_keywords:
|
|
complexity += content.count(keyword)
|
|
return complexity
|
|
|
|
def _detect_language(self, file_path: str) -> str:
|
|
"""Detect programming language from file extension"""
|
|
ext = os.path.splitext(file_path)[1].lower()
|
|
language_map = {
|
|
'.py': 'python',
|
|
'.js': 'javascript',
|
|
'.ts': 'typescript',
|
|
'.go': 'go',
|
|
'.java': 'java',
|
|
'.cpp': 'c++',
|
|
'.cc': 'c++',
|
|
'.cxx': 'c++',
|
|
'.h': 'c-header',
|
|
'.hpp': 'c-header'
|
|
}
|
|
return language_map.get(ext, 'unknown')
|
|
|
|
def save_analysis(self, analysis_data: Dict[str, Any]):
|
|
"""Save analysis results to JSON file"""
|
|
output_file = os.path.join(self.output_dir, 'data', 'code-analysis.json')
|
|
os.makedirs(os.path.dirname(output_file), exist_ok=True)
|
|
|
|
with open(output_file, 'w', encoding='utf-8') as f:
|
|
json.dump(analysis_data, f, indent=2, ensure_ascii=False)
|
|
|
|
def run_full_analysis(self, repo_url: str = None):
|
|
"""Run complete code analysis pipeline"""
|
|
if repo_url:
|
|
self.repo_url = repo_url
|
|
|
|
print(f"Starting code analysis for {self.repo_url}")
|
|
self.clone_repository()
|
|
analysis_data = self.analyze_structure()
|
|
self.save_analysis(analysis_data)
|
|
print(f"Analysis completed. Results saved to {self.output_dir}/data/code-analysis.json")
|
|
|
|
return analysis_data
|
|
|
|
if __name__ == "__main__":
|
|
# Example usage
|
|
import sys
|
|
if len(sys.argv) != 3:
|
|
print("Usage: python code-analysis-module.py <repo_url> <output_dir>")
|
|
sys.exit(1)
|
|
|
|
repo_url = sys.argv[1]
|
|
output_dir = sys.argv[2]
|
|
|
|
analyzer = CodeAnalyzer(repo_url, output_dir)
|
|
analyzer.run_full_analysis() |