Package Manager 抽象層
Package manager 抽象層是 dotfile 跨發行版可攜的關鍵切分:一份 dotfile repo 裡,真正綁特定發行版的只有「用哪個 package manager 裝套件」這一層,其餘(config 檔內容、symlink 部署、shell 框架安裝)都是跨 distro 共通的。把這一層隔離出來,同一份 repo 就能同時服務 Arch 工作站、Debian 容器與 macOS。這層抽象是 發行版打包粒度 差異的因應之道。
概念位置
這個抽象讓 GNU Stow 管的 config 層完全可攜。實作見 工作站 dotfile 跨發行版落地 與 dotfile 跨進 runtime container。
綁 distro 的只有裝套件那一步
各發行版的差異集中在 package manager 的指令與套件名:
1Arch pacman -S --needed --noconfirm <pkg>
2Debian/Ubuntu apt-get install -y --no-install-recommends <pkg>
3macOS brew install <pkg>
4Alpine apk add --no-cache <pkg>除了這一步,其餘幾乎都可攜:.zshrc 的內容、stow 建 symlink 的方式、oh-my-zsh 的 git clone、config 檔本身——這些不管在哪個 distro 都一樣。所以跨 distro 的正解不是維護多份 dotfile,是維護一份 config + 一個依 package manager 分支的安裝層。
Detection 分支的兩種形態
抽象這一層有兩種常見寫法,差別在分支放哪:
- 入口 detection:安裝腳本開頭偵測 package manager,dispatch 到對應的
install-<platform>.sh,套件清單各平台一份(packages/arch-*.txt、packages/debian-*.txt)。適合工作站,因為各平台的套件集差異大。 - 行內 detection:一支腳本內用
command -v apt-get / pacman / apk分支,共用同一份套件名。適合容器內的輕量 ergonomics 安裝——只裝少數幾個工具、不值得拆多檔。
判讀訊號:什麼進分支、什麼是共通層
判準是「這一項換 distro 會不會變」:會變的(套件名、安裝指令)進 detection 分支;不會變的(config 內容、symlink 邏輯、框架 clone)留共通層。一個常見的誤置是把套件名寫死在共通層,結果換 distro 就壞——正確做法是共通層只呼叫抽象後的安裝函式,具體套件名下沉到各平台清單。
套件名分歧的常見形態
「換 package manager」不只是換指令前綴,套件名本身在不同 distro 有好幾種分歧,各要不同處理:
- 同工具不同套件名:Arch 的
fd在 Debian 叫fd-find、github-cli在 Debian 叫gh。要靠各平台清單逐項對照,不能假設同名。 - binary 名被改:Debian 為了讓整個 archive 的
/usr/bin名字全域唯一,會在上游 binary 名跟現有套件撞名時改名——fd-find裝出來的 binary 是fdfind、bat是batcat。所以「套件裝好了」不等於「指令叫得動」,.zshrc的 alias 要按平台補(Debian 上alias fd=fdfind)。 - 名字撞到別的工具:
apt install delta裝到的是一個 heuristic minimizer、不是.gitconfig指的那個 diff pager(那個叫 git-delta、且 bookworm 沒打包)。同名不同物,照抄會裝錯東西。 - 套件被拆分或合併:同一個上游工具在 Debian 常被拆成
foo+foo-dev+foo-common(照抄單一名字會漏裝-dev、編不起來),或反過來多個工具併進一個 meta-package(如build-essential)。安裝顆粒度跟 Arch 不對齊,要看該 distro 怎麼切。
除了名字,同名套件的版本也常分歧:Debian stable 凍結的版本往往比 Arch 舊一個世代,名字一樣、行為卻不同——這不是名字問題,但一樣影響對齊,見 發行版打包粒度。
邊界
當某工具在目標 distro 根本沒打包時,抽象層也擋不住——退回手動安裝或換等價工具。哪些工具在保守發行版容易缺席,見 發行版打包粒度;為什麼清單裡一個爛名字會拖垮整批安裝,見 apt 安裝的交易原子性。