#!/usr/bin/python3
#---------------------------------------------------------------
# Project         : Linux-Mandrake
# Module          : rpm-rebuilder
# File            : compute-compile-order
# Version         : $Id: compute-compile-order,v 1.3 2000/10/02 05:44:57 flepied Exp $
# Author          : Frederic Lepied
# Created On      : Thu Sep 28 11:03:01 2000
# Purpose         : build a shell script on the output to be used as
# an orderer option for rpm-rebuilder.
#
# usage: compute-compile-order.py /SRPMS /RPMS
#---------------------------------------------------------------

import sys
import commands
import re
import os
import rpm

import site

if os.path.isdir("../rpmlint"):
    site.addsitedir("../rpmlint")
elif os.path.isdir("/usr/share/rpmlint"):
    site.addsitedir("/usr/share/rpmlint")
    
import Pkg

FORCED=['binutils', 'gcc', 'glibc', 'bzip2', 'rpm', 'spec-helper',
        'binutils', 'gcc', 'glibc', 'patch', 'bzip2', 'rpm', 'egcs']

# put some static values because some packages use dependencies on files
rpm2srpm_assoc={'rpmlib(VersionedDependencies)': None,
                '/usr/bin/gnroff': 'groff',
                '/usr/lib/libdb1.a': 'db1',
                '/bin/chmod': 'fileutils',
                '/usr/bin/host': 'bind',
                'rpmlib(CompressedFileNames)': None,
                '/usr/bin/latex': 'tetex',
                '/usr/bin/dvips': 'tetex',
                '/usr/bin/perl': 'perl'}
srpm_count={}
srpm_dep={}

# cvs is for the buggy package version of Glide_V3-DRI
version_regex=re.compile('(.*?)-([0-9]|cvs).+')

def strip_version_info(name):
    res=version_regex.search(name)
    if res:
        return res.group(1)
    else:
        return name

def process_requires(name, reqs, prereqs):
    deps=[]
    for d in reqs + prereqs:
        if d[0] == '/':
            sys.stderr.write("warning %s has a file dependency: %s\n" % (name, d[0]))
        try:
            src=rpm2srpm_assoc[d[0]]
        except KeyError:
            if name != d[0]:
                sys.stderr.write("error in process_requires for %s %s\n" % (name, d[0]))
            else:
                sys.stderr.write("error no binary package for %s\n" % d[0])
            src=d[0]
        if src:
            deps.append(src)
    srpm_dep[name]=deps
DONE=[]

def build_closure(name, direct_deps):
    if not name in DONE:
        # append first to break loops
        DONE.append(name)
        closure=direct_deps
        for n in direct_deps:
            try:
                ret=build_closure(n, srpm_dep[n])
                if name in ret:
                    sys.stderr.write("detected loop between %s and %s: %s\n" % (name, n, ret))
                closure=closure+ret
            except KeyError:
                sys.stderr.write("no dep for %s(%s)\n" % (n, name))
        srpm_dep[name]=uniquify(closure)
        sys.stderr.write("%s: %s\n" % (name, srpm_dep[name]))
    return srpm_dep[name]
    
# sort in reverse order according to srpm_count
def count_sort(a, b):
    return cmp(srpm_count[b], srpm_count[a])

def uniquify(list):
    sorted=list
    sorted.sort()
    new=[]
    current=None
    for l in sorted:
        if current != l:
            new.append(l)
            current=l
    return new

# main

srpms_dir=sys.argv[1]
srpms=os.listdir(srpms_dir)
rpms_dir=sys.argv[2]
rpms=os.listdir(rpms_dir)

sys.stderr.write("reading binary rpms\n")
for p in rpms:
    file=rpms_dir + '/' + p
    try:
        pkg = Pkg.Pkg(file, "/tmp")
    except:
        sys.stderr.write("\nerror reading %s\n" % file)
        continue
    srpm=strip_version_info(pkg[rpm.RPMTAG_SOURCERPM])
    rpm2srpm_assoc[pkg[rpm.RPMTAG_NAME]]=srpm
    for prov in pkg.provides():
        rpm2srpm_assoc[prov[0]]=srpm
        
sys.stderr.write("reading source rpms\n")
for s in srpms:
    file=srpms_dir + '/' + s
    try:
        pkg = Pkg.Pkg(file, "/tmp")
    except:
        sys.stderr.write("error reading %s\n" % file)
        continue
    process_requires(pkg[rpm.RPMTAG_NAME], pkg.requires(), pkg.prereq())

sys.stderr.write("building closures\n")
for n in srpm_dep.keys():
    build_closure(n, srpm_dep[n])
    
sys.stderr.write("calculating compile order\n")
for srpm in srpm_dep.keys():
    if not srpm_count.has_key(srpm):
        srpm_count[srpm] = 0
        
    for d in srpm_dep[srpm]:
        try:
            srpm_count[d] = srpm_count[d] + 1
        except KeyError:
            srpm_count[d] = 1

#for f in srpm_dep.keys():
#    print f, 'depends on', srpm_dep[f]

# force the count of the packages for which the order is forced because
# they are implicit (gcc, glibc, ...)
for n in FORCED:
    try:
        del srpm_count[n]
    except KeyError:
        pass

names=srpm_count.keys()
names.sort(count_sort)

#for f in names:
#    print f, srpm_count[f]

rank=0

print '#!/bin/sh'
print 'uno=$1;ord=$2'

for f in FORCED + names:
    print '[ -f $uno/%s-[0-9]* ] && ln -s $uno/%s-[0-9]* $ord/%05d-%s-build.src.rpm' % (f, f, rank, f)
    rank=rank+1
    
# Local variables:
# mode: python
# End:
#
# compute-compile-order ends here
