Michal Suchanek 3a12a8
#!/usr/bin/python
Benjamin Poirier 4e62ed
# -*- coding: utf-8 -*-,
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
import sys
Jeff Mahoney 89f2a2
import re
Jeff Mahoney 89f2a2
from optparse import OptionParser
Jeff Mahoney 89f2a2
from . import patch
Benjamin Poirier 4e62ed
from io import StringIO
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
diffstart = re.compile("^(---|\*\*\*|Index:|\+\+\+)[ \t][^ \t]\S+/|^diff -")
Jeff Mahoney 89f2a2
tag_regex = re.compile("(\S+):[ \t]*(.*)")
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
tag_map = {
Jeff Mahoney 89f2a2
    'Patch-mainline' : {
Jeff Mahoney 89f2a2
        'required' : True,
Jeff Mahoney 89f2a2
        'accepted' : [
Jeff Mahoney 89f2a2
            {
Jeff Mahoney 89f2a2
                # In mainline repo, tagged for release
Jeff Mahoney 89f2a2
                'name' : 'Version',
Jeff Mahoney 89f2a2
                'match': 'v?(\d+\.)+\d+(-rc\d+)?\s*$',
Jeff Mahoney 89f2a2
                'requires' : [ 'Git-commit' ],
Jeff Mahoney 89f2a2
                'excludes' : [ 'Git-repo' ],
Jeff Mahoney 89f2a2
            }, {    # In mainline repo but not tagged yet
Jeff Mahoney 89f2a2
                'name' : 'Version',
Jeff Mahoney 89f2a2
                'match': 'v?(\d+\.)+\d+(-rc\d+)?\s+or\s+v?(\d+\.)+\d+(-rc\d+)?\s+\(next release\)\s*$',
Jeff Mahoney 89f2a2
                'requires' : [ 'Git-commit' ],
Jeff Mahoney 89f2a2
                'excludes' : [ 'Git-repo' ],
Jeff Mahoney 89f2a2
            }, {
Jeff Mahoney 89f2a2
                # Queued in subsystem maintainer repo
Jeff Mahoney 89f2a2
                'name' : 'Queued',
Jeff Mahoney 89f2a2
                'match' : 'Queued(.*)',
Jeff Mahoney 89f2a2
                'requires' : [ 'Git-commit', 'Git-repo' ],
Jeff Mahoney 89f2a2
            }, {
Jeff Mahoney 89f2a2
                # Depends on another non-upstream patch
Jeff Mahoney 89f2a2
                'name' : 'Depends',
Jeff Mahoney 89f2a2
                'match' : 'Depends on\s+.+',
Jeff Mahoney 89f2a2
                'excludes' : [ 'Git-commit', 'Git-repo' ],
Jeff Mahoney 89f2a2
            }, {
Jeff Mahoney 89f2a2
                # No, typically used for patches that have review issues
Jeff Mahoney 89f2a2
                # but are not fundamentally rejected
Jeff Mahoney 89f2a2
                'name' : 'No',
Jeff Mahoney 89f2a2
                'match' : 'No,?\s+.+',
Jeff Mahoney 89f2a2
                'excludes' : [ 'Git-commit', 'Git-repo' ],
Jeff Mahoney 89f2a2
            }, {
Jeff Mahoney 89f2a2
                # Never, typically used for patches that have been rejected
Jeff Mahoney 89f2a2
                # for upstream inclusion but still have a compelling reason
Jeff Mahoney 89f2a2
                # for inclusion in a SUSE release or are otherwise
Jeff Mahoney 89f2a2
                # inappropriate for upstream inclusion (packaging, kABI,
Jeff Mahoney 89f2a2
                # SLES-only feature.)
Jeff Mahoney 89f2a2
                'name' : 'Never',
Jeff Mahoney 89f2a2
                'match' : 'Never,?\s+.+',
Jeff Mahoney 89f2a2
                'excludes' : [ 'Git-commit', 'Git-repo' ],
Jeff Mahoney 89f2a2
            }, {
Jeff Mahoney 89f2a2
                # Submitted upstream.  Description should provide either
Jeff Mahoney 89f2a2
                # a date and a mailing list or a URL to an archived post.
Jeff Mahoney 89f2a2
                'name' : 'Submitted',
Jeff Mahoney 89f2a2
                'match' : 'Submitted,?\s+.+',
Jeff Mahoney 89f2a2
                'excludes' : [ 'Git-commit', 'Git-repo' ],
Jeff Mahoney 89f2a2
            }, {
Jeff Mahoney 89f2a2
                # Should be used rarely.  Description should provide
Jeff Mahoney 89f2a2
                # reason for the patch not being accepted upstream.
Jeff Mahoney 89f2a2
                'name' : 'Not yet',
Jeff Mahoney 89f2a2
                'match' : 'Not yet,?\s+.+',
Jeff Mahoney 89f2a2
                'excludes' : [ 'Git-commit', 'Git-repo' ],
Jeff Mahoney 89f2a2
            }, {
Jeff Mahoney 89f2a2
                'match' : 'Submitted\s*$',
Jeff Mahoney 89f2a2
                'error' : 'Requires a description: <date> <list> or <url>',
Jeff Mahoney 89f2a2
                'excludes' : [ 'Git-commit', 'Git-repo' ],
Jeff Mahoney 89f2a2
            }, {
Jeff Mahoney 89f2a2
                'match' : 'Yes\s+$',
Jeff Mahoney 89f2a2
                'error' : 'Exact version required',
Jeff Mahoney 89f2a2
            }, {
Jeff Mahoney 89f2a2
                'match' : 'Yes.*(\d+\.)+\d+',
Jeff Mahoney 89f2a2
                'error' : '`Yes\' keyword is invalid',
Jeff Mahoney 89f2a2
                'excludes' : [ 'Git-commit', 'Git-repo' ],
Jeff Mahoney 89f2a2
            }, {
Jeff Mahoney 89f2a2
                'match' : '(Never|Not yet|No)\s*$',
Jeff Mahoney 89f2a2
                'error' : 'Requires a reason',
Jeff Mahoney 89f2a2
                'excludes' : [ 'Git-commit', 'Git-repo' ],
Jeff Mahoney 89f2a2
            },
Jeff Mahoney 89f2a2
        ],
Jeff Mahoney 89f2a2
        'requires_any' : [ 'Signed-off-by:SUSE', 'Acked-by:SUSE', 'From:SUSE',
Jeff Mahoney 89f2a2
                           'Reviewed-by:SUSE' ],
Jeff Mahoney 89f2a2
    },
Jeff Mahoney 89f2a2
    'Git-commit' : {
Jeff Mahoney 89f2a2
        'multi' : True,
Jeff Mahoney 89f2a2
        'accepted' : [
Jeff Mahoney 89f2a2
            {
Jeff Mahoney 89f2a2
                # 40-character SHA1 hash with optional partial tag
Jeff Mahoney 89f2a2
                'match' : '([0-9a-fA-F]){40}(\s+\(partial\))?',
Jeff Mahoney 89f2a2
            }
Jeff Mahoney 89f2a2
        ],
Jeff Mahoney 89f2a2
        'requires_any' : [ 'Patch-mainline:Version', 'Patch-mainline:Queued' ],
Jeff Mahoney 89f2a2
        'error' : "requires full SHA1 hash and optional (partial) tag",
Jeff Mahoney 89f2a2
    },
Jeff Mahoney 89f2a2
    'Git-repo' : {
Jeff Mahoney 89f2a2
        'accepted' : [
Jeff Mahoney 89f2a2
            {
Jeff Mahoney 89f2a2
                # Weak match for URL.  Abbreviated names are not acceptable.
Jeff Mahoney 89f2a2
                'match' : '.*/.*',
Jeff Mahoney 89f2a2
            }
Jeff Mahoney 89f2a2
        ],
Jeff Mahoney 89f2a2
        'requires' : [ 'Git-commit' ],
Jeff Mahoney 89f2a2
        'error' : "must contain URL pointing to repository containing the commit (and branch, if not master)",
Jeff Mahoney 89f2a2
    },
Jeff Mahoney 89f2a2
    'Signed-off-by' : {
Jeff Mahoney 89f2a2
        'multi' : True,
Jeff Mahoney 89f2a2
        'accepted' : [
Jeff Mahoney 89f2a2
            {
Jeff Mahoney 89f2a2
                'name' : 'SUSE',
Michal Suchanek ffde1c
                'match' : '.*@suse\.(com|de|cz)',
Jeff Mahoney 89f2a2
            },
Jeff Mahoney 89f2a2
            {
Jeff Mahoney 89f2a2
                'match' : '.*',
Jeff Mahoney 89f2a2
            }
Jeff Mahoney 89f2a2
        ],
Jeff Mahoney 89f2a2
    },
Jeff Mahoney 89f2a2
    'Acked-by' : {
Jeff Mahoney 89f2a2
        'multi' : True,
Jeff Mahoney 89f2a2
        'accepted' : [
Jeff Mahoney 89f2a2
            {
Jeff Mahoney 89f2a2
                'name' : 'SUSE',
Michal Suchanek ffde1c
                'match' : '.*@suse\.(com|de|cz)',
Jeff Mahoney 89f2a2
            },
Jeff Mahoney 89f2a2
            {
Jeff Mahoney 89f2a2
                'match' : '.*',
Jeff Mahoney 89f2a2
            }
Jeff Mahoney 89f2a2
        ],
Jeff Mahoney 89f2a2
    },
Jeff Mahoney 89f2a2
    'Reviewed-by' : {
Jeff Mahoney 89f2a2
        'multi' : True,
Jeff Mahoney 89f2a2
        'accepted' : [
Jeff Mahoney 89f2a2
            {
Jeff Mahoney 89f2a2
                'name' : 'SUSE',
Michal Suchanek ffde1c
                'match' : '.*@suse\.(com|de|cz)',
Jeff Mahoney 89f2a2
            },
Jeff Mahoney 89f2a2
            {
Jeff Mahoney 89f2a2
                'match' : '.*',
Jeff Mahoney 89f2a2
            }
Jeff Mahoney 89f2a2
        ],
Jeff Mahoney 89f2a2
    },
Jeff Mahoney 89f2a2
    'From' : {
Jeff Mahoney 89f2a2
        'multi' : True,
Jeff Mahoney d1e5de
        'required' : True,
Jeff Mahoney 89f2a2
        'accepted' : [
Jeff Mahoney 89f2a2
            {
Jeff Mahoney 89f2a2
                'name' : 'SUSE',
Michal Suchanek ffde1c
                'match' : '.*@suse\.(com|de|cz)',
Jeff Mahoney 89f2a2
            },
Jeff Mahoney 89f2a2
            {
Jeff Mahoney 89f2a2
                'match' : '.*',
Jeff Mahoney 89f2a2
            }
Jeff Mahoney 89f2a2
        ],
Jeff Mahoney 89f2a2
    },
Jeff Mahoney d1e5de
    'Subject' : {
Jeff Mahoney d1e5de
        'required' : True,
Jeff Mahoney d1e5de
        'accepted' :  [
Jeff Mahoney d1e5de
            {
Jeff Mahoney 3b2ea9
                'match' : '\S+',
Jeff Mahoney d1e5de
            },
Jeff Mahoney d1e5de
        ],
Jeff Mahoney d1e5de
    },
Jeff Mahoney ae9d1c
    'References' : {
Jeff Mahoney ae9d1c
        'required' : True,
Jeff Mahoney 37049b
        'required_on_update' : False,
Jeff Mahoney ae9d1c
        'multi' : True,
Jeff Mahoney ae9d1c
        'accepted' : [
Jeff Mahoney ae9d1c
            {
Jeff Mahoney ae9d1c
                'name' : 'SUSE',
Jeff Mahoney b7bee5
                'match' : '((bsc|boo|bnc|fate)#\d+|jsc#\w+-\d+)',
Jeff Mahoney ae9d1c
            },
Jeff Mahoney ae9d1c
            {
Jeff Mahoney ae9d1c
                'match' : '\S+',
Jeff Mahoney ae9d1c
            },
Jeff Mahoney ae9d1c
        ],
Jeff Mahoney ae9d1c
        'error' : "must contain list of references",
Jeff Mahoney ae9d1c
     # Enable to require real References tags
Jeff Mahoney ae9d1c
     #   'requires' : ['References:SUSE'],
Jeff Mahoney ae9d1c
    }
Jeff Mahoney 89f2a2
}
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
class ValidationError(patch.ValidationError):
Jeff Mahoney 89f2a2
    def __init__(self, name, msg):
