100 lines
3.6 KiB
Python
100 lines
3.6 KiB
Python
import os
|
||
import shutil
|
||
import subprocess
|
||
import tempfile
|
||
from datetime import datetime
|
||
|
||
CODE_EXTENSIONS = {
|
||
'.py', '.js', '.ts', '.java', '.c', '.cpp', '.h', '.hpp', '.cs', '.php', '.rb', '.go',
|
||
'.rs', '.kt', '.swift', '.html', '.css', '.scss', '.json', '.xml', '.yaml', '.yml',
|
||
'.sh', '.bat', '.sql', '.md'
|
||
}
|
||
|
||
SKIP_DIRS = {'.git', 'node_modules', '__pycache__', 'venv', '.venv', 'dist', 'build'}
|
||
|
||
|
||
def run_cmd(cmd, cwd=None):
|
||
result = subprocess.run(
|
||
cmd,
|
||
cwd=cwd,
|
||
stdout=subprocess.PIPE,
|
||
stderr=subprocess.PIPE,
|
||
text=True,
|
||
timeout=60,
|
||
)
|
||
if result.returncode != 0:
|
||
raise Exception(result.stderr.strip() or result.stdout.strip())
|
||
return result.stdout.strip()
|
||
|
||
|
||
def repo_name_from_url(url):
|
||
name = url.rstrip('/').split('/')[-1]
|
||
if name.endswith('.git'):
|
||
name = name[:-4]
|
||
return name or 'repository'
|
||
|
||
|
||
def count_code_lines(repo_path):
|
||
total = 0
|
||
files_count = 0
|
||
for root, dirs, files in os.walk(repo_path):
|
||
dirs[:] = [d for d in dirs if d not in SKIP_DIRS]
|
||
for filename in files:
|
||
ext = os.path.splitext(filename)[1].lower()
|
||
if ext not in CODE_EXTENSIONS:
|
||
continue
|
||
path = os.path.join(root, filename)
|
||
try:
|
||
with open(path, 'r', encoding='utf-8', errors='ignore') as f:
|
||
total += len(f.readlines())
|
||
files_count += 1
|
||
except Exception:
|
||
pass
|
||
return total, files_count
|
||
|
||
|
||
def analyze_repository(repo_url):
|
||
temp_dir = tempfile.mkdtemp(prefix='git_analyzer_')
|
||
repo_dir = os.path.join(temp_dir, repo_name_from_url(repo_url))
|
||
try:
|
||
run_cmd(['git', 'clone', '--depth', '100', repo_url, repo_dir])
|
||
|
||
repo_name = repo_name_from_url(repo_url)
|
||
authors_raw = run_cmd(['git', 'log', '--format=%an'], cwd=repo_dir)
|
||
authors = []
|
||
for name in authors_raw.splitlines():
|
||
name = name.strip()
|
||
if name and name not in authors:
|
||
authors.append(name)
|
||
|
||
created = run_cmd(['git', 'log', '--reverse', '--format=%ci', '-1'], cwd=repo_dir)
|
||
updated = run_cmd(['git', 'log', '-1', '--format=%ci'], cwd=repo_dir)
|
||
commits_count = run_cmd(['git', 'rev-list', '--count', 'HEAD'], cwd=repo_dir)
|
||
branch = run_cmd(['git', 'branch', '--show-current'], cwd=repo_dir)
|
||
lines, files_count = count_code_lines(repo_dir)
|
||
|
||
main_author = authors[0] if authors else 'нет данных'
|
||
coauthors = authors[1:]
|
||
|
||
text = []
|
||
text.append(f'Ссылка: {repo_url}')
|
||
text.append(f'Название репозитория: {repo_name}')
|
||
text.append(f'Ветка: {branch or "не определена"}')
|
||
text.append('')
|
||
text.append(f'Автор по первому коммиту: {main_author}')
|
||
text.append('Соавторы по коммитам:')
|
||
if coauthors:
|
||
for a in coauthors:
|
||
text.append(f'- {a}')
|
||
else:
|
||
text.append('- нет соавторов')
|
||
text.append('')
|
||
text.append(f'Дата создания по первому коммиту: {created or "нет данных"}')
|
||
text.append(f'Дата последнего изменения: {updated or "нет данных"}')
|
||
text.append(f'Количество коммитов: {commits_count or "0"}')
|
||
text.append(f'Файлов с кодом/текстом: {files_count}')
|
||
text.append(f'Строк кода/текста: {lines}')
|
||
return '\n'.join(text)
|
||
finally:
|
||
shutil.rmtree(temp_dir, ignore_errors=True)
|