Home

Awesome

gx logo

gx translate-svg

与语言无关的通用包管理器


校对✔

欢迎 `Issue` 和 `Pull` ❤️, 最好 `Pull` 👏

翻译的原文与日期原文更新更多
commit2018 7.25last commit中文翻译

生活

help me live , live need money 💰


gx是围绕IPFS - 分布式内容寻址{星际}文件系统 构建的打包工具. 它旨在灵活,强大和简单.

gx是阿尔法质量. 它还不完美,但它已被证明足以管理go-ipfs的依赖关系,并准备 开拓开发人员和早期用户尝试和探索.

如果你想了解ipfs - ipfs 旅行 | ipfs/ipfs 中文 | 中文白皮书

目录

<!-- START doctoc generated TOC please keep comment here to allow auto update --> <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> <!-- END doctoc generated TOC please keep comment here to allow auto update -->

背景

gx最初设计用于以分布式方式处理Go项目中的依赖项,并从其他 心爱的包管理器 中提取想法 (如npm) .

gx的设计考虑了以下主要目标:

  1. 对于 语言/生态系统 可能通过 提供git-like 钩子来添加新的生态系统.
  2. 通过 内容寻址(ipfs 特性) 提供 完全一样的包.
  3. 使用灵活的分布式存储后端-ipfs.

要求

鼓励用户运行IPFS 守护程序在他们的机器上,且至少0.4.2版本. 如果不存在,gx将使用公共网关. 但如果您希望发布包,则本地运行守护程序是一项硬性要求.

安装

$ go get -u github.com/whyrusleeping/gx

这将把 源项目 下载到$GOPATH/src/github.com/whyrusleeping/gx并构建和安装二进制文件到$GOPATH/bin. 要修改gx,只需更改该目录中的源项目,然后运行即可go build.

用法

创建和发布 新的通用包:

$ gx init
$ gx publish

这将输出一个'package-hash',它对于发布时 包的确切内容 是唯一的. 如果有人要下载你的软件包并重新发布它,它就会产生准确相同的哈希.

package.json

应该注意的是,gx意味着与现有package.json文件合作. 如果你添加一个包给gx,且你在其根目录会有package.json文件,gx将尝试与它一起工作. 任何共享字段都具有相同的类型,并且gx独有的任何字段将保持独立.

例如. 单个package.json文件可用于同时为gx和另一个打包工具提供服务,例如npm. 因为gx是阿尔法质量,正如上述陈述可能有一些例外,如果您注意到,请提出问题.

安装gx包

如果你已复制了gx包-package.json,只需运行即可gx install要么gx i安装它 (及其依赖项) .

依赖

要将另一个包的依赖项添加到包中,只需通过其哈希导入它:

$ gx import QmaDFJvcHAnxpnMwcEh6VStYN4v4PB4S16j4pAuC2KSHVr

这会将指定的哈希包下载到工作区中vendor目录. 它还添加了一个引用该包的字段到本地package.json.

Gx有一些很好的工具来查看和分析依赖项. 首先,简单列出:

$ gx deps
go-log              QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52 1.2.0
go-libp2p-peer      QmWXjJo15p4pzT7cayEwZi2sWgJqLnGDof6ZGMh9xBgU1p 2.0.4
go-libp2p-peerstore QmYkwVGkwoPbMVQEbf6LonZg4SsCxGP3H7PBEtdNCNRyxD 1.2.5
go-testutil         QmYpVUnnedgGrp6cX2pBii5HRQgcSr778FiKVe7o7nF5Z3 1.0.2
go-ipfs-util        QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1 1.0.0

