跳到主要内容

trigger

trigger 命令将创建或替换一个触发器。

触发器是针对受监控根目录保存的增量查询。当文件发生更改并与查询表达式匹配时,Watchman 将派生一个进程并将有关已更改文件的信息传递给它。

触发的进程由在后台运行的 Watchman 服务器进程派生;它们无权访问您的终端,并且它们的输出(默认情况下)被重定向到 Watchman 日志文件。

Watchman 会等待文件系统稳定后再处理任何触发器,在调用注册命令之前将已更改的文件列表批量处理。您可以通过 .watchmanconfig 文件调整稳定期。

请注意,已删除的文件被计为已更改的文件,并以与已更改但存在的文件完全相同的方式传递给命令。

Watchman 一次只会运行触发器进程的单个实例。这避免了在触发器也修改文件的情况下出现 fork-bomb 类型的行为。当进程终止时,watchman 将根据上次派生进程时的时间戳重新评估触发器条件;如果生成文件列表,watchman 将派生一个新的子进程,其中包含在此期间更改的文件。

除非使用 no-save-state,否则触发器会被保存并在 Watchman 进程重启后重新建立。如果您在升级到 Watchman 2.9.7 之前保存了触发器,那么在升级到 2.9.7 及更高版本时,这些触发器将被遗忘;您需要重新注册它们。

注册触发器有两种语法:一种简单语法,允许使用一些合理的默认设置进行非常简单的触发器配置,以及自 Watchman 2.9.7 版本以来可用的第二种扩展语法。

简单语法是根据扩展语法实现的,并且为了与旧客户端向后兼容而保留。

扩展语法

自 2.9.7 版本起。

您可以使用下面详述的扩展 JSON 触发器定义语法。它比早期版本提供更多对触发命令的调用方式的控制。

JSON

["trigger", "/path/to/dir", <triggerobj>]

其中 triggerobj 是一个触发器配置对象,其中包含以下定义的字段。

这是一个通过 CLI 指定的示例触发器,每当资产或源文件发生更改时,都会运行 make

$ watchman -j <<-EOT
["trigger", "/path/to/root", {
"name": "assets",
"expression": ["pcre", "\.(js|css|c|cpp)$"],
"command": ["make"]
}]
EOT

可能的触发器对象属性有

  • name 定义触发器的名称。您可以使用此名称稍后删除触发器。使用与现有触发器相同的名称注册不同的触发器将隐式删除旧触发器,然后注册新触发器,从而导致针对整个树评估触发器表达式。

  • command 指定要调用的命令。它必须是字符串值的数组;这将构成触发器进程的 argv 数组。派生触发器时,将使用 Watchman 进程的 $PATH 来定位命令。如果自 Watchman 进程启动以来您已更改了 $PATH,则 Watchman 将无法看到您的新 $PATH。如果您正在注册一个从不寻常或非默认位置运行的触发器,建议您指定该命令的完整路径。如果您正在注册一个可以在受监控根目录中找到的触发器脚本,只需指定相对于根目录的路径即可。

  • append_files 是一个可选的布尔参数;如果启用,则在调用触发器时,command 数组将附加一组匹配的文件名。系统限制(例如 sysconf(_SC_ARG_MAX) 和/或 RLIMIT_STACK)对传递给派生进程的参数和环境的大小设置了上限。Watchman 将尝试通过将文件名参数的数量保持在系统限制以下来确保命令可运行。如果无法将完整集合传递给进程,Watchman 将传递它认为可以容纳的尽可能多的参数,并省略其余的参数。发生此参数列表截断时,Watchman 将导出 WATCHMAN_FILES_OVERFLOW=true 到环境中,以便子进程可以确定是否发生了这种情况。Watchman 无法拆分参数并为每个参数批次运行多个进程;对于该功能,请对 command 使用 xargs(1) 并将 stdin 属性设置为 NAME_PER_LINE

  • expression 接受查询表达式。该表达式应用于已更改文件列表以生成与此触发器相关的文件集。如果没有文件匹配,则不会调用该命令。省略表达式将匹配所有已更改的文件。

  • stdin 指定应如何配置命令调用的标准输入。您可以将此属性的值设置为以下之一

    • 字符串值 /dev/null - 将标准输入设置为从 /dev/null 读取。这是默认值,如果您省略 stdin 属性,将使用此值。

    • 数组值将被解释为字段名称列表。调用该命令时,Watchman 将生成一个 JSON 对象数组,其中包含标准输入上的这些字段名称。例如,如果 stdin 设置为 ["name", "size"],则标准输入将是一个 JSON 数组,其中包含已更改文件的列表,表示为具有 namesize 属性的对象:[{"name": "filename.txt", "size": 123}]。有效字段的列表与 query 命令中记录的列表相同。与 query 命令一样,如果字段列表由单个字段组成,则 JSON 将是这些字段值的数组。例如,如果将 stdin 设置为 ["name"],则 JSON 的格式将是 ["filename.txt"] 而不是 [{"name": "filename.txt"}]

    • 字符串值 NAME_PER_LINE 将导致 Watchman 在标准输入上生成文件名列表,每行一个名称。不会对名称应用任何引号,并且它们可能包含空格。

  • stdoutstderr 控制输出流和错误流。如果省略,则相应的流将从 Watchman 进程继承,这通常意味着命令输出/错误流将显示在 Watchman 日志文件中。如果指定,则该值必须是一个字符串

    • >path/to/file - 导致输出重定向到指定的文件。该路径相对于受监控的根目录,如果文件存在,则会在写入之前截断该文件,如果文件不存在,则会创建该文件。

    • >>path/to/file - 导致输出重定向到指定的文件。该路径相对于受监控的根目录。如果文件已经存在,则会附加到该文件。如果文件不存在,则会创建该文件。

  • max_files_stdin 指定在 stdin 设置为保存匹配文件集时,标准输入上报告的文件数量限制。如果匹配的文件数量超过此限制,则输入将被截断以匹配此限制,并且 WATCHMAN_FILES_OVERFLOW=true 也会导出到环境中。如果省略,则默认为无限制。

  • chdir 可用于指定应在派生进程之前设置的工作目录。默认是将工作目录设置为受监控的根目录。此属性的值是一个字符串,将相对于受监控的根目录进行解释。请注意,更改工作目录不会导致重写查询结果中的文件名:它们将始终相对于受监控的根目录。根目录的路径可以在 $WATCHMAN_ROOT 环境变量中找到。

