Watchman version 命令完全指南:查询版本号与能力协商(Capability Negotiation)
2026/9/22 11:39:04 网站建设 项目流程
  • 后端
  • 开发工具

【免费下载链接】watchman

Watches files and records, or triggers actions, when they change.

项目地址:https://gitcode.com/gh_mirrors/watchm/watchman
点击查看免费下载

导读

version是 Watchman 中最基础也最容易被低估的命令:它既能查询当前守护进程(daemon)的版本与构建信息,也能在客户端与服务端版本不一致时帮助你快速定位问题。更重要的是,自 Watchman 3.8 起,version命令扩展出"能力协商"(capability negotiation)能力,让客户端不再需要硬编码版本号判断逻辑,而是直接询问服务端"你是否支持某功能"。本文以 version.md 为核心,结合本仓库源码,完整讲解version命令的三种用法、capability 的命名规范与底层实现,以及 Python/Node 客户端中的capabilityCheck封装。

一、查询版本与构建信息

version命令会向当前正在运行的 Watchman 服务(watchman service)查询版本号和构建信息:

$ watchman version { "version": "2.9.6", "buildinfo": "git:2727d9a1e47a4a2229c65cbb2f0c7656cbd96270" }

响应中两个字段的含义:

  • version:服务端版本号,例如2.9.6
  • buildinfo:构建信息,通常是构建对应的 git commit 哈希(git:前缀),可用于精确定位服务端二进制由哪个源码版本编译而来。

从源码实现看,该命令定义于 info.cpp:VersionCommandResponse结构继承自BaseResponse,其中version字段由PACKAGE_VERSION宏在编译期确定,buildinfo则在特定平台构建宏开启时填充。命令注册时声明了CMD_DAEMON | CMD_CLIENT | CMD_ALLOW_ANY_USER标志,意味着它既可以由任何用户执行,也支持直接以客户端模式调用。另外,每一个命令都会通过capability_register()在命令注册的同时登记对应的能力名(见 CommandRegistry.cpp),这正是后文能力协商的根基。

客户端版本:watchman -v

如果不希望连接守护进程,只想查看命令行客户端自身的版本,可以使用:

$ watchman -v 2.9.8

在 Options.cpp 中可以看到-v/--version被定义为OPT_NONE型选项,且标记为NOT_DAEMON(即不启动守护进程);随后 parseOptions() 在检测到该标志时直接打印PACKAGE_VERSION并退出。注意这里打印的是客户端版本,与上面version命令返回的服务端版本可能不同。

服务端与客户端版本不一致怎么办

文档给出了明确建议:如果服务端与客户端版本对不上,大概率是服务端二进制太旧,应当重启服务端使其重新加载:

$ watchman shutdown-server ; watchman

先关闭旧服务端,再启动一个新实例,随后再执行watchman version确认版本已同步。从shutdown-server到重新watchman的完整流程可参考 shutdown-server.md 与 watch.md 的说明。

二、能力协商(Capabilities)

为什么需要 capability

在 Watchman 3.8 之前,客户端要判断服务端是否支持某个功能,只能把"版本号 → 功能"的对应表硬编码进客户端代码。这种做法的弊端很明显:每次 Watchman 新增功能,所有下游客户端都要跟着升级版本判断逻辑。

Capabilities 机制(自 3.8 起)改变了这一局面:客户端只需按功能名称询问服务端是否支持,服务端自行回答 true/false,客户端完全不需要维护版本知识。

能力名的命名规范

为了保持命名统一,capability 名称有严格的约定,详见 capabilities.md:

类别命名规则示例
命令cmd-前缀 + 命令名cmd-watch-project
表达式 termterm-前缀 + term 名term-match
查询字段field-前缀 + 字段名field-size
功能增强手工指定的名字relative_root(3.3)、wildmatch(3.7)、suffix-set(5.0)

从 CommandRegistry.cpp 可以看到,每个命令定义构造时都会调用capability_register(),将能力名存入注册表;capability_supported()则用于运行时查询某个名字是否被支持。

查询可选能力:optional

向服务端发送version命令,并在参数中传入optional列表,即可查询这些能力是否支持:

$ watchman -j <<< '["version", {"optional":["relative_root"]}]' { "version": "3.8.0", "capabilities": { "relative_root": true } }

如果某个能力不被支持,结果中对应值就是false,而不会报错:

$ watchman -j <<< '["version", {"optional":["will-never-exist"]}]' { "version": "3.8.0", "capabilities": { "will-never-exist": false } }

注意这里使用的是watchman -j,即通过 stdin 传入 JSON 请求数组的方式(["version", {...}]是"命令名 + 参数对象"的标准 JSON 请求格式),与直接watchman version的命令行形式等价。

必需能力:required

如果某个能力是客户端必须依赖的,就放入required列表。此时只要有一个必需能力不被支持,服务端就会在响应中附带error字段:

$ watchman -j <<< '["version", {"required":["will-never-exist"]}]' { "version": "3.8.0", "capabilities": { "will-never-exist": false }, "error": "client required capability `will-never-exist` is not supported by this server" }

