diff --git a/docs/Cask-Cookbook.md b/docs/Cask-Cookbook.md index 387095ee5d..941ac6ce14 100644 --- a/docs/Cask-Cookbook.md +++ b/docs/Cask-Cookbook.md @@ -1,6 +1,6 @@ # 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: +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 "alfred" do @@ -19,7 +19,7 @@ end ## 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 Cask will figure out what needs to be done at install time. +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 Cask will figure out what needs to be done 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. @@ -29,36 +29,32 @@ Exception: `do` blocks such as `postflight` may enclose a block of pure Ruby cod ### Efficiency -Conditional statements are permitted, but only if they are very efficient. -Tests on the following values are known to be acceptable: +Conditional statements are permitted, but only if they are very efficient. Tests on the following values are known to be acceptable: -| value | examples -| ----------------------------|-------------------------------------- -| `MacOS.version` | [coconutbattery.rb](https://github.com/Homebrew/homebrew-cask/blob/a11ee55e8ed8255f7dab77120dfb1fb955789559/Casks/coconutbattery.rb#L2-L16), [yasu.rb](https://github.com/Homebrew/homebrew-cask/blob/21d3f7ac8a4adac0fe474b3d4b020d284eeef88d/Casks/yasu.rb#L2-L23) +| value | examples | +| --------------------------- | -------- | +| `MacOS.version` | [bbedit.rb](https://github.com/Homebrew/homebrew-cask/blob/576798b72f3f6f02289e84a62c11a987da97bc6d/Casks/bbedit.rb#L2-L14), [powerphotos.rb](https://github.com/Homebrew/homebrew-cask/blob/fe5320b237d72e025549a0d6402aa34647ed990d/Casks/powerphotos.rb#L2-L18), [choosy.rb](https://github.com/Homebrew/homebrew-cask/blob/43224bc403345f3180e684d754789d928b7d0beb/Casks/choosy.rb#L2-L22) ### Version Comparisons -Tests against `MacOS.version` may use either symbolic names or version -strings with numeric comparison operators: +Tests against `MacOS.version` may use either one of [these symbolic names](#depends_on-macos) or version strings with numeric comparison operators: ```ruby if MacOS.version <= :mojave # symbolic name ``` ```ruby -if MacOS.version <= "10.14" # version string +if MacOS.version <= "10.14" # version string for major release ``` -The available symbols for macOS versions are: `:el_capitan`, `:sierra`, `:high_sierra`, `:mojave`, `:catalina`, `:big_sur`, `:monterey`, and `:ventura`. The corresponding numeric version strings should be given as major releases containing a single dot. - -Note that in the official Homebrew Cask repositories only the symbolic names are allowed. The numeric comparison may only be used for third-party taps. +Note that in the official Homebrew Cask taps only the symbolic names are allowed. The numeric comparison may only be used for third-party taps. ### Always Fall Through to the Newest Case -Conditionals should be constructed so that the default is the newest OS version. When using an `if` statement, test for older versions, and then let the `else` statement hold the latest and greatest. This makes it more likely that the Cask will work without alteration when a new OS is released. Example (from [coconutbattery.rb](https://github.com/Homebrew/homebrew-cask/blob/2c801af44be29fff7f3cb2996455fce5dd95d1cc/Casks/coconutbattery.rb)): +Conditionals should be constructed so that the default is the newest OS version. When using an `if` statement, test for older versions, and then let the `else` statement hold the latest and greatest. This makes it more likely that the cask will work without alteration when a new OS version is released. Example (from [calibre.rb](https://github.com/Homebrew/homebrew-cask/blob/da62b1769b7a34807f1335ab8ec16bf3184b3a7e/Casks/calibre.rb#L2-L11)): ```ruby -if MacOS.version <= :sierra +if MacOS.version <= :high_sierra # ... elsif MacOS.version <= :mojave # ... @@ -69,11 +65,11 @@ end ### Switch Between Languages or Regions -If a cask is available in multiple languages, you can use the `language` stanza to switch between languages or regions based on the system locale. +If a cask is available in multiple languages, you can use the [`language` stanza](#stanza-language) 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: +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 @@ -93,82 +89,79 @@ cask "myapp" do end ``` -This should be used sparingly: any method which is needed by two or more Casks should instead be rolled into the core. Care must also be taken that such methods be very efficient. +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 Cask internals. ## Header Line Details -The first non-comment line in a Cask follows the form: +The first non-comment line in a cask follows the form: ```ruby cask "" do ``` -[``](#token-reference) should match the Cask filename, without the `.rb` extension, -enclosed in single quotes. +[``](#token-reference) should match the cask filename, without the `.rb` extension, enclosed in double quotes. -There are currently some arbitrary limitations on Cask tokens which are in the process of being removed. GitHub Actions will catch any errors during the transition. +There are currently some arbitrary limitations on cask tokens which are in the process of being removed. GitHub Actions will catch any errors during the transition. ## 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 delineate information. +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. -``` -version -sha256 + version + sha256 -language + language -url -appcast -name -desc -homepage + url + appcast + name + desc + homepage -livecheck + livecheck -auto_updates -conflicts_with -depends_on -container + auto_updates + conflicts_with + depends_on + container -suite -app -pkg -installer -binary -manpage -colorpicker -dictionary -font -input_method -internet_plugin -prefpane -qlplugin -mdimporter -screen_saver -service -audio_unit_plugin -vst_plugin -vst3_plugin -artifact, target: # target: shown here as is required with `artifact` -stage_only + suite + app + pkg + installer + binary + manpage + colorpicker + dictionary + font + input_method + internet_plugin + prefpane + qlplugin + mdimporter + screen_saver + service + audio_unit_plugin + vst_plugin + vst3_plugin + artifact, target: # target: shown here as is required with `artifact` + stage_only -preflight + preflight -postflight + postflight -uninstall_preflight + uninstall_preflight -uninstall_postflight + uninstall_postflight -uninstall + uninstall -zap + zap -caveats -``` + 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. @@ -176,64 +169,64 @@ Note that every stanza that has additional parameters (`:symbols` after a `,`) s ### Required Stanzas -Each of the following stanzas is required for every Cask. +Each of the following stanzas is required for every cask. -| name | multiple occurrences allowed? | value | -| ---------- |------------------------------ | ------------------------------- | -| `version` | no | Application version.
See [Version Stanza Details](#stanza-version) for more information. -| `sha256` | no | SHA-256 checksum of the file downloaded from `url`, calculated by the command `shasum -a 256 `. Can be suppressed by using the special value `:no_check`.
See [Checksum Stanza Details](#stanza-sha256) for more information. -| `url` | no | URL to the `.dmg`/`.zip`/`.tgz`/`.tbz2` file that contains the application.
A [comment](#when-url-and-homepage-hostnames-differ-add-a-comment) should be added if the hostnames in the `url` and `homepage` stanzas differ. Block syntax should be used for URLs that change on every visit.
See [URL Stanza Details](#stanza-url) for more information. -| `name` | yes | String providing the full and proper name defined by the vendor.
See [Name Stanza Details](#stanza-name) for more information. -| `desc` | no | One-line description of the Cask. Shows when running `brew info`.
See [Desc Stanza Details](#stanza-desc) for more information. -| `homepage` | no | Application homepage; used for the `brew home` command. +| name | multiple occurrences allowed? | value | +| ---------------------------- | :---------------------------: | ----- | +| [`version`](#stanza-version) | no | Application version. +| [`sha256`](#stanza-sha256) | no | SHA-256 checksum of the file downloaded from `url`, calculated by the command `shasum -a 256 `. Can be suppressed by using the special value `:no_check`. +| [`url`](#stanza-url) | no | URL to the `.dmg`/`.zip`/`.tgz`/`.tbz2` file that contains the application. A [comment](#when-url-and-homepage-domains-differ-add-verified) should be added if the domains in the `url` and `homepage` stanzas differ. Block syntax should be used for URLs that change on every visit. +| [`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. ### At Least One Artifact Stanza Is Also Required -Each Cask must declare one or more *artifacts* (i.e. something to install). +Each cask must declare one or more *artifacts* (i.e. something to install). -| name | multiple occurrences allowed? | value | -| ------------------- |------------------------------ | ---------------------- | -| `app` | yes | Relative path to an `.app` that should be moved into the `/Applications` folder on installation.
See [App Stanza Details](#stanza-app) for more information. -| `pkg` | yes | Relative path to a `.pkg` file containing the distribution.
See [Pkg Stanza Details](#stanza-pkg) for more information. -| `binary` | yes | Relative path to a Binary that should be linked into the `$(brew --prefix)/bin` folder (typically `/usr/local/bin`) on installation.
See [Binary Stanza Details](#stanza-binary) for more information. -| `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 a Input Method that should be moved into the `~/Library/Input Methods` folder on installation. -| `internet_plugin` | yes | Relative path to a Service that should be moved into the `~/Library/Internet Plug-Ins` folder on installation. -| `manpage` | yes | Relative path to a Man Page that should be linked into the respective man page folder on installation, e.g. `/usr/local/share/man/man3` for `my_app.3`. -| `prefpane` | yes | Relative path to a Preference Pane that should be moved into the `~/Library/PreferencePanes` folder on installation. -| `qlplugin` | yes | Relative path to a QuickLook Plugin that should be moved into the `~/Library/QuickLook` 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/Components` folder on installation. -| `vst_plugin` | yes | Relative path to a VST Plugin that should be moved into the `~/Library/Audio/VST` folder on installation. -| `vst3_plugin` | yes | Relative path to a VST3 Plugin that should be moved into the `~/Library/Audio/VST3` folder on installation. -| `suite` | yes | Relative path to a containing directory that should be moved into the `/Applications` folder on installation.
See [Suite Stanza Details](#stanza-suite) for more information. -| `artifact` | yes | Relative path to an arbitrary path that should be moved on installation. Must provide an absolute path as a `target` (example [alcatraz.rb](https://github.com/Homebrew/homebrew-cask/blob/312ae841f1f1b2ec07f4d88b7dfdd7fbdf8d4f94/Casks/alcatraz.rb#L12)). This is only for unusual cases. The `app` stanza is strongly preferred when moving `.app` bundles. -| `installer` | yes | Describes an executable which must be run to complete the installation.
See [Installer Stanza Details](#stanza-installer) for more information. -| `stage_only` | no | `true`. Assert that the Cask contains no activatable artifacts. +| name | multiple occurrences allowed? | value | +| -------------------------------- | :---------------------------: | ----- | +| [`app`](#stanza-app) | yes | Relative path to an `.app` that should be moved into the `/Applications` folder on installation. +| [`pkg`](#stanza-pkg) | yes | Relative path to a `.pkg` file containing the distribution. +| [`binary`](#stanza-binary) | yes | Relative path to a Binary that should be linked into the `$(brew --prefix)/bin` folder on installation. +| `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 a Input Method that should be moved into the `~/Library/Input Methods` folder on installation. +| `internet_plugin` | yes | Relative path to a Service that should be moved into the `~/Library/Internet Plug-Ins` folder on installation. +| `manpage` | yes | Relative path to a Man Page that should be linked into the respective man page folder on installation, e.g. `/usr/local/share/man/man3` for `my_app.3`. +| `prefpane` | yes | Relative path to a Preference Pane that should be moved into the `~/Library/PreferencePanes` folder on installation. +| `qlplugin` | yes | Relative path to a QuickLook Plugin that should be moved into the `~/Library/QuickLook` 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/Components` folder on installation. +| `vst_plugin` | yes | Relative path to a VST Plugin that should be moved into the `~/Library/Audio/VST` folder on installation. +| `vst3_plugin` | yes | Relative path to a VST3 Plugin that should be moved into the `~/Library/Audio/VST3` folder on installation. +| [`suite`](#stanza-suite) | yes | Relative path to a containing directory that should be moved into the `/Applications` 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/8bc2da7270292f899b9819972cf2ee647b8c6a3e/Casks/free-gpgmail.rb#L39)) This is only for unusual cases; the `app` stanza is strongly preferred when moving `.app` bundles. +| [`installer`](#stanza-installer) | yes | Describes an executable which must be run to complete the installation. +| `stage_only` | no | `true`. Asserts that the cask contains no activatable artifacts. ### Optional Stanzas -| name | multiple occurrences allowed? | value | -| ---------------------- |------------------------------ | ------------------- | -| `uninstall` | yes | Procedures to uninstall a Cask. Optional unless the `pkg` stanza is used.
See [Uninstall Stanza Details](#stanza-uninstall) for more information. -| `zap` | yes | Additional procedures for a more complete uninstall, including user files and shared resources.
See [Zap Stanza Details](#stanza-zap) for more information. -| `appcast` | no | URL providing an appcast feed to find updates for this Cask.
See [Appcast Stanza Details](#stanza-appcast) for more information. -| `depends_on` | yes | List of dependencies and requirements for this Cask.
See [Depends_on Stanza Details](#stanza-depends_on) for more information. -| `conflicts_with` | yes | List of conflicts with this Cask (*not yet functional*).
See [Conflicts_with Stanza Details](#stanza-conflicts_with) for more information. -| `caveats` | yes | String or Ruby block providing the user with Cask-specific information at install time.
See [Caveats Stanza Details](#stanza-caveats) for more information. -| `livecheck` | no | Ruby block describing how to find updates for this Cask.
See [Livecheck Stanza Details](#stanza-livecheck) for more information. -| `preflight` | yes | Ruby block containing preflight install operations (needed only in very rare cases). -| `postflight` | yes | Ruby block containing postflight install operations.
See [Postflight Stanza Details](#stanza-flight) for more information. -| `uninstall_preflight` | yes | Ruby block containing preflight uninstall operations (needed only in very rare cases). -| `uninstall_postflight` | yes | Ruby block containing postflight uninstall operations. -| `language` | required | Ruby block, called with language code parameters, containing other stanzas and/or a return value.
See [Language Stanza Details](#stanza-language) for more information. -| `container nested:` | no | Relative path to an inner container that must be extracted before moving on with the installation. This allows us to support dmg inside tar, zip inside dmg, etc. -| `container type:` | no | Symbol to override container-type autodetect. May be one of: `:air`, `:bz2`, `: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/312ae841f1f1b2ec07f4d88b7dfdd7fbdf8d4f94/Casks/parse.rb#L11)) -| `auto_updates` | no | `true`. Assert the Cask artifacts auto-update. Use if `Check for Updates…` or similar is present in app menu, but not if it only opens a webpage and does not do the download and installation for you. +| name | multiple occurrences allowed? | value | +| ------------------------------------------ | :---------------------------: | ----- | +| [`uninstall`](#stanza-uninstall) | yes | Procedures to uninstall a cask. Optional unless the `pkg` stanza is used. +| [`zap`](#stanza-zap) | yes | Additional procedures for a more complete uninstall, including user files and shared resources. +| [`appcast`](#stanza-appcast) | no | URL providing an appcast feed to find updates for this cask. +| [`depends_on`](#stanza-depends_on) | yes | List of dependencies and requirements for this cask. +| [`conflicts_with`](#stanza-conflicts_with) | yes | List of conflicts with this cask (*not yet functional*). +| [`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 for this cask. +| `preflight` | yes | Ruby block containing preflight install operations (needed only in very rare cases). +| [`postflight`](#stanza-flight) | yes | Ruby block containing postflight install operations. +| `uninstall_preflight` | yes | Ruby block containing preflight uninstall operations (needed only in very rare cases). +| `uninstall_postflight` | yes | Ruby block containing postflight uninstall operations. +| [`language`](#stanza-language) | required | 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. +| `container type:` | no | Symbol to override container-type autodetect. May be one of: `:air`, `:bz2`, `: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/0a8004efb40e29510d47d932ab551885cee2aad7/Casks/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. ## Stanza descriptions @@ -253,70 +246,70 @@ by default moves the source to: #### 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/312ae841f1f1b2ec07f4d88b7dfdd7fbdf8d4f94/Casks/scala-ide.rb#L21)): +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/1fed44e89a8896f27e2b69a5789a3cd916d7abe5/Casks/scala-ide.rb#L24)): ```ruby -app "eclipse/Eclipse.app", target: "Scala IDE.app" +app "eclipse.app", target: "Scala IDE.app" ``` -#### target: May Contain an Absolute Path +#### *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 [manopen.rb](https://github.com/Homebrew/homebrew-cask/blob/312ae841f1f1b2ec07f4d88b7dfdd7fbdf8d4f94/Casks/manopen.rb#L12)): +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/75a34b96e4e2af70e1ffc0d6ba64ea7c306b79a3/Casks/sapmachine-jdk.rb#L21)): ```ruby -artifact "openman.1", target: "/usr/local/share/man/man1/openman.1" +artifact "sapmachine-jdk-#{version}.jdk", target: "/Library/Java/JavaVirtualMachines/sapmachine-jdk-#{version}.jdk" ``` -#### target: Works on Most Artifact Types +#### *target* Works on Most Artifact Types -The `target:` key works similarly for most Cask artifacts, such as `app`, `binary`, `colorpicker`, `dictionary`, `font`, `input_method`, `prefpane`, `qlplugin`, `mdimporter`, `service`, `suite`, and `artifact`. +The `target:` key works similarly for most cask artifacts, such as `app`, `binary`, `colorpicker`, `dictionary`, `font`, `input_method`, `prefpane`, `qlplugin`, `mdimporter`, `service`, `suite`, and `artifact`. -#### target: Should Only Be Used in Select Cases +#### *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/312ae841f1f1b2ec07f4d88b7dfdd7fbdf8d4f94/Casks/imagemin.rb#L12); [for consistency](https://github.com/Homebrew/homebrew-cask/blob/d2a6b26df69fc28c4d84d6f5198b2b652c2f414d/Casks/devonthink-pro-office.rb#L16); [to prevent conflicts](https://github.com/Homebrew/homebrew-cask/blob/bd6dc1a64e0bdd35ba0e20789045ea023b0b6aed/Casks/flash-player-debugger.rb#L11); [due to developer suggestion](https://github.com/Homebrew/homebrew-cask/blob/ff3e9c4a6623af44b8a071027e8dcf3f4edfc6d9/Casks/kivy.rb#L12). +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/0661430a4b0143671459260e5c8affc2f8e50413/Casks/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/f34503e7b5f5d018a65f4c726e1c57e15b8111ae/Casks/telegram-desktop.rb#L20); [due to developer suggestion](https://github.com/Homebrew/homebrew-cask/blob/ff3e9c4a6623af44b8a071027e8dcf3f4edfc6d9/Casks/kivy.rb#L12). ### Stanza: `appcast` The value of the `appcast` stanza is a string, holding the URL for an appcast which provides information on future updates. -Note: The [`livecheck` stanza](#stanza-livecheck) should be preferred in most cases, as it allows casks to be updated automatically. +**Note:** The [`livecheck` stanza](#stanza-livecheck) is usually preferred, as it allows casks to be updated automatically. -The main casks repo only accepts submissions for stable versions of software (and [documented exceptions](https://docs.brew.sh/Acceptable-Casks#but-there-is-no-stable-version)), but it still gets pull requests for unstable versions. By checking the submitted `version` against the contents of an appcast, we can better detect these invalid cases. - -Example: [`atom.rb`](https://github.com/Homebrew/homebrew-cask/blob/645dbb8228ec2f1f217ed1431e188687aac13ca5/Casks/atom.rb#L7) +The main [homebrew/cask](https://github.com/Homebrew/homebrew-cask) repository only accepts submissions for stable versions of software (and [documented exceptions](https://docs.brew.sh/Acceptable-Casks#but-there-is-no-stable-version)), but it still gets pull requests for unstable versions. By checking the submitted `version` against the contents of an appcast, we can better detect these invalid cases. There are a few different ways the `appcast` can be determined: -* If the app is distributed via GitHub releases, the `appcast` will be of the form `https://github.com///releases.atom`. Example: [`electron.rb`](https://github.com/Homebrew/homebrew-cask/blob/645dbb8228ec2f1f217ed1431e188687aac13ca5/Casks/electron.rb#L7) +* If the app is distributed via GitHub releases, the `appcast` will be of the form `https://github.com///releases.atom`. Example: [electron.rb](https://github.com/Homebrew/homebrew-cask/blob/645dbb8228ec2f1f217ed1431e188687aac13ca5/Casks/electron.rb#L7) -* If the app is distributed via GitLab releases, the `appcast` will be of the form `https://gitlab.com///-/tags?format=atom`. Example: [`grafx.rb`](https://github.com/Homebrew/homebrew-cask/blob/b22381902f9da870bb07d21b496558f283dad612/Casks/grafx.rb#L6) +* If the app is distributed via GitLab releases, the `appcast` will be of the form `https://gitlab.com///-/tags?format=atom`. Example: [grafx.rb](https://github.com/Homebrew/homebrew-cask/blob/b22381902f9da870bb07d21b496558f283dad612/Casks/grafx.rb#L6) -* The popular update framework [Sparkle](https://sparkle-project.org/) generally uses the `SUFeedURL` property in `Contents/Info.plist` inside `.app` bundles. Example: [`glyphs.rb`](https://github.com/Homebrew/homebrew-cask/blob/645dbb8228ec2f1f217ed1431e188687aac13ca5/Casks/glyphs.rb#L6) +* The popular update framework [Sparkle](https://sparkle-project.org/) generally uses the `SUFeedURL` property in `Contents/Info.plist` inside `.app` bundles. Example: [fstream.rb](https://github.com/Homebrew/homebrew-cask/blob/519999d874792f3ad7cc0fffd0520a8fdf468880/Casks/fstream.rb#L6) -* Sourceforge projects follow the form `https://sourceforge.net/projects//rss`. A more specific page can be used as needed, pointing to a specific directory structure: `https://sourceforge.net/projects//rss?path=/`. Example: [`seashore.rb`](https://github.com/Homebrew/homebrew-cask/blob/645dbb8228ec2f1f217ed1431e188687aac13ca5/Casks/seashore.rb#L6) +* SourceForge projects follow the form `https://sourceforge.net/projects//rss`. A more specific page can be used as needed, pointing to a specific directory structure: `https://sourceforge.net/projects//rss?path=/path/here`. Example: [displaycal.rb](https://github.com/Homebrew/homebrew-cask/blob/347dc92405889488ea72c47f7d50b1afaf348909/Casks/displaycal.rb#L7) -* An appcast can be any URL hosted by the app’s developer that changes every time a new release is out or that contains the version number of the current release (e.g. a download HTML page). Webpages that only change on new version releases are preferred, as are sites that do not contain previous version strings (i.e. avoid changelog pages if the download page contains the current version number but not older ones). Example: [`razorsql.rb`](https://github.com/Homebrew/homebrew-cask/blob/645dbb8228ec2f1f217ed1431e188687aac13ca5/Casks/razorsql.rb#L6) +* An appcast can be any URL hosted by the app’s developer that changes every time a new release is out or that contains the version number of the current release (e.g. a download HTML page). Webpages that only change on new version releases are preferred, as are sites that do not contain previous version strings (i.e. avoid changelog pages if the download page contains the current version number but not older ones). Example: [securityspy.rb](https://github.com/Homebrew/homebrew-cask/blob/e3495e32b7fb3ed1929b6082a4e3eb6a94d9494f/Casks/securityspy.rb#L6) -The [`find-appcast`](https://github.com/Homebrew/homebrew-cask/blob/HEAD/developer/bin/find-appcast) script is able to identify some of these, as well as `electron-builder` appcasts which are trickier to find by hand. Run it with `"$(brew --repository homebrew/cask)/developer/bin/find-appcast" ''`. +The [`find-appcast`](https://github.com/Homebrew/homebrew-cask/blob/HEAD/developer/bin/find-appcast) script is able to identify some of these, as well as `electron-builder` appcasts which are trickier to find by hand. Run it with: -#### Parameters +```bash +"$(brew --repository homebrew/cask)/developer/bin/find-appcast" '/path/to/application.app' +``` + +#### `appcast` Parameters | key | value | | --------------- | ----------- | -| `must_contain:` | a custom string for `brew audit --appcast ` to check against. | +| `must_contain:` | Custom string for `brew audit --appcast ` to check against. (Example: [icollections.rb](https://github.com/Homebrew/homebrew-cask/blob/705ed8ddc23a0e7719348dfb278046f031495938/Casks/icollections.rb#L6-L7)) -Sometimes a `version` doesn’t match a string on the webpage, in which case we tweak what to search for. Example: if `version` is `6.26.1440` and the appcast’s contents only show `6.24`, the check for “is `version` in the appcast feed” will fail. With `must_contain`, the check is told to “look for this string instead of `version`”. In the example, `must_contain: version.major_minor` is saying “look for `6.24`”, making the check succeed. +Sometimes a `version` doesn’t match a string on the webpage, in which case we tweak what to search for. For example, if `version` is `6.26.1440` and the appcast’s contents only show `6.24`, the check for “is `version` in the appcast feed” will fail. With `must_contain`, the check is told to “look for this string instead of `version`”. In the example, `must_contain: version.major_minor` is saying “look for `6.24`”, making the check succeed. -If no `must_contain` is given, the check considers from the beginning of the `version` string until the first character that isn’t alphanumeric or a period. Example: if `version` is `6.26b-14,40`, the check will see `6.26b`. This is so it covers most cases by default, while still allowing complex `version`s suitable for interpolation on the rest of the cask. - -Example of using `must_contain`: [`hwsensors.rb`](https://github.com/Homebrew/homebrew-cask/blob/87bc3860f43d5b14d0c38ae8de469d24ee7f5b2f/Casks/hwsensors.rb#L6L7) +If no `must_contain` is given, the check considers from the beginning of the `version` string until the first character that isn’t alphanumeric or a period. For example, if `version` is `6.26b-14,40`, the check will look for `6.26b`. This is so it covers most cases by default, while still allowing complex `version`s suitable for interpolation in the rest of the cask. ### Stanza: `binary` -In the simple case of a string argument to `binary`, the source file is linked into the `$(brew --prefix)/bin` directory (typically `/usr/local/bin`) on installation. For example (from [operadriver.rb](https://github.com/Homebrew/homebrew-cask/blob/60531a2812005dd5f17dc92f3ce7419af3c5d019/Casks/operadriver.rb#L11)): +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/8145c76101534aabcfc419488578455e636d6330/Casks/operadriver.rb#L15)): ```ruby -binary "operadriver" +binary "operadriver_mac64/operadriver" ``` creates a symlink to: @@ -328,7 +321,7 @@ $(brew --prefix)/bin/operadriver from a source file such as: ```bash -/usr/local/Caskroom/operadriver/0.2.2/operadriver +$(brew --caskroom)/operadriver/106.0.5249.119/operadriver_mac64/operadriver ``` A binary (or multiple) can also be contained in an application bundle: @@ -344,7 +337,7 @@ You can rename the target which appears in your binaries directory by adding a ` 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/9ad93b833961f1d969505bc6bdb1c2ad4e58a433/Casks/openscad.rb#L12), [removing an extension](https://github.com/Homebrew/homebrew-cask/blob/c443d4f5c6864538efe5bb1ecf662565a5ffb438/Casks/filebot.rb#L13), or [cleaning up the name](https://github.com/Homebrew/homebrew-cask/blob/146917cbcc679648de6b0bccff4e9b43fce0e6c8/Casks/minishift.rb#L13). +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/36c6305caf2e9d543192632165c9c722b3f1451d/Casks/godot.rb#L17), [removing an extension](https://github.com/Homebrew/homebrew-cask/blob/e607b7e27f90316df5213fc9061f7dfa608e7f84/Casks/filebot.rb#L19), or [cleaning up the name](https://github.com/Homebrew/homebrew-cask/blob/7c72a90cb38ea2082688ceab0615dd866d833e7f/Casks/fig.rb#L21). ### Stanza: `caveats` @@ -352,29 +345,29 @@ Sometimes there are particularities with the installation of a piece of software 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 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 +#### `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: +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, typically `/usr/local/Caskroom/` (only available with block form) -| `staged_path` | the staged location for this Cask, including version number: `/usr/local/Caskroom//` (only available with block form) +| `token` | the cask token +| `version` | the cask version +| `homepage` | the cask homepage +| `caskroom_path` | the containing directory for this cask: `$(brew --caskroom)/` (only available with block form) +| `staged_path` | the staged location for this cask, including version number: `$(brew --caskroom)//` (only available with block form) Example: ```ruby -caveats "Using #{token} is hazardous to your health." +caveats "Using #{token} may be hazardous to your health." ``` -#### caveats as a Block +#### `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`. +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`](https://rubydoc.brew.sh/Cask/Cask). -#### caveats Mini-DSL +#### `caveats` Mini-DSL There is a mini-DSL available within `caveats` blocks. @@ -382,17 +375,18 @@ 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). -| `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. -| `discontinued` | all software development has been officially discontinued upstream. -| `free_license "web_page"` | users may get an official license to use the software at `web_page`. -| `kext` | users may need to enable their kexts in System Preferences → Security & Privacy → General. -| `unsigned_accessibility` | users will need to re-enable the app on each update in System Preferences → Security & Privacy → Privacy as it is unsigned. -| `license "web_page"` | software has a usage license at `web_page`. +| `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. +| `discontinued` | All software development has been officially discontinued upstream. +| `kext` | Users may need to enable their kexts in *System Preferences → Security & Privacy → General*. +| `unsigned_accessibility` | Users will need to re-enable the app on each update in *System Preferences → Security & Privacy → Privacy* as it is unsigned. +| `license "web_page"` | Users may find the software's usage license at `web_page`. +| `free_license "web_page"` | Users may obtain an official license to use the software at `web_page`. Example: @@ -404,25 +398,25 @@ end ### Stanza: `conflicts_with` -`conflicts_with` is used to declare conflicts that keep a Cask from installing or working correctly. +`conflicts_with` is used to declare conflicts that keep a cask from installing or working correctly. -#### conflicts_with cask +#### `conflicts_with` *cask* -The value should be another Cask token. +The value should be another cask token. -Example use: [`wireshark`](https://github.com/Homebrew/homebrew-cask/blob/903493e09cf33b845e7cf497ecf9cfc9709087ee/Casks/wireshark.rb#L10), which conflicts with `wireshark-chmodbpf`. +Example: [Wireshark](https://github.com/Homebrew/homebrew-cask/blob/01ae340fd7f449e222d4b2dec1186edf9278cdfb/Casks/wireshark.rb#L20), which conflicts with `wireshark-chmodbpf`. ```ruby conflicts_with cask: "wireshark-chmodbpf" ``` -#### conflicts_with formula +#### `conflicts_with` *formula* -Note: `conflicts_with formula:` is a stub and is not yet functional. +**Note:** `conflicts_with formula:` is a stub and is not yet functional. The value should be another formula name. -Example use: [`macvim`](https://github.com/Homebrew/homebrew-cask/blob/84b90afd7b571e581f8a48d4bdf9c7bb24ebff3b/Casks/macvim.rb#L10), which conflicts with the `macvim` formula. +Example: [MacVim](https://github.com/Homebrew/homebrew-cask/blob/7ed1a049e23196358f2ed1e6a57412cc479aceb8/Casks/macvim.rb#L16), which conflicts with the `macvim` formula. ```ruby conflicts_with formula: "macvim" @@ -430,30 +424,29 @@ conflicts_with formula: "macvim" ### Stanza: `depends_on` -`depends_on` is used to declare dependencies and requirements for a Cask. -`depends_on` is not consulted until `install` is attempted. +`depends_on` is used to declare dependencies and requirements for a cask. `depends_on` is not consulted until `install` is attempted. -#### depends_on cask +#### `depends_on` *cask* -The value should be another Cask token, needed by the current Cask. +The value should be another cask token, needed by the current cask. -Example use: [`cellery`](https://github.com/Homebrew/homebrew-cask/blob/4002df8f6bca93ed6eb40494995fcfa038cf99bf/Casks/cellery.rb#L11) depends on OSXFUSE: +Example: [NTFSTool](https://github.com/Homebrew/homebrew-cask/blob/b7ac7fca6538f6c8a36a8128d76cfceadfb8b653/Casks/ntfstool.rb#L11), which depends on macFUSE. ```ruby -depends_on cask: "osxfuse" +depends_on cask: "macfuse" ``` -#### depends_on formula +#### `depends_on` *formula* -The value should name a Homebrew Formula needed by the Cask. +The value should name a Homebrew formula needed by the cask. -Example use: 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 Homebrew Formula `unar`: +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 +#### `depends_on` *macos* ##### Requiring an Exact macOS Release @@ -461,8 +454,8 @@ The value for `depends_on macos:` may be a symbol or an array of symbols, listin The available values for macOS releases are: -| symbol | corresponding release -| -------------------|---------------------- +| symbol | corresponding release | +| ------------------ | --------------------- | | `:el_capitan` | `10.11` | `:sierra` | `10.12` | `:high_sierra` | `10.13` @@ -472,7 +465,7 @@ The available values for macOS releases are: | `:monterey` | `12` | `:ventura` | `13` -Only major releases are covered (version numbers containing a single dot). The symbol form is used for readability. The following are all valid ways to enumerate the exact macOS release requirements for a Cask: +Only major releases are covered (version numbers containing a single dot). The symbol form is used for readability. The following are all valid ways to enumerate the exact macOS release requirements for a cask: ```ruby depends_on macos: :big_sur @@ -492,17 +485,17 @@ depends_on macos: ">= :big_sur" A comparison expression cannot be combined with any other form of `depends_on macos:`. -#### depends_on arch +#### `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 multiple `arch:` value matches the user’s hardware. +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 multiple `arch:` values matches the user’s hardware. The available symbols for hardware are: | symbol | meaning | | ---------- | -------------- | -| `:x86_64` | 64-bit Intel | -| `:intel` | 64-bit Intel | -| `:arm64` | Apple Silicon | +| `:x86_64` | 64-bit Intel +| `:intel` | 64-bit Intel +| `:arm64` | Apple Silicon The following are all valid expressions: @@ -513,14 +506,14 @@ depends_on arch: [:x86_64] # same meaning as above depends_on arch: :arm64 ``` -#### All depends_on Keys +#### `depends_on` Parameters | key | description | | ---------- | ----------- | -| `formula:` | a Homebrew Formula -| `cask:` | a Cask token -| `macos:` | a symbol, string, array, or comparison expression defining macOS release requirements -| `arch:` | a symbol or array defining hardware requirements +| `formula:` | Homebrew formula +| `cask:` | cask token +| `macos:` | symbol, string, array, or comparison expression defining macOS release requirements +| `arch:` | symbol or array defining hardware requirements | `java:` | *stub - not yet functional* ### Stanza: `desc` @@ -545,7 +538,7 @@ depends_on arch: :arm64 + desc "Sound and music editor" ``` -* **Do** describe what the software does or is: +* **Do** describe what the software does or is. ```diff - desc "Development of musical ideas made easy" @@ -559,14 +552,14 @@ depends_on arch: :arm64 + desc "Sound and music editor" ``` -* **Do not** include the Cask’s [name](#stanza-name). +* **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. +* **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" @@ -587,13 +580,15 @@ depends_on arch: :arm64 + desc "Sound and music editor" ``` -### Stanza: `\*flight` +### Stanza: `*flight` + +The stanzas `preflight`, `postflight`, `uninstall_preflight`, and `uninstall_postflight` define operations to be run before or after installation or uninstallation. #### Evaluation of Blocks is Always Deferred -The Ruby blocks defined by `preflight`, `postflight`, `uninstall_preflight`, and `uninstall_postflight` are not evaluated until install time or uninstall time. Within a block, you may refer to the `@cask` instance variable, and invoke any method available on `@cask`. +The Ruby blocks defined by these stanzas are not evaluated until install time or uninstall time. Within a block you may refer to the `@cask` instance variable, and invoke [any method available on `@cask`](https://rubydoc.brew.sh/Cask/Cask). -#### \*flight Mini-DSL +#### `*flight` Mini-DSL There is a mini-DSL available within these blocks. @@ -601,10 +596,10 @@ The following methods may be called to perform standard tasks: | method | availability | description | | ----------------------------------------- | ------------------------------------------------ | ----------- | -| `set_ownership(paths)` | `preflight`, `postflight`, `uninstall_preflight` | set user and group ownership of `paths`. Example: [`unifi-controller.rb`](https://github.com/Homebrew/homebrew-cask/blob/8a452a41707af6a661049da6254571090fac5418/Casks/unifi-controller.rb#L13) -| `set_permissions(paths, permissions_str)` | `preflight`, `postflight`, `uninstall_preflight` | set permissions in `paths` to `permissions_str`. Example: [`docker-machine.rb`](https://github.com/Homebrew/homebrew-cask/blob/8a452a41707af6a661049da6254571090fac5418/Casks/docker-machine.rb#L16) +| `set_ownership(paths)` | `preflight`, `postflight`, `uninstall_preflight` | Set user and group ownership of `paths`. (Example: [docker-toolbox.rb](https://github.com/Homebrew/homebrew-cask/blob/9cd40bb37d6e7977340c6396c3574ceb1164a6be/Casks/docker-toolbox.rb#L42)) +| `set_permissions(paths, permissions_str)` | `preflight`, `postflight`, `uninstall_preflight` | Set permissions in `paths` to `permissions_str`. (Example: [ngrok.rb](https://github.com/Homebrew/homebrew-cask/blob/3d5e870b1a5324a138a01ffbd3b60f4cad9630b7/Casks/ngrok.rb#L30)) -`set_ownership(paths)` defaults user ownership to the current user and group ownership to `staff`. These can be changed by passing in extra options: `set_ownership(paths, user: 'user', group: 'group')`. +`set_ownership(paths)` defaults user ownership to the current user and group ownership to `staff`. These can be changed by passing in extra options: `set_ownership(paths, user: "user", group: "group")`. (Example: [wsjtx.rb](https://github.com/Homebrew/homebrew-cask/blob/2648e02fc0c0db1bd47fe931b8bfd2eeef16b71a/Casks/wsjtx.rb#L21)) ### Stanza: `installer` @@ -612,33 +607,33 @@ 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* -`installer manual:` takes a single string value, describing a GUI installer which must be run by the user at a later time. The path may be absolute, or relative to the Cask. Example (from [nutstore.rb](https://github.com/Homebrew/homebrew-cask/blob/249ec31048591308e63e50f79dae01d2f933cccf/Casks/nutstore.rb#L9)): +`installer manual:` takes a single string value, describing a GUI installer which must be run by the user at a later time. The path may be absolute, or relative to the cask. Example (from [nutstore.rb](https://github.com/Homebrew/homebrew-cask/blob/2820a91fd156f9cfcf16121d885bf5d6b572ed46/Casks/nutstore.rb#L18)): ```ruby installer manual: "Nutstore Installer.app" ``` -#### installer script +#### `installer` *script* -`installer script:` introduces 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:`: +`installer script:` introduces 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 -| ----------------|------------------------------ +| 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 -| `sudo:` | set to `true` if the script needs `sudo` +| `sudo:` | set to `true` if the script needs *sudo* -The path may be absolute, or relative to the Cask. Example (from [miniforge.rb](https://github.com/Homebrew/homebrew-cask/blob/ed2033fb3578376c3ee58a2cb459ef96fa6eb37d/Casks/miniforge.rb#L15L18)): +The path may be absolute, or relative to the cask. Example (from [miniforge.rb](https://github.com/Homebrew/homebrew-cask/blob/8bcb2763b1646c0059b5db4cd14cae2fd7fb2621/Casks/miniforge.rb#L23-L26)): ```ruby - installer script: { - executable: "Miniforge3-#{version}-MacOSX-x86_64.sh", - args: ["-b", "-p", "#{caskroom_path}/base"], - } +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-values it can point directly to the path of the install script: @@ -689,13 +684,13 @@ The return value of the matching `language` block can be accessed by simply call homepage "https://example.org/#{language}" ``` -Examples: [Firefox](https://github.com/Homebrew/homebrew-cask/blob/306b8fbd9502036f1ca742f70c569d8677b62403/Casks/firefox.rb#L4L74), [Battle.net](https://github.com/Homebrew/homebrew-cask/blob/306b8fbd9502036f1ca742f70c569d8677b62403/Casks/battle-net.rb#L5L17) +Examples: [firefox.rb](https://github.com/Homebrew/homebrew-cask/blob/b0053f9715d37659265ddb4cf3c485425bcb6756/Casks/firefox.rb#L4-L210), [battle-net.rb](https://github.com/Homebrew/homebrew-cask/blob/c939e584fc71e41d08904a95cc5e35d0d48a0544/Casks/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 ``` @@ -703,15 +698,15 @@ brew install firefox --language=it The `livecheck` stanza is used to automatically fetch the latest version of a cask from changelogs, release notes, appcasts, etc. See also: [`brew livecheck` reference](Brew-Livecheck.md) -Every `livecheck` block must contain a `url`, which can either be a string or a symbol pointing to other URLs in the cask (`:url` or `:homepage`). +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`). Additionally, a `livecheck` should specify which `strategy` should be used to extract the version: -| `strategy` | Description | -|-----------------|-----------| -| `:header_match` | extract version from HTTP headers (e.g. `Location` or `Content-Disposition`) | -| `:page_match` | extract version from page contents | -| `:sparkle` | extract version from Sparkle appcast contents | +| `strategy` | description | +|---------------- | ----------- | +| `:header_match` | extract version from HTTP headers (e.g. `Location` or `Content-Disposition`) +| `:page_match` | extract version from page contents +| `:sparkle` | extract version from Sparkle appcast contents Here is a basic example, extracting a simple version from a page: @@ -733,14 +728,14 @@ livecheck do end ``` -The `header_match` strategy will try parsing a version from the filename (in the `Content-Disposition` header) and the final URL (in the `Location` header). If that doesn't work, a `regex` can be specified, e.g.: +The `header_match` strategy will try to parse a version from the filename (in the `Content-Disposition` header) and the final URL (in the `Location` header). If that doesn't work, a `regex` can be specified, e.g.: ```ruby strategy :header_match regex(/MyApp-(\d+(?:\.\d+)*)\.zip/i) ``` -If the version depends on multiple header fields, a block can be specified, e.g. +If the version depends on multiple header fields, a block can be specified, e.g.: ```ruby strategy :header_match do |headers| @@ -767,17 +762,17 @@ end `name` accepts a UTF-8 string defining the name of the software, including capitalization 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 capitalization, 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, and including the vendor name if necessary. A good example is [`pycharm-ce`](https://github.com/Homebrew/homebrew-cask/blob/fc05c0353aebb28e40db72faba04b82ca832d11a/Casks/pycharm-ce.rb#L6-L7), whose name is spelled out as `Jetbrains PyCharm Community Edition`, even though it is likely never referenced as such anywhere. +Unlike the [token](#token-reference), which is simplified and reduced to a limited set of characters, the `name` stanza can include the proper capitalization, 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/cf92ff397b6c6cb7480cd15690b48ab0ce654dfc/Casks/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. +Additional details about the software can be provided in the [`desc` stanza](#stanza-desc). -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/0fe48607f5656e4f1de58c6884945378b7e6f960/Casks/cave-story.rb#L7-L9) cask, whose original name does not use the Latin alphabet. +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/6b07917a10dc34c4a2f784df9c17b9c68cdfc0ed/Casks/cave-story.rb#L48-L50) cask, whose original name does not use the Latin alphabet. ### Stanza: `pkg` -This stanza must always be accompanied by [`uninstall`](#stanza-uninstall) +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. For example: +The first argument to the `pkg` stanza should be a relative path to the `.pkg` file to be installed. Example: ```ruby pkg "Unity.pkg" @@ -785,73 +780,68 @@ pkg "Unity.pkg" Subsequent arguments to `pkg` are key/value pairs which modify the install process. Currently supported keys are `allow_untrusted:` and `choices:`. -#### `pkg allow_untrusted:` +#### `pkg` *allow_untrusted* -`pkg allow_untrusted: true` can be used to install the `.pkg` with an untrusted certificate passing `-allowUntrusted` to `/usr/sbin/installer`. +`pkg allow_untrusted: true` can be used to install a `.pkg` containing an untrusted certificate by passing `-allowUntrusted` to `/usr/sbin/installer`. -This option is not permitted in official Homebrew Cask taps, it is only provided for use in third-party taps or local Casks. +This option is not permitted in official Homebrew Cask taps; it is only provided for use in third-party taps or local casks. -Example ([alinof-timer.rb](https://github.com/Homebrew/homebrew-cask/blob/312ae841f1f1b2ec07f4d88b7dfdd7fbdf8d4f94/Casks/alinof-timer.rb#L10)): +Example (from [alinof-timer.rb](https://github.com/Homebrew/homebrew-cask/blob/312ae841f1f1b2ec07f4d88b7dfdd7fbdf8d4f94/Casks/alinof-timer.rb#L10)): ```ruby pkg "AlinofTimer.pkg", allow_untrusted: true ``` -#### `pkg choices:` +#### `pkg` *choices* -`pkg choices:` can be used to override `.pkg`’s default install options via `-applyChoiceChangesXML`. It uses a deserialized 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`). +`pkg choices:` can be used to override a `.pkg`’s default install options via `-applyChoiceChangesXML`. It uses a deserialized 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 the macOS command: +Running this macOS `installer` command: ```bash installer -showChoicesXML -pkg '/path/to/my.pkg' ``` -will output an XML which you can use to extract the `choices:` values, as well as their equivalents to the GUI options. +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 ([wireshark-chmodbpf.rb](https://github.com/Homebrew/homebrew-cask/blob/f95b8a8306b91fe9da7908b842f4a5fa80f7afe0/Casks/wireshark-chmodbpf.rb#L9-L26)): +Example (from [lando.rb](https://github.com/Homebrew/homebrew-cask/blob/e35c4ac349c21262b460535c57a8f37e7fe6de27/Casks/lando.rb#L21-L33)): ```ruby -pkg "Wireshark #{version} Intel 64.pkg", +pkg "LandoInstaller.pkg", choices: [ - { - "choiceIdentifier" => "wireshark", - "choiceAttribute" => "selected", - "attributeSetting" => 0, - }, - { - "choiceIdentifier" => "chmodbpf", - "choiceAttribute" => "selected", - "attributeSetting" => 1, - }, - { - "choiceIdentifier" => "cli", - "choiceAttribute" => "selected", - "attributeSetting" => 0, - }, - ] + { + "choiceIdentifier" => "choiceDocker", + "choiceAttribute" => "selected", + "attributeSetting" => 0, + }, + { + "choiceIdentifier" => "choiceLando", + "choiceAttribute" => "selected", + "attributeSetting" => 1, + }, + ] ``` -Example ([wine-staging.rb](https://github.com/Homebrew/homebrew-cask/blob/51b65f6a5a25a7f79af4d372e1a0bf1dc3849251/Casks/wine-staging.rb#L11-L18)): +Example (from [microsoft-office.rb](https://github.com/Homebrew/homebrew-cask/blob/7d0fb4a6527c1836bf326dce8dff9966be8e7da0/Casks/microsoft-office.rb#L27-L34)): ```ruby -pkg "winehq-staging-#{version}.pkg", +pkg "Microsoft_Office_#{version}_Installer.pkg", choices: [ - { - "choiceIdentifier" => "choice3", - "choiceAttribute" => "selected", - "attributeSetting" => 1, - }, - ] + { + "choiceIdentifier" => "com.microsoft.autoupdate", # Office16_all_autoupdate.pkg + "choiceAttribute" => "selected", + "attributeSetting" => 0, + }, + ] ``` ### Stanza: `sha256` -#### Calculating the SHA256 +#### Calculating the SHA-256 -The `sha256` value is usually calculated by the command: +The `sha256` value is usually calculated by the `shasum` command: ```bash shasum --algorithm 256 @@ -869,10 +859,10 @@ We use a checksum whenever possible. 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 [sketchup.rb](https://github.com/Homebrew/homebrew-cask/blob/312ae841f1f1b2ec07f4d88b7dfdd7fbdf8d4f94/Casks/sketchup.rb#L12)): +For these casks, use the `suite` stanza to define the directory containing the application suite. Example (from [sketchup.rb](https://github.com/Homebrew/homebrew-cask/blob/e3495e32b7fb3ed1929b6082a4e3eb6a94d9494f/Casks/sketchup.rb#L12)): ```ruby -suite "SketchUp 2016" +suite "SketchUp #{version.csv.first}" ``` The value of `suite` is never an `.app` bundle, but a plain directory. @@ -883,15 +873,15 @@ The value of `suite` is never an `.app` bundle, but a plain directory. #### `uninstall pkgutil:` Is The Easiest and Most Useful -`pkgutil:` is the easiest and most useful `uninstall` directive. See [Uninstall Key pkgutil:](#uninstall-key-pkgutil). +The easiest and most useful `uninstall` directive is [`pkgutil:`](#uninstall-pkgutil). It should cover most use cases. -#### `uninstall` Is Required for Casks That Install a pkg or installer manual +#### `uninstall` Is Required for Casks That Install using `pkg` or `installer manual:` -For most Casks, uninstall actions are determined automatically, and an explicit `uninstall` stanza is not needed. However, a Cask which uses the `pkg` or `installer manual:` stanzas will **not** know how to uninstall correctly unless an `uninstall` stanza is given. +For most casks, uninstall actions are determined automatically, and an explicit `uninstall` stanza is not needed. However, a cask which uses the `pkg` or `installer manual:` 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 end-users if every `pkg` and `installer manual:` has a corresponding `uninstall`. +So, while the [cask DSL](#required-stanzas) does not enforce the requirement, it is much better for users if every `pkg` and `installer manual:` has a corresponding `uninstall`. -The `uninstall` stanza is available for non-`pkg` Casks, 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`. +The `uninstall` stanza is available for non-`pkg` casks, 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 @@ -899,114 +889,114 @@ Since `pkg` installers can do arbitrary things, different techniques are needed #### Summary of Keys -* `early_script:` (string or hash) - like [`script:`](#uninstall-key-script), but runs early (for special cases, best avoided) -* [`launchctl:`](#uninstall-key-launchctl) (string or array) - ids of `launchctl` jobs to remove -* [`quit:`](#uninstall-key-quit) (string or array) - bundle ids of running applications to quit -* [`signal:`](#uninstall-key-signal) (array of arrays) - signal numbers and bundle ids of running applications to send a Unix signal to (used when `quit:` does not work) -* [`login_item:`](#uninstall-key-login_item) (string or array) - names of login items to remove -* [`kext:`](#uninstall-key-kext) (string or array) - bundle ids of kexts to unload from the system -* [`script:`](#uninstall-key-script) (string or hash) - relative path to an uninstall script to be run via sudo; use hash if args are needed +* **`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) +* [`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 to be run via sudo; use hash if args are needed * `executable:` - relative path to an uninstall script to be run via sudo (required for hash form) * `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 - * `sudo:` - set to `true` if the script needs `sudo` -* [`pkgutil:`](#uninstall-key-pkgutil) (string, regexp or array of strings and regexps) - strings or regexps matching bundle ids of packages to uninstall using `pkgutil` -* [`delete:`](#uninstall-key-delete) (string or array) - single-quoted, absolute paths of files or directory trees to remove. `delete:` should only be used as a last resort. `pkgutil:` is strongly preferred. -* `rmdir:` (string or array) - single-quoted, absolute paths of directories to remove if empty. Works recursively. -* [`trash:`](#uninstall-key-trash) (string or array) - single-quoted, absolute paths of files or directory trees to move to Trash. + * `sudo:` - set to `true` if the script needs *sudo* +* [`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) - single-quoted, absolute paths of files or directory trees to remove. Should only be used as a last resort; `pkgutil:` is strongly preferred. +* **`rmdir:`** (string or array) - single-quoted, absolute paths of directories to remove if empty. Works recursively. +* [`trash:`](#uninstall-trash) (string or array) - single-quoted, absolute paths of files or directory trees to move to Trash -Each `uninstall` technique is applied according to the order above. The order in which `uninstall` keys appear in the Cask file is ignored. +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 scripts found under `developer/bin` in the Homebrew Cask repository. Each of these scripts responds to the `-help` option with additional documentation. -The easiest way to work out an `uninstall` stanza is on a system where the `pkg` 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. +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` Key `pkgutil:` +#### `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 the command: +IDs for the most recently installed packages can be listed using [`list_recent_pkg_ids`](https://github.com/Homebrew/homebrew-cask/blob/HEAD/developer/bin/list_recent_pkg_ids): ```bash "$(brew --repository homebrew/cask)/developer/bin/list_recent_pkg_ids" ``` -`pkgutil:` also accepts a regular expression match against multiple package IDs. The regular expressions are somewhat nonstandard. To test a `pkgutil:` regular expression against currently-installed packages, use the command: +`pkgutil:` also accepts a regular expression match against multiple package IDs. The regular expressions are somewhat nonstandard. To test a `pkgutil:` regular expression against currently installed packages, use [`list_pkg_ids_by_regexp`](https://github.com/Homebrew/homebrew-cask/blob/HEAD/developer/bin/list_pkg_ids_by_regexp): ```bash "$(brew --repository homebrew/cask)/developer/bin/list_pkg_ids_by_regexp" ``` -#### List Files Associated With a pkg Id +#### List Files Associated With a Package ID -Once you know the ID for an installed package, (above), you can list all files on your system associated with that package ID using the macOS command: +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 ``` -Listing the associated files can help you assess whether the package included any `launchctl` jobs or kernel extensions (kexts). +Listing the associated files can help you assess whether the package included any `launchd` jobs or kernel extensions (kexts). -#### `uninstall` Key `launchctl:` +#### `uninstall` *launchctl* -IDs for currently loaded `launchctl` jobs can be listed using the command: +IDs for currently loaded `launchd` jobs can be listed using [`list_loaded_launchjob_ids`](https://github.com/Homebrew/homebrew-cask/blob/HEAD/developer/bin/list_loaded_launchjob_ids): ```bash "$(brew --repository homebrew/cask)/developer/bin/list_loaded_launchjob_ids" ``` -IDs for all installed `launchctl` jobs can be listed using the command: +IDs for all installed `launchd` jobs can be listed using [`list_installed_launchjob_ids`](https://github.com/Homebrew/homebrew-cask/blob/HEAD/developer/bin/list_installed_launchjob_ids): ```bash "$(brew --repository homebrew/cask)/developer/bin/list_installed_launchjob_ids" ``` -#### `uninstall` Key `quit:` +#### `uninstall` *quit* -Bundle IDs for currently running Applications can be listed using the command: +Bundle IDs for currently running applications can be listed using [`list_running_app_ids`](https://github.com/Homebrew/homebrew-cask/blob/HEAD/developer/bin/list_running_app_ids): ```bash "$(brew --repository homebrew/cask)/developer/bin/list_running_app_ids" ``` -Bundle IDs inside an Application bundle on disk can be listed using the command: +Bundle IDs inside an application bundle on disk can be listed using [`list_ids_in_app`](https://github.com/Homebrew/homebrew-cask/blob/HEAD/developer/bin/list_ids_in_app): ```bash "$(brew --repository homebrew/cask)/developer/bin/list_ids_in_app" '/path/to/application.app' ``` -#### `uninstall` Key `signal:` +#### `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 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. +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` man page for more details). +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 which are sufficient to stop a process. The `KILL` signal in particular can have unwanted side-effects. +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: +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"], - ] +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 signaled. +Note that when multiple running processes match the given bundle ID, all matching processes will be signaled. 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 may also be considered a bug, and should be addressed in some fashion in a future version. -## `uninstall` key `login_item:` +#### `uninstall` *login_item* -Login items associated with an Application bundle on disk can be listed using the command: +Login items associated with an application bundle on disk can be listed using [`list_login_items_for_app`](https://github.com/Homebrew/homebrew-cask/blob/HEAD/developer/bin/list_login_items_for_app): ```bash "$(brew --repository homebrew/cask)/developer/bin/list_login_items_for_app" '/path/to/application.app' @@ -1014,34 +1004,37 @@ Login items associated with an Application bundle on disk can be listed using th Note that you will likely need to have opened the app at least once for any login items to be present. -#### `uninstall` Key `kext:` +#### `uninstall` *kext* -IDs for currently loaded kernel extensions can be listed using the command: +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 you have located on disk can be listed using the command: +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` Key `script:` +#### `uninstall` *script* -`uninstall script:` introduces a series of key-value pairs describing a command which will automate completion of the uninstall. Example (from [gpgtools.rb](https://github.com/Homebrew/homebrew-cask/blob/4a0a49d1210a8202cbdd54bce2986f15049b8b61/Casks/gpgtools.rb#L33-#L37)): +`uninstall script:` introduces a series of key-value pairs describing a command which will automate completion of the uninstall. Example (from [virtualbox.rb](https://github.com/Homebrew/homebrew-cask/blob/af2f04dd54228b970d241b790d3380f3356cf900/Casks/virtualbox.rb#L55-L61)): ```ruby - uninstall script: { - executable: "#{staged_path}/Uninstall.app/Contents/Resources/GPG Suite Uninstaller.app/Contents/Resources/uninstall.sh", - sudo: true, - } +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 detriment of [`pkgutil:`](#uninstall-key-pkgutil), but as a complement when possible. +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` Key `delete:` +#### `uninstall` *delete* `delete:` should only be used as a last resort, if other `uninstall` methods are insufficient. @@ -1053,39 +1046,39 @@ Arguments to `uninstall delete:` should use the following basic rules: To remove user-specific files, use the [`zap` stanza](#stanza-zap). -#### `uninstall` Key `trash:` +#### `uninstall` *trash* `trash:` arguments follow the same rules listed above for `delete:`. -#### Working With a pkg File Manually +#### Working With a `.pkg` File Manually -Advanced users may wish to work with a `pkg` file manually, without having the package installed. +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 the command: +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 the command: +Candidate application names helpful for determining the name of a cask may be extracted from a `.pkg` file using [`list_apps_in_pkg`](https://github.com/Homebrew/homebrew-cask/blob/HEAD/developer/bin/list_apps_in_pkg): ```bash "$(brew --repository homebrew/cask)/developer/bin/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 the command: +Candidate package IDs which may be useful in a `pkgutil:` key may be extracted from a `.pkg` file using [`list_ids_in_pkg`](https://github.com/Homebrew/homebrew-cask/blob/HEAD/developer/bin/list_ids_in_pkg): ```bash "$(brew --repository homebrew/cask)/developer/bin/list_ids_in_pkg" '/path/to/my.pkg' ``` -A fully manual method for finding bundle ids in a package file follows: +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 `` tags that look like ``, where extraneous attributes have been snipped out and replaced with ellipses. +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 `` tags that look like ``, 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 `` tag with a `path` attribute that contains a `.kext` extension, for example ``. -5. Once bundle ids have been identified, the unpacked package directory can be deleted. +5. Once bundle IDs have been identified, the unpacked package directory can be deleted. ### Stanza: `url` @@ -1093,29 +1086,29 @@ A fully manual method for finding bundle ids in a package file follows: If available, an HTTPS URL is preferred. A plain HTTP URL should only be used in the absence of a secure alternative. -#### Additional HTTP/S URL Parameters +#### 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 | | ------------------ | ----------- | -| `verified:` | a string repeating the beginning of `url`, for verification purposes. [See below](#when-url-and-homepage-domains-differ-add-verified). +| `verified:` | string repeating the beginning of `url`, for [verification purposes](#when-url-and-homepage-domains-differ-add-verified) | `using:` | the symbol `:post` is the only legal value -| `cookies:` | a hash of cookies to be set in the download request -| `referer:` | a string holding the URL to set as referer in the download request -| `header:` | a string holding the header to set for the download request. -| `user_agent:` | a 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:` | a hash of parameters to be set in the POST request +| `cookies:` | hash of cookies to be set in the download request +| `referer:` | string holding the URL to set as referer in the download request +| `header:` | string holding the header to set for the download request +| `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 in the POST request -Example of using `cookies:`: [java.rb](https://github.com/Homebrew/homebrew-cask/blob/472930df191d66747a57d5c96c0d00511d56e21b/Casks/java.rb#L5-L8) +Example of using `cookies:`: [oracle-jdk-javadoc.rb](https://github.com/Homebrew/homebrew-cask/blob/cba3261569dc582f95f72356bda40ccb11c5809d/Casks/oracle-jdk-javadoc.rb#L5-L8) -Example of using `referer:`: [rrootage.rb](https://github.com/Homebrew/homebrew-cask/blob/312ae841f1f1b2ec07f4d88b7dfdd7fbdf8d4f94/Casks/rrootage.rb#L5) +Example of using `referer:`: [firealpaca.rb](https://github.com/Homebrew/homebrew-cask/blob/37f434b99f51259e642793d65b7490540b71dc21/Casks/firealpaca.rb#L5-L6) Example of using `header:`: [issue-325182724](https://github.com/Homebrew/brew/pull/6545#issue-325182724) #### When URL and Homepage Domains Differ, Add `verified:` -When the domains of `url` and `homepage` differ, the discrepancy should be documented with the `verified:` parameter, repeating the smallest possible portion of the URL that uniquely identifies the app or vendor, excluding the protocol. Example: [`shotcut.rb`](https://github.com/Homebrew/homebrew-cask/blob/08733296b49c59c58b6beeada59ed4207cef60c3/Casks/shotcut.rb#L5L6). +When the domains of `url` and `homepage` differ, the discrepancy should be documented with the `verified:` parameter, repeating the smallest possible portion of the URL that uniquely identifies the app or vendor, excluding the protocol. (Example: [shotcut.rb](https://github.com/Homebrew/homebrew-cask/blob/3184fb84140296cd16322a707596e1ab3d86c962/Casks/shotcut.rb#L8-L9)) This must be added so a user auditing the cask knows the URL was verified by the Homebrew Cask team as the one provided by the vendor, even though it may look unofficial. It is our responsibility as Homebrew Cask maintainers to verify both the `url` and `homepage` information when first added (or subsequently modified, apart from versioning). @@ -1123,7 +1116,7 @@ The parameter doesn’t mean you should trust the source blindly, but we only ap #### Difficulty Finding a URL -Web browsers may obscure the direct `url` download location for a variety of reasons. Homebrew Cask supplies a script which can read extended file attributes to extract the actual source URL for most files downloaded by a browser on macOS. The script usually emits multiple candidate URLs; you may have to test each of them: +Web browsers may obscure the direct `url` download location for a variety of reasons. Homebrew Cask supplies a [`list_url_attributes_on_file`](https://github.com/Homebrew/homebrew-cask/blob/HEAD/developer/bin/list_url_attributes_on_file) script which can read extended file attributes to extract the actual source URL of most files downloaded by a browser on macOS. The script usually emits multiple candidate URLs; you may have to test each of them: ```bash $(brew --repository homebrew/cask)/developer/bin/list_url_attributes_on_file @@ -1136,20 +1129,20 @@ In rare cases, a distribution may not be available over ordinary HTTP/S. Subvers | key | value | | ------------------ | ----------- | | `using:` | the symbol `:svn` is the only legal value -| `revision:` | a string identifying the subversion revision to download +| `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 also may 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`: +Artifacts also may 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:` | a string identifying the git tag to download -| `revision:` | a string identifying the git revision to download -| `branch:` | a string identifying the git branch to download -| `only_path:` | a path within the repository to limit the checkout to. If only a single directory of a large repository is required, using this option can signficantly speed up downloads. If provided, artifact paths are relative to this path. +| `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 signficantly speed up downloads. If provided, artifact paths are relative to this path. #### SourceForge/OSDN URLs @@ -1157,27 +1150,19 @@ SourceForge and OSDN (formerly `SourceForge.JP`) projects are common ways to dis We prefer URLs of this format: -``` -https://downloads.sourceforge.net//. -``` + https://downloads.sourceforge.net//. -Or, if it’s from [OSDN](https://osdn.jp/): +Or, if it’s from [OSDN](https://osdn.net/), where `` is typically of the form `dl` or `.dl`: -``` -http://.osdn.jp///. -``` - -`` is typically of the form `dl` or `.dl`. + http://.osdn.jp///. 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//files/latest/download -``` + https://sourceforge.net/projects//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. +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). While some cases [could be circumvented](#using-a-block-to-defer-code-execution), they 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. @@ -1187,15 +1172,15 @@ Some casks—notably nightlies—have versioned download URLs but are updated so ##### The Problem -In theory, one can write arbitrary Ruby code right in the Cask definition to fetch and construct a disposable URL. +In theory, one can write arbitrary Ruby code right in the cask definition to fetch and construct a disposable URL. -However, this typically involves an HTTP round trip to a landing site, which may take a long time. Because of the way Homebrew Cask loads and parses Casks, it is not acceptable that such expensive operations be performed directly in the body of a Cask definition. +However, this typically involves an HTTP round trip to a landing site, which may take a long time. Because of the way Homebrew Cask loads and parses casks, it is not acceptable that such expensive operations be performed directly in the body of a cask definition. ##### Writing the Block Similar to the `preflight`, `postflight`, `uninstall_preflight`, and `uninstall_postflight` blocks, the `url` stanza offers an optional *block syntax*: -```rb +```ruby url "https://handbrake.fr/nightly.php" do |page| file_path = page[/href=["']?([^"' >]*Handbrake[._-][^"' >]+\.dmg)["' >]/i, 1] file_path ? URI.join(page.url, file_path) : nil @@ -1204,13 +1189,13 @@ end You can also nest `url do` blocks inside `url do` blocks to follow a chain of URLs. -The block is only evaluated when needed, for example on download time or when auditing a Cask. Inside a block, you may safely do things such as HTTP/S requests that may take a long time to execute. You may also refer to the `@cask` instance variable, and invoke any method available on `@cask`. +The block is only evaluated when needed, for example at download time or when auditing a cask. Inside a block, you may safely do things such as HTTP/S requests that may take a long time to execute. You may also refer to the `@cask` instance variable, and invoke [any method available on `@cask`](https://rubydoc.brew.sh/Cask/Cask). The block will be called immediately before downloading; its result value will be assumed to be a `String` (or a pair of a `String` and `Hash` containing parameters) and subsequently used as a download URL. You can use the `url` stanza with either a direct argument or a block but not with both. -Example for using the block syntax: [vlc-nightly.rb](https://github.com/Homebrew/homebrew-cask-versions/blob/2bf0f13dd49d263ebec0ca56e58ad8458633f789/Casks/vlc-nightly.rb#L5L10) +Example of using the block syntax: [vlc-nightly.rb](https://github.com/Homebrew/homebrew-cask-versions/blob/2bf0f13dd49d263ebec0ca56e58ad8458633f789/Casks/vlc-nightly.rb#L5-L10) ##### Mixing Additional URL Parameters With the Block Syntax @@ -1220,73 +1205,71 @@ This is possible by returning a two-element array as a block result. The first e ### 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). +`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 +For example, instead of: ```ruby version "1.2.3" url "https://example.com/file-version-123.dmg" ``` -We can use +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 +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 +we can use: ```ruby version "1.2.3build4" url "https://example.com/#{version.sub(%r{build\d+}, '')}/file-version-#{version}.dmg" ``` -#### version :latest +#### `version :latest` -The special value `:latest` is used on casks which: +The special value `:latest` is used in casks for which either: -1. `url` doesn’t contain a version. -2. Having a correct value to `version` is too difficult or impractical, even with our automated systems. +1. `url` doesn’t contain a version, or +2. having a correct value for `version` is too difficult or impractical, even with our automated systems. -Example: [spotify.rb](https://github.com/Homebrew/homebrew-cask/blob/f56e8ba057687690e26a6502623aa9476ff4ac0e/Casks/spotify.rb#L2) +Example: [chromium.rb](https://github.com/Homebrew/homebrew-cask/blob/f3e9de24ba57d7b1d949132504e581759725d0c5/Casks/chromium.rb#L4) -#### version methods +#### `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` | -| `before_comma` | `1.2.3-a45,ccdd88` | `1.2.3-a45` | -| `after_comma` | `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` | +| 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` +| `before_comma` | `1.2.3-a45,ccdd88` | `1.2.3-a45` +| `after_comma` | `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 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 of those at once. +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` that returns an array of comma-separated values. `csv`, `before_comma` and `after_comma` are extra special to allow for otherwise complex cases, and should be used sparingly. There should be no more than two of `,` per `version`. +Finally, there is `csv` which returns an array of comma-separated values. `csv`, `before_comma` and `after_comma` are extra-special to allow for otherwise complex cases, and should be used sparingly. There should be no more than two of `,` per `version`. ### Stanza: `zap` -#### `zap` Stanza Purpose +#### `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`: +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 @@ -1301,17 +1284,17 @@ brew uninstall --zap firefox * 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: +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` Stanza Syntax +#### `zap` Syntax -The form of `zap` stanza follows the [`uninstall` stanza](#stanza-uninstall). All of the same directives are available. The `trash:` key is preferred over `delete:`. +The form of the `zap` stanza follows the [`uninstall` stanza](#stanza-uninstall). All the same directives are available. The `trash:` key is preferred over `delete:`. -Example: [dropbox.rb](https://github.com/Homebrew/homebrew-cask/blob/31cd96cc0e00dab1bff74d622e32d816bafd1f6f/Casks/dropbox.rb#L17-L35) +Example: [dropbox.rb](https://github.com/Homebrew/homebrew-cask/blob/1391cefbe79d469509b882ec825bbb0e4f9d7966/Casks/dropbox.rb#L30-L68) #### `zap` Creation @@ -1319,10 +1302,10 @@ The simplest method is to use [@nrlquaker's CreateZap](https://github.com/nrlqua Manual creation can be facilitated with: -* Some of the developer tools are already available in Homebrew Cask. +* Some of the developer tools which are already available in Homebrew Cask. * `sudo find / -iname "**"` * An uninstaller tool such as [AppCleaner](https://github.com/Homebrew/homebrew-cask/blob/HEAD/Casks/appcleaner.rb). -* Inspecting the usual suspects, i.e. `/Library/{'Application Support',LaunchAgents,LaunchDaemons,Frameworks,Logs,Preferences,PrivilegedHelperTools}` and `~/Library/{'Application Support',Caches,Containers,LaunchAgents,Logs,Preferences,'Saved Application State'}`. +* 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'}`. --- @@ -1336,10 +1319,10 @@ This section describes the algorithm implemented in the `generate_cask_token` sc * [Cask Filenames](#cask-filenames) * [Cask Headers](#cask-headers) * [Cask Token Examples](#cask-token-examples) -* [Tap Specific Cask Token Examples](#tap-specific-cask-token-examples) -* [Token Overlap](#token-overlap) +* [Tap-Specific Cask Token Examples](#tap-specific-cask-token-examples) +* [Special Affixes](#special-affixes) -## Purpose +### Purpose Software vendors are often inconsistent with their naming. By enforcing strict naming conventions we aim to: @@ -1347,15 +1330,15 @@ Software vendors are often inconsistent with their naming. By enforcing strict n * Minimize renaming events * Unambiguously boil down the name of the software into a unique identifier -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. `name` accepts an unrestricted UTF-8 string. +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. `name` accepts an unrestricted UTF-8 string. -## Finding the Simplified Name of the Vendor’s Distribution +### Finding the Simplified Name of the Vendor’s Distribution -### Simplified Names of Apps +#### Simplified Names of Apps -* Start with the exact name of the Application bundle as it appears on disk, such as `Google Chrome.app`. +* 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). +* 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. @@ -1371,19 +1354,19 @@ Details of software names and brands will inevitably be lost in the conversion t * 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/playonmac.rb). -* Remove from the end: hardware designations such as “for x86”, “32-bit”, “ppc”. +* 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: 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 that 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, 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/unison.rb) and [panic-unison.rb](https://github.com/Homebrew/homebrew-cask/blob/HEAD/Casks/panic-unison.rb). +* If the result conflicts with the name of an existing cask, 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/unison.rb) and [panic-unison.rb](https://github.com/Homebrew/homebrew-cask/blob/HEAD/Casks/panic-unison.rb). * 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 +#### 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: @@ -1398,19 +1381,19 @@ Details of software names and brands will inevitably be lost in the conversion t * As a last resort, translate the name of the app bundle into English. -### Simplified Names of `pkg`-based Installers +#### 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 +#### Simplified Names of non-App Software * Currently, rules for generating a token are not well-defined for Preference Panes, QuickLook plugins, and several other types of software installable by Homebrew Cask. 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 standardized in the future. -## Converting the Simplified Name To a Token +### Converting the Simplified Name To a Token -The token is the primary identifier for a package in our project. It’s the unique string users refer to when operating on the Cask. +The token is the primary identifier for a package in this project. It’s the unique string users refer to when operating on the cask. To convert the App’s Simplified Name (above) to a token: @@ -1426,15 +1409,15 @@ To convert the App’s Simplified Name (above) to a token: * Collapse a series of multiple hyphens into one hyphen. * Delete a leading or trailing hyphen. -## Cask Filenames +### Cask Filenames Casks are stored in a Ruby file named after the token, with the file extension `.rb`. -## Cask Headers +### Cask Headers -The token is also given in the header line for each Cask. +The token is also given in the header line for each cask. -## Cask Token Examples +### Cask Token Examples These illustrate most of the rules for generating a token: @@ -1446,25 +1429,23 @@ App Name on Disk | Simplified App Name | Cask Token | Filename `LPK25 Editor.app` | LPK25 Editor | lpk25-editor | `lpk25-editor.rb` `Sublime Text 2.app` | Sublime Text | sublime-text | `sublime-text.rb` -## Tap Specific Cask Token Examples +#### Tap-Specific Cask Token Examples Cask taps have naming conventions specific to each tap. -[Homebrew/cask-versions](https://github.com/Homebrew/homebrew-cask-versions/blob/HEAD/CONTRIBUTING.md#naming-versions-casks) +* [Homebrew/cask-versions](https://github.com/Homebrew/homebrew-cask-versions/blob/HEAD/CONTRIBUTING.md#naming-versions-casks) +* [Homebrew/cask-fonts](https://github.com/Homebrew/homebrew-cask-fonts/blob/HEAD/CONTRIBUTING.md#naming-font-casks) +* [Homebrew/cask-drivers](https://github.com/Homebrew/homebrew-cask-drivers/blob/HEAD/CONTRIBUTING.md#naming-driver-casks) -[Homebrew/cask-fonts](https://github.com/Homebrew/homebrew-cask-fonts/blob/HEAD/CONTRIBUTING.md#naming-font-casks) - -[Homebrew/cask-drivers](https://github.com/Homebrew/homebrew-cask-drivers/blob/HEAD/CONTRIBUTING.md#naming-driver-casks) - -# Special Affixes +### Special Affixes A few situations require a prefix or suffix to be added to the token. -## Token Overlap +#### 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 (for possibly both Casks). See [Forks and Apps with Conflicting Names](Acceptable-Casks.md#forks-and-apps-with-conflicting-names) for information on how to proceed. +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 +#### 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. diff --git a/docs/Formula-Cookbook.md b/docs/Formula-Cookbook.md index daf02b572e..feb17f0323 100644 --- a/docs/Formula-Cookbook.md +++ b/docs/Formula-Cookbook.md @@ -4,29 +4,29 @@ A *formula* is a package definition written in Ruby. It can be created with `bre ## Homebrew terminology -| Term | Description | Example | -|----------------|------------------------------------------------------------|-----------------------------------------------------------------| -| **Formula** | The package definition | `/usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/Formula/foo.rb` | -| **Keg** | The installation prefix of a **Formula** | `/usr/local/Cellar/foo/0.1` | -| **Keg-only** | A **Formula** is **Keg-only** if it is not linked into the Homebrew prefix | The [`openjdk` formula](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/openjdk.rb) | -| **opt prefix** | A symlink to the active version of a **Keg** | `/usr/local/opt/foo ` | -| **Cellar** | All **Kegs** are installed here | `/usr/local/Cellar` | -| **Tap** | A Git repository of **Formulae** and/or commands | `/usr/local/Homebrew/Library/Taps/homebrew/homebrew-core` | -| **Bottle** | Pre-built **Keg** used instead of building from source | `qt-4.8.4.catalina.bottle.tar.gz` | -| **Cask** | An [extension of Homebrew](https://github.com/Homebrew/homebrew-cask) to install macOS native apps | `/Applications/MacDown.app/Contents/SharedSupport/bin/macdown` | -| **Brew Bundle**| An [extension of Homebrew](https://github.com/Homebrew/homebrew-bundle) to describe dependencies | `brew 'myservice', restart_service: true` | +| term | description | example | +| -------------- | ---------------------------------------------------------- | ------- | +| **Formula** | the package definition | `/usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/Formula/foo.rb` +| **Keg** | the installation prefix of a **Formula** | `/usr/local/Cellar/foo/0.1` +| **Keg-only** | a **Formula** is **Keg-only** if it is not linked into the Homebrew prefix | the [`openjdk`](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/openjdk.rb) formula +| **opt prefix** | a symlink to the active version of a **Keg** | `/usr/local/opt/foo` +| **Cellar** | all **Kegs** are installed here | `/usr/local/Cellar` +| **Tap** | a Git repository of **Formulae** and/or commands | `/usr/local/Homebrew/Library/Taps/homebrew/homebrew-core` +| **Bottle** | pre-built **Keg** used instead of building from source | `qt-4.8.4.catalina.bottle.tar.gz` +| **Cask** | an [extension of Homebrew](https://github.com/Homebrew/homebrew-cask) to install macOS native apps | `/Applications/MacDown.app/Contents/SharedSupport/bin/macdown` +| **Brew Bundle**| an [extension of Homebrew](https://github.com/Homebrew/homebrew-bundle) to describe dependencies | `brew 'myservice', restart_service: true` ## An introduction Homebrew uses Git for downloading updates and contributing to the project. -Homebrew installs to the `Cellar` and then symlinks some of the installation into `/usr/local` so that other programs can see what's going on. We suggest you `brew ls` a few of the kegs in your Cellar to see how it is all arranged. +Homebrew installs to the `Cellar` and then symlinks some of the installation into `/usr/local` so that other programs can see what's going on. We suggest running `brew ls` on a few of the kegs in your Cellar to see how it is all arranged. -Packages are installed according to their formulae, which live in `/usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/Formula`. Check out a simple one, e.g. `brew edit etl` (or [`etl`](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/etl.rb)) or a more advanced one, e.g. `brew edit git` (or [`git`](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/git.rb)). +Packages are installed according to their formulae, which live in `$(brew --repository)/Library/Taps/homebrew/homebrew-core/Formula`. Read over a simple one, e.g. `brew edit etl` (or [etl.rb](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/etl.rb)) or a more advanced one, e.g. `brew edit git` (or [git.rb](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/git.rb)). ## Basic instructions -Make sure you run `brew update` before you start. This turns your Homebrew installation into a Git repository. +Make sure you run `brew update` before you start. This ensures your Homebrew installation is a Git repository. Before submitting a new formula make sure your package: @@ -34,7 +34,7 @@ Before submitting a new formula make sure your package: * isn't already in Homebrew (check `brew search `) * isn't already waiting to be merged (check the [issue tracker](https://github.com/Homebrew/homebrew-core/pulls)) * is still supported by upstream (i.e. doesn't require extensive patching) -* has a stable, tagged version (i.e. not just a GitHub repository with no versions) +* has a stable, tagged version (i.e. isn't just a GitHub repository with no versions) * passes all `brew audit --new-formula ` tests Before submitting a new formula make sure you read over our [contribution guidelines](https://github.com/Homebrew/brew/blob/HEAD/CONTRIBUTING.md#contributing-to-homebrew). @@ -47,7 +47,7 @@ Run `brew create` with a URL to the source tarball: brew create https://example.com/foo-0.1.tar.gz ``` -This creates `/usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/Formula/foo.rb` and opens it in your `EDITOR`. It'll look something like: +This creates `$(brew --repository)/Library/Taps/homebrew/homebrew-core/Formula/foo.rb` and opens it in your `EDITOR`. If run without any options to customize the output for specific build systems (check `brew create --help` to see which are available) it'll look something like: ```ruby class Foo < Formula @@ -61,11 +61,8 @@ class Foo < Formula def install # ENV.deparallelize - system "./configure", "--disable-debug", - "--disable-dependency-tracking", - "--disable-silent-rules", - "--prefix=#{prefix}" - # system "cmake", ".", *std_cmake_args + system "./configure", *std_configure_args, "--disable-silent-rules" + # system "cmake", "-S", ".", "-B", "build", *std_cmake_args system "make", "install" end @@ -77,8 +74,7 @@ end If `brew` said `Warning: Version cannot be determined from URL` when doing the `create` step, you’ll need to explicitly add the correct [`version`](https://rubydoc.brew.sh/Formula#version-class_method) to the formula and then save the formula. -Homebrew will try to guess the formula’s name from its URL. If it fails to do -so you can override this with `brew create --set-name `. +Homebrew will try to guess the formula’s name from its URL. If it fails to do so you can override this with `brew create --set-name `. ### Fill in the `homepage` @@ -86,7 +82,7 @@ so you can override this with `brew create --set-name `. An SSL/TLS (https) [`homepage`](https://rubydoc.brew.sh/Formula#homepage%3D-class_method) is preferred, if one is available. -Try to summarise from the [`homepage`](https://rubydoc.brew.sh/Formula#homepage%3D-class_method) what the formula does in the [`desc`](https://rubydoc.brew.sh/Formula#desc%3D-class_method)ription. Note that the [`desc`](https://rubydoc.brew.sh/Formula#desc%3D-class_method)ription is automatically prepended with the formula name. +Try to summarise from the [`homepage`](https://rubydoc.brew.sh/Formula#homepage%3D-class_method) what the formula does in the [`desc`](https://rubydoc.brew.sh/Formula#desc%3D-class_method)ription. Note that the [`desc`](https://rubydoc.brew.sh/Formula#desc%3D-class_method)ription is automatically prepended with the formula name when printed. ### Fill in the `license` @@ -128,15 +124,9 @@ We generally try not to duplicate system libraries and complicated tools in core Special exceptions are OpenSSL and LibreSSL. Things that use either *should* be built using Homebrew’s shipped equivalent and our Brew Test Bot's post-install `audit` will warn if it detects you haven't done this. -Homebrew’s OpenSSL is [`keg_only`](https://rubydoc.brew.sh/Formula#keg_only-class_method) -to avoid conflicting with the system so sometimes formulae need to -have environment variables set or special configuration flags passed -to locate our OpenSSL. You can see this mechanism in the -[`clamav`](https://github.com/Homebrew/homebrew-core/blob/89c4574ef1a6d15e92196637ff315a0a4bb3e289/Formula/clamav.rb#L37) -formula. Usually this is unnecessary because Homebrew sets up our [build environment](https://github.com/Homebrew/brew/blob/HEAD/Library/Homebrew/extend/ENV/super.rb) -to favour finding [`keg_only`](https://rubydoc.brew.sh/Formula#keg_only-class_method) formulae first. +Homebrew’s OpenSSL is [`keg_only`](https://rubydoc.brew.sh/Formula#keg_only-class_method) to avoid conflicting with the system so sometimes formulae need to have environment variables set or special configuration flags passed to locate our OpenSSL. You can see this mechanism in the [`bind`](https://github.com/Homebrew/homebrew-core/blob/024535144dfdbc107bcc76056361f9515289fe3e/Formula/bind.rb#L48) formula. Usually this is unnecessary because Homebrew sets up our [build environment](https://github.com/Homebrew/brew/blob/HEAD/Library/Homebrew/extend/ENV/super.rb) to favour finding [`keg_only`](https://rubydoc.brew.sh/Formula#keg_only-class_method) formulae first. -**Important:** `$(brew --prefix)/bin` is NOT on the `PATH` during formula installation. If you have dependencies at build time, you must specify them and `brew` will add them to the `PATH` or create a [`Requirement`](https://rubydoc.brew.sh/Requirement). +**Important:** `$(brew --prefix)/bin` is NOT in the `PATH` during formula installation. If you have dependencies at build time, you must specify them and `brew` will add them to the `PATH` or create a [`Requirement`](https://rubydoc.brew.sh/Requirement). ### Specifying other formulae as dependencies @@ -144,45 +134,40 @@ to favour finding [`keg_only`](https://rubydoc.brew.sh/Formula#keg_only-class_me class Foo < Formula depends_on "pkg-config" depends_on "jpeg" - depends_on "readline" => :recommended depends_on "gtk+" => :optional + depends_on "readline" => :recommended depends_on "httpd" => [:build, :test] - depends_on :xcode => "9.3" + depends_on arch: :x86_64 + depends_on macos: :high_sierra + depends_on xcode: ["9.3", :build] end ``` -A String (e.g. `"jpeg"`) specifies a formula dependency. +A `String` (e.g. `"jpeg"`) specifies a formula dependency. -A Symbol (e.g. `:xcode`) specifies a [`Requirement`](https://rubydoc.brew.sh/Requirement) which can be fulfilled by one or more formulae, casks or other system-wide installed software (e.g. Xcode). +A `Symbol` (e.g. `:xcode`) specifies a [`Requirement`](https://rubydoc.brew.sh/Requirement) to restrict installation to systems meeting certain criteria, which can be fulfilled by one or more formulae, casks or other system-wide installed software (e.g. Xcode). Some [`Requirement`](https://rubydoc.brew.sh/Requirement)s can also take a string or symbol specifying their minimum version that the formula depends on. -A Hash (e.g. `=>`) adds information to a dependency. Given a String or Symbol, the value can be one or more of the following values: +A `Hash` (e.g. `=>`) adds information to a dependency. Given a string or symbol, the value can be one or more of the following values: -* `:build` means that dependency is a build-time only dependency so it can -be skipped when installing from a bottle or when listing missing -dependencies using `brew missing`. -* `:test` means that dependency is only required when running `brew test`. -* `:optional` generates an implicit `with-foo` option for the formula. -This means that, given `depends_on "foo" => :optional`, the user must pass `--with-foo` in order to use the dependency. -* `:recommended` generates an implicit `without-foo` option, meaning that -the dependency is enabled by default and the user must pass -`--without-foo` to disable this dependency. The default -description can be overridden using the normal option syntax (in this case, the option declaration must precede the dependency): - ```ruby - option "with-foo", "Compile with foo bindings" # This overrides the generated description if you want to - depends_on "foo" => :optional # Generated description would otherwise be "Build with foo support" - ``` -* Some [`Requirement`](https://rubydoc.brew.sh/Requirement)s can also take a string specifying their minimum version that the formula depends on. +* `:build` means this is a build-time only dependency so it can be skipped when installing from a bottle or when listing missing dependencies using `brew missing`. +* `:test` means this is only required when running `brew test`. +* `:optional` generates an implicit `with-foo` option for the formula. This means that, given `depends_on "foo" => :optional`, the user must pass `--with-foo` to use the dependency. +* `:recommended` generates an implicit `without-foo` option, meaning that the dependency is enabled by default and the user must pass `--without-foo` to disable this dependency. The default description can be overridden using the [`option`](https://rubydoc.brew.sh/Formula#option-class_method) syntax (in this case, the [`option` declaration](#adding-optional-steps) must precede the dependency): + + ```ruby + option "with-foo", "Compile with foo bindings" # This overrides the generated description if you want to + depends_on "foo" => :optional # Generated description would otherwise be "Build with foo support" + ``` **Note:** `:optional` and `:recommended` are not allowed in Homebrew/homebrew-core as they are not tested by CI. ### Specifying conflicts with other formulae -Sometimes there’s hard conflict between formulae, and it can’t be avoided or circumvented with [`keg_only`](https://rubydoc.brew.sh/Formula#keg_only-class_method). +Sometimes there’s a hard conflict between formulae that can’t be avoided or circumvented with [`keg_only`](https://rubydoc.brew.sh/Formula#keg_only-class_method). -A good example formula for minor conflict is [`mbedtls`](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/mbedtls.rb), which ships and compiles a "Hello World" executable. This is obviously non-essential to `mbedtls`’s functionality, and conflict with the popular GNU [`hello`](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/hello.rb) formula would be overkill, so we just [remove it](https://github.com/Homebrew/homebrew-core/blob/966273060ad507fea490bd931971963de8b1a1dc/Formula/mbedtls.rb#L30-L31) during the installation process. +A good example for minor conflict is the [`mbedtls`](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/mbedtls.rb) formula, which ships and compiles a "Hello World" executable. This is obviously non-essential to `mbedtls`’s functionality, and as conflict with the popular GNU [`hello`](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/hello.rb) formula would be overkill, we just [remove it](https://github.com/Homebrew/homebrew-core/blob/4009b5999e5ce2136fd86c8714b502d905cc2832/Formula/mbedtls.rb#L50-L51) during the installation process. -[`pdftohtml`](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/pdftohtml.rb) provides an example of a serious -conflict, where both formula ship an identically-named binary that is essential to functionality, so a [`conflicts_with`](https://rubydoc.brew.sh/Formula#conflicts_with-class_method) is preferable. +[`pdftohtml`](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/pdftohtml.rb) provides an example of a serious conflict, where each listed formula ships an identically named binary that is essential to functionality, so a [`conflicts_with`](https://rubydoc.brew.sh/Formula#conflicts_with-class_method) is preferable. As a general rule, [`conflicts_with`](https://rubydoc.brew.sh/Formula#conflicts_with-class_method) should be a last-resort option. It’s a fairly blunt instrument. @@ -198,7 +183,7 @@ In Homebrew we sometimes accept formulae updates that don’t include a version Occasionally, these updates require a forced-recompile of the formula itself or its dependents to either ensure formulae continue to function as expected or to close a security issue. This forced-recompile is known as a [`revision`](https://rubydoc.brew.sh/Formula#revision%3D-class_method) and is inserted underneath the [`homepage`](https://rubydoc.brew.sh/Formula#homepage%3D-class_method)/[`url`](https://rubydoc.brew.sh/Formula#url-class_method)/[`sha256`](https://rubydoc.brew.sh/Formula#sha256%3D-class_method) block. -When a dependent of a formula fails against a new version of that dependency it must receive a [`revision`](https://rubydoc.brew.sh/Formula#revision%3D-class_method). An example of such failure can be seen [here](https://github.com/Homebrew/legacy-homebrew/issues/31195) and the fix [here](https://github.com/Homebrew/legacy-homebrew/pull/31207). +When a dependent of a formula fails to build against a new version of that dependency it must receive a [`revision`](https://rubydoc.brew.sh/Formula#revision%3D-class_method). An example of such failure is in [this issue report](https://github.com/Homebrew/legacy-homebrew/issues/31195) and [its fix](https://github.com/Homebrew/legacy-homebrew/pull/31207). [`revision`](https://rubydoc.brew.sh/Formula#revision%3D-class_method)s are also used for formulae that move from the system OpenSSL to the Homebrew-shipped OpenSSL without any other changes to that formula. This ensures users aren’t left exposed to the potential security issues of the outdated OpenSSL. An example of this can be seen in [this commit](https://github.com/Homebrew/homebrew-core/commit/0d4453a91923e6118983961e18d0609e9828a1a4). @@ -206,7 +191,7 @@ When a dependent of a formula fails against a new version of that dependency it Sometimes formulae have version schemes that change such that a direct comparison between two versions no longer produces the correct result. For example, a project might be version `13` and then decide to become `1.0.0`. As `13` is translated to `13.0.0` by our versioning system by default this requires intervention. -When a version scheme of a formula fails to recognise a new version as newer it must receive a [`version_scheme`](https://rubydoc.brew.sh/Formula#version_scheme%3D-class_method). An example of this can be seen [here](https://github.com/Homebrew/homebrew-core/pull/4006). +When a version scheme of a formula fails to recognise a new version as newer it must receive a [`version_scheme`](https://rubydoc.brew.sh/Formula#version_scheme%3D-class_method). An example of this can be seen in [this pull request](https://github.com/Homebrew/homebrew-core/pull/4006). ### Double-check for dependencies @@ -227,6 +212,28 @@ $ otool -L /usr/local/bin/ldapvi /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1213.0.0) ``` +### Specifying macOS components as dependencies + +If a formula dependency is required on all platforms but can be handled by a component that ships with macOS, specify it with [`uses_from_macos`](https://rubydoc.brew.sh/Formula#uses_from_macos-class_method). On Linux it acts like [`depends_on`](https://rubydoc.brew.sh/Formula#depends_on-class_method), while on macOS it's ignored unless the host system is older than the optional `since:` parameter. + +For example, to require the `bzip2` formula on Linux while relying on built-in `bzip2` on macOS: + +```ruby +uses_from_macos "bzip2" +``` + +To require the `perl` formula only when building or testing on Linux: + +```ruby +uses_from_macos "perl" => [:build, :test] +``` + +To require the `curl` formula on Linux and pre-macOS 12: + +```ruby +uses_from_macos "curl", since: :monterey +``` + ### Specifying gems, Python modules, Go projects, etc. as dependencies Homebrew doesn’t package already-packaged language-specific libraries. These should be installed directly from `gem`/`cpan`/`pip` etc. @@ -262,17 +269,15 @@ Check the top of the e.g. `./configure` output. Some configure scripts do not re ### Add a test to the formula -Add a valid test to the [`test do`](https://rubydoc.brew.sh/Formula#test-class_method) block of the formula. This will be run by `brew test foo` and the [Brew Test Bot](Brew-Test-Bot.md). +Add a valid test to the [`test do`](https://rubydoc.brew.sh/Formula#test-class_method) block of the formula. This will be run by `brew test foo` and [Brew Test Bot](Brew-Test-Bot.md). -The [`test do`](https://rubydoc.brew.sh/Formula#test-class_method) block automatically creates and changes to a temporary directory which -is deleted after run. You can access this [`Pathname`](https://rubydoc.brew.sh/Pathname) with the [`testpath`](https://rubydoc.brew.sh/Formula#testpath-instance_method) -function. The environment variable `HOME` is set to [`testpath`](https://rubydoc.brew.sh/Formula#testpath-instance_method) within the [`test do`](https://rubydoc.brew.sh/Formula#test-class_method) block. +The [`test do`](https://rubydoc.brew.sh/Formula#test-class_method) block automatically creates and changes to a temporary directory which is deleted after run. You can access this [`Pathname`](https://rubydoc.brew.sh/Pathname) with the [`testpath`](https://rubydoc.brew.sh/Formula#testpath-instance_method) function. The environment variable `HOME` is set to [`testpath`](https://rubydoc.brew.sh/Formula#testpath-instance_method) within the [`test do`](https://rubydoc.brew.sh/Formula#test-class_method) block. We want tests that don't require any user input and test the basic functionality of the application. For example `foo build-foo input.foo` is a good test and (despite their widespread use) `foo --version` and `foo --help` are bad tests. However, a bad test is better than no test at all. -See [`cmake`](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/cmake.rb) for an example of a formula with a good test. The formula writes a basic `CMakeLists.txt` file into the test directory then calls CMake to generate Makefiles. This test checks that CMake doesn't e.g. segfault during basic operation. +See the [`cmake`](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/cmake.rb) formula for an example of a good test. It writes a basic `CMakeLists.txt` file into the test directory then calls CMake to generate Makefiles. This test checks that CMake doesn't e.g. segfault during basic operation. -You can check that the output is as expected with `assert_equal` or `assert_match` on the output of the [Formula assertions](https://rubydoc.brew.sh/Homebrew/Assertions.html) such as in this example from the [envv formula](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/envv.rb): +You can check that the output is as expected with `assert_equal` or `assert_match` on the output of the [Formula assertions](https://rubydoc.brew.sh/Homebrew/Assertions) such as in this example from the [`envv`](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/envv.rb) formula: ```ruby assert_equal "mylist=A:C; export mylist", shell_output("#{bin}/envv del mylist B").strip @@ -285,12 +290,12 @@ assert_predicate testpath/"output.txt", :exist? ``` Some advice for specific cases: -* If the formula is a library, compile and run some simple code that links against it. It could be taken from upstream's documentation / source examples. -A good example is [`tinyxml2`](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/tinyxml2.rb), which writes a small C++ source file into the test directory, compiles and links it against the tinyxml2 library and finally checks that the resulting program runs successfully. + +* If the formula is a library, compile and run some simple code that links against it. It could be taken from upstream's documentation / source examples. A good example is [`tinyxml2`](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/tinyxml2.rb)'s test, which writes a small C++ source file into the test directory, compiles and links it against the tinyxml2 library and finally checks that the resulting program runs successfully. * If the formula is for a GUI program, try to find some function that runs as command-line only, like a format conversion, reading or displaying a config file, etc. * If the software cannot function without credentials or requires a virtual machine, docker instance, etc. to run, a test could be to try to connect with invalid credentials (or without credentials) and confirm that it fails as expected. This is preferred over mocking a dependency. -* Homebrew comes with a number of [standard test fixtures](https://github.com/Homebrew/brew/tree/master/Library/Homebrew/test/support/fixtures), including numerous sample images, sounds, and documents in various formats. You can get the file path to a test fixture with `test_fixtures("test.svg")`. -* If your test requires a test file that isn't a standard test fixture, you can install it from a source repository during the `test` phase with a resource block, like this: +* Homebrew comes with a number of [standard test fixtures](https://github.com/Homebrew/brew/tree/master/Library/Homebrew/test/support/fixtures), including numerous sample images, sounds, and documents in various formats. You can get the file path to a test fixture with e.g. `test_fixtures("test.svg")`. +* If your test requires a test file that isn't a standard test fixture, you can install it from a source repository during the `test` phase with a [`resource`](https://rubydoc.brew.sh/Formula#resource-class_method) block, like this: ```ruby resource("testdata") do @@ -313,15 +318,13 @@ Some software installs to `man` instead of `share/man`, so check the output and ### Caveats -In case there are specific issues with the Homebrew packaging (compared to how the software is installed from other sources) a `caveats` block can be added to the formula to warn users. This can indicate non-standard install paths, an example from the `ruby` formula: +In case there are specific issues with the Homebrew packaging (compared to how the software is installed from other sources) a `caveats` block can be added to the formula to warn users. This can indicate non-standard install paths, like this example from the [`ruby`](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/ruby.rb) formula: -``` -==> Caveats -By default, binaries installed by gem will be placed into: - /usr/local/lib/ruby/gems/bin + ==> Caveats + By default, binaries installed by gem will be placed into: + /usr/local/lib/ruby/gems/bin -You may want to add this to your PATH. -``` + You may want to add this to your PATH. ### A quick word on naming @@ -348,12 +351,11 @@ Add aliases by creating symlinks in an `Aliases` directory in the tap root. ### Audit the formula -You can run `brew audit --strict --online` to test formulae for adherence to Homebrew house style. The `audit` command includes warnings for trailing whitespace, preferred URLs for certain source hosts, and a lot of other style issues. Fixing these warnings before committing will make the process a lot quicker for everyone. +You can run `brew audit --strict --online` to test formulae for adherence to Homebrew house style, which is loosely based on the [Ruby Style Guide](https://github.com/rubocop-hq/ruby-style-guide#the-ruby-style-guide). The `audit` command includes warnings for trailing whitespace, preferred URLs for certain source hosts, and many other style issues. Fixing these warnings before committing will make the process a lot quicker for everyone. -New formulae being submitted to Homebrew should run `brew audit --new-formula foo`. This command is performed by the Brew Test Bot on new submissions as part of the automated build and test process, and highlights more potential issues than the standard audit. +New formulae being submitted to Homebrew should run `brew audit --new-formula foo`. This command is performed by Brew Test Bot on new submissions as part of the automated build and test process, and highlights more potential issues than the standard audit. -Use `brew info` and check if the version guessed by Homebrew from the URL is -correct. Add an explicit [`version`](https://rubydoc.brew.sh/Formula#version-class_method) if not. +Use `brew info` and check if the version guessed by Homebrew from the URL is correct. Add an explicit [`version`](https://rubydoc.brew.sh/Formula#version-class_method) if not. ### Commit @@ -376,7 +378,8 @@ The established standard for Git commit messages is: * explain the commit thoroughly. At Homebrew, we like to put the name of the formula up front like so: `foobar 7.3 (new formula)`. -This may seem crazy short, but you’ll find that forcing yourself to summarise the commit encourages you to be atomic and concise. If you can’t summarise it in 50-80 characters, you’re probably trying to commit two commits as one. For a more thorough explanation, please read Tim Pope’s excellent blog post, [A Note About Git Commit Messages](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). + +This may seem crazy short, but you’ll find that forcing yourself to summarise the commit encourages you to be atomic and concise. If you can’t summarise it in 50 to 80 characters, you’re probably trying to commit two commits as one. For a more thorough explanation, please read Tim Pope’s excellent blog post, [A Note About Git Commit Messages](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). The preferred commit message format for simple version updates is `foobar 7.3` and for fixes is `foobar: fix flibble matrix.`. @@ -386,12 +389,12 @@ Ensure you reference any relevant GitHub issue, e.g. `Closes #12345` in the comm Now you just need to push your commit to GitHub. -If you haven’t forked Homebrew yet, [go to the `homebrew-core` repository and hit the Fork button](https://github.com/Homebrew/homebrew-core). +If you haven’t forked Homebrew yet, [go to the `homebrew/core` repository and hit the Fork button](https://github.com/Homebrew/homebrew-core). If you have already forked Homebrew on GitHub, then you can manually push (just make sure you have been pulling from the `Homebrew/homebrew-core` master): ```sh -git push https://github.com/myname/homebrew-core/ +git push https://github.com/myname/homebrew-core/ ``` Now, [open a pull request](https://docs.brew.sh/How-To-Open-a-Homebrew-Pull-Request) for your changes. @@ -450,7 +453,7 @@ Make sure you modify `s`! This block ignores the returned value. [`inreplace`](https://rubydoc.brew.sh/Utils/Inreplace) should be used instead of patches when patching something that will never be accepted upstream, e.g. making the software’s build system respect Homebrew’s installation hierarchy. If it's something that affects both Homebrew and MacPorts (i.e. macOS specific) it should be turned into an upstream submitted patch instead. -If you need modify variables in a `Makefile`, rather than using [`inreplace`](https://rubydoc.brew.sh/Utils/Inreplace), pass them as arguments to `make`: +If you need to modify variables in a `Makefile`, rather than using [`inreplace`](https://rubydoc.brew.sh/Utils/Inreplace), pass them as arguments to `make`: ```ruby system "make", "target", "VAR2=value1", "VAR2=value2", "VAR3=values can have spaces" @@ -466,7 +469,7 @@ Note that values *can* contain unescaped spaces if you use the multiple-argument While [`patch`](https://rubydoc.brew.sh/Formula#patch-class_method)es should generally be avoided, sometimes they are temporarily necessary. -When [`patch`](https://rubydoc.brew.sh/Formula#patch-class_method)ing (i.e. fixing header file inclusion, fixing compiler warnings, etc.) the first thing to do is check whether or not the upstream project is aware of the issue. If not, file a bug report and/or submit your patch for inclusion. We may sometimes still accept your patch before it was submitted upstream but by getting the ball rolling on fixing the upstream issue you reduce the length of time we have to carry the patch around. +When [`patch`](https://rubydoc.brew.sh/Formula#patch-class_method)ing (i.e. fixing header file inclusion, fixing compiler warnings, etc.) the first thing to do is check whether the upstream project is aware of the issue. If not, file a bug report and/or submit your patch for inclusion. We may sometimes still accept your patch before it was submitted upstream but by getting the ball rolling on fixing the upstream issue you reduce the length of time we have to carry the patch around. *Always justify a [`patch`](https://rubydoc.brew.sh/Formula#patch-class_method) with a code comment!* Otherwise, nobody will know when it is safe to remove the patch, or safe to leave it in when updating the formula. The comment should include a link to the relevant upstream issue(s). @@ -510,15 +513,13 @@ patch :p0, :DATA with the patch data included at the end of the file: -``` -__END__ -diff --git a/foo/showfigfonts b/foo/showfigfonts -index 643c60b..543379c 100644 ---- a/foo/showfigfonts -+++ b/foo/showfigfonts -@@ -14,6 +14,7 @@ -… -``` + __END__ + diff --git a/foo/showfigfonts b/foo/showfigfonts + index 643c60b..543379c 100644 + --- a/foo/showfigfonts + +++ b/foo/showfigfonts + @@ -14,6 +14,7 @@ + … Patches can also be embedded by passing a string. This makes it possible to provide multiple embedded patches while making only some of them conditional. @@ -538,15 +539,16 @@ brew edit foo ``` Now just paste into the formula after `__END__`. -Instead of `git diff | pbcopy`, for some editors `git diff >> path/to/your/formula/foo.rb` might help you ensure that the patch is not touched, e.g. white space removal, indentation changes, etc. + +Instead of `git diff | pbcopy`, for some editors `git diff >> path/to/your/formula/foo.rb` might help you ensure that the patch is not altered, e.g. whitespace removal, indentation changes, etc. ## Advanced formula tricks -If anything isn’t clear, you can usually figure it out by `grep`ping the `$(brew --repository homebrew/core)` directory. Please submit a pull request to amend this document if you think it will help! +If anything isn’t clear, you can usually figure it out by `grep`ping the `$(brew --repository homebrew/core)` directory for examples. Please submit a pull request to amend this document if you think it will help! ### Handling different system configurations -Often, formulae need different dependencies, resources, patches, conflicts, deprecations or `keg_only` statuses on different OSes and arches. In these cases, the components can be nested inside `on_macos`, `on_linux`, `on_arm` or `on_intel` blocks. For example, here's how to add `gcc` as a Linux-only dependency: +Often, formulae need different dependencies, resources, patches, conflicts, deprecations or `keg_only` statuses on different OSes and architectures. In these cases, the components can be nested inside `on_macos`, `on_linux`, `on_arm` or `on_intel` blocks. For example, here's how to add `gcc` as a Linux-only dependency: ```ruby on_linux do @@ -588,7 +590,7 @@ Inside `def install` and `test do`, don't use these `on_*` methods. Instead, use * `Hardware::CPU.intel?` and `Hardware::CPU.arm?` return `true` or `false` based on the arch * `MacOS.version` returns the current macOS version. Use `==`, `<=` or `>=` to compare to symbols corresponding to macOS versions (e.g. `if MacOS.version >= :mojave`) -See [`rust`](https://github.com/Homebrew/homebrew-core/blob/fe831237a7c24033a48f588a1578ba54f953f922/Formula/rust.rb#L72) for an example. +See the [`rust`](https://github.com/Homebrew/homebrew-core/blob/cd860158d268e95c4202f13195c147b54a460f31/Formula/rust.rb#L73) formula for an example. ### `livecheck` blocks @@ -601,15 +603,11 @@ livecheck do end ``` -For `url`/`regex` guidelines and additional `livecheck` block examples, refer to the [`brew livecheck` documentation](Brew-Livecheck.md). For more technical information on the methods used in a `livecheck` block, please refer to the [`Livecheck` class documentation](https://rubydoc.brew.sh/Livecheck.html). +For `url`/`regex` guidelines and additional `livecheck` block examples, refer to the [`brew livecheck` documentation](Brew-Livecheck.md). For more technical information on the methods used in a `livecheck` block, please refer to the [`Livecheck` class documentation](https://rubydoc.brew.sh/Livecheck). ### Unstable versions (`head`) -Formulae can specify an alternate download for the upstream project’s [`head`](https://rubydoc.brew.sh/Formula#head-class_method) (`master`/`trunk`). - -#### `head` - -[`head`](https://rubydoc.brew.sh/Formula#head-class_method) URLs (activated by passing `--HEAD`) build the development cutting edge. Specifying it is easy: +Formulae can specify an alternate download for the upstream project’s development cutting-edge source (e.g. `master`/`main`/`trunk`) using [`head`](https://rubydoc.brew.sh/Formula#head-class_method), which can be activated by passing `--HEAD` when installing. Homebrew auto-detects most Git, SVN and Mercurial URLs. Specifying it is easy: ```ruby class Foo < Formula @@ -617,59 +615,49 @@ class Foo < Formula end ``` -Homebrew understands `git`, `svn`, and `hg` URLs, and has a way to specify `cvs` repositories as a URL as well. You can test whether the [`head`](https://rubydoc.brew.sh/Formula#head-class_method) is being built with `build.head?`. +You can also bundle the URL and any `head`-specific dependencies and resources in a `head do` block. To use a specific commit, tag, or branch from a repository, specify [`head`](https://rubydoc.brew.sh/Formula#head-class_method) with the `:tag` and `:revision`, `:revision`, or `:branch` option, like so: ```ruby class Foo < Formula - head "https://github.com/some/package.git", revision: "090930930295adslfknsdfsdaffnasd13" - # or branch: "main" (the default is "master") + head do + url "https://github.com/some/package.git", branch: "main" # the default is "master" # or tag: "1_0_release", revision: "090930930295adslfknsdfsdaffnasd13" + # or revision: "090930930295adslfknsdfsdaffnasd13" + depends_on "pkg-config" => :build + end end ``` -### Compiler selection - -Sometimes a package fails to build when using a certain compiler. Since recent [Xcode versions](Xcode.md) no longer include a GCC compiler we cannot simply force the use of GCC. Instead, the correct way to declare this is the [`fails_with`](https://rubydoc.brew.sh/Formula#fails_with-class_method) DSL method. A properly constructed [`fails_with`](https://rubydoc.brew.sh/Formula#fails_with-class_method) block documents the latest compiler build version known to cause compilation to fail, and the cause of the failure. For example: - -```ruby -fails_with :clang do - build 211 - cause "Miscompilation resulting in segfault on queries" -end -``` - -`build` takes a Fixnum (an integer; you can find this number in your `brew --config` output). `cause` takes a String, and the use of heredocs is encouraged to improve readability and allow for more comprehensive documentation. - -[`fails_with`](https://rubydoc.brew.sh/Formula#fails_with-class_method) declarations can be used with any of `:gcc`, `:llvm`, and `:clang`. Homebrew will use this information to select a working compiler (if one is available). +You can test whether the [`head`](https://rubydoc.brew.sh/Formula#head-class_method) is being built with `build.head?` in the `install` method. ### Specifying the download strategy explicitly -To use one of Homebrew’s built-in download strategies, specify the `:using =>` flag on a [`url`](https://rubydoc.brew.sh/Formula#url-class_method) or [`head`](https://rubydoc.brew.sh/Formula#head-class_method). For example: +To use one of Homebrew’s built-in download strategies, specify the `using:` flag on a [`url`](https://rubydoc.brew.sh/Formula#url-class_method) or [`head`](https://rubydoc.brew.sh/Formula#head-class_method). For example: ```ruby -class Python3 < Formula - homepage "https://www.python.org/" - url "https://www.python.org/ftp/python/3.4.3/Python-3.4.3.tar.xz" - sha256 "b5b3963533768d5fc325a4d7a6bd6f666726002d696f1d399ec06b043ea996b8" - head "https://hg.python.org/cpython", :using => :hg +class Nginx < Formula + homepage "https://nginx.org/" + url "https://nginx.org/download/nginx-1.23.2.tar.gz" + sha256 "a80cc272d3d72aaee70aa8b517b4862a635c0256790434dbfc4d618a999b0b46" + head "https://hg.nginx.org/nginx/", using: :hg ``` Homebrew offers anonymous download strategies. -| `:using` value | download strategy | -|----------------|-------------------------------| -| `:bzr` | `BazaarDownloadStrategy` | -| `:curl` | `CurlDownloadStrategy` | -| `:cvs` | `CVSDownloadStrategy` | -| `:fossil` | `FossilDownloadStrategy` | -| `:git` | `GitDownloadStrategy` | -| `:hg` | `MercurialDownloadStrategy` | -| `:nounzip` | `NoUnzipCurlDownloadStrategy` | -| `:post` | `CurlPostDownloadStrategy` | -| `:svn` | `SubversionDownloadStrategy` | -|----------------|-------------------------------| +| `:using` value | download strategy | +| ---------------- | ----------------------------- | +| `:bzr` | `BazaarDownloadStrategy` +| `:curl` | `CurlDownloadStrategy` +| `:cvs` | `CVSDownloadStrategy` +| `:fossil` | `FossilDownloadStrategy` +| `:git` | `GitDownloadStrategy` +| `:hg` | `MercurialDownloadStrategy` +| `:homebrew_curl` | `HomebrewCurlDownloadStrategy` +| `:nounzip` | `NoUnzipCurlDownloadStrategy` +| `:post` | `CurlPostDownloadStrategy` +| `:svn` | `SubversionDownloadStrategy` If you need more control over the way files are downloaded and staged, you can create a custom download strategy and specify it using the [`url`](https://rubydoc.brew.sh/Formula#url-class_method) method's `:using` option: @@ -687,11 +675,37 @@ class Foo < Formula end ``` +### Compiler selection + +Sometimes a package fails to build when using a certain compiler. Since recent [Xcode versions](Xcode.md) no longer include a GCC compiler we cannot simply force the use of GCC. Instead, the correct way to declare this is with the [`fails_with`](https://rubydoc.brew.sh/Formula#fails_with-class_method) DSL method. A properly constructed [`fails_with`](https://rubydoc.brew.sh/Formula#fails_with-class_method) block documents the latest compiler build version known to cause compilation to fail, and the cause of the failure. For example: + +```ruby +fails_with :clang do + build 211 + cause "Miscompilation resulting in segfault on queries" +end + +fails_with :gcc do + version "5" # fails with GCC 5.x and earlier + cause "Requires C++17 support" +end + +fails_with gcc: "7" do + version "7.1" # fails with GCC 7.0 and 7.1 but not 7.2, or any other major GCC version + cause <<-EOS + warning: dereferencing type-punned pointer will break strict-aliasing rules + Fixed in GCC 7.2, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=42136 + EOS +end +``` + +For `:clang`, `build` takes an integer (you can find this number in your `brew --config` output), while `:gcc` uses either just `version` which takes a string to indicate the last problematic GCC version, or a major version argument combined with `version` to single out a range of specific GCC releases. `cause` takes a string, and the use of heredocs is encouraged to improve readability and allow for more comprehensive documentation. + +[`fails_with`](https://rubydoc.brew.sh/Formula#fails_with-class_method) declarations can be used with any of `:gcc`, `:llvm`, and `:clang`. Homebrew will use this information to select a working compiler (if one is available). + ### Just moving some files -When your code in the install function is run, the current working directory is set to the extracted tarball. - -So it is easy to just move some files: +When your code in the install function is run, the current working directory is set to the extracted tarball. This makes it easy to just move some files: ```ruby prefix.install "file1", "file2" @@ -703,46 +717,52 @@ Or everything: prefix.install Dir["output/*"] ``` -Generally we'd rather you were specific about what files or directories need to be installed rather than installing everything. +Or just the tarball's top-level files like README, LICENSE etc.: + +```ruby +prefix.install_metafiles +``` + +Generally we'd rather you were specific about which files or directories need to be installed rather than installing everything. #### Variables for directory locations -| Name | Default | Example | -|-----------------------|------------------------------------------------|-------------------------------------------------------------| -| **`HOMEBREW_PREFIX`** | `/usr/local` | | -| **`prefix`** | `#{HOMEBREW_PREFIX}/Cellar/#{name}/#{version}` | `/usr/local/Cellar/foo/0.1` | -| **`opt_prefix`** | `#{HOMEBREW_PREFIX}/opt/#{name}` | `/usr/local/opt/foo` | -| **`bin`** | `#{prefix}/bin` | `/usr/local/Cellar/foo/0.1/bin` | -| **`doc`** | `#{prefix}/share/doc/#{name}` | `/usr/local/Cellar/foo/0.1/share/doc/foo` | -| **`include`** | `#{prefix}/include` | `/usr/local/Cellar/foo/0.1/include` | -| **`info`** | `#{prefix}/share/info` | `/usr/local/Cellar/foo/0.1/share/info` | -| **`lib`** | `#{prefix}/lib` | `/usr/local/Cellar/foo/0.1/lib` | -| **`libexec`** | `#{prefix}/libexec` | `/usr/local/Cellar/foo/0.1/libexec` | -| **`man`** | `#{prefix}/share/man` | `/usr/local/Cellar/foo/0.1/share/man` | -| **`man[1-8]`** | `#{prefix}/share/man/man[1-8]` | `/usr/local/Cellar/foo/0.1/share/man/man[1-8]` | -| **`sbin`** | `#{prefix}/sbin` | `/usr/local/Cellar/foo/0.1/sbin` | -| **`share`** | `#{prefix}/share` | `/usr/local/Cellar/foo/0.1/share` | -| **`pkgshare`** | `#{prefix}/share/#{name}` | `/usr/local/Cellar/foo/0.1/share/foo` | -| **`elisp`** | `#{prefix}/share/emacs/site-lisp/#{name}` | `/usr/local/Cellar/foo/0.1/share/emacs/site-lisp/foo` | -| **`frameworks`** | `#{prefix}/Frameworks` | `/usr/local/Cellar/foo/0.1/Frameworks` | -| **`kext_prefix`** | `#{prefix}/Library/Extensions` | `/usr/local/Cellar/foo/0.1/Library/Extensions` | -| **`zsh_function`** | `#{prefix}/share/zsh/site-functions` | `/usr/local/Cellar/foo/0.1/share/zsh/site-functions` | -| **`fish_function`** | `#{prefix}/share/fish/vendor_functions` | `/usr/local/Cellar/foo/0.1/share/fish/vendor_functions` | -| **`bash_completion`** | `#{prefix}/etc/bash_completion.d` | `/usr/local/Cellar/foo/0.1/etc/bash_completion.d` | -| **`zsh_completion`** | `#{prefix}/share/zsh/site-functions` | `/usr/local/Cellar/foo/0.1/share/zsh/site-functions` | -| **`fish_completion`** | `#{prefix}/share/fish/vendor_completions.d` | `/usr/local/Cellar/foo/0.1/share/fish/vendor_completions.d` | -| **`etc`** | `#{HOMEBREW_PREFIX}/etc` | `/usr/local/etc` | -| **`pkgetc`** | `#{HOMEBREW_PREFIX}/etc/#{name}` | `/usr/local/etc/foo` | -| **`var`** | `#{HOMEBREW_PREFIX}/var` | `/usr/local/var` | -| **`buildpath`** | A temporary directory somewhere on your system | `/private/tmp/[formula-name]-0q2b/[formula-name]` | +| name | default path | example | +| --------------------- | ---------------------------------------------- | ------- | +| **`HOMEBREW_PREFIX`** | output of `$(brew --prefix)` | `/usr/local` +| **`prefix`** | `#{HOMEBREW_PREFIX}/Cellar/#{name}/#{version}` | `/usr/local/Cellar/foo/0.1` +| **`opt_prefix`** | `#{HOMEBREW_PREFIX}/opt/#{name}` | `/usr/local/opt/foo` +| **`bin`** | `#{prefix}/bin` | `/usr/local/Cellar/foo/0.1/bin` +| **`doc`** | `#{prefix}/share/doc/#{name}` | `/usr/local/Cellar/foo/0.1/share/doc/foo` +| **`include`** | `#{prefix}/include` | `/usr/local/Cellar/foo/0.1/include` +| **`info`** | `#{prefix}/share/info` | `/usr/local/Cellar/foo/0.1/share/info` +| **`lib`** | `#{prefix}/lib` | `/usr/local/Cellar/foo/0.1/lib` +| **`libexec`** | `#{prefix}/libexec` | `/usr/local/Cellar/foo/0.1/libexec` +| **`man`** | `#{prefix}/share/man` | `/usr/local/Cellar/foo/0.1/share/man` +| **`man[1-8]`** | `#{prefix}/share/man/man[1-8]` | `/usr/local/Cellar/foo/0.1/share/man/man[1-8]` +| **`sbin`** | `#{prefix}/sbin` | `/usr/local/Cellar/foo/0.1/sbin` +| **`share`** | `#{prefix}/share` | `/usr/local/Cellar/foo/0.1/share` +| **`pkgshare`** | `#{prefix}/share/#{name}` | `/usr/local/Cellar/foo/0.1/share/foo` +| **`elisp`** | `#{prefix}/share/emacs/site-lisp/#{name}` | `/usr/local/Cellar/foo/0.1/share/emacs/site-lisp/foo` +| **`frameworks`** | `#{prefix}/Frameworks` | `/usr/local/Cellar/foo/0.1/Frameworks` +| **`kext_prefix`** | `#{prefix}/Library/Extensions` | `/usr/local/Cellar/foo/0.1/Library/Extensions` +| **`zsh_function`** | `#{prefix}/share/zsh/site-functions` | `/usr/local/Cellar/foo/0.1/share/zsh/site-functions` +| **`fish_function`** | `#{prefix}/share/fish/vendor_functions` | `/usr/local/Cellar/foo/0.1/share/fish/vendor_functions` +| **`bash_completion`** | `#{prefix}/etc/bash_completion.d` | `/usr/local/Cellar/foo/0.1/etc/bash_completion.d` +| **`zsh_completion`** | `#{prefix}/share/zsh/site-functions` | `/usr/local/Cellar/foo/0.1/share/zsh/site-functions` +| **`fish_completion`** | `#{prefix}/share/fish/vendor_completions.d` | `/usr/local/Cellar/foo/0.1/share/fish/vendor_completions.d` +| **`etc`** | `#{HOMEBREW_PREFIX}/etc` | `/usr/local/etc` +| **`pkgetc`** | `#{HOMEBREW_PREFIX}/etc/#{name}` | `/usr/local/etc/foo` +| **`var`** | `#{HOMEBREW_PREFIX}/var` | `/usr/local/var` +| **`buildpath`** | temporary directory somewhere on your system | `/private/tmp/[formula-name]-0q2b/[formula-name]` -These can be used, for instance, in code such as +These can be used, for instance, in code such as: ```ruby bin.install Dir["output/*"] ``` -to move binaries into their correct location into the Cellar, and +to move binaries into their correct location within the Cellar, and: ```ruby man.mkpath @@ -754,6 +774,56 @@ To install man pages into specific locations, use `man1.install "foo.1", "bar.1" Note that in the context of Homebrew, [`libexec`](https://rubydoc.brew.sh/Formula#libexec-instance_method) is reserved for private use by the formula and therefore is not symlinked into `HOMEBREW_PREFIX`. +### File-level operations + +You can use the file utilities provided by Ruby's [`FileUtils`](https://www.ruby-doc.org/stdlib/libdoc/fileutils/rdoc/index.html). These are included in the [`Formula`](https://rubydoc.brew.sh/Formula) class, so you do not need the `FileUtils.` prefix to use them. + +When creating symlinks, take special care to ensure they are *relative* symlinks. This makes it easier to create a relocatable bottle. For example, to create a symlink in `bin` to an executable in `libexec`, use: + +```ruby +bin.install_symlink libexec/"name" +``` + +instead of: + +```ruby +ln_s libexec/"name", bin +``` + +The symlinks created by [`install_symlink`](https://rubydoc.brew.sh/Pathname#install_symlink-instance_method) are guaranteed to be relative. `ln_s` will only produce a relative symlink when given a relative path. + +Several other utilities for Ruby's [`Pathname`](https://rubydoc.brew.sh/Pathname) can simplify some common operations. + +* To perform several operations within a directory, enclose them within a [`cd do`](https://rubydoc.brew.sh/Pathname#cd-instance_method) block: + + ```ruby + cd "src" do + system "./configure", "--disable-debug", "--prefix=#{prefix}" + system "make", "install" + end + ``` + +* To surface one or more binaries buried in `libexec` or a macOS `.app` package, use [`write_exec_script`](https://rubydoc.brew.sh/Pathname#write_exec_script-instance_method) or [`write_jar_script`](https://rubydoc.brew.sh/Pathname#write_jar_script-instance_method): + + ```ruby + bin.write_exec_script (libexec/"bin").children + bin.write_exec_script prefix/"Package.app/Contents/MacOS/package" + bin.write_jar_script libexec/jar_file, "jarfile", java_version: "11" + ``` + +* For binaries that require setting one or more environment variables to function properly, use [`write_env_script`](https://rubydoc.brew.sh/Pathname#write_env_script-instance_method) or [`env_script_all_files`](https://rubydoc.brew.sh/Pathname#env_script_all_files-instance_method): + + ```ruby + (bin/"package").write_env_script libexec/"package", PACKAGE_ROOT: libexec + bin.env_script_all_files(libexec/"bin", PERL5LIB: ENV["PERL5LIB"]) + ``` + +### Rewriting a script shebang + +Some formulae install executable scripts written in an interpreted language such as Python or Perl. Homebrew provides a `rewrite_shebang` method to rewrite the shebang of a script. This replaces a script's original interpreter path with the one the formula depends on. This guarantees that the correct interpreter is used at execution time. This isn't required if the build system already handles it (e.g. often with `pip` or Perl `ExtUtils::MakeMaker`). + +For example, the [`icdiff`](https://github.com/Homebrew/homebrew-core/blob/c88dd1843d76416948ecd3405f9e3167fdd7ba48/Formula/icdiff.rb#L19) formula uses this utility. Note that it is necessary to include the utility in the formula; for example with Python one must use `include Language::Python::Shebang`. + ### Adding optional steps **Note:** [`option`](https://rubydoc.brew.sh/Formula#option-class_method)s are not allowed in Homebrew/homebrew-core as they are not tested by CI. @@ -782,33 +852,9 @@ if build.without? "ham" end ``` -[`option`](https://rubydoc.brew.sh/Formula#option-class_method) names should be prefixed with the words `with` or `without`. For example, an option to run a test suite should be named `--with-test` or `--with-check` rather than `--test`, and an option to enable a shared library `--with-shared` rather than `--shared` or `--enable-shared`. +[`option`](https://rubydoc.brew.sh/Formula#option-class_method) names should be prefixed with the words `with` or `without`. For example, an option to run a test suite should be named `--with-test` or `--with-check` rather than `--test`, and an option to enable a shared library `--with-shared` rather than `--shared` or `--enable-shared`. See the [alternative `ffmpeg`](https://github.com/homebrew-ffmpeg/homebrew-ffmpeg/blob/HEAD/Formula/ffmpeg.rb) formula for examples. -[`option`](https://rubydoc.brew.sh/Formula#option-class_method)s that aren’t `build.with? ` or `build.without?` should be deprecated with [`deprecated_option`](https://rubydoc.brew.sh/Formula#deprecated_option-class_method). See [`wget`](https://github.com/Homebrew/homebrew-core/blob/3f762b63c6fbbd49191ffdf58574d7e18937d93f/Formula/wget.rb#L27-L31) for an example. - -### File level operations - -You can use the file utilities provided by Ruby's [`FileUtils`](https://www.ruby-doc.org/stdlib/libdoc/fileutils/rdoc/index.html). These are included in the [`Formula`](https://rubydoc.brew.sh/Formula) class, so you do not need the `FileUtils.` prefix to use them. - -When creating symlinks, take special care to ensure they are *relative* symlinks. This makes it easier to create a relocatable bottle. For example, to create a symlink in `bin` to an executable in `libexec`, use - -```ruby -bin.install_symlink libexec/"name" -``` - -instead of: - -```ruby -ln_s libexec/"name", bin -``` - -The symlinks created by [`install_symlink`](https://rubydoc.brew.sh/Pathname#install_symlink-instance_method) are guaranteed to be relative. `ln_s` will only produce a relative symlink when given a relative path. - -### Rewriting a script shebang - -Some formulae install executable scripts written in an interpreted language such as Python or Perl. Homebrew provides a `rewrite_shebang` method to rewrite the shebang of a script. This replaces a script's original interpreter path with the one the formula depends on. This guarantees that the correct interpreter is used at execution time. This isn't required if the build system already handles it (e.g. often with `pip` or Perl `ExtUtils::MakeMaker`). - -For example, the [`icdiff` formula](https://github.com/Homebrew/homebrew-core/blob/7beae5ab57c65249403699b2b0700fbccf14e6cb/Formula/icdiff.rb#L16) uses such utility. Note that it is necessary to include the utility in the formula, for example with Python one must use `include Language::Python::Shebang`. +[`option`](https://rubydoc.brew.sh/Formula#option-class_method)s that aren’t `build.with?` or `build.without?` should be deprecated with [`deprecated_option`](https://rubydoc.brew.sh/Formula#deprecated_option-class_method). See the [`wget`](https://github.com/Homebrew/homebrew-core/blob/3f762b63c6fbbd49191ffdf58574d7e18937d93f/Formula/wget.rb#L27-L31) formula for an example. ### Handling files that should persist over formula upgrades @@ -818,140 +864,154 @@ Another example would be configuration files that should not be overwritten on p ### Service files -There are two ways to add plists and systemd services to a formula, so that [`brew services`](https://github.com/Homebrew/homebrew-services) can pick it up: -1. If the formula already provides a file the formula can install it into the prefix like so. +There are two ways to add `launchd` plists and `systemd` services to a formula, so that [`brew services`](https://github.com/Homebrew/homebrew-services) can pick them up: + +1. If the package already provides a service file the formula can install it into the prefix: + + ```ruby + prefix.install_symlink "file.plist" => "#{plist_name}.plist" + prefix.install_symlink "file.service" => "#{service_name}.service" + ``` + +2. If the formula does not provide a service file you can generate one using the following stanza: + + ```ruby + service do + run bin/"script" + end + ``` + +#### Service block methods + +This table lists the options you can set within a `service` block. Only the `run` field is required which indicates what to run. + +| method | default | macOS | Linux | description | +| ----------------------- | ------------ | :---: | :---: | ----------- | +| `run` | - | yes | yes | command to execute: an array with arguments or a path +| `run_type` | `:immediate` | yes | yes | type of service: `:immediate`, `:interval` or `:cron` +| `interval` | - | yes | yes | controls the start interval, required for the `:interval` type +| `cron` | - | yes | yes | controls the trigger times, required for the `:cron` type +| `keep_alive` | `false` | yes | yes | [sets contexts](#keep_alive-options) in which the service will keep the process running +| `launch_only_once` | `false` | yes | yes | whether the command should only run once +| `require_root` | `false` | yes | yes | whether the service requires root access +| `environment_variables` | - | yes | yes | hash of variables to set +| `working_dir` | - | yes | yes | directory to operate from +| `root_dir` | - | yes | yes | directory to use as a chroot for the process +| `input_path` | - | yes | yes | path to use as input for the process +| `log_path` | - | yes | yes | path to write `stdout` to +| `error_log_path` | - | yes | yes | path to write `stderr` to +| `restart_delay` | - | yes | yes | number of seconds to delay before restarting a process +| `process_type` | - | yes | no-op | type of process to manage: `:background`, `:standard`, `:interactive` or `:adaptive` +| `macos_legacy_timers` | - | yes | no-op | timers created by `launchd` jobs are coalesced unless this is set +| `sockets` | - | yes | no-op | socket that is created as an accesspoint to the service + +For services that are kept alive after starting you can use the default `run_type`: ```ruby -prefix.install_symlink "file.plist" => "#{plist_name}.plist" -prefix.install_symlink "file.service" => "#{service_name}.service" -``` - -2. If the formula does not provide a service you can generate one using the following stanza. -```rb service do - run bin/"script" + run [opt_bin/"beanstalkd", "test"] + keep_alive true + run_type :immediate # This should be omitted since it's the default end ``` -#### Service block methods -There are many more options you can set within such a block, and in this table you will find them all. -The only required field in a `service` block is the `run` field to indicate what to run. - -| Method | Default | macOS | Linux | Description | -|-------------------------|--------------|-------|-------|------------------------------------------------------------------------------------------| -| `run` | - | yes | yes | Command to execute, an array with arguments or a path | -| `run_type` | `:immediate` | yes | yes | The type of service, `:immediate`, `:interval` or `:cron` | -| `keep_alive` | `false` | yes | yes | If the service needs to keep the process running after exit | -| `interval` | - | yes | yes | Controls the start interval, required for the `:interval` type | -| `cron` | - | yes | yes | Controls the trigger times, required for the `:cron` type | -| `launch_only_once` | false | yes | yes | If the command should only run once | -| `environment_variables` | - | yes | yes | A hash of variables to set | -| `working_dir` | - | yes | yes | The directory to operate from | -| `root_dir` | - | yes | yes | The directory to use as a chroot for the process | -| `input_path` | - | yes | yes | Path to use as input for the process | -| `log_path` | - | yes | yes | Path to write stdout to | -| `error_log_path` | - | yes | yes | Path to write stderr to | -| `restart_delay` | - | yes | yes | The delay before restarting a process | -| `process_type` | - | yes | no-op | The type of process to manage, `:background`, `:standard`, `:interactive` or `:adaptive` | -| `macos_legacy_timers` | - | yes | no-op | Timers created by launchd jobs are coalesced unless this is set | -| `sockets` | - | yes | no-op | A socket that is created as an accesspoint to the service | - -For services that start and keep running alive you can use the default `run_type :` like so: -```ruby - service do - run [opt_bin/"beanstalkd", "test"] - keep_alive true - run_type :immediate # This should be omitted since it's the default - end -``` - If a service needs to run on an interval, use `run_type :interval` and specify an interval: + ```ruby - service do - run [opt_bin/"beanstalkd", "test"] - run_type :interval - interval 500 - end +service do + run [opt_bin/"beanstalkd", "test"] + run_type :interval + interval 500 +end ``` If a service needs to run at certain times, use `run_type :cron` and specify a time with the crontab syntax: + ```ruby - service do - run [opt_bin/"beanstalkd", "test"] - run_type :cron - cron "5 * * * *" - end +service do + run [opt_bin/"beanstalkd", "test"] + run_type :cron + cron "5 * * * *" +end ``` -For environment variables you can specify a hash. For the path there is the helper method `std_service_path_env`. -This method will set the path to `#{HOMEBREW_PREFIX}/bin:#{HOMEBREW_PREFIX}/sbin:/usr/bin:/bin:/usr/sbin:/sbin` so the service can find other `brew` commands. -```rb - service do - run opt_bin/"beanstalkd" - environment_variables PATH: std_service_path_env - end +Environment variables can be set with a hash. For the `PATH` there is the helper method `std_service_path_env` which returns `#{HOMEBREW_PREFIX}/bin:#{HOMEBREW_PREFIX}/sbin:/usr/bin:/bin:/usr/sbin:/sbin` so the service can find other `brew`-installed commands. + +```ruby +service do + run opt_bin/"beanstalkd" + environment_variables PATH: std_service_path_env +end ``` -#### KeepAlive options -The standard options, keep alive regardless of any status or circomstances -```rb - service do - run [opt_bin/"beanstalkd", "test"] - keep_alive true # or false - end +#### `keep_alive` options + +The standard options keep the service alive regardless of any status or circumstances: + +```ruby +service do + run [opt_bin/"beanstalkd", "test"] + keep_alive true # or false +end ``` -Same as above in hash form -```rb - service do - run [opt_bin/"beanstalkd", "test"] - keep_alive { always: true } - end +Same as above in hash form: + +```ruby +service do + run [opt_bin/"beanstalkd", "test"] + keep_alive { always: true } +end ``` -Keep alive until the job exits with a non-zero return code -```rb - service do - run [opt_bin/"beanstalkd", "test"] - keep_alive { succesful_exit: true } - end +Keep alive until the service exits with a non-zero return code: + +```ruby +service do + run [opt_bin/"beanstalkd", "test"] + keep_alive { succesful_exit: true } +end ``` -Keep alive only if the job crashed -```rb - service do - run [opt_bin/"beanstalkd", "test"] - keep_alive { crashed: true } - end +Keep alive only if the job crashed: + +```ruby +service do + run [opt_bin/"beanstalkd", "test"] + keep_alive { crashed: true } +end ``` -Keep alive as long as a file exists -```rb - service do - run [opt_bin/"beanstalkd", "test"] - keep_alive { path: "/some/path" } - end +Keep alive as long as a file exists: + +```ruby +service do + run [opt_bin/"beanstalkd", "test"] + keep_alive { path: "/some/path" } +end ``` -#### Socket format -The sockets method accepts a formatted socket definition as `://:`. -- `type`: `udp` or `tcp` -- `host`: The host to run the socket on. For example `0.0.0.0` -- `port`: The port the socket should listen on. +#### `sockets` format + +The `sockets` method accepts a formatted socket definition as `://:`. + +* `type`: `udp` or `tcp` +* `host`: host to run the socket on, e.g. `0.0.0.0` +* `port`: port number the socket should listen on Please note that sockets will be accessible on IPv4 and IPv6 addresses by default. ### Using environment variables -Homebrew has multiple levels of environment variable filtering which affects variables available to formulae. +Homebrew has multiple levels of environment variable filtering which affects which variables are available to formulae. -Firstly, the overall environment in which Homebrew runs is filtered to avoid environment contamination breaking from-source builds (). In particular, this process filters all but the given whitelisted variables, but allows environment variables prefixed with `HOMEBREW_`. The specific implementation can be seen in [`bin/brew`](https://github.com/Homebrew/brew/blob/HEAD/bin/brew). +Firstly, the overall [environment in which Homebrew runs is filtered](https://github.com/Homebrew/brew/issues/932) to avoid environment contamination breaking from-source builds. In particular, this process filters all but a select list of variables, plus allowing any prefixed with `HOMEBREW_`. The specific implementation is found in [`bin/brew`](https://github.com/Homebrew/brew/blob/HEAD/bin/brew). -The second level of filtering removes sensitive environment variables (such as credentials like keys, passwords or tokens) to avoid malicious subprocesses obtaining them (). This has the effect of preventing any such variables from reaching a formula's Ruby code as they are filtered before it is called. The specific implementation can be seen in the [`ENV.clear_sensitive_environment!` method](https://github.com/Homebrew/brew/blob/HEAD/Library/Homebrew/extend/ENV.rb). +The second level of filtering [removes sensitive environment variables](https://github.com/Homebrew/brew/pull/2524) (such as credentials like keys, passwords or tokens) to prevent malicious subprocesses from obtaining them. This has the effect of preventing any such variables from reaching a formula's Ruby code since they are filtered before it is called. The specific implementation is found in the [`ENV.clear_sensitive_environment!` method](https://github.com/Homebrew/brew/blob/HEAD/Library/Homebrew/extend/ENV.rb). -You can set environment variables in a formula's `install` method using `ENV["VARIABLE_NAME"] = "VALUE"`. An example can be seen in [the `gh` formula](https://github.com/Homebrew/homebrew-core/blob/fd9ad29f8e3ca9476f838ebb13794ddb7dafba00/Formula/gh.rb#L22). Environment variables can also be set temporarily using the `with_env` method; any variables defined in the call to that method will be restored to their original values at the end of the block. An example can be seen in [the `csound` formula](https://github.com/Homebrew/homebrew-core/blob/c3feaff8cdb578331385676620c865796cfc3388/Formula/csound.rb#L155-L157). +You can set environment variables in a formula's `install` method using `ENV["VARIABLE_NAME"] = "VALUE"`. An example can be seen in the [`csound`](https://github.com/Homebrew/homebrew-core/blob/60e775b0ede2445f9a0d277fa86bb7e594cd6778/Formula/csound.rb#L94) formula. Environment variables can also be set temporarily using the `with_env` method; any variables defined in the call to that method will be restored to their original values at the end of the block. An example can be seen in the [`gh`](https://github.com/Homebrew/homebrew-core/blob/5cd44bc2d74eba8cbada8bb85f505c0ac847057b/Formula/gh.rb#L28) formula. -In summary, environment variables used by a formula need to conform to these filtering rules in order to be available. +In summary, any environment variables intended for use by a formula need to conform to these filtering rules in order to be available. ### Deprecating and disabling a formula @@ -959,42 +1019,25 @@ See our [Deprecating, Disabling, and Removing Formulae](Deprecating-Disabling-an ## Updating formulae -Eventually a new version of the software will be released. In this case you should update the [`url`](https://rubydoc.brew.sh/Formula#url-class_method) and [`sha256`](https://rubydoc.brew.sh/Formula#sha256%3D-class_method). You can use: +When a new version of the software is released, use `brew bump-formula-pr` to automatically update the [`url`](https://rubydoc.brew.sh/Formula#url-class_method) and [`sha256`](https://rubydoc.brew.sh/Formula#sha256%3D-class_method), remove any [`revision`](https://rubydoc.brew.sh/Formula#revision%3D-class_method) lines, and submit a pull request. See our [How To Open a Homebrew Pull Request](How-To-Open-a-Homebrew-Pull-Request.md) documentation for more information. -```sh -brew bump-formula-pr foo -``` +## Troubleshooting for new formulae -If a [`revision`](https://rubydoc.brew.sh/Formula#revision%3D-class_method) line exists outside any `bottle do` block it should be removed. - -Leave the `bottle do ... end` block as-is; our CI system will update it when we pull your change. - -Check if the formula you are updating is a dependency for any other formulae by running `brew uses `. If it is a dependency, run `brew reinstall` for all the dependencies after it is installed and verify they work correctly. - -## Style guide - -Homebrew wants to maintain a consistent Ruby style across all formulae mostly based on [Ruby Style Guide](https://github.com/rubocop-hq/ruby-style-guide#the-ruby-style-guide). Other formulae may not have been updated to match this guide yet but all new ones should. Also: - -* The order of methods in a formula should be consistent with other formulae (e.g.: `def install` goes before `def post_install`). -* An empty line is required before the `__END__` line. - -## Troubleshooting for people writing new formulae - -### Version detection fails +### Version detection failures Homebrew tries to automatically determine the [`version`](https://rubydoc.brew.sh/Formula#version-class_method) from the [`url`](https://rubydoc.brew.sh/Formula#url-class_method) to avoid duplication. If the tarball has an unusual name you may need to manually assign the [`version`](https://rubydoc.brew.sh/Formula#version-class_method). ### Bad makefiles -Not all projects have makefiles that will run in parallel so try to deparallelize by adding these lines to the `install` method: +If a project's makefile will not run in parallel, try to deparallelize by adding these lines to the formula's `install` method: ```ruby ENV.deparallelize -system "make" # separate make and make install steps +system "make" # separate compilation and installation steps system "make", "install" ``` -If that fixes it, please open an [issue](https://github.com/Homebrew/homebrew-core/issues) so that we can fix it for everyone. +If that fixes it, please open an issue with the upstream project so that we can fix it for everyone. ### Still won’t work? @@ -1005,25 +1048,25 @@ brew search --macports foo brew search --fink foo ``` -## Superenv notes +### Superenv notes `superenv` is our "super environment" that isolates builds by removing `/usr/local/bin` and all user `PATH`s that are not essential for the build. It does this because user `PATH`s are often full of stuff that breaks builds. `superenv` also removes bad flags from the commands passed to `clang`/`gcc` and injects others (for example all [`keg_only`](https://rubydoc.brew.sh/Formula#keg_only-class_method) dependencies are added to the `-I` and `-L` flags). -## Fortran +### Fortran Some software requires a Fortran compiler. This can be declared by adding `depends_on "gcc"` to a formula. -## MPI +### MPI -Formula requiring MPI should use [OpenMPI](https://www.open-mpi.org/) by adding `depends_on "open-mpi"` to the formula, rather than [MPICH](https://www.mpich.org/). These packages have conflicts and provide the same standardised interfaces. Choosing a default implementation and requiring it to be adopted allows software to link against multiple libraries that rely on MPI without creating un-anticipated incompatibilities due to differing MPI runtimes. +Packages requiring MPI should use [OpenMPI](https://www.open-mpi.org/) by adding `depends_on "open-mpi"` to the formula, rather than [MPICH](https://www.mpich.org/). These packages have conflicts and provide the same standardised interfaces. Choosing a default implementation and requiring its adoption allows software to link against multiple libraries that rely on MPI without creating unanticipated incompatibilities due to differing MPI runtimes. -## Linear algebra libraries +### Linear algebra libraries -By default packages that require BLAS/LAPACK linear algebra interfaces should link to [OpenBLAS](https://www.openblas.net/) using `depends_on "openblas"` and passing `-DBLA_VENDOR=OpenBLAS` to CMake (applies to CMake based formula only) rather than Apple's Accelerate framework, or the default reference lapack implementation. Apple's implementation of BLAS/LAPACK is outdated and may introduce hard-to-debug problems. The reference `lapack` formula is fine, although it is not actively maintained or tuned. For this reason, formulae needing BLAS/LAPACK should link with OpenBLAS. +Packages requiring BLAS/LAPACK linear algebra interfaces should link to [OpenBLAS](https://www.openblas.net/) by adding `depends_on "openblas"` and (if built with CMake) passing `-DBLA_VENDOR=OpenBLAS` to CMake, rather than Apple's Accelerate framework or the default reference `lapack` implementation. Apple's implementation of BLAS/LAPACK is outdated and may introduce hard-to-debug problems. The reference `lapack` formula is fine, although it is not actively maintained or tuned. ## How to start over (reset to upstream `master`) -Have you created a real mess in Git which stops you from creating a commit you want to submit to us? You might want to consider starting again from scratch. Your changes can be reset to the Homebrew `master` branch by running: +Have you created a real mess in Git which stops you from creating a commit you want to submit to us? You might want to consider starting again from scratch. Your changes to the Homebrew `master` branch can be reset by running: ```sh git checkout -f master