#
# The MIT License
# Copyright (c) 2007 Kimmo Varis
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

# This script gets log from Subversion as XML, parses it
# and prints it.

# Subversion binary
svn_binary = 'C:\\Program Files\\Subversion\\bin\\svn.exe'
# Log command
svn_command = 'log'
# Paramaters to output all info into XML, limit count is appended later
svn_params = [' --verbose', ' --xml', ' --limit']

from xml.dom.minidom import parseString
import subprocess
import os
import sys

def run_svn(revisions):
    """This function runs svn log command and returns output of it.
    
       Returns SVN log as XML string.
    """
    svn_params.append(' %s' % revisions)
    command = [svn_binary, svn_command, svn_params]
    #os.chdir("G:\\WinMerge\\WinMerge_SVN")
    print "Reading log from Subversion. This may take a while...\n"
    output = subprocess.Popen(command, stdout = subprocess.PIPE).communicate()[0]
    return output

def parse_xml(xml_string):
    """This function parses XML string to list of log entries.
    
       Returns list log entries as strings.
    """
    dom1 = parseString(xml_string)
    top_element = dom1.documentElement
    log_list = []
    for e in top_element.childNodes:
        revision = get_revision(e)
        item = parse_element(e)
        if len(item) > 0:
            log_line = revision, item[0], item[1], item[2]
            log_list.append(log_line)
    dom1.unlink()
    return log_list
 
def get_revision(elem):
    """ This function gets revision number from given element.
    
        Returns revision number as string.
    """
    revision = None
    if elem.attributes != None:
        attrib = elem.attributes["revision"]
        if attrib != None:
            revision = attrib.value
    return revision

def parse_element(elem):
    """ This function parses log data from one element it gets.
    
        Returns tuple having date, author and message
    """
    msg_element = None
    author_element = None
    date_element = None
    item = ()
        
    for e in elem.childNodes:
        if e.nodeType == e.ELEMENT_NODE:
            if e.localName == "msg":
                msg_element = e
            if e.localName == "author":
                author_element = e
            if e.localName == "date":
                date_element = e
    if msg_element != None and author_element != None and date_element != None:
        msg = ''
        # There might be empty log messages
        if len(msg_element.childNodes) > 0:
            msg = msg_element.childNodes[0].nodeValue
        author = author_element.childNodes[0].nodeValue
        date = date_element.childNodes[0].nodeValue
        item = date, author, msg
        #print item
    return item

def generate_output(log_lines):
    output_header()
    output_log_lines(log_lines)

def output_header():
    print 'This is WinMerge changelog generated by a script.'
    print 'Log has been generated from WinMerge subversion repository.\n'

def output_log_lines(log_lines):
    for line in log_lines:
        rev = line[0]
        date = line[1]
        author = line[2] + ':'
        msg = line[3]
        
        # If the log is about release, make it a header (with underline)
        if msg.startswith('WinMerge') and (msg.find('Stable') > 0 or
                                           msg.find('Beta') > 0 or
                                           msg.find('Experimental')):
            words = msg.split()
            version = words[3]
            title = "\nWinMerge %s\n" % version
            for i in range(len(title)):
                title = title + "="
            print title
        else:
            msg = msg.replace('\n', '\n            ')
            print '  %-10s %s (r%s)' % (author, msg, rev)

def usage():
    print 'WinMerge changelog script.'
    print 'Usage: changelog [-h] [-r:n] [--help] [--revisions:n]'
    print '  where:'
    print '    -h, --help print this help'
    print '    -r:n, -revisions:n tell script to output last n revisions'
    print '     by default 100 last revisions are printed\n'

def main(argv):
    revcount = 100
    if len(argv) > 0:
        opts, args = getopt.getopt(argv, "hr:", ["help", "revisions:"])
        
        for opt, arg in opts:
            if opt in ("-h", "--help"):
                usage()
                sys.exit()
            if opt in ("-r", "--revisions"):
                revcount = arg

    output = run_svn(revcount)
    log_lines = parse_xml(output)
    generate_output(log_lines)

### MAIN ###
if __name__ == "__main__":
    main(sys.argv[1:])
