#!/usr/bin/env python
# Simple post-commit hook for bzr that submits the commit to 
# CIA (http://cia.navi.cx/)

# Requires a recent version of bzr (0.7 or higher)

# Copyright (C) 2005 Jelmer Vernooij <jelmer@samba.org>
# Published under the GNU GPL

# Installation:
# Copy this file to ~/.bazaar/plugins

# Configuration:
# In ~/.bazaar/bazaar.conf, set 'cia_user' to your username on CIA.

# Enable the post_commit hook by setting post_commit to something like 
# 'bzrlib.plugins.cia_bzr.post_commit' in ~/.bazaar/branches.conf

# Other options that can be set are 'cia_server' and 'cia_quiet'

# To enable CIA reporting for a particular branch, run:
# $ bzr cia-project <name> 
# inside that branch

import sys
import xmlrpclib
import bzrlib
from bzrlib.delta import compare_trees
from xml.sax import saxutils
from bzrlib.commands import Command, register_command
from bzrlib.branch import Branch
from warnings import warn

def post_commit(branch, revision_id, dry_run=False):
    branch_config = bzrlib.config.BranchConfig(branch)
    tree_config = branch.tree_config()
    global_config = bzrlib.config.GlobalConfig()
    revision = branch.repository.get_revision(revision_id)

    # Migrate from branchconfig to treeconfig
    project = branch_config.get_user_option('cia_project')
    if project:
        tree_config.set_option('cia_project', project)
    else:
        project = tree_config.get_option('cia_project', default=None)

    if not project:
        return

    server = tree_config.get_option('cia_server', default="http://cia.navi.cx")

    author = branch_config.get_user_option('cia_user')
    if not author:
        author = global_config.get_user_option('cia_user')
    if not author:
        author = global_config.username()
    quiet = global_config.get_user_option('cia_quiet')

    old_tree = branch.repository.revision_tree(revision.parent_ids[0])
    new_tree = branch.repository.revision_tree(revision.revision_id)
    delta = compare_trees(old_tree, new_tree, want_unchanged=False)
    files = []

    [files.append(f) for (f,_,_) in delta.added]
    [files.append(f) for (f,_,_) in delta.removed]
    [files.append(f) for (_,f,_,_,_,_) in delta.renamed]
    [files.append(f) for (f,_,_,_,_) in delta.modified]

    msg = """
<message>
  <generator> 
    <name>bzr</name> 
    <version>%s</version> 
    <url>http://samba.org/~jelmer/bzr/cia_bzr.py</url>
  </generator>
  <source>
    <project>%s</project>
    <module>%s</module>
  </source>
  <timestamp>%d</timestamp>
  <body>
    <commit>
      <revision>%s</revision>
      <files>%s</files>
      <author>%s</author>
      <log>%s</log>
    </commit>
  </body>
</message>
""" % (bzrlib.version_string, project, branch.nick, revision.timestamp, revision_id, 
        "\n".join(["<file>%s</file>" % saxutils.escape(f) for f in files]), 
        saxutils.escape(author), 
        saxutils.escape(revision.message))

    if not quiet:
        print "Submitting revision to CIA."
    if not dry_run:
        xmlrpclib.ServerProxy(server).hub.deliver(msg)
    else:
        print msg

class cmd_cia_project(Command):
    """Print or set project to submit changes to on CIA.

    """
    takes_args = ['project?']
    takes_options = []

    def run(self, project=None, branch='.'):
        br = Branch.open_containing(branch)[0]
        
        tree_config = br.tree_config()
        if project:
            tree_config.set_option(project, 'cia_project')
        else:
            print tree_config.get_option('cia_project')

class cmd_submit_cia(Command):
    """Submit a revision to CIA

    """
    takes_args = ['branch?']
    takes_options = ['revision','dry-run']

    def run(self, branch='.', revision=None,dry_run=False):
        br = Branch.open(branch)

        if revision is None:
            rev_id = br.last_revision()
        elif len(revision) != 1:
            raise BzrCommandError('bzr submit-cia --revision takes exactly 1 argument')
        else:
            rev_id = revision[0].in_history(br).rev_id

        post_commit(br, rev_id, dry_run)
        
        return 0

register_command(cmd_cia_project)
register_command(cmd_submit_cia)
