From 55efd1f83cf0c81b442f1138d4d9cc705d238918 Mon Sep 17 00:00:00 2001 From: Bevan Kay Date: Fri, 4 Sep 2026 21:46:45 +1000 Subject: [PATCH] docs/Cask-Cookbook: align with cask standards - `depends_on macos:`: drop the `">= :big_sur"` and `"== :big_sur"` forms, deprecated by `MacOSRequirement.parse` and unused in homebrew/cask. An exact set needs two or more symbols, as a one-element array is parsed as a minimum. - Stanza parameters: drop the claim that they are alphabetical, which is untrue of `uninstall`, `zap` and `sha256`. - `uninstall`: reword the note on directive order. - OSDN: `audit_download_url_is_osdn` rejects any `osdn.jp` host, so drop the OSDN URL format and narrow the section, the audit error linked to it and the headings vale style to SourceForge. - Replace the `appium-desktop` cask, since removed, with `unison-app` as the example of the `-app` suffix rule. - Document `launchctl:` wildcards and the `os` stanza, the latter alongside `arch`, which it mirrors. - Document that the minimum macOS release comes from the artifact and Sparkle feed rather than vendor documentation, per `audit_min_os`. --- Library/Homebrew/cask/audit.rb | 6 +-- docs/Cask-Cookbook.md | 67 ++++++++++++++++++-------- docs/vale-styles/Homebrew/Headings.yml | 1 - 3 files changed, 50 insertions(+), 24 deletions(-) diff --git a/Library/Homebrew/cask/audit.rb b/Library/Homebrew/cask/audit.rb index 855f697c95109..402cc525ad7e7 100644 --- a/Library/Homebrew/cask/audit.rb +++ b/Library/Homebrew/cask/audit.rb @@ -466,8 +466,8 @@ def audit_hosting_with_livecheck end end - SOURCEFORGE_OSDN_REFERENCE_URL = "https://docs.brew.sh/Cask-Cookbook#sourceforgeosdn-urls" - private_constant :SOURCEFORGE_OSDN_REFERENCE_URL + SOURCEFORGE_REFERENCE_URL = "https://docs.brew.sh/Cask-Cookbook#sourceforge-urls" + private_constant :SOURCEFORGE_REFERENCE_URL sig { void } def audit_download_url_format @@ -476,7 +476,7 @@ def audit_download_url_format odebug "Auditing URL format" return unless bad_sourceforge_url? - add_error "SourceForge URL format incorrect. See #{Formatter.url(SOURCEFORGE_OSDN_REFERENCE_URL)}", + add_error "SourceForge URL format incorrect. See #{Formatter.url(SOURCEFORGE_REFERENCE_URL)}", location: url.location end diff --git a/docs/Cask-Cookbook.md b/docs/Cask-Cookbook.md index 40ca62d4d8567..7036ee6c7c77a 100644 --- a/docs/Cask-Cookbook.md +++ b/docs/Cask-Cookbook.md @@ -1,5 +1,5 @@ --- -last_review_date: "2026-08-25" +last_review_date: "2026-09-06" --- # Cask Cookbook @@ -115,7 +115,8 @@ Having a common order for stanzas makes casks easier to update and parse. Below 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. +Note that every stanza that has additional parameters (`:symbols` after a `,`) shall have them on separate lines, one per line. +An exception is `target:` which typically consists of short lines. ## Stanzas @@ -410,7 +411,7 @@ conflicts_with cask: "macfuse@dev" | ---------------- | ----------- | | `cask:` | required Homebrew cask tokens as string or array | | `formula:` | required Homebrew formula names as string or array | -| `macos:` | minimum macOS release as a symbol, or an array of exact acceptable releases; the older string comparison form is deprecated | +| `macos:` | minimum macOS release as a symbol, or an array of two or more exact acceptable releases | | `maximum_macos:` | maximum macOS release requirement using a `<=` comparison | | `linux:` | Linux requirement, expressed as `depends_on :linux` | | `arch:` | hardware requirements as symbol or array | @@ -447,13 +448,8 @@ Only major releases are covered (10.x numbers containing a single dot or whole n depends_on macos: :big_sur ``` -`depends_on macos:` still accepts a string starting with a comparison operator such as `>=`, followed by a macOS release in the form above. The following is a valid expression meaning “at least macOS Big Sur (11.0)”: - -```ruby -depends_on macos: ">= :big_sur" -``` - -Use `==` in the string form only when a cask must run on one exact macOS release. An array of symbols is also accepted when a cask must run on one of an exact set of macOS releases: +An array of symbols is accepted when a cask must run on one of an exact set of macOS releases. +The array must list two or more releases; a single-element array means the same thing as the bare symbol, i.e. a minimum: ```ruby depends_on macos: [ @@ -476,6 +472,16 @@ on_macos do end ``` +##### Choosing the minimum macOS release + +The minimum comes from the software, not from the vendor’s documentation. +`brew audit --online` reads the minimum the artifact declares for itself, from `LSMinimumSystemVersion` in a bundle’s `Info.plist`, the `Distribution` file in a `pkg`, or the load commands of a bundle’s main executable. +It compares that with `minimumSystemVersion` from the feed when the cask’s `livecheck` uses `strategy :sparkle`, takes the newer of the two, and errors when the cask declares something else. +A vendor’s website or release notes claiming a different minimum does not change what is expected here. +`brew audit --cask --online --fix` can write the correct value for a cask with no architecture-, OS- or release-specific stanzas. + +Casks are only expected to declare a minimum newer than the oldest macOS release Homebrew allows. + #### `depends_on` *linux* Top-level `depends_on :linux` marks a cask as Linux-only. @@ -966,7 +972,7 @@ The easiest and most useful `uninstall` directive is [`pkgutil:`](#uninstall-pkg * [`trash:`](#uninstall-trash) (string or array) - double-quoted, absolute paths of files or directory trees to move to Trash * **`rmdir:`** (string or array) - double-quoted, absolute paths of directories to remove if empty; works recursively -Each `uninstall` technique is applied according to the order above. The order in which `uninstall` keys appear in the cask file is ignored. +Each `uninstall` technique is applied according to the order above, regardless of the order present in the cask file. 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. @@ -1012,6 +1018,8 @@ for plist in /Library/Launch{Agents,Daemons}/*.plist ~/Library/LaunchAgents/*.pl done ``` +A job ID may contain a `*` wildcard, which removes every currently running `launchd` job whose ID matches. + #### `uninstall` *quit* `quit:` sends the standard macOS quit Apple Event to the application (equivalent to Cmd+Q), which allows the app to present save dialogs before closing. It runs during both `brew uninstall` and `brew upgrade`/`brew reinstall`. @@ -1226,19 +1234,15 @@ Artifacts may also be distributed via Git repositories. URLs that end in `.git` | `branch:` | string identifying the Git branch to download | | `only_path:` | path within the repository to limit the checkout to. If only a single directory of a large repository is required, using this option can significantly speed up downloads. If provided, artifact paths are relative to this path. (Example: [font-geo.rb](https://github.com/Homebrew/homebrew-cask/blob/a6348a1710928bf43510098725c2068ffe3adc69/Casks/font/font-g/font-geo.rb#L5-L8)) | -#### SourceForge/OSDN URLs +#### SourceForge URLs -SourceForge and OSDN (formerly `SourceForge.JP`) projects are common ways to distribute binaries, but they provide many different styles of URLs to get to the goods. +SourceForge projects are a common way to distribute binaries, but they provide many different styles of URLs to get to the goods. We prefer URLs of this format: https://downloads.sourceforge.net//. -Or, if it’s from OSDN, where `` 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: +If that format is 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 @@ -1363,7 +1367,11 @@ If no additional files are discovered, instead of a zap stanza, include the foll Casks can deliver specific versions of artifacts depending on the current macOS release, CPU architecture, or system OS by either tailoring the `url` / `sha256` / `version` stanzas, using the [`on_` syntax](Formula-Cookbook.md#handling-different-system-configurations) (which replaces conditional statements using `MacOS.version` or `Hardware::CPU`), or both. -If your cask's artifact is offered as separate downloads for Apple Silicon and Intel architectures, or offers downloads for Linux, they'll presumably be downloadable at distinct URLs that differ only slightly. To adjust the URL depending on the current CPU architecture and system OS, supply a hash for each to the `arm:`, `intel:`, `arm64_linux:`, and `x86_64_linux:` parameters of `sha256`; use the special `arch` and `os` stanzas to define the unique components of the respective URLs for substitution in the `url`. Additional substitutions can be defined by calling `on_arch_conditional` and `on_system_conditional` directly. Example (from [libreoffice.rb](https://github.com/Homebrew/homebrew-cask/blob/a4164b8f5084fdaefb6e2e2f4f699270690b7845/Casks/l/libreoffice.rb#L1-L10)): +If your cask's artifact is offered as separate downloads for Apple Silicon and Intel architectures, or offers downloads for Linux, they'll presumably be downloadable at distinct URLs that differ only slightly. +To adjust the URL depending on the current CPU architecture and system OS, supply a hash for each to the `arm:`, `intel:`, `arm64_linux:`, and `x86_64_linux:` parameters of `sha256`; use the special `arch` (`arm:`, `intel:`) and `os` (`macos:`, `linux:`) stanzas to define the unique components of the respective URLs for substitution in the `url`. +Leave a key out rather than giving it an empty string when a component is only present on one architecture or operating system. +Each stanza defines one substitution; additional substitutions can be defined by calling `on_arch_conditional` and `on_system_conditional` directly. +Example (from [libreoffice.rb](https://github.com/Homebrew/homebrew-cask/blob/a4164b8f5084fdaefb6e2e2f4f699270690b7845/Casks/l/libreoffice.rb#L1-L10)): ```ruby cask "libreoffice" do @@ -1378,6 +1386,24 @@ cask "libreoffice" do end ``` +A cask that varies by both takes a `sha256` for each supported combination. +Example (from [1password-cli.rb](https://github.com/Homebrew/homebrew-cask/blob/e04021c857906ba15366b622c8b35957b9aef13c/Casks/1/1password-cli.rb#L1-L11)): + +```ruby +cask "1password-cli" do + arch arm: "arm64", intel: "amd64" + os macos: "darwin", linux: "linux" + + version "2.39.0" + sha256 arm: "05391d3388a0c0b4f602691bedc1ab368541c487b6f14d2e3399743b4682af67", + intel: "753fbf56b00996426edbb8439d2f3c0be9227b9557cdff468fb144cd3621aa6e", + arm64_linux: "829baeff1c07e055cfa132031b1d9f2282ccdf5076258e482caf2fda70aea5d0", + x86_64_linux: "6fba7f376b6c6dec49f41b06408930a43ad064cce103c6a2ce5b3d0413a86434" + + url "https://cache.agilebits.com/dist/1P/op2/pkg/v#{version}/op_#{os}_#{arch}_v#{version}.zip" +end +``` + If the version number is different for each architecture, locate the unique `version` and (if checked) `sha256` stanzas within `on_arm` and `on_intel` blocks. Example (from [inkscape.rb](https://github.com/Homebrew/homebrew-cask/blob/11f6966bf17628b98895d64a61a4fb0bc1bb31bf/Casks/i/inkscape.rb#L1-L13)): ```ruby @@ -1526,7 +1552,8 @@ Details of software names and brands will inevitably be lost in the conversion t * If the result conflicts with the name of an existing cask or Homebrew/homebrew-core formula, make yours unique by prepending the name of the vendor or developer, followed by a hyphen. Example: [caffeine.rb](https://github.com/Homebrew/homebrew-cask/blob/HEAD/Casks/c/caffeine.rb) and [domzilla-caffeine.rb](https://github.com/Homebrew/homebrew-cask/blob/HEAD/Casks/d/domzilla-caffeine.rb). -* If the result still conflicts with the name of an existing Homebrew/homebrew-core formula, adjust the name to better describe the difference by e.g. appending `-app`. Example: `appium` formula and `appium-desktop` cask, `angband` formula and `angband-app` cask. +* If the result still conflicts with the name of an existing Homebrew/homebrew-core formula, adjust the name to better describe the difference by e.g. appending `-app`. + Example: `unison` formula and [`unison-app`](https://github.com/Homebrew/homebrew-cask/blob/HEAD/Casks/u/unison-app.rb) cask, `angband` formula and [`angband-app`](https://github.com/Homebrew/homebrew-cask/blob/HEAD/Casks/a/angband-app.rb) cask. * Inevitably, there are a small number of exceptions not covered by the rules. Don’t hesitate to [use the forum](https://github.com/orgs/Homebrew/discussions) if you have a problem. diff --git a/docs/vale-styles/Homebrew/Headings.yml b/docs/vale-styles/Homebrew/Headings.yml index 11568c50e48da..213ade5e8293f 100644 --- a/docs/vale-styles/Homebrew/Headings.yml +++ b/docs/vale-styles/Homebrew/Headings.yml @@ -46,7 +46,6 @@ exceptions: - LLM - Launchpad - MPI - - OSDN - Ops Team - PLC - PRs