Jeff Mahoney 89f2a2
        super(ValidationError, self).__init__(msg)
Jeff Mahoney 89f2a2
        self.name = name
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
class FormatError(ValidationError):
Jeff Mahoney 89f2a2
    def __init__(self, name, value, error=None):
Jeff Mahoney 89f2a2
        name = name.capitalize()
Jeff Mahoney 89f2a2
        if error is None:
Jeff Mahoney 89f2a2
            error = "invalid value"
Jeff Mahoney 89f2a2
        msg = "%s: `%s': %s." % (name, value, error)
Jeff Mahoney 89f2a2
        super(FormatError, self).__init__(name, msg)
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
class MissingTagError(ValidationError):
Jeff Mahoney 89f2a2
    def __init__(self, tag, requires):
Jeff Mahoney 89f2a2
        if not tag:
Jeff Mahoney 89f2a2
            tag = Tag("Policy", None)
Jeff Mahoney 89f2a2
        msg = "%s%s requires %s%s." % (tag.name, \
Jeff Mahoney 89f2a2
                    " (%s)" % tag.tagtype if tag.tagtype else "", \
Jeff Mahoney 250320
                    requires['name'], \
Jeff Mahoney 250320
                    " (%s)" % requires['type'] if 'type' in requires else "")
Jeff Mahoney 89f2a2
        self.target = [requires]
