GUIX 吸引我的部分原因是可以同时“安装”各种不同版本的软件包,而不会相互干扰。但我不知道如何实际使用这些不同的版本。
比如最近,该pyyaml
软件包已从 5.4.1 升级到 6.0。由于种种原因,我想继续使用5.4.1。 (我只是在这里使用 pyyaml 作为示例。)我的商店里确实有旧版本:
$ ls -d1 /gnu/store/*pyyaml*
/gnu/store/22v8l25b33vs65wjd9ap28n772bvlih3-python-pyyaml-5.4.1/
/gnu/store/2j2s1jd6y8x7mlqjp968955misx1qw1c-python-pyyaml-6.0/
/gnu/store/54imz4x65s3xbjrgrfswgk815gfkhk4b-python-pyyaml-5.4.1/
/gnu/store/6537a8na1rbilffqqi642q0lipqfi2zg-python-pyyaml-5.4.1.drv
/gnu/store/6flrrmhq203vg6awdw7r2lsmzix4g2rh-python-pyyaml-6.0-guile-builder
/gnu/store/73k3qdz9rdh64pl7a0f0951zm2pbx5s2-python-pyyaml-5.4.1.drv
/gnu/store/7bcbwi93ihz8v2sdzmj6l9vhjqaxr14l-python-pyyaml-5.4.1-builder
...
我如何使用这些旧版本?
仅单独使用这样的旧版本就可以了。例如,我希望这样的事情能够起作用:
$ guix shell "[email protected]" python
guix shell: error: python-pyyaml: package not found for version 5.4.1
此错误是预料之中的,因为旧版本在我的频道中不可用。因此,也许可以以某种方式指定要使用的旧版本通道,但我不知道如何指定。
关于 XY 问题的侧节点,这个问题的直接原因是 docker-compose 现在不再工作:
$ guix shell docker-compose
guix shell: error: build of `/gnu/store/8qhvnw5mwra9i6ji24xlywcpdl0rdznn-docker-compose-1.29.2.drv' failed
$ zcat /var/log/guix/drvs/8q/hvnw5mwra9i6ji24xlywcpdl0rdznn-docker-compose-1.29.2.drv.gz
...checking requirements: ERROR: docker-compose==1.29.2 ContextualVersionConflict(PyYAML 6.0 (/gnu/store/igfl4023dzvl8vi6xs1m96lcsr4fdw07-python-pyyaml-6.0/lib/python3.9/site-packages), Requirement.parse('PyYAML<6,>=3.10'), {'docker-compose'})
但是,我并不特别关心 docker-compose (关于这个问题)。如果有的话,这个问题是我用 GUIX 原生工具取代它的旅程的一部分。
(另外,我知道 pyyaml 6 对其用户强制使用一些安全功能,因此不应再使用 pyyaml 5;pyyaml 仅用作示例。)
答案1
第三次是魅力,使用下等人的清单似乎是最好的。
info guix Inferiors
详情请参阅。这是信息页面的快照。 (有趣的是,他们的用例与我的非常相似:使用旧版本的 json 库作为 guile 解释器,而不是使用旧版本的 yaml 库作为 python 解释器。)
Note: The functionality described here is a “technology preview” as
of version 0.0-git. As such, the interface is subject to change.
Sometimes you might need to mix packages from the revision of Guix
you’re currently running with packages available in a different revision
of Guix. Guix “inferiors” allow you to achieve that by composing
different Guix revisions in arbitrary ways.
...
When combined with channels (*note Channels::), inferiors provide a
simple way to interact with a separate revision of Guix. For example,
let’s assume you want to install in your profile the current ‘guile’
package, along with the ‘guile-json’ as it existed in an older revision
of Guix—perhaps because the newer ‘guile-json’ has an incompatible API
and you want to run your code against the old API. To do that, you
could write a manifest for use by ‘guix package --manifest’ (*note
Invoking guix package::); in that manifest, you would create an inferior
for that old Guix revision you care about, and you would look up the
‘guile-json’ package in the inferior.
继续举一个例子。以下是适用于该特定用例的相同示例:
$ cat mypyyamlmanifest.scm
(use-modules (guix inferior) (guix channels)
(srfi srfi-1))
(define channels
(list (channel
(name 'guix)
(url "https://git.savannah.gnu.org/git/guix.git")
(commit
;; The commit with the python-pyyaml 5.4.1
"d3e1a94391a838332b0565d56762a58cf87ac6b1"))))
(define inferior
(inferior-for-channels channels))
(packages->manifest
(list (first (lookup-inferior-packages inferior "python-pyyaml"))
(specification->package "python")))
$ guix shell -m mypyyamlmanifest.scm
...
$ python3 -c "import yaml; print(yaml.__version__)"
5.4.1
反思为什么花了这么长时间才找到这些信息。 (也许 GUIX 开发人员会读到这篇文章,也许我可以用它来为文档提供补丁。)
guix info guix package
是我使用清单的起点。描述--manifest
中有关于如何制作清单的简短示例,但没有讨论渠道。有一个指向--export-manifest
描述的链接,我通过该链接了解如何重新创建为创建的环境我的第一个答案。该部分解释说此导出不包含通道信息,这使我得出结论,清单根本不包含通道信息并且需要第二个文件(我的第二个答案)。描述--export-manifest
链接到--export-channels
其正下方,起初我没有阅读,因为我只是调整了现有的channels.scm
.然而,该部分最后解释了需要下等人。
--manifest
如果的部分guix package
解释可以直接在清单中定义通道,我可能会更容易理解。
如果我理解正确的话,劣等在技术上与通道不同,所以上面的最后一句话是错误的,并且不可能在清单中定义通道。然而在实践中,似乎可以对清单中的所有包使用次等包,从而有效地对清单中的通道进行硬编码。这让我想知道直接在清单中允许通道规范是否会更简单。
在回答问题时,这个解决方案仍然不足以解决触发问题的最初问题: running docker-compose
,因为docker-compose
仍然使用python-pyyaml
原始通道中的 。有可能让一个包使用次等作为输入使用modify-inputs
。这使得可以只docker-compose
使用python-pyyaml
劣质的过时的,而让配置文件的其余部分使用python-pyyaml
原始渠道的较新的。
答案2
感谢优秀的info guix
页面,我认为这是可行的:
guix shell \
--with-git-url=python-pyyaml="https://github.com/yaml/pyyaml.git" \
--with-branch=python-pyyaml="release/5.4.1" \
python-pyyaml python
但如果已经有一个完美的包定义,感觉有点hackishhttps://git.savannah.gnu.org/cgit/guix.git/tree/gnu/packages/python-xyz.scm?h=d3e1a94391a838332b0565d56762a58cf87ac6b1#n3907。
是pyyaml
一个非常简单的包,很好地托管在 github 上,遵循标准 git 分支和 Python 安装程序。但某些包可能更复杂,这样简单的替换可能不起作用。
有没有某种方法可以指定通道 git url 上的特定提交以用于包? (或者完整的guix shell
命令?)
编辑:这个解决方案不是很好的另一个原因是它不适用于--export-manifest
:
$ guix shell \
--with-git-url=python-pyyaml="https://github.com/yaml/pyyaml.git" \
--with-branch=python-pyyaml="release/5.4.1" \
--export-manifest \
python-pyyaml python > mymanifest.scm
$ guix shell -m mymanifest.scm
guix shell: error: the source of [email protected] is not a Git
和mymanifest.scm
:
$ cat mymanifest.scm
;; What follows is a "manifest" equivalent to the command line you gave.
;; You can store it in a file that you may then pass to any 'guix' command
;; that accepts a '--manifest' (or '-m') option.
(use-modules (guix transformations))
(define transform1
(options->transformation
'((with-git-url
.
"python-pyyaml=https://github.com/yaml/pyyaml.git")
(with-branch . "python-pyyaml=release/5.4.1"))))
(packages->manifest
(list (transform1
(specification->package "python-pyyaml"))
(transform1 (specification->package "python"))))
答案3
这也许更加 GUIXy:
- 从仍具有 pyyaml 5.4.1 的提交创建通道文件。
- 从该通道文件创建配置文件。
- 激活该配置文件。
- 使用所需的包创建清单。
- 使用该清单创建一个 shell。
$ cat mypyyamlchannels.scm
(list (channel
(name 'guix)
(url "https://git.savannah.gnu.org/git/guix.git")
(branch "master")
(commit
"d3e1a94391a838332b0565d56762a58cf87ac6b1")
(introduction
(make-channel-introduction
"9edb3f66fd807b096b48283debdcddccfea34bad"
(openpgp-fingerprint
"BBB0 2DDF 2CEA F6A8 0D1D E643 A2A0 6DF2 A33A 54FA")))))
$ guix pull -C mypyyamlchannels.scm -p mypyyamlprofile
$ GUIX_PROFILE="$(realpath mypyyamlprofile)"
$ . "$GUIX_PROFILE/etc/profile"
$ guix shell python-pyyaml python --export-manifest > mypyyamlmanifest.scm
$ cat mypyyamlmanifest.scm
;; What follows is a "manifest" equivalent to the command line you gave.
;; You can store it in a file that you may then pass to any 'guix' command
;; that accepts a '--manifest' (or '-m') option.
(specifications->manifest
(list "python-pyyaml" "python"))
$ guix shell -m mypyyamlmanifest.scm
但这有两个缺点:
- 这有点冗长。它需要 2 个文件(通道和清单)和 4 个命令(guix pull、set GUIX_PROFILE、源配置文件、guix shell)和 2 个符号链接 (
mypyyamlprofile
,mypyyamlprofile-1-link
) 来重新创建相同的环境。不起作用的转换解决方案只需要 1 个清单文件和 1 个 guix shell 命令。是否有一种方法可以将通道和清单文件组合成一个东西,然后可以用来在单个命令中实例化 shell? - 它不允许从主通道进行混合和匹配。我认为混合需要创建一个组合默认通道的通道文件,然后以某种方式从具有特定提交的通道中挑选 python-pyyaml 包。这可能会导致不一致,但这些可能是可以解决的。
编辑:显然劣质会让混合和匹配更容易:
Sometimes you might need to mix packages from the revision of Guix
you’re currently running with packages available in a different revision
of Guix. Guix “inferiors” allow you to achieve that by composing
different Guix revisions in arbitrary ways.