<commit_before>#
# Copyright (c) 2008-2009 rPath, Inc.
#
# This program is distributed under the terms of the Common Public License,
# version 1.0. A copy of this license should have been distributed with this
# source file in a file called LICENSE. If it is not present, the license
# is always available at http://www.rpath.com/permanent/licenses/CPL-1.0.
#
# This program is distributed in the hope that it will be useful, but
# without any warranty; without even the implied warranty of merchantability
# or fitness for a particular purpose. See the Common Public License for
# full details.
#

"""
Module for parsing package sections of xml files from the repository metadata.
"""

__all__ = ('PackageXmlMixIn', 'PackageCompare', )

import os

from rpath_xmllib import api1 as xmllib

from updatebot.lib import util

from repomd.errors import UnknownElementError, UnknownAttributeError
from repomd.xmlcommon import SlotNode

class PackageCompare(object):
    def __str__(self):
        return '-'.join([self.name, self.epoch, self.version, self.release,
                         self.arch])

    def __hash__(self):
        # NOTE: We do not hash on epoch, because not all package objects will
        #       have epoch set. This will cause hash collisions that should be
        #       handled in __cmp__.
        return hash((self.name, self.version, self.release, self.arch))

    def __cmp__(self, other):
        return util.packageCompareByName(self, other)


class _Package(SlotNode, PackageCompare):
    """
    Python representation of package section of xml files from the repository
    metadata.
    """

    # R0902 - Too many instance attributes
    # pylint: disable-msg=R0902

    __slots__ = ('name', 'arch', 'epoch', 'version', 'release',
                 'checksum', 'checksumType', 'summary', 'description',
                 'fileTimestamp', 'buildTimestamp', 'packageSize',
                 'installedSize', 'archiveSize', 'location', 'format',
                 'license', 'vendor', 'group', 'buildhost',
                 'sourcerpm', 'headerStart', 'headerEnd',
                 'licenseToConfirm', 'files')

    # All attributes are defined in __init__ by iterating over __slots__,
    # this confuses pylint.
    # W0201 - Attribute $foo defined outside __init__
    # pylint: disable-msg=W0201


    def addChild(self, child):
        """
        Parse children of package element.
        """

        # R0912 - Too many branches
        # pylint: disable-msg=R0912

        # R0915 - Too many statements
        # pylint: disable-msg=R0915

        # E0203 - Access to member 'files' before its definition line 84
        # files is set to None by the superclasses __init__
        # pylint: disable-msg=E0203

        n = child.getName()
        if n == 'name':
            self.name = child.finalize()
        elif n == 'arch':
            self.arch = child.finalize()
        elif n == 'version':
            self.epoch = child.getAttribute('epoch')
            self.version = child.getAttribute('ver')
            self.release = child.getAttribute('rel')
        elif n == 'checksum':
            self.checksum = child.finalize()
            self.checksumType = child.getAttribute('type')
        elif n == 'summary':
            self.summary = child.finalize()
        elif n == 'description':
            self.description = child.finalize()
        elif n == 'packager':
            self.packager = child.finalize()
        elif n == 'url':
            self.url = child.finalize()
        elif n == 'time':
            self.fileTimestamp = child.getAttribute('file')
            self.buildTimestamp = child.getAttribute('build')
        elif n == 'size':
            self.packageSize = child.getAttribute('package')
            self.installedSize = child.getAttribute('installed')
            self.archiveSize = child.getAttribute('archive')
        elif n == 'location':
            self.location = child.getAttribute('href')
        elif n == 'file':
            if self.files is None:
                self.files = []
            self.files.append(child.finalize())
        elif child.getName() == 'format':
            self.format = []
            for node in child.iterChildren():
                nn = node.getName()
                if nn == 'rpm:license':
                    self.license = node.getText()
                elif nn == 'rpm:vendor':
                    self.vendor = node.getText()
                elif nn == 'rpm:group':
                    self.group = node.getText()
                elif nn == 'rpm:buildhost':
                    self.buildhost = node.getText()
                elif nn == 'rpm:sourcerpm':
                    self.sourcerpm = node.getText()
                elif nn == 'rpm:header-range':
                    self.headerStart = node.getAttribute('start')
                    self.headerEnd = node.getAttribute('end')
                elif nn in ('rpm:provides', 'rpm:requires',
                                        'rpm:obsoletes', 'rpm:recommends',
                                        'rpm:conflicts', 'suse:freshens',
                                        'rpm:enhances', 'rpm:supplements',
                                        'rpm:suggests', ):
                    self.format.append(node)
                elif nn == 'file':
                    pass
                else:
                    raise UnknownElementError(node)
        elif n == 'pkgfiles':
            pass
        elif n == 'suse:license-to-confirm':
            self.licenseToConfirm = child.finalize()
        else:
            raise UnknownElementError(child)

    def __repr__(self):
        return os.path.basename(self.location)

    def __cmp__(self, other):
        pkgcmp = PackageCompare.__cmp__(self, other)
        if pkgcmp != 0:
            return pkgcmp

        # Compare checksum only for equality, otherwise sorting will result in
        # checksum ordering.
        if (self.checksum and other.checksum and
            self.checksumType == other.checksumType and
            self.checksum == other.checksum):
            return 0

        # Compare on archiveSize for equality only. This is needed for rpms
        # that have identical contents, but may have been rebuilt. Idealy we
        # would use file checksums for this, but we don't have the payload
        # contents available at this time.
        if (self.archiveSize and other.archiveSize and
            self.archiveSize == other.archiveSize):
            return 0

        return cmp(self.location, other.location)

    def getNevra(self):
        """
        Return the name, epoch, version, release, and arch the package.
        """

        return (self.name, self.epoch, self.version, self.release, self.arch)

    def getConaryVersion(self):<commit_msg>compare packages on arch before checksum in case of different-arch packages with same content<commit_after>#
