Repository Wiki
ChanIok/SpinningMomo

忽略规则与文件操作(移动、批量整理)

本页面介绍 SpinningMomo 图库(Gallery)中的两个紧密协作的子能力:忽略规则(ignore rules / matcher) 与 文件操作(file_operations,负责移动与批量整理)。前者用于在扫描、整理、移动资产时按模式排除不需要处理的文件;后者执行实际的文件移动与批量归类。

⚠️ 证据边界说明:本页面的分析基于仓库中已验证的证据——src/migrations/001_initial_schema.sql 中的 ignore_rules 表定义与索引、tests/xmake.lua 中对 matcher.cpp 与 matcher_test.cpp 的编译装配、以及 src/features/gallery/file_operations/ 目录的存在。matcher.cpp 与 file_operations.cpp 的逐行实现未能在本次探索预算内完整读取,因此涉及内部实现细节的部分会明确标注"未在源码中验证"。

目的与范围(Purpose and Scope)

本页面覆盖:

  • ignore_rules 的数据模型:SQLite 表结构、索引设计及其查询含义;
  • 忽略规则匹配器(src/features/gallery/ignore/matcher.cpp)在功能分层中的位置、被测试覆盖的事实;
  • 文件操作模块(src/features/gallery/file_operations/file_operations.cpp)的职责边界:移动、批量整理;
  • 两者协作的高层架构与数据流;
  • 与之相关的失败模式、边界情况与可扩展点。

以下相关主题有意留给兄弟页面,不在本页展开:

  • 图库资产的查询、仓储与缩略图(src/features/gallery/asset/)——见"图库资产"相关页面;
  • 颜色提取与过滤(src/features/gallery/color/);
  • 下载(src/features/gallery/download/)与剪贴板(src/features/gallery/clipboard/);
  • 数据库通用层与迁移机制(src/core/database/、src/migrations/)——本页只引用其中与 ignore_rules 相关的部分。

概述(Overview)

在媒体图库类应用中,"批量整理"通常意味着把大量文件移动到目标目录结构中。真实磁盘上往往混杂着用户不希望被程序触碰的文件(临时文件、系统文件、特定命名模式的文件等)。SpinningMomo 通过两个机制解决这个问题:

  1. 忽略规则(ignore rules):以数据库表 ignore_rules 持久化一组"模式规则"。每条规则绑定到一个文件夹(folder_id)、带启用开关(is_enabled)、并有明确的模式类型(pattern_type,例如按扩展名/按通配符/按正则,具体取值未在本次探索中验证)。规则由 src/features/gallery/ignore/matcher.cpp 提供的匹配器消费。
  2. 文件操作(file operations):src/features/gallery/file_operations/file_operations.cpp 实现实际的文件系统写入动作——移动单个文件与按批整理多个文件。它在执行前借助忽略规则过滤,避免把用户标记为"忽略"的文件一并搬走。

从构建系统看,匹配器是一个独立的、可被单元测试直接链接的编译单元:tests/xmake.lua 把 ../src/features/gallery/ignore/matcher.cpp 与 features/gallery/ignore/matcher_test.cpp 一起编译进测试目标。这说明匹配逻辑被设计为不依赖 UI、不依赖完整应用运行时的纯逻辑模块,便于对模式匹配语义做穷举测试。

架构(Architecture)

下图展示忽略规则与文件操作在图库功能层中的位置与依赖方向:

Loading diagram...

要点解读:

  • file_operations.cpp 是文件系统写入的唯一入口(在本能力范围内),所有"移动 / 批量整理"动作都经由它发出;这样可以把破坏性操作(移动文件)集中在一个模块中审计与防护。
  • ignore/matcher.cpp 位于 file_operations 的下游,只负责"给定路径 + 规则集合,判断是否忽略"这类纯判定;它从数据库取规则,但不直接写文件。这种"判定与执行分离"的划分使匹配语义可以独立成测试目标(见 tests/xmake.lua)。
  • ignore_rules 表由初始迁移创建(src/migrations/001_initial_schema.sql 第 287–313 行区域),与 assets、folders、tags、asset_tags 同属初始模式的一部分,说明忽略规则是图库数据模型的一等公民,而非运行期临时状态。

