#!/usr/bin/python

import os
import sys
import cgi
import traceback
import types

sys.stderr = sys.stdout

serversToUseLocal = {
    "geeko.linuxdev.us.dell.com": "hb.us.dell.com",
    }

osarchmap = { 
    'el3-i386': 'rh30',
    'el3-x86_64': 'rh30_64',
    'el4-i386': 'rh40',
    'el6-x86_64': 'rh60_64',
    'el5-i386': 'rh50',
    'el5-x86_64': 'rh50_64',
    'sles9-i386': 'suse9',
    'sles9-x86_64': 'suse9_64',
    'sles10-i386': 'suse10',
    'sles10-x86_64': 'suse10_64',
    'sles11-i386': 'suse11',
    'sles11-x86_64': 'suse11_64',
    }

debuglog = []
def dprintlog():
    for line in debuglog: print line

def dprint(s=""):
    global debuglog
    debuglog.append(s)
    

def getRpmPath(rpmName, repoPath):
    # speed things up by not importing xml stuff for the common case. (hopefully)
    import xml.dom.minidom
    import gzip
    primary = os.path.join(repoPath, "repodata", "primary.xml.gz")
    f = gzip.GzipFile(primary, "r")
    dprint("# looking for %s" % rpmName)
    dom = xml.dom.minidom.parseString(f.read())
    for nodeElem in iterNodeElement( dom, "metadata", "package" ):
        arch = getNodeText(getNodeElement(nodeElem, "arch"))
        name = getNodeText(getNodeElement(nodeElem, "name"))
        location = getNodeAttribute(nodeElem, "href", "location")
        dprint("# rpm %s.%s  at %s"% (name, arch, location))
        if arch == "src":
            continue
        if name == rpmName:
            return location

    raise Exception()

def xformOsArch2Dir(osName, baseArch, native):
    if native == '0' and baseArch == 'x86_64':
        baseArch = 'i386'
    return osarchmap.get("%s-%s" % (osName, baseArch), "UNKNOWN_OS")

def handleVariants(osname):
    # RHEL variants
    if   osname.startswith("el3"): osname = "el3"
    if osname.startswith("rhel3"): osname = "el3"
    if   osname.startswith("el4"): osname = "el4"
    if osname.startswith("rhel4"): osname = "el4"
    if   osname.startswith("el5"): osname = "el5"
    if osname.startswith("rhel5"): osname = "el5"
    if   osname.startswith("el6"): osname = "el6"
    if osname.startswith("rhel6"): osname = "el6"
    if   osname.startswith("el7"): osname = "el7"
    if osname.startswith("rhel7"): osname = "el7"

    # Fedora backwards compat with old %{dist}
    if osname.startswith("fc"): osname = "f" + osname[2:]

    # Fedora BETA stuff
    # Roger Lopez TODO: fix the below to do pattern matching: f$NUM.xxx -> f$NUM+1
    if osname.startswith("f7."): osname = "f8"
    if osname.startswith("f8."): osname = "f9"
    if osname.startswith("f9."): osname = "f10"

    return osname

# handles the case where cgi is called like mirrors.cgi/options..
# rather than mirrors.cgi?options...
def handlePathInfo(pathInfo):
    altInput = {}
    if pathInfo:
        for pair in pathInfo[1:].split("&"):
            name, value = pair.split("=")
            altInput[name] = value
    return altInput

def xformServerName(serverName):
    return serversToUseLocal.get(serverName, serverName)

def sanitize_hex(n):
    if not n.startswith("0x"): n = "0x" + n
    try:
        return "0x%04x" % int(n,16)
    except ValueError:
        return "0x0000"

