homebrew 安裝 formula 的不同歷史版本——以安裝 node 為例


homebrew 安裝 formula 的不同歷史版本——以安裝 node 為例

系統環境

  • macOS Mojave 10.14
  • Homebrew 1.8.0
    Homebrew/homebrew-core (git revision 586b0f; last commit 2018-10-27)
    Homebrew/homebrew-cask (git revision 76ddc; last commit 2018-10-27)

背景

最近 nodejs 發布了 11.0.0 版本,而我是用 brew 安裝了名為 node 的這個 formula ,現在 brew upgrade 會自動將 node 更新到最新版本,於是我遇到了一些問題:

  1. 一些需要編譯安裝的依賴包還不支持 node@11 ;
  2. 不知道如何自動切換兩個 formula ( node 和 node@10 )之間的可執行文件;
  3. 是否能夠設定某個 formula 不自動更新?

在經過一番折騰后,現在我刪掉了 node 和 node@10 兩個 formula ,包括之前安裝的歷史版本(所以算是多走了一點彎路),想要同時保留 10 和 11 兩個大版本,並可方便切換。

前置條件

若下列條件不滿足,可能導致需要額外的操作來解決環境問題,這些操作不在本文討論范圍內:

  1. 只通過 homebrew 來安裝 node ;
  2. 沒有使用如 n / nvm 等 node 版本管理工具;
  3. 某種意義下連接性良好的網絡。

適用情況

本文覆蓋了如下四種情況:

  1. 某個 formula 跟隨着更新上來,沒有運行過 cleanup 或 force uninstall ,想切回舊版本的(見關鍵點三);
  2. 全新安裝且只想安裝某個 formula (如 node 而非 node@10 ),但又想先用着舊版本的(見解決方案一);
  3. 某個 formula 在用的是舊版本,但想切換編譯選項(如 --with-openssl@1.1 )重新安裝(同上);
  4. 在兩個 formula 之間切換,如一個是 LTS 版的,一個是不穩定版的(見解決方案二)。

關鍵點

如何在 brew install / upgrade 時禁止自動更新

這一步很關鍵,否則我們總是會安裝到最新版本。只要在運行命令前,設置環境變量 HOMEBREW_NO_AUTO_UPDATE 為 1 就可以了,比如:

$ HOMEBREW_NO_AUTO_UPDATE=1 brew install node

也可以直接寫進 shell 配置文件中(如 .bashrc / .zshrc 等):

export HOMEBREW_NO_AUTO_UPDATE=1

查看某個 formula 的本地已安裝版本

有兩種方式可查看,一是 brew list --versions ,輸出以空格分隔,簡潔明了,推薦使用:

$ brew list node --versions
node 11.0.0 10.12.0
$ brew list zsh --versions |tr ' ' '\n'
node
11.0.0
10.12.0

二是 brew info 在查看 formula 信息時也可看到本地已安裝的版本:

$ brew info node
$ brew info node |grep -i '\/cellar'
/usr/local/Cellar/node/10.12.0 (3,668 files, 41.7MB)
/usr/local/Cellar/node/11.0.0 (3,665 files, 42MB) *

后面帶有的星號 * 表示當前激活的版本。

切換某個 formula 的版本

自有的 brew switch 命令即可,之前感覺 brew 較易上手,安裝后沒看文檔直接用到現在,所以不知道這個命令。命令的說明也很直觀:

brew switch formula version:
    Symlink all of the specific version of formula's install to Homebrew prefix.

直接鍵盤一頓敲就行了,如 brew switch node 10.12.0

解決方案

安裝某個 formula 的歷史版本

  1. 切換到 brew 的倉庫目錄下

    $ cd "$(brew --repo homebrew/core)"
    
  2. 查看某個 formula 的 git 歷史記錄

    $ git log master -- Formula/node.rb
    

    在里面找到想要的歷史版本,比如這個就挺像我所需要的:

    commit b801cc6b71e7c09448b4f823e493710665de68eb
    Author: BrewTestBot <homebrew-test-bot@lists.sfconservancy.org>
    Date:   Thu Oct 11 00:12:43 2018 +0000
    
        node: update 10.12.0 bottle.
    
  3. 檢出 git 歷史提交

    $ git checkout b801cc6b71e7c09448b4f823e493710665de68eb
    
  4. 在禁止自動更新的前提下安裝這個 formula

    $ HOMEBREW_NO_AUTO_UPDATE=1 brew install node --with-openssl@1.1
    
  5. 由於剛才第 3 步后處於分離頭指針狀態下,記得要切回來

    $ git checkout master
    
  6. 升級這個 formula 試試

    $ brew upgrade node
    
  7. 檢查當前版本,應該是最新的,現在再把它切回來

    $ node -v
    v11.0.0
    $ brew switch node 10.12.0
    Cleaning /usr/local/Cellar/node/10.12.0
    Cleaning /usr/local/Cellar/node/11.0.0
    7 links created for /usr/local/Cellar/node/10.12.0
    $ node -v
    v10.12.0
    

