summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--man/make.conf.55
-rw-r--r--pym/_emerge/__init__.py14
-rw-r--r--pym/portage/__init__.py36
-rw-r--r--pym/portage/cache/util.py21
-rw-r--r--pym/portage/dbapi/porttree.py24
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)