Add support for FEATURES=parse-eapi-ebuild-head, which is similar to GLEP 55
authorZac Medico <zmedico@gentoo.org>
Fri, 27 Mar 2009 04:14:33 +0000 (04:14 -0000)
committerZac Medico <zmedico@gentoo.org>
Fri, 27 Mar 2009 04:14:33 +0000 (04:14 -0000)
except that the EAPI is parsed from the head of the ebuild (first 30 lines).
This feature is only intended for experimental purposes and should not be
enabled under normal circumstances. (trunk r13173)

svn path=/main/branches/2.1.6/; revision=13203

man/make.conf.5
pym/_emerge/__init__.py
pym/portage/__init__.py
pym/portage/cache/util.py
pym/portage/dbapi/porttree.py

index 1300f49f9137da88b999951cb1fe5d7ffec1eeff..e85fbd0d702b06bb52b79ba7f1cda574f34329e0 100644 (file)
@@ -269,6 +269,11 @@ Fetch in the background while compiling. Run
 `tail \-f /var/log/emerge\-fetch.log` in a
 terminal to view parallel-fetch progress.
 .TP
+.B parse\-eapi\-ebuild\-head
+Parse \fBEAPI\fR from the head of the ebuild (first 30 lines). This feature
+is only intended for experimental purposes and should not be enabled under
+normal circumstances.
+.TP
 .B protect\-owned
 This is identical to the \fIcollision\-protect\fR feature except that files
 may be overwritten if they are not explicitly listed in the contents of a
index c1999dd082bf1e3e7390a56d39a89d89a444a1eb..c9480d3dc89e89bbd76893bce0ba49e4502429b0 100644 (file)
@@ -4,6 +4,7 @@
 # $Id$
 
 import array
+import codecs
 from collections import deque
 import fcntl
 import formatter
@@ -3010,6 +3011,19 @@ class EbuildMetadataPhase(SubProcess):
                settings = self.settings
                settings.setcpv(self.cpv)
                ebuild_path = self.ebuild_path
+
+               if 'parse-eapi-ebuild-head' in settings.features:
+                       eapi = portage._parse_eapi_ebuild_head(codecs.open(ebuild_path,
+                               mode='r', encoding='utf_8', errors='replace'))
+                       if not portage.eapi_is_supported(eapi):
+                               self.metadata_callback(self.cpv, self.ebuild_path,
+                                       self.repo_path, {'EAPI' : eapi}, self.ebuild_mtime)
+                               self.returncode = os.EX_OK
+                               self.wait()
+                               return
+
+                       settings.configdict['pkg']['EAPI'] = eapi
+
                debug = settings.get("PORTAGE_DEBUG") == "1"
                master_fd = None
                slave_fd = None
index aa3c63b8b26908ca4ff8371bfa2b38571a9cdd52..8281d03edd29715669675e88352707b1ccad5e3c 100644 (file)
@@ -1780,6 +1780,9 @@ class config(object):
 
                        self["FEATURES"] = " ".join(sorted(self.features))
                        self.backup_changes("FEATURES")
+                       global _validate_cache_for_unsupported_eapis
+                       if 'parse-eapi-ebuild-head' in self.features:
+                               _validate_cache_for_unsupported_eapis = False
 
                        self._init_dirs()
 
@@ -5014,6 +5017,30 @@ def eapi_is_supported(eapi):
                return False
        return eapi <= portage.const.EAPI
 
+# Generally, it's best not to assume that cache entries for unsupported EAPIs
+# can be validated. However, the current package manager specification does not
+# guarantee that that the EAPI can be parsed without sourcing the ebuild, so
+# it's too costly to discard existing cache entries for unsupported EAPIs.
+# Therefore, by default, assume that cache entries for unsupported EAPIs can be
+# validated. If FEATURES=parse-eapi-* is enabled, this assumption is discarded
+# since the EAPI can be determined without the incurring the cost of sourcing
+# the ebuild.
+_validate_cache_for_unsupported_eapis = True
+
+_parse_eapi_ebuild_head_re = re.compile(r'^EAPI=[\'"]?([^\'"]*)')
+_parse_eapi_ebuild_head_max_lines = 30
+
+def _parse_eapi_ebuild_head(f):
+       count = 0
+       for line in f:
+               m = _parse_eapi_ebuild_head_re.match(line)
+               if m is not None:
+                       return m.group(1).strip()
+               count += 1
+               if count >= _parse_eapi_ebuild_head_max_lines:
+                       break
+       return '0'
+
 def doebuild_environment(myebuild, mydo, myroot, mysettings, debug, use_cache, mydbapi):
 
        ebuild_path = os.path.abspath(myebuild)
