123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 |
- import os, json,hashlib,re
- from fastapi import APIRouter, BackgroundTasks
- from base_config import path, avatar_url
- from git import Repo
- from pydantic import BaseModel
- from models.gitModels import Users
- class RequestBody(BaseModel):
- uuid: str
- repo_url: str
- class CommitHash(BaseModel):
- uuid: str
- repo_url: str
- commit_hash: str
- def generate_repo_path(uuid, repo_url):
- repo_name = repo_url.split("/")[-1].replace(".git", "")
- base_path = os.path.join(path, uuid)
- return os.path.join(base_path, repo_name), repo_name
- def get_repo(uuid, repo_url):
- path, _ = generate_repo_path(uuid, repo_url)
- if not os.path.exists(path):
- return 0
- return Repo(path)
- def git_stats_to_json(text):
- pattern = r",?\s*(\d+)\s*files changed|,?\s*(\d+)\s*insertions\(\+\)|,?\s*(\d+)\s+deletions\(\-\)"
- data = re.findall(pattern, text)
- result = {}
- for item in data:
- if item[0]:
- result["files_changed"] = int(item[0])
- if item[1]:
- result["insertions"] = int(item[1])
- if item[2]:
- result["deletions"] = int(item[2])
- return result
- gitrouter = APIRouter()
- @gitrouter.post("/clone")
- async def clone(request: RequestBody, background_tasks: BackgroundTasks):
- local_path, repo_name = generate_repo_path(request.uuid, request.repo_url)
- if os.path.exists(local_path):
- return {"status": "400", "msg": "仓库已存在", "uuid": request.uuid, "repo_url": request.repo_url,
- "path": local_path}
- else:
- background_tasks.add_task(Repo.clone_from, request.repo_url, local_path)
- response = {"status": "200", "msg": "成功创建克隆任务", "uuid": request.uuid, "repo_name": repo_name,
- "local_path": local_path}
- return response
- @gitrouter.post("/log")
- async def log(request: RequestBody):
- local_path, _ = generate_repo_path(request.uuid, request.repo_url)
- repo = get_repo(request.uuid, request.repo_url)
- if not repo:
- return {"status": "404", "msg": "仓库不存在", "uuid": request.uuid, "repo_url": request.repo_url,
- "local_path": local_path}
- log_ = repo.git.log('--pretty={"commit":"%h","author":"%an","email":"%ce","summary":"%s","date":"%cd"}', max_count=50,
- date='format:%Y-%m-%d %H:%M').split("\n")
- log = list(map(json.loads, log_))
- for i in log:
- email = i["email"]
- email_md5 = hashlib.md5(email.encode(encoding='UTF-8')).hexdigest()
- i["avatar"] = avatar_url+email_md5+"?d=identicon"
- status=repo.git.execute(["git", "show",i["commit"] , "--shortstat"]).split("\n")[-1]
- i["change"]=git_stats_to_json(status)
- response = {"status": "200", "msg": "成功获取日志", "uuid": request.uuid, "repo_url": request.repo_url,
- "local_path": local_path, "git_log": log}
- return response
- @gitrouter.post("/status")
- async def status(request: RequestBody):
- repo = get_repo(request.uuid, request.repo_url)
- # 手动获取所有数据
- active_branch = repo.active_branch
- tracking_branch = active_branch.tracking_branch()
- ahead = sum(1 for _ in repo.iter_commits(f"{active_branch}..{tracking_branch}"))
- behind = sum(1 for _ in repo.iter_commits(f"{tracking_branch}..{active_branch}"))
- conflicts = repo.index.unmerged_blobs()
- conflicted = [path for path, entries in conflicts.items()]
- created_files = repo.untracked_files
- current = repo.active_branch.name
- head_commit = repo.head.commit
- tree = head_commit.tree
- all_files = [item.path for item in tree.traverse() if item.type == 'blob']
- diffs = repo.index.diff(None)
- deleted = [d.a_path for d in diffs if d.change_type == 'D']
- detached = repo.head.is_detached
- ignored_files = repo.git.execute(["git", "ls-files", "--others", "--ignored", "--exclude-standard"]).split("\n")
- modified_files = [d.a_path for d in diffs]
- untracked_files = repo.untracked_files
- staged_entries = repo.index.entries
- staged = [path[0] for path, _ in staged_entries.items()]
- tracking = active_branch.tracking_branch().name
- status = {"ahead": ahead, "behind": behind, "conflicted": conflicted, "created": created_files,
- "current": current, "deleted": deleted, "detached": detached, "files": all_files,
- "ignored": ignored_files,
- "modified": modified_files, "not_added": untracked_files, "staged": staged, "tracking": tracking}
- return status
- @gitrouter.post("/change")
- async def change(request: CommitHash):
- repo = get_repo(request.uuid, request.repo_url)
- if not repo:
- return {"status": "404", "msg": "仓库不存在", "uuid": request.uuid, "repo_url": request.repo_url}
- commit = repo.commit(request.commit_hash)
- if not commit.parents:
- print("首次提交,无父提交对比")
- return
- parent = commit.parents[0]
- diffs = commit.diff(commit,create_patch=True, no_renames=True)
- print(diffs)
- for diff in diffs:
- print(f"文件 {diff.a_path} ({diff.change_type}):")
- print(diff.diff.decode('utf-8'))
|