ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

EdenFS 文件通配(Globbing)机制解析:Ignore 文件与 globFiles Thrift 接口的完整指南

EdenFS 文件通配(Globbing)机制解析:Ignore 文件与 globFiles Thrift 接口的完整指南 开发工具CLI后端【免费下载链接】saplingA Scalable, User-Friendly Source Control System.项目地址https://gitcode.com/gh_mirrors/sa/sapling点击查看免费下载EdenFSSapling 的虚拟文件系统守护进程在内部提供了两套 glob 能力一是用于getScmStatus状态查询的 ignore 文件匹配二是暴露给客户端如hg status、edenfsctl glob、prefetch 工具的globFilesThrift API。本文以 EdenFS File Globs 文档 为骨架结合 eden.thrift、GlobNodeImpl、ThriftGlobImpl 与 GlobNodeTest 等源码系统讲解 glob 模式的语法语义、编译与匹配的底层实现、Thrift 参数含义、符号链接的特殊行为以及命令行与测试验证方法。EdenFS 中的两类 Glob 接口EdenFS 支持 glob 模式的入口共有两个二者面向的场景不同接口用途典型调用方Ignore 文件如.gitignore在getScmStatusThrift API 中排除文件hg status等状态查询globFilesThrift API显式按模式查询匹配路径edenfsctl glob、prefetchFiles、集成客户端前者用于“告诉 EdenFS 哪些文件不该被报告”后者用于“按模式枚举仓库中的文件/目录”。两条路径共享同一套模式语法EdenFS 的 glob 语法与 Git 版本控制系统的gitignore模式格式兼容即便 EdenFS checkout 底层是 Mercurial 仓库也是如此。从源码看这份兼容性承诺落实在 GlobMatcher.h 的实现注释中GlobMatcher performs matching of filename glob patterns. This aims to be100% compatible with the syntax used in gitignore files.也就是说你在.gitignore里能写的模式在globFiles里同样成立反过来glob 模式中出现的特殊字符在 ignore 文件中语义也一致。Ignore 文件状态查询中的排除规则工作方式与优先级EdenFS 使用 ignore 文件在getScmStatusThrift API例如hg status的底层调用中排除文件。ignore 文件的语法与 Git 的gitignore完全兼容即使 checkout 的仓库类型是 Mercurial。在源码层面单个 ignore 文件的解析与匹配由 GitIgnore.h 中的GitIgnore类承担它返回四种匹配结果enum MatchResult { EXCLUDE, // 该路径被 ignore 规则显式排除 INCLUDE, // 该路径被规则显式包含重新包含 NO_MATCH, // 未命中任何规则可继续向低优先级规则查询 HIDDEN, // 特殊隐藏路径如 .hg、.eden完全不报告 };注释明确指出对于一条完整路径通常需要按“优先级从高到低”依次检查多个GitIgnore对象这一步由GitIgnoreStack完成路径所在目录的.gitignore逐级向上直到仓库根目录的每一层.gitignoreEden 客户端全局 exclude 文件systemIgnoreFile用户个人 exclude 文件userIgnoreFile。每一层都可能返回“显式排除 / 显式包含 / 未命中”一旦命中显式排除或包含就立即停止全部未命中则视为隐式包含。此外还有一个重要规则如果某个目录被 ignore那么它内部的任何内容都被视为已忽略——即使显式 include 规则也不能“重新包含”被忽略目录内的未跟踪文件。EdenFS 守护进程侧通过 ServerState.cpp 维护userIgnoreFileMonitor_与systemIgnoreFileMonitor_两个CachedParsedFileMonitorGitIgnoreFileParser分别跟踪配置项userIgnoreFile与systemIgnoreFile对应的文件文件变化后自动重新解析。一个容易混淆的点需要特别说明ignore 文件只影响getScmStatus这类状态接口的过滤不参与globFiles的结果过滤。edenfsctl glob的帮助文本明确写明了这一点见 glob.rsPrint matching filenames. Glob patterns can be provided via a pattern file.This command does not do any filtering based on source control state or gitignore files.因此glob 结果可能包含被 ignore 的文件这是设计使然不是缺陷。Glob 模式中的特殊字符语义EdenFS 在 glob 模式中按如下规则解释特殊 tokenToken语义**匹配零个、一个或多个路径分量跨目录层级*匹配零个、一个或多个合法的路径分量字符不跨目录分隔符?匹配恰好一个合法的路径分量字符[匹配给定字符集合中的恰好一个路径分量字符集合以]结束[!、[^匹配不在给定字符集合中的恰好一个路径分量字符集合以]结束这些语义与 gitignore 模式一致。注意*与**的关键差别*不能跨越/目录分隔符**则专门用于跨目录的递归匹配。模式编译把模式拆成“节点树”理解这些 token 的最佳方式是看编译过程。 GlobNodeImpl.h 的类注释给出了核心设计将 glob 按路径分量拆分构建一棵“名字匹配操作”的树。对非递归 glob 而言这允许我们高效地边遍历目录树边比较。不含 glob 特殊字符的路径分量可以直接按名字在目录内容中做 ID 查找而不是把模式与每个条目反复做模式匹配。具体实现位于 GlobNodeImpl.cpp 的parse()模式被按/逐段 token 化每段生成一个GlobNodeImpl子节点普通子段进入children_遇到**则进入recursiveChildren_递归匹配会破坏大部分优化因此**之后不再继续 token 化。每个节点有两个关键布尔标志见 GlobNodeImpl.hhasSpecials_该段是否含特殊字符。为false时走精确名字查找分支lookupEntry按路径分量做 hash 查找为true时才遍历目录条目逐一调用GlobMatcher。这就是大目录下dir/sub/file.txt这类“全字面量”模式能保持高性能的原因。isLeaf_该节点是否是模式的最后一个分量叶子决定是否产出匹配结果。大小写与点文件选项编译每个节点时GlobNodeImpl.cppGlobMatcher::create(pattern, options)会按以下逻辑组合选项includeDotfiles true时使用GlobOptions::DEFAULT否则使用GlobOptions::IGNORE_DOTFILES默认忽略点文件大小写不敏感CaseSensitivity::Insensitive时追加GlobOptions::CASE_INSENSITIVE当includeDotfilestrue且模式就是**或*时节点被标记为alwaysMatch_无条件命中跳过匹配器模式编译失败会抛出携带EINVAL的std::system_error给出失败原因。顺带一提GlobMatcher还内置了两道匹配保护失败状态记忆化上限默认 65,536与回溯步数上限默认 100,000防止病态模式拖垮守护进程见 GlobMatcher.h。globFiles Thrift API参数与结果结构globFiles的完整定义位于 eden.thriftGlob globFiles(1: GlobParams params) throws (1: EdenError ex);请求参数结构GlobParamseden.thrift字段如下字段类型说明mountPointPathString挂载点路径globsliststring要执行的 glob 模式列表includeDotfilesbool是否把以.开头的条目纳入匹配prefetchFilesbool若为 true同时预取匹配文件的 blobsuppressFileListbool若为 true不在Glob结果里填充 matchingFiles通常与 prefetchFiles 配合wantDtypebool是否返回每个匹配条目的 dtyperevisionslistThriftRootId要针对哪些提交revision求值为空则只对当前 checkout revision 求值列表中不应有重复项prefetchMetadatabool已无实际效果保留字段searchRootPathStringglob 从哪个目录开始求值默认是仓库根目录backgroundbool若为 true预取在后台执行、不等结果predictiveGloboptional PredictiveFetch已废弃、被守护进程忽略仅保留 wire 兼容listOnlyFilesbool只返回文件、过滤目录注意为 false 时 matchingFiles 并不等同于实际喂给 backing store 的预取列表syncSyncBehavior本次 glob 查询是否同步工作副本返回结构Globeden.thriftstruct Glob { 1: listGlobPathValue matchingFiles; // 可能含重复值且不保证有序 2: listOsDtype dtypes; // 每个匹配条目的文件类型 3: listbinary originHashes; // 匹配文件所属提交的哈希 }matchingFiles可能包含重复值多个模式命中同一文件、不保证有序originHashes目前是匹配文件所属提交的 commit hash若 EdenFS 未来放弃 commit hash则可能改为根树哈希。当传入多个revisions时同一文件可能对应多个 origin hash。内部实现GlobTree 与 GlobNode 两条求值路径globFiles的服务端实现位于 ThriftGlobImpl.cpp它根据是否指定revisions选择两条不同的求值路径指定 revisions → GlobTree基于 tree 元数据当revisions非空时代码对每个 revision 取根树co_getRootTree沿searchRoot解析出子树然后构造GlobTree针对存储层的原始 Tree 元数据求值GlobTree.cpp。这种方式不触碰工作副本 inode可对任意历史提交做只读 glob。测试中的builder_.setAllReady()对应的正是“树已就绪、直接按元数据匹配”的场景。无 revisions → GlobNode基于工作副本 inode当revisions为空时回退到当前 checkout先通过edenMount-co_getInodeSlow(searchRoot, ...)拿到目录 inode再构造GlobNode在工作副本上求值ThriftGlobImpl.cpp。GlobNodeGlobNode.cpp会感知 overlay 中的物化materialized状态——测试 recursiveTxtWithChanges 证明通过 overlay 添加的文件、符号链接以及被chmod物化后的文件都能被正确枚举出来。两种路径共享同一套evaluateImpl/evaluateRecursiveComponentImpl模板GlobNodeImpl.h通过TreeInodePtrRoot加锁遍历 inode 目录与TreeRoot直接遍历存储树两个策略对象统一访问方式。**的递归分量由evaluateRecursiveComponentImpl处理它会先收集所有递归子目录释放目录锁后并发加载子树并利用recursiveAsyncDepth默认 3由配置globRecursiveAsyncDepth控制决定前几层递归是否强制切换到 folly executor 异步执行。并发聚合采用collectAllTryRange而非collectAllRange——注释明确指出后者会在首个失败时向兄弟任务发送协作取消可能导致globResult/prefetchList写入不完整。大小写敏感由配置驱动值得注意GlobNode 路径的匹配大小写并不是硬编码的而是看配置项globUseMountCaseSensitivity见 ThriftGlobImpl.cpp为 true默认启用时→ 使用 mount 的 checkout 配置getCaseSensitive()为 false → 强制大小写敏感CaseSensitivity::Sensitive。结果结构GlobResult每次命中都会生成一条 GlobResult包含name相对路径、dtype条目类型如dtype_t::Regular、dtype_t::Symlink、dtype_t::Dir以及originId该文件所属的 root id。dtype_t::Symlink这一枚举直接支撑了下一节的符号链接行为。与符号链接Symlink相关的行为原文档对符号链接行为的规定如下模式精确命中符号链接本身globFile返回该符号链接自身而不是它的 target作为匹配结果。模式的前缀命中符号链接globFile既不返回该符号链接也不返回其 target更不会解析符号链接去继续匹配模式剩余部分。换句话说符号链接可以被“整体命中”但永远不会被“钻进去”当作目录遍历。测试 recursiveTxtWithChanges 对第一条规定给出了直接证据挂载点中addSymlink(sym.txt, root.txt)之后用**/*.txt匹配期望结果包含GlobResult(sym.txt_relpath, dtype_t::Symlink, kZeroRootId)——返回的正是符号链接自身且 dtype 明确标记为Symlink。第二条规定对应实现中entryIsTree()判定符号链接条目在遍历时不满足“是目录”的条件因此不会被recurseIfNecessary继续下钻也不会触发co_getOrLoadChildTree。这与VirtualInode.cpp中多处对dtype_t::Symlink的显式拒绝如计算 blake3/SHA1 时拒绝符号链接是一致的防御性设计。命令行实战edenfsctl glob 与 prefetchglob 子命令edenfsctl globglob.rs是globFiles的直接 CLI 封装常用参数edenfsctl glob [OPTIONS] PATTERN...--mount-point PATH别名--repo指定挂载点默认取当前目录所属仓库根--pattern-file FILE从文件逐行读取模式-表示从标准输入读取--include-dot-files把以.开头的文件纳入匹配--list-only-files只输出文件、过滤目录--dtype输出每个匹配条目的文件类型如 regular / symlink / directory--revision HASH指定要搜索的 revision可重复使用多 revision 时结果会带 origin hash--list-origin-hash显示匹配文件所属提交的哈希仅当指定多个--revision时才有数据--json以 JSON 格式输出--verbose额外打印匹配文件数、dtypes 数、origin hashes 数。模式参数相对仓库根目录解释底层直接调用glob_files(mount_point, patterns, include_dot_files, ..., want_dtype, search_root, ..., list_only_files)与 Thrift 层的GlobParams一一对应。注意该命令不做基于源码控制状态或 gitignore 的过滤。prefetch 子命令glob 的另一个重要消费方是预取。PrefetchParamseden.thrift同样接收globs、revisions、searchRoot、directoriesOnly只预取树、不取 blob、background、preload/preloadProgress预取完成后继续预热 OS 页缓存等参数。Python 侧的实现位于 prefetch.py它先把 checkout 与模式规范化再调用client.globFiles(globs..., prefetchFiles..., ...)获得待预取文件随后按prefetchBlobBatchSize分批调用store-prefetchBlobs见 ThriftGlobImpl.cpp。在GlobNode::evaluate的签名中可以看到预取与 glob 的伴生关系GlobNode.hfileBlobsToPrefetch与globResult同时传入命中文件时若条目未物化且非目录就把对象 ID 追加到PrefetchList实现“查一次、预取一次”。测试matchFilesByExtensionRecursivelyGlobNodeTest.cpp验证了**/*.txt会同时产出两个匹配与两个待预取对象 ID。测试体系如何验证 glob 行为glob 的核心单元测试集中在 GlobNodeTest.cpp它以参数化测试TEST_P同时覆盖“inode 路径 / 存储树路径”与“是否预取”两种维度。值得留意的用例starTxt/star/starExcludeDot验证*的单层匹配以及includeDotfiles对点文件的开关作用默认排除.eden、.watchmanconfig等点文件starStarExcludeDot、starStarRootExcludeDot、dotDirectoryStarExcludeDot验证**递归匹配与点文件排除的组合行为matchFilesByExtensionRecursively**/*.txt递归命中嵌套目录并给出对应的预取对象 IDrecursiveTxtWithChanges覆盖 overlay 新增文件、符号链接、物化chmod条目的枚举同时验证“物化条目不进入预取列表”只有未物化的dir/sub/b.txt出现在expectIdsmatchGlobDirectoryAndDirectoryChild同时注册dir/*与dir/*/*两条模式验证模式树合并后目录与子目录条目都能正确命中。结合这些用例与上文实现可以总结出 EdenFS glob 的完整行为链模式编译成节点树含**递归分支→ 按hasSpecials_选择精确查找或匹配器扫描 → 命中叶子节点时产出GlobResult并收集预取对象 → 对目录条目排除受限目录与符号链接并发下钻。理解这条链无论是排查hg status的 ignore 过滤、编写edenfsctl glob模式还是评估大规模仓库下的 glob 预取性能都能事半功倍。关键源码路径速查接口定义eden.thriftGlobParams/Glob、eden.thriftglobFiles服务端实现ThriftGlobImpl.cppGlobTree/GlobNode 双路径、searchRoot、suppressFileList、预取分批编译与匹配GlobNodeImpl.h / GlobNodeImpl.cpptoken 化、children_/recursiveChildren_、hasSpecials_ 优化匹配器GlobMatcher.hgitignore 兼容、CASE_INSENSITIVE/IGNORE_DOTFILES、回溯保护Ignore 文件GitIgnore.hEXCLUDE/INCLUDE/NO_MATCH/HIDDEN 与优先级栈工作副本 inode 求值GlobNode.cpp / GlobNode.h存储层 tree 求值GlobTree.cpp结果结构GlobResult.h测试GlobNodeTest.cppCLIglob.rs、common.rs、prefetch.py赞分享开发工具CLI后端【免费下载链接】saplingA Scalable, User-Friendly Source Control System.项目地址https://gitcode.com/gh_mirrors/sa/sapling点击查看免费下载相关推荐xonsh 文件通配Globbing完全指南普通通配、正则通配与 Match 通配实战xonsh 文件通配Globbing完全指南普通通配、正则通配与 Match 通配实战 本文是 xonshPython powered shell官方开发工具ruoyi-ai 完整上手指南从零搭建 AI 对话平台到第一次流式对话ruoyi ai 完整上手指南从零搭建 AI 对话平台到第一次流式对话 自己搭一个 AI 对话平台最耗时间的从来不是接个模型而是模型计费、流式推送、用后端AI 应用大模型RAGApache Flink 文件系统通用配置指南默认文件系统与连接限制机制详解Apache Flink 文件系统通用配置指南默认文件系统与连接限制机制详解 本文是 Apache Flink 文件系统通用配置Common Configu后端大数据流处理批处理上一篇JavaCV开源生态相关库与工具集成指南下一篇dnSpyEx终极调试器插件架构揭秘.NET逆向工程的完整可扩展方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表