@@ -5086,6 +5113,15 @@ def doebuild_environment(myebuild, mydo, myroot, mysettings, debug, use_cache, m
        if portage.util.noiselimit < 0:
                mysettings["PORTAGE_QUIET"] = "1"
 
+       if mydo == 'depend' and \
+               'EAPI' not in mysettings.configdict['pkg'] and \
+               'parse-eapi-ebuild-head' in mysettings.features:
+               eapi = _parse_eapi_ebuild_head(codecs.open(ebuild_path,
+                       mode='r', encoding='utf_8', errors='replace'))
+               if not eapi_is_supported(eapi):
+                       raise portage.exception.UnsupportedAPIException(mycpv, eapi)
+               mysettings.configdict['pkg']['EAPI'] = eapi
+
        if mydo != "depend":
                # Metadata vars such as EAPI and RESTRICT are
                # set by the above config.setcpv() call.
index 9fcd4b49b1a7df8379438905c2fe4947a613e4e8..0f2685c0a96e8fc1c4030c7e543f42a69e58a5ee 100644 (file)
@@ -10,7 +10,8 @@ from portage.cache import cache_errors
 
 def mirror_cache(valid_nodes_iterable, src_cache, trg_cache, eclass_cache=None, verbose_instance=None):
 
-       from portage import eapi_is_supported
+       from portage import eapi_is_supported, \
+               _validate_cache_for_unsupported_eapis
        if not src_cache.complete_eclass_entries and not eclass_cache:
                raise Exception("eclass_cache required for cache's of class %s!" % src_cache.__class__)
 
@@ -39,6 +40,17 @@ def mirror_cache(valid_nodes_iterable, src_cache, trg_cache, eclass_cache=None,
                        noise.exception(x, ce)
                        del ce
                        continue
+
+               eapi = entry.get('EAPI')
+               if not eapi:
+                       eapi = '0'
+               eapi = eapi.lstrip('-')
+               eapi_supported = eapi_is_supported(eapi)
+               if not eapi_supported:
+                       if not _validate_cache_for_unsupported_eapis:
+                               noise.misc(x, "unable to validate cache for EAPI='%s'" % eapi)
+                               continue
+
                write_it = True
                trg = None
                try:
@@ -102,13 +114,10 @@ def mirror_cache(valid_nodes_iterable, src_cache, trg_cache, eclass_cache=None,
                                        continue
                                entry["_eclasses_"] = eclasses
 
-                       eapi = entry.get("EAPI")
-                       if not eapi:
-                               eapi = "0"
-                       if not eapi_is_supported(eapi):
+                       if not eapi_supported:
                                for k in set(entry).difference(("_mtime_", "_eclasses_")):
                                        entry[k] = ""
-                               entry["EAPI"] = "-" + eapi.lstrip("-")
+                               entry["EAPI"] = "-" + eapi
 
                        # by this time, if it reaches here, the eclass has been validated, and the entry has 
                        # been updated/translated (if needs be, for metadata/cache mainly)
index 077715239aadbe4b3217f129d27c1eb55c34e815..4cbf7af303218531fdcf06b8a750662b181c199c 100644 (file)
@@ -25,7 +25,7 @@ from portage import eclass_cache, auxdbkeys, doebuild, flatten, \
        listdir, dep_expand, eapi_is_supported, key_expand, dep_check, \
        _eapi_is_deprecated
 
-import os, stat
+import codecs, os, stat
 from itertools import izip
 
 def _src_uri_validate(cpv, eapi, src_uri):
@@ -419,12 +419,22 @@ class portdbapi(dbapi):
 
                        self.doebuild_settings.setcpv(mycpv)
                        mydata = {}
-                       myret = doebuild(myebuild, "depend",
-                               self.doebuild_settings["ROOT"], self.doebuild_settings,
-                               dbkey=mydata, tree="porttree", mydbapi=self)
-                       if myret != os.EX_OK:
-                               self._broken_ebuilds.add(myebuild)
-                               raise KeyError(mycpv)
+                       eapi = None
+
+                       if 'parse-eapi-ebuild-head' in self.doebuild_settings.features:
+                               eapi = portage._parse_eapi_ebuild_head(codecs.open(myebuild,
+                                       mode='r', encoding='utf_8', errors='replace'))
+                               self.doebuild_settings.configdict['pkg']['EAPI'] = eapi
+
+                       if eapi is not None and not portage.eapi_is_supported(eapi):
+                               mydata['EAPI'] = eapi
+                       else:
+                               myret = doebuild(myebuild, "depend",
+                                       self.doebuild_settings["ROOT"], self.doebuild_settings,
+                                       dbkey=mydata, tree="porttree", mydbapi=self)
+                               if myret != os.EX_OK:
+                                       self._broken_ebuilds.add(myebuild)
+                                       raise KeyError(mycpv)
 
                        self._metadata_callback(
                                mycpv, myebuild, mylocation, mydata, emtime)