summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pym/portage/dep/__init__.py162
-rw-r--r--pym/portage/package/ebuild/config.py45
-rw-r--r--pym/portage/sets/base.py12
-rw-r--r--pym/portage/tests/dep/testAtom.py6
-rw-r--r--pym/portage/tests/dep/testExtendedAtomDict.py18
-rw-r--r--pym/portage/tests/dep/test_best_match_to_list.py4
6 files changed, 173 insertions, 74 deletions
diff --git a/pym/portage/dep/__init__.py b/pym/portage/dep/__init__.py
index e6f2362b1..c276edbea 100644
--- a/pym/portage/dep/__init__.py
+++ b/pym/portage/dep/__init__.py
@@ -33,7 +33,7 @@ import portage.exception
from portage.exception import InvalidData, InvalidAtom
from portage.localization import _
from portage.versions import catpkgsplit, catsplit, \
- pkgcmp, pkgsplit, ververify, _cat, _pkg, _cp, _cpv
+ pkgcmp, pkgsplit, ververify, _cp, _cpv
import portage.cache.mappings
if sys.hexversion >= 0x3000000:
@@ -602,15 +602,20 @@ class Atom(_atom_base):
blocker = False
self.__dict__['blocker'] = blocker
m = _atom_re.match(s)
+ extended_syntax = False
if m is None:
if allow_wildcard:
m = _atom_wildcard_re.match(s)
if m is None:
raise InvalidAtom(self)
op = None
- cpv = cp = m.groupdict()['simple']
- slot = None
+ gdict = m.groupdict()
+ cpv = cp = gdict['simple']
+ if cpv.find("**") != -1:
+ raise InvalidAtom(self)
+ slot = gdict['slot']
use_str = None
+ extended_syntax = True
else:
raise InvalidAtom(self)
elif m.group('op') is not None:
@@ -644,6 +649,7 @@ class Atom(_atom_base):
self.__dict__['cpv'] = cpv
self.__dict__['slot'] = slot
self.__dict__['operator'] = op
+ self.__dict__['extended_syntax'] = extended_syntax
if use_str is not None:
use = _use_dep(dep_getusedeps(s))
@@ -748,6 +754,107 @@ class Atom(_atom_base):
memo[id(self)] = self
return self
+def extended_cp_match(extended_atom, other):
+ """
+ Checks if an extended syntax atom matches the other, non extended atom
+ """
+ my_slot = dep_getslot(extended_atom)
+ if my_slot is not None:
+ extended_atom = extended_atom[:-(len(my_slot)+1)]
+ mysplit = catsplit(extended_atom)
+ my_cat = mysplit[0]
+ my_pkg = mysplit[1]
+
+ other_slot = dep_getslot(other)
+ if other_slot is not None:
+ other = other[:-(len(other_slot)+1)]
+ othersplit = catsplit(other)
+ other_cat = othersplit[0]
+ other_pkg = othersplit[1]
+
+ if my_slot is not None and other_slot is not None and \
+ my_slot != other_slot:
+ return False
+
+ for my_val, other_val in ((my_cat, other_cat), (my_pkg, other_pkg)):
+ if my_val == "*":
+ continue
+
+ start = 0
+ parts = my_val.split("*")
+ for id, part in enumerate(parts):
+ if not part:
+ if id == len(parts)-1:
+ start = len(other_val)
+ continue
+ start = other_val.find(part, start)
+ if start == -1:
+ return False
+
+ start += len(part)
+
+ if start != len(other_val):
+ return False
+
+ return True
+
+class ExtendedAtomDict(object):
+ """
+ dict() wrapper that supports extended atoms as keys and allows lookup
+ of a normal cp against other normal cp and extended cp.
+ The value type has to be given to __init__ and is assumed to be the same
+ for all values.
+ """
+ def __init__(self, value_class):
+ self._extended = {}
+ self._normal = {}
+ self._value_class = value_class
+
+ def setdefault(self, cp, default=None):
+ if "*" in cp:
+ return self._extended.setdefault(cp, default)
+ else:
+ return self._normal.setdefault(cp, default)
+
+ def get(self, cp):
+ ret = self._value_class()
+ normal_match = self._normal.get(cp)
+ if normal_match is not None:
+ if hasattr(ret, "update"):
+ ret.update(normal_match)
+ elif hasattr(ret, "extend"):
+ ret.extend(normal_match)
+ else:
+ raise NotImplementedError()
+
+ for extended_cp in self._extended:
+ if extended_cp_match(extended_cp, cp):
+ if hasattr(ret, "update"):
+ ret.update(self._extended[extended_cp])
+ elif hasattr(ret, "extend"):
+ ret.extend(self._extended[extended_cp])
+ else:
+ raise NotImplementedError()
+
+ return ret
+
+ def __setitem__(self, cp, val):
+ if "*" in cp:
+ self._extended[cp] = val
+ else:
+ self._normal[cp] = val
+
+ def __getitem__(self, cp):
+ if "*" in cp:
+ return self._extended[cp]
+ else:
+ return self._normal[cp]
+
+ def clear(self):
+ self._extended.clear()
+ self._normal.clear()
+
+
def get_operator(mydep):
"""
Return the operator used in a depstring.
@@ -945,7 +1052,11 @@ _atom_re = re.compile('^(?P<without_use>(?:' +
'(?P<op>' + _op + _cpv + ')|' +
'(?P<star>=' + _cpv + r'\*)|' +
'(?P<simple>' + _cp + '))(:' + _slot + ')?)(' + _use + ')?$', re.VERBOSE)
-_atom_wildcard_re = re.compile('(?P<simple>((' + _cat + '|\*)/(' + _pkg + '|\*)))$')
+
+_extended_cat = r'[\w+*][\w+.*-]*'
+_extended_pkg = r'[\w+*][\w+*-]*?'
+
+_atom_wildcard_re = re.compile('(?P<simple>(' + _extended_cat + ')/(' + _extended_pkg + '))(:(?P<slot>' + _slot + '))?$')
def isvalidatom(atom, allow_blockers=False, allow_wildcard=False):
"""
@@ -1103,30 +1214,29 @@ def best_match_to_list(mypkg, mylist):
- >=cpv 2
- <=cpv 2
- cp 1
- - */p 0
- - c/* 0
- - */* -1
+ - cp:slot with extended syntax 0
+ - cp with extended syntax -1
"""
operator_values = {'=':6, '~':5, '=*':4,
'>':2, '<':2, '>=':2, '<=':2, None:1}
maxvalue = -2
bestm = None
for x in match_to_list(mypkg, mylist):
+ if x.extended_syntax:
+ if dep_getslot(x) is not None:
+ if maxvalue < 0:
+ maxvalue = 0
+ bestm = x
+ else:
+ if maxvalue < -1:
+ maxvalue = -1
+ bestm = x
+ continue
if dep_getslot(x) is not None:
if maxvalue < 3:
maxvalue = 3
bestm = x
op_val = operator_values[x.operator]
- if x.operator is None:
- c, p = catsplit(x)
- if c == "*":
- if p == "*":
- op_val = -1
- else:
- op_val = 0
- elif p == "*":
- op_val = 0
-
if op_val > maxvalue:
maxvalue = op_val
bestm = x
@@ -1183,18 +1293,14 @@ def match_from_list(mydep, candidate_list):
if cp is None:
mysplit = catpkgsplit(remove_slot(x))
if mysplit is not None:
- c = mysplit[0]
- p = mysplit[1]
- else:
- continue
- else:
- mysplit = catsplit(cp)
- c = mysplit[0]
- p = mysplit[1]
+ cp = mysplit[0] + '/' + mysplit[1]
+
+ if cp is None:
+ continue
- if cat in (c, "*") and pkg in (p, "*"):
+ if cp == mycpv or (mydep.extended_syntax and \
+ extended_cp_match(mycpv, cp)):
mylist.append(x)
-
elif operator == "=": # Exact match
for x in candidate_list:
@@ -1270,7 +1376,7 @@ def match_from_list(mydep, candidate_list):
else:
raise KeyError(_("Unknown operator: %s") % mydep)
- if slot is not None:
+ if slot is not None and not mydep.extended_syntax:
candidate_list = mylist
mylist = []
for x in candidate_list:
diff --git a/pym/portage/package/ebuild/config.py b/pym/portage/package/ebuild/config.py
index c7aa42d20..a58cd0c3b 100644
--- a/pym/portage/package/ebuild/config.py
+++ b/pym/portage/package/ebuild/config.py
@@ -771,11 +771,11 @@ class config(object):
self["EROOT"] = target_root
self.backup_changes("EROOT")
- self.pusedict = {}
- self.pkeywordsdict = {}
- self._plicensedict = {}
- self._ppropertiesdict = {}
- self.punmaskdict = {}
+ self.pusedict = portage.dep.ExtendedAtomDict(dict)
+ self.pkeywordsdict = portage.dep.ExtendedAtomDict(dict)
+ self._plicensedict = portage.dep.ExtendedAtomDict(dict)
+ self._ppropertiesdict = portage.dep.ExtendedAtomDict(dict)
+ self.punmaskdict = portage.dep.ExtendedAtomDict(list)
abs_user_config = os.path.join(config_root, USER_CONFIG_PATH)
# locations for "categories" and "arch.list" files
@@ -922,7 +922,7 @@ class config(object):
pkgmasklines = stack_lists(pkgmasklines, incremental=1)
pkgunmasklines = stack_lists(pkgunmasklines, incremental=1)
- self.pmaskdict = {}
+ self.pmaskdict = portage.dep.ExtendedAtomDict(list)
for x in pkgmasklines:
self.pmaskdict.setdefault(x.cp, []).append(x)
@@ -1497,11 +1497,7 @@ class config(object):
has_changed = True
oldpuse = self.puse
self.puse = ""
- cpdict = {}
- cpdict.update(self.pusedict.get("*/*", {}))
- cpdict.update(self.pusedict.get(cat+"/*", {}))
- cpdict.update(self.pusedict.get("*/"+cp.split("/")[1], {}))
- cpdict.update(self.pusedict.get(cp, {}))
+ cpdict = self.pusedict.get(cp)
if cpdict:
keys = list(cpdict)
while keys:
@@ -1714,19 +1710,10 @@ class config(object):
"""
cp = cpv_getkey(cpv)
- c, p = catsplit(cp)
- mask_atoms = []
- mask_atoms.extend(self.pmaskdict.get("*/*", []))
- mask_atoms.extend(self.pmaskdict.get(c+"/*", []))
- mask_atoms.extend(self.pmaskdict.get("*/"+p, []))
- mask_atoms.extend(self.pmaskdict.get(cp, []))
+ mask_atoms = self.pmaskdict.get(cp)
if mask_atoms:
pkg_list = ["%s:%s" % (cpv, metadata["SLOT"])]
- unmask_atoms = []
- unmask_atoms.extend(self.punmaskdict.get("*/*", []))
- unmask_atoms.extend(self.punmaskdict.get(c+"/*", []))
- unmask_atoms.extend(self.punmaskdict.get("*/"+p, []))
- unmask_atoms.extend(self.punmaskdict.get(cp, []))
+ unmask_atoms = self.punmaskdict.get(cp)
for x in mask_atoms:
if not match_from_list(x, pkg_list):
continue
@@ -1874,12 +1861,7 @@ class config(object):
"""
accept_license = self._accept_license
cp = cpv_getkey(cpv)
- c, p = catsplit(cp)
- cpdict = {}
- cpdict.update(self._plicensedict.get("*/*", {}))
- cpdict.update(self._plicensedict.get(c+"/*", {}))
- cpdict.update(self._plicensedict.get("*/"+p, {}))
- cpdict.update(self._plicensedict.get(cp, {}))
+ cpdict = self._plicensedict.get(cp)
if cpdict:
accept_license = list(self._accept_license)
cpv_slot = "%s:%s" % (cpv, metadata["SLOT"])
@@ -1959,12 +1941,7 @@ class config(object):
"""
accept_properties = self._accept_properties
cp = cpv_getkey(cpv)
- c, p = catsplit(cp)
- cpdict = {}
- cpdict.update(self._ppropertiesdict.get("*/*", {}))
- cpdict.update(self._ppropertiesdict.get(c+"/*", {}))
- cpdict.update(self._ppropertiesdict.get("*/"+p, {}))
- cpdict.update(self._ppropertiesdict.get(cp, {}))
+ cpdict = self._ppropertiesdict.get(cp)
if cpdict:
accept_properties = list(self._accept_properties)
cpv_slot = "%s:%s" % (cpv, metadata["SLOT"])
diff --git a/pym/portage/sets/base.py b/pym/portage/sets/base.py
index 108dda3ec..a143b8272 100644
--- a/pym/portage/sets/base.py
+++ b/pym/portage/sets/base.py
@@ -2,7 +2,7 @@
# Distributed under the terms of the GNU General Public License v2
import sys
-from portage.dep import Atom, best_match_to_list, match_from_list
+from portage.dep import Atom, ExtendedAtomDict, best_match_to_list, match_from_list
from portage.exception import InvalidAtom
from portage.versions import catsplit, cpv_getkey
@@ -21,7 +21,7 @@ class PackageSet(object):
def __init__(self):
self._atoms = set()
- self._atommap = {}
+ self._atommap = ExtendedAtomDict(set)
self._loaded = False
self._loading = False
self.errors = []
@@ -140,15 +140,9 @@ class PackageSet(object):
"""
cpv_slot_list = [pkg]
cp = cpv_getkey(pkg.cpv)
- c, p = catsplit(cp)
self._load() # make sure the atoms are loaded
- atoms = set()
- atoms.update(self._atommap.get("*/*", set()))
- atoms.update(self._atommap.get(c+"/*", set()))
- atoms.update(self._atommap.get("*/"+p, set()))
- atoms.update(self._atommap.get(cp, set()))
-
+ atoms = self._atommap.get(cp)
if atoms:
for atom in atoms:
if match_from_list(atom, cpv_slot_list):
diff --git a/pym/portage/tests/dep/testAtom.py b/pym/portage/tests/dep/testAtom.py
index 091cef3a2..a4972905c 100644
--- a/pym/portage/tests/dep/testAtom.py
+++ b/pym/portage/tests/dep/testAtom.py
@@ -27,7 +27,11 @@ class TestAtom(TestCase):
( "sys-apps/*",
(None, 'sys-apps/*', None, None, None), True ),
( "*/portage",
- (None, '*/portage', None, None, None), True )
+ (None, '*/portage', None, None, None), True ),
+ ( "s*s-*/portage:1",
+ (None, 's*s-*/portage', None, '1', None), True ),
+ ( "*/po*ge:2",
+ (None, '*/po*ge', None, '2', None), True ),
]
tests_xfail = [
diff --git a/pym/portage/tests/dep/testExtendedAtomDict.py b/pym/portage/tests/dep/testExtendedAtomDict.py
new file mode 100644
index 000000000..702bec196
--- /dev/null
+++ b/pym/portage/tests/dep/testExtendedAtomDict.py
@@ -0,0 +1,18 @@
+# test_isvalidatom.py -- Portage Unit Testing Functionality
+# Copyright 2006 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from portage.tests import TestCase
+from portage.dep import ExtendedAtomDict
+
+class TestExtendedAtomDict(TestCase):
+
+ def testExtendedAtomDict(self):
+ d = ExtendedAtomDict(dict)
+ d["*/*"] = { "test1": "x" }
+ d["dev-libs/*"] = { "test2": "y" }
+ d.setdefault("sys-apps/portage", {})["test3"] = "z"
+ self.assertEqual(d.get("dev-libs/A"), { "test1": "x", "test2": "y" })
+ self.assertEqual(d.get("sys-apps/portage"), { "test1": "x", "test3": "z" })
+ self.assertEqual(d["dev-libs/*"], { "test2": "y" })
+ self.assertEqual(d["sys-apps/portage"], { "test3": "z" })
diff --git a/pym/portage/tests/dep/test_best_match_to_list.py b/pym/portage/tests/dep/test_best_match_to_list.py
index c5f4fbbc0..d050adc51 100644
--- a/pym/portage/tests/dep/test_best_match_to_list.py
+++ b/pym/portage/tests/dep/test_best_match_to_list.py
@@ -31,12 +31,12 @@ class Test_best_match_to_list(TestCase):
[Atom("=dev-libs/A-1:0")]),
("dev-libs/A-1", [Atom("dev-libs/*", allow_wildcard=True), Atom("=dev-libs/A-1:0")], \
[Atom("=dev-libs/A-1:0"), Atom("dev-libs/*", allow_wildcard=True)]),
- ("dev-libs/A-1", [Atom("*/*", allow_wildcard=True), Atom("dev-libs/*", allow_wildcard=True), \
+ ("dev-libs/A-1:0", [Atom("dev-*/*", allow_wildcard=True), Atom("dev-*/*:0", allow_wildcard=True),\
Atom("dev-libs/A"), Atom("<=dev-libs/A-2"), Atom("dev-libs/A:0"), \
Atom("=dev-libs/A-1*"), Atom("~dev-libs/A-1"), Atom("=dev-libs/A-1")], \
[Atom("=dev-libs/A-1"), Atom("~dev-libs/A-1"), Atom("=dev-libs/A-1*"), \
Atom("dev-libs/A:0"), Atom("<=dev-libs/A-2"), Atom("dev-libs/A"), \
- Atom("dev-libs/*", allow_wildcard=True), Atom("*/*", allow_wildcard=True)])
+ Atom("dev-*/*:0", allow_wildcard=True), Atom("dev-*/*", allow_wildcard=True)])
]
for pkg, atom_list, result in tests: