|
|
@ -13,7 +13,7 @@
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
|
|
|
# limitations under the License.
|
|
|
|
from collections import Mapping
|
|
|
|
from collections import Mapping, defaultdict
|
|
|
|
|
|
|
|
|
|
|
|
import re
|
|
|
|
import re
|
|
|
|
import sys
|
|
|
|
import sys
|
|
|
@ -28,12 +28,10 @@ from os import path
|
|
|
|
from calculate.lib.utils.files import (getProgPath, STDOUT,
|
|
|
|
from calculate.lib.utils.files import (getProgPath, STDOUT,
|
|
|
|
PercentProgress, process, readFile,
|
|
|
|
PercentProgress, process, readFile,
|
|
|
|
readLinesFile)
|
|
|
|
readLinesFile)
|
|
|
|
from calculate.lib.utils.colortext.output import XmlOutput
|
|
|
|
|
|
|
|
from calculate.lib.utils.colortext.converter import (ConsoleCodes256Converter,
|
|
|
|
|
|
|
|
XmlConverter)
|
|
|
|
|
|
|
|
from calculate.lib.utils.common import cmpVersion
|
|
|
|
from calculate.lib.utils.common import cmpVersion
|
|
|
|
from contextlib import closing
|
|
|
|
from contextlib import closing
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import xml.etree.ElementTree as ET
|
|
|
|
import xml.etree.ElementTree as ET
|
|
|
|
|
|
|
|
|
|
|
|
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate
|
|
|
|
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate
|
|
|
@ -127,7 +125,6 @@ class Layman:
|
|
|
|
self._add_to_makeconf(rpath)
|
|
|
|
self._add_to_makeconf(rpath)
|
|
|
|
return True
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Git:
|
|
|
|
class Git:
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Объект для управление git репозиторием
|
|
|
|
Объект для управление git репозиторием
|
|
|
@ -487,7 +484,7 @@ class EmergePackage(Mapping):
|
|
|
|
pv = r"(?:-(\d[^-]*?))?"
|
|
|
|
pv = r"(?:-(\d[^-]*?))?"
|
|
|
|
pr = r"(?:-(r\d+))?"
|
|
|
|
pr = r"(?:-(r\d+))?"
|
|
|
|
tbz = r"(?:.(tbz2))?"
|
|
|
|
tbz = r"(?:.(tbz2))?"
|
|
|
|
slot = r'(?::(\d+(?:\.\d+)*(?:/\d+(?:\.\d+))?))?'
|
|
|
|
slot = r'(?::(\w+(?:\.\w+)*(?:/\w+(?:\.\w+)*)?))?'
|
|
|
|
repo = r'(?:::(\w+))?'
|
|
|
|
repo = r'(?:::(\w+))?'
|
|
|
|
|
|
|
|
|
|
|
|
reParse = re.compile(
|
|
|
|
reParse = re.compile(
|
|
|
@ -515,7 +512,10 @@ class EmergePackage(Mapping):
|
|
|
|
'REPO': x[REPO] or self.default_repo,
|
|
|
|
'REPO': x[REPO] or self.default_repo,
|
|
|
|
'CATEGORY/PN': "%s/%s" % (x[CATEGORY], x[PN]),
|
|
|
|
'CATEGORY/PN': "%s/%s" % (x[CATEGORY], x[PN]),
|
|
|
|
'PR': x[PR] or 'r0'}
|
|
|
|
'PR': x[PR] or 'r0'}
|
|
|
|
d['PVR'] = "%s-%s" % (d['PV'], d['PR'])
|
|
|
|
if x[PR]:
|
|
|
|
|
|
|
|
d['PVR'] = "%s-%s" % (d['PV'], d['PR'])
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
d['PVR'] = d['PV']
|
|
|
|
if d['PF'].endswith('-r0'):
|
|
|
|
if d['PF'].endswith('-r0'):
|
|
|
|
d['PF'] = d['PF'][:-3]
|
|
|
|
d['PF'] = d['PF'][:-3]
|
|
|
|
return d.copy()
|
|
|
|
return d.copy()
|
|
|
@ -538,27 +538,31 @@ class EmergePackage(Mapping):
|
|
|
|
if "CATEGORY/PN" in version and "PVR" in version:
|
|
|
|
if "CATEGORY/PN" in version and "PVR" in version:
|
|
|
|
if self['CATEGORY/PN'] < version['CATEGORY/PN']:
|
|
|
|
if self['CATEGORY/PN'] < version['CATEGORY/PN']:
|
|
|
|
return True
|
|
|
|
return True
|
|
|
|
version = version['PVR']
|
|
|
|
elif self['CATEGORY/PN'] > version['CATEGORY/PN']:
|
|
|
|
return cmpVersion(self['PVR'], version) == -1
|
|
|
|
return False
|
|
|
|
|
|
|
|
version = "%s-%s" % (version['PV'], version['PR'])
|
|
|
|
|
|
|
|
currentVersion = "%s-%s" % (self['PV'], self['PR'])
|
|
|
|
|
|
|
|
return cmpVersion(currentVersion, version) == -1
|
|
|
|
|
|
|
|
|
|
|
|
def __eq__(self, version):
|
|
|
|
def __eq__(self, version):
|
|
|
|
if "CATEGORY" in version and "PF" in version:
|
|
|
|
if "CATEGORY" in version and "PF" in version:
|
|
|
|
return ("%s/%s" % (self['CATEGORY'], self['PF']) ==
|
|
|
|
return ("%s/%s" % (self['CATEGORY'], self['PF']) ==
|
|
|
|
"%s/%s" % (version['CATEGORY'], version['PF']))
|
|
|
|
"%s/%s" % (version['CATEGORY'], version['PF']))
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
return cmpVersion(self['PVR'], version) == 0
|
|
|
|
currentVersion = "%s-%s" % (self['PV'], self['PR'])
|
|
|
|
|
|
|
|
return cmpVersion(currentVersion, version) == 0
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, package):
|
|
|
|
def __init__(self, package):
|
|
|
|
if isinstance(package, EmergePackage):
|
|
|
|
if isinstance(package, EmergePackage):
|
|
|
|
self.__result = package.__result
|
|
|
|
self.__result = package.__result
|
|
|
|
self.__package = package.__package
|
|
|
|
self._package = package._package
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
self.__package = package
|
|
|
|
self._package = package
|
|
|
|
self.__result = None
|
|
|
|
self.__result = None
|
|
|
|
|
|
|
|
|
|
|
|
def __getitem__(self, item):
|
|
|
|
def __getitem__(self, item):
|
|
|
|
if not self.__result:
|
|
|
|
if not self.__result:
|
|
|
|
self.__result = self._parsePackageString(self.__package)
|
|
|
|
self.__result = self._parsePackageString(self._package)
|
|
|
|
return self.__result[item]
|
|
|
|
return self.__result[item]
|
|
|
|
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
def __repr__(self):
|
|
|
@ -568,6 +572,85 @@ class EmergePackage(Mapping):
|
|
|
|
return "%s/%s" % (self['CATEGORY'], self['PF'])
|
|
|
|
return "%s/%s" % (self['CATEGORY'], self['PF'])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PackageInformation:
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
Объект позволяет получать информацию о пакете из eix
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
eix_cmd = getProgPath("/usr/bin/eix")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
query_packages = []
|
|
|
|
|
|
|
|
information_cache = defaultdict(dict)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fields = ["DESCRIPTION"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, pkg):
|
|
|
|
|
|
|
|
self._pkg = pkg
|
|
|
|
|
|
|
|
if not pkg in self.query_packages:
|
|
|
|
|
|
|
|
self.query_packages.append(pkg)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __getitem__(self, item):
|
|
|
|
|
|
|
|
if not self._pkg['CATEGORY/PN'] in self.information_cache:
|
|
|
|
|
|
|
|
self.query_information()
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
|
|
return self.information_cache[self._pkg['CATEGORY/PN']][item]
|
|
|
|
|
|
|
|
except KeyError:
|
|
|
|
|
|
|
|
return ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def query_information(self):
|
|
|
|
|
|
|
|
pkg_list = "|".join(
|
|
|
|
|
|
|
|
[x['CATEGORY/PN'].replace("+", r"\+") for x in self.query_packages])
|
|
|
|
|
|
|
|
output = pexpect.spawn(self.eix_cmd, ["--xml", pkg_list]).read()
|
|
|
|
|
|
|
|
xml = ET.fromstring(output)
|
|
|
|
|
|
|
|
for pkg in self.query_packages:
|
|
|
|
|
|
|
|
cat_pn = pkg['CATEGORY/PN']
|
|
|
|
|
|
|
|
if not cat_pn in self.information_cache:
|
|
|
|
|
|
|
|
descr_node = xml.find(
|
|
|
|
|
|
|
|
'category[@name="%s"]/package[@name="%s"]/description'
|
|
|
|
|
|
|
|
% (pkg['CATEGORY'], pkg['PN']))
|
|
|
|
|
|
|
|
if descr_node is not None:
|
|
|
|
|
|
|
|
self.information_cache[cat_pn]['DESCRIPTION'] = \
|
|
|
|
|
|
|
|
descr_node.text
|
|
|
|
|
|
|
|
while self.query_packages:
|
|
|
|
|
|
|
|
self.query_packages.pop()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
|
|
|
def add_info(cls, pkg):
|
|
|
|
|
|
|
|
pkg.info = cls(pkg)
|
|
|
|
|
|
|
|
return pkg
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class UnmergePackage(EmergePackage):
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
Информация об обновлении одного пакета
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
re_pkg_info = re.compile("^\s(\S+)\n\s+selected:\s(\S+)",re.MULTILINE)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, package):
|
|
|
|
|
|
|
|
super(UnmergePackage, self).__init__(package)
|
|
|
|
|
|
|
|
if not isinstance(package, EmergePackage):
|
|
|
|
|
|
|
|
self._package = self.convert_package_info(package)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def convert_package_info(self, package):
|
|
|
|
|
|
|
|
match = self.re_pkg_info.search(package)
|
|
|
|
|
|
|
|
if match:
|
|
|
|
|
|
|
|
return "%s-%s" % match.groups()
|
|
|
|
|
|
|
|
return ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def recalculate_update_info(cls):
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
Добавить
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
cls.update_info = re.compile(
|
|
|
|
|
|
|
|
r"^({install_info})\s+({atom_info})\s*(?:{prev_version})?"
|
|
|
|
|
|
|
|
r"\s*({use_info})?.*?({pkg_size})?$".format(
|
|
|
|
|
|
|
|
install_info=cls.install_info,
|
|
|
|
|
|
|
|
atom_info=cls.atom_info,
|
|
|
|
|
|
|
|
prev_version=cls.prev_version,
|
|
|
|
|
|
|
|
use_info=cls.use_info,
|
|
|
|
|
|
|
|
pkg_size=cls.pkg_size), re.MULTILINE)
|
|
|
|
|
|
|
|
return cls
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@recalculate_update_info
|
|
|
|
@total_ordering
|
|
|
|
@total_ordering
|
|
|
|
class EmergeUpdateInfo(Mapping):
|
|
|
|
class EmergeUpdateInfo(Mapping):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
@ -578,27 +661,22 @@ class EmergeUpdateInfo(Mapping):
|
|
|
|
atom_info = r"\S+"
|
|
|
|
atom_info = r"\S+"
|
|
|
|
use_info = 'USE="[^"]+"'
|
|
|
|
use_info = 'USE="[^"]+"'
|
|
|
|
prev_version = "\[([^\]]+)\]"
|
|
|
|
prev_version = "\[([^\]]+)\]"
|
|
|
|
update_info = re.compile(
|
|
|
|
pkg_size = r"\d+ \w+"
|
|
|
|
r"^({install_info})\s+({atom_info})\s+(?:{prev_version})?"
|
|
|
|
|
|
|
|
r"\s*({use_info})?".format(install_info=install_info,
|
|
|
|
|
|
|
|
atom_info=atom_info,
|
|
|
|
|
|
|
|
prev_version=prev_version,
|
|
|
|
|
|
|
|
use_info=use_info))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
attrs = ['binary', 'REPLACING_VERSIONS']
|
|
|
|
attrs = ['binary', 'REPLACING_VERSIONS', 'SIZE']
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, data):
|
|
|
|
def __init__(self, data):
|
|
|
|
self._data = data
|
|
|
|
self._data = data
|
|
|
|
self._package = None
|
|
|
|
self._package = None
|
|
|
|
self._info = {}
|
|
|
|
self._info = {}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _parseData(self):
|
|
|
|
def _parseData(self):
|
|
|
|
r = self.update_info.search(self._data)
|
|
|
|
r = self.update_info.search(self._data)
|
|
|
|
if r:
|
|
|
|
if r:
|
|
|
|
self._info['binary'] = r.group(2) == 'binary'
|
|
|
|
self._info['binary'] = r.group(2) == 'binary'
|
|
|
|
self._package = EmergePackage(r.group(3))
|
|
|
|
self._package = EmergePackage(r.group(3))
|
|
|
|
self._info['REPLACING_VERSIONS'] = r.group(4) or ""
|
|
|
|
self._info['REPLACING_VERSIONS'] = r.group(4) or ""
|
|
|
|
|
|
|
|
self._info['SIZE'] = r.group(6) or ""
|
|
|
|
|
|
|
|
|
|
|
|
def __iter__(self):
|
|
|
|
def __iter__(self):
|
|
|
|
return chain(EmergePackage.attrs, self.attrs)
|
|
|
|
return chain(EmergePackage.attrs, self.attrs)
|
|
|
@ -639,16 +717,12 @@ class EmergeUpdateInfo(Mapping):
|
|
|
|
def __str__(self):
|
|
|
|
def __str__(self):
|
|
|
|
return "%s/%s" % (self['CATEGORY'], self['PF'])
|
|
|
|
return "%s/%s" % (self['CATEGORY'], self['PF'])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@recalculate_update_info
|
|
|
|
class EmergeError(Exception):
|
|
|
|
class EmergeRemoveInfo(EmergeUpdateInfo):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Ошибка при сборке пакетов
|
|
|
|
Информация об удалении одного пакета (в списке обновляемых пакетов)
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
(NEED_ROOT, NO_EBUILD, CONFLICT, CUSTOM) = range(0, 4)
|
|
|
|
install_info = "\[(uninstall)[^\]]+\]"
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, msg, errno=CUSTOM):
|
|
|
|
|
|
|
|
Exception.__init__(self, msg)
|
|
|
|
|
|
|
|
self.errno = errno
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Eix:
|
|
|
|
class Eix:
|
|
|
@ -721,277 +795,7 @@ class Eix:
|
|
|
|
return iter(())
|
|
|
|
return iter(())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Emerge:
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
Объект для выполнения сборки пакетов
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
# параметры по умолчанию
|
|
|
|
|
|
|
|
default_params = ["-av", "--color=y", "--nospinner"]
|
|
|
|
|
|
|
|
cmd = getProgPath("/usr/bin/emerge")
|
|
|
|
|
|
|
|
# шаблон выборки списка пакетов
|
|
|
|
|
|
|
|
install_pkgs_pattern = \
|
|
|
|
|
|
|
|
"(\\[[^\\]]+\\]\\s*(\\S+).*(?:{nl}|$))".format(nl="\r*\n")
|
|
|
|
|
|
|
|
re_install_pkgs = re.compile("^%s+" % install_pkgs_pattern,
|
|
|
|
|
|
|
|
re.MULTILINE)
|
|
|
|
|
|
|
|
# конфликтный пакет
|
|
|
|
|
|
|
|
_conflict_pkg = r"[\w-]+/[\w-]+:\d+"
|
|
|
|
|
|
|
|
# конкретная версия конфликтного пакета
|
|
|
|
|
|
|
|
_conflict_candidate = r" \(.*"
|
|
|
|
|
|
|
|
# пакеты в которым необходим конфликтный пакет
|
|
|
|
|
|
|
|
_conflict_req = r" \S.*"
|
|
|
|
|
|
|
|
# шаблон конфликтного блока
|
|
|
|
|
|
|
|
conflict_block = \
|
|
|
|
|
|
|
|
"({nl}{nl}({0}{nl}({1}{nl})+{nl})+)".format(_conflict_candidate,
|
|
|
|
|
|
|
|
_conflict_req,
|
|
|
|
|
|
|
|
nl="\r*\n")
|
|
|
|
|
|
|
|
re_conflict_block = re.compile(
|
|
|
|
|
|
|
|
"^{0}{conflict_block}([\w\W]+{conflict_block})*".format(
|
|
|
|
|
|
|
|
_conflict_pkg, conflict_block=conflict_block),
|
|
|
|
|
|
|
|
re.MULTILINE)
|
|
|
|
|
|
|
|
# шаблон устновки консольного цвета
|
|
|
|
|
|
|
|
_color_block = "(?:\033\[[^m]+?m)?"
|
|
|
|
|
|
|
|
re_custom_error = re.compile(
|
|
|
|
|
|
|
|
r"^Calculating dependencies.*{nl}".format(nl="\r*\n") +
|
|
|
|
|
|
|
|
"%s*" % install_pkgs_pattern +
|
|
|
|
|
|
|
|
r"(?P<result>[\w\W]+)", re.MULTILINE)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# regexp для удаления неиспользуемой информации
|
|
|
|
|
|
|
|
re_cut_blocks = \
|
|
|
|
|
|
|
|
re.compile(r"(It may be possible to solve.*?"
|
|
|
|
|
|
|
|
"solve this conflict automatically\.|"
|
|
|
|
|
|
|
|
"For more information, see.*?Gentoo Handbook\.)\s*", re.S)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
expect_need_root = "This action requires superuser access"
|
|
|
|
|
|
|
|
expect_conflict = "Multiple package[ \w]+pulled"
|
|
|
|
|
|
|
|
expect_to_merge = "Would you like to merge"
|
|
|
|
|
|
|
|
expect_nothing_merge = ("Nothing to merge|No outdated packages|"
|
|
|
|
|
|
|
|
"\s0 packages")
|
|
|
|
|
|
|
|
expect_no_ebuild = "no ebuilds to satisfy \""
|
|
|
|
|
|
|
|
expect_custom_question = "{c}Yes{c}/{c}No{c}".format(c=_color_block)
|
|
|
|
|
|
|
|
expect_emerge_package = ("Emerging (binary )?\({c}(\d+){c} "
|
|
|
|
|
|
|
|
"of {c}(\d+){c}\) {c}([^\s\033]+){c}".format(
|
|
|
|
|
|
|
|
c=_color_block))
|
|
|
|
|
|
|
|
expect_install_package = ("Installing (binary )?\({c}(\d+){c} "
|
|
|
|
|
|
|
|
"of {c}(\d+){c}\) {c}([^\s\033]+){c}".format(
|
|
|
|
|
|
|
|
c=_color_block))
|
|
|
|
|
|
|
|
expect_error_on_install = "ERROR: \S* failed \([^)]+\)"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, packages, extra_params=[], env=None, cwd=None,
|
|
|
|
|
|
|
|
command_runner=None,
|
|
|
|
|
|
|
|
converter=ConsoleCodes256Converter(XmlOutput())):
|
|
|
|
|
|
|
|
self.text_converter = converter
|
|
|
|
|
|
|
|
self.packages = packages
|
|
|
|
|
|
|
|
self.params = self.default_params + extra_params
|
|
|
|
|
|
|
|
self.child = None
|
|
|
|
|
|
|
|
self.update_block = None
|
|
|
|
|
|
|
|
self.conflict_block = None
|
|
|
|
|
|
|
|
self.update_packages = None
|
|
|
|
|
|
|
|
self.custom_error = ""
|
|
|
|
|
|
|
|
self.env = env
|
|
|
|
|
|
|
|
self.cwd = cwd
|
|
|
|
|
|
|
|
# событие начало сборки
|
|
|
|
|
|
|
|
self.event_emerging = []
|
|
|
|
|
|
|
|
# событие начало установки
|
|
|
|
|
|
|
|
self.event_installing = []
|
|
|
|
|
|
|
|
self.error_log = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def handle_emerging(self, f):
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
Добавить обработку начала сборки пакета
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
if not f in self.event_emerging:
|
|
|
|
|
|
|
|
self.event_emerging.append(f)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def handle_installing(self, f):
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
Добавить обработку начала установки пакета
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
if not f in self.event_installing:
|
|
|
|
|
|
|
|
self.event_installing.append(f)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _get_text(self, re_result, already_text=False):
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
Получить результат из регулярки и преобразовать его через self.converter
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
if re_result:
|
|
|
|
|
|
|
|
if not already_text:
|
|
|
|
|
|
|
|
re_result = re_result.group()
|
|
|
|
|
|
|
|
result = self.re_cut_blocks.sub("", re_result)
|
|
|
|
|
|
|
|
return self.text_converter.transform(result.strip())
|
|
|
|
|
|
|
|
return ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _get_custom_error_output(self, buf):
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
Получить вывод об прочих ошибках в ходе вычисления зависимостей
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
r = self.re_custom_error.search(buf)
|
|
|
|
|
|
|
|
if r:
|
|
|
|
|
|
|
|
return self._get_text(r.groupdict()["result"], already_text=True)
|
|
|
|
|
|
|
|
return ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _get_package_list_output(self, buf):
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
Получить из вывода emerge часть текста со списком пакетов
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
return self._get_text(self.re_install_pkgs.search(buf))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _get_conflict_list_output(self, buf):
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
Разобрать вывод о конфликтах среди пакетов
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
return self._get_text(self.re_conflict_block.search(buf))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_update_block(self):
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
Получить список устанавливаемых пакетов
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
if self.update_block is None:
|
|
|
|
|
|
|
|
self.execute()
|
|
|
|
|
|
|
|
events = {v: k for k, v in enumerate(sorted([
|
|
|
|
|
|
|
|
self.expect_need_root,
|
|
|
|
|
|
|
|
self.expect_conflict,
|
|
|
|
|
|
|
|
self.expect_to_merge,
|
|
|
|
|
|
|
|
self.expect_nothing_merge,
|
|
|
|
|
|
|
|
self.expect_no_ebuild,
|
|
|
|
|
|
|
|
self.expect_custom_question,
|
|
|
|
|
|
|
|
pexpect.EOF]))}
|
|
|
|
|
|
|
|
res = self.child.expect(sorted(events.keys()))
|
|
|
|
|
|
|
|
if res == events[self.expect_need_root]:
|
|
|
|
|
|
|
|
self.process_need_root()
|
|
|
|
|
|
|
|
elif res == events[self.expect_to_merge]:
|
|
|
|
|
|
|
|
self.update_block = (
|
|
|
|
|
|
|
|
self._get_package_list_output(self.child.before))
|
|
|
|
|
|
|
|
elif res == events[self.expect_nothing_merge]:
|
|
|
|
|
|
|
|
self.update_block = ""
|
|
|
|
|
|
|
|
elif res == events[self.expect_no_ebuild]:
|
|
|
|
|
|
|
|
raise EmergeError(_("No ebuilds to satisfy %s") %
|
|
|
|
|
|
|
|
self.child.buffer.split('"', 1)[0],
|
|
|
|
|
|
|
|
errno=EmergeError.NO_EBUILD)
|
|
|
|
|
|
|
|
elif res == events[self.expect_conflict]:
|
|
|
|
|
|
|
|
self.update_block = \
|
|
|
|
|
|
|
|
self._get_package_list_output(self.child.before)
|
|
|
|
|
|
|
|
self.conflict_block = \
|
|
|
|
|
|
|
|
self._get_conflict_list_output(self.child.read())
|
|
|
|
|
|
|
|
raise EmergeError(_("Multiple package instances within "
|
|
|
|
|
|
|
|
"a single package slot"),
|
|
|
|
|
|
|
|
errno=EmergeError.CONFLICT)
|
|
|
|
|
|
|
|
elif res == events[self.expect_custom_question]:
|
|
|
|
|
|
|
|
self.custom_error = self._get_custom_error_output(
|
|
|
|
|
|
|
|
self.child.before)
|
|
|
|
|
|
|
|
self.child.sendline("no")
|
|
|
|
|
|
|
|
raise EmergeError(_("Unexpected question"))
|
|
|
|
|
|
|
|
elif res == events[pexpect.EOF]:
|
|
|
|
|
|
|
|
if re.search("Total:\s+\d+ package", self.child.before):
|
|
|
|
|
|
|
|
self.update_block = (
|
|
|
|
|
|
|
|
self._get_package_list_output(self.child.before))
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
self.custom_error = self._get_custom_error_output(
|
|
|
|
|
|
|
|
self.child.before)
|
|
|
|
|
|
|
|
raise EmergeError(_("Failed to emerge"))
|
|
|
|
|
|
|
|
return self.update_block
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def notifyEmergingPackage(self, package, num=1, max_num=2, binary=False):
|
|
|
|
|
|
|
|
[f(EmergePackage(package), num=num, max_num=max_num, binary=binary)
|
|
|
|
|
|
|
|
for f in self.event_emerging]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def notifyInstallingPackage(self, package):
|
|
|
|
|
|
|
|
[f(EmergePackage(package)) for f in self.event_installing]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def install(self):
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
Install packages
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
self.execute()
|
|
|
|
|
|
|
|
self.child.sendline("yes")
|
|
|
|
|
|
|
|
pkg_name = ""
|
|
|
|
|
|
|
|
events = {v: k for k, v in enumerate(sorted([
|
|
|
|
|
|
|
|
self.expect_need_root,
|
|
|
|
|
|
|
|
self.expect_emerge_package,
|
|
|
|
|
|
|
|
self.expect_install_package,
|
|
|
|
|
|
|
|
self.expect_error_on_install,
|
|
|
|
|
|
|
|
pexpect.EOF]))}
|
|
|
|
|
|
|
|
while True:
|
|
|
|
|
|
|
|
res = self.child.expect(sorted(events.keys()))
|
|
|
|
|
|
|
|
if res == events[self.expect_need_root]:
|
|
|
|
|
|
|
|
self.process_need_root()
|
|
|
|
|
|
|
|
elif res in (events[self.expect_install_package],
|
|
|
|
|
|
|
|
events[self.expect_emerge_package]):
|
|
|
|
|
|
|
|
pkg_name = self.child.match.group(4).strip()
|
|
|
|
|
|
|
|
if res == events[self.expect_emerge_package]:
|
|
|
|
|
|
|
|
binary_pkg = bool(self.child.match.group(1))
|
|
|
|
|
|
|
|
current_pkg_num = int(self.child.match.group(2))
|
|
|
|
|
|
|
|
max_pkg_num = int(self.child.match.group(3))
|
|
|
|
|
|
|
|
self.notifyEmergingPackage(pkg_name, num=current_pkg_num,
|
|
|
|
|
|
|
|
max_num=max_pkg_num,
|
|
|
|
|
|
|
|
binary=binary_pkg)
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
self.notifyInstallingPackage(pkg_name)
|
|
|
|
|
|
|
|
elif res == events[self.expect_error_on_install]:
|
|
|
|
|
|
|
|
if self.child.expect(
|
|
|
|
|
|
|
|
["The complete build log is located at '[^']+",
|
|
|
|
|
|
|
|
pexpect.EOF]) == 0:
|
|
|
|
|
|
|
|
self.error_log = self.child.after.rpartition("'")[-1]
|
|
|
|
|
|
|
|
raise EmergeError(_("Emerge %s is failed") % pkg_name)
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
if self.child.isalive():
|
|
|
|
|
|
|
|
self.child.wait()
|
|
|
|
|
|
|
|
return self.child.exitstatus == 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def execute(self):
|
|
|
|
|
|
|
|
# TODO: убрать лог в /tmp
|
|
|
|
|
|
|
|
if self.child is None:
|
|
|
|
|
|
|
|
self.child = pexpect.spawn(self.cmd, self.params + self.packages,
|
|
|
|
|
|
|
|
logfile=open('/tmp/emerge.log', 'w'),
|
|
|
|
|
|
|
|
env=self.env, cwd=self.cwd, timeout=None)
|
|
|
|
|
|
|
|
return self.child
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def close(self):
|
|
|
|
|
|
|
|
if self.child is not None:
|
|
|
|
|
|
|
|
self.child.close()
|
|
|
|
|
|
|
|
self.child = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_error_log(self):
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
Получить путь до журнала сборки
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
return self.error_log
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def process_need_root(self):
|
|
|
|
|
|
|
|
raise EmergeError(
|
|
|
|
|
|
|
|
_("This action requires superuser access"),
|
|
|
|
|
|
|
|
errno=EmergeError.NEED_ROOT)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __enter__(self):
|
|
|
|
|
|
|
|
return self
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __exit__(self, *exc_info):
|
|
|
|
|
|
|
|
self.close()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_update_list(self):
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
Проверить есть ли в обновлениях пакет совпадающий с pkg_pattern
|
|
|
|
|
|
|
|
полученный пакет можно проверить указанной check функцией
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
if self.update_packages is None:
|
|
|
|
|
|
|
|
list_block = XmlConverter().transform(self.get_update_block())
|
|
|
|
|
|
|
|
self.update_packages = self._parse_update_list(list_block)
|
|
|
|
|
|
|
|
return PackageList(self.update_packages)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _parse_update_list(self, list_block):
|
|
|
|
|
|
|
|
return filter(lambda x: x['PN'] is not None,
|
|
|
|
|
|
|
|
map(EmergeUpdateInfo,
|
|
|
|
|
|
|
|
list_block.split('\n')))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class RevdepRebuild(Emerge):
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def execute(self):
|
|
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class EmergeLogTask(object):
|
|
|
|
class EmergeLogTask(object):
|
|
|
|
|
|
|
|
|
|
|
|
def has_marker(self, line):
|
|
|
|
def has_marker(self, line):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Определить есть ли в строке маркер задачи
|
|
|
|
Определить есть ли в строке маркер задачи
|
|
|
@ -1010,6 +814,7 @@ class EmergeLogTask(object):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
return ""
|
|
|
|
return ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class EmergeLogNamedTask(EmergeLogTask):
|
|
|
|
class EmergeLogNamedTask(EmergeLogTask):
|
|
|
|
date_format = "%b %d, %Y %T"
|
|
|
|
date_format = "%b %d, %Y %T"
|
|
|
|
|
|
|
|
|
|
|
@ -1036,19 +841,23 @@ class EmergeLogNamedTask(EmergeLogTask):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
return "*** Finished %s" % self.taskname
|
|
|
|
return "*** Finished %s" % self.taskname
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class EmergeLog:
|
|
|
|
class EmergeLog:
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
EmergeLog(after).get_update(package_pattern)
|
|
|
|
EmergeLog(after).get_update(package_pattern)
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
emerge_log = "/var/log/emerge.log"
|
|
|
|
emerge_log = "/var/log/emerge.log"
|
|
|
|
re_complete_emerge = re.compile(r":::\scompleted emerge \(.*?\) (\S+)",
|
|
|
|
re_complete_emerge = re.compile(r":::\scompleted (emerge) \(.*?\) (\S+)",
|
|
|
|
re.M)
|
|
|
|
re.M)
|
|
|
|
|
|
|
|
re_complete_unmerge = re.compile(r">>>\s(unmerge) success: (\S+)", re.M)
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, emerge_task=EmergeLogTask()):
|
|
|
|
def __init__(self, emerge_task=EmergeLogTask()):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
@type emerge_task: EmergeLogTask
|
|
|
|
@type emerge_task: EmergeLogTask
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
self.emerge_task = emerge_task
|
|
|
|
self.emerge_task = emerge_task
|
|
|
|
|
|
|
|
self._list = None
|
|
|
|
|
|
|
|
self._remove_list = None
|
|
|
|
|
|
|
|
|
|
|
|
def _get_last_changes(self):
|
|
|
|
def _get_last_changes(self):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
@ -1060,16 +869,36 @@ class EmergeLog:
|
|
|
|
log_data.save()
|
|
|
|
log_data.save()
|
|
|
|
return log_data.restore()
|
|
|
|
return log_data.restore()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
|
|
|
def list(self):
|
|
|
|
|
|
|
|
if self._list is None:
|
|
|
|
|
|
|
|
self.get_packages()
|
|
|
|
|
|
|
|
return self._list
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
|
|
|
def remove_list(self):
|
|
|
|
|
|
|
|
if self._remove_list is None:
|
|
|
|
|
|
|
|
self.get_packages()
|
|
|
|
|
|
|
|
return self._remove_list
|
|
|
|
|
|
|
|
|
|
|
|
def get_packages(self):
|
|
|
|
def get_packages(self):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Получить список пакетов
|
|
|
|
Получить список пакетов
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
return list(self._parse_log(self._get_last_changes()))
|
|
|
|
self._list, self._remove_list = \
|
|
|
|
|
|
|
|
zip(*self._parse_log(self._get_last_changes()))
|
|
|
|
|
|
|
|
self._list = filter(None,self._list)
|
|
|
|
|
|
|
|
self._remove_list = filter(None, self._remove_list)
|
|
|
|
|
|
|
|
|
|
|
|
def _parse_log(self, data):
|
|
|
|
def _parse_log(self, data):
|
|
|
|
for re_match in ifilter(None,
|
|
|
|
searcher = lambda x:(self.re_complete_emerge.search(x) or
|
|
|
|
imap(self.re_complete_emerge.search, data)):
|
|
|
|
self.re_complete_unmerge.search(x))
|
|
|
|
yield re_match.group(1)
|
|
|
|
for re_match in ifilter(None, imap(searcher, data)):
|
|
|
|
|
|
|
|
if re_match.group(1) == "emerge":
|
|
|
|
|
|
|
|
yield re_match.group(2), None
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
yield None, re_match.group(2)
|
|
|
|
|
|
|
|
yield None, None
|
|
|
|
|
|
|
|
|
|
|
|
def _set_marker(self, text_marker):
|
|
|
|
def _set_marker(self, text_marker):
|
|
|
|
with open(self.emerge_log, 'a') as f:
|
|
|
|
with open(self.emerge_log, 'a') as f:
|
|
|
@ -1096,13 +925,18 @@ class PackageList(object):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Список пакетов с возможностью среза и сравнением с версией
|
|
|
|
Список пакетов с возможностью среза и сравнением с версией
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, packages):
|
|
|
|
def __init__(self, packages):
|
|
|
|
self._raw_list = packages
|
|
|
|
self._raw_list = packages
|
|
|
|
|
|
|
|
self.result = None
|
|
|
|
|
|
|
|
|
|
|
|
def _packages(self):
|
|
|
|
def _packages(self):
|
|
|
|
return ifilter(lambda x: x['PN'] is not None,
|
|
|
|
if self.result is None:
|
|
|
|
imap(lambda x: x if isinstance(x, Mapping) else EmergePackage(x),
|
|
|
|
self.result = filter(lambda x: x['PN'],
|
|
|
|
self._raw_list))
|
|
|
|
imap(lambda x: (x if isinstance(x, Mapping)
|
|
|
|
|
|
|
|
else EmergePackage(x)),
|
|
|
|
|
|
|
|
self._raw_list))
|
|
|
|
|
|
|
|
return self.result
|
|
|
|
|
|
|
|
|
|
|
|
def __getitem__(self, item):
|
|
|
|
def __getitem__(self, item):
|
|
|
|
re_item = re.compile(item)
|
|
|
|
re_item = re.compile(item)
|
|
|
@ -1113,7 +947,7 @@ class PackageList(object):
|
|
|
|
return iter(self._packages())
|
|
|
|
return iter(self._packages())
|
|
|
|
|
|
|
|
|
|
|
|
def __len__(self):
|
|
|
|
def __len__(self):
|
|
|
|
return len(self._raw_list)
|
|
|
|
return len(list(self._packages()))
|
|
|
|
|
|
|
|
|
|
|
|
def __lt__(self, other):
|
|
|
|
def __lt__(self, other):
|
|
|
|
return any(pkg < other for pkg in self._packages())
|
|
|
|
return any(pkg < other for pkg in self._packages())
|
|
|
|