mirror of
https://github.com/Homebrew/brew.git
synced 2026-08-12 22:29:27 +04:00
Structured cask install steps run in a sandbox that denies network access. This breaks casks whose upstream setup commands must retrieve installation-time dependencies, including `gcloud-cli` virtualenv creation. - Add a serialised `network_access:` option to `run` steps. - Omit the option from API data when it retains the default denial. - Enable network access only when an explicit run requests it. - Preserve network denial for existing steps and generated completions. - Document the opt-in and cover both sandbox policies in tests. This avoids disabling network restrictions for all cask operations while giving affected casks an explicit, auditable escape hatch. See #23495.
1620 lines
98 KiB
Markdown
1620 lines
98 KiB
Markdown
---
|
||
last_review_date: "2026-07-18"
|
||
---
|
||
|
||
# Cask Cookbook
|
||
|
||
Each cask is a Ruby block, beginning with a special header line. The cask definition itself is always enclosed in a `do … end` block. Example:
|
||
|
||
```ruby
|
||
cask "anybar" do
|
||
version "0.2.3"
|
||
sha256 "c87dbc6aff5411676a471e84905d69c671b62b93b1210bd95c9d776d087de95c"
|
||
|
||
url "https://github.com/tonsky/AnyBar/releases/download/#{version}/AnyBar-#{version}.zip"
|
||
name "AnyBar"
|
||
desc "Menu bar status indicator"
|
||
homepage "https://github.com/tonsky/AnyBar"
|
||
|
||
app "AnyBar.app"
|
||
end
|
||
```
|
||
|
||
* Table of Contents
|
||
{:toc}
|
||
|
||
## The cask language is declarative
|
||
|
||
Each cask contains a series of stanzas (or “fields”) which *declare* how the software is to be obtained and installed. In a declarative language, the author does not need to worry about **order**. As long as all the needed fields are present, Homebrew determines what to do at install time.
|
||
|
||
To make maintenance easier, the most-frequently-updated stanzas are usually placed at the top. But that’s a convention, not a rule.
|
||
|
||
Exception: `*_steps` blocks contain an ordered sequence of constrained operations.
|
||
|
||
## Header line details
|
||
|
||
The cask name ([`<cask-token>`](#token-reference)) on the header line `cask <cask-token> do` should match the cask filename, without the `.rb` extension, enclosed in double quotes.
|
||
|
||
The [token reference](#token-reference) describes the current naming rules and exceptions.
|
||
|
||
## Stanza order
|
||
|
||
Having a common order for stanzas makes casks easier to update and parse. Below is the complete stanza sequence (no cask will have all stanzas). The empty lines shown here are also important, as they help to visually delimit information.
|
||
|
||
arch
|
||
on_arch_conditional # additional custom-defined substitutions
|
||
os
|
||
on_system_conditional # additional custom-defined substitutions
|
||
|
||
version
|
||
sha256
|
||
|
||
on_<system> # arm, intel, supported macOS releases (oldest first), macos, then linux
|
||
|
||
language
|
||
|
||
url
|
||
name
|
||
desc
|
||
homepage
|
||
|
||
livecheck
|
||
|
||
no_autobump!
|
||
|
||
deprecate!
|
||
disable!
|
||
|
||
auto_updates
|
||
conflicts_with
|
||
depends_on
|
||
container
|
||
|
||
rename
|
||
|
||
suite
|
||
app
|
||
app_image
|
||
pkg
|
||
generated_script
|
||
installer
|
||
binary
|
||
command_wrapper
|
||
manpage
|
||
bash_completion
|
||
fish_completion
|
||
zsh_completion
|
||
generate_completions_from_executable
|
||
colorpicker
|
||
dictionary
|
||
font
|
||
input_method
|
||
internet_plugin
|
||
keyboard_layout
|
||
prefpane
|
||
mdimporter
|
||
screen_saver
|
||
service
|
||
audio_unit_plugin
|
||
vst_plugin
|
||
vst3_plugin
|
||
artifact, target: # target: shown here as is required with `artifact`
|
||
stage_only
|
||
|
||
preflight_steps
|
||
|
||
postflight_steps
|
||
|
||
uninstall_preflight_steps
|
||
|
||
uninstall_postflight_steps
|
||
|
||
uninstall
|
||
|
||
zap
|
||
|
||
caveats
|
||
|
||
Note that every stanza that has additional parameters (`:symbols` after a `,`) shall have them on separate lines, one per line, in alphabetical order. An exception is `target:` which typically consists of short lines.
|
||
|
||
## Stanzas
|
||
|
||
### Required stanzas
|
||
|
||
Each cask requires the identity and download stanzas below.
|
||
Submissions to `homebrew/cask` may require additional stanzas such as `livecheck`, `depends_on`, `uninstall` or `zap` when the package needs them.
|
||
|
||
| name | multiple occurrences allowed? | value |
|
||
| ---------------------------------- | :---------------------------: | ----- |
|
||
| [`version`](#stanza-version) | no | Application version, or the special value `:latest`. |
|
||
| [`sha256`](#stanza-sha256) | no | SHA-256 checksum of the file downloaded from `url` as calculated by the command `shasum -a 256 <file>`, or the special value `:no_check`. |
|
||
| [`url`](#stanza-url) | no | URL to the `.dmg`/`.zip`/`.tgz` file (or other common archive formats) that contains the application. |
|
||
| [`name`](#stanza-name) | yes | String providing the full and proper name defined by the vendor. |
|
||
| [`desc`](#stanza-desc) | no | One-line description of the cask. Shown when running `brew info`. |
|
||
| `homepage` | no | Application homepage; used for the `brew home` command. |
|
||
|
||
If a homepage blocks automated requests but works in a browser, record the date it was last checked by a human:
|
||
|
||
```ruby
|
||
homepage "https://www.example.com/", browsed: "2026-07-26"
|
||
```
|
||
|
||
This skips automated homepage availability audits for one year. Do not use a future date.
|
||
|
||
### At least one artifact stanza is also required
|
||
|
||
Each cask must declare one or more [artifacts](/rubydoc/Cask/Artifact.html) (i.e. something to install).
|
||
Not every artifact type is supported on every operating system and a cask does not need to support both macOS and Linux.
|
||
The `app_image` stanza is Linux-only, macOS integration stanzas such as `app` and `pkg` are macOS-only and portable stanzas such as `binary` can be used on either operating system.
|
||
|
||
| name | multiple occurrences allowed? | value |
|
||
| -------------------------------------------------------------------------------------- | :---------------------------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||
| [`suite`](#stanza-suite) | yes | Relative path to a containing directory that should be moved into the `/Applications` folder on installation. |
|
||
| [`app`](#stanza-app) | yes | Relative path to an `.app` that should be moved into the `/Applications` folder on installation. |
|
||
| `app_image` | yes | Relative path to an AppImage that should be linked into the configured AppImage directory on installation. |
|
||
| [`pkg`](#stanza-pkg) | yes | Relative path to a `.pkg` file containing the distribution. |
|
||
| [`generated_script`](#stanza-generated_script) | yes | Generates a script for another artifact or install step to use. |
|
||
| [`installer`](#stanza-installer) | yes | Describes an executable which must be run to complete the installation. |
|
||
| [`binary`](#stanza-binary) | yes | Relative path to a Binary that should be linked into the `$(brew --prefix)/bin` folder on installation. |
|
||
| [`command_wrapper`](#stanza-command_wrapper) | yes | Generates a command wrapper and links it into the `$(brew --prefix)/bin` folder. |
|
||
| `manpage` | yes | Relative path to a Man Page that should be linked into the respective man page folder on installation, e.g. `/opt/homebrew/share/man/man3` for `my_app.3`. |
|
||
| `bash_completion` | yes | Relative path to a Bash completion file that should be linked into the `$(brew --prefix)/etc/bash_completion.d` folder on installation. |
|
||
| `fish_completion` | yes | Relative path to a fish completion file that should be linked into the `$(brew --prefix)/share/fish/vendor_completions.d` folder on installation. |
|
||
| `zsh_completion` | yes | Relative path to a Zsh completion file that should be linked into the `$(brew --prefix)/share/zsh/site-functions` folder on installation. |
|
||
| [`generate_completions_from_executable`](#stanza-generate_completions_from_executable) | yes | Command and arguments used to generate shell completions from an executable at installation time. |
|
||
| `colorpicker` | yes | Relative path to a ColorPicker plugin that should be moved into the `~/Library/ColorPickers` folder on installation. |
|
||
| `dictionary` | yes | Relative path to a Dictionary that should be moved into the `~/Library/Dictionaries` folder on installation. |
|
||
| `font` | yes | Relative path to a Font that should be moved into the `~/Library/Fonts` folder on installation. |
|
||
| `input_method` | yes | Relative path to an Input Method that should be moved into the `~/Library/Input Methods` folder on installation. |
|
||
| `internet_plugin` | yes | Relative path to an Internet Plugin that should be moved into the `~/Library/Internet Plug-Ins` folder on installation. |
|
||
| `keyboard_layout` | yes | Relative path to a Keyboard Layout that should be moved into the `/Library/Keyboard Layouts` folder on installation. |
|
||
| `prefpane` | yes | Relative path to a Preference Pane that should be moved into the `~/Library/PreferencePanes` folder on installation. |
|
||
| `mdimporter` | yes | Relative path to a Spotlight Metadata Importer that should be moved into the `~/Library/Spotlight` folder on installation. |
|
||
| `screen_saver` | yes | Relative path to a Screen Saver that should be moved into the `~/Library/Screen Savers` folder on installation. |
|
||
| `service` | yes | Relative path to a Service that should be moved into the `~/Library/Services` folder on installation. |
|
||
| `audio_unit_plugin` | yes | Relative path to an Audio Unit Plugin that should be moved into the `~/Library/Audio/Plug-Ins/Components` folder on installation. |
|
||
| `vst_plugin` | yes | Relative path to a VST Plugin that should be moved into the `~/Library/Audio/Plug-Ins/VST` folder on installation. |
|
||
| `vst3_plugin` | yes | Relative path to a VST3 Plugin that should be moved into the `~/Library/Audio/Plug-Ins/VST3` folder on installation. |
|
||
| `artifact` | yes | Relative path to an arbitrary path that should be moved on installation. Must provide an absolute path as a `target`. (Example: [free-gpgmail.rb](https://github.com/Homebrew/homebrew-cask/blob/b3c438d608d9702380edf10d5495e0727cf17108/Casks/f/free-gpgmail.rb#L44)) This is only for unusual cases; the `app` stanza is strongly preferred when moving `.app` bundles. |
|
||
| `stage_only` | no | `true`. Asserts that the cask contains no activatable artifacts. |
|
||
|
||
### Cask artifact trust and sandboxing
|
||
|
||
Homebrew treats cask installation artifacts as trusted vendor installation actions once the cask has been accepted. Artifact stanzas such as [`app`](#stanza-app), [`pkg`](#stanza-pkg) and [`installer script`](#installer-script) are expected to install software and may write outside the Caskroom through Homebrew-managed moves, macOS installer services or vendor installer code.
|
||
|
||
Generated completion artifacts are different: `generate_completions_from_executable` runs an installed executable only to produce shell completion text. The complete generation operation, including writing the completion, runs in an isolated Ruby subprocess where Homebrew has an available sandbox. The sandbox allows reading the staged cask, writing the completion and temporary/cache files and blocks network access. This limits side effects from commands that should only print completion data.
|
||
|
||
`installer script:` is not sandboxed. Many installer scripts are vendor installers that require broad filesystem writes, macOS services or `sudo`; macOS sandboxing does not work for root processes, and narrowing the write allowlist to the Caskroom plus uninstall or zap paths would break installers that legitimately write elsewhere. It would also change documented `SystemCommand` behaviours such as `sudo:`, `must_succeed:` and output handling.
|
||
|
||
`pkg` artifacts are not run in the cask sandbox either. They are installed by macOS `/usr/sbin/installer`, which applies package payloads, scripts and receipts according to the package metadata.
|
||
|
||
### Optional stanzas
|
||
|
||
| name | multiple occurrences allowed? | value |
|
||
| ------------------------------------------ | :---------------------------: | ----- |
|
||
| [`uninstall`](#stanza-uninstall) | yes | Procedures to uninstall a cask. Optional unless a `pkg` or `installer` artifact stanza is used. |
|
||
| [`conflicts_with`](#stanza-conflicts_with) | yes | List of conflicts with this cask. |
|
||
| [`caveats`](#stanza-caveats) | yes | String or Ruby block providing the user with cask-specific information at install time. |
|
||
| [`livecheck`](#stanza-livecheck) | no | Ruby block describing how to find updates when automatic detection is insufficient. It is not used with `version :latest` unless the block uses `skip`. |
|
||
| [`depends_on`](#stanza-depends_on) | yes | Dependencies and operating-system or architecture requirements for this cask. |
|
||
| [`zap`](#stanza-zap) | no | Additional procedures for a more complete uninstall, including user files and shared resources. |
|
||
| [`deprecate!`](#stanza-deprecate--disable) | no | Date as a string in `YYYY-MM-DD` format and a string or symbol providing a reason. |
|
||
| [`disable!`](#stanza-deprecate--disable) | no | Date as a string in `YYYY-MM-DD` format and a string or symbol providing a reason. |
|
||
| `preflight_steps` | yes | Declarative file preparation steps run before artifact installation. |
|
||
| `postflight_steps` | yes | Declarative file preparation steps run after artifact installation. |
|
||
| `uninstall_preflight_steps` | yes | Declarative file preparation steps run before artifact uninstallation. |
|
||
| `uninstall_postflight_steps` | yes | Declarative file preparation steps run after artifact uninstallation. |
|
||
| [`language`](#stanza-language) | yes | Ruby block, called with language code parameters, containing other stanzas and/or a return value. |
|
||
| `container nested:` | no | Relative path to an inner container that must be extracted before moving on with the installation. This allows for support of `.dmg` inside `.tar`, `.zip` inside `.dmg`, etc. (Example: [blocs.rb](https://github.com/Homebrew/homebrew-cask/blob/aa461148bbb5119af26b82cccf5003e2b4e50d95/Casks/b/blocs.rb#L17-L19)) |
|
||
| `container type:` | no | Symbol to override container-type autodetect. May be one of: `:air`, `:bzip2`, `:cab`, `:dmg`, `:generic_unar`, `:gzip`, `:otf`, `:pkg`, `:rar`, `:seven_zip`, `:sit`, `:tar`, `:ttf`, `:xar`, `:zip`, `:naked`. (Example: [parse.rb](https://github.com/Homebrew/homebrew-cask/blob/aa461148bbb5119af26b82cccf5003e2b4e50d95/Casks/p/parse.rb#L10)) |
|
||
| `auto_updates` | no | `true`. Asserts that the cask artifacts auto-update. Use if `Check for Updates…` or similar is present in an app menu, but not if it only opens a webpage and does not do the download and installation for you. |
|
||
| [`no_autobump!`](#stanza-no_autobump) | no | Allowed symbol or a string. Excludes cask from autobumping if set. |
|
||
| [`rename`](#stanza-rename) | yes | A pair of strings. |
|
||
|
||
## Stanza descriptions
|
||
|
||
### Stanza: `app`
|
||
|
||
In the simple case of a string argument to `app`, the source file is moved to the target `/Applications` directory. For example:
|
||
|
||
```ruby
|
||
app "Alfred 2.app"
|
||
```
|
||
|
||
by default moves the source to:
|
||
|
||
```bash
|
||
/Applications/Alfred 2.app
|
||
```
|
||
|
||
When an archive expands into a subdirectory, include that subdirectory in the path to the app bundle:
|
||
|
||
```ruby
|
||
app "Simple Floating Clock/SimpleFloatingClock.app"
|
||
```
|
||
|
||
#### Renaming the target
|
||
|
||
You can rename the target which appears in your `/Applications` directory by adding a `target:` key to `app`. Example (from [scala-ide.rb](https://github.com/Homebrew/homebrew-cask/blob/aa461148bbb5119af26b82cccf5003e2b4e50d95/Casks/s/scala-ide.rb#L24)):
|
||
|
||
```ruby
|
||
app "eclipse.app", target: "Scala IDE.app"
|
||
```
|
||
|
||
#### *target* may contain an absolute path
|
||
|
||
If `target:` has a leading slash, it is interpreted as an absolute path. The containing directory for the absolute path will be created if it does not already exist. Example (from [sapmachine-jdk.rb](https://github.com/Homebrew/homebrew-cask/blob/aa461148bbb5119af26b82cccf5003e2b4e50d95/Casks/s/sapmachine-jdk.rb#L21)):
|
||
|
||
```ruby
|
||
artifact "sapmachine-jdk-#{version}.jdk", target: "/Library/Java/JavaVirtualMachines/sapmachine-jdk-#{version}.jdk"
|
||
```
|
||
|
||
#### *target* works on most artifact types
|
||
|
||
The `target:` key works similarly for most cask artifacts, such as `app`, `binary`, `bash_completion`, `fish_completion`, `zsh_completion`, `colorpicker`, `dictionary`, `font`, `input_method`, `internet_plugin`, `keyboard_layout`, `prefpane`, `mdimporter`, `screen_saver`, `service`, `suite`, `audio_unit_plugin`, `vst_plugin`, `vst3_plugin`, and `artifact`.
|
||
|
||
#### *target* should only be used in select cases
|
||
|
||
Don’t use `target:` for aesthetic reasons, like removing version numbers (`app "Slack #{version}.app", target: "Slack.app"`). Use it when it makes sense functionally and document your reason clearly in the cask, using one of the templates: [for clarity](https://github.com/Homebrew/homebrew-cask/blob/aa461148bbb5119af26b82cccf5003e2b4e50d95/Casks/i/imagemin.rb#L10); [for consistency](https://github.com/Homebrew/homebrew-cask/blob/8be96e3658ff7ab66ca40723c3018fc5e35e3735/Casks/x-moto.rb#L16); [to prevent conflicts](https://github.com/Homebrew/homebrew-cask/blob/4472df441468e2aa657005550e2b951c2ef817f4/Casks/t/telegram-desktop.rb#L20); [due to developer suggestion](https://github.com/Homebrew/homebrew-cask/blob/ff3e9c4a6623af44b8a071027e8dcf3f4edfc6d9/Casks/kivy.rb#L12).
|
||
|
||
### Stanza: `binary`
|
||
|
||
In the simple case of a string argument to `binary`, the source file is linked into the `$(brew --prefix)/bin` directory on installation. For example (from [operadriver.rb](https://github.com/Homebrew/homebrew-cask/blob/326c44e93aeb8d4dd73acea14a99ae215c75fdd6/Casks/o/operadriver.rb#L15)):
|
||
|
||
```ruby
|
||
binary "operadriver_mac64/operadriver"
|
||
```
|
||
|
||
creates a symlink to:
|
||
|
||
```bash
|
||
$(brew --prefix)/bin/operadriver
|
||
```
|
||
|
||
from a source file such as:
|
||
|
||
```bash
|
||
$(brew --caskroom)/operadriver/106.0.5249.119/operadriver_mac64/operadriver
|
||
```
|
||
|
||
A binary (or multiple) can also be contained in an application bundle:
|
||
|
||
```ruby
|
||
app "Atom.app"
|
||
binary "#{appdir}/Atom.app/Contents/Resources/app/apm/bin/apm"
|
||
```
|
||
|
||
You can rename the target which appears in your binaries directory by adding a `target:` key to `binary`:
|
||
|
||
```ruby
|
||
binary "#{appdir}/Atom.app/Contents/Resources/app/atom.sh", target: "atom"
|
||
```
|
||
|
||
Behaviour and usage of `target:` is [the same as with `app`](#renaming-the-target). However, for `binary` the select cases don’t apply as rigidly. It’s fine to take extra liberties with `target:` to be consistent with other command-line tools, like [changing case](https://github.com/Homebrew/homebrew-cask/blob/aa461148bbb5119af26b82cccf5003e2b4e50d95/Casks/g/godot.rb#L19), [removing an extension](https://github.com/Homebrew/homebrew-cask/blob/aa461148bbb5119af26b82cccf5003e2b4e50d95/Casks/f/filebot.rb#L19), or [cleaning up the name](https://github.com/Homebrew/homebrew-cask/blob/aa461148bbb5119af26b82cccf5003e2b4e50d95/Casks/f/fig.rb#L21).
|
||
|
||
### Stanza: `command_wrapper`
|
||
|
||
`command_wrapper` writes an executable shim script into the staged cask and links it like a [`binary`](#stanza-binary) using the declared command name. Use it when an application does not provide a suitable command-line entry point. When using `executable:`, fixed arguments and environment variables can be passed with `args:` and `env:`.
|
||
|
||
```ruby
|
||
command_wrapper "example",
|
||
executable: "#{appdir}/Example.app/Contents/MacOS/example",
|
||
args: ["--cli"],
|
||
env: { "EXAMPLE_MODE" => "batch" }
|
||
```
|
||
|
||
Use `content:` instead of `executable:` for wrappers which need custom shell logic. It contains the complete wrapper and cannot be combined with `args:` or `env:`.
|
||
|
||
### Stanza: `generated_script`
|
||
|
||
`generated_script` writes literal content to a script in the staged cask and makes it executable. It does not link or run the file. Use it when a later `installer`, `uninstall` or install step needs a generated script.
|
||
|
||
```ruby
|
||
generated_script "installer.sh", content: <<~SH
|
||
#!/bin/sh
|
||
exec "#{staged_path}/payload/install" "$@"
|
||
SH
|
||
installer script: "installer.sh"
|
||
```
|
||
|
||
### Stanza: `rename`
|
||
|
||
The `rename` stanza provides a convenience method to rename files to provide more practical access to them.
|
||
This stanza should be used sparingly, and is reserved for scenarios where the path of a file/directory is impossible to pre-determine.
|
||
|
||
The example below can be used when the `pkg` path has a value such as timestamp that can't be detected without extracting the archive it is distributed within.
|
||
|
||
```ruby
|
||
# Upstream provides a `pkg` - "foobar-<timestamp>.pkg"
|
||
rename "foobar-*.pkg", "foobar.pkg"
|
||
```
|
||
|
||
### Stanza: `caveats`
|
||
|
||
Sometimes there are particularities with the installation of a piece of software that cannot or should not be handled programmatically by Homebrew’s cask installer. In those instances, `caveats` is the way to inform the user. Information in `caveats` is displayed when a cask is invoked with either `install` or `info`.
|
||
|
||
To avoid flooding users with too many messages (thus desensitising them to the important ones), `caveats` should be used sparingly and exclusively for installation-related matters. If you’re not sure whether a `caveat` you find pertinent is installation-related or not, ask a maintainer. As a general rule, if your case isn’t already covered in our comprehensive [`caveats mini-DSL`](#caveats-mini-dsl), it’s unlikely to be accepted.
|
||
|
||
#### `caveats` as a string
|
||
|
||
When `caveats` is a string, it is evaluated at compile time. The following methods are available for interpolation if `caveats` is placed in its customary position at the end of the cask:
|
||
|
||
| method | description |
|
||
| ------------------ | ----------- |
|
||
| `token` | the cask token |
|
||
| `version` | the cask version |
|
||
| `homepage` | the cask homepage |
|
||
| `caskroom_path` | the containing directory for this cask: `$(brew --caskroom)/<token>` |
|
||
| `staged_path` | the staged location for this cask, including version number: `$(brew --caskroom)/<token>/<version>` |
|
||
|
||
Example:
|
||
|
||
```ruby
|
||
caveats "Using #{token} may be hazardous to your health."
|
||
```
|
||
|
||
#### `caveats` as a block
|
||
|
||
When `caveats` is a Ruby block, evaluation is deferred until install time. Within a block you may refer to the `@cask` instance variable, and invoke [any method available on `@cask`](/rubydoc/Cask/Cask.html).
|
||
|
||
#### `caveats` mini-DSL
|
||
|
||
There is a mini-DSL available within `caveats` blocks.
|
||
|
||
The following methods may be called to generate standard warning messages:
|
||
|
||
| method | description |
|
||
| ---------------------------------- | ----------- |
|
||
| `path_environment_variable "path"` | Users should make sure `path` is in their `PATH` environment variable. |
|
||
| `zsh_path_helper "path"` | `zsh` users must take additional steps to make sure `path` is in their `PATH` environment variable. |
|
||
| `depends_on_java "version"` | Users should make sure they have the specified version of Java installed. `version` can be exact (e.g. `6`), a minimum (e.g. `7+`), or omitted (when any version works). |
|
||
| `requires_rosetta` | The cask requires Rosetta 2 for it to run on Apple Silicon. |
|
||
| `logout` | Users should log out and log back in to complete installation. |
|
||
| `reboot` | Users should reboot to complete installation. |
|
||
| `files_in_usr_local` | The cask installs files to `/usr/local`, which may confuse Homebrew. |
|
||
| `kext` | Users may need to enable their kexts in *System Settings → Privacy & Security*. |
|
||
| `unsigned_accessibility` | Users will need to re-enable the app on each update in *System Settings → Privacy & Security* (or *System Preferences → Security & Privacy → Privacy* in earlier macOS versions) as it is unsigned. |
|
||
| `license "web_page"` | Users may find the software's usage licence at `web_page`. |
|
||
| `free_license "web_page"` | Users may obtain an official licence to use the software at `web_page`. |
|
||
|
||
Example:
|
||
|
||
```ruby
|
||
caveats do
|
||
path_environment_variable "/usr/texbin"
|
||
end
|
||
```
|
||
|
||
### Stanza: `conflicts_with`
|
||
|
||
`conflicts_with` is used to declare conflicts that prevent a cask from installing or working correctly.
|
||
|
||
#### `conflicts_with` *cask*
|
||
|
||
The value should be another cask token.
|
||
|
||
Example: [macFUSE](https://github.com/Homebrew/homebrew-cask/blob/aa461148bbb5119af26b82cccf5003e2b4e50d95/Casks/m/macfuse.rb#L17), which conflicts with `macfuse-dev`.
|
||
|
||
```ruby
|
||
conflicts_with cask: "macfuse-dev"
|
||
```
|
||
|
||
### Stanza: `depends_on`
|
||
|
||
`depends_on` is used to declare dependencies and requirements for a cask. `depends_on` is not consulted until `install` is attempted.
|
||
|
||
| key | description |
|
||
| ---------------- | ----------- |
|
||
| `cask:` | required Homebrew cask tokens as string or array |
|
||
| `formula:` | required Homebrew formula names as string or array |
|
||
| `macos:` | minimum macOS release as a symbol, or an array of exact acceptable releases; the older string comparison form is deprecated |
|
||
| `maximum_macos:` | maximum macOS release requirement using a `<=` comparison |
|
||
| `linux:` | Linux requirement, expressed as `depends_on :linux` |
|
||
| `arch:` | hardware requirements as symbol or array |
|
||
|
||
#### `depends_on` *cask*
|
||
|
||
The value should be one or more tokens of casks needed by the current cask, as a string or array of strings.
|
||
|
||
Example: [NTFSTool](https://github.com/Homebrew/homebrew-cask/blob/aa461148bbb5119af26b82cccf5003e2b4e50d95/Casks/n/ntfstool.rb#L11), which depends on macFUSE.
|
||
|
||
```ruby
|
||
depends_on cask: "macfuse"
|
||
```
|
||
|
||
#### `depends_on` *formula*
|
||
|
||
The value should be one or more names of formulae needed by the current cask, as a string or array of strings.
|
||
|
||
Example: some distributions are contained in archive formats such as `7z` which are not supported by stock Apple tools. For these cases, a more capable archive reader may be pulled in at install time by declaring a dependency on the `unar` formula:
|
||
|
||
```ruby
|
||
depends_on formula: "unar"
|
||
```
|
||
|
||
#### `depends_on` *macos*
|
||
|
||
##### Setting a minimum macOS release
|
||
|
||
Top-level `depends_on :macos` marks a cask as macOS-only. Top-level `depends_on macos:` marks a cask as macOS-only and declares the minimum compatible macOS release. The values for supported macOS releases can be found in the [`MacOSVersion` class](/rubydoc/MacOSVersion.html) documentation.
|
||
|
||
Only major releases are covered (10.x numbers containing a single dot or whole numbers since macOS 11). The symbol form is used for readability:
|
||
|
||
```ruby
|
||
depends_on macos: :big_sur
|
||
```
|
||
|
||
`depends_on macos:` still accepts a string starting with a comparison operator such as `>=`, followed by a macOS release in the form above. The following is a valid expression meaning “at least macOS Big Sur (11.0)”:
|
||
|
||
```ruby
|
||
depends_on macos: ">= :big_sur"
|
||
```
|
||
|
||
Use `==` in the string form only when a cask must run on one exact macOS release. An array of symbols is also accepted when a cask must run on one of an exact set of macOS releases:
|
||
|
||
```ruby
|
||
depends_on macos: [
|
||
:catalina,
|
||
:big_sur,
|
||
]
|
||
```
|
||
|
||
Top-level `depends_on maximum_macos:` marks a cask as macOS-only and declares the newest compatible macOS release:
|
||
|
||
```ruby
|
||
depends_on maximum_macos: :ventura
|
||
```
|
||
|
||
For a cask that supports both macOS and Linux but needs a specific macOS version, put the macOS version requirement inside `on_macos`:
|
||
|
||
```ruby
|
||
on_macos do
|
||
depends_on macos: :big_sur
|
||
end
|
||
```
|
||
|
||
#### `depends_on` *linux*
|
||
|
||
Top-level `depends_on :linux` marks a cask as Linux-only.
|
||
|
||
#### `depends_on` *arch*
|
||
|
||
The value for `depends_on arch:` may be a symbol or an array of symbols, listing the hardware compatibility requirements for a cask. The requirement is satisfied at install time if any one of the provided `arch:` values matches the user’s hardware.
|
||
|
||
The available symbols for hardware are:
|
||
|
||
| symbol | meaning |
|
||
| ---------- | ------- |
|
||
| `:arm64` | Apple Silicon |
|
||
| `:x86_64` | 64-bit Intel |
|
||
| `:intel` | 64-bit Intel |
|
||
|
||
The following are all valid expressions:
|
||
|
||
```ruby
|
||
depends_on arch: :arm64
|
||
depends_on arch: :intel
|
||
depends_on arch: :x86_64 # same meaning as above
|
||
depends_on arch: [:x86_64] # same meaning as above
|
||
```
|
||
|
||
### Stanza: `deprecate!` / `disable!`
|
||
|
||
`deprecate!` and `disable!` are used to declare that a cask is no longer functional or supported.
|
||
Casks that contain a `deprecate!` stanza can still be installed, but will print a warning message when they are installed or upgraded.
|
||
Casks that contain a `disable!` stanza cannot be installed or upgraded and will print an error message.
|
||
|
||
The syntax for both stanzas is the same:
|
||
|
||
```ruby
|
||
deprecate! date: "YYYY-MM-DD", because: "is ..."
|
||
disable! date: "YYYY-MM-DD", because: "is ..."
|
||
|
||
# Or with a preset reason and suggested replacement (see the parameter sections below)
|
||
deprecate! date: "YYYY-MM-DD", because: :discontinued, replacement_formula: "another"
|
||
disable! date: "YYYY-MM-DD", because: :unmaintained, replacement_cask: "alternative"
|
||
```
|
||
|
||
#### `date:` parameter
|
||
|
||
The `date:` parameter controls when the deprecation or disabling will take effect.
|
||
Casks that have a `deprecate!` stanza with a date in the future will not be treated as being deprecated until that date.
|
||
Casks that have a `disable!` stanza with a date in the future will be automatically deprecated until that date, at which point they will become disabled.
|
||
|
||
#### `because:` parameter
|
||
|
||
The `because:` parameter accepts a reason for the cask being deprecated or disabled.
|
||
The info message will be `<cask> is deprecated because it <reason>!`, so format the reason to fit that sentence.
|
||
For example, `because: "is broken"` will result in `<cask> is deprecated because it is broken!`.
|
||
|
||
The `because:` parameter can also accept a symbol that corresponds to a preset reason, for example:
|
||
|
||
```ruby
|
||
deprecate! date: "YYYY-MM-DD", because: :discontinued
|
||
```
|
||
|
||
A complete list of allowable symbols can be found in the [`DeprecateDisable` module](/rubydoc/DeprecateDisable.html) documentation.
|
||
|
||
#### `replacement_formula:` / `replacement_cask:` parameter
|
||
|
||
The `replacement_formula:` and `replacement_cask:` parameters accept a string for suggesting a replacement formula or cask to the user.
|
||
|
||
Refer to [Deprecating, Disabling and Removing](Deprecating-Disabling-and-Removing.md) for more information about the deprecation process for casks and Homebrew code.
|
||
|
||
### Stanza: `desc`
|
||
|
||
`desc` accepts a single-line UTF-8 string containing a short description of the software. As it’s used to help with searchability and disambiguation, it must concisely describe what the software does (or what you can accomplish with it).
|
||
|
||
`desc` is not for app slogans! Vendors’ descriptions tend to be filled with generic adjectives such as “modern” and “lightweight”. Those are meaningless marketing fluff (do you ever see apps proudly describing themselves as outdated and bulky?) which must be deleted. It’s fine to use the information on the software’s website as a starting point, but it will require editing in almost all cases.
|
||
|
||
#### Dos and don'ts
|
||
|
||
* **Do** start with an uppercase letter.
|
||
|
||
```diff
|
||
- desc "sound and music editor"
|
||
+ desc "Sound and music editor"
|
||
```
|
||
|
||
* **Do** be brief, i.e. use less than 80 characters.
|
||
|
||
```diff
|
||
- desc "Sound and music editor which comes with effects, instruments, sounds and all kinds of creative features"
|
||
+ desc "Sound and music editor"
|
||
```
|
||
|
||
* **Do** describe what the software does or is.
|
||
|
||
```diff
|
||
- desc "Development of musical ideas made easy"
|
||
+ desc "Sound and music editor"
|
||
```
|
||
|
||
* **Do not** include the platform. Platform compatibility belongs in the cask's requirements rather than its description.
|
||
|
||
```diff
|
||
- desc "Sound and music editor for macOS"
|
||
+ desc "Sound and music editor"
|
||
```
|
||
|
||
* **Do not** include the cask’s [name](#stanza-name).
|
||
|
||
```diff
|
||
- desc "Ableton Live is a sound and music editor"
|
||
+ desc "Sound and music editor"
|
||
```
|
||
|
||
* **Do not** include the vendor. This should be added to the cask’s [name](#stanza-name) instead.
|
||
|
||
```diff
|
||
- desc "Sound and music editor made by Ableton"
|
||
+ desc "Sound and music editor"
|
||
```
|
||
|
||
* **Do not** add user pronouns.
|
||
|
||
```diff
|
||
- desc "Edit your music files"
|
||
+ desc "Sound and music editor"
|
||
```
|
||
|
||
* **Do not** use empty marketing jargon.
|
||
|
||
```diff
|
||
- desc "Beautiful and powerful modern sound and music editor"
|
||
+ desc "Sound and music editor"
|
||
```
|
||
|
||
### Stanza: `*flight_steps`
|
||
|
||
The stanzas `preflight_steps`, `postflight_steps`, `uninstall_preflight_steps` and `uninstall_postflight_steps` define operations to be run before or after installation or uninstallation. Casks in official Homebrew taps must use these structured stanzas; legacy Ruby flight blocks are rejected. The legacy forms remain available temporarily for third-party tap compatibility.
|
||
|
||
These steps are stored in the JSON API and avoid loading cask Ruby.
|
||
|
||
```ruby
|
||
preflight_steps do
|
||
mkdir_p "Shared"
|
||
touch "Shared/state"
|
||
end
|
||
|
||
postflight_steps do
|
||
move "payload", "Shared/payload"
|
||
symlink "Shared/payload", "Payload", source_base: :relative
|
||
set_permissions "Shared/payload", "0755"
|
||
end
|
||
|
||
uninstall_postflight_steps do
|
||
delete_keychain_certificates "Charles"
|
||
delete_keychain_certificates "NodeMITMProxyCA",
|
||
fingerprint_of: "~/Library/Application Support/betwixt/ssl/certs/ca.pem"
|
||
end
|
||
```
|
||
|
||
A steps block may only contain supported step calls with literal arguments; it cannot call the wider cask DSL or arbitrary Ruby code.
|
||
|
||
#### File preparation steps
|
||
|
||
Relative paths default to `staged_path` for `base:`, `source_base:` and `target_base:`. Symlink steps can use `remove_on_uninstall: true` to remove the symlink during uninstall.
|
||
|
||
{% raw %}
|
||
|
||
* `mkdir_p`: create a directory and any missing parents; example: `mkdir_p "Shared"`.
|
||
* `touch`: create or update a file timestamp; example: `touch "Shared/state"`.
|
||
* `move`: move one file or directory; example: `move "payload", "Shared/payload"`.
|
||
* `move_contents`: move the contents of one directory into another; example: `move_contents "payload", "Shared/payload"`.
|
||
* `copy`: copy a file or, with `recursive: true`, a directory; example: `copy "payload", "Shared/payload"`.
|
||
* `remove`: remove one or more paths; example: `remove ["Shared/old", "Shared/*.bak"], recursive: true`.
|
||
* `inreplace`: replace a string or regular expression in a file; example: `inreplace "Shared/foo.conf", "@PREFIX@", "{{HOMEBREW_PREFIX}}"`.
|
||
* `symlink`: create a symlink; example: `symlink "Shared/payload", "Payload", source_base: :relative`.
|
||
* `write_file`: atomically write literal content, replacing an existing file by default; pass `append_newline: true` to ensure a trailing newline or `overwrite: false` to preserve it; example: `write_file "Shared/foo.conf", "key = value\n"`.
|
||
* `delete_keychain_certificates`: delete macOS keychain certificates whose common name matches the argument; example: `delete_keychain_certificates "Charles"`. Pass `fingerprint_of:` with a local certificate path to delete only the matching SHA-256 fingerprint; example:
|
||
`delete_keychain_certificates "NodeMITMProxyCA", fingerprint_of: "~/Library/Application Support/betwixt/ssl/certs/ca.pem"`.
|
||
* `set_permissions`: recursively change existing path permissions with `chmod`; example: `set_permissions "Shared/payload", "0755"`.
|
||
* `set_ownership`: recursively change existing path ownership with `sudo chown`; example: `set_ownership "Shared/payload", user: "root", group: "wheel"`. Missing paths are ignored. When `user:` is omitted, the current user is used. When `group:` is omitted, `staff` is used.
|
||
* `run`: run one executable with literal arguments; example: `run "Example.app/Contents/MacOS/helper", args: ["--repair"], base: :appdir`.
|
||
* `terminate_process`: terminate a process by name; example: `terminate_process "Example"`. It supports `match: :full`, a total `attempts:` count, `notices:` shown before the first attempt and a `failure_message:` warning. Failure is ignored by default; pass `must_succeed: true` when it should abort.
|
||
* `change_dylib_id`: change one Mach-O dynamic library ID; pass the complete source and new ID, use `resolve_source: true` for a source symlink and wrap the step in `on_macos`.
|
||
|
||
`move` and `copy` replace an existing target by default, matching the corresponding file helpers; pass `overwrite: false` to reject replacement. `symlink` preserves an existing target by default, so pass `overwrite: true` when replacement is intentional. `copy`, `move` and symlink steps accept `source_glob: true`; path collections used by `remove`, `set_permissions` and `set_ownership` expand globs automatically. Symlink removal matches the serialised source during uninstall, while `remove` can restrict removal with `symlink_target_contains:` or `content_contains:` and accepts `sudo: true` or `sudo: :if_needed`.
|
||
|
||
Use `if_path_exists`, `unless_path_exists`, `on_macos` and `on_linux` blocks to guard one or more steps. A condition is evaluated once when its scope begins, so related steps make the same decision. Use `unless_path_exists` around `write_file` when an existing file must be preserved.
|
||
|
||
`run` does not evaluate a shell command string. It supports a literal `env:`, `stdin_path:`, `stdout_path:`, `chdir:` and `sudo:`. Standard output is hidden by default and standard error is printed; use `print_stdout: true` or `print_stderr: false` to change that behaviour. Failure aborts the installation or uninstallation; pass `must_succeed: false` when a non-zero exit status is expected and should be ignored, such as a cleanup command that cannot run when its dependency is absent. Nothing is written to `stdout_path:` when an ignored command fails. The complete steps block runs in an isolated Ruby subprocess without network or general home-directory access where Homebrew has an available sandbox. Pass `network_access: true` when a `run` command must access the network. The sandbox permits writes to declared step destinations, the caskroom, app directory, temporary and cache directories and Homebrew's link directories. Ruby file operations and system or cask-provided commands therefore share the same restrictions. Use `writable_paths:` with directory roots, and `writable_base:` for relative roots, when an opaque command needs another declared write location.
|
||
|
||
#### Interpolation in steps blocks
|
||
|
||
Ruby `#{...}` interpolation is normally evaluated before structured steps are serialised. The Ruby expression does not pass through the JSON API; only the string it produced does. A concrete result is safe only when it is identical for every installation represented by the JSON. RuboCop cannot generally establish that from arbitrary Ruby, so use interpolation in ordinary cask stanzas, for example `command_wrapper "example", executable: "#{appdir}/Example.app/Contents/MacOS/example"`.
|
||
|
||
`{{...}}` is not Ruby interpolation. It remains literal in the JSON API and the install-step runner expands supported tokens at install time. Use this form for install-time values inside `preflight_steps`, `postflight_steps`, `uninstall_preflight_steps` and `uninstall_postflight_steps`. When a path argument supports `base:`, `source_base:` or `target_base:`, prefer those options to embedding a path token.
|
||
|
||
The runtime steps DSL retains compatibility helpers for `token`, `name`, `version`, `version.major` and `version.major_minor`. Interpolating these helpers is safe and permitted by RuboCop because they return the corresponding `{{...}}` token text rather than a concrete value. Other Ruby interpolation is rejected. Prefer explicit `{{...}}` tokens in new steps so it is clear that expansion is deferred until installation.
|
||
|
||
Content, replacements, command arguments and command environments may use fixed install-time tokens. These include `{{HOMEBREW_BREW_FILE}}`, `{{HOMEBREW_CELLAR}}`, `{{HOMEBREW_PREFIX}}`, `{{token}}`, `{{name}}`, `{{user}}`, `{{staged_path}}`, `{{appdir}}`, `{{caskroom_path}}`, `{{temp}}`, `{{version}}`, `{{version.major}}` and `{{version.major_minor}}`. `{{name}}` is retained for compatibility; prefer `{{token}}`. Any other `{{...}}` is left verbatim. For example: `write_file "settings.conf", "application = {{appdir}}/Example.app"`.
|
||
|
||
{% endraw %}
|
||
|
||
### Stanza: `generate_completions_from_executable`
|
||
|
||
`generate_completions_from_executable` runs an installed executable at cask install time to produce shell completion scripts for shells. The first argument is the path to the executable (relative to the cask's staged directory, or absolute). Any further positional arguments are subcommands passed to it.
|
||
|
||
```ruby
|
||
generate_completions_from_executable "My App.app/Contents/MacOS/my-app", "completions"
|
||
```
|
||
|
||
The optional keyword arguments are:
|
||
|
||
| argument | description |
|
||
| -------- | ----------- |
|
||
| `shells:` | Array of shells to generate completions for. Defaults to `[:bash, :zsh, :fish]`. Use `[:bash, :zsh, :fish, :pwsh]` to include PowerShell. |
|
||
| `base_name:` | Base filename for the generated completion scripts. Defaults to the basename of the executable, or the cask token if the basename is empty. |
|
||
| `shell_parameter_format:` | How the shell name is passed to the executable. Defaults to passing it as a plain positional argument. See the table below for accepted values. |
|
||
|
||
| `shell_parameter_format:` value | shell argument passed |
|
||
| ------------------------------- | --------------------- |
|
||
| _(omitted)_ | shell name as a plain argument (`bash`, `zsh`, etc.) |
|
||
| `:arg` | `--shell=<shell>` |
|
||
| `:clap` | sets `COMPLETE=<shell>` env var; no argument |
|
||
| `:click` | sets `_<PROGNAME>_COMPLETE=<shell>_source` env var; no argument |
|
||
| `:cobra` | `completion <shell>`; also enables `:pwsh` by default |
|
||
| `:flag` | `--<shell>` |
|
||
| `:none` | no argument |
|
||
| `:typer` | `--show-completion <shell>`; also enables `:pwsh` by default |
|
||
| `"<prefix>"` (custom string) | prefix concatenated with the shell name |
|
||
|
||
```ruby
|
||
generate_completions_from_executable "My App.app/Contents/MacOS/my-app",
|
||
shell_parameter_format: :cobra,
|
||
base_name: "my-app"
|
||
```
|
||
|
||
### Stanza: `installer`
|
||
|
||
This stanza must always be accompanied by [`uninstall`](#stanza-uninstall).
|
||
|
||
The `installer` stanza takes a series of key-value pairs, the first key of which must be `manual:` or `script:`.
|
||
|
||
#### `installer` *manual*
|
||
|
||
`installer manual:` takes a single string value for the path to an interactive installer which must be run by the user at a later time. The path may be absolute, or relative to the cask. Example (from [rubymotion.rb](https://github.com/Homebrew/homebrew-cask/blob/aa461148bbb5119af26b82cccf5003e2b4e50d95/Casks/r/rubymotion.rb#L15)):
|
||
|
||
```ruby
|
||
installer manual: "RubyMotion Installer.app"
|
||
```
|
||
|
||
#### `installer` *script*
|
||
|
||
`installer script:` takes a series of key-value pairs describing a command which will automate completion of the install. **It should never be used for interactive installations.** The form is similar to [`uninstall script:`](#uninstall-script):
|
||
|
||
| key | value |
|
||
| --------------- | ----- |
|
||
| `executable:` | path to an install script to be run |
|
||
| `args:` | array of arguments to the install script |
|
||
| `input:` | array of lines of input to be sent to `stdin` of the script |
|
||
| `must_succeed:` | set to `false` if the script is allowed to fail |
|
||
| `print_stderr:` | set to `false` to suppress `stderr` output |
|
||
| `print_stdout:` | set to `false` to suppress `stdout` output |
|
||
| `sudo:` | set to `true` if the script needs *sudo* |
|
||
|
||
Installer scripts run without the cask sandbox. Use them only when the vendor provides an installer command that cannot be represented by a more specific artifact stanza such as [`app`](#stanza-app) or [`pkg`](#stanza-pkg).
|
||
|
||
The path may be absolute, or relative to the cask. Example (from [miniforge.rb](https://github.com/Homebrew/homebrew-cask/blob/864f623e2cd17dbde5987a7b3923fdb0b4ac9ee5/Casks/m/miniforge.rb#L23-L26)):
|
||
|
||
```ruby
|
||
installer script: {
|
||
executable: "Miniforge3-#{version}-MacOSX-x86_64.sh",
|
||
args: ["-b", "-p", "#{caskroom_path}/base"],
|
||
}
|
||
```
|
||
|
||
If the `installer script:` does not require any of the key-value pairs, it can be given just the path to the install script:
|
||
|
||
```ruby
|
||
installer script: "#{staged_path}/install.sh"
|
||
```
|
||
|
||
### Stanza: `language`
|
||
|
||
The `language` stanza can match [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) language codes, script codes ([ISO 15924](https://en.wikipedia.org/wiki/ISO_15924)) and regional identifiers ([ISO 3166-1 Alpha 2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2)), or a combination thereof.
|
||
|
||
US English should always be used as the default language:
|
||
|
||
```ruby
|
||
language "zh", "CN" do
|
||
"zh_CN"
|
||
end
|
||
|
||
language "de" do
|
||
"de_DE"
|
||
end
|
||
|
||
language "en-GB" do
|
||
"en_GB"
|
||
end
|
||
|
||
language "en", default: true do
|
||
"en_US"
|
||
end
|
||
```
|
||
|
||
Note that the following are not the same:
|
||
|
||
```ruby
|
||
language "en", "GB" do
|
||
# matches all locales containing "en" or "GB"
|
||
end
|
||
|
||
language "en-GB" do
|
||
# matches only locales containing "en" and "GB"
|
||
end
|
||
```
|
||
|
||
The return value of the matching `language` block can be accessed by simply calling `language`.
|
||
|
||
```ruby
|
||
homepage "https://example.org/#{language}"
|
||
```
|
||
|
||
The JSON API stores the return value and resulting stanza changes for every language block.
|
||
API installs select the matching snapshot from the preferred locales, falling back to the declared default, without evaluating the cask's Ruby source.
|
||
|
||
Examples: [firefox.rb](https://github.com/Homebrew/homebrew-cask/blob/939b4331dc2a6860350d66a1b2c7b3f22442cc08/Casks/f/firefox.rb#L4-L207), [battle-net.rb](https://github.com/Homebrew/homebrew-cask/blob/e039d079560cf2f77b671f7dda4752a053341180/Casks/b/battle-net.rb#L5-L10)
|
||
|
||
#### Installation
|
||
|
||
To install a cask in a specific language, you can pass the `--language=` option to `brew install`:
|
||
|
||
```bash
|
||
brew install firefox --language=it
|
||
```
|
||
|
||
### Stanza: `livecheck`
|
||
|
||
The `livecheck` stanza is used to automatically fetch the latest version of a cask from changelogs, release notes, appcasts, etc.
|
||
|
||
Every `livecheck` block must contain a `url`, which can be either a string or a symbol pointing to other URLs in the cask (`:url` or `:homepage`).
|
||
|
||
Refer to the [`brew livecheck`](Brew-Livecheck.md) documentation for how to write a `livecheck` block.
|
||
|
||
### Stanza: `no_autobump!`
|
||
|
||
The `no_autobump!` stanza excludes a cask from the autobump list. This means all updates are to be handled manually by submitting pull requests to the `Homebrew/homebrew-cask` repository.
|
||
|
||
`no_autobump!` requires a reason to be provided with the `because:` parameter. It accepts a string or a symbol that corresponds to a preset reason, for example:
|
||
|
||
```ruby
|
||
no_autobump! because: :incompatible_version_format
|
||
```
|
||
|
||
A complete list of allowed symbols can be found in [`NO_AUTOBUMP_REASONS_LIST`](/rubydoc/top-level-namespace.html#NO_AUTOBUMP_REASONS_LIST-constant).
|
||
|
||
Casks that use `strategy :extract_plist` in their `livecheck` block or have `version :latest` are always excluded from the autobump list and do not require `no_autobump!` to be declared.
|
||
|
||
Refer to the [Autobump](Autobump.md) page for more information about the autobump process in Homebrew.
|
||
|
||
### Stanza: `name`
|
||
|
||
`name` accepts a UTF-8 string defining the name of the software, including capitalisation and punctuation. It is used to help with searchability and disambiguation.
|
||
|
||
Unlike the [token](#token-reference), which is simplified and reduced to a limited set of characters, the `name` stanza can include the proper capitalisation, spacing and punctuation to match the official name of the software. For disambiguation purposes, it is recommended to spell out the name of the application, including the vendor name if necessary. A good example is the [`pycharm-ce`](https://github.com/Homebrew/homebrew-cask/blob/aa461148bbb5119af26b82cccf5003e2b4e50d95/Casks/p/pycharm-ce.rb#L9-L10) cask, whose name is spelled out as `Jetbrains PyCharm Community Edition`, even though it is likely never referenced as such anywhere.
|
||
|
||
Additional details about the software can be provided in the [`desc`](#stanza-desc) stanza.
|
||
|
||
The `name` stanza can be repeated multiple times if there are useful alternative names. The first instance should use the Latin alphabet. For example, see the [`cave-story`](https://github.com/Homebrew/homebrew-cask/blob/aa461148bbb5119af26b82cccf5003e2b4e50d95/Casks/c/cave-story.rb#L58-L60) cask, whose original name does not use the Latin alphabet.
|
||
|
||
### Stanza: `pkg`
|
||
|
||
This stanza must always be accompanied by [`uninstall`](#stanza-uninstall).
|
||
|
||
The first argument to the `pkg` stanza should be a relative path to the `.pkg` file to be installed. Example:
|
||
|
||
```ruby
|
||
pkg "Unity.pkg"
|
||
```
|
||
|
||
Subsequent arguments to `pkg` are key-value pairs which modify the install process. The only currently supported key is `choices:`.
|
||
|
||
#### `pkg` *choices*
|
||
|
||
`pkg choices:` can be used to override a `.pkg`’s default install options via `-applyChoiceChangesXML`. It uses a deserialised version of the `choiceChanges` property list (refer to the `CHOICE CHANGES FILE` section of the `installer` manual page by running `man -P 'less --pattern "^CHOICE CHANGES FILE"' installer`).
|
||
|
||
Running this macOS `installer` command:
|
||
|
||
```bash
|
||
installer -showChoicesXML -pkg '/path/to/my.pkg'
|
||
```
|
||
|
||
will output XML that you can use to extract the `choices:` values, as well as their equivalents to the GUI options.
|
||
|
||
See [this pull request for wireshark-chmodbpf](https://github.com/Homebrew/homebrew-cask/pull/26997) and [this one for wine-staging](https://github.com/Homebrew/homebrew-cask/pull/27937) for some examples of the procedure.
|
||
|
||
Example (from [lando.rb](https://github.com/Homebrew/homebrew-cask/blob/aa461148bbb5119af26b82cccf5003e2b4e50d95/Casks/l/lando.rb#L21-L33)):
|
||
|
||
```ruby
|
||
pkg "LandoInstaller.pkg",
|
||
choices: [
|
||
{
|
||
"choiceIdentifier" => "choiceDocker",
|
||
"choiceAttribute" => "selected",
|
||
"attributeSetting" => 0,
|
||
},
|
||
{
|
||
"choiceIdentifier" => "choiceLando",
|
||
"choiceAttribute" => "selected",
|
||
"attributeSetting" => 1,
|
||
},
|
||
]
|
||
```
|
||
|
||
Example (from [microsoft-office.rb](https://github.com/Homebrew/homebrew-cask/blob/56cabc6cec8be8f8a2fd06bc0b88f851d3b075d7/Casks/m/microsoft-office.rb#L30-L37)):
|
||
|
||
```ruby
|
||
pkg "Microsoft_365_and_Office_#{version}_Installer.pkg",
|
||
choices: [
|
||
{
|
||
"choiceIdentifier" => "com.microsoft.autoupdate", # Office16_all_autoupdate.pkg
|
||
"choiceAttribute" => "selected",
|
||
"attributeSetting" => 0,
|
||
},
|
||
]
|
||
```
|
||
|
||
### Stanza: `sha256`
|
||
|
||
#### Calculating the SHA-256
|
||
|
||
The `sha256` value is usually calculated by the `shasum` command:
|
||
|
||
```bash
|
||
shasum --algorithm 256 <file>
|
||
```
|
||
|
||
#### Special value `:no_check`
|
||
|
||
The special value `sha256 :no_check` is used to turn off SHA checking whenever checksumming is impractical due to the upstream configuration, e.g. when `url` does not change between releases.
|
||
|
||
`sha256 :no_check` is required by [`version :latest`](#special-value-latest), and this pairing is common. However, `sha256 :no_check` does not require `version :latest`.
|
||
|
||
We use a checksum whenever possible.
|
||
|
||
### Stanza: `suite`
|
||
|
||
Some distributions provide a suite of multiple applications, or an application with required data, to be installed together in a subdirectory of `/Applications`.
|
||
|
||
For these casks, use the `suite` stanza to define the directory containing the application suite. Example (from [racket.rb](https://github.com/Homebrew/homebrew-cask/blob/e65e45e94d27d14a78e1bd02b584b0c89c8f9e8b/Casks/r/racket.rb#L18)):
|
||
|
||
```ruby
|
||
suite "Racket v#{version}"
|
||
```
|
||
|
||
The value of `suite` is never an `.app` bundle, but a plain directory.
|
||
|
||
### Stanza: `uninstall`
|
||
|
||
> If you cannot design a working `uninstall` stanza, please submit your cask anyway. The maintainers can help you write an `uninstall` stanza, just ask!
|
||
|
||
#### `uninstall` is required for casks that install using `pkg` or `installer`
|
||
|
||
For most casks, uninstall actions are determined automatically, and an explicit `uninstall` stanza is not needed. However, a cask which uses the [`pkg`](#stanza-pkg) or [`installer`](#stanza-installer) stanzas will **not** know how to uninstall correctly unless an `uninstall` stanza is given.
|
||
|
||
So, while the [cask DSL](#required-stanzas) does not enforce the requirement, it is much better for users if every `pkg` and `installer` has a corresponding `uninstall`.
|
||
|
||
The `uninstall` stanza is available for other artifact types, and is useful for a few corner cases. However, the documentation below concerns the typical case of using `uninstall` to define procedures for a `pkg`.
|
||
|
||
#### There are multiple uninstall techniques
|
||
|
||
Since `pkg` installers can do arbitrary things, different techniques are needed to uninstall in each case. You may need to specify one, or several, of the following key-value pairs as arguments to `uninstall`.
|
||
|
||
##### `uninstall pkgutil:` is the easiest and most useful
|
||
|
||
The easiest and most useful `uninstall` directive is [`pkgutil:`](#uninstall-pkgutil). It should cover most use cases.
|
||
|
||
#### Summary of keys
|
||
|
||
* **`early_script:`** (string or hash) - like [`script:`](#uninstall-script), but runs early (for special cases, best avoided)
|
||
* [`launchctl:`](#uninstall-launchctl) (string or array) - IDs of `launchd` jobs to remove
|
||
* [`quit:`](#uninstall-quit) (string or array) - bundle IDs of running applications to quit
|
||
* [`signal:`](#uninstall-signal) (array of arrays) - signal numbers and bundle IDs of running applications to send a Unix signal to, for when `quit:` does not work (does not run when uninstall is initiated by `brew upgrade` or `brew reinstall` unless specified in `on_upgrade:`)
|
||
* **`on_upgrade:`** (symbol or array) - set to `:signal` (or `[:signal]`) to also run the `signal:` directive during `brew upgrade` and `brew reinstall`
|
||
* [`login_item:`](#uninstall-login_item) (string or array) - names of login items to remove
|
||
* [`kext:`](#uninstall-kext) (string or array) - bundle IDs of kexts to unload from the system
|
||
* [`script:`](#uninstall-script) (string or hash) - relative path to an uninstall script; use a hash to provide arguments or request `sudo: true`
|
||
* [`pkgutil:`](#uninstall-pkgutil) (string, regexp or array of strings and regexps) - strings or regexps matching bundle IDs of packages to uninstall using `pkgutil`
|
||
* [`delete:`](#uninstall-delete) (string or array) - double-quoted, absolute paths of files or directory trees to remove. Should only be used as a last resort; `pkgutil:` is strongly preferred.
|
||
* [`trash:`](#uninstall-trash) (string or array) - double-quoted, absolute paths of files or directory trees to move to Trash
|
||
* **`rmdir:`** (string or array) - double-quoted, absolute paths of directories to remove if empty; works recursively
|
||
|
||
Each `uninstall` technique is applied according to the order above. The order in which `uninstall` keys appear in the cask file is ignored.
|
||
|
||
For assistance filling in the right values for `uninstall` keys, there are several helper [commands found under `cmd`](https://github.com/Homebrew/homebrew-cask/tree/HEAD/cmd) and [scripts found under `developer/bin`](https://github.com/Homebrew/homebrew-cask/tree/HEAD/developer/bin) in the `homebrew/cask` repository. Many support `--help` (or otherwise print usage) with additional documentation.
|
||
|
||
Working out an `uninstall` stanza is easiest when done on a system where the package is currently installed and operational. To operate on an uninstalled `.pkg` file, see [Working with a `.pkg` file manually](#working-with-a-pkg-file-manually), below.
|
||
|
||
#### `uninstall` *pkgutil*
|
||
|
||
This is the most useful uninstall key. `pkgutil:` is often sufficient to completely uninstall a `pkg`, and is strongly preferred over `delete:`.
|
||
|
||
IDs for the most recently installed packages can be listed using [`brew list-recent-pkg-ids`](https://github.com/Homebrew/homebrew-cask/blob/HEAD/cmd/list-recent-pkg-ids.rb):
|
||
|
||
```bash
|
||
brew list-recent-pkg-ids
|
||
```
|
||
|
||
`pkgutil:` also accepts a regular expression to match against multiple package IDs. The regular expressions are somewhat nonstandard. To test a `pkgutil:` regular expression against currently installed packages, use [`brew list-pkg-ids-by-regexp`](https://github.com/Homebrew/homebrew-cask/blob/HEAD/cmd/list-pkg-ids-by-regexp.rb):
|
||
|
||
```bash
|
||
brew list-pkg-ids-by-regexp <regular-expression>
|
||
```
|
||
|
||
#### List files associated with a package ID
|
||
|
||
Once you know the ID for an installed package (see above), you can list all files on your system associated with that package ID using the macOS `pkgutil` command:
|
||
|
||
```bash
|
||
pkgutil --files <package.id.goes.here>
|
||
```
|
||
|
||
Listing the associated files can help you assess whether the package included any `launchd` jobs or kernel extensions (kexts).
|
||
|
||
#### `uninstall` *launchctl*
|
||
|
||
IDs for currently loaded `launchd` jobs can be listed using [`brew list-loaded-launchjob-ids`](https://github.com/Homebrew/homebrew-cask/blob/HEAD/cmd/list-loaded-launchjob-ids.rb):
|
||
|
||
```bash
|
||
brew list-loaded-launchjob-ids
|
||
```
|
||
|
||
IDs for all installed `launchd` jobs can be listed using [`brew list-installed-launchjob-ids`](https://github.com/Homebrew/homebrew-cask/blob/HEAD/cmd/list-installed-launchjob-ids.rb):
|
||
|
||
```bash
|
||
brew list-installed-launchjob-ids
|
||
```
|
||
|
||
#### `uninstall` *quit*
|
||
|
||
`quit:` sends the standard macOS quit Apple Event to the application (equivalent to Cmd+Q), which allows the app to present save dialogs before closing. It runs during both `brew uninstall` and `brew upgrade`/`brew reinstall`.
|
||
|
||
Bundle IDs for currently running applications can be listed using [`brew list-running-app-ids`](https://github.com/Homebrew/homebrew-cask/blob/HEAD/cmd/list-running-app-ids.rb):
|
||
|
||
```bash
|
||
brew list-running-app-ids
|
||
```
|
||
|
||
Bundle IDs inside an application bundle on disk can be listed using [`brew list-ids-in-app`](https://github.com/Homebrew/homebrew-cask/blob/HEAD/cmd/list-ids-in-app.rb):
|
||
|
||
```bash
|
||
brew list-ids-in-app '/path/to/application.app'
|
||
```
|
||
|
||
#### `uninstall` *signal*
|
||
|
||
`signal:` should only be needed in the rare case that a process does not respond to `quit:`.
|
||
|
||
Bundle IDs for `signal:` targets may be obtained in the same way as for `quit:`. The value for `signal:` is an array of arrays, with each cell containing two elements: the desired Unix signal followed by the corresponding bundle ID.
|
||
|
||
The Unix signal may be given in numeric or string form (see the `kill`(1) man page for more details).
|
||
|
||
The elements of the `signal:` array are applied in order, only if there is an existing process associated the bundle ID, and stopping when that process terminates. A bundle ID may be repeated to send more than one signal to the same process.
|
||
|
||
It is better to use the least-severe signals that are sufficient to stop a process. The `KILL` signal in particular can have unwanted side effects.
|
||
|
||
An example, with commonly used signals in ascending order of severity:
|
||
|
||
```ruby
|
||
uninstall signal: [
|
||
["TERM", "fr.madrau.switchresx.daemon"],
|
||
["QUIT", "fr.madrau.switchresx.daemon"],
|
||
["INT", "fr.madrau.switchresx.daemon"],
|
||
["HUP", "fr.madrau.switchresx.daemon"],
|
||
["KILL", "fr.madrau.switchresx.daemon"],
|
||
]
|
||
```
|
||
|
||
Note that when multiple running processes match the given bundle ID, all matching processes will be signalled.
|
||
|
||
Unlike `quit:` directives, Unix signals originate from the current user, not from the superuser. This is construed as a safety feature, since the superuser is capable of bringing down the system via signals. However, this inconsistency could also be considered a bug, and may be addressed in some fashion in a future version.
|
||
|
||
`signal:` directives are skipped during `brew upgrade` and `brew reinstall`. To opt a cask into running this directive during an upgrade or reinstall, add `on_upgrade: :signal`:
|
||
|
||
```ruby
|
||
uninstall signal: [["TERM", "com.example.daemon"]],
|
||
on_upgrade: :signal
|
||
```
|
||
|
||
To run both `quit:` and `signal:` during an upgrade or reinstall:
|
||
|
||
```ruby
|
||
uninstall quit: "com.example.app",
|
||
signal: [["TERM", "com.example.app"]],
|
||
on_upgrade: :signal
|
||
```
|
||
|
||
#### `uninstall` *login_item*
|
||
|
||
Login items associated with an application bundle on disk can be listed using [`brew list-login-items-for-app`](https://github.com/Homebrew/homebrew-cask/blob/HEAD/cmd/list-login-items-for-app.rb):
|
||
|
||
```bash
|
||
brew list-login-items-for-app '/path/to/application.app'
|
||
```
|
||
|
||
Note that you will likely need to have opened the app at least once for any login items to be present.
|
||
|
||
#### `uninstall` *kext*
|
||
|
||
IDs for currently loaded kernel extensions can be listed using [`list_loaded_kext_ids`](https://github.com/Homebrew/homebrew-cask/blob/HEAD/developer/bin/list_loaded_kext_ids):
|
||
|
||
```bash
|
||
"$(brew --repository homebrew/cask)/developer/bin/list_loaded_kext_ids"
|
||
```
|
||
|
||
IDs inside a kext bundle on disk can be listed using [`list_id_in_kext`](https://github.com/Homebrew/homebrew-cask/blob/HEAD/developer/bin/list_id_in_kext):
|
||
|
||
```bash
|
||
"$(brew --repository homebrew/cask)/developer/bin/list_id_in_kext" '/path/to/name.kext'
|
||
```
|
||
|
||
#### `uninstall` *script*
|
||
|
||
`uninstall script:` introduces a series of key-value pairs describing a command which will automate completion of the uninstall. The form is similar to [`installer script:`](#installer-script):
|
||
|
||
| key | value |
|
||
| --------------- | ----- |
|
||
| `executable:` | path to an uninstall script to be run |
|
||
| `args:` | array of arguments to the uninstall script |
|
||
| `input:` | array of lines of input to be sent to `stdin` of the script |
|
||
| `must_succeed:` | set to `false` if the script is allowed to fail |
|
||
| `print_stderr:` | set to `false` to suppress `stderr` output |
|
||
| `print_stdout:` | set to `false` to suppress `stdout` output |
|
||
| `sudo:` | set to `true` if the script needs *sudo* |
|
||
|
||
The path may be absolute, or relative to the cask. Example (from [virtualbox.rb](https://github.com/Homebrew/homebrew-cask/blob/ef9931087f6e101262bf64119166e2d9cec068f0/Casks/v/virtualbox.rb#L55-L61)):
|
||
|
||
```ruby
|
||
uninstall script: {
|
||
executable: "VirtualBox_Uninstall.tool",
|
||
args: ["--unattended"],
|
||
sudo: true,
|
||
},
|
||
pkgutil: "org.virtualbox.pkg.*",
|
||
delete: "/usr/local/bin/vboximg-mount"
|
||
```
|
||
|
||
It is important to note that, although `script:` in the above example does attempt to completely uninstall the `pkg`, it should not be used in place of [`pkgutil:`](#uninstall-pkgutil), but as a complement when possible.
|
||
|
||
#### `uninstall` *delete*
|
||
|
||
`delete:` should only be used as a last resort, if other `uninstall` methods are insufficient.
|
||
|
||
Arguments to `uninstall delete:` should use the following basic rules:
|
||
|
||
* Basic tilde expansion is performed on paths, i.e. leading `~` is expanded to the home directory.
|
||
* Paths must be absolute.
|
||
* Glob expansion is performed using the [standard set of characters](https://en.wikipedia.org/wiki/Glob_(programming)).
|
||
|
||
To remove user-specific files, use the [`zap`](#stanza-zap) stanza.
|
||
|
||
#### `uninstall` *trash*
|
||
|
||
`trash:` arguments follow the same rules listed above for `delete:`.
|
||
|
||
#### Working with a `.pkg` file manually
|
||
|
||
Advanced users may wish to work with a `.pkg` file manually, without having the package installed.
|
||
|
||
A list of files which may be installed from a `.pkg` can be extracted using [`list_payload_in_pkg`](https://github.com/Homebrew/homebrew-cask/blob/HEAD/developer/bin/list_payload_in_pkg):
|
||
|
||
```bash
|
||
"$(brew --repository homebrew/cask)/developer/bin/list_payload_in_pkg" '/path/to/my.pkg'
|
||
```
|
||
|
||
Candidate application names helpful for determining the name of a cask may be extracted from a `.pkg` file using [`brew list-apps-in-pkg`](https://github.com/Homebrew/homebrew-cask/blob/HEAD/cmd/list-apps-in-pkg.rb):
|
||
|
||
```bash
|
||
brew list-apps-in-pkg '/path/to/my.pkg'
|
||
```
|
||
|
||
Candidate package IDs which may be useful in a `pkgutil:` key may be extracted from a `.pkg` file using [`brew list-ids-in-pkg`](https://github.com/Homebrew/homebrew-cask/blob/HEAD/cmd/list-ids-in-pkg.rb):
|
||
|
||
```bash
|
||
brew list-ids-in-pkg '/path/to/my.pkg'
|
||
```
|
||
|
||
A fully manual method for finding bundle IDs in a package file follows:
|
||
|
||
1. Unpack `/path/to/my.pkg` (replace with your package name) with `pkgutil --expand /path/to/my.pkg /tmp/expanded.unpkg`.
|
||
2. The unpacked package is a folder. Bundle IDs are contained within files named `PackageInfo`. These files can be found with the command `find /tmp/expanded.unpkg -name PackageInfo`.
|
||
3. `PackageInfo` files are XML files, and bundle IDs are found within the `identifier` attributes of `<pkg-info>` tags that look like `<pkg-info ... identifier="com.oracle.jdk7u51" ... >` (where extraneous attributes have been snipped out and replaced with ellipses).
|
||
4. Kexts inside packages are also described in `PackageInfo` files. If any kernel extensions are present, the command `find /tmp/expanded.unpkg -name PackageInfo -print0 | xargs -0 grep -i kext` should return a `<bundle id>` tag with a `path` attribute that contains a `.kext` extension, for example `<bundle id="com.wavtap.driver.WavTap" ... path="./WavTap.kext" ... />`.
|
||
5. Once bundle IDs have been identified, the unpacked package directory can be deleted.
|
||
|
||
### Stanza: `url`
|
||
|
||
#### HTTPS URLs are preferred
|
||
|
||
If available, an HTTPS URL is preferred. A plain HTTP URL should only be used in the absence of a secure alternative.
|
||
|
||
#### Additional `url` parameters
|
||
|
||
When a plain URL string is insufficient to fetch a file, additional information may be provided to the `curl`-based downloader, in the form of key-value pairs appended to `url`:
|
||
|
||
| key | value |
|
||
| ------------------ | ----- |
|
||
| `using:` | the symbols `:post` and `:homebrew_curl` are the only legal values |
|
||
| `cookies:` | hash of cookies to be set for the download request (Example: [oracle-jdk-javadoc.rb](https://github.com/Homebrew/homebrew-cask/blob/326c44e93aeb8d4dd73acea14a99ae215c75fdd6/Casks/o/oracle-jdk-javadoc.rb#L5-L8)) |
|
||
| `referer:` | string holding the URL to set as referer for the download request (Example: [firealpaca.rb](https://github.com/Homebrew/homebrew-cask/blob/c4b3f0742e044ae2a6e114eb6b90068763d0d12b/Casks/f/firealpaca.rb#L5-L6)) |
|
||
| `header:` | string or array of strings holding the header(s) to set for the download request (Example: [pull-6545](https://github.com/Homebrew/brew/pull/6545#issue-503302353), [issue-15590](https://github.com/Homebrew/brew/issues/15590#issue-1774825542)) |
|
||
| `user_agent:` | string holding the user agent to set for the download request. Can also be set to the symbol `:fake`, which will use a generic browser-like user agent string. We prefer `:fake` when the server does not require a specific user agent. |
|
||
| `data:` | hash of parameters to be set for a POST request (Example: [segger-jlink.rb](https://github.com/Homebrew/homebrew-cask/blob/38ac55614f146d68ae317594f0c119e9acbd7c9e/Casks/s/segger-jlink.rb#L6-L11)) |
|
||
|
||
#### Difficulty finding a URL
|
||
|
||
Web browsers may obscure the direct `url` of a download for a variety of reasons. The `homebrew/cask` repository provides a [`brew list-url-attributes-on-file`](https://github.com/Homebrew/homebrew-cask/blob/HEAD/cmd/list-url-attributes-on-file.rb) command which can read extended file attributes to extract the actual source URL of most files downloaded by a browser on macOS. The command usually emits multiple candidate URLs; you may have to test each of them:
|
||
|
||
```bash
|
||
brew list-url-attributes-on-file <file>
|
||
```
|
||
|
||
#### Subversion URLs
|
||
|
||
In rare cases, a distribution may not be available over ordinary HTTP(S). Subversion URLs are also supported, and can be specified by appending the following key-value pairs to `url`:
|
||
|
||
| key | value |
|
||
| ------------------ | ----- |
|
||
| `using:` | the symbol `:svn` is the only legal value |
|
||
| `revision:` | string identifying the Subversion revision to download |
|
||
| `trust_cert:` | set to `true` to automatically trust the certificate presented by the server (avoiding an interactive prompt) |
|
||
|
||
#### Git URLs
|
||
|
||
Artifacts may also be distributed via Git repositories. URLs that end in `.git` are automatically assumed to be Git repositories, and the following key-value pairs may be appended to `url`:
|
||
|
||
| key | value |
|
||
| ------------------ | ----- |
|
||
| `using:` | the symbol `:git` is the only legal value |
|
||
| `tag:` | string identifying the Git tag to download |
|
||
| `revision:` | string identifying the Git revision to download |
|
||
| `branch:` | string identifying the Git branch to download |
|
||
| `only_path:` | path within the repository to limit the checkout to. If only a single directory of a large repository is required, using this option can significantly speed up downloads. If provided, artifact paths are relative to this path. (Example: [font-geo.rb](https://github.com/Homebrew/homebrew-cask/blob/a6348a1710928bf43510098725c2068ffe3adc69/Casks/font/font-g/font-geo.rb#L5-L8)) |
|
||
|
||
#### SourceForge/OSDN URLs
|
||
|
||
SourceForge and OSDN (formerly `SourceForge.JP`) projects are common ways to distribute binaries, but they provide many different styles of URLs to get to the goods.
|
||
|
||
We prefer URLs of this format:
|
||
|
||
https://downloads.sourceforge.net/<project_name>/<filename>.<ext>
|
||
|
||
Or, if it’s from OSDN, where `<subdomain>` is typically of the form `dl` or `<user>.dl`:
|
||
|
||
http://<subdomain>.osdn.jp/<project_name>/<release_id>/<filename>.<ext>
|
||
|
||
If these formats are not available, and the application is macOS-exclusive (otherwise a command-line download defaults to the Windows version) we prefer the use of this format:
|
||
|
||
https://sourceforge.net/projects/<project_name>/files/latest/download
|
||
|
||
#### Some providers block command-line downloads
|
||
|
||
Some hosting providers actively block command-line HTTP clients. Such URLs cannot be used in casks.
|
||
|
||
Other providers may use URLs that change periodically, or even on each visit (example: FossHub). These cases tend to occur when the vendor is actively trying to prevent automated downloads, so we prefer to not add those casks to the main repository.
|
||
|
||
### Stanza: `version`
|
||
|
||
`version`, while related to the app’s own versioning, doesn’t have to follow it exactly. It is common to change it slightly so it can be [interpolated](https://en.wikipedia.org/wiki/String_interpolation#Ruby/Crystal) in other stanzas, usually in `url` to create a cask that only needs `version` and `sha256` changes when updated. This can be taken further, when needed, with [Ruby `String` methods](https://ruby-doc.org/core/String.html).
|
||
|
||
For example, instead of:
|
||
|
||
```ruby
|
||
version "1.2.3"
|
||
url "https://example.com/file-version-123.dmg"
|
||
```
|
||
|
||
we can use:
|
||
|
||
```ruby
|
||
version "1.2.3"
|
||
url "https://example.com/file-version-#{version.delete(".")}.dmg"
|
||
```
|
||
|
||
We can also leverage the power of regular expressions. So instead of:
|
||
|
||
```ruby
|
||
version "1.2.3build4"
|
||
url "https://example.com/1.2.3/file-version-1.2.3build4.dmg"
|
||
```
|
||
|
||
we can use:
|
||
|
||
```ruby
|
||
version "1.2.3build4"
|
||
url "https://example.com/#{version.sub(/build\d+/, "")}/file-version-#{version}.dmg"
|
||
```
|
||
|
||
#### `version` methods
|
||
|
||
The examples above can become hard to read, however. Since many of these changes are common, we provide a number of helpers to clearly interpret otherwise obtuse cases:
|
||
|
||
| method | input | output |
|
||
| ------------------------ | ------------------ | ------ |
|
||
| `major` | `1.2.3-a45,ccdd88` | `1` |
|
||
| `minor` | `1.2.3-a45,ccdd88` | `2` |
|
||
| `patch` | `1.2.3-a45,ccdd88` | `3-a45` |
|
||
| `major_minor` | `1.2.3-a45,ccdd88` | `1.2` |
|
||
| `major_minor_patch` | `1.2.3-a45,ccdd88` | `1.2.3-a45` |
|
||
| `minor_patch` | `1.2.3-a45,ccdd88` | `2.3-a45` |
|
||
| `csv.first` | `1.2.3-a45,ccdd88` | `1.2.3-a45` |
|
||
| `csv.second` | `1.2.3-a45,ccdd88` | `ccdd88` |
|
||
| `dots_to_hyphens` | `1.2.3-a45,ccdd88` | `1-2-3-a45,ccdd88` |
|
||
| `no_dots` | `1.2.3-a45,ccdd88` | `123-a45,ccdd88` |
|
||
|
||
Similar to `dots_to_hyphens`, we provide methods for all logical permutations of `{dots,hyphens,underscores}_to_{dots,hyphens,underscores}`. The same applies to `no_dots` in the form of `no_{dots,hyphens,underscores}`, with an extra `no_dividers` that applies all these at once.
|
||
|
||
Finally, there is `csv` which returns an array of comma-separated values, which replaces the deprecated `before_comma` and `after_comma` methods. Comma-separated versions should only be used for otherwise complex cases; ideally, there should be no more than two instances of `,` per `version`, although methods up to `csv.fifth` are available.
|
||
|
||
#### Special value `:latest`
|
||
|
||
The special value `version :latest` is used when:
|
||
|
||
* `url` does not contain any version information and there is no way to retrieve the version using a `livecheck`, or
|
||
* having a correct value for `version` is too difficult or impractical, even with our automated systems. For example, [chromium.rb](https://github.com/Homebrew/homebrew-cask/blob/aa461148bbb5119af26b82cccf5003e2b4e50d95/Casks/c/chromium.rb#L4) which releases multiple versions per day.
|
||
|
||
In both cases, using the special value [`sha256 :no_check`](#special-value-no_check) is also required. Casks that use `version :latest` are excluded from [autobumping](Autobump.md).
|
||
|
||
### Stanza: `zap`
|
||
|
||
#### `zap` purpose
|
||
|
||
The `zap` stanza describes a more complete uninstallation of files associated with a cask. The `zap` procedures will never be performed by default, but only if the user uses `--zap` on `uninstall`:
|
||
|
||
```bash
|
||
brew uninstall --zap firefox
|
||
```
|
||
|
||
`zap` stanzas may remove:
|
||
|
||
* Preference files and caches stored within the user’s `~/Library` directory.
|
||
* Shared resources such as application updaters. Since shared resources may be removed, other applications may be affected by `brew uninstall --zap`. Understanding that is the responsibility of the end user.
|
||
|
||
`zap` stanzas should not remove:
|
||
|
||
* Files created by the user directly.
|
||
|
||
Appending `--force` to the command will allow you to perform these actions even if the cask is no longer installed:
|
||
|
||
```bash
|
||
brew uninstall --zap --force firefox
|
||
```
|
||
|
||
#### `zap` syntax
|
||
|
||
The form of the `zap` stanza follows the [`uninstall`](#stanza-uninstall) stanza. All the same directives are available. The `trash:` key is preferred over `delete:`.
|
||
|
||
Example: [dropbox.rb](https://github.com/Homebrew/homebrew-cask/blob/974a55ade77bb4edc8bbb80ef72eec83ae0e76c0/Casks/d/dropbox.rb#L30-L68)
|
||
|
||
#### `zap` creation
|
||
|
||
The simplest method is to use `brew generate-zap`, which scans the system for associated files and directories to automatically generate the stanza. The target application should have been launched at least once so that preference files and caches exist on disk. In a few instances it may fail to pick up anything and manual creation may be required.
|
||
|
||
Manual creation can be facilitated with:
|
||
|
||
* Some of the [helper scripts found under `developer/bin`](https://github.com/Homebrew/homebrew-cask/tree/HEAD/developer/bin)
|
||
* `sudo find / -iname "*<search item>*"`
|
||
* An uninstaller tool such as [AppCleaner](https://formulae.brew.sh/cask/appcleaner)
|
||
* Inspection of the usual paths, i.e. `/Library/{'Application Support',LaunchAgents,LaunchDaemons,Frameworks,Logs,Preferences,PrivilegedHelperTools}` and `~/Library/{'Application Support',Caches,Containers,LaunchAgents,Logs,Preferences,'Saved Application State'}`
|
||
|
||
If no additional files are discovered, instead of a zap stanza, include the following comment:
|
||
|
||
```ruby
|
||
# No zap stanza required
|
||
```
|
||
|
||
## Conditional statements
|
||
|
||
### Handling different system configurations
|
||
|
||
Casks can deliver specific versions of artifacts depending on the current macOS release, CPU architecture, or system OS by either tailoring the `url` / `sha256` / `version` stanzas, using the [`on_<system>` syntax](Formula-Cookbook.md#handling-different-system-configurations) (which replaces conditional statements using `MacOS.version` or `Hardware::CPU`), or both.
|
||
|
||
If your cask's artifact is offered as separate downloads for Apple Silicon and Intel architectures, or offers downloads for Linux, they'll presumably be downloadable at distinct URLs that differ only slightly. To adjust the URL depending on the current CPU architecture and system OS, supply a hash for each to the `arm:`, `intel:`, `arm64_linux:`, and `x86_64_linux:` parameters of `sha256`; use the special `arch` and `os` stanzas to define the unique components of the respective URLs for substitution in the `url`. Additional substitutions can be defined by calling `on_arch_conditional` and `on_system_conditional` directly. Example (from [libreoffice.rb](https://github.com/Homebrew/homebrew-cask/blob/a4164b8f5084fdaefb6e2e2f4f699270690b7845/Casks/l/libreoffice.rb#L1-L10)):
|
||
|
||
```ruby
|
||
cask "libreoffice" do
|
||
arch arm: "aarch64", intel: "x86-64"
|
||
folder = on_arch_conditional arm: "aarch64", intel: "x86_64"
|
||
|
||
version "7.6.0"
|
||
sha256 arm: "81eab945a33622fc156951e804024d23aa9a745c06743b4947215ed9303ad1c4",
|
||
intel: "ede541af151487f60eb518e310d20dad1a973f3dbe9ff78d782dd29b14ba2946"
|
||
|
||
url "https://download.documentfoundation.org/libreoffice/stable/#{version}/mac/#{folder}/LibreOffice_#{version}_MacOS_#{arch}.dmg"
|
||
end
|
||
```
|
||
|
||
If the version number is different for each architecture, locate the unique `version` and (if checked) `sha256` stanzas within `on_arm` and `on_intel` blocks. Example (from [inkscape.rb](https://github.com/Homebrew/homebrew-cask/blob/11f6966bf17628b98895d64a61a4fb0bc1bb31bf/Casks/i/inkscape.rb#L1-L13)):
|
||
|
||
```ruby
|
||
cask "inkscape" do
|
||
arch arm: "arm64", intel: "x86_64"
|
||
|
||
on_arm do
|
||
version "1.3.0,42339"
|
||
sha256 "e37b5f8b8995a0ecc41ca7fcae90d79bcd652b7a25d2f6e52c4e2e79aef7fec1"
|
||
end
|
||
on_intel do
|
||
version "1.3.0,42338"
|
||
sha256 "e97de6804d8811dd2f1bc45d709d87fb6fe45963aae710c24a4ed655ecd8eb8a"
|
||
end
|
||
|
||
url "https://inkscape.org/gallery/item/#{version.csv.second}/Inkscape-#{version.csv.first}_#{arch}.dmg"
|
||
end
|
||
```
|
||
|
||
To adjust the installed version depending on the current macOS release, use a series of `on_<system>` blocks that cover the range of supported releases. Each block can contain stanzas that set which version to download and customise installation/uninstallation and livecheck behaviour for one or more releases. Example (from [calibre.rb](https://github.com/Homebrew/homebrew-cask/blob/482c34e950da8d649705f4aaea7b760dcb4b5402/Casks/c/calibre.rb#L1-L34)):
|
||
|
||
```ruby
|
||
cask "calibre" do
|
||
on_sonoma :or_older do
|
||
version "3.48.0"
|
||
sha256 "68829cd902b8e0b2b7d5cf7be132df37bcc274a1e5720b4605d2dd95f3a29168"
|
||
|
||
livecheck do
|
||
skip "Legacy version"
|
||
end
|
||
end
|
||
on_sequoia do
|
||
# ...
|
||
end
|
||
on_tahoe :or_newer do
|
||
version "6.25.0"
|
||
sha256 "a7ed19ae0526630ccb138b9afee6dc5169904180b02f7a3089e78d3e0022753b"
|
||
|
||
livecheck do
|
||
url "https://github.com/kovidgoyal/calibre"
|
||
strategy :github_latest
|
||
end
|
||
end
|
||
end
|
||
```
|
||
|
||
Such `on_<system>` blocks can be nested and contain other stanzas not listed here. However, version-specific macOS requirements should be placed in `on_macos` blocks rather than individual macOS release blocks. Examples: [calhash.rb](https://github.com/Homebrew/homebrew-cask/blob/HEAD/Casks/c/calhash.rb), [r-app.rb](https://github.com/Homebrew/homebrew-cask/blob/HEAD/Casks/r/r-app.rb), [wireshark-app.rb](https://github.com/Homebrew/homebrew-cask/blob/HEAD/Casks/w/wireshark-app.rb).
|
||
|
||
### Switch between languages or regions
|
||
|
||
If a cask is available in multiple languages, you can use the [`language`](#stanza-language) stanza to switch between languages or regions based on the system locale.
|
||
|
||
## Arbitrary Ruby methods
|
||
|
||
In the exceptional case that the cask DSL is insufficient, it is possible to define arbitrary Ruby variables and methods inside the cask by creating a `Utils` namespace. Example:
|
||
|
||
```ruby
|
||
cask "myapp" do
|
||
module Utils
|
||
def self.arbitrary_method
|
||
# ...
|
||
end
|
||
end
|
||
|
||
version "1.0"
|
||
sha256 "a32565cdb1673f4071593d4cc9e1c26bc884218b62fef8abc450daa47ba8fa92"
|
||
|
||
url "https://#{Utils.arbitrary_method}"
|
||
name "MyApp"
|
||
homepage "https://www.example.com/"
|
||
# ...
|
||
end
|
||
```
|
||
|
||
This should be used sparingly: any method which is needed by two or more casks should instead be rolled into Homebrew/brew. Care must also be taken that such methods be very efficient.
|
||
|
||
Variables and methods should not be defined outside the `Utils` namespace, as they may collide with Homebrew’s cask internals.
|
||
|
||
## Token reference
|
||
|
||
This section describes the algorithm implemented in the `generate_cask_token` script and covers detailed rules and exceptions that are not needed in most cases.
|
||
Generate a token from the installed app bundle or the software's full name with:
|
||
|
||
```sh
|
||
"$(brew --repository homebrew/cask)/developer/bin/generate_cask_token" "/full/path/to/Software.app"
|
||
"$(brew --repository homebrew/cask)/developer/bin/generate_cask_token" "Software Name"
|
||
```
|
||
|
||
* [Purpose](#purpose)
|
||
* [Finding the simplified name of the vendor’s distribution](#finding-the-simplified-name-of-the-vendors-distribution)
|
||
* [Converting the simplified name to a token](#converting-the-simplified-name-to-a-token)
|
||
* [Cask filenames](#cask-filenames)
|
||
* [Cask headers](#cask-headers)
|
||
* [Cask token examples](#cask-token-examples)
|
||
* [Special affixes](#special-affixes)
|
||
|
||
### Purpose
|
||
|
||
Software vendors are often inconsistent with their naming. By enforcing strict naming conventions we aim to:
|
||
|
||
* Prevent duplicate submissions
|
||
* Minimise renaming events
|
||
* Unambiguously boil down the name of the software into a unique identifier
|
||
* Avoid conflicts with Homebrew/homebrew-core formulae
|
||
|
||
Details of software names and brands will inevitably be lost in the conversion to a minimal token. To capture the vendor’s full name for a distribution, use the [`name`](#stanza-name) within a cask, which accepts an unrestricted UTF-8 string.
|
||
|
||
### Finding the simplified name of the vendor’s distribution
|
||
|
||
#### Simplified names of apps
|
||
|
||
* Start with the exact name of the application bundle as it appears on disk, such as `Google Chrome.app`.
|
||
|
||
* If the name uses letters outside A–Z, convert it to ASCII as described in [Converting to ASCII](#converting-to-ascii).
|
||
|
||
* Remove `.app` from the end.
|
||
|
||
* Remove from the end: the string “app”, if the vendor styles the name like “Software App.app”.
|
||
|
||
* Exception: when “app” is an inseparable part of the name, without which the name would be inherently nonsensical, as in [whatsapp.rb](https://github.com/Homebrew/homebrew-cask/blob/HEAD/Casks/w/whatsapp.rb).
|
||
|
||
* Remove from the end: version numbers or incremental release designations such as “alpha”, “beta”, or “release candidate”. Strings which distinguish different capabilities or codebases such as “Community Edition” are currently accepted.
|
||
|
||
* Exception: when a number is not an incremental release counter, but a differentiator for a different product from a different vendor, as in [kdiff3.rb](https://github.com/Homebrew/homebrew-cask/blob/HEAD/Casks/k/kdiff3.rb).
|
||
|
||
* If the version number is arranged to occur in the middle of the App name, it should also be removed.
|
||
|
||
* Remove from the end: “Launcher”, “Quick Launcher”, "Desktop", "for Desktop".
|
||
|
||
* Exception: when the suffix is an intrinsic part of the product name, as in [Docker Desktop.app](https://github.com/Homebrew/homebrew-cask/blob/HEAD/Casks/d/docker-desktop.rb).
|
||
|
||
* Remove from the end: strings such as “Mac”, “for Mac”, “for OS X”, “macOS”, “for macOS”. These terms are generally added to ported software such as “MAME OS X.app”.
|
||
|
||
* Exception: when the software is not a port, and “Mac” is an inseparable part of the name, without which the name would be inherently nonsensical, as in [PlayOnMac.app](https://github.com/Homebrew/homebrew-cask/blob/HEAD/Casks/p/playonmac.rb).
|
||
|
||
* Remove from the end: hardware designations such as “for x86”, “32-bit”, “ARM”.
|
||
|
||
* Remove from the end: software framework names such as “Cocoa”, “Qt”, “Gtk”, “Wx”, “Java”, “Oracle JVM”, etc.
|
||
|
||
* Exception: the framework is the product being casked.
|
||
|
||
* Remove from the end: localization strings such as “en-US”.
|
||
|
||
* If the result of this process is a generic term, such as “Macintosh Installer”, try prepending the name of the vendor or developer, followed by a hyphen. If that doesn’t work, then just create the best name you can, based on the vendor’s web page.
|
||
|
||
* If the result conflicts with the name of an existing cask or Homebrew/homebrew-core formula, make yours unique by prepending the name of the vendor or developer, followed by a hyphen. Example: [unison.rb](https://github.com/Homebrew/homebrew-cask/blob/HEAD/Casks/u/unison.rb) and [panic-unison.rb](https://github.com/Homebrew/homebrew-cask/blob/HEAD/Casks/p/panic-unison.rb).
|
||
|
||
* If the result still conflicts with the name of an existing Homebrew/homebrew-core formula, adjust the name to better describe the difference by e.g. appending `-app`. Example: `appium` formula and `appium-desktop` cask, `angband` formula and `angband-app` cask.
|
||
|
||
* Inevitably, there are a small number of exceptions not covered by the rules. Don’t hesitate to [use the forum](https://github.com/orgs/Homebrew/discussions) if you have a problem.
|
||
|
||
#### Converting to ASCII
|
||
|
||
* If the vendor provides an English localization string, that is preferred. Here are the places it may be found, in order of preference:
|
||
|
||
* `CFBundleDisplayName` in the main `Info.plist` file of the app bundle
|
||
* `CFBundleName` in the main `Info.plist` file of the app bundle
|
||
* `CFBundleDisplayName` in `InfoPlist.strings` of an `en.lproj` localization directory
|
||
* `CFBundleName` in `InfoPlist.strings` of an `en.lproj` localization directory
|
||
* `CFBundleDisplayName` in `InfoPlist.strings` of an `English.lproj` localization directory
|
||
* `CFBundleName` in `InfoPlist.strings` of an `English.lproj` localization directory
|
||
|
||
* When there is no vendor localisation string, romanise the name by transliteration or decomposition.
|
||
|
||
* As a last resort, translate the name of the app bundle into English.
|
||
|
||
#### Simplified names of `pkg`-based installers
|
||
|
||
* The simplified name of a `pkg` may be more tricky to determine than that of an App. If a `pkg` installs an App, then use that App name with the rules above. If not, just create the best name you can, based on the vendor’s web page.
|
||
|
||
#### Simplified names of non-app software
|
||
|
||
* Currently, rules for generating a token are not well-defined for Preference Panes, Quick Look plugins and several other types of software installable as casks. Just create the best name you can, based on the filename on disk or the vendor’s web page. Watch out for duplicates.
|
||
|
||
Non-app tokens should become more standardised in the future.
|
||
|
||
### Converting the simplified name to a token
|
||
|
||
As the token is the primary identifier for casks, it’s the unique string users refer to when operating on them.
|
||
|
||
To convert the App’s simplified name (above) to a token:
|
||
|
||
* Convert all letters to lower case.
|
||
* Expand the `+` symbol into a separated English word: `-plus-`.
|
||
* Expand the `@` symbol into a separated English word: `-at-`.
|
||
* Spaces become hyphens.
|
||
* Underscores become hyphens.
|
||
* Middots/Interpuncts become hyphens.
|
||
* Hyphens stay hyphens.
|
||
* Digits stay digits.
|
||
* Delete any character which is not alphanumeric or a hyphen.
|
||
* Collapse a series of multiple hyphens into one hyphen.
|
||
* Delete any leading or trailing hyphens.
|
||
|
||
#### Casks pinned to specific versions
|
||
|
||
A versioned cask may only be created for a release line that meets the [acceptance requirements for versioned releases](Acceptable-Casks.md#default-and-alternative-release-channels).
|
||
Casks pinned to a specific version of the application (e.g. [`corretto@11`](https://github.com/Homebrew/homebrew-cask/blob/HEAD/Casks/c/corretto%4011.rb)) should use the same token as the standard cask with a suffix of `@<version-number>`.
|
||
For Corretto (`corretto`), pinned to version 11, the token is `corretto@11`, while the most recent version does not have a suffix.
|
||
|
||
#### Casks for alternative release channels
|
||
|
||
Casks that track an alternative upstream release channel should use the same token as the standard cask with an `@<channel>` suffix.
|
||
For Google Chrome (`google-chrome`), the beta-channel token is `google-chrome@beta`.
|
||
|
||
A suffix such as `@latest` names an upstream release channel and is unrelated to the [`version :latest`](#special-value-latest) special value.
|
||
Use a concrete version and checksum when the channel provides versioned artifacts.
|
||
|
||
### Cask filenames
|
||
|
||
Casks are defined in a Ruby file named after the token, with the file extension `.rb`.
|
||
|
||
### Cask headers
|
||
|
||
The token is also given in the header line for each cask.
|
||
|
||
### Cask token examples
|
||
|
||
These illustrate most of the rules for generating a token:
|
||
|
||
| App Name on Disk | Simplified App Name | Cask Token | Filename |
|
||
| ---------------------- | ------------------- | ---------------- | -------- |
|
||
| `Audio Hijack Pro.app` | Audio Hijack Pro | audio-hijack-pro | `audio-hijack-pro.rb` |
|
||
| `VLC.app` | VLC | vlc | `vlc.rb` |
|
||
| `BetterTouchTool.app` | BetterTouchTool | bettertouchtool | `bettertouchtool.rb` |
|
||
| `LPK25 Editor.app` | LPK25 Editor | lpk25-editor | `lpk25-editor.rb` |
|
||
| `Sublime Text 2.app` | Sublime Text | sublime-text | `sublime-text.rb` |
|
||
|
||
For versioned/development channel casks:
|
||
|
||
| Standard Cask Token | Derivative | Cask Token | Filename |
|
||
| -------------------- | ------------------- | ---------------------- | -------- |
|
||
| `google-chrome` | Beta channel | `google-chrome@beta` | `google-chrome@beta.rb` |
|
||
| `vlc` | Nightly channel | `vlc@nightly` | `vlc@nightly.rb` |
|
||
| `corretto` | Pinned to version 11 | `corretto@11` | `corretto@11.rb` |
|
||
|
||
### Special affixes
|
||
|
||
A few situations require a prefix or suffix to be added to the token.
|
||
|
||
#### Token overlap
|
||
|
||
When the token for a new cask would otherwise conflict with the token of an already existing cask, the nature of that overlap dictates the token, potentially for both casks. See [Forks and apps with conflicting names](Acceptable-Casks.md#forks-and-apps-with-conflicting-names) for information on how to proceed.
|
||
|
||
#### Potentially misleading name
|
||
|
||
If the token for a piece of unofficial software that interacts with a popular service would make it look official and the vendor is not authorised to use the name, [a prefix must be added](Acceptable-Casks.md#forks-and-apps-with-conflicting-names) for disambiguation.
|
||
|
||
In cases where the prefix is ambiguous and would make the app appear official, the `-unofficial` suffix may be used.
|