Cask Cookbook

每個 Cask 都是一個 Ruby 塊,以特殊的標頭行開始。 Cask 定義本身始終被封裝在一個 do ... end 塊中。例子

cask "anybar" do
  version "0.2.3"
  sha256 "c87dbc6aff5411676a471e84905d69c671b62b93b1210bd95c9d776d087de95c"

  url "https://github.com/tonsky/AnyBar/releases/download/#{version}/AnyBar-#{version}.zip"
  name "AnyBar"
  desc "Menu bar status indicator"
  homepage "https://github.com/tonsky/AnyBar"

  app "AnyBar.app"
end

Cask 語言是宣告性的

每個 cask 包含一系列的 stanza(或“字段”),它們聲明了軟件的獲取和安裝方式。在一個宣告性的語言中,作者不需要擔心順序。只要所有所需的字段都存在,Homebrew Cask 就會在安裝時找出需要做的事情。

為了使維護更加輕鬆,通常將最常更新的 stanza 放在頂部。但這只是一個慣例,不是一個規則。

例外:像 postflight 這樣的 do 塊可能封裝了一塊純粹的 Ruby 代碼塊。該塊內的行遵循程序化(依賴順序)範式。

標頭行詳細資訊

標頭行上的 Cask 名稱(<cask-token>cask <cask-token> do 應與 Cask 檔名匹配,不帶 .rb 擴展名,並用雙引號括起來。

目前對於 cask tokens 存在一些任意限制,這些限制正在被移除的過程中。GitHub Actions 會在過渡期間檢查任何錯誤。

Stanza 順序

將 stanza 以固定的順序排列,可以使 cask 更容易更新和解析。以下是完整的 stanza 順序(沒有 cask 會包含所有 stanza)。這裡顯示的空行也很重要,因為它們有助於視覺上區分信息。

version
sha256

language

url
name
desc
homepage

livecheck

deprecate!
disable!

auto_updates
conflicts_with
depends_on
container

suite
app
pkg
installer
binary
manpage
colorpicker
dictionary
font
input_method
internet_plugin
keyboard_layout
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

postflight

uninstall_preflight

uninstall_postflight

uninstall

zap

caveats

請注意,每個具有額外參數的 stanza(在逗號後面有 :symbols 的 stanza)應該單獨放在一行上,按字母順序排列。一個例外是 target:,它通常由短行組成。

Stanzas

必要的 Stanza

每個 cask 都需要以下的每個 stanza。

名稱 允許多次出現?
版本 應用程式版本。
sha256 url 下載的文件的 SHA-256 校驗和,通過命令 shasum -a 256 <file> 計算。可以通過使用特殊值 :no_check 來抑制。
url .dmg/.zip/.tgz/.tbz2 檔案的 URL,該檔案包含應用程式。如果 urlhomepage stanza 中的域名不同,應添加一個註釋。對於每次訪問都會更改的 URL,應使用區塊語法。
名稱 提供供應商定義的完整和正確名稱的字符串。
desc cask 的一行描述。運行 brew info 時顯示。
homepage 應用程式主頁;用於 brew home 命令。
livecheck 描述如何查找此 cask 的更新的 Ruby 塊。優先於 appcast
depends_on 此 cask 的依賴項和要求的列表。
zap 更完整的卸載的附加程序,包括用戶文件和共享資源。

至少還需要一個 artifact stanza

每個 cask 必須聲明一個或多個artifacts(即要安裝的東西)。

名稱 允許多次出現?
app 應該在安裝時移動到 /Applications 文件夾中的 .app 的相對路徑。
suite 應該在安裝時移動到 /Applications 文件夾中的包含目錄的相對路徑。
pkg 包含發行版的 .pkg 文件的相對路徑。
installer 描述一個必須運行的可執行文件,以完成安裝。
二進制文件 相對路徑到一個二進制文件,在安裝時應該鏈接到$(brew --prefix)/bin文件夾中。
手冊頁 相對路徑到一個手冊頁,在安裝時應該鏈接到相應的手冊頁文件夾中,例如/usr/local/share/man/man3用於my_app.3
顏色選擇器 相對路徑到一個顏色選擇器插件,在安裝時應該移動到~/Library/ColorPickers文件夾中。
字典 相對路徑到一個字典,在安裝時應該移動到~/Library/Dictionaries文件夾中。
字體 相對路徑到一個字體,在安裝時應該移動到~/Library/Fonts文件夾中。
輸入法 相對路徑到一個輸入法,在安裝時應該移動到~/Library/Input Methods文件夾中。
互聯網插件 相對路徑到一個互聯網插件,在安裝時應該移動到~/Library/Internet Plug-Ins文件夾中。
鍵盤布局 相對路徑到一個鍵盤布局,在安裝時應該移動到/Library/Keyboard Layouts文件夾中。
首選項窗格 相對路徑到一個首選項窗格,在安裝時應該移動到~/Library/PreferencePanes文件夾中。
快速查看插件 相對路徑到一個快速查看插件,在安裝時應該移動到~/Library/QuickLook文件夾中。
Spotlight元數據導入器 相對路徑到一個Spotlight元數據導入器,在安裝時應該移動到~/Library/Spotlight文件夾中。
屏幕保護程序 相對路徑到一個屏幕保護程序,在安裝時應該移動到~/Library/Screen Savers文件夾中。
服務 相對路徑到一個服務,在安裝時應該移動到~/Library/Services文件夾中。
音頻單元插件 應將音訊單元插件的相對路徑在安裝時移至~/Library/Audio/Components資料夾。
vst_plugin 應將 VST 插件的相對路徑在安裝時移至~/Library/Audio/VST資料夾。
vst3_plugin 應將 VST3 插件的相對路徑在安裝時移至~/Library/Audio/VST3資料夾。
artifact 在安裝時應移動至任意路徑的相對路徑。必須提供target的絕對路徑。(例如:free-gpgmail.rb) 這僅適用於非常規情況;當移動.app包時,強烈建議使用app段。
stage_only true。確保該 Cask 不包含可啟動的 artifacts。

可選的 Stanza

名稱 允許多次出現?
uninstall 卸載 Cask 的程序。僅在使用pkg段時才是可選的。
conflicts_with 與該 Cask 衝突的列表(尚未生效)。
caveats 在安裝時為用戶提供特定於 Cask 的信息的字符串或 Ruby 塊。
deprecate! 日期作為字符串,格式為YYYY-MM-DD,以及提供原因的字符串或符號。
disable! 日期作為字符串,格式為YYYY-MM-DD,以及提供原因的字符串或符號。
preflight 包含預安裝操作的 Ruby 塊(僅在非常罕見的情況下需要)。
postflight 包含後安裝操作的 Ruby 塊。
uninstall_preflight 包含卸載前操作的 Ruby 塊(僅在非常罕見的情況下需要)。
uninstall_postflight 包含卸載後操作的 Ruby 塊。
language required 包含其他段和/或返回值的 Ruby 塊,使用語言代碼參數調用。
container nested 內部容器的相對路徑,必須在繼續安裝之前解壓縮。這允許支持.dmg中的.tar.dmg中的.zip等(例如:blocs.rb)。
容器類型 符號以覆蓋容器類型的自動偵測。可以是以下之一::air, :bz2, :cab, :dmg, :generic_unar, :gzip, :otf, :pkg, :rar, :seven_zip, :sit, :tar, :ttf, :xar, :zip, :naked。(範例:parse.rb
自動更新 true。斷言該 Cask 藝術品會自動更新。當應用程式選單中出現 Check for Updates… 或類似功能時使用,但如果它只是打開一個網頁而不是為您下載和安裝,則不使用。

Stanza 描述

Stanza: app

在簡單情況下,對 app 的字符串參數,源文件將移動到目標 /Applications 目錄。例如

app "Alfred 2.app"

默認將源移動到

/Applications/Alfred 2.app

重命名目標

您可以通過在 app 中添加一個 target: 鍵來重命名出現在您的 /Applications 目錄中的目標。範例(來自:scala-ide.rb

app "eclipse.app", target: "Scala IDE.app"

target 可以包含絕對路徑

如果 target: 有前斜線,則解釋為絕對路徑。如果絕對路徑的包含目錄不存在,則會創建它。範例(來自:sapmachine-jdk.rb

artifact "sapmachine-jdk-#{version}.jdk", target: "/Library/Java/JavaVirtualMachines/sapmachine-jdk-#{version}.jdk"

target 適用於大多數藝術品類型

target: 鍵對大多數 Cask 藝術品類型的操作類似,例如 app, binary, colorpicker, dictionary, font, input_method, internet_plugin, keyboard_layout, prefpane, qlplugin, mdimporter, screen_saver, service, suite, audio_unit_plugin, vst_plugin, vst3_plugin, 和 artifact

target 應僅在特定情況下使用

不要出於美觀考量使用 target:,比如移除版本號(app "Slack #{version}.app", target: "Slack.app")。在功能上有意義時才使用,並在 cask 中清楚地記錄您的原因,使用以下模板之一:為了清晰為了一致性避免衝突基於開發者建議

Stanza: binary

binary 的字串參數簡單情況下,源文件在安裝時連結到 $(brew --prefix)/bin 目錄中。例如(來自 operadriver.rb

binary "operadriver_mac64/operadriver"

建立到的符號鏈結

$(brew --prefix)/bin/operadriver

來源文件,例如

$(brew --caskroom)/operadriver/106.0.5249.119/operadriver_mac64/operadriver

一個(或多個)二進制文件也可以包含在應用程式捆綁包中

app "Atom.app"
binary "#{appdir}/Atom.app/Contents/Resources/app/apm/bin/apm"

您可以通過將 target: 鍵添加到 binary 來重新命名出現在您的二進制文件目錄中的目標

binary "#{appdir}/Atom.app/Contents/Resources/app/atom.sh", target: "atom"

target: 的行為和用法與 app 相同。但是,對於 binary,選擇性情況不那麼嚴格。對於 target: 採取額外靈活性,以與其他命令行工具保持一致,比如 更改大小寫刪除擴展名清理名稱 都是可以的。

Stanza: caveats

有時候,一個軟件的安裝有特殊性,無法或不應該由 Homebrew Cask 自動處理。在這些情況下,caveats 是通知用戶的方式。當使用 installinfo 呼叫 cask 時,caveats 中的信息會顯示出來。

為了避免向用戶發送太多消息(從而使他們對重要消息產生麻木),caveats 應該節省使用,並且僅用於與安裝相關的事項。如果您不確定您找到的 caveat 是否與安裝相關,請向維護者詢問。一般而言,如果您的情況在我們全面的 caveats Mini-DSL 中尚未涵蓋,那麼它不太可能被接受。

作為字符串的 caveats

caveats 是字符串時,它在編譯時被評估。如果 caveats 放在其慣用位置結尾

方法 描述
標記 桶標記
版本 桶版本
homepage 桶首頁
桶路徑 此桶的包含目錄:$(brew --caskroom)/<token>(僅在區塊形式下可用)
暫存路徑 此桶的暫存位置,包括版本號:$(brew --caskroom)/<token>/<version>(僅在區塊形式下可用)

範例

caveats "Using #{token} may be hazardous to your health."

caveats 作為區塊

caveats是Ruby區塊時,評估將延遲至安裝時間。在區塊內,您可以參考@cask實例變數,並調用任何可用於@cask的方法

caveats 迷你DSL

caveats區塊內有一個迷你DSL可用。

以下方法可調用以生成標準警告訊息

方法 描述
path_environment_variable "path" 用戶應確保path位於其PATH環境變量中。
zsh_path_helper "path" zsh用戶必須採取額外步驟確保path位於其PATH環境變量中。
depends_on_java "version" 用戶應確保安裝了指定版本的Java。version可以是精確的(例如6)、最小的(例如7+)或省略的(當任何版本均可使用時)。
requires_rosetta 此桶需要Rosetta 2才能在蘋果矽上運行。
登出 用戶應登出並重新登入以完成安裝。
重新啟動 用戶應重新啟動以完成安裝。
files_in_usr_local 此桶將文件安裝到/usr/local,這可能會讓Homebrew困惑。
kext 用戶可能需要在系統設置 → 隱私與安全(或在較早的macOS版本中是系統偏好設置 → 安全性與隱私 → 通用)中啟用他們的kext。
unsigned_accessibility 用戶將需要在每次更新時重新在系統設置 → 隱私與安全(或在較早的macOS版本中是系統偏好設置 → 安全性與隱私 → 隱私)中重新啟用應用程式,因為它是未簽署的。
許可證 "web_page" 使用者可以在 web_page 找到軟體的使用許可證。
free_license "web_page" 使用者可以在 web_page 取得正式許可證以使用軟體。

範例

caveats do
  path_environment_variable "/usr/texbin"
end

Stanza: deprecate! / disable!

deprecate!disable! 用於宣告一個桶(cask)已不再可用或受支援。包含 deprecate! 段落的桶(cask)仍可安裝,但在安裝或升級時將顯示警告訊息。包含 disable! 段落的桶(cask)將無法安裝或升級,並顯示錯誤訊息。

兩種段落的語法相同

deprecate! date: "YYYY-MM-DD", because: "is ..."
disable! date: "YYYY-MM-DD", because: "is ..."

# Or with a preset reason (see the `because:` argument section below)
deprecate! date: "YYYY-MM-DD", because: :discontinued
disable! date: "YYYY-MM-DD", because: :discontinued

date: 參數

date: 參數控制淘汰或停用的生效時間。具有未來日期的 deprecate! 段落的桶(cask)將不會被視為淘汰,直到該日期。具有未來日期的 disable! 段落的桶(cask)將在該日期之前自動被淘汰,屆時將被停用。

because: 參數

because: 參數接受桶(cask)淘汰或停用的原因。信息訊息將是 <cask> 因為 <reason> 而被淘汰!,因此請格式化原因以符合該句子。例如,because: "is broken" 將導致 <cask> 因為它是壞的而被淘汰!

because: 參數也可以接受與預設原因對應的符號,例如

deprecate! date: "YYYY-MM-DD", because: :discontinued

完整的允許符號列表可在DeprecateDisable 模組中找到。

Stanza: conflicts_with

conflicts_with 用於宣告衝突,使得桶(cask)無法正確安裝或運作。

conflicts_with cask

值應該是另一個桶(cask)標記。

例如:macFUSE 桶(cask),與 macfuse-dev 衝突。

conflicts_with cask: "macfuse-dev"

conflicts_with formula

注意: conflicts_with formula: 為一個存根,尚未功能正常。

該值應為另一個公式名稱。

例如:MacVim,它與 macvim 公式衝突。

conflicts_with formula: "macvim"

Stanza: depends_on

depends_on 用於聲明 cask 的依賴和需求。只有在嘗試 install 時才會使用 depends_on

depends_on cask

該值應為另一個 cask token,被當前 cask 需要。

例如:NTFSTool,它依賴於 macFUSE。

depends_on cask: "macfuse"

depends_on formula

該值應該是 cask 需要的 Homebrew 公式名稱。

例如:某些發行版包含在像 7z 這樣的存檔格式中,這些格式不受 Apple 原始工具支持。對於這些情況,可以通過聲明對 unar 公式的依賴來在安裝時引入更強大的存檔閱讀器。

depends_on formula: "unar"

depends_on macos

需要確切的 macOS 版本

depends_on macos: 的值可以是一個符號或一個符號的數組,列出精確兼容的 macOS 發行版本。macOS 發行版本的可用值在 MacOSVersion 類 中定義。

只涵蓋主要發行版本(包含單個點或自 macOS 11 起的整數 10.x 數字)。符號形式用於可讀性。以下是列舉 cask 的確切 macOS 版本要求的所有有效方式

depends_on macos: :big_sur
depends_on macos: [
  :catalina,
  :big_sur,
]
設置最低 macOS 版本

depends_on macos: 也可以接受以比較運算符開頭的字符串,例如 >=,後跟上面形式的 macOS 發行版本。以下是一個有效表達式,意思是“至少 macOS Big Sur (11.0)”

depends_on macos: ">= :big_sur"

比較表達式不能與任何其他形式的 depends_on macos: 結合使用。

depends_on arch

depends_on arch: 的值可以是一個符號或一個符號的數組,列出 cask 的硬件兼容性要求。如果任何一個 arch: 值與用戶的硬件匹配,則在安裝時滿足該要求。

硬體可用符號為:

符號 意義
:x86_64 64 位元 Intel
:intel 64 位元 Intel
:arm64 蘋果矽

以下是所有有效的表示式

depends_on arch: :intel
depends_on arch: :x86_64            # same meaning as above
depends_on arch: [:x86_64]          # same meaning as above
depends_on arch: :arm64

depends_on 參數

描述
公式 Homebrew 公式
cask cask 標記
macOS 符號、陣列或字串比較表達式,定義 macOS 版本要求
arch 定義硬體要求的符號或陣列
java 桩 - 尚未功能化

Stanza: desc

desc 接受包含軟體簡短描述的單行 UTF-8 字串。它用於幫助搜索和消歧義,因此必須簡潔地描述軟體的功能(或您可以用它做些什麼)。

desc 不是用於應用程序口號!供應商的描述往往充滿了像“現代”和“輕量級”這樣的通用形容詞。這些都是毫無意義的行銷花招(你有見過應用程序自豪地描述自己為過時和笨重嗎?),必須刪除。在幾乎所有情況下,使用軟體網站上的信息作為起點都沒問題,但它需要進行編輯。

要做和不要做

Stanza: *flight

stanzas preflightpostflightuninstall_preflightuninstall_postflight 定義要在安裝或卸載之前或之後運行的操作。

區塊的評估始終被推遲

這些 stanza 定義的 Ruby 區塊在安裝或卸載時才被評估。在區塊中,您可以參考 @cask 實例變數,並調用 @cask 上可用的任何方法

*flight 迷你 DSL

這些區塊內部提供了一個迷你 DSL。

以下方法可用於執行標準任務

方法 可用性 描述
set_ownership(paths) preflightpostflightuninstall_preflight 設置paths的使用者和群組擁有權。(例如:docker-toolbox.rb
set_permissions(paths, permissions_str) preflightpostflightuninstall_preflight paths中的權限設置為permissions_str。(例如:ngrok.rb

set_ownership(paths)預設使用者擁有權為當前使用者,群組擁有權為staff。這些可以通過傳遞額外選項進行更改:set_ownership(paths, user: "user", group: "group")。(例如:hummingbird.rb

Stanza: installer

這個段必須始終與uninstall一起使用。

installer段落接受一系列鍵值對,其中第一個鍵必須是manual:script:

installer manual

installer manual: 接受單個字符串值,描述了一個GUI安裝程式,必須由使用者在以後的某個時間運行。路徑可以是絕對的,也可以是相對於cask的。例如(來自rubymotion.rb

installer manual: "RubyMotion Installer.app"

installer script

installer script: 介紹了一系列描述將自動完成安裝的命令的鍵值對。 它不應用於互動式安裝。形式與uninstall script:類似

executable 要運行的安裝腳本的路徑
args 安裝腳本的參數數組
input 要發送到腳本的stdin的輸入行數組
must_succeed 如果允許腳本失敗,則設置為false
sudo 如果腳本需要sudo,則設置為true

路徑可以是絕對的,也可以是相對於cask的。例如(來自miniforge.rb

installer script: {
  executable: "Miniforge3-#{version}-MacOSX-x86_64.sh",
  args:       ["-b", "-p", "#{caskroom_path}/base"],
}

如果安裝腳本:installer script: 不需要任何鍵值,它可以直接指向安裝腳本的路徑。

installer script: "#{staged_path}/install.sh"

Stanza: language

language 段落可以匹配ISO 639-1 語言代碼,腳本代碼(ISO 15924)和地區標識符(ISO 3166-1 Alpha 2),或其組合。

美式英語應該始終作為默認語言使用。

language "zh", "CN" do
  "zh_CN"
end

language "de" do
  "de_DE"
end

language "en-GB" do
  "en_GB"
end

language "en", default: true do
  "en_US"
end

請注意以下兩者並不相同。

language "en", "GB" do
  # matches all locales containing "en" or "GB"
end

language "en-GB" do
  # matches only locales containing "en" and "GB"
end

匹配的 language 塊的返回值可以通過簡單調用 language 來訪問。

homepage "https://example.org/#{language}"

例子:firefox.rbbattle-net.rb

安裝

要在特定語言中安裝一個 cask,您可以將 --language= 選項傳遞給 brew install

brew install firefox --language=it

Stanza: livecheck

livecheck 段落用於從變更日誌、發布說明、應用程式傳播等自動獲取 cask 的最新版本。

每個 livecheck 塊必須包含一個 url,它可以是一個指向 cask 中其他 URL 的字符串或符號(:url:homepage)。

請參閱brew livecheck 文檔以了解如何編寫 livecheck 塊。

Stanza: name

name 接受一個 UTF-8 字符串,用於定義軟件的名稱,包括大寫和標點符號。它用於幫助搜索和消歧義。

與簡化並縮小到一組有限字符的token不同,name節可以包括正確的大寫、間距和標點,以匹配軟件的官方名稱。為了消除歧義,建議拼寫應用程序的名稱,必要時包括供應商名稱。一個好的例子是pycharm-ce cask,其名稱被拼寫為Jetbrains PyCharm Community Edition,儘管它很可能在任何地方都不會被引用為這樣。

有關軟件的其他詳細信息可以在desc中提供。

如果有有用的替代名稱,name節可以多次重複。第一個實例應使用拉丁字母。例如,請參閱cave-story cask,其原始名稱不使用拉丁字母。

Stanza: pkg

這個段必須始終與uninstall一起使用。

pkg節的第一個參數應該是要安裝的.pkg文件的相對路徑。例如:

pkg "Unity.pkg"

pkg的後續參數是修改安裝過程的鍵/值對。目前支持的鍵是allow_untrusted:choices:

pkg allow_untrusted

pkg allow_untrusted: true可以用來安裝包含不受信任證書的.pkg,通過將-allowUntrusted傳遞給/usr/sbin/installer

此選項不允許在官方Homebrew Cask taps中使用;它僅提供給第三方taps或本地casks使用。

歷史示例(來自alinof-timer.rb

pkg "AlinofTimer.pkg", allow_untrusted: true

pkg choices

pkg 選項: 可以通過 -applyChoiceChangesXML 覆蓋 .pkg 的默認安裝選項。它使用 choiceChanges 屬性列表的反序列化版本(參見運行 man -P 'less --pattern "^CHOICE CHANGES FILE"' installer 查看 installer 手冊頁面的 CHOICE CHANGES FILE 部分)。

運行這個 macOS installer 命令

installer -showChoicesXML -pkg '/path/to/my.pkg'

將輸出 XML,您可以用來提取 choices: 的值,以及它們對應的 GUI 選項。

查看 這個 pull request 有關 wireshark-chmodbpf 的這個 pull request 有關 wine-staging 的 一些例子。

例子(來自 lando.rb

pkg "LandoInstaller.pkg",
    choices: [
      {
        "choiceIdentifier" => "choiceDocker",
        "choiceAttribute"  => "selected",
        "attributeSetting" => 0,
      },
      {
        "choiceIdentifier" => "choiceLando",
        "choiceAttribute"  => "selected",
        "attributeSetting" => 1,
      },
    ]

例子(來自 microsoft-office.rb

pkg "Microsoft_365_and_Office_#{version}_Installer.pkg",
    choices: [
      {
        "choiceIdentifier" => "com.microsoft.autoupdate", # Office16_all_autoupdate.pkg
        "choiceAttribute"  => "selected",
        "attributeSetting" => 0,
      },
    ]

Stanza: sha256

計算 SHA-256

sha256 值通常是通過 shasum 命令計算的

shasum --algorithm 256 <file>

特殊值 :no_check

特殊值 sha256 :no_check 用於在由於上游配置而不可行時關閉 SHA 檢查時的校驗。

version :latest 需要 sha256 :no_check,這種配對是常見的。但是,sha256 :no_check 不需要 version :latest

我們會在可能的情況下使用校驗。

Stanza: suite

一些發行版提供了一套多個應用程序或應用程序與必需數據,要一起安裝在 /Applications 的子目錄中。

對於這些 Cask,使用 suite 段來定義包含應用程序套件的目錄。示例(來自 racket.rb

suite "Racket v#{version}"

suite 的值從不是一個 .app 捆,而是一個普通目錄。

Stanza: uninstall

如果您無法設計一個有效的uninstall段落,請無論如何提交您的桶。管理者可以幫助您編寫一個uninstall段落,只要問一下!

uninstall pkgutil: 是最簡單和最有用的

最簡單和最有用的uninstall指示是pkgutil:。它應該涵蓋大多數使用情況。

uninstall是安裝使用pkginstaller manual:的桶所必需的

對於大多數桶來說,卸載操作會自動確定,並且不需要明確的uninstall段落。然而,使用pkginstaller manual:段落的桶將無法正確卸載,除非給定uninstall段落。

因此,雖然cask DSL不強制執行此要求,但如果每個pkginstaller manual:都有對應的uninstall,對用戶來說會更好。

uninstall段落適用於非pkg桶,並且對一些特殊情況非常有用。然而,下面的文檔涉及使用uninstall來定義pkg的程序的典型情況。

有多種卸載技術

由於pkg安裝程式可以執行任意操作,因此需要根據每種情況採取不同的技術進行卸載。您可能需要指定一個或多個以下鍵/值對作為uninstall的參數。

鍵的摘要

每个uninstall技术都根据上述顺序应用。忽略在 Cask 文件中出现的uninstall键的顺序。

在填寫 uninstall 鍵的正確值時,可以在 Homebrew Cask 存儲庫的 developer/bin 下找到幾個輔助腳本。每個腳本都會對 -help 選項做出回應,提供額外的文檔。

在目前已安裝並運行該軟件包的系統上進行 uninstall stanza 的工作最簡單。要操作未安裝的 .pkg 文件,請參閱下面的 手動處理 .pkg 文件

uninstall pkgutil

這是最有用的卸載鍵。 pkgutil: 往往足以完全卸載一個 pkg,強烈建議使用它,而不是 delete:

可以使用 list_recent_pkg_ids 列出最近安裝的包的 ID。

"$(brew --repository homebrew/cask)/developer/bin/list_recent_pkg_ids"

pkgutil: 還可以接受對多個包 ID 的正則表達式匹配。這些正則表達式有些非標準。要測試 pkgutil: 正則表達式是否與當前安裝的包匹配,請使用 list_pkg_ids_by_regexp

"$(brew --repository homebrew/cask)/developer/bin/list_pkg_ids_by_regexp" <regular-expression>

列出與包 ID 相關聯的文件

一旦知道已安裝的包的 ID(見上文),就可以使用 macOS 的 pkgutil 命令列出與該包 ID 相關的系統上的所有文件。

pkgutil --files <package.id.goes.here>

列出相關的文件可以幫助您評估該軟件包是否包含任何 launchd 任務或內核擴展(kexts)。

uninstall launchctl

可以使用 list_loaded_launchjob_ids 列出當前加載的 launchd 任務的 ID。

"$(brew --repository homebrew/cask)/developer/bin/list_loaded_launchjob_ids"

可以使用 list_installed_launchjob_ids 列出所有已安裝的 launchd 任務的 ID。

"$(brew --repository homebrew/cask)/developer/bin/list_installed_launchjob_ids"

uninstall quit

目前正在運行應用程式的 Bundle IDs 可以使用 list_running_app_ids 列出

"$(brew --repository homebrew/cask)/developer/bin/list_running_app_ids"

磁碟中應用程式束內的 Bundle IDs 可以使用 list_ids_in_app 列出

"$(brew --repository homebrew/cask)/developer/bin/list_ids_in_app" '/path/to/application.app'

uninstall signal

signal: 應該只在一個進程不響應 quit: 的極少數情況下需要。

針對 signal: 目標的 Bundle IDs 可以通過與 quit: 相同的方式獲取。 signal: 的值是一個二維陣列,每個儲存格包含兩個元素:期望的 Unix 信號,後跟相應的 Bundle ID。

Unix 信號可以以數字或字符串形式給出(詳見 kill(1) 手冊頁面)。

signal: 陣列的元素將按順序應用,僅當存在與 Bundle ID 相關聯的進程時,並在該進程終止時停止。可以重複使用 Bundle ID 以向同一個進程發送多個信號。

最好使用足以停止進程的最輕微的信號。特別是 KILL 信號可能會產生意外的副作用。

一個常見的示例,按嚴重性升序排列的常用信號

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"],
]

請注意,當多個運行中的進程匹配給定的 Bundle ID 時,將向所有匹配的進程發送信號。

quit: 指令不同,Unix 信號源自當前用戶,而不是超級用戶。這被解釋為一個安全功能,因為超級用戶可以通過信號關閉系統。然而,這種不一致性也可能被認為是一個錯誤,應該在將來的版本中以某種方式解決。

uninstall login_item

與磁碟中應用程式束關聯的登錄項可以使用 list_login_items_for_app 列出

"$(brew --repository homebrew/cask)/developer/bin/list_login_items_for_app" '/path/to/application.app'

請注意,您可能需要至少打開應用程式一次才能出現任何登錄項。

uninstall kext

目前加載的內核擴展的識別碼可以使用list_loaded_kext_ids列出。

"$(brew --repository homebrew/cask)/developer/bin/list_loaded_kext_ids"

磁碟上的 kext 捆綁包內的識別碼可以使用list_id_in_kext列出。

"$(brew --repository homebrew/cask)/developer/bin/list_id_in_kext" '/path/to/name.kext'

uninstall 腳本

uninstall 腳本:介紹了一系列描述將自動完成卸載的命令的鍵值對。例如(來自virtualbox.rb

uninstall script:  {
            executable: "VirtualBox_Uninstall.tool",
            args:       ["--unattended"],
            sudo:       true,
          },
          pkgutil: "org.virtualbox.pkg.*",
          delete:  "/usr/local/bin/vboximg-mount"

值得注意的是,儘管上面的例子中的script:嘗試完全卸載pkg,但不應該將其用於取代pkgutil:,而應該在可能時作為補充。

uninstall 刪除

delete:只應在其他uninstall方法不足時使用。

uninstall delete:的參數應遵循以下基本規則

要刪除特定用戶文件,請使用zap 段落

uninstall 垃圾桶

trash:的參數遵循上面列出的delete:的規則。

手動處理 .pkg 檔案

高級用戶可能希望在不安裝包的情況下手動處理.pkg文件。

可以使用list_payload_in_pkg提取可能從.pkg安裝的文件列表。

"$(brew --repository homebrew/cask)/developer/bin/list_payload_in_pkg" '/path/to/my.pkg'

用於確定桶名稱的候選申請名稱可能從一個 .pkg 文件中提取,使用 list_apps_in_pkg

"$(brew --repository homebrew/cask)/developer/bin/list_apps_in_pkg" '/path/to/my.pkg'

可能有用於 pkgutil: 關鍵的候選套件 ID 可以從一個 .pkg 文件中提取,使用 list_ids_in_pkg

"$(brew --repository homebrew/cask)/developer/bin/list_ids_in_pkg" '/path/to/my.pkg'

一種完全手動的方法用於找到包文件中的 bundle ID

  1. 解開 /path/to/my.pkg(用您的套件名稱替換)使用 pkgutil --expand /path/to/my.pkg /tmp/expanded.unpkg
  2. 解開的套件是一個文件夾。Bundle ID 包含在名為 PackageInfo 的文件中。這些文件可以用命令找到 find /tmp/expanded.unpkg -name PackageInfo
  3. PackageInfo 文件是 XML 文件,bundle ID 位於看起來像 <pkg-info ... identifier="com.oracle.jdk7u51" ... ><pkg-info> 標籤的 identifier 屬性內,其中多餘的屬性已被剪切並用省略號替換。
  4. 套件文件中還描述了包中的 Kext。如果有任何核心擴展存在,命令 find /tmp/expanded.unpkg -name PackageInfo -print0 | xargs -0 grep -i kext 應返回一個包含 .kext 擴展名的 path 屬性的 <bundle id> 標籤,例如 <bundle id="com.wavtap.driver.WavTap" ... path="./WavTap.kext" ... />
  5. 一旦識別出 bundle ID,解開的套件目錄可以刪除。

Stanza: url

優先使用 HTTPS URL

如果有可用的,優先使用 HTTPS URL。僅在沒有安全替代方案的情況下才應使用普通的 HTTP URL。

其他 url 參數

當一個普通的 URL 字符串不足以獲取文件時,可以提供其他信息給基於 curl 的下載器,以鍵/值對的形式附加到 url

已驗證 字串重複 url 開頭,用於 驗證目的
使用 符號 :post:homebrew_curl 是唯一合法的值
cookies 在下載請求中設定的 cookie 雜湊(示例:oracle-jdk-javadoc.rb
referer 持有要在下載請求中設定為參考的 URL 的字串(示例:firealpaca.rb
header 要為下載請求設定的標頭的字串或字串陣列(示例:pull-6545issue-15590
user_agent 要為下載請求設定的使用者代理的字串。也可以設定為符號 :fake,這將使用通用的瀏覽器樣式的使用者代理字串。當伺服器不要求特定的使用者代理時,我們更傾向於使用 :fake
data 要在 POST 請求中設定的參數雜湊(示例:segger-jlink.rb

當 URL 和主頁域名不同時,添加 verified:

urlhomepage 的域名不同時,應該使用 verified: 參數來記錄差異,重複可能最小的能夠唯一識別應用程式或供應商的 URL 部分,不包括協議。(示例:shotcut.rb

這必須添加以便正在審核 cask 的使用者知道該 URL 已由 Homebrew Cask 團隊驗證為供應商提供的 URL,即使它看起來可能不是官方的。當首次添加(或隨後修改,除了版本號)時,我們作為 Homebrew Cask 維護者負責驗證 urlhomepage 資訊。

該參數並不意味著您應該盲目信任來源,而是我們僅批准使用者可以輕易驗證其真實性的桶,例如檢查官方主頁或公共存儲庫。偶爾可能需要使用稍微複雜的技術,例如檢查我們確立為官方的 livecheck URL。當無法進行此類快速驗證時(例如下載 URL 被註冊牆隔絕),將以更嚴格的方式處理,詳情請參閱非官方、無供應商和註冊牆構建

尋找 URL 的困難

網頁瀏覽器可能因各種原因而遮蔽直接的 url 下載位置。Homebrew Cask 提供了一個 list_url_attributes_on_file 腳本,可以讀取擴展文件屬性以提取 macOS 上由瀏覽器下載的大多數文件的實際來源 URL。該腳本通常會生成多個候選 URL;您可能需要測試每一個

$(brew --repository homebrew/cask)/developer/bin/list_url_attributes_on_file <file>

Subversion URL

在罕見情況下,分發可能無法通過普通的 HTTP/S 獲得。Subversion URL 也受支持,可以通過將以下鍵/值對附加到 url 來指定

使用 符號 :svn 是唯一合法的值
revision 標識要下載的 Subversion 版本的字符串
trust_cert 設置為 true 以自動信任服務器提供的證書(避免交互式提示)

Git URL

藝術品也可以通過 Git 存儲庫分發。以 .git 結尾的 URL 將自動假定為 Git 存儲庫,並且以下鍵/值對可以附加到 url

使用 符號 :git 是唯一合法的值
tag 標識要下載的 Git 標籤的字符串
revision 標識要下載的 Git 版本的字符串
分支 識別 Git 分支以進行下載的字串
only_path 限制檢查的存儲庫內路徑。如果僅需要大型存儲庫中的單個目錄,使用此選項可以顯著加快下載速度。如果提供了此選項,則存儲的路徑相對於此路徑。(示例:font-geo.rb

SourceForge/OSDN 網址

SourceForge 和 OSDN(前身為 SourceForge.JP) 項目是分發二進制文件的常見方式,但它們提供許多不同風格的網址來獲取商品。

我們偏好這種格式的網址

https://downloads.sourceforge.net/<project_name>/<filename>.<ext>

或者,如果來自 OSDN,其中 <subdomain> 通常是形如 dl<user>.dl 的形式

http://<subdomain>.osdn.jp/<project_name>/<release_id>/<filename>.<ext>

如果這些格式不可用,且應用程序僅限於 macOS(否則命令行下載將默認為 Windows 版本),我們偏好使用此格式

https://sourceforge.net/projects/<project_name>/files/latest/download

某些提供商阻止命令行下載

某些托管提供商積極阻止命令行 HTTP 客戶端。這些網址不能用於 Casks。

其他提供商可能使用定期更改的網址,甚至每次訪問時都會更改(例如:FossHub)。雖然某些情況可以 繞過,但它們往往發生在供應商積極嘗試阻止自動下載時,因此我們偏好不將這些 Casks 添加到主存儲庫中。

使用區塊延遲代碼執行

一些 Casks —— 特別是每晚版本 —— 具有版本化的下載網址,但由於更新頻繁,使其保持最新的方式變得不切實際。對於這些情況,我們希望動態確定 url

問題

理論上,可以在 Cask 定義中寫入任意的 Ruby 代碼來獲取並構建一個一次性的 URL。

然而,這通常涉及到向登陸站點發送 HTTP 請求,這可能需要很長時間。由於 Homebrew Cask 加載和解析 Casks 的方式,不可接受在 Cask 定義的主體中直接執行這樣昂貴的操作。

編寫區塊

preflightpostflightuninstall_preflightuninstall_postflight 區塊類似,url 段落提供了一個可選的 區塊語法

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
end

您還可以將 url do 區塊嵌套在另一個 url do 區塊內,以跟蹤一系列 URL。

該區塊僅在需要時進行評估,例如在下載時或對 cask 進行審計時。在區塊內,您可以安全地執行諸如可能需要很長時間才能執行的 HTTP/S 請求等操作。您還可以參考 @cask 實例變數,並調用 @cask 上可用的任何方法

該區塊將在立即下載之前調用;其結果值將被假定為一個 String(或包含參數的一對 StringHash),並隨後用作下載 URL。

您可以使用 url 段落,要么是直接參數,要么是區塊,但不能兩者都使用。

使用區塊語法的示例:vlc@nightly.rb

混合附加的 URL 參數與區塊語法

在罕見情況下,您可能需要設置像 cookiesreferer 之類的 URL 參數,同時也使用區塊語法。

這可以通過將區塊結果返回為一個具有兩個元素的數組來實現。數組的第一個元素必須是下載 URL;第二個元素必須是包含參數的 Hash

Stanza: version

version,雖與應用程序自身的版本相關,但不一定要完全遵循它。通常會稍微更改它,以便在其他段落中進行 插值,通常在 url 中創建一個只需要在更新時更改 versionsha256 的 cask。在需要時,可以進一步使用 Ruby 字符串方法

例如,不使用

version "1.2.3"
url "https://example.com/file-version-123.dmg"

可以使用

version "1.2.3"
url "https://example.com/file-version-#{version.delete(".")}.dmg"

我們也可以利用正則表達式的威力。所以不是使用

version "1.2.3build4"
url "https://example.com/1.2.3/file-version-1.2.3build4.dmg"

可以使用

version "1.2.3build4"
url "https://example.com/#{version.sub(/build\d+/, "")}/file-version-#{version}.dmg"

版本 方法

然而,以上的例子可能變得難以閱讀。由於許多這些更改是常見的,我們提供了一些輔助工具,以清晰地解釋否則晦澀的情況

方法 input 輸出
主要 1.2.3-a45,ccdd88 1
次要 1.2.3-a45,ccdd88 2
修補 1.2.3-a45,ccdd88 3-a45
主要次要 1.2.3-a45,ccdd88 1.2
主要次要修補 1.2.3-a45,ccdd88 1.2.3-a45
次要修補 1.2.3-a45,ccdd88 2.3-a45
逗號前 1.2.3-a45,ccdd88 1.2.3-a45
逗號後 1.2.3-a45,ccdd88 ccdd88
點轉連字符 1.2.3-a45,ccdd88 1-2-3-a45,ccdd88
無點 1.2.3-a45,ccdd88 123-a45,ccdd88

點轉連字符 類似,我們提供所有邏輯排列的方法 {點、連字符、底線}_to_{點、連字符、底線}。對於 無點 也是一樣,形式為 no_{點、連字符、底線},加上額外的 no_dividers 一次應用所有這些。

最後,有一個 csv,它返回一個逗號分隔值的陣列。 csv逗號前逗號後 是特別的,允許處理否則復雜的情況,應該節約使用。每個 版本 最多不應該有兩個 ,

版本 :latest

特殊值 :latest 用於當

Stanza: zap

zap 目的

zap 段落描述了與 cask 相關的文件的更完整的卸載。 zap 程序不會默認執行,只有在用戶在 uninstall 上使用 --zap 時才執行

brew uninstall --zap firefox

zap stanza可能會移除

zap stanza不應該移除

在命令中添加--force將允許您執行這些操作,即使該cask已不再安裝

brew uninstall --zap --force firefox

zap語法

zap stanza的形式遵循uninstall stanza。所有相同的指令都是可用的。 trash:鍵優先於delete:

示例:dropbox.rb

zap的創建

最簡單的方法是使用@nrlquaker的CreateZap,它可以自動生成stanza。在某些情況下,它可能無法檢測到任何內容,需要手動創建。

手動創建可以借助

如果未發現其他文件,則在zap stanza之外,包含以下註釋

# No zap stanza required

條件陳述

處理不同的系統配置

根據當前的macOS版本或CPU架構,cask可以提供特定版本的產物,方法是通過調整URL / SHA-256哈希 / 版本,使用on_<system>語法(它取代了使用MacOS.versionHardware::CPU的條件語句),或兩者兼用。

如果您的桶的藝術品以單獨的下載方式提供給 Intel 和 Apple Silicon 架構,它們可能會在稍有不同的 URL 上提供下載。根據當前的 CPU 架構調整 URL,為每個架構提供一個散列給 sha256arm:intel: 參數,並使用特殊的 arch 段落來定義相應 URL 的唯一組件,以便在 url 中進行替換。其他替換可以通過直接調用 on_arch_conditional 來定義。示例(來自 libreoffice.rb

cask "libreoffice" do
  arch arm: "aarch64", intel: "x86-64"
  folder = on_arch_conditional arm: "aarch64", intel: "x86_64"

  version "7.6.0"
  sha256 arm:   "81eab945a33622fc156951e804024d23aa9a745c06743b4947215ed9303ad1c4",
         intel: "ede541af151487f60eb518e310d20dad1a973f3dbe9ff78d782dd29b14ba2946"

  url "https://download.documentfoundation.org/libreoffice/stable/#{version}/mac/#{folder}/LibreOffice_#{version}_MacOS_#{arch}.dmg",
      verified: "download.documentfoundation.org/libreoffice/stable/"
end

如果每個架構的版本號不同,則在 on_armon_intel 塊內定位獨特的 version 和(如果檢查過) sha256 段落。示例(來自 inkscape.rb

cask "inkscape" do
  arch arm: "arm64", intel: "x86_64"

  on_arm do
    version "1.3.0,42339"
    sha256 "e37b5f8b8995a0ecc41ca7fcae90d79bcd652b7a25d2f6e52c4e2e79aef7fec1"
  end
  on_intel do
    version "1.3.0,42338"
    sha256 "e97de6804d8811dd2f1bc45d709d87fb6fe45963aae710c24a4ed655ecd8eb8a"
  end

  url "https://inkscape.org/gallery/item/#{version.csv.second}/Inkscape-#{version.csv.first}_#{arch}.dmg"
end

根據當前的 macOS 版本調整安裝版本,使用一系列涵蓋支援版本範圍的 on_<system> 塊。每個塊都可以包含設置要下載的版本和自定義安裝/卸載以及用於一個或多個版本的實時檢查行為的段落。示例(來自 calibre.rb

cask "calibre" do
  on_high_sierra :or_older do
    version "3.48.0"
    sha256 "68829cd902b8e0b2b7d5cf7be132df37bcc274a1e5720b4605d2dd95f3a29168"

    livecheck do
      skip "Legacy version"
    end
  end
  on_mojave do
    # ...
  end
  on_catalina do
    # ...
  end
  on_big_sur :or_newer do
    version "6.25.0"
    sha256 "a7ed19ae0526630ccb138b9afee6dc5169904180b02f7a3089e78d3e0022753b"

    livecheck do
      url "https://github.com/kovidgoyal/calibre"
      strategy :github_latest
    end
  end
end

這樣的 on_<system> 塊可以嵌套並包含這裡未列出的其他段落。示例:calhash.rb, openzfs.rb, r.rb, wireshark.rb

切換語言或地區

如果一個桶可用於多種語言,您可以使用language 段落基於系統區域設置語言或地區。

任意的 Ruby 方法

在特殊情況下,如果桶 DSL 不足以應付,可以通過創建 Utils 命名空間在桶內定義任意的 Ruby 變量和方法。示例

cask "myapp" do
  module Utils
    def self.arbitrary_method
      # ...
    end
  end

  version "1.0"
  sha256 "a32565cdb1673f4071593d4cc9e1c26bc884218b62fef8abc450daa47ba8fa92"

  url "https://#{Utils.arbitrary_method}"
  name "MyApp"
  homepage "https://www.example.com/"
  # ...
end

這應該節制使用:任何被兩個或更多桶需要的方法應該被合併到 Homebrew/brew 中。還必須注意,這樣的方法必須非常高效。

變量和方法不應該在 Utils 命名空間外定義,因為它們可能與 Homebrew Cask 內部產生衝突。

標記參考

本節描述了在 generate_cask_token 腳本中實現的算法,並涵蓋了大多數情況下不需要的詳細規則和例外情況。

目的

軟體供應商通常在命名上不一致。通過強制執行嚴格的命名慣例,我們旨在

軟體名稱和品牌的詳細信息在轉換為最小令牌時不可避免地會丟失。要捕獲發行的供應商的完整名稱,請在 cask 中使用 namename 接受無限制的 UTF-8 字符串。

找到供應商發布的簡化名稱

應用程式的簡化名稱

轉換為ASCII

pkg 安裝程式的簡化名稱

非應用程式軟體的簡化名稱

將簡化名稱轉換為標記

令牌是該項目中包裝的主要識別符。這是用戶在操作 cask 時引用的唯一字符串。

將應用程式的簡化名稱(如上所述)轉換為令牌

固定到特定版本的 Casks

固定應用程式的特定版本(例如carbon-copy-cloner@5)的桶應使用與標準桶相同的令牌,後綴為@<version-number。例如,對於Carbon Copy Cloner(carbon-copy-cloner)固定到版本5,令牌應為carbon-copy-cloner@5

固定到開發頻道的 Casks

使用開發“渠道”的桶,例如測試版,應使用與標準桶相同的令牌,後綴為@<channel>。例如,對於Google Chrome(google-chrome)使用“beta”渠道,令牌應為google-chrome@beta

Cask 檔名

桶存儲在以令牌命名的Ruby文件中,文件擴展名為.rb

Cask 標頭

每個桶的標題行中還會給出令牌。

Cask 標記範例

這些說明了生成令牌的大部分規則。

磁碟上的應用程式名稱 簡化應用程式名稱 桶令牌 檔名
Audio Hijack Pro.app Audio Hijack Pro audio-hijack-pro audio-hijack-pro.rb
VLC.app VLC vlc vlc.rb
BetterTouchTool.app BetterTouchTool bettertouchtool bettertouchtool.rb
LPK25 Editor.app LPK25 Editor lpk25-editor lpk25-editor.rb
Sublime Text 2.app Sublime Text sublime-text sublime-text.rb

對於帶版本/開發渠道的桶

標準桶令牌 衍生 桶令牌 檔名
google-chrome 測試版渠道 google-chrome@beta google-chrome@beta.rb
vlc 夜間版渠道 vlc@nightly vlc@nightly.rb
carbon-copy-cloner 固定到版本5 carbon-copy-cloner@5 carbon-copy-cloner@5.rb

特定桶令牌示例

桶水龍頭具有特定於每個水龍頭的命名慣例。

特殊詞綴

一些情況需要在令牌中添加前綴或後綴。

令牌重疊

當新桶的令牌與已存在桶的令牌衝突時,重疊的性質決定了令牌,可能適用於兩個桶。請參閱分支和具有衝突名稱的應用程式以了解如何繼續。

潛在誤導的名稱

如果一個未經授權的軟體與一個熱門服務互動,其令牌會使其看起來像官方軟體,而供應商未經授權使用該名稱,必須添加前綴以消歧義

在前綴不明確並且會使應用程式顯示為官方的情況下,可以使用-unofficial後綴。

Fork me on GitHub