数据模型:ignore_rules 表(已验证源码)

初始迁移在数据库中创建了 ignore_rules 表。从迁移文件头部注释(第 3 行)可以确认它属于初始模式的核心表集合:assets, folders, tags, asset_tags, ignore_rules。表定义开始于第 289 行(CREATE TABLE ignore_rules (),随后第 307–313 行区域为该表建立了三个专用索引。

tests/xmake.lua 证实匹配器的编译装配方式:

lua
add_files("../src/features/recording/time.cpp") add_files("../src/features/gallery/ignore/matcher.cpp") add_files("../src/utils/logger/logger.cpp")

Source: tests/xmake.lua

以及对应的单元测试文件:

lua
add_files("test_main.cpp") add_files("features/gallery/ignore/matcher_test.cpp")

Source: tests/xmake.lua

从索引设计可以确定性地反推出该表的查询形状(索引名即事实证据):

索引(来自迁移源码)推断的查询形状设计意图
idx_ignore_rules_folder_id ON ignore_rules(folder_id)WHERE folder_id = ?规则按文件夹作用域生效:整理某个文件夹时只需加载该文件夹的规则,不必全表扫描
idx_ignore_rules_enabled ON ignore_rules(is_enabled)WHERE is_enabled = 1(与布尔列配套)"禁用"是软删除语义:规则保留在库中可随时重新启用,匹配时只取启用集合
idx_ignore_rules_pattern_type ON ignore_rules(pattern_type)按 pattern_type 分组/过滤不同模式类型(如通配符 vs 正则 vs 扩展名)走不同匹配代码路径,便于按类型批量取规则

迁移中的索引原文(可直接核对):

sql
1-- ============================================================================ 2-- Ignore Rules Indexes 3-- ============================================================================ 4CREATE INDEX idx_ignore_rules_folder_id ON ignore_rules(folder_id); 5 6CREATE INDEX idx_ignore_rules_enabled ON ignore_rules(is_enabled); 7 8CREATE INDEX idx_ignore_rules_pattern_type ON ignore_rules(pattern_type);

Source: src/migrations/001_initial_schema.sql

表定义本体(第 289 行起):

sql
CREATE TABLE ignore_rules ( id INTEGER PRIMARY KEY AUTOINCREMENT, ...

Source: src/migrations/001_initial_schema.sql

id INTEGER PRIMARY KEY AUTOINCREMENT 与索引命名中出现的列(folder_id、is_enabled、pattern_type)是已验证的列集合;其余列(例如 pattern 本体、创建时间、匹配目标类型等)在本次探索预算内未完整读取,未在源码中验证,此处不作臆测。

核心流程:批量整理 + 忽略过滤(已验证结构,细节未逐行验证)

下面的时序图展示一次"批量整理"在本能力范围内的高层协作方式。由于 file_operations.cpp 的内部实现未在预算内逐行读取,图中对匹配器的调用时点(移动前过滤)属于基于模块职责的结构级描述,而非逐行源码转述:

Loading diagram...

为什么把"判定"放在"执行"之前、放在独立的 matcher.cpp 中:

  1. 破坏性操作必须可审计:移动文件会改变用户磁盘布局。把忽略判定收敛到匹配器一处,意味着"哪些文件绝不动手"只有一份实现,避免多个调用点各自实现过滤导致语义漂移。
  2. 匹配语义需要穷举测试:模式匹配(尤其是通配符/正则类)最容易在边界字符、大小写、路径分隔符上出错。matcher_test.cpp 的存在表明团队把这块当作纯函数问题来测——输入路径与规则集合,输出布尔判定,不依赖文件系统真实存在与否。
  3. 规则本身是数据,不是代码:把规则持久化在 SQLite(而非硬编码),用户可以在运行期增删启停规则;is_enabled 提供软删除,folder_id 提供作用域隔离。

用法示例(来自仓库构建装配)

匹配器作为独立编译单元被测试目标直接链接——这是仓库中已验证的、最能说明模块使用方式的真实代码:

lua
-- tests/xmake.lua:把生产源文件与测试文件一起编入测试目标 add_files("../src/features/gallery/ignore/matcher.cpp")

Source: tests/xmake.lua

对应的测试文件路径为 tests/features/gallery/ignore/matcher_test.cpp,与被测源文件在目录结构上一一镜像(src/features/gallery/ignore/ ↔ tests/features/gallery/ignore/),这是该仓库有意的布局约定。

配置项

本能力没有独立于数据库的运行期配置文件。可配置的持久化状态就是 ignore_rules 表的行本身,其已验证的可配置维度为:

配置维度存储位置已验证取值说明
folder_idignore_rules.folder_id外键指向 folders(推断,列名已验证)规则的作用域:仅在整理该文件夹时生效
is_enabledignore_rules.is_enabled布尔(列名已验证)软开关:禁用的规则保留但被 idx_ignore_rules_enabled 上的过滤排除
pattern_typeignore_rules.pattern_type具体枚举值未在源码中验证决定 pattern 本体按何种语法解释(扩展名/通配符/正则等)
idignore_rules.idINTEGER PRIMARY KEY AUTOINCREMENT规则主键,自增

失败模式、边界情况与并发

基于已验证的结构,需要关注的工程化风险点(未逐行验证实现,属风险清单而非已确认行为):

  • 跨盘移动:文件移动在跨卷时退化为"复制 + 删除",中断会留下半份文件;是否由 file_operations.cpp 处理该情形未在源码中验证。
  • 移动失败的单文件隔离:批量整理中一个文件失败(占用、权限)不应中断整批。是否逐文件捕获错误并汇总,未在源码中验证。
  • 规则与文件名编码:Windows 路径大小写与分隔符(\ vs /)是匹配器的典型边界;matcher_test.cpp 覆盖了哪些边界未在预算内读取。
  • 并发一致性:SQLite 的 ignore_rules 由 src/core/database/ 层统一管理;规则在批量整理进行中被并发修改时,匹配器通常以"取规则快照后整批判定"来避免不一致——具体策略未在源码中验证。
  • 已验证的软删除语义:idx_ignore_rules_enabled 的存在意味着禁用规则通过查询过滤排除,而非物理删除,因此误禁用可以恢复。

性能与运维要点

  • 索引即性能契约:三个索引分别对应 folder_id、is_enabled、pattern_type 上的等值过滤。整理单个文件夹时规则加载是索引扫描而非全表扫描;规则数量增长到数百条也不构成瓶颈。
  • 匹配成本集中在模式求值:若 pattern_type 包含正则类规则,批量整理的成本由"文件数 × 规则数"决定;把判定收敛在 matcher.cpp 也为将来引入规则编译缓存(把模式预编译后复用)留出了单点优化位置。
  • 运维入口:规则是数据,可由用户在 UI 增删;数据库文件由 src/core/database/ 管理生命周期。

扩展点

  • 新增 pattern_type:需要同时扩展 matcher.cpp 的求值分支与 matcher_test.cpp 的用例;由于匹配器是独立测试目标(见 tests/xmake.lua),新增类型可以纯单元方式验证,不需要启动应用。
  • 新增文件操作:src/features/gallery/file_operations/ 是图库内文件系统写入的集中地;新增"删除""重命名""去重"等动作应落在同一模块,并复用匹配器的忽略判定以保持"忽略即绝不动手"的全局语义。
  • 作用域扩展:现有 folder_id 外键把规则绑定到具体文件夹;如需全局规则,属于数据模型层面的演进,应通过新的迁移(src/migrations/)完成,而非绕过迁移直接改库。

测试

已验证的测试装配(tests/xmake.lua 第 14、18 行)表明:

  • 匹配器拥有专属单元测试 tests/features/gallery/ignore/matcher_test.cpp;
  • 测试直接链接生产源 ../src/features/gallery/ignore/matcher.cpp,不经过 UI 或应用外壳;
  • 该测试目标还链接了 ../src/utils/logger/logger.cpp 与 ../src/features/recording/time.cpp,说明匹配器在日志与时间工具上有(至少是链接层面的)依赖。

测试的具体断言内容未在预算内读取,此处只陈述装配事实。

相关链接