eggs/mercurial-1.7.3-py2.6-linux-x86_64.egg/hgext/hgcia.py
changeset 69 c6bca38c1cbf
equal deleted inserted replaced
68:5ff1fc726848 69:c6bca38c1cbf
       
     1 # Copyright (C) 2007-8 Brendan Cully <brendan@kublai.com>
       
     2 #
       
     3 # This software may be used and distributed according to the terms of the
       
     4 # GNU General Public License version 2 or any later version.
       
     5 
       
     6 """hooks for integrating with the CIA.vc notification service
       
     7 
       
     8 This is meant to be run as a changegroup or incoming hook. To
       
     9 configure it, set the following options in your hgrc::
       
    10 
       
    11   [cia]
       
    12   # your registered CIA user name
       
    13   user = foo
       
    14   # the name of the project in CIA
       
    15   project = foo
       
    16   # the module (subproject) (optional)
       
    17   #module = foo
       
    18   # Append a diffstat to the log message (optional)
       
    19   #diffstat = False
       
    20   # Template to use for log messages (optional)
       
    21   #template = {desc}\\n{baseurl}/rev/{node}-- {diffstat}
       
    22   # Style to use (optional)
       
    23   #style = foo
       
    24   # The URL of the CIA notification service (optional)
       
    25   # You can use mailto: URLs to send by email, eg
       
    26   # mailto:cia@cia.vc
       
    27   # Make sure to set email.from if you do this.
       
    28   #url = http://cia.vc/
       
    29   # print message instead of sending it (optional)
       
    30   #test = False
       
    31 
       
    32   [hooks]
       
    33   # one of these:
       
    34   changegroup.cia = python:hgcia.hook
       
    35   #incoming.cia = python:hgcia.hook
       
    36 
       
    37   [web]
       
    38   # If you want hyperlinks (optional)
       
    39   baseurl = http://server/path/to/repo
       
    40 """
       
    41 
       
    42 from mercurial.i18n import _
       
    43 from mercurial.node import bin, short
       
    44 from mercurial import cmdutil, patch, templater, util, mail
       
    45 import email.Parser
       
    46 
       
    47 import xmlrpclib
       
    48 from xml.sax import saxutils
       
    49 
       
    50 socket_timeout = 30 # seconds
       
    51 try:
       
    52     # set a timeout for the socket so you don't have to wait so looooong
       
    53     # when cia.vc is having problems. requires python >= 2.3:
       
    54     import socket
       
    55     socket.setdefaulttimeout(socket_timeout)
       
    56 except:
       
    57     pass
       
    58 
       
    59 HGCIA_VERSION = '0.1'
       
    60 HGCIA_URL = 'http://hg.kublai.com/mercurial/hgcia'
       
    61 
       
    62 
       
    63 class ciamsg(object):
       
    64     """ A CIA message """
       
    65     def __init__(self, cia, ctx):
       
    66         self.cia = cia
       
    67         self.ctx = ctx
       
    68         self.url = self.cia.url
       
    69 
       
    70     def fileelem(self, path, uri, action):
       
    71         if uri:
       
    72             uri = ' uri=%s' % saxutils.quoteattr(uri)
       
    73         return '<file%s action=%s>%s</file>' % (
       
    74             uri, saxutils.quoteattr(action), saxutils.escape(path))
       
    75 
       
    76     def fileelems(self):
       
    77         n = self.ctx.node()
       
    78         f = self.cia.repo.status(self.ctx.parents()[0].node(), n)
       
    79         url = self.url or ''
       
    80         elems = []
       
    81         for path in f[0]:
       
    82             uri = '%s/diff/%s/%s' % (url, short(n), path)
       
    83             elems.append(self.fileelem(path, url and uri, 'modify'))
       
    84         for path in f[1]:
       
    85             # TODO: copy/rename ?
       
    86             uri = '%s/file/%s/%s' % (url, short(n), path)
       
    87             elems.append(self.fileelem(path, url and uri, 'add'))
       
    88         for path in f[2]:
       
    89             elems.append(self.fileelem(path, '', 'remove'))
       
    90 
       
    91         return '\n'.join(elems)
       
    92 
       
    93     def sourceelem(self, project, module=None, branch=None):
       
    94         msg = ['<source>', '<project>%s</project>' % saxutils.escape(project)]
       
    95         if module:
       
    96             msg.append('<module>%s</module>' % saxutils.escape(module))
       
    97         if branch:
       
    98             msg.append('<branch>%s</branch>' % saxutils.escape(branch))
       
    99         msg.append('</source>')
       
   100 
       
   101         return '\n'.join(msg)
       
   102 
       
   103     def diffstat(self):
       
   104         class patchbuf(object):
       
   105             def __init__(self):
       
   106                 self.lines = []
       
   107                 # diffstat is stupid
       
   108                 self.name = 'cia'
       
   109             def write(self, data):
       
   110                 self.lines.append(data)
       
   111             def close(self):
       
   112                 pass
       
   113 
       
   114         n = self.ctx.node()
       
   115         pbuf = patchbuf()
       
   116         cmdutil.export(self.cia.repo, [n], fp=pbuf)
       
   117         return patch.diffstat(pbuf.lines) or ''
       
   118 
       
   119     def logmsg(self):
       
   120         diffstat = self.cia.diffstat and self.diffstat() or ''
       
   121         self.cia.ui.pushbuffer()
       
   122         self.cia.templater.show(self.ctx, changes=self.ctx.changeset(),
       
   123                                 url=self.cia.url, diffstat=diffstat)
       
   124         return self.cia.ui.popbuffer()
       
   125 
       
   126     def xml(self):
       
   127         n = short(self.ctx.node())
       
   128         src = self.sourceelem(self.cia.project, module=self.cia.module,
       
   129                               branch=self.ctx.branch())
       
   130         # unix timestamp
       
   131         dt = self.ctx.date()
       
   132         timestamp = dt[0]
       
   133 
       
   134         author = saxutils.escape(self.ctx.user())
       
   135         rev = '%d:%s' % (self.ctx.rev(), n)
       
   136         log = saxutils.escape(self.logmsg())
       
   137 
       
   138         url = self.url and '<url>%s/rev/%s</url>' % (saxutils.escape(self.url),
       
   139                                                      n) or ''
       
   140 
       
   141         msg = """
       
   142 <message>
       
   143   <generator>
       
   144     <name>Mercurial (hgcia)</name>
       
   145     <version>%s</version>
       
   146     <url>%s</url>
       
   147     <user>%s</user>
       
   148   </generator>
       
   149   %s
       
   150   <body>
       
   151     <commit>
       
   152       <author>%s</author>
       
   153       <version>%s</version>
       
   154       <log>%s</log>
       
   155       %s
       
   156       <files>%s</files>
       
   157     </commit>
       
   158   </body>
       
   159   <timestamp>%d</timestamp>
       
   160 </message>
       
   161 """ % \
       
   162             (HGCIA_VERSION, saxutils.escape(HGCIA_URL),
       
   163             saxutils.escape(self.cia.user), src, author, rev, log, url,
       
   164             self.fileelems(), timestamp)
       
   165 
       
   166         return msg
       
   167 
       
   168 
       
   169 class hgcia(object):
       
   170     """ CIA notification class """
       
   171 
       
   172     deftemplate = '{desc}'
       
   173     dstemplate = '{desc}\n-- \n{diffstat}'
       
   174 
       
   175     def __init__(self, ui, repo):
       
   176         self.ui = ui
       
   177         self.repo = repo
       
   178 
       
   179         self.ciaurl = self.ui.config('cia', 'url', 'http://cia.vc')
       
   180         self.user = self.ui.config('cia', 'user')
       
   181         self.project = self.ui.config('cia', 'project')
       
   182         self.module = self.ui.config('cia', 'module')
       
   183         self.diffstat = self.ui.configbool('cia', 'diffstat')
       
   184         self.emailfrom = self.ui.config('email', 'from')
       
   185         self.dryrun = self.ui.configbool('cia', 'test')
       
   186         self.url = self.ui.config('web', 'baseurl')
       
   187 
       
   188         style = self.ui.config('cia', 'style')
       
   189         template = self.ui.config('cia', 'template')
       
   190         if not template:
       
   191             template = self.diffstat and self.dstemplate or self.deftemplate
       
   192         template = templater.parsestring(template, quoted=False)
       
   193         t = cmdutil.changeset_templater(self.ui, self.repo, False, None,
       
   194                                         style, False)
       
   195         t.use_template(template)
       
   196         self.templater = t
       
   197 
       
   198     def sendrpc(self, msg):
       
   199         srv = xmlrpclib.Server(self.ciaurl)
       
   200         res = srv.hub.deliver(msg)
       
   201         if res is not True:
       
   202             raise util.Abort(_('%s returned an error: %s') %
       
   203                              (self.ciaurl, res))
       
   204 
       
   205     def sendemail(self, address, data):
       
   206         p = email.Parser.Parser()
       
   207         msg = p.parsestr(data)
       
   208         msg['Date'] = util.datestr(format="%a, %d %b %Y %H:%M:%S %1%2")
       
   209         msg['To'] = address
       
   210         msg['From'] = self.emailfrom
       
   211         msg['Subject'] = 'DeliverXML'
       
   212         msg['Content-type'] = 'text/xml'
       
   213         msgtext = msg.as_string()
       
   214 
       
   215         self.ui.status(_('hgcia: sending update to %s\n') % address)
       
   216         mail.sendmail(self.ui, util.email(self.emailfrom),
       
   217                       [address], msgtext)
       
   218 
       
   219 
       
   220 def hook(ui, repo, hooktype, node=None, url=None, **kwargs):
       
   221     """ send CIA notification """
       
   222     def sendmsg(cia, ctx):
       
   223         msg = ciamsg(cia, ctx).xml()
       
   224         if cia.dryrun:
       
   225             ui.write(msg)
       
   226         elif cia.ciaurl.startswith('mailto:'):
       
   227             if not cia.emailfrom:
       
   228                 raise util.Abort(_('email.from must be defined when '
       
   229                                    'sending by email'))
       
   230             cia.sendemail(cia.ciaurl[7:], msg)
       
   231         else:
       
   232             cia.sendrpc(msg)
       
   233 
       
   234     n = bin(node)
       
   235     cia = hgcia(ui, repo)
       
   236     if not cia.user:
       
   237         ui.debug('cia: no user specified')
       
   238         return
       
   239     if not cia.project:
       
   240         ui.debug('cia: no project specified')
       
   241         return
       
   242     if hooktype == 'changegroup':
       
   243         start = repo.changelog.rev(n)
       
   244         end = len(repo.changelog)
       
   245         for rev in xrange(start, end):
       
   246             n = repo.changelog.node(rev)
       
   247             ctx = repo.changectx(n)
       
   248             sendmsg(cia, ctx)
       
   249     else:
       
   250         ctx = repo.changectx(n)
       
   251         sendmsg(cia, ctx)