brew/docs/Brew-Livecheck.md

138 lines
8.6 KiB
Markdown
Raw Normal View History

# `brew livecheck`
2020-07-08 00:32:02 -04:00
The `brew livecheck` command finds the newest version of a formula or cask's software by checking upstream. Livecheck has [strategies](https://rubydoc.brew.sh/Homebrew/Livecheck/Strategy.html) to identify versions from various sources, such as Git repositories, websites, etc.
2020-07-08 00:32:02 -04:00
## Behavior
2020-07-08 00:32:02 -04:00
When livecheck isn't given instructions for how to check for upstream versions, it does the following by default:
2020-07-08 00:32:02 -04:00
1. For formulae: Collect the `head`, `stable`, and `homepage` URLs, in that order. For casks: Collect the `url` and `homepage` URLs, in that order.
1. Determine if any strategies apply to the first URL. If not, try the next URL.
1. If a strategy can be applied, use it to check for new versions.
1. Return the newest version (or an error if versions could not be found at any available URLs).
2020-07-08 00:32:02 -04:00
It's sometimes necessary to override this default behavior to create a working check for a formula/cask. If a source doesn't provide the newest version, we need to check a different one. If livecheck doesn't correctly match version text, we need to provide an appropriate regex.
2020-07-08 00:32:02 -04:00
This can be accomplished by adding a `livecheck` block to the formula/cask. For more information on the available methods, please refer to the [`Livecheck` class documentation](https://rubydoc.brew.sh/Livecheck.html).
2020-07-08 00:32:02 -04:00
## Creating a check
2020-07-08 00:32:02 -04:00
1. **Use the debug output to understand the situation**. `brew livecheck --debug <formula>|<cask>` provides information about which URLs livecheck tries, any strategies that apply, matched versions, etc.
2020-07-08 00:32:02 -04:00
1. **Research available sources to select a URL**. Try removing the file name from `stable`/`url`, to see if this is a directory listing page. If that doesn't work, try to find a page that links to the file (e.g. a download page). If it's not possible to find the newest version on the website, try checking other sources from the formula/cask. When necessary, search for other sources outside of the formula/cask.
2020-07-08 00:32:02 -04:00
1. **Create a regex, if necessary**. If the check works without a regex and wouldn't benefit from having one, it's usually fine to omit it. More information on creating regexes can be found in the [regex guidelines](#regex-guidelines) section.
2020-07-08 00:32:02 -04:00
### General guidelines
2020-07-08 00:32:02 -04:00
* **Only use `strategy` when it's necessary**. For example, if livecheck is already using `Git` for a URL, it's not necessary to use `strategy :git`. However, if `Git` applies to a URL but we need to use `PageMatch`, it's necessary to use `strategy :page_match`.
2020-07-08 00:32:02 -04:00
* **Only use the `GithubLatest` strategy when it's necessary and correct**. Github.com rate limits requests and we try to minimize our use of this strategy to avoid hitting the rate limit on CI or when using `brew livecheck --tap` on large taps (e.g. homebrew/core). The `Git` strategy is often sufficient and we only need to use `GithubLatest` when the "latest" release is different than the newest version from the tags.
2020-07-08 00:32:02 -04:00
### URL guidelines
2020-07-08 00:32:02 -04:00
* **A `url` is required in a `livecheck` block**. This can be a URL string (e.g. `"https://www.example.com/downloads/"`) or a formula/cask URL symbol (i.e. `:stable`, `:url`, `:head`, `:homepage`). The exception to this rule is a `livecheck` block that only uses `skip`.
2020-07-08 00:32:02 -04:00
* **Check for versions in the same location as the stable archive, whenever possible**.
2020-07-08 00:32:02 -04:00
* **Avoid checking paginated release pages, when possible**. For example, we generally avoid checking the `release` page for a GitHub project because the latest stable version can be pushed off the first page by pre-release versions. In this scenario, it's more reliable to use the `Git` strategy, which fetches all the tags in the repository.
2020-07-08 00:32:02 -04:00
### Regex guidelines
2020-07-08 00:32:02 -04:00
The `livecheck` block regex restricts matches to a subset of the fetched content and uses a capture group around the version text.
2020-07-08 00:32:02 -04:00
* **Regexes should be made case insensitive, whenever possible**, by adding `i` at the end (e.g. `/.../i` or `%r{...}i`). This improves reliability, as the regex will handle changes in letter case without needing modifications.
2020-07-08 00:32:02 -04:00
* **Regexes should only use a capturing group around the version text**. For example, in `/href=.*?example-v?(\d+(?:\.\d+)+)(?:-src)?\.t/i`, we're only using a capturing group around the version test (matching a version like `1.2`, `1.2.3`, etc.) and we're using non-capturing groups elsewhere (e.g. `(?:-src)?`).
2020-07-08 00:32:02 -04:00
* **Anchor the start/end of the regex, to restrict the scope**. For example, on HTML pages we often match file names or version directories in `href` attribute URLs (e.g. `/href=.*?example[._-]v?(\d+(?:\.\d+)+)\.zip/i`). The general idea is that limiting scope will help exclude unwanted matches.
2020-07-08 00:32:02 -04:00
* **Avoid generic catch-alls like `.*` or `.+`** in favor of something non-greedy and/or contextually appropriate. For example, to match characters within the bounds of an HTML attribute, use `[^"' >]+?`.
2020-07-08 00:32:02 -04:00
* **Use `[._-]` in place of a period/underscore/hyphen between the software name and version in a file name**. For a file named `example-1.2.3.tar.gz`, `example[._-]v?(\d+(?:\.\d+)+)\.t` will continue matching if the upstream file name format changes to `example_1.2.3.tar.gz` or `example.1.2.3.tar.gz`.
2020-07-08 00:32:02 -04:00
* **Use `\.t` in place of `\.tgz`, `\.tar\.gz`, etc.** There are a variety of different file extensions for tarballs (e.g. `.tar.bz2`, `tbz2`, `.tar.gz`, `.tgz`, `.tar.xz`, `.txz`, etc.) and the upstream source may switch from one compression format to another over time. `\.t` avoids this issue by matching current and future formats starting with `t`. Outside of tarballs, we use the full file extension in the regex like `\.zip`, `\.jar`, etc.
2020-07-08 00:32:02 -04:00
## Example `livecheck` blocks
2020-07-08 00:32:02 -04:00
The following examples cover a number of patterns that you may encounter. These are intended to be representative samples and can be easily adapted.
2020-07-08 00:32:02 -04:00
When in doubt, start with one of these examples instead of copy-pasting a `livecheck` block from a random formula/cask.
2020-07-08 00:32:02 -04:00
### File names
2020-07-08 00:32:02 -04:00
```ruby
livecheck do
url "https://www.example.com/downloads/"
regex(/href=.*?example[._-]v?(\d+(?:\.\d+)+)\.t/i)
end
```
2020-07-08 00:32:02 -04:00
When matching the version from a file name on an HTML page, we often restrict matching to `href` attributes. `href=.*?` will match the opening delimiter (`"`, `'`) as well as any part of the URL before the file name.
2020-07-08 00:32:02 -04:00
We sometimes make this more explicit to exclude unwanted matches. URLs with a preceding path can use `href=.*?/` and others can use `href=["']?`. For example, this is necessary when the page also contains unwanted files with a longer prefix (`another-example-1.2.tar.gz`).
2020-07-08 00:32:02 -04:00
### Version directories
2020-07-08 00:32:02 -04:00
```ruby
livecheck do
url "https://www.example.com/releases/example/"
regex(%r{href=["']?v?(\d+(?:\.\d+)+)/?["' >]}i)
end
```
2020-07-08 00:32:02 -04:00
When checking a directory listing page, sometimes files are separated into version directories (e.g. `1.2.3/`). In this case, we must identify versions from the directory names.
2020-07-08 00:32:02 -04:00
### Git tags
2020-07-08 00:32:02 -04:00
```ruby
livecheck do
url :stable
regex(/^v?(\d+(?:\.\d+)+)$/i)
end
```
2020-07-08 00:32:02 -04:00
When the `stable` URL uses the `Git` strategy, the regex above will only match tags like `1.2`/`v1.2`, etc.
2020-07-08 00:32:02 -04:00
If tags include the software name as a prefix (e.g. `example-1.2.3`), it's easy to modify the regex accordingly: `/^example[._-]v?(\d+(?:\.\d+)+)$/i`
2020-07-08 00:32:02 -04:00
### `PageMatch` `strategy` block
```ruby
livecheck do
url :homepage
regex(/href=.*?example[._-]v?(\d{4}-\d{2}-\d{2})\.t/i)
strategy :page_match do |page, regex|
page.scan(regex).map { |match| match&.first&.gsub(/\D/, "") }
end
end
```
2020-07-08 00:32:02 -04:00
When necessary, a `strategy` block allows us to have greater flexibility in how upstream version information is matched and processed. Currently, they're only used when the upstream version format needs to be manipulated to match the formula/cask format. In the example above, we're converting a date format like `2020-01-01` into `20200101`.
2020-07-08 00:32:02 -04:00
The `PageMatch` `strategy` block style seen here also applies to any strategy that uses `PageMatch` internally.
2020-07-08 00:32:02 -04:00
### `Git` `strategy` block
2020-07-08 00:32:02 -04:00
```ruby
livecheck do
url :stable
regex(/^(\d{4}-\d{2}-\d{2})$/i)
strategy :git do |tags, regex|
tags.map { |tag| tag[regex, 1]&.gsub(/\D/, "") }.compact
end
end
```
2020-07-08 00:32:02 -04:00
A `strategy` block for `Git` is a bit different, as the block receives an array of tag strings instead of a page content string. Similar to the `PageMatch` example, this is converting tags with a date format like `2020-01-01` into `20200101`.
2020-07-08 00:32:02 -04:00
### Skip
2020-07-08 00:32:02 -04:00
```ruby
livecheck do
skip "No version information available"
end
```
2020-07-08 00:32:02 -04:00
Livecheck automatically skips some formulae/casks for a number of reasons (deprecated, disabled, discontinued, etc.). However, on rare occasions we need to use a `livecheck` block to do a manual skip. The `skip` method takes a string containing a very brief reason for skipping.