Добработан Eix для использования вывода различными парсерами

master-3.5 3.5.7_beta3
Mike Hiretsky 7 years ago
parent 09d761cf74
commit 999420dcd9

@ -38,7 +38,7 @@ from collections import Mapping, defaultdict
from .common import getTupleVersion
from contextlib import closing
from functools import total_ordering
from itertools import ifilter, imap, chain
from itertools import ifilter, imap, chain, groupby
Colors = TextState.Colors
import glob
@ -762,6 +762,7 @@ class Eix(object):
Xml = '--xml'
Upgrade = '--upgrade'
TestObsolete = '--test-obsolete'
Exact = "--exact"
default_options = [Option.Xml]
@ -770,20 +771,22 @@ class Eix(object):
self.package = list(package)
else:
self.package = [package]
self.options = list(options) + self.package + self.default_options
self._options = options
self.no_default = kwargs.get('no_default', False)
if not kwargs.get('all_versions', False):
self.__get_versions = self._get_versions
self._get_versions = self._get_best_version
self.parser = EixFullnameParserBestVersion()
else:
self.parser = EixFullnameParser()
def _get_best_version(self, et):
ret = None
for ver in ifilter(lambda x: x.find('mask') is None,
et.iterfind('version')):
ret = ver.attrib['id']
yield ret
@property
def options(self):
if self.no_default:
return list(self._options) + self.package
else:
return list(self._options) + self.package + self.default_options
def _process(self):
return process(self.cmd, *self.options)
return process(self.cmd, *self.options, env={"LANG": "C"})
def get_output(self):
"""
@ -796,31 +799,153 @@ class Eix(object):
"""
Получить список пакетов
"""
return list(self._parseXml(self.get_output()))
return list(self.parser.parseXml(self.get_output()))
def _get_versions(self, et):
class EixParser(object):
"""
Парсер XML вывода от eix
"""
def parseXml(self, buffer):
try:
eix_xml = ET.fromstring(buffer)
return self.get_categories(eix_xml)
except ET.ParseError:
return iter(())
def get_categories(self, et):
raise StopIteration()
class EixFullnameParser(EixParser):
"""
Получить все версии пакета
"""
def get_versions(self, et):
for ver in et.iterfind('version'):
yield ver.attrib['id']
def _get_packages(self, et):
def get_packages(self, et):
for pkg in et:
for version in self._get_versions(pkg):
for version in self.get_versions(pkg):
if version:
yield "%s-%s" % (pkg.attrib['name'], version)
else:
yield pkg.attrib['name']
def _get_categories(self, et):
def get_categories(self, et):
for category in et:
for pkg in self._get_packages(category):
for pkg in self.get_packages(category):
yield EmergePackage("%s/%s" % (category.attrib['name'], pkg))
def _parseXml(self, buffer):
try:
eix_xml = ET.fromstring(buffer)
return self._get_categories(eix_xml)
except ET.ParseError:
return iter(())
class EixFullnameParserBestVersion(EixFullnameParser):
"""
Получить только одну максимальную версию пакета
"""
def get_versions(self, et):
ret = None
for ver in ifilter(lambda x: x.find('mask') is None,
et.iterfind('version')):
ret = ver.attrib['id']
yield ret
class PackageVersionInfo(object):
"""
Информация о версии пакета
"""
class Mask(object):
Keyword = 1
MissingKeyword = 2
Hardmask = 3
def __init__(self, pn, version):
self.pn = pn
self.slot = ""
self.version = version
self.mask = []
self.installed = False
def clone(self):
obj = PackageVersionInfo(self.pn, self.version)
obj.mask = list(self.mask)
obj.installed = self.installed
obj.slot = self.slot
return obj
@property
def stable(self):
return not self.mask
@property
def hardmask(self):
return PackageVersionInfo.Mask.Hardmask in self.mask
@property
def unstable(self):
return any(x in (PackageVersionInfo.Mask.Keyword,
PackageVersionInfo.Mask.MissingKeyword)
for x in self.mask)
@property
def unstable_keyword(self):
return PackageVersionInfo.Mask.Keyword in self.mask
@property
def missing_keyword(self):
return PackageVersionInfo.Mask.MissingKeyword in self.mask
def __repr__(self):
return "<{pn}-{pv}:{slot} {attrs}>".format(
pn=self.pn,
pv=self.version,
slot=self.slot,
attrs=" ".join(x for x in ("stable", "hardmask",
"unstable", "unstable_keyword",
"installed",
"missing_keyword") if getattr(self, x)))
class EixVersionParser(EixParser):
"""
Возвращает информацию о версии
"""
mask_map = {
'hard': PackageVersionInfo.Mask.Hardmask,
'keyword': PackageVersionInfo.Mask.Keyword,
'missing_keyword': PackageVersionInfo.Mask.MissingKeyword,
}
def get_categories(self, et):
for category in et:
for version in self.get_packages(category):
yield version
def get_packages(self, et):
for pkg in et:
pvi = PackageVersionInfo("%s/%s"%
(et.attrib['name'],
pkg.attrib['name']), None)
for version in self.get_versions(pkg, pvi):
yield version
def get_versions(self, et, pvi):
for ver in et.iterfind('version'):
retver = pvi.clone()
retver.version = ver.attrib['id']
if "slot" in ver.attrib:
retver.slot = ver.attrib['slot']
else:
retver.slot = "0"
if "installed" in ver.attrib:
retver.installed = True
for verattr in ver.iterfind('mask'):
_type = verattr.get('type')
if _type in self.mask_map:
retver.mask.append(self.mask_map[_type])
yield retver
class ChrootEix(Eix):
@ -1456,6 +1581,70 @@ class BinaryPackage(object):
def clear(self):
removeDir(self.work_dn)
class WorldPackage(object):
def __init__(self, package):
self.pkg = EmergePackage(package)
def __hash__(self):
return hash("%s:%s" % (self.pkg["CATEGORY/PN"], self.pkg["SLOT!"]))
def __eq__(self, obj):
return (self.pkg["CATEGORY/PN"] == obj["CATEGORY/PN"] and
self.pkg["SLOT!"] == obj["SLOT!"])
def __getitem__(self, item):
return self.pkg[item]
def __repr__(self):
return str("%s:%s"%(self.pkg["CATEGORY/PN"], self.pkg["SLOT"])
if self.pkg["SLOT!"] else self.pkg["CATEGORY/PN"])
class WorldFile(object):
class DiffType(object):
Added = 0
Removed = 1
Omitted = 2
def __init__(self, data):
self.data = data
self.packages = {
WorldPackage(x)
for x in (x.strip() for x in self.data.split('\n')
if x.strip() and not x.startswith("#"))}
def diff_new(self, worldfile):
return worldfile.packages - self.packages
def diff_removed(self, worldfile):
return self.packages - worldfile.packages
def diff_omitted(self, worldfile):
return worldfile.packages & self.packages
def category_diff(self, worldfile):
for group, data in groupby(sorted(chain(
((WorldFile.DiffType.Added, x)
for x in self.diff_new(worldfile)),
((WorldFile.DiffType.Removed, x)
for x in self.diff_removed(worldfile)),
((WorldFile.DiffType.Omitted, x)
for x in self.diff_omitted(worldfile))),
key=lambda x: x[1]["CATEGORY/PN"]),
lambda x: x[1]["CATEGORY/PN"]):
data = list(data)
added = sorted((pkg for _type, pkg in data
if _type == WorldFile.DiffType.Added),
key=lambda x: str(x))
removed = sorted((pkg for _type, pkg in data
if _type == WorldFile.DiffType.Removed),
key=lambda x: str(x))
omitted = sorted((pkg for _type, pkg in data
if _type == WorldFile.DiffType.Omitted),
key=lambda x: str(x))
if added or removed:
yield (group, added, removed, omitted)
def get_binary_file(pkg, pkgdir):
"""
Получить имя файла бинарного пакета

Loading…
Cancel
Save