GLEP 55:使用 EAPI 后缀的 ebuild 文件(.ebuild-EAPI)
作者 | Piotr Jaroszyński <peper@gentoo.org> |
---|---|
类型 | 标准跟踪 |
状态 | 已拒绝 |
版本 | 1 |
创建日期 | 2007-12-17 |
最后修改日期 | 2014-01-23 |
发布历史 | 2007-12-17, 2007-12-22, 2009-05-17 |
GLEP 源代码 | glep-0055.rst |
内容
"浅学误人,要么深究,要么别碰皮埃里亚的泉水:浅尝辄止会使头脑迷乱,而大量饮用则会使人清醒。"
——亚历山大·蒲柏,《论批评》
状态
该 GLEP 在 2010 年 8 月 23 日的会议上被委员会否决。委员会在 2012 年 5 月 8 日的会议上再次否决了它,赞成从 ebuild 中的 bash 赋值语句中解析 EAPI。
摘要
本 GLEP 提议对 ebuild 使用 EAPI 后缀的文件扩展名(例如,foo-1.2.3.ebuild-1)。
问题
目前在 ebuild 中指定 EAPI 的方式存在缺陷。为了获取 EAPI,包管理器需要加载 ebuild,而 ebuild 本身首先需要 EAPI。否则,它会带来严重的限制,即每个 ebuild 使用任何未来的 EAPI 都必须能够被旧的包管理器加载,因此无法执行以下任何操作
- 以任何方式更改 inherit 的行为(例如,扩展或更改 eclass 功能)。
- 以任何合理的方式添加新的全局作用域函数。
- 扩展 EAPI 中的版本控制规则 - 例如,添加 scm 后缀 - GLEP54 [1] 或允许更合理的版本格式,例如1-rc1, 1-alpha等等,以更紧密地匹配上游。
- 使用较新的 bash 功能。
当前行为
以下小节显示了如果您在 ebuild 中引入任何上述更改并尝试使用 portage 2.1.6.13 安装它时会发生什么。
继承的不可兼容更改(例如,使其也查看包目录)
sys-apps/foo-1.ebuild:
EAPI="5" inherit "foo" DESCRIPTION="" HOMEPAGE="" SRC_URI="" ...
结果
* * ERROR: sys-apps/foo-1 failed. * Call stack: * ebuild.sh, line 1879: Called _source_ebuild * ebuild.sh, line 1818: Called source '/var/lib/gentoo/repositories/peper/sys-apps/foo/foo-1.ebuild' * foo-1.ebuild, line 6: Called inherit 'foo' * ebuild.sh, line 1218: Called die * The specific snippet of code: * [ ! -e "$location" ] && die "${1}.eclass could not be found by inherit()" * The die message: * foo.eclass could not be found by inherit() * * If you need support, post the topmost build error, and the call stack if relevant. * This ebuild is from an overlay: '/var/lib/gentoo/repositories/peper/' * !!! All ebuilds that could satisfy "sys-apps/foo" have been masked. !!! One of the following masked packages is required to complete your request: - sys-apps/foo-1 (masked by: corruption)
当前的 portage 仅在eclass存储库的目录。这会导致致命错误,并且 ebuild 被标记为损坏 - 对用户来说可能非常令人困惑。
新的全局作用域函数
sys-apps/foo-1.ebuild:
EAPI="5" new_global_scope_function "foo" DESCRIPTION="" HOMEPAGE="" SRC_URI="" ...
结果
/var/lib/gentoo/repositories/peper/sys-apps/foo/foo-1.ebuild: line 7: new_global_scope_function: command not found !!! All ebuilds that could satisfy "sys-apps/foo" have been masked. !!! One of the following masked packages is required to complete your request: - sys-apps/foo-1 (masked by: EAPI 5) The current version of portage supports EAPI '2'. You must upgrade to a newer version of portage before EAPI masked packages can be installed.
这不算太糟糕,因为建议用户升级 portage。
新的版本格式
sys-apps/foo-2-rc1.ebuild:
Invalid ebuild name: /var/lib/gentoo/repositories/peper/sys-apps/foo/foo-2-rc1.ebuild emerge: there are no ebuilds to satisfy "sys-apps/foo"
这不是最佳的错误消息,尤其是在有很多错误消息时。
使用较新的 bash 功能
|&是 bash-4 中添加的一种新的重定向类型。它甚至不能在本地作用域中使用,因为 bash 仍然解析整个 ebuild。
sys-apps/foo-1.ebuild:
EAPI="5" foo() { echo "foo" |& cat }
结果
/var/lib/gentoo/repositories/peper/sys-apps/foo/foo-1.ebuild: line 8: syntax error near unexpected token `&' /var/lib/gentoo/repositories/peper/sys-apps/foo/foo-1.ebuild: line 8: ` echo "foo" |& cat' * * ERROR: sys-apps/foo-1 failed. * Call stack: * ebuild.sh, line 1879: Called _source_ebuild * ebuild.sh, line 1818: Called die * The specific snippet of code: * source "${EBUILD}" || die "error sourcing ebuild" * The die message: * error sourcing ebuild * * If you need support, post the topmost build error, and the call stack if relevant. * This ebuild is from an overlay: '/var/lib/gentoo/repositories/peper/' * ... done! !!! All ebuilds that could satisfy "sys-apps/foo" have been masked. !!! One of the following masked packages is required to complete your request: - sys-apps/foo-1 (masked by: corruption)
同样,这不是最佳的错误。
抽象解决方案
此问题的解决方案必须解除这些限制,而唯一的方法是使包管理器能够以无需加载 ebuild 的方式获取 ebuild 的 EAPI。另一个重要要求是解决方案必须向后兼容,这具有使解决方案能够立即应用于 Gentoo 树的良好副作用。与等待任意长的时间相反,因为无论如何时间都不够长,正如在常见 portage 问题页面上列出的问题 - [2] - 所示。
提议的解决方案
提议的解决方案是对 ebuild 使用 EAPI 后缀的文件扩展名。这允许包管理器从 ebuild 文件名中轻松读取 EAPI。它也向后兼容,因为当前 ebuild 通过.ebuild文件扩展名识别,因此包管理器会忽略 EAPI 后缀的 ebuild。
规范
Ebuild 文件名扩展名语法ebuild[-<EAPI>],其中[]表示可选部分,并且<EAPI>是 ebuild 的 EAPI。
ebuild 使用的 EAPI 是如果设置了文件名中包含的 EAPI。否则,将使用 ebuild 内部设置的 EAPI,默认为 0(这是当前行为)。
具有不受支持的 EAPI 的 ebuild 将被屏蔽。
在文件名和 ebuild 中同时设置 EAPI 应被视为错误。
示例
- pkg-1.ebuild,ebuild 内部未设置 EAPI
- EAPI 默认为 0。
- pkg-2.ebuild-1,ebuild 内部未设置 EAPI
- 使用 EAPI 1。
- pkg-3.ebuild-1, EAPI="1"
- 在两个地方都设置了 EAPI - 错误。
请注意,仍然不允许具有多个具有相同类别、包名称和版本的 ebuild。尽管它具有允许作者提供向后兼容的 ebuild 的优势,但它也会带来问题。第一个是需要严格的 EAPI 排序,第二个是确保单个类别/包版本的每个 ebuild 都等效,即安装其中的任何一个对给定系统具有完全相同的影响。
另请注意,这不是新的限制。已经可以非法地拥有具有不同 EAPI 的多个版本,例如1.0 == 1.00 == 1.00-r0因此,您可以拥有foo-1.0.ebuild使用 EAPI X 和foo-1.00.ebuild使用 EAPI Y。
想法总结
文件名中使用 EAPI 并进行一次性扩展更改
提议的文件名格式之一<PKG>-<VER>.eapi-<EAPI>.eb
- 属性
- 可以立即使用:是
- 影响性能:否
这等同于提议的解决方案。
有人说它更好,因为扩展名是静态的。
在 ebuild 内部轻松获取 EAPI
- 属性
- 可以立即使用:否
- 影响性能:是
无法立即使用,因为它会对旧的包管理器触发“当前行为”部分中显示的错误。
性能下降的原因是,在版本格式更改的情况下,包管理器需要 EAPI 来解析 ebuild 的版本。这意味着仅仅选择软件包的最佳版本就需要加载每个可用 ebuild 的 EAPI(来自缓存或 ebuild)。
以下是包管理器如何找出具有 N 个可用版本的软件包的最佳可用版本。
- 文件名中的 EAPI
- 读取包含软件包的目录 - readdir()
- 对于每个 ebuild,读取其 EAPI 并使用它解析其版本 - 无 I/O
- 对版本进行排序 - 无 I/O
- 从最高版本到最低版本依次向下
- 从缓存中获取元数据 - 2 x stat() + read()
- 如果版本可见,则中断
- ebuild 中的 EAPI
- 读取包含软件包的目录 - readdir()
- 对于每个 ebuild,从缓存中加载其元数据以获取其 EAPI - N x (2 x stat() + read())
- 对版本进行排序 - 无 I/O
- 从最高版本到最低版本依次向下
- (元数据已加载) - 无 I/O
- 如果版本可见,则中断 - 无 I/O
区别在于包管理器需要访问缓存多少个版本。使用 ebuild 中的 EAPI,它需要对所有版本执行此操作,使用文件名中的 EAPI,它取决于版本的可见性。例如,软件包 foo 的版本为 1、2、3、4、5 和 6。6 被屏蔽,5 为 ~arch,1、2、3 和 4 为 arch。假设用户仅接受此软件包的 arch。使用文件名中的 EAPI,它将仅读取版本 6、5 和 4 的元数据。使用 ebuild 中的 EAPI,它需要加载所有版本的元数据。
很难说平均情况是什么,但肯定最坏的情况(只有最低版本可见)并不常见。
在 ebuild 内部轻松获取 EAPI 并进行一次性扩展更改
- 属性
- 可以立即使用:是
- 影响性能:是
如上一节所述的性能下降。
有人说它清晰简单,也有人说它令人困惑且不直观,因为在其他情况下它是一个 bash 脚本,因此存在任意格式限制。
为不同的 EAPI 使用不同的子目录,例如 cat/pkg/eapiX/
- 属性
- 可以立即使用:是
- 影响性能:是
性能下降的原因是它增加了多个目录读取操作。
有人说它使得维护人员难以查看他们拥有的内容。
参考文献
[1] | GLEP 54,scm 软件包版本后缀 (https://gentoolinux.cn/glep/glep-0054.html) |
[2] | 常见的 portage 问题 (https://wiki.gentoo.org/wiki/Project:Portage/Common_problems) |
版权
此作品根据知识共享署名-相同方式共享 3.0 未移植许可获得许可。要查看此许可证的副本,请访问 https://creativecommons.org/licenses/by-sa/3.0/。