#!/usr/bin/python

import sys
import os
import os.path
import rpm
import string

# FIXME: we really want this information somewhere, but not in the pkgorder
# file itself.
from rhpl.log import log
from anaconda_log import anaconda_log
anaconda_log.open("/dev/null")
log.handler = anaconda_log

# set up rpm dependency whiteouts
import whiteout

rpmFD = None

import hdrlist
import rhpl.arch

def cmpHeaderByName(h1, h2):
    n1 = string.lower(h1.nevra())
    n2 = string.lower(h2.nevra())

    if n1 < n2:
	return -1
    elif n1 == n2:
	return 0;

    return 1

def addIfNeeded(pkg):
    global pkgOrder, pkgHash
    multi = rhpl.arch.getMultiArchInfo()
    if multi is not None:
        prim = multi[1]
        second = multi[2]
        
    diff = rhpl.arch.archDifference
    if not pkgHash.has_key (pkg.name):
        pkgHash[pkg.name] = [ pkg ]
        pkgOrder.append(pkg.nevra())
    elif multi is None:
        # this isn't a biarch arch, so we don't need to worry about
        # multiple glibcs
        return
    else:
        # this is a biarch arch.  we want to just have a primary package
        # for each here
        add = -1
        for p in pkgHash[pkg.name]:
            arch1 = p['arch']
            arch2 = pkg['arch']
            # same arch, don't worry about it
            if arch1 == arch2:
                add = 0
                break
            # if one of them doesn't work for the canon arch and the other
            # does, then one of them is for the secondary arch and we want
            # to add it.  
            if ((((diff(prim, arch1) == 0) and (diff(second, arch2) != 0)) or
                 ((diff(prim, arch2) == 0) and (diff(second, arch1) != 0))) and
                add == -1):
                add = 1
                
        if add == 1:
            pkgHash[pkg.name].append(pkg)
            pkgOrder.append(pkg.nevra())


outputted = []
# Now set up rpm to run the transaction deporder
testpath = '/tmp/pkgorder-' + str (os.getpid ())
os.system ("mkdir -p " + testpath + "/var/lib/rpm")

def runTsAndOutput(pkglist):
    global outputted

    # no sense trying with no packages
    if len(pkglist) == 0:
        return
    
    ts = rpm.TransactionSet(testpath)
    ts.setVSFlags(~(rpm.RPMVSF_NORSA|rpm.RPMVSF_NODSA))
    ts.setFlags(rpm.RPMTRANS_FLAG_ANACONDA)

    done = []
    for item in pkglist:
        # make sure we don't double add package names
        if item.hdr['name'] in done:
            continue
        done.append(item.hdr['name'])
#        print >> sys.stderr, "adding %s" %(item.name,)
        ts.addInstall(item.hdr, item.hdr, "i")

    ts.check()
    ts.order()

    theorder = ts.getKeys()
    if theorder is None: theorder = []
    # print the results.
    for p in theorder:
        def archSort(hdr1, hdr2):
            h1 = hdlist[hdr1[0]]
            h2 = hdlist[hdr2[0]]
            
            if rhpl.arch.score(h1['arch']) > rhpl.arch.score(h2['arch']):
                return -1
            elif rhpl.arch.score(h1['arch']) < rhpl.arch.score(h2['arch']):
                return 1
            return 0
    
        if p['name'] in outputted:
            continue
        outputted.append(p['name'])
        pkgs = hdlist.pkgnames[p['name']]
        pkgs.sort(archSort)
        for pnevra in pkgs:
            pkg = hdlist.pkgs[pnevra[0]]
            line = "%s-%s-%s.%s.rpm\n" % (pkg['name'], pkg['version'],
                                          pkg['release'], pkg['arch'])
            ofile.write(line)
    


# set PKGORDER_DEBUG to get rpm debugging
if os.environ.has_key("PKGORDER_DEBUG"):
    rpm.setVerbosity(rpm.RPMLOG_DEBUG)

productPath = None
ofile = sys.stdout

#parse optional arguments
args = [sys.argv[0]]
n = 1
while n < len(sys.argv):
    arg = sys.argv[n]
    n += 1
    if arg == "--debug":
        rpm.setVerbosity(rpm.RPMLOG_DEBUG)
    elif arg == "--file":
        ofile = open(sys.argv[n],'w')
        n += 1
    elif arg == "--product":
        productPath = sys.argv[n]
        n += 1
    else:
        args.append(arg)