# Copyright (c) 2008-2009 rPath, Inc.
#
# This program is distributed under the terms of the Common Public License,
# version 1.0. A copy of this license should have been distributed with this
# source file in a file called LICENSE. If it is not present, the license
# is always available at http://www.rpath.com/permanent/licenses/CPL-1.0.
#
# This program is distributed in the hope that it will be useful, but
# without any warranty; without even the implied warranty of merchantability
# or fitness for a particular purpose. See the Common Public License for
# full details.
#

"""
Module for parsing package sections of xml files from the repository metadata.
"""

__all__ = ('PackageXmlMixIn', 'PackageCompare', )

import os

from rpath_xmllib import api1 as xmllib

from updatebot.lib import util

from repomd.errors import UnknownElementError, UnknownAttributeError
from repomd.xmlcommon import SlotNode

class PackageCompare(object):
    def __str__(self):
        return '-'.join([self.name, self.epoch, self.version, self.release,
                         self.arch])

    def __hash__(self):
        # NOTE: We do not hash on epoch, because not all package objects will
        #       have epoch set. This will cause hash collisions that should be
        #       handled in __cmp__.
        return hash((self.name, self.version, self.release, self.arch))

    def __cmp__(self, other):
        return util.packageCompareByName(self, other)


class _Package(SlotNode, PackageCompare):
    """
    Python representation of package section of xml files from the repository
    metadata.
    """

    # R0902 - Too many instance attributes
    # pylint: disable-msg=R0902

    __slots__ = ('name', 'arch', 'epoch', 'version', 'release',
                 'checksum', 'checksumType', 'summary', 'description',
                 'fileTimestamp', 'buildTimestamp', 'packageSize',
                 'installedSize', 'archiveSize', 'location', 'format',
                 'license', 'vendor', 'group', 'buildhost',
                 'sourcerpm', 'headerStart', 'headerEnd',
                 'licenseToConfirm', 'files')

    # All attributes are defined in __init__ by iterating over __slots__,
    # this confuses pylint.
    # W0201 - Attribute $foo defined outside __init__
    # pylint: disable-msg=W0201


    def addChild(self, child):
        """
        Parse children of package element.
        """

        # R0912 - Too many branches
        # pylint: disable-msg=R0912

        # R0915 - Too many statements
        # pylint: disable-msg=R0915

        # E0203 - Access to member 'files' before its definition line 84
        # files is set to None by the superclasses __init__
        # pylint: disable-msg=E0203

        n = child.getName()
        if n == 'name':
            self.name = child.finalize()
        elif n == 'arch':
            self.arch = child.finalize()
        elif n == 'version':
            self.epoch = child.getAttribute('epoch')
            self.version = child.getAttribute('ver')
            self.release = child.getAttribute('rel')
        elif n == 'checksum':
            self.checksum = child.finalize()
            self.checksumType = child.getAttribute('type')
        elif n == 'summary':
            self.summary = child.finalize()
        elif n == 'description':
            self.description = child.finalize()
        elif n == 'packager':
            self.packager = child.finalize()
        elif n == 'url':
            self.url = child.finalize()
        elif n == 'time':
            self.fileTimestamp = child.getAttribute('file')
            self.buildTimestamp = child.getAttribute('build')
        elif n == 'size':
            self.packageSize = child.getAttribute('package')
            self.installedSize = child.getAttribute('installed')
            self.archiveSize = child.getAttribute('archive')
        elif n == 'location':
            self.location = child.getAttribute('href')
        elif n == 'file':
            if self.files is None:
                self.files = []
            self.files.append(child.finalize())
        elif child.getName() == 'format':
            self.format = []
            for node in child.iterChildren():
                nn = node.getName()
                if nn == 'rpm:license':
                    self.license = node.getText()
                elif nn == 'rpm:vendor':
                    self.vendor = node.getText()
                elif nn == 'rpm:group':
                    self.group = node.getText()
                elif nn == 'rpm:buildhost':
                    self.buildhost = node.getText()
                elif nn == 'rpm:sourcerpm':
                    self.sourcerpm = node.getText()
                elif nn == 'rpm:header-range':
                    self.headerStart = node.getAttribute('start')
                    self.headerEnd = node.getAttribute('end')
                elif nn in ('rpm:provides', 'rpm:requires',
                                        'rpm:obsoletes', 'rpm:recommends',
                                        'rpm:conflicts', 'suse:freshens',
                                        'rpm:enhances', 'rpm:supplements',
                                        'rpm:suggests', ):
                    self.format.append(node)
                elif nn == 'file':
                    pass
                else:
                    raise UnknownElementError(node)
        elif n == 'pkgfiles':
            pass
        elif n == 'suse:license-to-confirm':
            self.licenseToConfirm = child.finalize()
        else:
            raise UnknownElementError(child)

    def __repr__(self):
        return os.path.basename(self.location)

    def __cmp__(self, other):
        pkgcmp = PackageCompare.__cmp__(self, other)
        if pkgcmp != 0:
            return pkgcmp

        # Compare arch before checksum to catch cases of multiple
        # arch-specific packages that happen to have same content
        # (e.g. SLES xorg-x11-fonts packages).
        archcmp = cmp(self.arch, other.arch)
        if archcmp != 0:
            return archcmp
        
        # Compare checksum only for equality, otherwise sorting will result in
        # checksum ordering.
        if (self.checksum and other.checksum and
            self.checksumType == other.checksumType and
            self.checksum == other.checksum):
            return 0

        # Compare on archiveSize for equality only. This is needed for rpms
        # that have identical contents, but may have been rebuilt. Idealy we
        # would use file checksums for this, but we don't have the payload
        # contents available at this time.
        if (self.archiveSize and other.archiveSize and
            self.archiveSize == other.archiveSize):
            return 0

        return cmp(self.location, other.location)

    def getNevra(self):
        """
        Return the name, epoch, version, release, and arch the package.
        """

        return (self.name, self.epoch, self.version, self.release, self.arch)

    def getConaryVersion(self):
{'fraction_non_alphanumeric': 0.10012166320761469, 'fraction_numerical': 0.008516424533027983, 'mean_word_length': 1.933249370277078, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 10}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1316343', 'n_tokens_mistral': 3753, 'n_tokens_neox': 3548, 'n_words': 1131}