
ipfs的御用包管理器 gx入門指南
何為 gx
官方稱其為一個通用包管理器,構(gòu)建于 IPFS 之上,gx 最初的設(shè)計靈感來自 nodejs 的 npm ,用來處理 golang 項目中的依賴包。如果從源碼來欣賞 IPFS 并且心存二次開發(fā)的愿望,那么對 gx 的掌握還是非常有必要的。
本人在年初學(xué)習(xí) IPFS (v0.4.12) 時并沒有重視 gx 這個工具,甚至還在二次開發(fā)的過程中放棄了 gx 而改用 govendor 來進(jìn)行 deps 的管理,這在后期升級 libp2p 時簡直就是一場災(zāi)難。由于工作需要現(xiàn)在又需要使用 go-libp2p 來做一個 p2p 應(yīng)用,所以下定決心一定要征服 gx
想要了解更多需要仔細(xì)閱讀源碼的 README,此處用來簡要說明這個工具的使用方法,希望對使用 go-ipfs 和 go-libp2p 的同學(xué)能起到一些幫助的作用
工具要求
使用 gx 前本地一定要先啟動 ipfs daemon ,版本也是有要求的,用最新版 ipfs 總是沒錯的。
如果沒有啟動 ipfs 那么 gx 會從 ipfs.io 這個公共網(wǎng)關(guān)獲取資源,在國內(nèi)這個網(wǎng)關(guān)幾乎是不可用的。
安裝 gx
$ go get -u github.com/whyrusleeping/gx
前提是已經(jīng)安裝和配置了最新版的 golang
工具會安裝在
$GOPATH/src/github.com/whyrusleeping/gx
并且會 install 到 $GOPATH/bin
不要忘記把 bin 目錄放到 PATH 中哦
使用 gx
創(chuàng)建和發(fā)布一個包:
$ gx init
$ gx publish
創(chuàng)建一個 golang 的工程,并在工程工程根目錄gx init 后,會生成一個 package.json 文件用來描述你的庫,執(zhí)行 gx publish 后將會得到一個 hash 值,這是與你當(dāng)前庫的版本相對應(yīng)的唯一ID,以后導(dǎo)入包時需要使用。
安裝 gx包
當(dāng)你在 github 上 clone 了一個 gx 包時,這個包很可能用 gx 管理了本地的依賴,所以你要通過 gx install 或者 gx i 這個子命令來進(jìn)行安裝,此時依賴包也會一并被安裝到 GOPATH$/src/gx/ipfs 這個目錄中。
導(dǎo)入依賴
導(dǎo)入一個依賴非常簡單,只要知道 hash 通過 import 即可完成導(dǎo)入
$ gx import QmaDFJvcHAnxpnMwcEh6VStYN4v4PB4S16j4pAuC2KSHVr
gx 會去 ipfs 中下載這個 hash 對應(yīng)的包并且這個包的 hash、版本、名字 都會出現(xiàn)在你的 package.json 中
$ gx deps
go-log QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52 1.2.0
go-libp2p-peer QmWXjJo15p4pzT7cayEwZi2sWgJqLnGDof6ZGMh9xBgU1p 2.0.4
......
查看直接依賴,還可以通過 -r -s 來查看全部依賴
$ gx deps -r -s
go-base58 QmT8rehPR3F6bmwL6zjUN8XpiDBFFpMP2myPdC6ApsWfJf 0.0.0
go-crypto Qme1boxspcQWR8FBzMxeppqug2fYgYc15diNWmqgDVnvn2 0.0.0
go-datastore QmbzuUusHqaLLoNTDEVLcSF6vZDHZDLPC7p4bztRvvkXxU 1.0.0
go-ipfs-util QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1 1.0.0
go-keyspace QmUusaX99BZoELh7dmPgirqRQ1FAmMnmnBn3oiqDFGBUSc 1.0.0
go-libp2p-crypto QmVoi5es8D5fNHZDqoW6DgDAEPEV5hQp8GBz161vZXiwpQ 1.0.4
go-libp2p-peer QmWXjJo15p4pzT7cayEwZi2sWgJqLnGDof6ZGMh9xBgU1p 2.0.4
go-libp2p-peerstore QmYkwVGkwoPbMVQEbf6LonZg4SsCxGP3H7PBEtdNCNRyxD 1.2.5
......
還可以通過 --tree 選項來查看完整的 依賴樹
$ gx deps --tree
├─ go-base58 QmT8rehPR3F6bmwL6zjUN8XpiDBFFpMP2myPdC6ApsWfJf 0.0.0
├─ go-multihash QmYf7ng2hG5XBtJA3tN34DQ2GUN5HNksEw1rLDkmr6vGku 0.0.0
│ ├─ go-base58 QmT8rehPR3F6bmwL6zjUN8XpiDBFFpMP2myPdC6ApsWfJf 0.0.0
│ └─ go-crypto Qme1boxspcQWR8FBzMxeppqug2fYgYc15diNWmqgDVnvn2 0.0.0
├─ go-ipfs-util QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1 1.0.0
│ ├─ go-base58 QmT8rehPR3F6bmwL6zjUN8XpiDBFFpMP2myPdC6ApsWfJf 0.0.0
│ └─ go-multihash QmYf7ng2hG5XBtJA3tN34DQ2GUN5HNksEw1rLDkmr6vGku 0.0.0
......
全部顯示出來通常不是我查看依賴的需求,更常用的是針對某個庫進(jìn)行檢查,gx 同時提供了 --highlight 選項來過濾感興趣的內(nèi)容
$ gx deps --tree --highlight=go-crypto
├─ go-multihash QmYf7ng2hG5XBtJA3tN34DQ2GUN5HNksEw1rLDkmr6vGku 0.0.0
│ └─ go-crypto Qme1boxspcQWR8FBzMxeppqug2fYgYc15diNWmqgDVnvn2 0.0.0
├─ go-ipfs-util QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1 1.0.0
│ └─ go-multihash QmYf7ng2hG5XBtJA3tN34DQ2GUN5HNksEw1rLDkmr6vGku 0.0.0
│ └─ go-crypto Qme1boxspcQWR8FBzMxeppqug2fYgYc15diNWmqgDVnvn2 0.0.0
......
這個過濾后的樹是前一個樹的子集,而且僅顯示出現(xiàn)在葉子節(jié)點(diǎn)上的 highlight 包
- gx deps 還有兩個自命令 'dupes' 和 'stats' 。
gx deps dupes 用來幫助我們查看重復(fù)導(dǎo)入的庫,例如相同的庫 在不同位置導(dǎo)入了 不同的 hash。
gx deps stats 用來輸出關(guān)于依賴的狀態(tài)信息,包括 Total Import Count、Unique Import Count 、Average Import Depth ,可以大概用來了解依賴關(guān)系的復(fù)雜度。
注意:gx import這個操作會去修改我們已經(jīng)寫好的代碼,例如:
我們在沒有使用 gx 時,導(dǎo)入了 go-lightrpc/rpcserver
import "github.com/cc14514/go-lightrpc/rpcserver"
之后我們將 go-lightrpc 通過 gx publish發(fā)布得到 QmYaVXmXZNpWs6owQ1rk5VAiwNinkTh2cYZuYx1JDSactL 這個 hash
執(zhí)行 gx import QmYaVXmXZNpWs6owQ1rk5VAiwNinkTh2cYZuYx1JDSactL
import "gx/ipfs/QmYaVXmXZNpWs6owQ1rk5VAiwNinkTh2cYZuYx1JDSactL/go-lightrpc/rpcserver"
查看代碼時你會發(fā)現(xiàn)工程中所有導(dǎo)入了 go-lightrpc 的地方都被替換了
依賴關(guān)系的設(shè)計原則
設(shè)計程序依賴時盡量遵循以下原則:
1、依賴關(guān)系深度最小化
2、盡量讓依賴樹的廣度最小化,但是不要以犧牲深度作為代價
更新
使用 gx 更新依賴非常簡單
$ gx update mypkg QmbH7fpAV1FgMp6J7GZXUV6rj6Lck5tDix9JJGBSjFPgUd
其中 mypkg 指依賴包的 name ,可以在 package.json 中找到要更新的 mypkg ,也可以通過 gx deps 來找到對應(yīng)的 mypkg.
也可以只提供要更新的包的 hash
$ gx update QmbH7fpAV1FgMp6J7GZXUV6rj6Lck5tDix9JJGBSjFPgUd
這樣做時 gx 會去下載這個 hash 后檢查名稱并更新項目中對應(yīng)的名稱。
這里要順便說一句,看過官方文檔你會發(fā)現(xiàn)還有一個叫 gx-go 的工具,可以幫你自動把 gx 依賴導(dǎo)入 govendor 來管理,現(xiàn)在是動蕩期,這個工具暫時就不推薦使用了,不出意外的話我們很快就要像送別 godeps 一樣送別 govendor 了。
其實(shí)gx update 還有一個很讓人期待的選項 '--with-deps',顧名思義,他會幫助我們深度更新依賴的依賴 , 但遺憾的是這個功能尚不能達(dá)到生產(chǎn)級別,可以跟隨gx每個版本的更新來體驗(yàn)其可用性,現(xiàn)在還是實(shí)驗(yàn)階段。
Publishing and Releasing
如果你要 publish 一個庫,但是并沒有修改版本號,那么默認(rèn)是不允許的,可以通過 '-f' 選項來強(qiáng)制發(fā)布。版本號記錄在 package.json 中,升級版本號可以通過 gx version 這個子命令來完成
$ gx version 5.11.4
版本號的格式通常遵循 : major.minor.patch 原則,所以可以直接用下面方式更新
$ gx version patch
updated version to: 5.11.5
$ gx version minor
updated version to: 5.12.0
$ gx version major
updated version to: 6.0.0
使用 gx 更新工程時通常會做如下操作:
$ gx version minor
updated version to: 6.1.0
$ gx publish
package whys-awesome-package published with hash: QmaoaEi6uNMuuXKeYcXM3gGUEQLzbDWGcFUdd3y49crtZK
$ git commit -a -m "gx publish 6.1.0"
[master 5c4d36c] gx publish 6.1.0
2 files changed, 3 insertions(+), 2 deletions(-)
為了自動執(zhí)行以上腳本,可以使用 release 子命令 gx release <version>將會自動幫你執(zhí)行 version update 和 publish ,隨后會執(zhí)行你在 package.json 中通過 releaseCmd 設(shè)置的指令,例如去獲取你設(shè)置的 git commit -a -m \"gx publish $VERSION\",執(zhí)行時 gx 會用 version 來覆蓋 $VERSION 變量。
忽略:Ignoring files from a publish
可以通過 .gxignore 文件來指定 gx 要在 publish 中忽略的文件,和 .gitignore 的作用類似,同時 gx 也遵守 .gitignore 約定。
中央庫:Repos
gx 可以像 maven 一樣來指定中央庫,不過因?yàn)?ipfs 的網(wǎng)絡(luò)多是以不穩(wěn)定的 pc 機(jī)組成,所以添加一個 node 作為中央庫也未必可靠,除非這個庫就是你自己部署的,如果是臨時的就不建議添加了。
如果你想在本地開發(fā)測試,在服務(wù)器上執(zhí)行編譯和運(yùn)行,那么服務(wù)器上也至少要運(yùn)行一個 ipfs daemon 了,此時你直接把本地 ipfs 連到 服務(wù)器上,如 'ipfs swarm connect 服務(wù)器ipfsid' ,當(dāng)然你也可以選擇交叉編譯,go 提供的交叉編譯能力還是很讓人滿意的。
- 添加一個新的中央庫
$ gx repo add myrepo /ipns/QmPupmUqXHBxikXxuptYECKaq8tpGNDSetx1Ed44irmew3
- 列出本地已經(jīng)添加的中央庫
$ gx repo list
myrepo /ipns/QmPupmUqXHBxikXxuptYECKaq8tpGNDSetx1Ed44irmew3
- 列出指定中央庫中包含的庫
$ gx repo list myrepo
events QmeJjwRaGJfx7j6LkPLjyPfzcD2UHHkKehDPkmizqSpcHT
smalltree QmRgTZA6jGi49ipQxorkmC75d3pLe69N6MZBKfQaN6grGY
stump QmebiJS1saSNEPAfr9AWoExvpfGoEK4QCtdLKCK4z6Qw7U
- 從指定的中央庫導(dǎo)入一個庫
$ gx repo import events