这列出了这个包的直接依赖性. 要查看依赖项的依赖项,请使用-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
go-log              QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52 1.2.0
go-logging          QmQvJiADDe7JR4m968MwXobTCCzUqQkP87aRHe29MEBGHV 0.0.0
go-multiaddr        QmYzDkkgAEmrcNzFCiYo6L1dTX4EAG1gZkbtdbd9trL4vd 0.0.0
go-multiaddr-net    QmY83KqqnQ286ZWbV2x7ixpeemH3cBpk8R54egS619WYff 1.3.0
go-multihash        QmYf7ng2hG5XBtJA3tN34DQ2GUN5HNksEw1rLDkmr6vGku 0.0.0
go-net              QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt 0.0.0
go-testutil         QmYpVUnnedgGrp6cX2pBii5HRQgcSr778FiKVe7o7nF5Z3 1.0.2
go-text             Qmaau1d1WjnQdTYfRYfFVsCS97cgD8ATyrKuNoEfexL7JZ 0.0.0
go.uuid             QmcyaFHbyiZfoX5GTpcqqCPYmbjYNAhRDekXSJPFHdYNSV 1.0.0
gogo-protobuf       QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV 0.0.0
goprocess           QmSF8fPo3jgVBAy8fpdjjYqgG87dkJgUprRBHRd2tmfgpP 1.0.0
mafmt               QmeLQ13LftT9XhNn22piZc3GP56fGqhijuL5Y8KdUaRn1g 1.1.1

这非常有用,我现在知道我的全套软件包的依赖. 但现在困难的是能够分辨出来自哪里. 为了解决这个问题,gx有一个--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
│     ├─ go-base58    QmT8rehPR3F6bmwL6zjUN8XpiDBFFpMP2myPdC6ApsWfJf 0.0.0
│     └─ go-crypto    Qme1boxspcQWR8FBzMxeppqug2fYgYc15diNWmqgDVnvn2 0.0.0
├─ go-log             QmNQynaz7qfriSUJkiEZUrm2Wen1u3Kj9goZzWtrPyu7XR 1.1.2
│  ├─ randbo          QmYvsG72GsfLgUeSojXArjnU6L4Wmwk7wuAxtNLuyXcc1T 0.0.0
│  ├─ go-net          QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt 0.0.0
│  │  ├─ go-text      Qmaau1d1WjnQdTYfRYfFVsCS97cgD8ATyrKuNoEfexL7JZ 0.0.0
│  │  └─ go-crypto    Qme1boxspcQWR8FBzMxeppqug2fYgYc15diNWmqgDVnvn2 0.0.0
│  └─ go-logging      QmQvJiADDe7JR4m968MwXobTCCzUqQkP87aRHe29MEBGHV 0.0.0
└─ go-libp2p-crypto   QmUEUu1CM8bxBJxc3ZLojAi8evhTr4byQogWstABet79oY 1.0.2
   ├─ gogo-protobuf   QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV 0.0.0
   ├─ go-log          Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH 0.0.0
   │  ├─ go.uuid      QmPC2dW6jyNzzBKYuHLBhxzfWaUSkyC9qaGMz7ciytRSFM 0.0.0
   │  ├─ go-logging   QmQvJiADDe7JR4m968MwXobTCCzUqQkP87aRHe29MEBGHV 0.0.0
   │  ├─ go-net       QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt 0.0.0
   │  │  ├─ go-text   Qmaau1d1WjnQdTYfRYfFVsCS97cgD8ATyrKuNoEfexL7JZ 0.0.0
   │  │  └─ go-crypto Qme1boxspcQWR8FBzMxeppqug2fYgYc15diNWmqgDVnvn2 0.0.0
   │  └─ randbo       QmYvsG72GsfLgUeSojXArjnU6L4Wmwk7wuAxtNLuyXcc1T 0.0.0
   ├─ go-ipfs-util    QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1 1.0.0
   │  ├─ 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-msgio        QmRQhVisS8dmPbjBUthVkenn81pBxrx1GxE281csJhm2vL 0.0.0
      └─ go-randbuf   QmYNGtJHgaGZkpzq8yG6Wxqm6EQTKqgpBfnyyGBKbZeDUi 0.0.0

现在你可以看到了整个该项目的依赖树. 虽然,对于较大的项目,这将变得混乱. 如果您只对单个包的依赖树感兴趣,可以使用--highlight过滤-tree打印的选项:

$ 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
├─ go-log             QmNQynaz7qfriSUJkiEZUrm2Wen1u3Kj9goZzWtrPyu7XR 1.1.2
│  └─ go-net          QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt 0.0.0
│     └─ go-crypto    Qme1boxspcQWR8FBzMxeppqug2fYgYc15diNWmqgDVnvn2 0.0.0
└─ go-libp2p-crypto   QmUEUu1CM8bxBJxc3ZLojAi8evhTr4byQogWstABet79oY 1.0.2
   ├─ go-log          Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH 0.0.0
   │  └─ go-net       QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt 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

此树是前一个树的子集,过滤仅显示到 所选包结束 的叶.

gx deps命令还有另外两个较小的子命令,dupesstats. gx deps dupes将打印出多个使用 相同名称 但 不同哈希 导入的包. 这可以用于查看在依赖关系树中的不同位置 是否已导入相同包的不同版本. 允许用户更轻松地解决差异. gx deps stats将输出导入的包的总数 (总数和唯一数) 以及 树中的平均导入深度. 这可以用来大致了解包的复杂性.

gx依赖关系图宣言

我坚信包会更好,在以下情况下:

1.依赖树的深度最小化.

这意味着重构代码的方式使树变平 (并可能因此而扩大) . 例如,在Go中,这通常意味着将 接口 作成 独立包,并将 实现 也放入它们自己的独立包中. 这里的好处是更平坦的树,更容易更新. 对于每个包的深度依赖,您必须更新,测试,提交,审查和合并另一个包. 这有很多工作,也有很多额外的空间可以让他们研究问题.

2.树的宽度最小化,但不以增加深度为代价.

这应该是相当常识的,但只在实际需要的地方努力去,导入包有助于提高代码质量. 想象一下在一个包中有一个辅助函数,只是因为它很方便,它却在 树中其他地方的一堆导入.

当然它很好,并没有实际增加你所依赖的'总'数量的包. 但当你随时更新时, 你会做了额外的工作,现在你也强迫 任何想要用你的帮助函数包的人,也导入所有其他依赖项.

遵守上述两条规则应该 (我非常愿意对此进行讨论) 提高整体代码质量,并使您的代码库更容易导航和工作.

更新

在gx中更新包很简单:

$ gx update mypkg QmbH7fpAV1FgMp6J7GZXUV6rj6Lck5tDix9JJGBSjFPgUd

这会查找你的package.jsonmypkg 并用给定的哈希引用替换它的哈希引用.

或者,您只需指定要更新的哈希:

$ gx update QmbH7fpAV1FgMp6J7GZXUV6rj6Lck5tDix9JJGBSjFPgUd

这样做将拉取这个哈希包,检查其名称,然后更新该依赖项.

请注意,默认情况下,这根本不会触及您的代码,因此您需要更新代码中 对 该哈希的任何引用. 如果您有语言工具 (例如gx-go) ,它有一个post-update钩子,应该正确更新给定包的引用.如果没有,您可能必须在包上运行 查询 来更新所有内容. 好的一面是,你不太可能因为任何其他原因而坐在那里,所以全局查找替换应该没问题.

出版和发布

如果您尚未更新其版本,则默认情况下Gx不允许您发布包两次.

要解决这个问题,你可以传递-f标志。 虽然不 推荐,它仍然是完美做到的。

要轻松更新版本,请使用gx version子命令。 您可以手动设置版本:

$ gx version 5.11.4

或者只是做一个'版本颠簸':

$ 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 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(-)

要自动执行此操作,您可以使用release子命令. gx release <version>将自动进行版本更新

要获得上面的git提交流程,您可以将其设置为: git commit -a -m \"gx publish $VERSION\"$VERSION会被gx取代成,新更改的版本.

忽略发布中的文件

你可以用一个.gxignore文件,使gx在发布期间忽略某些文件. 这与.gitignore具有相同的行为.

注意:是 .gx``ignroe,当然

Gx也遵守.gitignore文件 (如果存在) ,并且不会发布它排除的任何文件.

存储库

