use dep_getkey for atom extraction to allow non existing versions and packages, added unit test to verify behaviour

This commit is contained in:
Robin Lutz 2017-09-05 09:34:54 +02:00
parent b3aa9ab394
commit ba7d00f58e
3 changed files with 131 additions and 29 deletions

View File

@ -75,9 +75,20 @@ def _porttree():
def _p_to_cp(p):
ret = _porttree().dbapi.xmatch("match-all", p)
try:
ret = portage.dep_getkey(p)
if ret:
return portage.cpv_getkey(ret[0])
return ret
except portage.exception.InvalidAtom:
pass
try:
ret = _porttree().dbapi.xmatch('bestmatch-visible', p)
if ret:
return portage.dep_getkey(ret)
except portage.exception.InvalidAtom:
pass
return None
@ -91,10 +102,13 @@ def _allnodes():
def _cpv_to_cp(cpv):
ret = portage.cpv_getkey(cpv)
try:
ret = portage.dep_getkey(cpv)
if ret:
return ret
else:
except portage.exception.InvalidAtom:
pass
return cpv

View File

@ -75,6 +75,8 @@ def _get_config_file(conf, atom):
if parts.cp == '*/*':
# parts.repo will be empty if there is no repo part
relative_path = parts.repo or "gentoo"
elif str(parts.cp).endswith('/*'):
relative_path = str(parts.cp).split("/")[0] + "_"
else:
relative_path = os.path.join(*[x for x in os.path.split(parts.cp) if x != '*'])
else:
@ -92,9 +94,20 @@ def _p_to_cp(p):
Convert a package name or a DEPEND atom to category/package format.
Raises an exception if program name is ambiguous.
'''
ret = _porttree().dbapi.xmatch("match-all", p)
try:
ret = portage.dep_getkey(p)
if ret:
return portage.cpv_getkey(ret[0])
return ret
except portage.exception.InvalidAtom:
pass
try:
ret = _porttree().dbapi.xmatch('bestmatch-visible', p)
if ret:
return portage.dep_getkey(ret)
except portage.exception.InvalidAtom:
pass
return None
@ -188,12 +201,7 @@ def _package_conf_file_to_dir(file_name):
else:
os.rename(path, path + '.tmpbak')
os.mkdir(path, 0o755)
with salt.utils.files.fopen(path + '.tmpbak') as fh_:
for line in fh_:
line = line.strip()
if line and not line.startswith('#'):
append_to_package_conf(file_name, string=line)
os.remove(path + '.tmpbak')
os.rename(path + '.tmpbak', os.path.join(path, 'tmp'))
return True
else:
os.mkdir(path, 0o755)
@ -218,7 +226,7 @@ def _package_conf_ordering(conf, clean=True, keep_backup=False):
shutil.copy(file_path, file_path + '.bak')
backup_files.append(file_path + '.bak')
if cp[0] == '/' or cp.split('/') > 2:
if cp[0] == '/' or len(cp.split('/')) > 2:
with salt.utils.files.fopen(file_path) as fp_:
rearrange.extend(fp_.readlines())
os.remove(file_path)

View File

@ -7,11 +7,14 @@
'''
# Import Python libs
from __future__ import absolute_import
import re
# Import Salt Testing libs
from tests.support.mixins import LoaderModuleMockMixin
from tests.support.unit import skipIf, TestCase
from tests.support.mock import NO_MOCK, NO_MOCK_REASON, MagicMock, patch
from tests.support.paths import TMP
import salt.utils.files
# Import salt libs
import salt.modules.portage_config as portage_config
@ -19,13 +22,42 @@ import salt.modules.portage_config as portage_config
@skipIf(NO_MOCK, NO_MOCK_REASON)
class PortageConfigTestCase(TestCase, LoaderModuleMockMixin):
class DummyAtom(object):
def __init__(self, atom):
self.cp, self.repo = atom.split("::") if "::" in atom else (atom, None)
def __init__(self):
self.cp = None
self.repo = None
def __call__(self, atom, *_, **__):
if atom == '#' or isinstance(atom, MagicMock):
self.repo = None
self.cp = None
return self
# extract (and remove) repo
atom, self.repo = atom.split('::') if '::' in atom else (atom, None)
# remove '>, >=, <=, =, ~' etc.
atom = re.sub('[<>~+=]', '', atom)
# remove slots
atom = re.sub(':[0-9][^:]*', '', atom)
# remove version
atom = re.sub('-[0-9][\.0-9]*', '', atom)
self.cp = atom
return self
def setup_loader_modules(self):
try:
import portage
return {}
except:
dummy_atom = self.DummyAtom()
self.portage = MagicMock()
self.portage.dep.Atom = MagicMock(side_effect=dummy_atom)
self.portage.dep_getkey = MagicMock(side_effect=lambda x: dummy_atom(x).cp)
self.portage.exception.InvalidAtom = Exception
self.addCleanup(delattr, self, 'portage')
return {portage_config: {'portage': self.portage}}
@ -33,13 +65,61 @@ class PortageConfigTestCase(TestCase, LoaderModuleMockMixin):
pairs = [
('*/*::repo', '/etc/portage/package.mask/repo'),
('*/pkg::repo', '/etc/portage/package.mask/pkg'),
('cat/*', '/etc/portage/package.mask/cat'),
('cat/*', '/etc/portage/package.mask/cat_'),
('cat/pkg', '/etc/portage/package.mask/cat/pkg'),
('cat/pkg::repo', '/etc/portage/package.mask/cat/pkg'),
]
for (atom, expected) in pairs:
dummy_atom = self.DummyAtom(atom)
self.portage.dep.Atom = MagicMock(return_value=dummy_atom)
with patch.object(portage_config, '_p_to_cp', MagicMock(return_value=dummy_atom.cp)):
self.assertEqual(portage_config._get_config_file('mask', atom), expected)
def test_enforce_nice_config(self):
atoms = [
('*/*::repo', 'repo'),
('*/pkg1::repo', 'pkg1'),
('cat/*', 'cat_'),
('cat/pkg2', 'cat/pkg2'),
('cat/pkg3::repo', 'cat/pkg3'),
('<cat/pkg4-0.0.0.0', 'cat/pkg4'),
('>cat/pkg5-0.0.0.0:0', 'cat/pkg5'),
('>cat/pkg6-0.0.0.0:0::repo', 'cat/pkg6'),
('<=cat/pkg7-0.0.0.0', 'cat/pkg7'),
('=cat/pkg8-0.0.0.0', 'cat/pkg8'),
]
supported = [
('accept_keywords', ['~amd64']),
('env', ['glibc.conf']),
('license', ['LICENCE1', 'LICENCE2']),
('mask', ['']),
('properties', ['* -interactive']),
('unmask', ['']),
('use', ['apple', '-banana', 'ananas', 'orange']),
]
base_path = TMP + '/package.{0}'
def make_line(atom, addition):
return atom + (' ' + addition if addition != '' else '') + '\n'
for typ, additions in supported:
path = base_path.format(typ)
with salt.utils.files.fopen(path, 'a') as fh:
for atom, _ in atoms:
for addition in additions:
line = make_line(atom, addition)
fh.write('# comment for: ' + line)
fh.write(line)
with patch.object(portage_config, 'BASE_PATH', base_path):
with patch.object(portage_config, '_merge_flags', lambda l1, l2, _: list(set(l1 + l2))):
portage_config.enforce_nice_config()
for typ, additions in supported:
for atom, file_name in atoms:
with salt.utils.files.fopen(base_path.format(typ) + "/" + file_name, 'r') as fh:
for line in fh:
self.assertTrue(atom in line, msg="'{}' not in '{}'".format(addition, line))
for addition in additions:
self.assertTrue(addition in line, msg="'{}' not in '{}'".format(addition, line))