GLEP:55
Title:Use EAPI-suffixed ebuilds (.ebuild-EAPI)
Version:1.5
Last-Modified:2009/05/17 20:56:53
Author:Piotr JaroszyƄski <peper at gentoo.org>
Status:Draft
Type:Standards Track
Content-Type:text/x-rst
Created:17-Dec-2007
Post-History:17-Dec-2007, 22-Dec-2007, 17-May-2009

Contents

"A little learning is a dangerous thing; drink deep, or taste not the Pierian spring: there shallow draughts intoxicate the brain, and drinking largely sobers us again."

—Alexander Pope, An Essay on Criticism

Abstract

This GLEP proposes usage of EAPI-suffixed file extensions for ebuilds (for example, foo-1.2.3.ebuild-1).

Problem

The current way of specifying the EAPI in ebuilds is flawed. In order to get the EAPI the package manager needs to source the ebuild, which itself needs the EAPI in the first place. Otherwise it imposes a serious limitation, namely every ebuild, using any of the future EAPIs, will have to be source'able by old package managers and hence there is no way to do any of the following:

Current behaviour

Following subsections show what happens if you introduce any of the mentioned changes in an ebuild and try to install it with portage 2.1.6.13.

Incompatible change of inherit (e.g. make it look in the package dir too)

sys-apps/foo-1.ebuild:

EAPI="5"
inherit "foo"

DESCRIPTION=""
HOMEPAGE=""
SRC_URI=""
...

Result:

*
* 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)

Current portage looks for eclasses only in the eclass directory of a repository. This results in a fatal error and ebuild being masked by corruption - might be pretty confusing to users.

New global scope function

sys-apps/foo-1.ebuild:

EAPI="5"
new_global_scope_function "foo"

DESCRIPTION=""
HOMEPAGE=""
SRC_URI=""
...

Result:

/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.

Not that bad as user is advised to upgrade portage.

New version format

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"

Not the best error message, especially if there are lots of them.

Use newer bash features

|& is a new type of redirection added in bash-4. It cannot be used even in local scope as bash still parses the whole ebuild.

sys-apps/foo-1.ebuild:

EAPI="5"

foo() {
   echo "foo" |& cat
}

Result:

/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)

Again, not the best error.

Abstract solution

A solution to this problem has to lift those limitations and the only way to do it is to make the EAPI of an ebuild available to the package managers in a way that doesn't require them to source the ebuild. Another important requirement is for the solution to be backward compatible, which has the pleasant side-effect of making the solution applicable in the Gentoo tree right away. Opposed to waiting an arbitrary amount of time, which is never long enough anyway, as the issues listed on the common portage problems page - [2] - show.

Proposed solution

The proposed solution is to use EAPI-suffixed file extensions for ebuilds. This allows package managers to trivially read the EAPI from the ebuild filename. It is also backwards compatible, because currently ebuilds are recognised by the .ebuild file extension and hence EAPI-suffixed ebuilds are simply ignored by the package managers.

Specification

Ebuild filename extension syntax: ebuild[-<EAPI>], where [] denotes an optional part, and <EAPI> is the EAPI of the ebuild.

The EAPI used by the ebuild is the EAPI included in the filename if it is set. Otherwise the EAPI set inside the ebuild is used, which defaults to 0 (this is the current behaviour).

Ebuilds with unsupported EAPIs are masked.

It should be considered an error to set the EAPI both in the filename and in the ebuild.

Examples:

Note that it is still not permitted to have more than one ebuild with equal category, package name, and version. Although it would have the advantage of allowing authors to provide backwards compatible ebuilds, it would introduce problems too. The first is the requirement to have strict EAPI ordering, the second is ensuring that all the ebuilds for a single category/package-version are equivalent, i.e. installing any of them has exactly the same effect on a given system.

Also note that it is not a new restriction. It is already possible to illegally have multiple versions with different EAPIs as e.g. 1.0 == 1.00 == 1.00-r0 and hence you could have foo-1.0.ebuild with EAPI X and foo-1.00.ebuild with EAPI Y.

Summary of ideas

EAPI-suffixed ebuilds (proposed solution)

Properties:
  • Can be used right away: yes
  • Hurts performance: no

Some say it is clear and simple, others that it is ugly and unintuitive.

EAPI in the filename with one-time extension change

One of the proposed filename formats: <PKG>-<VER>.eapi-<EAPI>.eb

Properties:
  • Can be used right away: yes
  • Hurts performance: no

This is equivalent to the proposed solution.

Some say it is better because the extension is static.

Easily fetchable EAPI inside the ebuild

Properties:
  • Can be used right away: no
  • Hurts performance: yes

Cannot be used right away as it would trigger the errors shown in Current behaviour section for old package managers.

Performance decrease comes from the fact that with version format changes in the picture package managers need EAPI to parse the ebuild's version. That means that merely picking the best version of a package requires loading EAPI (from cache or the ebuild) for each available ebuild.

Here is more or less how the package manager figures out the best available version for a package with N versions available.

  • EAPI in the filename
    • Read the directory containing the package - readdir()
    • For each ebuild, read its EAPI and using that parse its version - no I/O
    • Sort the versions - no I/O
    • Going down from the highest to the lowest version
      • Get the metadata from cache - 2 x stat() + read()
      • break if the version is visible
  • EAPI in the ebuild
    • Read the directory containing the package - readdir()
    • For each ebuild load its metadata from cache to get its EAPI - N x (2 x stat() + read())
    • Sort the versions - no I/O
    • Going down from the highest to the lowest version
      • (metadata is already loaded) - no I/O
      • break if the version is visible - no I/O

The difference is in for how many versions the package manager needs to hit cache. With EAPI in the ebuild it needs to do that for all versions, with EAPI in the filename it depends on versions visibility. For example, package foo has versions 1, 2, 3, 4, 5 and 6. 6 is masked, 5 is ~arch and 1,2,3 and 4 are arch. Say, the user accepts only arch for this package. With EAPI in the filename it will read metadata only for versions 6, 5 and 4. With EAPI in the ebuild it needs to load metadata for all versions.

It's hard to say what's the avarage case, but surely the worst case scenario (when only the lowest version is visible) is uncommon.

Easily fetchable EAPI inside the ebuild and one-time extension change

Properties:
  • Can be used right away: yes
  • Hurts performance: yes

Performance decrease as described in the previous section.

Some say it is clear and simple, others that it is confusing and unintuitive, because of the arbitrary format restrictions in what is a bash script otherwise.

Use different subdirectories for different EAPIs, i.e. cat/pkg/eapiX/

Properties:
  • Can be used right away: yes
  • Hurts performance: yes

Performance decrease comes from the fact that it adds several more directory reads.

Some say that it makes it much harder for maintainers to see what they have.

References

[1]GLEP 54, scm package version suffix (http://glep.gentoo.org/glep-0054.html)
[2]Common portage problems (http://www.gentoo.org/proj/en/portage/doc/common-problems.xml)