Jeff Mahoney 89f2a2
        super(MissingTagError, self).__init__(tag.name, msg)
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
class MissingMultiTagError(MissingTagError):
Jeff Mahoney 89f2a2
    def __init__(self, tag, requires):
Jeff Mahoney 89f2a2
        if not tag:
Jeff Mahoney 89f2a2
            tag = Tag("Policy", None)
Jeff Mahoney 89f2a2
        msg = "%s%s requires %s." % (tag.name, \
Jeff Mahoney 89f2a2
                " (%s)" % tag.tagtype if tag.tagtype else "", \
Jeff Mahoney 250320
                " or ".join(["%s%s" % (req['name'], \
Jeff Mahoney 250320
                    " (%s)" % req['type'] if 'type' in req else "") for req in requires]))
Jeff Mahoney 89f2a2
        self.target = requires
Jeff Mahoney 89f2a2
        super(MissingTagError, self).__init__(tag.name, msg)
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
class ExcludedTagError(ValidationError):
Jeff Mahoney 89f2a2
    def __init__(self, tag, excludes):
Jeff Mahoney 89f2a2
        msg = "%s%s excludes %s%s." % (tag.name,
Jeff Mahoney 89f2a2
                " (%s)" % tag.tagtype if tag.tagtype else "", \
Jeff Mahoney 250320
                excludes['name'], \
Jeff Mahoney 250320
                " (%s)" % excludes['type'] if 'type' in excludes else "")
