mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2026-10-14 00:20:06 +08:00
✨ feat(http_utils): 添加可选的 accept_status_codes 参数以支持自定义状态码处理 (#2096)
- 在 AsyncHttpx 类中,新增 accept_status_codes 参数,允许用户指定哪些 HTTP 状态码不视为错误。 - 更新了单次请求的逻辑,以便在响应状态码符合 accept_status_codes 时不调用 raise_for_status 方法。 ✨ feat(message): 增加随机失败提示消息功能 - 在 MessageUtils 类中,添加可爱风格的失败提示消息列表和获取随机消息的方法。 ✨ feat(github_utils): 引入动态查询外部插件分组的功能 - 在 AliyunFileInfo 类中,新增 list_group_repositories 方法以列出分组下的所有仓库,并实现通过仓库名称获取仓库ID的逻辑。 ✨ feat(virtual_env_package_manager): 增加清理 requirements 文件的功能 - 新增 _clean_requirements_file 方法,清理 requirements 文件中的非ASCII注释,避免 Windows 上 pip 使用 GBK 编码读取 UTF-8 文件时出错。 ✨ feat(repo_utils): 优化阿里云仓库 URL 处理逻辑 - 更新 prepare_aliyun_url 方法以支持指定分组名称,并新增 get_aliyun_group_for_repo 方法以获取仓库所属的阿里云分组名。
This commit is contained in:
@@ -23,7 +23,7 @@ from .exceptions import (
|
||||
RepoManagerError,
|
||||
)
|
||||
from .models import FileDownloadResult, RepoFileInfo, RepoType
|
||||
from .utils import prepare_aliyun_url, sparse_checkout_clone
|
||||
from .utils import get_aliyun_group_for_repo, prepare_aliyun_url, sparse_checkout_clone
|
||||
|
||||
|
||||
class RepoFileManager:
|
||||
@@ -469,6 +469,35 @@ class RepoFileManager:
|
||||
if all(f.path != file.path for f in file_list if f != file)
|
||||
]
|
||||
|
||||
def _clean_requirements_content(self, content: str) -> str:
|
||||
"""
|
||||
清理 requirements.txt 内容,移除包含非ASCII字符的注释行
|
||||
|
||||
这是为了防止 Windows 上 pip 使用 GBK 编码读取 UTF-8 文件时出错
|
||||
|
||||
参数:
|
||||
content: requirements.txt 文件内容
|
||||
|
||||
返回:
|
||||
str: 清理后的内容
|
||||
"""
|
||||
lines = content.splitlines()
|
||||
cleaned_lines = []
|
||||
for line in lines:
|
||||
stripped = line.strip()
|
||||
# 跳过空行
|
||||
if not stripped:
|
||||
continue
|
||||
# 如果是注释行且包含非ASCII字符,跳过
|
||||
if stripped.startswith("#"):
|
||||
try:
|
||||
stripped.encode("ascii")
|
||||
except UnicodeEncodeError:
|
||||
# 包含非ASCII字符的注释行,跳过
|
||||
continue
|
||||
cleaned_lines.append(line)
|
||||
return "\n".join(cleaned_lines) + "\n" if cleaned_lines else ""
|
||||
|
||||
async def download_files(
|
||||
self,
|
||||
repo_url: str,
|
||||
@@ -576,6 +605,10 @@ class RepoFileManager:
|
||||
local_path = file_path_mapping[repo_file_path]
|
||||
local_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
if isinstance(content, str):
|
||||
# 对 requirements 文件特殊处理:移除包含非ASCII字符的注释行
|
||||
# 防止 Windows GBK 编码问题
|
||||
if repo_file_path.endswith(("requirements.txt", "requirement.txt")):
|
||||
content = self._clean_requirements_content(content)
|
||||
content_bytes = content.encode("utf-8")
|
||||
else:
|
||||
content_bytes = content
|
||||
@@ -604,8 +637,16 @@ class RepoFileManager:
|
||||
result: FileDownloadResult,
|
||||
) -> FileDownloadResult:
|
||||
try:
|
||||
# 获取仓库所属的分组名(外部插件仓库可能在不同分组下)
|
||||
repo_name = (
|
||||
repo_url.split("/tree/")[0].split("/")[-1].replace(".git", "").strip()
|
||||
)
|
||||
group_name = await get_aliyun_group_for_repo(repo_name)
|
||||
|
||||
aliyun_repo_url = prepare_aliyun_url(repo_url, group_name)
|
||||
|
||||
await sparse_checkout_clone(
|
||||
repo_url=prepare_aliyun_url(repo_url),
|
||||
repo_url=aliyun_repo_url,
|
||||
branch=branch,
|
||||
sparse_path=sparse_path,
|
||||
target_dir=target_dir,
|
||||
@@ -618,7 +659,7 @@ class RepoFileManager:
|
||||
total_size += f.stat().st_size
|
||||
result.success = True
|
||||
result.file_size = total_size
|
||||
logger.info(f"sparse-checkout 克隆成功: {target_dir}")
|
||||
logger.info(f"sparse-checkout 克隆成功: {target_dir}:{aliyun_repo_url}")
|
||||
return result
|
||||
except GitUnavailableError as e:
|
||||
logger.error(f"Git不可用: {e}")
|
||||
|
||||
@@ -227,11 +227,12 @@ async def sparse_checkout_clone(
|
||||
shutil.move(str(source_path), str(target_path))
|
||||
|
||||
|
||||
def prepare_aliyun_url(repo_url: str) -> str:
|
||||
def prepare_aliyun_url(repo_url: str, group_name: str | None = None) -> str:
|
||||
"""解析阿里云CodeUp的仓库URL
|
||||
|
||||
参数:
|
||||
repo_url: 仓库URL
|
||||
group_name: 分组名称,如果为None则使用默认组织名称
|
||||
|
||||
返回:
|
||||
str: 解析后的仓库URL
|
||||
@@ -239,10 +240,12 @@ def prepare_aliyun_url(repo_url: str) -> str:
|
||||
config = RepoConfig.get_instance()
|
||||
|
||||
repo_name = repo_url.split("/tree/")[0].split("/")[-1].replace(".git", "")
|
||||
# 使用指定的分组名或默认组织名称
|
||||
group = group_name or config.aliyun_codeup.organization_name
|
||||
# 构建仓库URL
|
||||
# 阿里云CodeUp的仓库URL格式通常为:
|
||||
# https://codeup.aliyun.com/{organization_id}/{organization_name}/{repo_name}.git
|
||||
url = f"https://codeup.aliyun.com/{config.aliyun_codeup.organization_id}/{config.aliyun_codeup.organization_name}/{repo_name}.git"
|
||||
# https://codeup.aliyun.com/{organization_id}/{group_name}/{repo_name}.git
|
||||
url = f"https://codeup.aliyun.com/{config.aliyun_codeup.organization_id}/{group}/{repo_name}.git"
|
||||
|
||||
# 添加访问令牌 - 使用base64解码后的令牌
|
||||
if config.aliyun_codeup.rdc_access_token_encrypted:
|
||||
@@ -258,3 +261,35 @@ def prepare_aliyun_url(repo_url: str) -> str:
|
||||
logger.error(f"解码RDC令牌失败: {e}")
|
||||
|
||||
return url
|
||||
|
||||
|
||||
async def get_aliyun_group_for_repo(repo_name: str) -> str | None:
|
||||
"""获取仓库所属的阿里云分组名
|
||||
|
||||
参数:
|
||||
repo_name: 仓库名称
|
||||
|
||||
返回:
|
||||
str | None: 分组名称,如果在核心映射中则返回None(使用默认组织名)
|
||||
"""
|
||||
from zhenxun.utils.github_utils.const import (
|
||||
ALIYUN_EXTERNAL_PLUGIN_GROUPS,
|
||||
ALIYUN_REPO_MAPPING,
|
||||
)
|
||||
from zhenxun.utils.github_utils.models import AliyunFileInfo
|
||||
|
||||
# 如果在核心映射中,使用默认组织名
|
||||
if repo_name in ALIYUN_REPO_MAPPING:
|
||||
return None
|
||||
|
||||
# 尝试从外部插件分组中查找
|
||||
for group_path in ALIYUN_EXTERNAL_PLUGIN_GROUPS:
|
||||
try:
|
||||
repos = await AliyunFileInfo.list_group_repositories(group_path)
|
||||
for repo in repos:
|
||||
if repo.get("name") == repo_name:
|
||||
return group_path
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
return None
|
||||
|
||||
Reference in New Issue
Block a user