# -*- Mode: Python; coding: utf-8 -*-

##
## Copyright (C) 2010 Mandriva S.A. <http://www.mandriva.com>
## All rights reserved
##
## This program is free software: you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by the Free
## Software Foundation, either version 3 of the License, or any later version.
##
## 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 GNU General Public License for
## more details.
##
## You should have received a copy of the GNU General Public License along with
## this program.  If not, see <http://www.gnu.org/licenses/>.
##
##   Contributor(s):	J. Victor Duarte Martins <jvictor@mandriva.com>
##
"""
A synthesis.hdlist.cz parser
"""

import gzip
import re

__all__ = ['parse']

def _parse_rpm_name(name):
    """Returns (name, version, release, arch) tuple from a rpm
    package name.
    """

    # TODO This could be put in a package for general use in other
    # scripts.

    parts = name.split('-')
    release_arch = parts[-1].split('.')

    arch = release_arch[-1]
    release = '.'.join(release_arch[:-1])

    version = parts[-2]
    name = '-'.join(parts[0:-2])

    return (name, version, release, arch)

def _parse_rpm_capability_list(cap_str_list):
    """Parse a list of capabilities specifications strings and
    their restrictions.  Returns a list of dictionaries for each
    capability."""

    cap_list = []

    for cap_str in cap_str_list:
        m = re.match('^(?P<name>[^[]+)(?:\[\*])*(?P<restriction>\[.*])?',
                     cap_str)
        if m is None:
            continue    # ignore malformed names

        cap = {'name': m.group('name')}
        restriction = m.group('restriction')

        if restriction is not None:

            # TODO This will accept restrictions with only
            # conditions, or invalid conditions (like =, or >=<):
            r = re.match('\[(?P<condition>[<>=]*) *(?P<version>.*)]',
                         restriction)

            if r is not None:
                cap['restriction'] = {'condition': r.group('condition'),
                                      'version': r.group('version')}
        cap_list.append(cap)

    return tuple(cap_list)


def parse(hdlist, add_raw=False):
    """Create a generator of packages parsed from synthesis hdlist
    file."""

    pkg = {}
    for line in gzip.open(hdlist, 'rb'):

        if add_raw:
            if 'raw' not in pkg:
                pkg['raw'] = ''
            pkg['raw'] += line

        fields = line.rstrip('\n').split('@')[1:]
        ltype = fields.pop(0)

        if ltype == 'info':
            (pkg['name'],
             pkg['version'],
             pkg['release'],
             pkg['arch']) = _parse_rpm_name(fields.pop(0))
            for field in ('epoch', 'size', 'group'):
                pkg[field] = fields.pop(0)
            yield pkg
            pkg = {}
        elif ltype == 'summary':
            pkg['summary'] = fields.pop(0)
        elif ltype in ('requires', 'provides', 'conflict', 'obsoletes'):
            pkg[ltype] = _parse_rpm_capability_list(fields)
    
if __name__ == '__main__':
    
    hdlist = '/var/lib/urpmi/Main/synthesis.hdlist.cz'

    for p in parse(hdlist, True):
        print "-" * 70
        print p['raw']
        print ("name = %s\n"
        "version = %s\n"
        "release = %s\n"
        "arch = %s\n"
        "epoch = %s\n"
        "size = %s (%sK)\n"
        "group = %s\n"
        "summary:\n"
        "%s") % (p['name'], p['version'], p['release'], p['arch'],
                 p['epoch'], p['size'], int(p['size']) / 1024.0, p['group'],
                 p['summary'])

        for cap in ('requires', 'provides', 'conflict', 'obsoletes'):
            if cap in p:
                print cap
                for c in p[cap]:
                    print "- name: %s" % c['name'],
                    if 'restriction' in c:
                        print "%s %s" % (c['restriction']['condition'],
                                         c['restriction']['version']),
                    print
        raw_input()

