brew livecheckbrew livecheck 命令通过检查上游来查找公式或 cask 软件的最新版本。Livecheck 具有 策略,可从各种来源(如 Git 存储库、网站等)识别版本。
当 livecheck 未收到有关如何检查上游版本的说明时,它默认执行以下操作
stable、head 和 homepage URL(资源仅使用其 url)。对于 cask:按该顺序收集 url 和 homepage URL。有时有必要覆盖此默认行为以创建有效检查。如果某个来源未提供最新版本,我们需要检查其他来源。如果 livecheck 未正确匹配版本文本,我们需要提供适当的正则表达式或 strategy 块。
可以通过向公式/cask/资源添加 livecheck 块来实现此目的。有关可用方法的更多信息,请参阅 Livecheck 类文档。
使用调试输出了解情况。 brew livecheck --debug <formula>|<cask> 提供有关 livecheck 尝试的 URL、适用的任何策略、匹配的版本等信息。
研究可用的来源以选择一个 URL。尝试从 stable/url 中移除文件名,看看它是否提供目录列表页面。如果不起作用,请尝试查找链接到该文件的页面(例如下载页面)。如果无法在网站上找到最新版本,请尝试检查公式/cask 中的其他来源。必要时,在公式/cask 外部搜索其他来源。
必要时创建正则表达式。如果检查在没有正则表达式的情况下也能正常工作,并且没有正则表达式可以受益,通常可以省略它。有关创建正则表达式的更多信息,请参阅 正则表达式指南 部分。
仅在必要时使用 strategy。例如,如果 livecheck 已经对 URL 使用 Git 策略,则无需使用 strategy :git。但是,如果 Git 适用于 URL,但我们需要使用 PageMatch,则需要指定 strategy :page_match。
仅在必要且正确时使用 GithubLatest 和 GithubReleases 策略。GitHub 速率限制 API 请求,因此我们仅在 Git 不够或不合适时使用这些策略。仅当上游存储库具有适合版本的“最新”版本,并且公式/cask 使用发布资产或 Git 策略无法正确识别最新发布版本时,才应使用 GithubLatest。仅当上游存储库使用发布版本并且 Git 和 GithubLatest 策略都不合适时,才应使用 GithubReleases。
livecheck 块中需要一个 url。它可以是 URL 字符串(例如 "https://www.example.com/downloads/")或公式/cask URL 符号(即 :stable、:url、:head、:homepage)。此规则的例外情况是仅使用 skip 的 livecheck 块。
尽可能在与稳定存档相同的位置检查版本.
尽可能避免检查分页的发布页面。例如,我们通常避免检查 GitHub 项目的 release 页面,因为预发布版本可能会将最新稳定版本推到第一页之外。在这种情况下,使用 Git 策略更可靠,它会获取存储库中的所有标签。
livecheck 块正则表达式将匹配限制为获取内容的子集,并在版本文本周围使用捕获组。
尽可能通过在末尾添加 i 来使正则表达式不区分大小写(例如 /.../i 或 %r{...}i)。这样可以提高可靠性,因为正则表达式将处理字母大小写的更改,而无需修改。
正则表达式应仅在版本文本周围使用捕获组。例如,在 /href=.*?example-v?(\d+(?:\.\d+)+)(?:-src)?\.t/i 中,我们仅在版本测试周围使用捕获组(匹配 1.2、1.2.3 等版本),并在其他地方使用非捕获组(例如 (?:-src)?)。
限定范围,固定正则表达式的开头/结尾。例如,在 HTML 页面上,我们经常在 href 属性 URL 中匹配文件名或版本目录(例如 /href=.*?example[._-]v?(\d+(?:\.\d+)+)\.zip/i)。其总体思路是,限制范围将有助于排除不需要的匹配。
避免使用 .* 或 .+ 等通用通配符,而应使用非贪婪和/或在上下文中适当的内容。例如,要匹配 HTML 属性边界内的字符,请使用 [^"' >]+?。
在文件名中的软件名称和版本之间的句点/下划线/连字符处使用 [._-]。对于名为 example-1.2.3.tar.gz 的文件,如果上游文件名格式更改为 example_1.2.3.tar.gz 或 example.1.2.3.tar.gz,example[._-]v?(\d+(?:\.\d+)+)\.t 将继续匹配。
使用 \.t 替换 \.tgz、\.tar\.gz 等。 tarball 有各种不同的文件扩展名(例如 .tar.bz2、tbz2、.tar.gz、.tgz、.tar.xz、.txz 等),而上游源可能会随着时间从一种压缩格式切换到另一种格式。 \.t 通过匹配以 t 开头的当前和未来格式来避免此问题。在 tarball 之外,我们在正则表达式中使用完整的文件扩展名,如 \.zip、\.jar 等。
livecheck 块以下示例涵盖了你可能遇到的许多模式。这些示例旨在成为具有代表性的示例,并且可以轻松改编。
如有疑问,请从以下示例之一开始,而不是从随机公式/cask 中复制粘贴 livecheck 块。
当从 HTML 页面上的文件名匹配版本时,我们通常将匹配限制为 href 属性。 href=.*? 将匹配开始定界符("、')以及文件名之前 URL 的任何部分。
livecheck do
url "https://www.example.com/downloads/"
regex(/href=.*?example[._-]v?(\d+(?:\.\d+)+)\.t/i)
end
我们有时会更明确地排除不需要的匹配。具有前导路径的 URL 可以使用 href=.*?/,而其他 URL 可以使用 href=["']?。例如,当页面还包含具有较长前缀(another-example-1.2.tar.gz)的不需要文件时,这是必需的。
当检查目录列表页面时,有时文件会分隔到版本目录中(例如 1.2.3/)。在这种情况下,我们必须从目录名称中识别版本。
livecheck do
url "https://www.example.com/releases/example/"
regex(%r{href=["']?v?(\d+(?:\.\d+)+)/?["' >]}i)
end
当 stable URL 使用 Git 策略时,以下示例将仅匹配 1.2/v1.2 等标签。
livecheck do
url :stable
regex(/^v?(\d+(?:\.\d+)+)$/i)
end
如果标签包含软件名称作为前缀(例如 example-1.2.3),则可以轻松地相应地修改正则表达式:/^example[._-]v?(\d+(?:\.\d+)+)$/i
配方/cask 可以通过使用 formula 或 cask 来使用与其他配方/cask 相同的检查。
livecheck do
formula "another-formula"
end
引用的配方/cask 应位于同一 tap 中,因为如果用户尚未点击引用自其他 tap 的配方/cask,则会生成错误。
strategy 块如果需要处理上游版本格式以匹配配方/cask 格式,则可以使用 strategy 块来代替 regex。
PageMatch strategy 块这是一个基本示例,从页面中提取简单版本
livecheck do
url "https://example.org/my-app/download"
regex(%r{href=.*?/MyApp-(\d+(?:\.\d+)*)\.zip}i)
strategy :page_match
end
可以通过指定块来处理更复杂的版本。
livecheck do
url "https://example.org/my-app/download"
regex(%r{href=.*?/(\d+)/MyApp-(\d+(?:\.\d+)*)\.zip}i)
strategy :page_match do |page, regex|
match = page.match(regex)
next if match.blank?
"#{match[2]},#{match[1]}"
end
end
在下面的示例中,我们正在扫描主页内容以查找类似于 2020-01-01 的日期格式并将其转换为 20200101。
livecheck do
url :homepage
strategy :page_match do |page|
page.scan(/href=.*?example[._-]v?(\d{4}-\d{2}-\d{2})\.t/i)
.map { |match| match&.first&.gsub(/\D/, "") }
end
end
此处看到的 PageMatch strategy 块样式也适用于任何在内部使用 PageMatch 的特定于站点的策略。
HeaderMatch strategy 块用于 HeaderMatch 的 strategy 块将尝试从文件名(在 Content-Disposition 头中)和最终 URL(在 Location 头中)解析版本。如果不起作用,则可以指定 regex。
livecheck do
url "https://example.org/my-app/download/latest"
regex(/MyApp-(\d+(?:\.\d+)*)\.zip/i)
strategy :header_match
end
如果版本取决于多个头字段,则可以指定块。
livecheck do
url "https://example.org/my-app/download/latest"
strategy :header_match do |headers|
v = headers["content-disposition"][/MyApp-(\d+(?:\.\d+)*)\.zip/i, 1]
id = headers["location"][%r{/(\d+)/download$}i, 1]
next if v.blank? || id.blank?
"#{v},#{id}"
end
end
Git strategy 块用于 Git 的 strategy 块有点不同,因为该块接收标签字符串数组而不是页面内容字符串。类似于 PageMatch 示例,这会将类似于 2020-01-01 的日期格式的标签转换为 20200101。
livecheck do
url :stable
strategy :git do |tags|
tags.map { |tag| tag[/^(\d{4}-\d{2}-\d{2})$/i, 1]&.gsub(/\D/, "") }.compact
end
end
GithubLatest strategy 块用于 GithubLatest 的 strategy 块接收来自 GitHub API 的解析 JSON 数据,用于存储库的“最新”版本,以及正则表达式。当在 livecheck 块中未提供正则表达式时,策略的默认正则表达式将传递到 strategy 块中。
默认情况下,此策略匹配版本文本中的发行版标签或标题,但可以使用 strategy 块来检查发行版 JSON 中的任何字段。以下 strategy 块中的逻辑类似于默认行为,但仅检查发行版标签,以进行演示
livecheck do
url :stable
regex(/^example[._-]v?(\d+(?:\.\d+)+)$/i)
strategy :github_latest do |json, regex|
match = json["tag_name"]&.match(regex)
next if match.blank?
match[1]
end
end
您可以在相关的 GitHub REST API 文档 中找到有关此 API 端点响应 JSON 的更多信息。
GithubReleases strategy 块针对 GithubReleases 的 strategy 块接收来自 GitHub API 的已解析 JSON 数据,其中包含存储库的最新发行版以及正则表达式。如果在 livecheck 块中未提供正则表达式,则会将策略的默认正则表达式传递到 strategy 块中。
默认情况下,此策略匹配每个发行版标签或标题中的版本文本,但可以使用 strategy 块来检查发行版 JSON 中的任何字段。以下 strategy 块中的逻辑类似于默认行为,但仅检查发行版标签,以进行演示
livecheck do
url :stable
regex(/^example[._-]v?(\d+(?:\.\d+)+)$/i)
strategy :github_releases do |json, regex|
json.map do |release|
next if release["draft"] || release["prerelease"]
match = release["tag_name"]&.match(regex)
next if match.blank?
match[1]
end
end
end
您可以在相关的 GitHub REST API 文档 中找到有关此 API 端点响应 JSON 的更多信息。
Crate strategy 块针对 Crate 的 strategy 块接收来自注册表 API 的 versions 端点的已解析 JSON 数据以及提供的或默认的策略正则表达式。默认情况下,该策略使用以下逻辑,因此此 strategy 块可能是修改后方法的一个良好起点
livecheck do
url :stable
strategy :crate do |json, regex|
json["versions"]&.map do |version|
next if version["yanked"]
next unless (match = version["num"]&.match(regex))
match[1]
end
end
end
ElectronBuilder strategy 块针对 ElectronBuilder 的 strategy 块获取 URL 中的内容,并将其解析为 YAML 格式的 electron-builder appcast。它用于使用 Electron 框架构建的 macOS 应用程序的 cask。
livecheck do
url "https://example.org/my-app/latest-mac.yml"
strategy :electron_builder
end
Json strategy 块strategy 块用于 Json 接收已解析的 JSON 数据,如果提供,则接收正则表达式。例如,如果我们有一个包含一个对象数组的对象,其中包含一个 version 字符串,我们可以仅选择与正则表达式匹配的成员,并隔离相关的版本文本,如下所示
livecheck do
url "https://www.example.com/example.json"
regex(/^v?(\d+(?:\.\d+)+)$/i)
strategy :json do |json, regex|
json["versions"].select { |item| item["version"]&.match?(regex) }
.map { |item| item["version"][regex, 1] }
end
end
Sparkle strategy 块strategy 块用于 Sparkle 接收一个 item,该 item 具有 version、short_version、nice_version、url、channel 和 title 的方法。它期望一个 XML feed 的 URL,该 URL 向使用 Sparkle 框架进行自我更新的 macOS 应用程序提供发行信息。此 URL 可以在应用程序包中找到,作为 Contents/Info.plist 中的 SUFeedURL 属性,或使用 find-appcast 脚本。使用以下命令运行它
"$(brew --repository homebrew/cask)/developer/bin/find-appcast" '/path/to/application.app'
Sparkle 策略的默认模式是从 sparkle:shortVersionString 和 sparkle:version 生成 "#{item.short_version},#{item.version}",如果两者都已设置。在下面的示例中,url 还包括一个下载 ID,这是必需的
livecheck do
url "https://www.example.com/example.xml"
strategy :sparkle do |item|
"#{item.short_version},#{item.version}:#{item.url[%r{/(\d+)/[^/]+\.zip}i, 1]}"
end
end
仅使用一个,请指定 &:version、&:short_version 或 &:nice_version
livecheck do
url "https://www.example.com/example.xml"
strategy :sparkle, &:short_version
end
Xml strategy 块用于 Xml 的 strategy 块接收一个 REXML::Document 对象,如果提供,则接收一个正则表达式。例如,如果 XML 包含一个 versions 元素,其中嵌套了 version 元素,并且它们的内部文本包含版本字符串,我们可以使用正则表达式将其提取出来,如下所示
livecheck do
url "https://www.example.com/example.xml"
regex(/v?(\d+(?:\.\d+)+)/i)
strategy :xml do |xml, regex|
xml.get_elements("versions//version").map { |item| item.text[regex, 1] }
end
end
有关如何使用 REXML::Document 对象的更多信息,请参阅 REXML::Document 和 REXML::Element 文档。
Yaml strategy 块用于 Yaml 的 strategy 块接收已解析的 YAML 数据,如果提供,则接收一个正则表达式。借用 Json 示例,如果我们有一个包含一个对象数组的对象,其中包含一个 version 字符串,我们可以仅选择与正则表达式匹配的成员,并隔离相关的版本文本,如下所示
livecheck do
url "https://www.example.com/example.yaml"
regex(/^v?(\d+(?:\.\d+)+)$/i)
strategy :yaml do |yaml, regex|
yaml["versions"].select { |item| item["version"]&.match?(regex) }
.map { |item| item["version"][regex, 1] }
end
end
ExtractPlist strategy 块如果在线上无法找到任何方法来检查 macOS 软件包的哪个版本是当前版本,作为最后手段,:extract_plist 策略将让 brew livecheck 下载工件并从包含的 .plist 文件中检索其版本字符串。
livecheck do
url :url
strategy :extract_plist
end
用于 ExtractPlist 的 strategy 块接收一个哈希,其中包含每个找到的包标识符的键和具有每个 version 和 short_version 的方法的 item。
livecheck do
url :url
strategy :extract_plist do |items|
items["com.example.MyApp"].short_version
end
end
跳过出于多种原因(已弃用、已禁用等),Livecheck 会自动跳过某些公式/桶。但是,在极少数情况下,我们需要使用 livecheck 块进行手动跳过。 skip 方法采用一个字符串,其中包含跳过的非常简短的原因。
livecheck do
skip "No version information available"
end