#!/usr/bin/python
# -*- coding: utf-8 -*-
#
#    MirrorKit - A python frontend to debmirror
#    Copyright (C) 2008-2009  Stephane Graber <stgraber@ubuntu.com>
#              (C) 2009       Michael Jeanson <mjeanson@rlnx.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

from urlparse import urlparse
import xml.dom.minidom, time, sys, subprocess, os

def SyncDEB(source, destination, dist, section, arch):
    "Return the syncronisation command for an APT source (Debian)"

    #Source format: <method>://<host>/<root>
    #Destination format: Unix path
    #Dist format: Distributions to mirror
    #Section format: Sections to mirror
    #Arch format: Architectures to mirror
    (method, host, path, Null, Null, Null)=urlparse(source)

    cmd="debmirror -v --host="+host
    if path:
        cmd+=" --root="+path
    cmd+=" --dist="+dist+" --section="+section+" --arch="+arch+" -m --progress --nosource --method="+method+" --ignore-release-gpg"
    if config["proxy"]:
        cmd+=" --proxy="+config["proxy"]
    cmd+=" "+destination
    return cmd

def XMLgetParameter(node,parameter):
    "Get a parameter from 'node'"

    value=""
    for node2 in node.getElementsByTagName(parameter):
        for node3 in node2.childNodes:
            if node3.nodeType == xml.dom.minidom.Node.TEXT_NODE:
                value += node3.data
    return value

def LoadMirrorList(list):
    "Load a XML file and return an array of dictionaries containing the mirror properties"

    mirrors=[]
    doc=xml.dom.minidom.parse(list)
    for node in doc.getElementsByTagName("mirror"):
        #Create the list of mirror properties and put them into a dictionary
        mirror={
            "name": node.getAttribute("name"),
            "type": XMLgetParameter(node,"type"),
            "source": XMLgetParameter(node,"source"), 
            "dist": XMLgetParameter(node,"dist"),
            "section": XMLgetParameter(node,"section"),
            "arch": XMLgetParameter(node,"arch"),
            "enabled": XMLgetParameter(node,"enabled"),
            "help": XMLgetParameter(node,"help")
        }
        if mirror["enabled"] != "0" and mirror["name"] != "admin" and mirror["name"] != "help": #generator and help are reserved names
            mirrors.append(mirror)
    return mirrors

def LoadConfig(list):
    doc=xml.dom.minidom.parse(list)
    config={}
    for node in doc.getElementsByTagName("config"):
        config={
            "www-url": XMLgetParameter(node,"www-url"),
            "www-dir": XMLgetParameter(node,"www-dir"),
            "log-dir": XMLgetParameter(node,"log-dir"),
            "template-html": XMLgetParameter(node,"template-html"),
            "proxy": XMLgetParameter(node,"proxy"),
            "help": XMLgetParameter(node,"help")
        }
    return config

def Now():
    return "["+time.strftime("%H:%M:%S")+"] "

def GenHTMLReport(mirror,log,error):
    "Generate HTML report from the log"

    if error != "":
        result="Failure"
        result_html="<span id=\"failure\">Failure</span>"
    else:
        result="Success"
        result_html="<span id=\"success\">Success</span>"
        error="No error reported"

    if log == "":
        log="No log message reported"

    file=open(config['template-html'],"r")
    page=file.read()
    file.close()
    size=subprocess.Popen(("du","-h","-s",config['www-dir']+"/"+mirror["name"]),stdout=subprocess.PIPE,stderr=subprocess.PIPE).stdout.read().split("\t")[0]

    page=page.replace("WWW_URL",config['www-url'])
    page=page.replace("RESULT_HTML",result_html)
    page=page.replace("RESULT",result)
    page=page.replace("MIRROR_CMD",mirror["cmd"])
    page=page.replace("MIRROR_SIZE",size)
    page=page.replace("MIRROR_TYPE",mirror["type"])
    page=page.replace("MIRROR_SOURCE",mirror["source"])
    page=page.replace("MIRROR_DESTINATION",config['www-dir']+"/"+mirror["name"])
    page=page.replace("MIRROR_DIST",mirror["dist"])
    page=page.replace("MIRROR_SECTION",mirror["section"])
    page=page.replace("MIRROR_ARCH",mirror["arch"])
    page=page.replace("MIRROR_NAME",mirror["name"])
    page=page.replace("DATE",time.strftime("%Y-%m-%d %H:%M:%S"))
    page=page.replace("LOG",log.replace("\n","<br />"))
    page=page.replace("ERROR",error.replace("\n","<br />"))

    filename=mirror["name"]+"-"+time.strftime("%Y%m%d.%H-%M-%S")+".html"
    file=open(config["log-dir"]+"/"+filename,"w+")
    file.write(page)
    file.close()
    try:
        os.remove(config["log-dir"]+"/"+mirror["name"]+".html")
    except:
        print Now()+"Symlink for "+mirror["name"]+" doesn't yet exist, creating."
    os.symlink(filename,config["log-dir"]+"/"+mirror["name"]+".html")

if len(sys.argv) != 2:
    print "Usage: "+sys.argv[0]+" <xml config file>"
    sys.exit(1)

mirrors=LoadMirrorList(sys.argv[1])
config=LoadConfig(sys.argv[1])
try:
    os.mkdir(config["www-dir"])
    print Now()+"Creating web directory ("+config["www-dir"]+")"
except:
    print Now()+"Web directory already exists ("+config["www-dir"]+")"

for mirror in mirrors:
    log=""
    error=""
    try:
        os.mkdir(config["www-dir"]+"/"+mirror["name"])
        print Now()+"Creating mirror directory ("+config["www-dir"]+")"
    except:
        print Now()+"Mirror directory already exists ("+config["www-dir"]+"/"+mirror["name"]+")"
    if mirror["type"] == "deb":
        mirror["cmd"]=SyncDEB(mirror["source"],config["www-dir"]+"/"+mirror["name"],mirror["dist"],mirror["section"],mirror["arch"])
    if mirror["type"] == "suse":
        mirror["cmd"]="echo Not implemented yet"
    if mirror["cmd"]:
        stdout=open(config["log-dir"]+"/stdout.txt","w+")
        stderr=open(config["log-dir"]+"/stderr.txt","w+")
        cmd=subprocess.Popen(mirror["cmd"].split(" "),stdout=stdout,stderr=stderr)
        print Now()+"Syncronisation started ("+mirror["name"]+")"
        cmd.wait()
        stdout.seek(0)
        stderr.seek(0)
        log=stdout.read()
        error=stderr.read()
        stdout.close()
        stderr.close()
        GenHTMLReport(mirror,log,error)
        print Now()+"Syncronisation completed ("+mirror["name"]+")"

if config["help"] == "1":
    print Now()+"Generating directory index"
    file=open(config["www-dir"]+"/help.html","w+")
    page="<h1>Mirrorkit</h1><table cellpadding=\"5\">\n"
    for mirror in mirrors:
        page+="<tr><td><b>"+mirror["name"]+"</b></td><td><a href=\""+mirror["help"]+"\">Installation instructions</a> <a href=\""+config["www-url"]+"/log/"+mirror["name"]+".html\">Generation log</a></td></tr>\n"
    page+="</table><br><br>"
    file.write(page)
    file.close()