if len(args) < 3:
    print "pkgorder <toppath> <arch>"
    sys.exit(1)

distDir = os.path.normpath(args[1])
arch = args[2]

# in previous versions, argument 3 was overloaded as both an optional
# productPath specification and the start of the optional complist
# specification. For script compatibility, we still have this overloading
# (as long as --product is not used).
if productPath is None:
    if len(args) > 3:
        productPath = args[3]
    else:
        productPath = "PU_IAS"

if not os.path.isdir(distDir):
    print "error: %s is not a directory" % distDir
    sys.exit(1)

disc1Dir = distDir + "-disc1"
disc1SrcDir = distDir + "-srpms"
disc2Dir = distDir + "-disc2"

# pull in the hdlist
f = distDir + "/%s/base/hdlist" % (productPath,)
try:
    hdlist = hdrlist.HeaderListFromFile(f)
    hdlist.mergeFullHeaders(distDir + "/%s/base/hdlist2" % (productPath,))    
except rpm.error:
    print "Failed to read header list", f
    sys.exit(1)
# and read the comps file
grpset = hdrlist.groupSetFromCompsFile("file://%s/%s/base/comps.xml"
                                       %(distDir,productPath), hdlist, doSelect = 0)
grpset.unselectAll()
#grpset.groups["everything"].select()

# work out the order we'd like to install everything in
pkgOrder = []
pkgHash = {}

# We always want all the kernels-.* in our package list, except for a few
for p in hdlist.values():
    package = p['name']
    if (package.startswith("kernel") and
        package in hdrlist.EverythingExclude.keys() and
        not package.endswith("-unsupported")):
        try:
            # FIXME: since we do unselect all at the end of the loop, these
            # stay selected for the first time through
            hdlist[package].select()
        except:
            print package
            print type(package)
        pkgOrder.append(hdlist[package].nevra())
        pkgHash[hdlist[package].name] = [ hdlist[package] ]

# Tier 1 language packages get priority.
tier1langs = ("en:en_US:de:de_DE:es:es_ES:fr:fr_FR:it:it_IT:ja:ja_JP:"
              "ko:ko_KR:zh:zh_CN:zh_TW:pt:pt_BR:en_GB:en_CA")


grpids = grpset.groups.keys()
grpids.sort()

# allow passing in an initial group list on the command line
if len(args) > 3:
    complist = args[3:]
else:
    complist = []
# then we add the things we have hard-coded.  this is kind of ugly and in
# a perfect world, we could figure it out automagically, but oh well
for g in ("core", "base", "text-internet", "web-server",
          "smb-server", "printing", "dialup", "server-cfg",
          "admin-tools"):
    if g not in complist: complist.append(g)
# now let's pull in all of workstation common
if grpset.groups.has_key("workstation-common"):
    comp = grpset.groups["workstation-common"]
    complist.append("workstation-common")
    for name in comp.groupreqs:
        if name not in complist:
            complist.append(name)
# a couple more that make sense to have early
for g in ("gnome-desktop", "emacs", "development-tools", "development-libs",
          "x-software-development", "gnome-software-development",
          "kde-desktop", "kde-software-development"):
    if g not in complist: complist.append(g)
        
latelangs = []
for id in grpids:
    if id in complist:
        continue
    if id == "everything": #this would be silly
        continue
    if ((grpset.groups[id].langonly is not None) and
        (tier1langs.find(grpset.groups[id].langonly) == -1)):
        latelangs.append(id)
    else:
        complist.append(id)
complist.extend(latelangs)

# for each comp, staring with base, list the packages
# in alphabetical order.
for id in complist:
    if not grpset.groups.has_key(id):
        continue
    group = grpset.groups[id]
    list = []

    group.select(selectOptional = 1)

    # append what got turned on to our order.
    for p in hdlist.pkgs.values():
        if p.isSelected():
            list.append(p)
    list.sort(cmpHeaderByName)

#    print >> sys.stderr, id
    for item in list:
        addIfNeeded(item)

    runTsAndOutput(list)
    grpset.unselectAll()
    
    
# add all of the packages that haven't been added yet.
list = []
for p in hdlist.pkgs.values():
    if not pkgHash.has_key (p.name):
        list.append(p)
list.sort(cmpHeaderByName)
for item in list:
    if item.nevra() not in pkgOrder:
        pkgOrder.append(item.nevra())

list = []
for p in pkgOrder:
    list.append(hdlist[p])

runTsAndOutput(list)

ofile.close()
