diff options
-rw-r--r-- | man/make.conf.5 | 5 | ||||
-rw-r--r-- | pym/_emerge/__init__.py | 14 | ||||
-rw-r--r-- | pym/portage/__init__.py | 36 | ||||
-rw-r--r-- | pym/portage/cache/util.py | 21 | ||||
-rw-r--r-- | pym/portage/dbapi/porttree.py | 24 |
5 files changed, 87 insertions, 13 deletions
diff --git a/man/make.conf.5 b/man/make.conf.5 index 2f9c36509..268fd4c81 100644 --- a/man/make.conf.5 +++ b/man/make.conf.5 @@ -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 preserve\-libs Preserve libraries when the sonames change during upgrade or downgrade. Libraries are preserved only if consumers of those libraries are detected. diff --git a/pym/_emerge/__init__.py b/pym/_emerge/__init__.py index 17fec42d1..76acb8a16 100644 --- a/pym/_emerge/__init__.py +++ b/pym/_emerge/__init__.py @@ -4,6 +4,7 @@ # $Id$ import array +import codecs from collections import deque import fcntl import formatter @@ -3029,6 +3030,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 diff --git a/pym/portage/__init__.py b/pym/portage/__init__.py index f56c64471..5c1cc1735 100644 --- a/pym/portage/__init__.py +++ b/pym/portage/__init__.py @@ -1790,6 +1790,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() @@ -5024,6 +5027,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) @@ -5096,6 +5123,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. diff --git a/pym/portage/cache/util.py b/pym/portage/cache/util.py index 9fcd4b49b..0f2685c0a 100644 --- a/pym/portage/cache/util.py +++ b/pym/portage/cache/util.py @@ -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) diff --git a/pym/portage/dbapi/porttree.py b/pym/portage/dbapi/porttree.py index 077715239..4cbf7af30 100644 --- a/pym/portage/dbapi/porttree.py +++ b/pym/portage/dbapi/porttree.py @@ -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) |