Jeff Mahoney 89f2a2
        super(ExcludedTagError, self).__init__(tag.name, msg)
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
class DuplicateTagError(ValidationError):
Jeff Mahoney 89f2a2
    def __init__(self, name):
Jeff Mahoney 89f2a2
        name = name.capitalize()
Jeff Mahoney 89f2a2
        msg = "%s must only be used once, even if it is identical." % name
Jeff Mahoney 89f2a2
        super(DuplicateTagError, self).__init__(name, msg)
Jeff Mahoney 89f2a2
    pass
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
class EmptyTagError(ValidationError):
Jeff Mahoney 89f2a2
    def __init__(self, name):
Jeff Mahoney 89f2a2
        name = name.capitalize()
Jeff Mahoney 89f2a2
        msg = "%s: Value cannot be empty." % name
Jeff Mahoney 89f2a2
        super(EmptyTagError, self).__init__(name, msg)
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
class HeaderException(patch.PatchException):
Jeff Mahoney 89f2a2
    def tag_is_missing(self, name):
Jeff Mahoney 89f2a2
        try:
Jeff Mahoney 89f2a2
            for err in self._errors:
Jeff Mahoney 89f2a2
                if isinstance(err, MissingTagError):
Jeff Mahoney 89f2a2
                    for tag in err.target:
Jeff Mahoney 250320
                        if tag['name'].lower() == name.lower():
Jeff Mahoney 89f2a2
                            return True
Benjamin Poirier 4e62ed
        except KeyError as e:
Jeff Mahoney 89f2a2
            pass
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
        return False
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
class Tag:
Jeff Mahoney 89f2a2
    def __init__(self, name, value):
Jeff Mahoney 89f2a2
        self.name = name.lower().capitalize()
Jeff Mahoney 89f2a2
        self.value = value
Jeff Mahoney 89f2a2
        self.tagtype = None
Jeff Mahoney 89f2a2
        self.valid = False
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
    def __str__(self):
Jeff Mahoney 89f2a2
        return "%s: %s" % (self.name, self.value)
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
    def __repr__(self):
Jeff Mahoney 89f2a2
        type = "<none>"
Jeff Mahoney 89f2a2
        if self.tagtype:
Jeff Mahoney 89f2a2
            type = self.tagtype
Jeff Mahoney 89f2a2
        valid = "No"
Jeff Mahoney 89f2a2
        if self.valid:
Jeff Mahoney 89f2a2
            valid = "Yes"
Jeff Mahoney 89f2a2
        return "<Tag: name=%s value='%s' type='%s' valid='%s'>" % \
Jeff Mahoney 89f2a2
                (self.name, self.value, type, valid)
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
    def match_req(self, req):
Jeff Mahoney 250320
        if self.name == req['name']:
Jeff Mahoney 250320
            if 'type' not in req or self.tagtype == req['type']:
Jeff Mahoney 89f2a2
                if self.valid:
Jeff Mahoney 89f2a2
                    return True
Jeff Mahoney 89f2a2
        return False
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
class HeaderChecker(patch.PatchChecker):
Jeff Mahoney 37049b
    def __init__(self, stream, updating=False):
Jeff Mahoney 89f2a2
        patch.PatchChecker.__init__(self)
Jeff Mahoney 37049b
        self.updating = updating
Jeff Mahoney 89f2a2
        if isinstance(stream, str):
Jeff Mahoney 89f2a2
            stream = StringIO(stream)
Jeff Mahoney 37049b
        self.stream = stream
Jeff Mahoney 37049b
Jeff Mahoney 37049b
        self.requires = {}
Jeff Mahoney 37049b
        self.requires_any = {}
Jeff Mahoney 37049b
        self.excludes = {}
Jeff Mahoney 37049b
        self.tags = []
Jeff Mahoney 37049b
        self.errors = []
Jeff Mahoney 37049b
Jeff Mahoney 37049b
        self.do_patch()
Jeff Mahoney 37049b
Jeff Mahoney 37049b
    def get_rulename(self, ruleset, rulename):
Jeff Mahoney 37049b
        if rulename in ruleset:
Jeff Mahoney 37049b
            if self.updating:
Jeff Mahoney 4ceadb
                 updating_rule = "%s_on_update" % rulename
Jeff Mahoney 37049b
                 if updating_rule in ruleset:
Jeff Mahoney 37049b
                     return updating_rule
Jeff Mahoney 37049b
            return rulename
Jeff Mahoney 37049b
        return None
Jeff Mahoney 37049b
Jeff Mahoney 37049b
    def handle_requires(self, tag, ruleset, rulename):
Jeff Mahoney 37049b
        target = getattr(self, rulename)