简单语法

与基于 JSON 的扩展语法相比,简单语法更容易从 CLI 执行,但不允许设置所有触发器选项。它仅支持用于查询的简单模式语法

从命令行

$ watchman -- trigger /path/to/dir triggername [patterns] -- [cmd]

请注意,第一个 -- 是为了区分 watchman CLI 开关与第二个 --,后者将模式与触发器命令分隔开。仅在使用 CLI 时才需要这样做,而在使用 JSON 协议时则不需要。

JSON

["trigger", "/path/to/dir", "triggername", <patterns>, "--", <cmd>]

例如

$ watchman -- trigger ~/www jsfiles '*.js' -- ls -l

请注意 *.js 周围的单引号;如果您省略它们,您的 shell 会将其扩展为文件名列表并在触发器中注册这些名称。虽然这有效,但您在注册触发器后添加的任何 *.js 文件都不会导致触发器运行。

或在 JSON 中

["trigger", "/home/wez/www", "jsfiles", "*.js", "--", "ls", "-l"]

简单语法被解释为具有以下设置的触发器对象

  • name 设置为 triggername
  • command 设置为 <cmd> 列表
  • expression 使用简单模式语法中规定的规则从 <patterns> 列表生成
  • append_files 设置为 true
  • stdin 设置为 ["name", "exists", "new", "size", "mode"]
  • stdoutstderr 将设置为输出到 Watchman 日志文件
  • max_files_stdin 将保持未设置

对于这个简单的示例,如果 ~/www/scripts/foo.js 发生更改,watchman 将 chdir 到 ~/www,然后调用 ls -l scripts/foo.js。请注意,输出将显示在 Watchman 日志文件中,而不是您的终端中。

触发器命令的环境

自 Watchman 2.9.7 版本起,为所有触发器命令设置以下环境变量,即使是使用简单触发器语法注册的命令也是如此

  • 如果文件数量超过 max_files_stdin 限制或系统参数大小限制,则 WATCHMAN_FILES_OVERFLOW 设置为 true
  • WATCHMAN_CLOCK 设置为触发器调用时的当前时钟。
  • WATCHMAN_SINCE 设置为先前触发器调用的时钟值;如果这是第一次触发器调用,则不设置。
  • WATCHMAN_ROOT 设置为被监视根目录的路径。
  • WATCHMAN_TRIGGER 设置为触发器的名称。
  • WATCHMAN_SOCK 设置为 Watchman 套接字的路径,以便您可以找到如何连接回 Watchman。

相对根目录

自 3.4 起。

Watchman 支持选择性地相对于被监视根目录中的路径评估触发器。这与 relative_root 参数一起使用。

["trigger", "/path/to/watched/root", {
"name": "relative-assets",
"expression": ["pcre", "\.(js|css|c|cpp)$"],
"command": ["make"],
"relative_root": "project1"
}]

设置相对根目录会导致以下对触发器的修改:

  • 查询是相对于相对根目录进行评估的。 有关更多信息,请参阅文件查询
  • 触发进程的当前目录设置为相对根目录,除非使用 chdir 更改。如果 chdir 是相对路径,那么它将相对于相对根目录进行评估。因此,对于上面的示例触发器,如果 chdir"subdir2",则触发的 make 调用的当前目录是 /path/to/watched/root/project1/subdir2
  • 在环境变量中,WATCHMAN_ROOT 仍然设置为实际根目录。
  • WATCHMAN_RELATIVE_ROOT 设置为相对根目录的完整路径。

相对根目录的行为类似于在子目录上单独进行的 Watchman 监视,而不会产生任何系统开销。 这对于大型存储库很有用,在这些存储库中,您的脚本或工具只对存储库中的特定目录感兴趣。