feat: 内置pygit2进行代码管理#548
Conversation
Walkthrough本次更新将 Git 功能从调用系统 Git 重构为基于 pygit2 的实现,移除 DownloadService 依赖,新增多个仓库管理与查询接口,并同步更新依赖、安装器与若干设置/界面中关于 Git 的组件与选项。 Changes
Sequence Diagram(s)sequenceDiagram
participant UI as UI 层
participant EnvCtx as EnvContext
participant GitSvc as GitService
participant PyGit2 as pygit2
participant Remote as 远程仓库
Note over GitSvc,PyGit2: 新的 pygit2 驱动工作流
UI->>EnvCtx: 请求同步/更新代码
EnvCtx->>GitSvc: fetch_latest_code(progress_cb)
GitSvc->>GitSvc: _open_repo() / _validate_working_directory()
alt 本地仓库存在
GitSvc->>PyGit2: 打开仓库 & _ensure_remote()
GitSvc->>PyGit2: _fetch_remote()
PyGit2->>Remote: fetch
Remote-->>PyGit2: 对象
GitSvc->>GitSvc: _checkout_branch() / _sync_with_remote()
else 仓库不存在
GitSvc->>PyGit2: _clone_repository(progress_cb)
PyGit2->>Remote: clone
Remote-->>PyGit2: 完整仓库
end
GitSvc-->>EnvCtx: (success:boolean, message:str)
EnvCtx-->>UI: 同步结果显示
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
eb68432 to
b17ea12
Compare
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (8)
deploy/OneDragon-Launcher.spec (1)
9-9: 在hiddenimports中加入_cffi_backend有助于避免运行时缺少 cffi 后端这行对 PyInstaller 是有效配置,可以确保打包后的启动器能正确加载 cffi 后端模块;静态分析提示 “Useless assignment to variable
hiddenimports” 在.spec文件场景下属于误报,如影响 CI,可以考虑在该文件或该规则上做忽略配置,而无需改动代码。src/one_dragon/envs/env_config.py (1)
269-283: git_remote getter/setter 实现合理,可考虑在 setter 中做枚举校验当前直接保存字符串配置是足够的,但如果用户手动改 YAML 写错值,会在运行时才暴露问题。可以考虑在
git_remotesetter 中校验new_value是否属于GitRemoteEnum的合法值(或在 UI 层保证只写入这些值),以提前避免配置错误。src/one_dragon/envs/git_service.py (6)
37-49: 构造函数的仓库路径处理与全局 git 配置隔离总体合理,但需注意全局副作用
repo_dir相对路径自动转成基于get_work_dir()的绝对路径,默认指向工作目录,这个约定和 CLI/打包场景都比较友好。_ensure_config_search_path()里把所有级别的 git 配置搜索路径清空并关闭所有权校验,能有效避免用户全局 git 配置(代理、证书、user.name 等)干扰程序,但这是对 pygit2 全局settings的修改,会影响同进程中其它潜在的 pygit2 使用场景。若未来项目内还有其它模块使用 pygit2、且需要尊重部分用户 git 配置,可能需要在文档中标明这一点,或将该行为做成可配置开关。Also applies to: 53-64
80-109: 远程仓库与代理地址解析逻辑清晰,可考虑对配置缺失情况做更强校验
_ensure_remote()会在远程不存在时自动创建,在 URL 变更时更新并打日志,整体流程和 Git 的直觉一致。_get_git_repository()根据repository_type与is_gh_proxy选择 GitHub/Gitee 地址,并在开启 GitHub 代理时拼接gh_proxy_url,逻辑简单直接。_get_proxy_address()仅在“个人代理”模式下启用代理,并自动补全http://前缀,容错性还不错。建议点:
- 若
project_config中的仓库地址字段为空(例如配置文件缺少),当前会返回空字符串并在_ensure_remote()中抛ValueError。可以在这里就记录更明确的配置错误日志,或在配置加载时做前置校验,避免用户只看到“未能获取有效的远程仓库地址”的笼统提示。- 若未来支持更多仓库类型或协议(如 SSH),可以考虑把这一块提炼成更明确的策略枚举,便于扩展。
Also applies to: 111-139
140-183: _fetch_remote 的增量/浅拉取策略设计良好,错误处理可以按需细化
- 根据本地是否已有同名分支及是否有提交历史来决定
depth=1(首次浅克隆)还是depth=0(完整增量拉取),在性能和完整性之间做了合理折中。- 通过捕获
KeyError且仅在信息包含'object not found'时回退到depth=1重试,可以应对部分增量拉取引用缺失的情况,其余错误交由外层统一处理并记录堆栈。如后续希望调试问题更方便,可以考虑:
- 对 pygit2 抛出的特定异常(例如 GitError)做更精细的分类处理或更详细的日志信息,以区分网络问题、认证问题和仓库损坏等不同场景。当前统一
except Exception的策略在稳健性上没问题,但会牺牲一部分可诊断性。
393-433: 克隆与更新流程拆分清晰,progress 回调粒度适中
_clone_repository()通过init_repository初始化本地仓库,然后调用_fetch_remote、_checkout_branch、_sync_with_remote(force=True)三步走,最后统一返回“克隆仓库成功”,结构清晰,且多处失败都会返回明确的本地化提示。_fetch_and_checkout_latest_branch()在已有仓库时复用相同的步骤顺序:拉取远程 → 校验工作区 → 切换分支 → 同步远程,并结合env_config.force_update决定是否允许覆盖本地修改。- 两个流程都使用 1/5 ~ 5/5 的进度分段报告,对于 UI 展示进度条已经足够细,且不易产生跳变。
可以视情况在未来扩展:在
_clone_repository失败时考虑清理半初始化状态的目录,避免用户二次重试时落在“存在但损坏的仓库”状态(目前这类情况会通过check_repo_exists()走更新路径)。Also applies to: 435-475
535-565: 分页获取 commit 与当前版本号获取实现合理,注意大页码可能带来的遍历成本
fetch_page_commit()使用 walker 从 HEAD 向后遍历,通过idx < page_num * page_size跳过前面页面,然后收集固定数量的GitLog,字段包括短哈希、作者、时间戳和首行 commit message,满足常见 UI 列表需求。get_current_version()直接复用fetch_page_commit(0, 1)拿到最新一条提交的短哈希,避免重复实现。唯一需要注意的是,当
page_num较大时仍然是从头开始遍历再丢弃前面的元素(线性复杂度),如果仓库历史非常长且经常访问高页码,可以以后考虑基于skip逻辑或手动 walker 控制优化;当前规模下问题不大。Also applies to: 584-590
591-634: 最新 tag 获取逻辑与语义版本解析配合良好,能区分稳定版和测试版
- 通过
_ensure_remote().list_heads(proxy=...)拉取远端 refs,然后筛选出refs/tags/前缀,使用packaging.version.parse解析为Version对象,并过滤掉无法解析的 tag。- 将这些版本按降序排序后,依次挑出第一个稳定版(非
is_prerelease)和第一个预发布版作为“最新稳定版”和“最新测试版”,在只存在测试版或只存在稳定版时也能正确返回另一项为空字符串。实现上覆盖了绝大多数语义化版本场景,如果未来仓库中存在大量非语义化 tag(例如纯日期或特殊前缀),可以视情况在这里做额外的过滤规则或白名单,以减少解析失败的噪音。
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
uv.lockis excluded by!**/*.lock
📒 Files selected for processing (10)
deploy/OneDragon-Launcher.spec(1 hunks)pyproject.toml(1 hunks)src/one_dragon/base/operation/one_dragon_env_context.py(1 hunks)src/one_dragon/envs/env_config.py(3 hunks)src/one_dragon/envs/git_service.py(1 hunks)src/one_dragon_qt/view/code_interface.py(3 hunks)src/one_dragon_qt/view/installer_interface.py(2 hunks)src/one_dragon_qt/view/setting/setting_env_interface.py(1 hunks)src/one_dragon_qt/view/source_config_interface.py(1 hunks)src/one_dragon_qt/widgets/install_card/git_install_card.py(0 hunks)
💤 Files with no reviewable changes (1)
- src/one_dragon_qt/widgets/install_card/git_install_card.py
🧰 Additional context used
🧬 Code graph analysis (6)
src/one_dragon_qt/view/setting/setting_env_interface.py (2)
src/one_dragon/envs/git_service.py (1)
update_remote(566-576)src/one_dragon_qt/widgets/setting_card/switch_setting_card.py (1)
SwitchSettingCard(15-69)
src/one_dragon/envs/env_config.py (3)
src/one_dragon/base/config/config_item.py (1)
ConfigItem(7-25)src/one_dragon/base/config/yaml_operator.py (3)
get(90-91)update(93-100)save(71-76)src/one_dragon/base/config/push_config.py (1)
setter(74-75)
src/one_dragon_qt/view/source_config_interface.py (1)
src/one_dragon/envs/git_service.py (1)
update_remote(566-576)
src/one_dragon/base/operation/one_dragon_env_context.py (1)
src/one_dragon/envs/git_service.py (1)
GitService(35-634)
src/one_dragon_qt/view/code_interface.py (2)
src/one_dragon_qt/widgets/setting_card/switch_setting_card.py (2)
SwitchSettingCard(15-69)init_with_adapter(58-61)src/one_dragon/base/config/yaml_config.py (1)
get_prop_adapter(87-103)
src/one_dragon/envs/git_service.py (4)
src/one_dragon/envs/env_config.py (13)
RepositoryTypeEnum(27-30)git_remote(270-275)git_remote(278-283)repository_type(170-175)repository_type(178-183)is_gh_proxy(150-151)gh_proxy_url(318-323)gh_proxy_url(326-331)is_personal_proxy(146-147)personal_proxy(154-159)personal_proxy(162-167)git_branch(286-291)git_branch(294-299)src/one_dragon/envs/project_config.py (1)
ProjectConfig(4-25)src/one_dragon/utils/i18_utils.py (1)
gt(50-61)src/one_dragon/utils/os_utils.py (1)
get_work_dir(45-56)
🪛 RuboCop (1.81.7)
deploy/OneDragon-Launcher.spec
[warning] 9-9: Useless assignment to variable - hiddenimports.
(Lint/UselessAssignment)
🪛 Ruff (0.14.4)
src/one_dragon_qt/view/setting/setting_env_interface.py
75-75: String contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF001)
src/one_dragon_qt/view/code_interface.py
52-52: String contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF001)
src/one_dragon/envs/git_service.py
56-56: Docstring contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF002)
57-57: Docstring contains ambiguous ( (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?
(RUF002)
57-57: Docstring contains ambiguous ) (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?
(RUF002)
58-58: Docstring contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF002)
58-58: Docstring contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF002)
67-67: Docstring contains ambiguous ( (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?
(RUF002)
67-67: Docstring contains ambiguous ) (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?
(RUF002)
75-75: Avoid specifying long messages outside the exception class
(TRY003)
97-97: Comment contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF003)
101-101: Comment contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF003)
106-106: Comment contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF003)
143-143: Docstring contains ambiguous : (FULLWIDTH COLON). Did you mean : (COLON)?
(RUF002)
144-144: Docstring contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF002)
144-144: Docstring contains ambiguous ( (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?
(RUF002)
144-144: Docstring contains ambiguous ) (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?
(RUF002)
145-145: Docstring contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF002)
145-145: Docstring contains ambiguous ( (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?
(RUF002)
145-145: Docstring contains ambiguous ) (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?
(RUF002)
163-163: Comment contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF003)
166-166: Comment contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF003)
172-172: Comment contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF003)
174-174: String contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF001)
180-180: Consider moving this statement to an else block
(TRY300)
181-181: Do not catch blind exception: Exception
(BLE001)
190-190: Docstring contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF002)
201-201: Comment contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF003)
209-209: Consider moving this statement to an else block
(TRY300)
210-210: Do not catch blind exception: Exception
(BLE001)
223-223: Do not catch blind exception: Exception
(BLE001)
239-239: Do not catch blind exception: Exception
(BLE001)
256-256: Do not catch blind exception: Exception
(BLE001)
272-272: Docstring contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF002)
278-278: Do not catch blind exception: Exception
(BLE001)
290-290: Do not catch blind exception: Exception
(BLE001)
308-308: Do not catch blind exception: Exception
(BLE001)
320-320: Consider moving this statement to an else block
(TRY300)
321-321: Do not catch blind exception: Exception
(BLE001)
329-329: Docstring contains ambiguous ( (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?
(RUF002)
329-329: Docstring contains ambiguous ) (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?
(RUF002)
339-339: Comment contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF003)
389-389: String contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF001)
403-403: Do not catch blind exception: Exception
(BLE001)
486-486: Docstring contains ambiguous : (FULLWIDTH COLON). Did you mean : (COLON)?
(RUF002)
486-486: Docstring contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF002)
501-501: Consider moving this statement to an else block
(TRY300)
502-502: Do not catch blind exception: Exception
(BLE001)
539-539: Docstring contains ambiguous ( (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?
(RUF002)
539-539: Docstring contains ambiguous ) (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?
(RUF002)
575-575: Do not catch blind exception: Exception
(BLE001)
592-592: Docstring contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF002)
597-597: Comment contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF003)
604-604: Do not catch blind exception: Exception
(BLE001)
🔇 Additional comments (18)
src/one_dragon_qt/view/source_config_interface.py (1)
87-87: 确认方法调用的一致性。代码将
update_git_remote()更新为update_remote(),与提供的相关代码片段一致。此更改符合 PR 中将 Git 服务重构为使用 PyGit2 的目标。src/one_dragon_qt/view/code_interface.py (4)
51-54: 自动更新选项集成正确。新增的
auto_update_optSwitchSettingCard 与相关代码片段中的SwitchSettingCard类定义一致,使用了适配器模式进行配置绑定。
131-131: 适配器初始化正确。使用
get_prop_adapter('auto_update')初始化开关状态,与其他配置项的初始化方式保持一致。
153-153: 分页计算修正正确。从
total // self.page_size + 1改为(total + self.page_size - 1) // self.page_size是正确的向上取整实现,避免了当total为 0 时错误地返回 1 页的问题。
52-52: 全角逗号是中文标点的正确用法。静态分析工具标记的全角逗号(,)在中文文本中是正确的标点符号用法,不是错误。在中文排版规范中,应该使用全角逗号而非半角逗号。
src/one_dragon_qt/view/setting/setting_env_interface.py (4)
71-71: 方法调用更新一致。与
source_config_interface.py中的更改保持一致,使用update_remote()方法。这符合 PyGit2 重构的整体变更。
74-77: 自动更新选项替换合理。用
auto_update_opt(SwitchSettingCard) 替换了之前的git_method_opt(ComboBoxSettingCard),简化了用户界面选项,提供了更直观的开关控制。
187-187: 适配器绑定正确。正确初始化
auto_update_opt与配置文件的auto_update字段绑定。
75-75: 全角逗号是中文标点的正确用法。静态分析工具标记的全角逗号在中文文本中是正确的标点符号,符合中文排版规范。
src/one_dragon_qt/view/installer_interface.py (2)
512-534: 安装步骤简化合理。将安装步骤从 4 步(Git 环境、代码同步、环境配置、安装启动器)简化为 3 步(代码同步、环境配置、安装启动器)。这个变更与移除独立 Git 安装步骤的决策一致,简化了用户安装流程。
484-484: 验证完成:PyGit2 依赖已正确配置。PyGit2 版本 1.19.0 已在
pyproject.toml文件中正确声明为项目依赖。移除git_opt安装卡与 PR 目标一致,因为 Git 功能现在通过 PyGit2 库作为 Python 依赖自动安装。pyproject.toml (1)
20-20: 新增 pygit2 依赖整体合理,但请确认运行/打包环境兼容性和现有依赖一样使用
==1.19.0固定版本是合理的,不过 pygit2 依赖底层 libgit2 与 cffi,建议你在目标平台(尤其是 Windows + Python 3.11 + PyInstaller 打包场景)上确认该版本有可用的 wheel 且运行正常,避免安装或打包时才暴露问题。src/one_dragon/envs/env_config.py (2)
46-50: GitRemoteEnum 设计清晰,和后续 GitService 用法匹配直接用
'origin'/'upstream'作为值,和后面 GitService 里通过env_config.git_remote读取远程名的实现是对齐的,后续若要扩展更多远程(例如镜像源),继续在此处加枚举即可。
480-482: ocr_cache 显式使用save=True能确保修改立即持久化将
ocr_cache更新时显式传入save=True,可以避免未来如果update默认行为调整导致配置未落盘的问题,与“这是用户偏好开关”的语义也更一致。src/one_dragon/base/operation/one_dragon_env_context.py (1)
24-26: GitService 初始化已正确适配新的构造函数签名这里从
GitService(project_config, env_config, download_service)改为仅传project_config和env_config与新实现保持一致,同时保留DownloadService给PythonService使用,职责划分更清晰,没有看到额外副作用。src/one_dragon/envs/git_service.py (3)
246-264: 工作区校验与分支同步逻辑整体正确,涵盖快进、强制更新和手动处理三种路径
_validate_working_directory()通过repo.status()判断是否“干净”,在未开启force_update且存在本地修改时中止后续操作,能很好地保护用户本地改动。_checkout_branch()在本地分支不存在时尝试从对应远程分支创建,再进行强制 checkout 与set_head,流程符合 Git 直觉;如果本地和远程都没有该分支,则明确打错误日志后返回失败。_sync_with_remote()中:
- 优先处理
HEAD不存在的情况,并尊重force参数是否允许直接reset到远程。- 使用
descendant_of(remote_oid, local_oid)+ 工作区干净性判断来识别快进场景,然后通过_reset_hard做快进更新。- 在无法快进时,若
force=True则执行强制重置,否则返回“需要手动处理”的提示信息。这些分支组合起来,可以覆盖大部分常见场景(首次更新、普通快进、本地有修改/分叉)。目前没有发现明显的边界条件错误,后续如果在某些极端历史形态(例如复杂分叉)下发现行为与预期不符,再根据实际 case 微调判断条件会更有针对性。
Also applies to: 282-323, 325-391
478-505: 仓库存在性检测与“是否最新”判断、commit 总数计算逻辑简洁可靠
check_repo_exists()使用discover_repository检查.git路径是否存在,配合fetch_latest_code()对“克隆 vs 更新”两条路径做了清晰分支。is_current_branch_latest()先强制拉取远程,再调用_get_local_and_remote_oid()对 HEAD OID 做比较,若一致直接返回(True, ''),接口语义直观,方便调用方根据布尔值和信息提示做 UI 展示。fetch_total_commit()基于_get_commit_walker()对 walker 简单计数,在失败时返回 0,容错性好;仓库 commit 数量一般不至于大到成为性能瓶颈。整体这里的 API 设计对上层调用比较友好,没有明显问题。
Also applies to: 506-526, 527-534
637-641: 模块级__fetch_latest_code帮助函数便于调试与脚本复用底部的
__fetch_latest_code()使用默认ProjectConfig/EnvConfig构造GitService并调用fetch_latest_code,在本地调试或命令行直接运行该模块时非常方便,也便于以后在其他脚本中直接复用这一入口。
b17ea12 to
3bda42b
Compare
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (2)
src/one_dragon/envs/git_service.py (2)
66-78: 仓库打开逻辑正确,建议优化错误消息。使用缓存机制避免重复打开仓库,提升性能。
discover_repository用于验证是否为有效的 Git 仓库,逻辑正确。不过,第 75 行的错误消息较长且直接内联在异常中。虽然这在当前场景下可以接受,但如果需要更好的国际化支持,可以考虑使用
gt()函数。
325-391: 远程同步逻辑全面且正确。该方法处理了所有主要的同步场景:
- HEAD 不存在 → 强制时重置到远程
- 提交相同 → 已是最新
- 可快进 → 快进更新
- 不可快进但强制 → 强制重置
- 不可快进且不强制 → 返回错误
快进检测使用
descendant_of方法正确。日志记录详细,便于调试。第 362 行使用
contextlib.suppress(Exception)捕获所有异常,虽然在此处是为了安全地检查是否可以快进,但建议在注释中说明这样做的原因。
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
uv.lockis excluded by!**/*.lock
📒 Files selected for processing (10)
deploy/OneDragon-Launcher.spec(1 hunks)pyproject.toml(1 hunks)src/one_dragon/base/operation/one_dragon_env_context.py(1 hunks)src/one_dragon/envs/env_config.py(3 hunks)src/one_dragon/envs/git_service.py(1 hunks)src/one_dragon_qt/view/code_interface.py(3 hunks)src/one_dragon_qt/view/installer_interface.py(2 hunks)src/one_dragon_qt/view/setting/setting_env_interface.py(2 hunks)src/one_dragon_qt/view/source_config_interface.py(1 hunks)src/one_dragon_qt/widgets/install_card/git_install_card.py(0 hunks)
💤 Files with no reviewable changes (1)
- src/one_dragon_qt/widgets/install_card/git_install_card.py
🚧 Files skipped from review as they are similar to previous changes (3)
- pyproject.toml
- src/one_dragon_qt/view/source_config_interface.py
- src/one_dragon/base/operation/one_dragon_env_context.py
🧰 Additional context used
🧬 Code graph analysis (4)
src/one_dragon_qt/view/code_interface.py (2)
src/one_dragon_qt/widgets/setting_card/switch_setting_card.py (2)
SwitchSettingCard(15-69)init_with_adapter(58-61)src/one_dragon/base/config/yaml_config.py (1)
get_prop_adapter(87-103)
src/one_dragon/envs/env_config.py (2)
src/one_dragon/base/config/config_item.py (1)
ConfigItem(7-25)src/one_dragon/base/config/yaml_operator.py (3)
get(90-91)update(93-100)save(71-76)
src/one_dragon/envs/git_service.py (4)
src/one_dragon/envs/env_config.py (15)
RepositoryTypeEnum(27-30)git_remote(270-275)git_remote(278-283)repository_type(170-175)repository_type(178-183)is_gh_proxy(150-151)gh_proxy_url(318-323)gh_proxy_url(326-331)is_personal_proxy(146-147)personal_proxy(154-159)personal_proxy(162-167)git_branch(286-291)git_branch(294-299)force_update(186-191)force_update(194-199)src/one_dragon/envs/project_config.py (1)
ProjectConfig(4-25)src/one_dragon/utils/i18_utils.py (1)
gt(50-61)src/one_dragon/utils/os_utils.py (1)
get_work_dir(45-56)
src/one_dragon_qt/view/setting/setting_env_interface.py (3)
src/one_dragon/envs/env_config.py (4)
RepositoryTypeEnum(27-30)ProxyTypeEnum(20-24)PipSourceEnum(40-44)CpythonSourceEnum(58-61)src/one_dragon/envs/git_service.py (1)
update_remote(566-576)src/one_dragon_qt/widgets/setting_card/switch_setting_card.py (1)
SwitchSettingCard(15-69)
🪛 RuboCop (1.81.7)
deploy/OneDragon-Launcher.spec
[warning] 9-9: Useless assignment to variable - hiddenimports.
(Lint/UselessAssignment)
🪛 Ruff (0.14.4)
src/one_dragon_qt/view/code_interface.py
52-52: String contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF001)
src/one_dragon/envs/git_service.py
56-56: Docstring contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF002)
57-57: Docstring contains ambiguous ( (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?
(RUF002)
57-57: Docstring contains ambiguous ) (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?
(RUF002)
58-58: Docstring contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF002)
58-58: Docstring contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF002)
67-67: Docstring contains ambiguous ( (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?
(RUF002)
67-67: Docstring contains ambiguous ) (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?
(RUF002)
75-75: Avoid specifying long messages outside the exception class
(TRY003)
97-97: Comment contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF003)
101-101: Comment contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF003)
106-106: Comment contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF003)
143-143: Docstring contains ambiguous : (FULLWIDTH COLON). Did you mean : (COLON)?
(RUF002)
144-144: Docstring contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF002)
144-144: Docstring contains ambiguous ( (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?
(RUF002)
144-144: Docstring contains ambiguous ) (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?
(RUF002)
145-145: Docstring contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF002)
145-145: Docstring contains ambiguous ( (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?
(RUF002)
145-145: Docstring contains ambiguous ) (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?
(RUF002)
163-163: Comment contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF003)
166-166: Comment contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF003)
172-172: Comment contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF003)
174-174: String contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF001)
180-180: Consider moving this statement to an else block
(TRY300)
181-181: Do not catch blind exception: Exception
(BLE001)
190-190: Docstring contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF002)
201-201: Comment contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF003)
209-209: Consider moving this statement to an else block
(TRY300)
210-210: Do not catch blind exception: Exception
(BLE001)
223-223: Do not catch blind exception: Exception
(BLE001)
239-239: Do not catch blind exception: Exception
(BLE001)
256-256: Do not catch blind exception: Exception
(BLE001)
272-272: Docstring contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF002)
278-278: Do not catch blind exception: Exception
(BLE001)
290-290: Do not catch blind exception: Exception
(BLE001)
308-308: Do not catch blind exception: Exception
(BLE001)
320-320: Consider moving this statement to an else block
(TRY300)
321-321: Do not catch blind exception: Exception
(BLE001)
329-329: Docstring contains ambiguous ( (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?
(RUF002)
329-329: Docstring contains ambiguous ) (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?
(RUF002)
339-339: Comment contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF003)
389-389: String contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF001)
403-403: Do not catch blind exception: Exception
(BLE001)
486-486: Docstring contains ambiguous : (FULLWIDTH COLON). Did you mean : (COLON)?
(RUF002)
486-486: Docstring contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF002)
501-501: Consider moving this statement to an else block
(TRY300)
502-502: Do not catch blind exception: Exception
(BLE001)
539-539: Docstring contains ambiguous ( (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?
(RUF002)
539-539: Docstring contains ambiguous ) (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?
(RUF002)
575-575: Do not catch blind exception: Exception
(BLE001)
592-592: Docstring contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF002)
597-597: Comment contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF003)
604-604: Do not catch blind exception: Exception
(BLE001)
src/one_dragon_qt/view/setting/setting_env_interface.py
74-74: String contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF001)
🔇 Additional comments (25)
src/one_dragon_qt/view/code_interface.py (3)
51-54: 新增自动更新选项实现正确。
auto_update_opt的添加与现有的force_update_opt保持一致的模式,并正确集成到了垂直布局中。
131-131: 适配器初始化正确。
auto_update_opt在界面显示时正确地使用配置适配器进行了初始化,与其他设置卡保持一致。
153-153: 分页计算逻辑优化正确。从
total // page_size + 1改为(total + page_size - 1) // page_size是标准的向上取整除法(ceiling division),可以正确处理边界情况。例如:
- 当
total=10, page_size=10时,旧逻辑返回 2,新逻辑返回 1(正确)- 当
total=11, page_size=10时,两者都返回 2(正确)src/one_dragon_qt/view/setting/setting_env_interface.py (3)
73-76: 自动更新选项集成正确。
auto_update_opt正确替换了git_method_opt,并且已添加到代码组中。这与 PR 目标一致,即从系统 Git 迁移到 pygit2 实现。
70-70: 验证 GitService 的 update_remote() 方法。代码从
update_git_remote()更改为update_remote()。根据相关代码片段,此方法在src/one_dragon/envs/git_service.py中已定义(lines 565-575)。
186-186: 适配器初始化位置正确。
auto_update_opt在on_interface_shown中正确初始化,与其他配置选项保持一致的初始化顺序。src/one_dragon_qt/view/installer_interface.py (3)
484-484: 移除 Git 安装卡正确。
base_install_cards列表中正确移除了self.git_opt,这与 PR 目标一致——内置 pygit2 进行代码管理,不再需要单独安装 Git。
512-512: 安装步骤名称更新正确。步骤名称从
["Git 环境", "代码同步", "环境配置", "安装启动器"]更新为["代码同步", "环境配置", "安装启动器"],正确反映了移除 Git 安装步骤后的流程。
521-534: 安装步骤列表更新正确且一致。
install_steps列表已正确更新:
- 移除了 Git 环境安装步骤
- 保留了代码同步步骤(使用
self.code_opt)- 环境配置步骤(uv、python、venv)
- 启动器安装步骤
步骤列表与
step_names(line 512)保持一致,安装流程简化合理。src/one_dragon/envs/env_config.py (2)
46-49: 实现正确,符合代码规范。新增的
GitRemoteEnum定义与其他枚举类的风格保持一致,用于替代之前的GitMethodEnum,符合本次重构的目标。
269-283: 实现正确,符合代码规范。新增的
git_remote属性实现遵循了文件中其他配置项的模式,提供了完整的 getter 和 setter 方法。src/one_dragon/envs/git_service.py (14)
37-49: 构造函数重构合理。移除了
DownloadService依赖,新增了repo_dir参数用于支持指定仓库目录。路径处理逻辑正确处理了相对路径和绝对路径的情况。初始化时调用_ensure_config_search_path()确保配置隔离,这是一个好的设计。
53-64: 配置隔离策略正确。通过清空 pygit2 的配置搜索路径,成功隔离了用户的系统级和全局级 Git 配置,避免了用户配置(如代理、SSL 证书等)对程序行为的干扰。这是一个关键的设计,能够有效防止环境相关的问题。
80-109: 远程仓库配置逻辑正确。该方法确保了远程仓库配置的正确性:
- 检查远程是否存在
- URL 相同时直接返回
- URL 不同时更新配置
- 不存在时创建新远程
逻辑清晰,处理了所有可能的情况。
111-138: 仓库地址和代理配置获取逻辑正确。
_get_git_repository()方法根据配置正确返回 GitHub 或 Gitee 的仓库地址,并在需要时应用 GH 代理。
_get_proxy_address()方法妥善处理了代理地址的格式化,自动为缺少协议前缀的地址添加http://前缀。
140-183: 远程代码获取逻辑设计合理。该方法实现了智能的深度优化策略:
- 新分支使用
depth=1节省带宽- 已有分支使用
depth=0进行增量拉取- 当增量拉取失败时,自动回退到
depth=1重试这种策略兼顾了性能和可靠性。代理支持也已正确集成。
185-212: 硬重置实现正确且文档完善。该方法支持多种目标格式(OID 对象、提交哈希、分支名、相对引用),并使用
revparse_single正确解析字符串引用。文档清晰说明了支持的格式,便于使用。
214-244: 提交 ID 获取逻辑设计良好。返回值设计清晰:
(local_oid, remote_oid, error_message),当remote_oid为None时表示失败。方法正确处理了 HEAD 不存在的情况,并验证了远程分支的存在性。错误消息国际化处理得当。
246-263: 工作区状态验证逻辑正确。使用
repo.status()检查工作区是否干净,并根据force_update配置决定是否允许继续。返回值结构清晰,错误消息友好。
265-323: 提交遍历器和分支切换逻辑正确。
_get_commit_walker()提供了简洁的提交历史遍历接口。
_checkout_branch()处理了以下场景:
- 本地分支存在:直接切换
- 本地分支不存在但远程存在:从远程创建后切换
- 都不存在:返回错误
使用
CheckoutStrategy.FORCE符合强制更新的语义。
393-474: 克隆和更新流程设计清晰。
_clone_repository()和_fetch_and_checkout_latest_branch()都遵循了清晰的步骤流程:克隆流程:初始化 → 获取远程 → 切换分支 → 同步代码
更新流程:获取远程 → 验证工作区 → 切换分支 → 同步代码
进度回调集成良好,每个步骤都有明确的进度和状态消息。错误处理统一返回
(success, message)元组,便于调用方处理。
478-525: 公共 API 实现正确。这些方法提供了清晰的公共接口:
check_repo_exists():简单可靠地检查仓库是否存在fetch_latest_code():智能路由到克隆或更新流程get_current_branch():安全地获取当前分支名is_current_branch_latest():正确比较本地和远程提交实现逻辑清晰,错误处理得当。
527-590: 提交查询和版本管理 API 实现正确。这些方法提供了完善的提交历史和版本管理功能:
fetch_total_commit():使用 walker 高效统计提交总数fetch_page_commit():实现了分页查询,正确构造GitLog对象reset_to_commit():委托给_reset_hard处理get_current_version():简洁地获取当前版本实现清晰,符合预期功能。
1-32: pygit2 1.19.0 版本验证完成,无安全问题。验证结果确认 pygit2 1.19.0 是有效的 PyPI 版本(发布于 2025-10-23,未被撤销),无已知安全漏洞。代码中的导入语句和 GitLog 数据类定义均正确合理,可安全使用。
591-634: ```shell
#!/bin/bash查看launcher_install_card中的使用场景
rg -n -A5 -B5 "get_latest_tag" src/one_dragon_qt/widgets/install_card/launcher_install_card.py
</blockquote></details> </blockquote></details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
| binaries=[], | ||
| datas=[], | ||
| hiddenimports=[], | ||
| hiddenimports=['_cffi_backend'], |
There was a problem hiding this comment.
🧩 Analysis chain
正确添加了 pygit2 所需的 CFFI 后端依赖。
此更改对于将 pygit2 打包到可执行文件中是必要的。pygit2 依赖 CFFI 来与 libgit2 交互,而 _cffi_backend 模块需要显式添加到 hiddenimports 中,以确保 PyInstaller 将其打包进来。
请验证 pygit2 的所有运行时依赖都已正确打包,特别是 libgit2 共享库文件。
运行以下脚本验证 pygit2 的其他依赖项:
注意:静态分析工具 RuboCop 的警告是误报,因为它是 Ruby 代码检查器,不应分析 Python/PyInstaller 配置文件。
🏁 Script executed:
#!/bin/bash
# 描述:检查 pygit2 的依赖项和 PyInstaller 打包建议
# 搜索项目中 pygit2 的使用,了解需要哪些功能
rg -n --type py "import pygit2|from pygit2" -C 2
# 检查是否有其他 PyInstaller spec 文件配置了 pygit2
fd -e spec -x cat {}Length of output: 2311
🏁 Script executed:
#!/bin/bash
# 描述:检查 OneDragon-Installer spec 文件是否使用 pygit2
# 并检查 sr_installer_app.py 是否导入 pygit2
# 查找 sr_installer_app.py 的位置和内容
fd -type f -name "sr_installer_app.py" -exec head -30 {} \;
# 搜索 sr_installer_app.py 中 pygit2 的导入
rg -n "pygit2" src/sr_od/gui/sr_installer_app.py 2>/dev/null || echo "No pygit2 imports found in sr_installer_app.py"Length of output: 217
🌐 Web query:
PyInstaller pygit2 hidden imports CFFI dependencies
💡 Result:
Short answer — include CFFI and the libgit2 binary when freezing, and add hidden imports for CFFI's runtime.
What to do (concise):
- Ensure libgit2 is available at runtime (binary wheel includes it on many platforms) — if not, bundle the libgit2 shared library with PyInstaller using --add-binary or a hook. (pygit2 docs). [1]
- Add CFFI runtime hidden imports so PyInstaller collects the C extension: at minimum add hiddenimports=['cffi','_cffi_backend']. You can pass --hidden-import=_cffi_backend --hidden-import=cffi or create a hook-pygit2.py that sets hiddenimports accordingly. [2]
- In your hook (or command) also collect pygit2 submodules/data if you use them: use PyInstaller.utils.hooks.collect_submodules('pygit2') and collect_data_files/collect_dynamic_libs for libgit2 if needed. Example hook skeleton:
- from PyInstaller.utils.hooks import collect_submodules, collect_data_files, collect_dynamic_libs
- hiddenimports = collect_submodules('pygit2') + ['cffi','_cffi_backend']
- datas = collect_data_files('pygit2')
- binaries = collect_dynamic_libs('pygit2') # or add libgit2 manually
Then use --additional-hooks-dir or drop hook in PyInstaller hooks dir. [2]
- If libgit2 is installed in a nonstandard location, set LD_LIBRARY_PATH / rpath or add the .so/.dll to binaries so the frozen app can find it (pygit2 run-path notes). [1]
References:
- pygit2 installation / runtime notes (libgit2, cffi). [1]
- PyInstaller hooks guide (hiddenimports, collect_submodules, collect_data_files, collect_dynamic_libs). [2]
hiddenimports 配置不完整,缺少 'cffi' 模块。
根据 PyInstaller 最佳实践,pygit2 的隐藏导入应至少包含 ['cffi', '_cffi_backend'],而当前配置仅包含 ['_cffi_backend']。
建议修改 deploy/OneDragon-Launcher.spec 第 9 行:
hiddenimports=['cffi', '_cffi_backend'],或更完善的做法是创建 PyInstaller 钩子文件,使用 collect_submodules() 和 collect_dynamic_libs() 来自动收集所有 pygit2 依赖项。
🧰 Tools
🪛 RuboCop (1.81.7)
[warning] 9-9: Useless assignment to variable - hiddenimports.
(Lint/UselessAssignment)
🤖 Prompt for AI Agents
In deploy/OneDragon-Launcher.spec around line 9, hiddenimports is missing the
'cffi' module; update the hiddenimports to include both 'cffi' and
'_cffi_backend' (i.e., hiddenimports=['cffi','_cffi_backend']) to ensure pygit2
CFFI bindings are bundled, or alternatively add a PyInstaller hook for pygit2
that uses collect_submodules() and collect_dynamic_libs() to automatically
gather all pygit2 dependencies.
| v_layout.setAlignment(Qt.AlignmentFlag.AlignTop) | ||
|
|
||
| self.auto_update_opt = SwitchSettingCard( | ||
| icon=FluentIcon.SYNC, title='自动更新', content='使用exe启动时,自动检测并更新代码', |
There was a problem hiding this comment.
修复全角逗号。
字符串中使用了全角逗号 ,,应该使用半角逗号 , 以保持一致性。
应用此修改:
- self.auto_update_opt = SwitchSettingCard(
- icon=FluentIcon.SYNC, title='自动更新', content='使用exe启动时,自动检测并更新代码',
- )
+ self.auto_update_opt = SwitchSettingCard(
+ icon=FluentIcon.SYNC, title='自动更新', content='使用exe启动时,自动检测并更新代码',
+ )📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| icon=FluentIcon.SYNC, title='自动更新', content='使用exe启动时,自动检测并更新代码', | |
| self.auto_update_opt = SwitchSettingCard( | |
| icon=FluentIcon.SYNC, title='自动更新', content='使用exe启动时,自动检测并更新代码', | |
| ) |
🧰 Tools
🪛 Ruff (0.14.4)
52-52: String contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF001)
🤖 Prompt for AI Agents
In src/one_dragon_qt/view/code_interface.py around line 52, the string uses a
full-width comma `,`; replace it with a standard ASCII comma `,` so the tuple
becomes: icon=FluentIcon.SYNC, title='自动更新', content='使用exe启动时, 自动检测并更新代码'
(ensure spacing/formatting matches project style).
| icon=FluentIcon.SYNC, title='拉取方式', content='不懂什么是ssh就选https', | ||
| options_enum=GitMethodEnum | ||
| self.auto_update_opt = SwitchSettingCard( | ||
| icon=FluentIcon.SYNC, title='自动更新', content='使用exe启动时,自动检测并更新代码', |
There was a problem hiding this comment.
修复全角逗号。
字符串中使用了全角逗号 ,,应该使用半角逗号 , 以保持一致性。
应用此修改:
- self.auto_update_opt = SwitchSettingCard(
- icon=FluentIcon.SYNC, title='自动更新', content='使用exe启动时,自动检测并更新代码',
- )
+ self.auto_update_opt = SwitchSettingCard(
+ icon=FluentIcon.SYNC, title='自动更新', content='使用exe启动时,自动检测并更新代码',
+ )📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| icon=FluentIcon.SYNC, title='自动更新', content='使用exe启动时,自动检测并更新代码', | |
| self.auto_update_opt = SwitchSettingCard( | |
| icon=FluentIcon.SYNC, title='自动更新', content='使用exe启动时,自动检测并更新代码', | |
| ) |
🧰 Tools
🪛 Ruff (0.14.4)
74-74: String contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF001)
🤖 Prompt for AI Agents
In src/one_dragon_qt/view/setting/setting_env_interface.py around line 74, the
string literal uses a fullwidth comma `,`; replace it with the ASCII halfwidth
comma `,` so the line becomes consistent (use ',' inside the content string
instead of ',').
| @ocr_cache.setter | ||
| def ocr_cache(self, new_value: bool) -> None: | ||
| self.update('ocr_cache', new_value, save=True) No newline at end of file | ||
| self.update('ocr_cache', new_value, save=True) |
There was a problem hiding this comment.
注意参数使用的一致性。
此处显式传递 save=True 参数,但根据 yaml_operator.py 中 update 方法的定义,save 参数默认值已经是 True。同时,本文件中其他所有 setter 方法(如 git_path、proxy_type、git_remote 等)都没有显式传递此参数。
建议保持一致性,要么移除此处的 save=True 参数,要么在所有 setter 中统一显式声明。
如需保持一致,可应用此修改:
- self.update('ocr_cache', new_value, save=True)
+ self.update('ocr_cache', new_value)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| self.update('ocr_cache', new_value, save=True) | |
| self.update('ocr_cache', new_value) |
🤖 Prompt for AI Agents
In src/one_dragon/envs/env_config.py around line 482, the call
self.update('ocr_cache', new_value, save=True) explicitly passes save=True while
other setters in this file omit that parameter and yaml_operator.py's update
defaults save to True; to maintain consistency remove the explicit save=True so
the call becomes self.update('ocr_cache', new_value) (or, if you prefer
explicitness project-wide, add save=True to the other setter calls—but prefer
removing here to match existing setters).
Summary by CodeRabbit
发布说明
新功能
功能移除
优化
依赖