Files
AnyImage/openspec/changes/separate-node-sources-and-tools/design.md
nan 198fcbf55b
Some checks failed
Test / test (push) Has been cancelled
Initial public release
2026-09-19 21:31:36 +08:00

6.2 KiB
Raw Blame History

Context

节点组的可维护源码位于 tools/nodes/groups 和 tools/nodes/common,构建入口、布局、校验与预览也位于同一包中。生成后的 src/anyimage/assets/O_AnyImage.blend 被扩展运行时读取并进入发布包,但它同时作为 Git LFS 文件提交,历史中已累积多个 1–10 MB 的版本。

项目通过 blender dependency group 安装 bpy==4.5.3,现有测试也使用该 wheel 创建节点、求值几何及写入 .blend。因此本地和 CI 都不需要额外安装或定位完整 Blender 应用程序。

Goals / Non-Goals

Goals:

  • 根目录 nodes/ 只表达节点组及共用节点构建定义。
  • tools/nodes/ 只表达构建、布局、校验和预览工具。
  • 干净 CI 从源码生成、验证并打包节点资产。
  • 本地与 CI 使用同一个 node-group 执行路径,不需要 .env 或 BLENDER_BIN。
  • Git 当前树不再包含生成的 .blend 或对应 LFS pointer。
  • 节点组的接口、默认值、求值和最终发布包保持不变。

Non-Goals:

  • 不在本变更中重写 Git 历史或清理远程 LFS 对象。
  • 不改变节点组业务名称和实现逻辑。
  • 不把节点资产改为扩展运行时动态创建。
  • 不提供选择其他 Blender 可执行程序或版本的兼容路径。

Decisions

节点定义成为独立顶层包

建立 nodes/ Python package:

nodes/
├── common/
└── groups/

tools/nodes/
├── arrangement/
├── preview/
├── build.py
├── check.py
└── cli.py

nodes/groups 保存各命名节点组定义,nodes/common 保存这些定义共享的节点图构建逻辑。布局属于产物呈现和构建工具,继续位于 tools/nodes/arrangement。旧 tools.nodes.groups 与 tools.nodes.common 路径直接删除,不提供转发模块。

Hatch 的工具 wheel同时包含 tools 和 nodes,确保安装后的 node-group 入口能导入节点定义。相应测试按同一职责拆分:节点行为测试进入 tests/nodes,工具入口、布局、保存资产和校验测试保留在 tests/tools/nodes。

.blend 是构建产物而不是源码

src/anyimage/assets/O_AnyImage.blend 加入 .gitignore 并从 Git 索引移除。源码检出不承诺该文件存在;开发者使用 node-group build 生成它。扩展运行时仍只通过 load_node_group 加载生成资产,不在用户运行时创建节点组。

保留 .gitattributes 的通用 Blender LFS 规则,因为它可能服务其他手工资产;忽略规则确保本生成物不再加入 Git。删除当前文件只影响未来提交,历史容量将在后续仓库历史整理时处理。

node-group 统一使用 bpy wheel

node-group build、check 和 preview 都在 uv run --group blender 提供的 Python 环境中工作。CLI 不再解析 --blender,也不再读取 BLENDER_BIN、项目 .env 或系统 PATH。

为保持构建与保存后检查的进程隔离,CLI 使用 sys.executable -m 顺序启动模块:

node-group build
├── python -m tools.nodes.build
├── python -m tools.nodes.check
└── python -m pytest tests/nodes tests/tools/nodes

check 只运行后两步,preview 使用同一 Python 运行预览导出模块。节点命令只运行与节点定义和工具直接相关的测试;项目常规与 AI 测试由各自命令负责。缺少 bpy 时命令明确提示使用 uv run --group blender node-group ...,不回退到外部 Blender。

相比保留完整 Blender 启动器,这一方案删除了路径发现、.env 解析、wheel 解压和 --python-expr bootstrap,且让本地与 CI 覆盖同一入口。

CI 通过 node-group 构建

测试工作流在 pytest 前执行:

uv run --group blender node-group build --skip-tests

该命令使用 CI 已安装的 bpy==4.5.3,顺序生成并检查资产。随后运行常规测试目录,节点资产测试读取刚生成的文件。

发布工作流采用同样顺序,在测试成功后执行 uv run pack。生成文件留在 job 工作区,由打包器收入扩展压缩包,不作为工作流 artifact 单独传递。

备选方案是在本地或 CI 查找完整 Blender。它下载更大、存在第二套 Python 和依赖 bootstrap,且现有 bpy wheel 已覆盖所需 API,因此删除而不是保留兼容路径。

缺失资产时打包明确失败

打包器在创建任何平台包前检查生成资产存在且为普通文件;缺失时给出先构建节点资产的错误。打包测试既验证缺失失败,也验证每个平台归档包含 assets/O_AnyImage.blend。

这避免生成步骤遗漏后发布一个运行时才报错的不完整扩展。

Risks / Trade-offs

  • [bpy wheel 的资产兼容性发生变化] → 固定 bpy==4.5.3,构建后在独立 Python 进程运行资产检查和现有求值测试。
  • [开发者从源码直接启用扩展时缺少资产] → node-group build 成为源码使用和打包前置步骤,缺失资产由工具给出明确错误。
  • [测试路径重组造成覆盖遗漏] → 沿真实导入路径迁移测试并运行节点构建、常规测试和全量测试。
  • [生成文件被误提交] → .gitignore 固定忽略具体资产路径,并增加版本控制边界测试。
  • [从 Git 删除文件不会立即释放现有远程 LFS 容量] → 本变更只阻止继续增长;后续创建精简根历史时排除旧 LFS 对象。

Migration Plan

  1. 移动节点定义及对应测试,更新全部导入与 wheel 包清单。
  2. 将 node-group 改为通过当前 Python 的独立子进程运行构建、检查和预览,删除完整 Blender 定位与 bootstrap。
  3. 在保留现有资产的情况下构建并验证,确认重组没有改变节点行为。
  4. 为测试和发布工作流加入统一的 node-group 生成步骤,补充缺失资产打包测试。
  5. 将生成资产加入 .gitignore 并从 Git 索引移除。
  6. 从无节点资产的干净状态执行 CI 等价流程,确认最终发布包包含重新生成的资产。

回滚时恢复节点定义路径、工作流和已提交资产即可;Git 历史清理不属于本变更,因此回滚不需要恢复远程历史。

Open Questions

无。