brew livecheck
brew 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