客户端应当把error字段视为连接/功能失败,从而决定回退策略或直接报错退出。

混合使用 required 与 optional

一个请求中可以同时指定必需能力和可选能力,两者都会出现在capabilities映射中,但只有required中缺失的项会触发error

$ watchman -j <<< '["version", {"required":["term-match"],"optional":["a","b"]}]' { "version": "3.8.0", "capabilities": { "a": false, "b": false, "term-match": true } }

服务端实现剖析

从 info.cpp 的VersionCommand::handle()可以看出完整的处理逻辑:

  1. optionalrequired列表非空,则进入能力检查分支;
  2. optional中的每个名字,调用capability_supported()并把结果写入response.capabilities[capname]
  3. required中的每个名字,同样写入布尔结果,但若返回 false 则收集进missing集合;
  4. missing非空,拼接错误信息client required capabilities [...] not supported by this server写入response.error

capability_supported()的实现(CommandRegistry.cpp)本质是在一个std::unordered_set<std::string>注册表中做查找——注册表由所有CommandDefinition构造时通过capability_register()填充,且注册表预分配了 128 个槽位(见 CommandRegistry.cpp)。此外,还有独立的 list-capabilities 命令,通过capability_get_list()一次性返回服务端支持的全部能力名。

三、客户端封装:capabilityCheck

Node 与 Python 官方客户端都提供了capabilityCheck方法,它在内部封装上述 version 能力协商请求,并额外提供针对旧版服务端的兼容支持——即当服务端版本过老、根本不认识 capabilities 时,客户端可以基于版本号做有限的回退推断,从而实现从"版本号判断"到"能力名判断"的平滑过渡。

Python 客户端

import pywatchman client = pywatchman.client() # will throw an error if any of the required names are not supported res = client.capabilityCheck(optional=['a'], required=['term-match']) print res # {'version': '3.8.0', 'capabilities': {'term-match': True, 'a': False}}

注意:只要有任何必需能力不被支持,capabilityCheck就会抛出异常;optional中的能力缺失则只反映为false,不会抛错。

Python 侧的版本兼容逻辑位于 capabilities.py:其中维护了一张cap_versions字典(如cmd-watch-project3.1relative_root3.3wildmatch3.7),parse_version()x.y.z版本号压扁为整数(每段乘 1000 累加)以便比较;当服务端版本过老时,synthesize()会用这张表"合成"出一个与真实服务端等价的 capabilities 响应,让新版客户端也能对旧服务端做出合理判断。

Node 客户端

var watchman = require('fb-watchman'); var client = new watchman.Client(); client.capabilityCheck({optional:['a'], required:['term-match']}, function (error, resp) { if (error) { // error will be an Error object if any of the required named // are not supported } console.log(resp); // {'version': '3.8.0', 'capabilities': {'term-match': false, 'a': false}} client.end(); });

在 Node 端,回调的第一个参数error会在任何必需能力缺失时被设置为Error对象;第二个参数resp中带有versioncapabilities映射。Node 客户端实现位于 index.js,签名同样接受{optional, required}两个数组;一个典型用法参见 example.js——先用capabilityCheck({required:['relative_root']})确认服务端支持relative_root,再继续后续查询。

何时用 capabilityCheck 而非裸 version

  • 如果你的代码运行在同时代的客户端与服务端上,直接用裸version能力协商即可;
  • 如果你需要同时兼容 3.8 之前的旧服务端,请使用capabilityCheck,它会基于cap_versions表做版本回退推断;
  • 如果你希望错误处理由客户端库统一完成(必需能力缺失直接抛错),capabilityCheck也比手工解析裸响应更省事。

四、实践建议

  1. version写进诊断脚本:服务端与客户端版本不一致是很多诡异行为的根源,先用watchman versionwatchman -v对比两端版本,再决定是否watchman shutdown-server ; watchman重启。
  2. 新代码一律用能力名而非版本号:判断功能可用性时优先查询relative_rootterm-matchsuffix-set等能力名,避免在客户端维护版本对应表。
  3. 必需能力用required,可降级功能用optional:缺失即无法工作的能力放required(让服务端返回 error),可以优雅降级的功能放optional(返回 false 后走备选路径)。
  4. 调试时用list-capabilities:想知道服务端到底支持哪些能力,直接执行 list-capabilities 命令即可拿到完整清单,无需逐一试探。

相关文档

  • capabilities.md:capability 命名规范与完整能力清单
  • list-capabilities.md:列出服务端全部能力
  • shutdown-server.md:关闭服务端(版本不一致时的处理步骤)
  • watchman_cmd.h:命令注册宏与能力注册入口
  • 后端
  • 开发工具

【免费下载链接】watchman

Watches files and records, or triggers actions, when they change.

项目地址:https://gitcode.com/gh_mirrors/watchm/watchman
点击查看免费下载
上一篇:Sumy核心算法揭秘:LSA、LexRank、TextRank技术原理详解
下一篇:G-Helper:让你的华硕笔记本告别臃肿控制软件,重获轻盈体验

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询