通道和生成索引#
通道布局#
.
├── channeldata.json
├── linux-32
| ├── repodata.json
│ └── package-0.0.0.tar.bz2
├── linux-64
| ├── repodata.json
│ └── package-0.0.0.tar.bz2
├── win-64
| ├── repodata.json
│ └── package-0.0.0.tar.bz2
├── win-32
| ├── repodata.json
│ └── package-0.0.0.tar.bz2
├── osx-64
| ├── repodata.json
│ └── package-0.0.0.tar.bz2
...
通道的组成部分#
channeldata.json
包含关于通道的元数据,包括通道包含哪些子目录。
通道中存在哪些包以及它们在哪些子目录中。
子目录与平台相关联。例如,linux-64 子目录包含用于 linux-64 系统的包。
repodata.json
包含子目录中包的索引。每个子目录将有自己的 repodata。通道在相应的子目录下以 tarball 形式存放包。
channeldata.json
#
{
"channeldata_version": 1,
"packages": {
"super-fun-package": {
"activate.d": false,
"binary_prefix": false,
"deactivate.d": false,
"home": "https://github.com/Home/super-fun-package",
"license": "BSD",
"post_link": false,
"pre_link": false,
"pre_unlink": false,
"reference_package": "win-64/super-fun-package-0.1.0-py310_0.tar.bz2",
"run_exports": {},
"subdirs": [
"win-64"
],
"summary": "A fun package! Open me up for rainbows",
"text_prefix": false,
"version": "0.1.0"
},
"subdirs": [
"win-64",
...
]
}
repodata.json
#
{
"packages": {
"super-fun-package-0.1.0-py310_0.tar.bz2": {
"build": "py37_0",
"build_number": 0,
"depends": [
"some-depends"
],
"license": "BSD",
"md5": "a75683f8d9f5b58c19a8ec5d0b7f796e",
"name": "super-fun-package",
"sha256": "1fe3c3f4250e51886838e8e0287e39029d601b9f493ea05c37a2630a9fe5810f",
"size": 3832,
"subdir": "win-64",
"timestamp": 1530731681870,
"version": "0.1.0"
},
...
},
"packages.conda": {
"super-fun-package-0.2.0-py310_0.conda": {
"build": "py37_0",
"build_number": 0,
"depends": [
"some-depends"
],
"license": "BSD",
"md5": "a75683f8d9f5b58c19a8ec5d0b7f796e",
"name": "super-fun-package",
"sha256": "e39029d601b9f493ea05c37a2630a9fe5810f1fe3c3f4250e51886838e8e0287",
"size": 4125,
"subdir": "win-64",
"timestamp": 1530731987654,
"version": "0.2.0"
},
...
}
}
索引是如何生成的#
对于每个子目录
查看子目录中存在的所有包。
生成要添加/更新/删除的包列表。
删除所有需要删除的包。
对于所有需要添加/更新的包
解压包以访问元数据,包括完整包名、文件修改时间 (
mtime
)、大小和index.json
。将包元数据聚合到 repodata 集合。
应用 repodata 热修复(补丁)。
计算并保存缩减后的
current_index.json
索引。
示例:构建通道#
要构建本地通道并将包放入其中,请按照以下说明操作
创建通道目录。
$ mkdir local-channel $ cd local-channel
现在,下载您最喜欢的包。在我们的示例中,我们将使用 SciPy。接下来的步骤取决于您的平台
Windows
$ mkdir win-64 $ curl -L https://anaconda.org/anaconda/scipy/1.9.1/download/win-64/scipy-1.9.1-py310h86744a3_0.tar.bz2 -o win-64\scipy-1.9.1-py310h86744a3_0.tar.bz2
Linux
大多数 Linux 系统都预装了
curl
。如果您还没有安装,请安装它。检查您是否安装了
curl
$ which curl
如果未找到
curl
,则安装它$ conda install curl
创建您想要包含在通道中的包的本地副本
$ mkdir linux-64 $ curl -L https://anaconda.org/anaconda/scipy/1.9.1/download/linux-64/scipy-1.9.1-py310hd5efca6_0.tar.bz2 -o linux-64\scipy-1.9.1-py310hd5efca6_0.tar.bz2
macOS,Intel 芯片
$ mkdir osx-64 $ curl -L https://anaconda.org/anaconda/scipy/1.9.1/download/osx-64/scipy-1.9.1-py310h09290a1_0.tar.bz2 -o osx-64/scipy-1.9.1-py310h09290a1_0.tar.bz2
macOS,Apple 芯片
$ mkdir osx-arm64 $ curl -L https://anaconda.org/anaconda/scipy/1.9.1/download/osx-arm64/scipy-1.9.1-py310h20cbe94_0.tar.bz2 -o osx-arm64/scipy-1.9.1-py310h20cbe94_0.tar.bz2
其他
要在上面列表中未包含的平台上查找最新的 SciPy,请转到 SciPy 的 Anaconda 包文件列表。
运行 conda index。这将为通道生成
channeldata.json
,为 linux-64 和 osx-64 子目录生成repodata.json
,以及其他一些文件$ conda index .
通过搜索通道检查您的工作
$ conda search -c file:/<path to>/local-channel scipy
SciPy 应该在多个通道中可用,包括
local-channel
。
幕后更多细节#
缓存包元数据#
如果存在,缓存将利用现有的 repodata.json
文件。索引检查哪些文件需要更新,基于自上次创建 repodata.json
以来哪些文件是新的、已删除或已更改的。当包是新的或已更改时,其元数据将被提取并缓存在包所属的子目录中。子文件夹是 .cache
文件夹。此文件夹有一个感兴趣的文件:stat.json
,其中包含每个文件的 stat
命令的结果。这用于了解文件何时已更改并且需要更新。在其他每个子文件夹中,每个包的提取的元数据文件都保存为原始包名,加上 .json
扩展名。如果有必要完全重新创建索引,预先提取这些可以节省大量时间。
题外话:.conda
包格式的一个设计目标是使索引尽可能快。为了实现这一点,.conda
格式将元数据与实际包内容分开。旧的 .tar.bz2
容器需要解压整个包才能获得元数据,而新的包格式允许提取元数据而无需接触包内容。这使得索引速度独立于包大小。大型 .tar.bz2
包可能需要很长时间才能解压和索引。
通常永远不需要手动更改缓存。要强制更新/重新扫描所有缓存的包,您可以删除 .cache 文件夹,或者您可以只删除 .cache/stat.json
文件。理想情况下,您可以仅从缓存中删除一个感兴趣的包,但该功能目前不存在。
Repodata 补丁#
包 repodata 从包内的 index.json 文件引导。不幸的是,该元数据并不总是正确的。有时需要追溯添加版本绑定。从包 index.json 文件派生的值更改 repodata 的过程称为“热修复”。热修复很棘手,因为它有可能破坏已经工作的环境,但有时也必须修复已知无法工作的环境。
从 python 脚本生成的 Repodata 补丁#
在您自己的服务器上,您可能可以运行您编写的任意 python 代码来应用您的补丁。这里的优势在于,每次生成索引时都会动态生成补丁。这意味着自上次提交补丁 python 文件以来添加的任何新包都将被拾取,并在适当的情况下应用热修复。
Anaconda 通过向 conda index
提供一个 python 文件来应用热修复,该文件具有关于如何更改元数据的逻辑。Anaconda 的热修复库位于 AnacondaRecipes/repodata-hotfixes
从 JSON 文件应用的 Repodata 补丁#
不幸的是,您不能总是直接运行您的 python 代码 - 其他托管您的补丁的人可能不允许您运行代码。您可以做的替代方法是将补丁打包为 .json 文件。这些将在应用时覆盖 repodata.json
中的条目。
例如,这是 conda-forge 必须采取的方法。他们的补丁创建代码在这里: conda-forge/conda-forge-repodata-patches-feedstock
该代码的作用是下载当前的 repodata.json
,然后运行他们的 python 逻辑来生成补丁 JSON 文件。这些补丁被放置在一个位置,Anaconda 的镜像工具将在镜像时找到它们并将它们应用于 conda-forge 的 repodata.json
。
这里的缺点是,这个 JSON 文件的新鲜度仅为 repodata-patches feedstock 上次生成包时的新鲜度。在此期间添加到索引的任何新包都不会应用任何热修复,因为热修复 JSON 文件不知道这些文件。
裁剪到“当前” repodata#
可用的包数量一直在增长。这意味着 conda 总是要做越来越多的工作。为了减缓这种增长,在 conda 4.7 中,我们添加了拥有备用 repodata.json 文件的能力,这些文件可能代表普通 repodata.json
的子集。其中一个特别的是 current_repodata.json
,它代表
每个包的最新版本
使最新版本可满足所需的任何早期版本的依赖项
current_repodata.json
也只保留一种文件类型:在 .conda
可用的情况下保留 .conda
,在只有 .tar.bz2
可用的情况下保留 .tar.bz2
。
对于 Anaconda 的默认“main”通道,current_repodata.json 文件大约是 repodata.json 大小的 1/7。这使得下载 repodata 更快,也使得将 repodata 加载到其 python 表示形式中更快。
对于那些对如何实现这一点感兴趣的人,请参考 conda/conda-build 中的代码