在兩個 formula 之間切換

我們也可以在 node 和 node@10 兩個 formula 之間切換文件鏈接。但是注意,這種方法可能會在運行 brew doctor 時產生警告,因為可能會有一個不是 keg-only 的包沒有被鏈接到 Cellar 中(如為了使用 node@10 而解除了 node 的鏈接),這個警告可以不去理會,但必須記住我們做過這樣的操作。

  1. 假定已經安裝了 node ,現在安裝 node@10 ,鍵盤一頓亂敲

    $ brew install node@10
    

    通常像這樣名字后面帶有版本號的 formula 都是 keg-only 的,簡單來說就是 brew 不會自動幫我們鏈接文件

  2. 先解除 node 的文件鏈接

    $ brew unlink node
    
  3. 鏈接 node@10 的文件

    $ brew link node@10
    

    這時會提示這個包是 keg-only 的,需要加上 --force 選項。如果第 2 步沒有進行,還會提示你需要先解除 node 的鏈接,或者直接用 --overwrite 選項覆蓋原有的鏈接。由於 npm 目錄一定需要覆蓋,所以我們總是可以打開 --overwrite 選項:

    $ brew link node@10 --force --overwrite
    
  4. 檢查當前版本,在解決方案一中提到過了,方法也有很多種,此處略過。

后續問題

  1. 全局安裝的包支持的 node 版本可能不同
    是的,這個問題一定會存在,建議通過切換 npm prefix 路徑解決,把不同版本 node 下安裝的全局包隔離開來。當然 nvm 等方案也可以解決問題,但本文是不一樣的煙火。

    $ mkdir -p ~/.npm-node10/npm-global
    $ npm config set prefix ~/.npm-node10/npm-global
    $ export PATH="$HOME/.npm-node10/npm-global/bin:$PATH"
    

    手動切換確實比較繁瑣,可以寫個 shell 腳本把切換 formula 和切換 npm prefix 結合起來。

  2. 如何固定某個 formula 的版本?
    雖然說不運行 brew upgrade 就一直是固定的版本,但如果想只固定某個 formula 的版本而允許其他可以升級,也是極好的。自帶的 pin 、 unpin 命令就是用來解決這一問題,如: brew pin node

  3. 如何刪除某個 formula 的舊版本?
    盡管 brew cleanup 可以刪除一個 formula 的所有舊版本,但通常我們可能只想刪除某幾個太舊且多余的版本而不是全部。 brew 沒有提供這樣的命令,我們可以直接從 Cellar 里面刪除:

    $ brew info node |grep -i '\/cellar'
    /usr/local/Cellar/node/10.12.0 (3,668 files, 41.7MB)
    /usr/local/Cellar/node/11.0.0 (3,665 files, 42MB) *
    $ rm -rf /usr/local/Cellar/node/10.12.0
    

    初步測試未發現有副作用,歡迎討論和建議。

  4. 如何在升級時自動刪除舊版本?
    根據 brew upgrade 命令的說明,設置一個 HOMEBREW_UPGRADE_CLEANUP 環境變量就好了,比較簡單。

參考資料

  1. Tips and Tricks - Homebrew Documentation
  2. Homebrew terminology - Homebrew Documentation
  3. FAQ - Homebrew Documentation
  4. homebrew - how to install older versions - Stack Overflow
  5. Homebrew install specific version of formula? - Stack Overflow
  6. Using Homebrew how do I remove some specific versions but not all old versions - Stack Overflow



本文基於 知識共享許可協議知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議 發布,歡迎引用、轉載或演繹,但是必須保留本文的署名 BlackStorm 以及本文鏈接 http://www.cnblogs.com/BlackStorm/p/homebrew-install-old-versions-take-node-for-example.html ,且未經許可不能用於商業目的。如有疑問或授權協商請與我聯系


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM