brew livecheck
Команда brew livecheck находит новейшую версию программного обеспечения формулы или cask, проверяя upstream. Livecheck использует стратегии для определения версий из различных источников, таких как репозитории Git, веб-сайты и т. д.
Поведение
Если для livecheck не заданы инструкции о том, как проверять версии upstream, по умолчанию выполняются следующие действия:
- Собирается список URL для проверки.
- Для формул: используются URL
stable,headиhomepageв указанном порядке. - Для ресурсов формул: используется
url. - Для cask: используются URL
urlиhomepageв указанном порядке.
- Определяется, применимы ли какие-либо стратегии к первому URL. Если нет, проверяется следующий URL.
- Если стратегию можно применить, с её помощью проверяются новые версии.
- Возвращается новейшая версия (или ошибка, если ни по одному из доступных URL не удалось найти версии).
Иногда необходимо переопределить это поведение по умолчанию, чтобы проверка работала. Если источник не содержит новейшую версию, нужно проверить другой источник. Если livecheck неправильно сопоставляет текст версии, необходимо задать подходящее регулярное выражение или блок strategy.
Это можно сделать, добавив блок livecheck в формулу/cask/ресурс. Дополнительную информацию о доступных методах см. в документации класса Livecheck.
Создание проверки
-
Изучите отладочный вывод, чтобы понять ситуацию.
brew livecheck --debug <formula>|<cask>содержит сведения о том, какие URL проверяет livecheck, какие стратегии применимы, какие версии сопоставлены и т. д. -
Изучите доступные источники и выберите URL. Попробуйте удалить имя файла из
stable/urlи проверьте, откроется ли страница со списком файлов в каталоге. Если это не поможет, попробуйте найти страницу со ссылкой на файл (например, страницу загрузки). Если на веб-сайте невозможно найти новейшую версию, попробуйте проверить другие источники, указанные в формуле/cask. При необходимости поищите другие источники за пределами формулы/cask. -
При необходимости создайте регулярное выражение. Если проверка работает без регулярного выражения и оно не принесёт пользы, обычно его можно не указывать. Дополнительную информацию о создании регулярных выражений см. в разделе рекомендации по регулярным выражениям.
Общие рекомендации
-
Используйте
strategyтолько при необходимости. Например, если livecheck уже использует стратегиюGitдля URL, использоватьstrategy :gitне нужно. Однако если к URL применимаGit, но необходимо использоватьPageMatch, нужно указатьstrategy :page_match. -
Используйте стратегии
GithubLatestиGithubReleasesтолько при необходимости и если они подходят. GitHub ограничивает частоту запросов к API, поэтому мы используем эти стратегии, только еслиGitнедостаточна или не подходит.GithubLatestследует использовать только в том случае, если в upstream-репозитории есть подходящий релиз «latest» и формула/cask использует ресурс релиза либо стратегияGitне может правильно определить версию последнего релиза.GithubReleasesследует использовать только в том случае, если в upstream-репозитории используются релизы, а стратегииGitиGithubLatestне подходят.
Рекомендации по URL
-
В блоке
livecheckобязательно должен быть указанurl. Это может быть строка URL (например,"https://www.example.com/downloads/") или символ URL формулы/cask (то есть:stable,:url,:head,:homepage). Исключение из этого правила — блокlivecheck, в котором используется толькоskip. -
По возможности проверяйте версии в том же месте, где находится стабильный архив.
-
По возможности не проверяйте страницы релизов с постраничной навигацией. Например, мы обычно не проверяем страницу
releaseпроекта на GitHub, поскольку предварительные версии могут вытеснить последнюю стабильную версию с первой страницы. В этом случае надёжнее использовать стратегиюGit, которая получает все теги репозитория.
Рекомендации по регулярным выражениям
Регулярное выражение в блоке livecheck ограничивает совпадения подмножеством полученного содержимого и использует группу захвата для текста версии.
-
По возможности регулярные выражения следует делать нечувствительными к регистру, добавляя в конце
i(например,/.../iили%r{...}i). Это повышает надёжность: регулярное выражение будет учитывать изменения регистра букв без необходимости вносить правки. -
В регулярных выражениях следует использовать группу захвата только для текста версии. Например, в
/href=.*?example-v?(\d+(?:\.\d+)+)(?:-src)?\.t/iгруппа захвата используется только для текста версии (сопоставляя версию вроде1.2,1.2.3и т. д.), а в остальных местах используются незахватывающие группы (например,(?:-src)?). -
Используйте привязки к началу/концу регулярного выражения, чтобы ограничить область поиска. Например, на HTML-страницах мы часто сопоставляем имена файлов или каталоги версий в URL атрибутов
href(например,/href=.*?example[._-]v?(\d+(?:\.\d+)+)\.zip/i). В целом ограничение области поиска помогает исключить нежелательные совпадения. -
Не используйте универсальные шаблоны вроде
.*или.+; вместо них выбирайте нежадные и/или подходящие по контексту выражения. Например, для сопоставления символов внутри HTML-атрибута используйте[^"' >]+?. -
Используйте
[._-]вместо точки/подчёркивания/дефиса между названием программы и версией в имени файла. Для файла с именемexample-1.2.3.tar.gzвыражениеexample[._-]v?(\d+(?:\.\d+)+)\.tпродолжит работать, даже если формат имени файла upstream изменится наexample_1.2.3.tar.gzилиexample.1.2.3.tar.gz. -
Используйте
\.tвместо\.tgz,\.tar\.gzи т. д. Для tar-архивов существует множество расширений (например,.tar.bz2,tbz2,.tar.gz,.tgz,.tar.xz,.txzи т. д.), и со временем upstream-источник может перейти с одного формата сжатия на другой.\.tпозволяет избежать этой проблемы: оно сопоставляет текущие и будущие форматы, начинающиеся сt. Для файлов, не являющихся tar-архивами, в регулярном выражении используется полное расширение файла, например\.zip,\.jarи т. д.
Примеры блоков livecheck
В следующих примерах рассматриваются различные встречающиеся шаблоны. Это типичные примеры, которые можно легко адаптировать.
Если вы сомневаетесь, начните с одного из этих примеров, а не копируйте блок livecheck из случайной формулы/cask.
Имена файлов
При сопоставлении версии по имени файла на HTML-странице мы часто ограничиваем поиск атрибутами href. href=.*? сопоставляет открывающий разделитель (", '), а также любую часть URL перед именем файла.
livecheck do url "https://www.example.com/downloads/" regex(/href=.*?example[._-]v?(\d+(?:\.\d+)+)\.t/i) end
Иногда мы делаем выражение более точным, чтобы исключить нежелательные совпадения. Для URL с предшествующим путём можно использовать href=.*?/, а для остальных — 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 Теги Git
Если для URL stable используется стратегия 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
Формула/cask может использовать ту же проверку, что и другая формула/cask, с помощью formula или cask.
livecheck do formula "another-formula" end
Формула/cask, на которую ссылаются, должна находиться в том же tap, поскольку ссылка на формулу/cask из другого tap приведёт к ошибке, если пользователь ещё не добавил этот tap.
Ресурс формулы, версия которого синхронизирована с нумерацией версий родительской формулы, может использовать ту же проверку с помощью formula :parent.
livecheck do formula :parent end
Запросы POST
Для некоторых проверок требуется отправить запрос POST. Это можно сделать, добавив параметр post_form или post_json в блок livecheck url.
livecheck do
url "https://example.com/download.php", post_form: {
Name: "",
"E-mail": "",
}
regex(/href=.*?example[._-]v?(\d+(?:\.\d+)+)\.t/i)
end post_form используется для данных формы, а post_json — для данных JSON. Перед отправкой запроса Livecheck кодирует предоставленное значение хеша в подходящий формат.
Поддержка POST распространяется только на стратегии, которые прямо или косвенно используют Strategy::page_headers или ::page_content, поэтому она не применима к ExtractPlist, Git, GithubLatest, GithubReleases и т. д.
Блоки strategy
Если формат версии upstream необходимо преобразовать, чтобы он соответствовал формату формулы/cask, вместо regex можно использовать блок strategy.
Блок стратегии 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
Блок strategy для HeaderMatch пытается извлечь версию из имени файла (в заголовке 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
Блок strategy для Git устроен несколько иначе: вместо строки содержимого страницы он получает массив строк тегов. Как и в примере с PageMatch, здесь теги с датой в формате 2020-01-01 преобразуются в 20200101.
livecheck do
url :stable
strategy :git do |tags|
tags.filter_map { |tag| tag[/^(\d{4}-\d{2}-\d{2})$/i, 1]&.gsub(/\D/, "") }
end
end
Блок стратегии GithubLatest strategy
Блок strategy для GithubLatest получает разобранные данные JSON из GitHub API для последнего релиза «latest» репозитория, а также регулярное выражение. Если регулярное выражение не задано в блоке 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 Дополнительную информацию о JSON-ответе этой конечной точки API см. в соответствующей документации GitHub REST API.
Блок стратегии GithubReleases strategy
Блок strategy для GithubReleases получает разобранные данные JSON из GitHub API о последних релизах репозитория, а также регулярное выражение. Если регулярное выражение не задано в блоке 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 По умолчанию логика стратегии пропускает релизы, помеченные как черновики или предварительные версии, но это можно изменить с помощью блока strategy. Если убрать условие release["prerelease"] из предыдущего примера, можно будет обрабатывать предварительные релизы, хотя регулярное выражение также может потребоваться адаптировать для нестабильных форматов версий.
Дополнительную информацию о JSON-ответе этой конечной точки API см. в соответствующей документации GitHub REST API.
Блок стратегии Crate strategy
Блок strategy для Crate получает разобранные данные JSON из конечной точки versions API реестра и предоставленное регулярное выражение стратегии либо регулярное выражение по умолчанию. По умолчанию стратегия использует следующую логику, поэтому этот блок 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
Блок strategy для ElectronBuilder загружает содержимое по URL и разбирает его как appcast electron-builder в формате YAML. Он используется для cask приложений macOS, созданных с помощью фреймворка Electron.
livecheck do url "https://example.org/my-app/latest-mac.yml" strategy :electron_builder end
Если необходимо изменить версию, можно получить доступ к хешу YAML в блоке strategy следующим образом:
livecheck do
url "https://example.org/my-app/latest-mac.yml"
strategy :electron_builder do |yaml|
yaml["version"]&.gsub(/\D/, "")
end
end Аналогичным образом можно работать с массивом files:
livecheck do
url "https://example.org/my-app/latest-mac.yml"
regex(/MyApp[._-]v?(\d+(?:\.\d+)+)-(\h+)\.dmg/i)
strategy :electron_builder do |yaml, regex|
yaml["files"]&.map do |file|
match = file["url"]&.match(regex)
next if match.blank?
"#{match[1]},#{match[2]}"
end
end
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, методы которого позволяют работать с version, short_version, nice_version, url, channel и title. Он ожидает URL XML-ленты с информацией о релизах для приложения macOS, которое обновляется самостоятельно с помощью фреймворка Sparkle. Этот URL можно найти в пакете приложения: он указан в свойстве SUFeedURL файла Contents/Info.plist. Также его можно найти с помощью команды find-appcast. Выполните её так:
brew find-appcast '/path/to/application.app'
По умолчанию стратегия Sparkle формирует "#{item.short_version},#{item.version}" на основе sparkle:shortVersionString и sparkle:version, если заданы оба значения. В примере ниже возвращаемое значение также содержит необходимый идентификатор загрузки из url:
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
Если значение, возвращаемое item, не является самым последним или не соответствует нужному, передайте вместо него items, чтобы перебрать все элементы ленты:
livecheck do
url "https://www.example.com/example.xml"
strategy :sparkle do |items|
items.find { |item| item.channel.nil? }&.short_version
end
end
Блок стратегии Xml strategy
Блок strategy для Xml получает объект 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
Блок strategy для Yaml получает разобранные данные 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
Блок strategy для ExtractPlist получает хеш, содержащий ключи для каждого найденного идентификатора пакета, и объекты item с методами для каждого version и short_version.
livecheck do
url :url
strategy :extract_plist do |items|
items["com.example.MyApp"].short_version
end
end Обратите внимание: если для пакета используется эта стратегия livecheck, он исключается из автоматического обновления, поскольку эта стратегия увеличивает время работы CI.
throttle
Для программ с очень частыми выпусками, не каждый из которых нужно публиковать в виде обновления формулы/cask, в livecheck можно настроить уменьшение числа отображаемых версий с помощью throttle. В этом примере возвращаются только версии, последняя часть которых делится на 10 без остатка.
livecheck do url :stable regex(/^v?(\d+(?:\.\d+)+)$/i) throttle 10 end
skip
Livecheck автоматически пропускает некоторые формулы/cask по ряду причин (устаревшие, отключённые и т. д.). Однако в редких случаях для ручного пропуска необходимо использовать блок livecheck. Метод skip принимает строку с очень кратким объяснением причины пропуска.
livecheck do skip "No version information available" end
© 2009–present Homebrew contributors
Licensed under the BSD 2-Clause License.
https://docs.brew.sh/Brew-Livecheck