gx支持自定义包命名通过用户配置存储库. 存储库只是一个ipfs对象,其链接包名称为哈希. 您可以将 存储库 添加为ipns或ipfs路径.

用法

添加一个新的存储库

$ gx repo add myrepo /ipns/QmPupmUqXHBxikXxuptYECKaq8tpGNDSetx1Ed44irmew3

列出配置的存储库

$ gx repo list
myrepo       /ipns/QmPupmUqXHBxikXxuptYECKaq8tpGNDSetx1Ed44irmew3

列出给定仓库中的包裹

$ gx repo list myrepo
events      QmeJjwRaGJfx7j6LkPLjyPfzcD2UHHkKehDPkmizqSpcHT
smalltree   QmRgTZA6jGi49ipQxorkmC75d3pLe69N6MZBKfQaN6grGY
stump       QmebiJS1saSNEPAfr9AWoExvpfGoEK4QCtdLKCK4z6Qw7U

从repo导入包:

$ gx repo import events

钩子

gx可以通过根据您所处的场景,具有可扩展的智能默认值 来 支持各种用例. 为此,gx具有在某些操作期间调用的钩子.

这些钩子是特定于语言的,并且gx将尝试调用与您的语言匹配的辅助二进制文件以执行钩子,例如,当使用go,gx用过gx-go hook <hookname> <args>的命令行使用钩子.

目前可用的钩子是:

包目录

默认情况下,Gx将会"全局"安装包,如果你给定了全局包类型. 全局gx包 在依赖于它们的所有包 中共享. 此目录的位置不是一成不变的,如果您想在特定的环境中使用它,只需在您的环境扩展工具中添加一个钩子install-path (见上文) ,那么gx将使用该路径. 如果您的语言未设置全局安装路径,则gx将作为默认值回退到本地安装. 这意味着它将在当前目录中创建一个名为vendor的文件夹并安装它.

运行gx install在包的目录中,gx将递归地获取在package.json中指定的所有依赖项,并将它们保存到指定的安装路径.

Gx支持本地和全局安装路径. 由于默认为全局,因此要在本地安装,请使用--local要么--global=false. 全局标志 传递给install-path钩子, 让您的扩展代码使用它的逻辑.

使用gx作为Go包管理器

如果你想 (像我一样) 使用gx作为go的包经理,这很容易. 在开始项目之前,您将需要gx go扩展:

$ go get -u github.com/whyrusleeping/gx-go

安装完成后,使用gx像正常导入依赖项一样. 您可以使用以下方法从 供应商目录 导入代码:

import "gx/ipfs/<hash>/packagename"

例如,如果我有一个包foobar,你可以gx导入,像这样:

$ gx import QmR5FHS9TpLbL9oYY8ZDR3A7UWcHTBawU1FJ6pu9SvTcPa

然后在你的go代码中,你可以使用它:

import "gx/ipfs/QmR5FHS9TpLbL9oYY8ZDR3A7UWcHTBawU1FJ6pu9SvTcPa/foobar"

然后只需设置环境变量GO15VENDOREXPERIMENT1,并像往常一样运行go build要么go install. 或者,全局安装依赖项 (gx install --global) 你可以省去环境变量部分.

看到gx-go repo更多细节.

使用gx作为Javascript包管理器

请看一下gx-js.

使用gx作为语言/环境X的包管理器

如果您想将gx 与 大量存储库/软件包 一起使用,请查看GX-工作区.

如果要扩展gx以使用任何其他语言或环境,可以在名为gx-X的二进制文件中实现相关的挂钩, 其中'X'是您环境的名称. 之后,在正常情况下 编程语言对应"X"名字的包 将调用该工具 挂钩gx操作. 例如,'go'包能运行gx-go hook pre-publish,命令会在gx publish实际发布包之前被调用. 有关挂钩的更多信息,请查看上面的挂钩部分.

另见examples目录.

为什么叫gx?

没有理由. "gx"代表什么都不是.

加入

如果您对gx感兴趣,请在 freenode irc 上 #gx和#ipfs!

执照

麻省理工学院. 杰罗米约翰逊 Jeromy Johnson.