def main():
    print 'Content-type: text/plain'
    form = cgi.FieldStorage()
    scriptDir = os.path.realpath(os.path.dirname(sys.argv[0]))

    pathInfo    = os.environ.get("PATH_INFO", "")
    scriptFilename = os.environ.get("SCRIPT_FILENAME", os.path.realpath(sys.argv[0]))
    scriptName  = os.environ.get("SCRIPT_NAME", "");
    serverName  = os.environ.get("SERVER_NAME", "")
    serverPort  = os.environ.get("SERVER_PORT", "80")
    baseWebPath = os.path.dirname(scriptName)

    altInput = handlePathInfo(pathInfo)

    def get(name, default=None):
        return altInput.get(name, form.getvalue(name, default))

    rpmName   = get('getrpm', None)
    osName    = get('osname', 'null_OS')
    baseArch  = get('basearch', 'null_ARCH')
    native    = get('native', '0')
    debug     = get('debug', False)
    redirPath = get('redirpath', None)
    venid     = sanitize_hex(get('sys_ven_id', "0x0000"))
    devid     = sanitize_hex(get('sys_dev_id', "0x0000"))

    osName = handleVariants(osName)

    serverName = xformServerName(serverName)
    subdir = xformOsArch2Dir(osName, baseArch, native)
    sysidpath = "system.ven_%s.dev_%s" % (venid, devid)
    if not os.path.exists(os.path.join(scriptDir, sysidpath, subdir)):
        sysidpath="platform_independent"

    if not os.path.exists(os.path.join(scriptDir, sysidpath, subdir)):
        subdir="emptyrepo"

    url = "http://%s%s/%s/%s" % (serverName, baseWebPath, sysidpath, subdir)

    # if we hit this, something is physically wrong with the repo, this dir
    # should always exist
    if not os.path.exists(os.path.join(scriptDir, sysidpath, subdir)):
        print "Status: 404 Not Found"
        url = "# REPOSITORY CONFIGURATION ERROR: Please notify repository admin."

    if rpmName:
        url = url + "/" + getRpmPath(rpmName, os.path.join(scriptDir, sysidpath, subdir))

    if redirPath is not None:
        print "Status: 301 Moved Permanently";
        print "Location: %s%s" % (url, redirPath)

    print
    print url

    dprint("# scriptDir  : %s" % scriptDir)
    dprint("# osName     : %s" % osName)
    dprint("# baseArch   : %s" % baseArch)
    dprint("# native     : %s" % native)
    dprint("# serverName : %s" % serverName)
    dprint("# scriptName : %s" % scriptName)
    dprint("# rpmName    : %s" % rpmName)

    if debug:
        dprintlog()


#
# XML Helper functions
#

def getText(nodelist):
    rc = ""
    if nodelist is not None:
        for node in nodelist:
            if node.nodeType == node.TEXT_NODE or node.nodeType == node.CDATA_SECTION_NODE:
                rc = rc + node.data
    return rc

def getNodeText( node, *args ):
    rc = ""
    node = getNodeElement(node, *args)
    if node is not None:
        rc = getText( node.childNodes )
    return rc

def getNodeElement( node, *args ):
    if len(args) == 0:
        return node

    if node is not None:
        for search in node.childNodes:
            if isinstance(args[0], types.StringTypes):
                if search.nodeName == args[0]:
                    candidate = getNodeElement( search, *args[1:] )
                    if candidate is not None:
                        return candidate
            else:
                if search.nodeName == args[0][0]:
                    attrHash = args[0][1]
                    found = 1
                    for (key, value) in attrHash.items():
                        if search.getAttribute( key ) != value:
                            found = 0
                    if found:
                        candidate = getNodeElement( search, *args[1:] )
                        if candidate is not None:
                            return candidate

    return None

def iterNodeElement( node, *args ):
     if len(args) == 0:
        yield node
     elif node is not None:
        for search in node.childNodes:
            if isinstance(args[0], types.StringTypes):
                if search.nodeName == args[0]:
                    for elem in iterNodeElement( search, *args[1:] ):
                        yield elem
            else:
                if search.nodeName == args[0][0]:
                    attrHash = args[0][1]
                    found = 1
                    for (key, value) in attrHash.items():
                        if search.getAttribute( key ) != value:
                            found = 0
                    if found:
                        for elem in iterNodeElement( search, *args[1:] ):
                            yield elem

def getNodeAttribute(node, attrName, *args ):
    attribute = None
    aNode = getNodeElement(node, *args)
    if aNode is not None:
        attribute = aNode.getAttribute(attrName)
        if attribute == '':
            attribute = None
    return attribute



if __name__ == "__main__":
    try:
        main()
    except Exception, e:
        print
        traceback.print_exc()