init
This commit is contained in:
@@ -52,9 +52,12 @@ class BaseScanner(ABC):
|
||||
repo_name = repo_url.split('/')[-1].replace('.git', '')
|
||||
commit_hash = commit_id or branch
|
||||
clone_dir = os.path.join(self.temp_dir, f"{repo_name}_{commit_hash}")
|
||||
# 如果目录已存在,先删除
|
||||
|
||||
# 如果目录已存在,先删除(带重试机制)
|
||||
if os.path.exists(clone_dir):
|
||||
shutil.rmtree(clone_dir)
|
||||
self.cleanup(clone_dir)
|
||||
|
||||
repo = None
|
||||
try:
|
||||
logger.info(f'克隆仓库: {repo_url}')
|
||||
# 克隆仓库(浅克隆,只获取最新提交)
|
||||
@@ -64,26 +67,52 @@ class BaseScanner(ABC):
|
||||
depth=1,
|
||||
branch=branch
|
||||
)
|
||||
|
||||
# 如果指定了 commit_id,切换到该提交
|
||||
if commit_id:
|
||||
repo.git.checkout(commit_id)
|
||||
|
||||
logger.info(f'仓库克隆成功: {clone_dir}')
|
||||
return clone_dir
|
||||
except Exception as e:
|
||||
logger.error(f'克隆仓库失败: {str(e)}')
|
||||
raise
|
||||
finally:
|
||||
# 显式关闭 Repo 对象以释放文件句柄(特别是 Windows)
|
||||
if repo is not None:
|
||||
repo.close()
|
||||
def cleanup(self, clone_dir: str):
|
||||
"""
|
||||
清理临时目录
|
||||
清理临时目录(带重试机制,处理 Windows 权限问题)
|
||||
Args:
|
||||
clone_dir: 克隆的目录路径
|
||||
"""
|
||||
try:
|
||||
if os.path.exists(clone_dir):
|
||||
shutil.rmtree(clone_dir)
|
||||
logger.info(f'清理临时目录: {clone_dir}')
|
||||
except Exception as e:
|
||||
logger.warning(f'清理临时目录失败: {str(e)}')
|
||||
import time
|
||||
import stat
|
||||
|
||||
def handle_remove_readonly(func, path, exc_info):
|
||||
"""处理只读文件的删除问题(Windows)"""
|
||||
# 添加写权限并重试
|
||||
os.chmod(path, stat.S_IWRITE)
|
||||
func(path)
|
||||
|
||||
max_retries = 3
|
||||
retry_delay = 1 # 秒
|
||||
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
if os.path.exists(clone_dir):
|
||||
# Windows 上使用 onerror 回调处理只读文件
|
||||
shutil.rmtree(clone_dir, onerror=handle_remove_readonly)
|
||||
logger.info(f'清理临时目录: {clone_dir}')
|
||||
return # 成功清理,直接返回
|
||||
except Exception as e:
|
||||
if attempt < max_retries - 1:
|
||||
logger.warning(f'清理临时目录失败,{retry_delay}秒后重试: {str(e)}')
|
||||
time.sleep(retry_delay)
|
||||
retry_delay *= 2 # 指数退避
|
||||
else:
|
||||
logger.warning(f'清理临时目录失败(已重试{max_retries}次): {str(e)}')
|
||||
def run_command(self, cmd: List[str], cwd: str, timeout: int = 300) -> Dict[str, Any]:
|
||||
"""
|
||||
运行命令并返回结果
|
||||
|
||||
Reference in New Issue
Block a user