blob: f22ef19588e4c6599a14e2bfd147b39652e7e1df [file] [log] [blame]
# -*- coding:utf-8 -*-
'''Package Metadata Checks operations'''
import sys
from itertools import chain
try:
import xml.etree.ElementTree
from xml.parsers.expat import ExpatError
except (SystemExit, KeyboardInterrupt):
raise
except (ImportError, SystemError, RuntimeError, Exception):
# broken or missing xml support
# http://bugs.python.org/issue14988
msg = ["Please enable python's \"xml\" USE flag in order to use repoman."]
from portage.output import EOutput
out = EOutput()
for line in msg:
out.eerror(line)
sys.exit(1)
# import our initialized portage instance
from repoman._portage import portage
from portage.exception import InvalidAtom
from portage import os
from portage import _encodings, _unicode_encode
from portage.dep import Atom
from repoman.metadata import (
metadata_xml_encoding, metadata_doctype_name,
metadata_dtd_uri, metadata_xml_declaration, parse_metadata_use)
from repoman.checks.herds.herdbase import get_herd_base
from repoman.checks.herds.metadata import check_metadata, UnknownHerdsError
from repoman._xml import _XMLParser, _MetadataTreeBuilder, XmlLint
class PkgMetadata(object):
'''Package metadata.xml checks'''
def __init__(self, options, qatracker, repoman_settings):
'''PkgMetadata init function
@param options: ArgumentParser.parse_known_args(argv[1:]) options
@param qatracker: QATracker instance
@param repoman_settings: settings instance
'''
self.options = options
self.qatracker = qatracker
self.repoman_settings = repoman_settings
self.musedict = {}
self.xmllint = XmlLint(self.options, self.repoman_settings)
def check(self, xpkg, checkdir, checkdirlist, repolevel):
'''Performs the checks on the metadata.xml for the package
@param xpkg: the pacakge being checked
@param checkdir: string, directory path
@param checkdirlist: list of checkdir's
@param repolevel: integer
'''
self.musedict = {}
# metadata.xml file check
if "metadata.xml" not in checkdirlist:
self.qatracker.add_error("metadata.missing", xpkg + "/metadata.xml")
# metadata.xml parse check
else:
metadata_bad = False
xml_info = {}
xml_parser = _XMLParser(xml_info, target=_MetadataTreeBuilder())
# read metadata.xml into memory
try:
_metadata_xml = xml.etree.ElementTree.parse(
_unicode_encode(
os.path.join(checkdir, "metadata.xml"),
encoding=_encodings['fs'], errors='strict'),
parser=xml_parser)
except (ExpatError, SyntaxError, EnvironmentError) as e:
metadata_bad = True
self.qatracker.add_error("metadata.bad", "%s/metadata.xml: %s" % (xpkg, e))
del e
else:
if not hasattr(xml_parser, 'parser') or \
sys.hexversion < 0x2070000 or \
(sys.hexversion > 0x3000000 and sys.hexversion < 0x3020000):
# doctype is not parsed with python 2.6 or 3.1
pass
else:
if "XML_DECLARATION" not in xml_info:
self.qatracker.add_error(
"metadata.bad", "%s/metadata.xml: "
"xml declaration is missing on first line, "
"should be '%s'" % (xpkg, metadata_xml_declaration))
else:
xml_version, xml_encoding, xml_standalone = \
xml_info["XML_DECLARATION"]
if xml_encoding is None or \
xml_encoding.upper() != metadata_xml_encoding:
if xml_encoding is None:
encoding_problem = "but it is undefined"
else:
encoding_problem = "not '%s'" % xml_encoding
self.qatracker.add_error(
"metadata.bad", "%s/metadata.xml: "
"xml declaration encoding should be '%s', %s" %
(xpkg, metadata_xml_encoding, encoding_problem))
if "DOCTYPE" not in xml_info:
metadata_bad = True
self.qatracker.add_error(
"metadata.bad",
"%s/metadata.xml: %s" % (xpkg, "DOCTYPE is missing"))
else:
doctype_name, doctype_system, doctype_pubid = \
xml_info["DOCTYPE"]
if doctype_system != metadata_dtd_uri:
if doctype_system is None:
system_problem = "but it is undefined"
else:
system_problem = "not '%s'" % doctype_system
self.qatracker.add_error(
"metadata.bad", "%s/metadata.xml: "
"DOCTYPE: SYSTEM should refer to '%s', %s" %
(xpkg, metadata_dtd_uri, system_problem))
if doctype_name != metadata_doctype_name:
self.qatracker.add_error(
"metadata.bad", "%s/metadata.xml: "
"DOCTYPE: name should be '%s', not '%s'" %
(xpkg, metadata_doctype_name, doctype_name))
# load USE flags from metadata.xml
try:
self.musedict = parse_metadata_use(_metadata_xml)
except portage.exception.ParseError as e:
metadata_bad = True
self.qatracker.add_error(
"metadata.bad", "%s/metadata.xml: %s" % (xpkg, e))
else:
for atom in chain(*self.musedict.values()):
if atom is None:
continue
try:
atom = Atom(atom)
except InvalidAtom as e:
self.qatracker.add_error(
"metadata.bad",
"%s/metadata.xml: Invalid atom: %s" % (xpkg, e))
else:
if atom.cp != xpkg:
self.qatracker.add_error(
"metadata.bad",
"%s/metadata.xml: Atom contains "
"unexpected cat/pn: %s" % (xpkg, atom))
# Run other metadata.xml checkers
try:
check_metadata(_metadata_xml, get_herd_base(
self.repoman_settings))
except (UnknownHerdsError, ) as e:
metadata_bad = True
self.qatracker.add_error(
"metadata.bad", "%s/metadata.xml: %s" % (xpkg, e))
del e
# Only carry out if in package directory or check forced
if not metadata_bad:
if not self.xmllint.check(checkdir, repolevel):
self.qatracker.add_error("metadata.bad", xpkg + "/metadata.xml")
del metadata_bad
return