#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright 2010 Per Øyvind Karlsen <peroyvind@mandriva.org>
#
# This program is free software. It may be redistributed and/or modified under
# the terms of the LGPL version 2.1 (or later).
#
# RPM5 python (egg) dependency generator.
#

from getopt import getopt
from os.path import basename, dirname, isdir, sep, splitext
from sys import argv, stderr, stdin, version
from pkg_resources import Distribution, FileMetadata, PathMetadata
from distutils.sysconfig import get_python_lib


opts, args = getopt(argv[1:], 'hPRSCOE',
        ['help', 'provides', 'requires', 'suggests', 'conflicts', 'obsoletes', 'extras'])

Provides = False
Requires = False
Suggests = False
Conflicts = False
Obsoletes = False
Extras = False

for o, a in opts:
    if o in ('-h', '--help'):
        print '-h, --help\tPrint help'
        print '-P, --provides\tPrint Provides'
        print '-R, --requires\tPrint Requires'
        print '-S, --suggests\tPrint Suggests'
        print '-C, --conflicts\tPrint Conflicts'
        print '-O, --obsoletes\tPrint Obsoletes (unused)'
        print '-E, --extras\tPrint Extras '
        exit(1)
    elif o in ('-P', '--provides'):
        Provides = True
    elif o in ('-R', '--requires'):
        Requires = True
    elif o in ('-S', '--suggests'):
        Suggests = True
    elif o in ('-C', '--conflicts'):
        Conflicts = True
    elif o in ('-O', '--obsoletes'):
        Obsoletes = True
    elif o in ('-E', '--extras'):
        Extras = True

if Requires:
    py_abi = True
else:
    py_abi = False
py_deps = {}
if args:
    files = args
else:
    files = stdin.readlines()
for f in files:
    f = f.strip()
    lower = f.lower()
    name = 'python(abi)'
    # add dependency based on path, versioned if within versioned python directory
    if py_abi and (lower.endswith('.py') or lower.endswith('.pyc') or lower.endswith('.pyo')):
        if not name in py_deps:
            py_deps[name] = []
        purelib = get_python_lib(standard_lib=1, plat_specific=0).split(version[:3])[0]
        platlib = get_python_lib(standard_lib=1, plat_specific=1).split(version[:3])[0]
        for lib in (purelib, platlib):
            if lib in f:
                spec = ('==',f.split(lib)[1].split(sep)[0])
                if not spec in py_deps[name]:
                    py_deps[name].append(spec)
    parent_name = dirname(f)
    # Determine provide, requires, conflicts & suggests based on egg metadata
    file_match = lower.endswith('.egg') or \
            lower.endswith('.egg-info') or \
            lower.endswith('.egg-link')
    dir_match = parent_name.endswith('.egg') or \
            parent_name.endswith('.egg-info') or \
            parent_name.endswith('.egg-link')
    if file_match or dir_match:
        dist_name = basename(f)
        if dir_match:
            path_item = dirname(parent_name)
            metadata = PathMetadata(path_item, parent_name)
        else:
            path_item = f
            if isdir(f):
                metadata = PathMetadata(parent_name, f)
            else:
                metadata = FileMetadata(f)
        dist = Distribution.from_location(path_item, dist_name, metadata)
        if not dist.py_version:
            continue
        py_major = dist.py_version[:1]
        if Provides:
            # If egg metadata says package name is python, we provide python(abi)
            if dist.key == 'python':
                name = 'python(abi)'
                if not name in py_deps:
                    py_deps[name] = []
                py_deps[name].append(('==', dist.py_version))
            name = 'pythonegg(%s)(%s)' % (py_major, dist.key)
            if not name in py_deps:
                py_deps[name] = []
            if dist.version:
                spec = ('==', dist.version)
                if not spec in py_deps[name]:
                    py_deps[name].append(spec)
        if Requires or (Suggests and dist.extras):
            name = 'python(abi)'
            # If egg metadata says package name is python, we don't add dependency on python(abi)
            if dist.key == 'python':
                py_abi = False
                if name in py_deps:
                    py_deps.pop(name)
            elif py_abi and dist.py_version:
                if not name in py_deps:
                    py_deps[name] = []
                spec = ('==', dist.py_version)
                if not spec in py_deps[name]:
                    py_deps[name].append(spec)
            deps = dist.requires()
            if Suggests:
                depsextras = dist.requires(extras=dist.extras)
                if not Requires:
                    for dep in reversed(depsextras):
                        if dep in deps:
                            depsextras.remove(dep)
                deps = depsextras
            # add requires/suggests based on egg metadata
            for dep in deps:
                name = 'pythonegg(%s)(%s)' % (py_major, dep.key)
                for spec in dep.specs:
                    if spec[0] != '!=':
                        if not name in py_deps:
                            py_deps[name] = []
                        if not spec in py_deps[name]:
                            py_deps[name].append(spec)
                if not dep.specs:
                    py_deps[name] = []
        # Unused, for automatic sub-package generation based on 'extras' from egg metadata
        # TODO: implement in rpm later, or...?
        if Extras:
            deps = dist.requires()
            extras = dist.extras
            print extras
            for extra in extras:
                print '%%package\textras-%s' % extra
                print 'Summary:\t%s extra for %s python egg' % (extra, dist.key)
                print 'Group:\t\tDevelopment/Python'
                depsextras = dist.requires(extras=[extra])
                for dep in reversed(depsextras):
                    if dep in deps:
                        depsextras.remove(dep)
                deps = depsextras
                for dep in deps:
                    for spec in dep.specs:
                        if spec[0] == '!=':
                            print 'Conflicts:\t%s %s %s' % (dep.key, '==', spec[1])
                        else:
                            print 'Requires:\t%s %s %s' % (dep.key, spec[0], spec[1])
                print '%%description\t%s' % extra
                print '%s extra for %s python egg' % (extra, dist.key)
                print '%%files\t\textras-%s\n' % extra
        if Conflicts:
            # Should we really add conflicts for extras?
            # Creating a meta package per extra with suggests on, which has
            # the requires/conflicts in stead might be a better solution...
            for dep in dist.requires(extras=dist.extras):
                name = dep.key
                for spec in dep.specs:
                    if spec[0] == '!=':
                        if not name in py_deps:
                            py_deps[name] = []
                        spec = ('==', spec[1])
                        if not spec in py_deps[name]:
                            py_deps[name].append(spec)
names = py_deps.keys()
names.sort()
for name in names:
    if py_deps[name]:
        # Print out versioned provides, requires, suggests, conflicts
        for spec in py_deps[name]:
            print '%s %s %s' % (name, spec[0], spec[1])
    else:
        # Print out unversioned provides, requires, suggests, conflicts
        print name