Jeff Mahoney 37049b
Jeff Mahoney 37049b
        rulename = self.get_rulename(ruleset, rulename)
Jeff Mahoney 37049b
        if not rulename:
Jeff Mahoney 37049b
            return
Jeff Mahoney 37049b
Jeff Mahoney 37049b
        if isinstance(tag, str):
Jeff Mahoney 37049b
            tag = Tag(tag, None)
Jeff Mahoney 37049b
Jeff Mahoney 37049b
        for req in ruleset[rulename]:
Jeff Mahoney 37049b
            s = req.split(':')
Jeff Mahoney 37049b
            new_req = {
Jeff Mahoney 37049b
                'name' : s[0]
Jeff Mahoney 37049b
            }
Jeff Mahoney 37049b
            if len(s) > 1:
Jeff Mahoney 37049b
                new_req['type'] = s[1]
Jeff Mahoney 37049b
            if not tag in target:
Jeff Mahoney 37049b
                target[tag] = []
Jeff Mahoney 37049b
            target[tag].append(new_req)
Jeff Mahoney 37049b
Jeff Mahoney 37049b
    def do_patch(self):
Benjamin Poirier 4e62ed
        for line in self.stream:
Jeff Mahoney 89f2a2
            if diffstart.match(line):
Jeff Mahoney 89f2a2
                break
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
            m = tag_regex.match(line)
Jeff Mahoney 89f2a2
            if m:
Jeff Mahoney 89f2a2
                tag = Tag(m.group(1), m.group(2))
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
                if tag.name not in tag_map:
Jeff Mahoney 89f2a2
                    continue;
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
                if re.match("\s*$", tag.value):
Jeff Mahoney 37049b
                    self.errors.append(EmptyTagError(tag.name))
Jeff Mahoney 89f2a2
                    continue
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
                mapping = tag_map[tag.name]
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
                try:
Jeff Mahoney 89f2a2
                    multi = mapping['multi']
Benjamin Poirier 4e62ed
                except KeyError as e:
Jeff Mahoney 89f2a2
                    multi = False
Jeff Mahoney 89f2a2
Jeff Mahoney 37049b
                for t in self.tags:
Jeff Mahoney 89f2a2
                    if tag.name == t.name and not multi:
Jeff Mahoney 37049b
                        self.errors.append(DuplicateTagError(tag.name))
Jeff Mahoney 89f2a2
                        continue
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
                # No rules to process
Jeff Mahoney 89f2a2
                if 'accepted' not in mapping:
Jeff Mahoney 37049b
                    self.tags.append(tag)
Jeff Mahoney 89f2a2
                    continue
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
                match = False
Jeff Mahoney 89f2a2
                error = False
Jeff Mahoney 89f2a2
                for rule in mapping['accepted']:
Jeff Mahoney 89f2a2
                    if not re.match(rule['match'], tag.value, re.I):
Jeff Mahoney 89f2a2
                        continue
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
                    match = True
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
                    if 'name' in rule:
Jeff Mahoney 89f2a2
                        tag.tagtype = rule['name']
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
                    if 'error' in rule:
Jeff Mahoney 89f2a2
                        error = True
Jeff Mahoney 37049b
                        self.errors.append(FormatError(tag.name, tag.value,
Jeff Mahoney 89f2a2
                                                  rule['error']))
Jeff Mahoney 89f2a2
                        break
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
                    tag.valid = True
Jeff Mahoney 89f2a2
Jeff Mahoney 250320
                    # Handle rule-level dependencies
Jeff Mahoney 37049b
                    self.handle_requires(tag, rule, 'requires')
Jeff Mahoney 37049b
                    self.handle_requires(tag, rule, 'requires_any')
Jeff Mahoney 37049b
                    self.handle_requires(tag, rule, 'excludes')
Jeff Mahoney 89f2a2
                    break
Jeff Mahoney 89f2a2
Jeff Mahoney 250320
                # Handle tag-level dependencies
Jeff Mahoney 89f2a2
                if tag.valid:
Jeff Mahoney 37049b
                    self.handle_requires(tag, mapping, 'requires')
Jeff Mahoney 37049b
                    self.handle_requires(tag, mapping, 'requires_any')
Jeff Mahoney 37049b
                    self.handle_requires(tag, mapping, 'excludes')
Jeff Mahoney 89f2a2
Jeff Mahoney 37049b
                self.tags.append(tag)
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
                if error:
Jeff Mahoney 89f2a2
                    continue
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
                if not match:
Jeff Mahoney 89f2a2
                    errmsg = None
Jeff Mahoney 89f2a2
                    if 'error' in mapping:
Jeff Mahoney 89f2a2
                        errmsg = mapping['error']
Jeff Mahoney 37049b
                    self.errors.append(FormatError(tag.name, tag.value, errmsg))
Jeff Mahoney 89f2a2
                    continue
Jeff Mahoney 89f2a2
Jeff Mahoney 37049b
        for reqtag in self.requires:
Jeff Mahoney 37049b
            for req in self.requires[reqtag]:
Jeff Mahoney 89f2a2
                found = False
Jeff Mahoney 37049b
                for tag in self.tags:
Jeff Mahoney cf012c
                    found = tag.match_req(req)
Jeff Mahoney 89f2a2
                    if found:
Jeff Mahoney 89f2a2
                        break
Jeff Mahoney 89f2a2
                if not found:
Jeff Mahoney 37049b
                    self.errors.append(MissingTagError(reqtag, req))
Jeff Mahoney cf012c
Jeff Mahoney 37049b
        for reqtag in self.requires_any:
Jeff Mahoney cf012c
            found = False
Jeff Mahoney 37049b
            for req in self.requires_any[reqtag]:
Jeff Mahoney 37049b
                for tag in self.tags:
Jeff Mahoney cf012c
                    found = tag.match_req(req)
Jeff Mahoney cf012c
                    if found:
Jeff Mahoney cf012c
                        break
Jeff Mahoney cf012c
                if found:
Jeff Mahoney cf012c
                    break
Jeff Mahoney cf012c
            if not found:
Jeff Mahoney 37049b
                self.errors.append(
Jeff Mahoney 37049b
                        MissingMultiTagError(reqtag, self.requires_any[reqtag]))
Jeff Mahoney 89f2a2
Jeff Mahoney 37049b
        for reqtag in self.excludes:
Jeff Mahoney 37049b
            for req in self.excludes[reqtag]:
Jeff Mahoney cf012c
                found = False
Jeff Mahoney 37049b
                for tag in self.tags:
Jeff Mahoney cf012c
                    found = tag.match_req(req)
Jeff Mahoney 89f2a2
                    if found:
Jeff Mahoney cf012c
                        break
Jeff Mahoney cf012c
                if found:
Jeff Mahoney 37049b
                    self.errors.append(ExcludedTagError(reqtag, req))
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
        for entry in tag_map:
Jeff Mahoney 89f2a2
            if 'required' in tag_map[entry]:
Jeff Mahoney 89f2a2
                found = False
Jeff Mahoney 37049b
                for tag in self.tags:
Jeff Mahoney 89f2a2
                    if entry == tag.name:
Jeff Mahoney 89f2a2
                        found = True
Jeff Mahoney 89f2a2
                if not found:
Jeff Mahoney 37049b
                    required = True
Jeff Mahoney 37049b
                    if self.updating and 'required_on_update' in tag_map[entry]:
Jeff Mahoney 37049b
                        if not tag_map[entry]['required_on_update']:
Jeff Mahoney 37049b
                            required = False
Jeff Mahoney 37049b
                    if required:
Jeff Mahoney 37049b
                        self.errors.append(MissingTagError(None,
Jeff Mahoney 37049b
                                                           { 'name' : entry }))
Jeff Mahoney 37049b
Jeff Mahoney 37049b
        if self.errors:
Jeff Mahoney 37049b
            raise HeaderException(self.errors)
Jeff Mahoney 89f2a2
Jeff Mahoney 89f2a2
Checker = HeaderChecker