#!/usr/bin/python

import os
import sys
import cgi
import traceback
import types

sys.stderr = sys.stdout

projectXref = {}

rpmNameXrefServer = {
    }

serversToUseLocal = {
    "geeko.linuxdev.us.dell.com": "http://hb.us.dell.com/repo/community",
    "linuxlib.us.dell.com":       "http://hb.us.dell.com/repo/community",
    }

#defaultRedirUrl = "http://download.opensuse.org/repositories/"

def getRpmPath(rpmName, baseDir, osName, baseArch, project):
    # speed things up by not importing xml stuff for the common case. (hopefully)
    import xml.dom.minidom
    import gzip
    repoPath = os.path.join(baseDir, xformProject2Dir(project), xformOsArch2Dir(osName, baseArch))
    repomd = os.path.join(repoPath, "repodata", "repomd.xml")
    primary = os.path.join(repoPath, "repodata", "primary.xml.gz")
    f = gzip.GzipFile(primary, "r")
    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")
        if arch == "src":
            continue
        if name == rpmName:
            return location

    raise Exception()

def xformRpmName(rpmName, serverName):
    return rpmNameXrefServer.get("%s:%s" % (serverName, rpmName), rpmName)

def xformProject2Dir(project):
    d = projectXref.get(project, project)
    d = d.replace(":", ":/")
    return d

def xformOsArch2Dir(osName, baseArch):
    return "%s-%s" % (osName, baseArch)

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"

    # Fedora BETA stuff
    if osname.startswith("f7."): osname = "f8"
    if osname.startswith("f8."): osname = "f9"
    if osname.startswith("f9."): osname = "f10"

    # Fedora backwards compat with old %{dist}
    if osname.startswith("fc7"): osname = "f7"
    if osname.startswith("fc8"): osname = "f8"
    if osname.startswith("fc9"): osname = "f9"
    if osname.startswith("fc10"): 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 getBaseRedirUrl(serverName, uri):
    return serversToUseLocal.get(serverName, "http://%s%s" % (serverName, uri) )

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", "/repo/community/mirrors.cgi");
    serverName  = os.environ.get("SERVER_NAME", "linux.dell.com")
    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')
    debug     = get('debug', False)
    project   = get('project', "content")
    redirPath = get('redirpath', None)

    osName = handleVariants(osName)

    baseRedirUrl = getBaseRedirUrl(serverName, baseWebPath)
    project = xformProject2Dir(project)
    subdir = xformOsArch2Dir(osName, baseArch)
    url = "%s/%s/%s" % (baseRedirUrl, project, subdir)

    if rpmName:
        rpmName = xformRpmName(rpmName, serverName)
        url = url + "/" + getRpmPath(rpmName, os.path.dirname(scriptFilename), osName, baseArch, project)

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

    print
    print url

    if debug:
        print
        print "# scriptDir  : %s" % scriptDir
        print "# osName     : %s" % osName
        print "# baseArch   : %s" % baseArch
        print "# serverName : %s" % serverName
        print "# scriptName: %s" % scriptName
        print "# rpmName: %s" % rpmName


#
# 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()

