blob: 2661f14bcd1f31d9a83996cdcb2b98cf08e5af77 [file] [log] [blame]
# -*- coding:utf-8 -*-
from __future__ import print_function, unicode_literals
import sys
import xml
# import our initialized portage instance
from repoman._portage import portage
from portage import os
from portage.output import red
from portage.process import find_binary
from repoman.metadata import fetch_metadata_dtd
from repoman._subprocess import repoman_getstatusoutput
class _XMLParser(xml.etree.ElementTree.XMLParser):
def __init__(self, data, **kwargs):
xml.etree.ElementTree.XMLParser.__init__(self, **kwargs)
self._portage_data = data
if hasattr(self, 'parser'):
self._base_XmlDeclHandler = self.parser.XmlDeclHandler
self.parser.XmlDeclHandler = self._portage_XmlDeclHandler
self._base_StartDoctypeDeclHandler = \
self.parser.StartDoctypeDeclHandler
self.parser.StartDoctypeDeclHandler = \
self._portage_StartDoctypeDeclHandler
def _portage_XmlDeclHandler(self, version, encoding, standalone):
if self._base_XmlDeclHandler is not None:
self._base_XmlDeclHandler(version, encoding, standalone)
self._portage_data["XML_DECLARATION"] = (version, encoding, standalone)
def _portage_StartDoctypeDeclHandler(
self, doctypeName, systemId, publicId, has_internal_subset):
if self._base_StartDoctypeDeclHandler is not None:
self._base_StartDoctypeDeclHandler(
doctypeName, systemId, publicId, has_internal_subset)
self._portage_data["DOCTYPE"] = (doctypeName, systemId, publicId)
class _MetadataTreeBuilder(xml.etree.ElementTree.TreeBuilder):
"""
Implements doctype() as required to avoid deprecation warnings with
>=python-2.7.
"""
def doctype(self, name, pubid, system):
pass
class XmlLint(object):
def __init__(self, options, repoman_settings, metadata_dtd=None):
self.metadata_dtd = (metadata_dtd or
os.path.join(repoman_settings["DISTDIR"], 'metadata.dtd'))
self.options = options
self.repoman_settings = repoman_settings
self._is_capable = metadata_dtd is not None
self.binary = None
self._check_capable()
def _check_capable(self):
if self.options.mode == "manifest":
return
self.binary = find_binary('xmllint')
if not self.binary:
print(red("!!! xmllint not found. Can't check metadata.xml.\n"))
self._is_capable = False
elif not self._is_capable:
if not fetch_metadata_dtd(self.metadata_dtd, self.repoman_settings):
sys.exit(1)
# this can be problematic if xmllint changes their output
self._is_capable = True
@property
def capable(self):
return self._is_capable
def check(self, checkdir, repolevel):
'''Runs checks on the package metadata.xml file
@param checkdir: string, path
@param repolevel: integer
@return boolean, False == bad metadata
'''
if not self.capable:
if self.options.xml_parse or repolevel == 3:
print("%s sorry, xmllint is needed. failing\n" % red("!!!"))
sys.exit(1)
return True
# xmlint can produce garbage output even on success, so only dump
# the ouput when it fails.
st, out = repoman_getstatusoutput(
self.binary + " --nonet --noout --dtdvalid %s %s" % (
portage._shell_quote(self.metadata_dtd),
portage._shell_quote(
os.path.join(checkdir, "metadata.xml"))))
if st != os.EX_OK:
print(red("!!!") + " metadata.xml is invalid:")
for z in out.splitlines():
print(red("!!! ") + z)
return False
return True