2010/03/08

Fake Eggs ?

This is an abstract from Scrambled eggs by Martin Aspeli.

藉由 egg 機制,我們可以更順暢地進行模組軟體的包裝與散佈,但是,遇到 buildout 想要自動昇級某些模組時,為了滿足相依衝突時,egg 也可能帶來許多痛苦,我們會被一堆版本昇級要求資訊淹沒。

由於 Plone 3.0 到 3.1 搭配的 Zope 並沒有包裝成 egg 檔案,導致 setuptools 無從得知 Zope 3 模組的 egg metadata 資訊。舉例來說,如果你安裝一個相依於 zope.component 的模組,但是 setuptools 並不知道你已經有 zope.component 了,因此會試著下載最新版的 zope.component。由於新版 zope.component 的下載動作會引發其他相依關係,很容易造成永無止境的昇級要求。

為了解決上述問題,plone.recipe.zope2install 這個 recipe 預設會安裝一些 fake egg,它的效果,就像是建立一堆指到 parts/zope2/lib/python/* 的 egg。如此一來,setuptools 就能知道系統裡存在 zope.component、zope.interface 等標準模組,不需要再去下載新版檔案。

常見的情況是,我們只知道需要安裝某個檔案,但不清楚所需的明確版本,因此 fake egg 會指定為 0.0 版本,除非你為特定的 recipe 額外指定它的版本號碼。也就是說,如果有個模組的相依關係是 zope.component >= 3.1,setuptools 仍然會以為系統既有的 zope.component 版本過舊,將嘗試下載新的版本。

那麼,模組的相依資訊被記錄於何處? 它的來源大致有兩類,一是在模組檔案的 setup.py 內容裡,二是從 buildout.cfg 檔案的 eggs 設定值尋找。相依資訊的常見形式,又可分成兩類,第一類的例子是「我需要和 zope.component 一起工作」,只指定模組名稱,而不指定模組版本,第二類的例子是「我需要和 zope.component >= 3.4 版本一起工作」,同時指定模組名稱與版本條件。

有時,在 setup.py 裡指定最小版本號碼是必要的,因為某些版本以上的模組,才提供我們需要的功能。當然,在 setup.py 裡明確指定「我需要和 zope.component == 3.4 版本工作」是合法的設定方式,但通常會造成日後的災難,而指定最大版本號碼的方式,例如「我需要和 zope.component >=3.4, <=3.4.999 版本工作」,通常也是很糟的形式。一般而言,除非有必要,永遠不要在 setup.py 裡指定「==」的版本要求,頂多使用「<=」的版本形式。因為,這類不適當的設定值一旦出錯,除錯工作極度困難。

另一方面,目前 setuptools 的運作方式,是找尋最新版本來下載,如果它先下載了某個模組的新版本,就會順著它的相依關係來下載其他模組,即使某個舊版本提供更合適的相依條件,setuptools 並無從得知,這會導致下列問題:

* setuptools 下載過新版本的模組,和稍後模組的最大版本條件相衝突。幸好,這個問題並不難解決。

* 原本 buildout 運作正常,但是有人在 PyPI 上傳新版模組,造成相依關係更新,接著你又執行 buildout 更新動作,下載了新版模組,引發更多新版模組的下載。運氣好的話,系統會通知版本衝突的訊息,運氣不好的話,表面上 build 動作完成,但執行系統時卻失敗。

No comments: