##// END OF EJS Templates
bookmarks: use recordchange instead of writing if transaction is active...
bookmarks: use recordchange instead of writing if transaction is active Before this patch, 'bmstore.write()' always write in-memory bookmark changes into '.hg/bookmarks' regardless of transaction activity. If 'bmstore.write()' is invoked inside a transaction and it writes changes into '.hg/bookmarks', then: - original bookmarks aren't restored at failure of that transaction This breaks "all or nothing" policy of the transaction. BTW, "hg rollback" can restore bookmarks successfully even before this patch, because original bookmarks are saved into '.hg/journal.bookmarks' at the beginning of the transaction, and it (actually renamed as '.hg/undo.bookmarks') is used by "hg rollback". - uncommitted bookmark changes are visible to other processes This is a kind of "dirty read" For example, 'rebase.rebase()' implies 'bmstore.write()', and it may be executed inside the transaction of "hg unshelve". Then, intentional aborting at the end of "hg unshelve" transaction doesn't restore original bookmarks (this is obviously a bug). This patch uses 'bmstore.recordchange()' instead of actual writing by 'bmstore._writerepo()', if any transaction is active This patch also removes meaningless restoring bmstore explicitly at the end of "hg shelve". This patch doesn't choose fixing each 'bmstore.write()' callers as like below, because writing similar code here and there is very redundant. before: bmstore.write() after: tr = repo.currenttransaction() if tr: bmstore.recordchange(tr) else: bmstore.write() Even though 'bmstore.write()' itself may have to be discarded by putting bookmark operations into transaction scope, this patch chose fixing it to implement "transactional dirstate" at first.

File last commit:

r25186:80c5b266 default
r26520:46dec89f default
Show More
hgcia.py
285 lines | 9.0 KiB | text/x-python | PythonLexer
Brendan Cully
Add hgcia to hgext
r7438 # Copyright (C) 2007-8 Brendan Cully <brendan@kublai.com>
Matt Mackall
Update license to GPLv2+
r10263 #
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
Brendan Cully
Add hgcia to hgext
r7438
Dirkjan Ochtman
extensions: change descriptions for hook-providing extensions...
r8935 """hooks for integrating with the CIA.vc notification service
Brendan Cully
Add hgcia to hgext
r7438
Martin Geisler
hgcia: wrap docstrings at 70 characters
r9260 This is meant to be run as a changegroup or incoming hook. To
configure it, set the following options in your hgrc::
Brendan Cully
Add hgcia to hgext
r7438
Martin Geisler
hgcia: use reST syntax for literal block
r9208 [cia]
# your registered CIA user name
user = foo
# the name of the project in CIA
project = foo
# the module (subproject) (optional)
#module = foo
# Append a diffstat to the log message (optional)
#diffstat = False
# Template to use for log messages (optional)
Cédric Krier
hgcia: Handle URL like in notify (issue2406)...
r14314 #template = {desc}\\n{baseurl}{webroot}/rev/{node}-- {diffstat}
Martin Geisler
hgcia: use reST syntax for literal block
r9208 # Style to use (optional)
#style = foo
# The URL of the CIA notification service (optional)
Mads Kiilerich
fix trivial spelling errors
r17424 # You can use mailto: URLs to send by email, e.g.
Martin Geisler
hgcia: use reST syntax for literal block
r9208 # mailto:cia@cia.vc
# Make sure to set email.from if you do this.
#url = http://cia.vc/
# print message instead of sending it (optional)
#test = False
Cédric Krier
hgcia: Handle URL like in notify (issue2406)...
r14314 # number of slashes to strip for url paths
#strip = 0
Brendan Cully
Add hgcia to hgext
r7438
Martin Geisler
hgcia: use reST syntax for literal block
r9208 [hooks]
# one of these:
changegroup.cia = python:hgcia.hook
#incoming.cia = python:hgcia.hook
Brendan Cully
Add hgcia to hgext
r7438
Martin Geisler
hgcia: use reST syntax for literal block
r9208 [web]
# If you want hyperlinks (optional)
baseurl = http://server/path/to/repo
Brendan Cully
Add hgcia to hgext
r7438 """
from mercurial.i18n import _
Brodie Rao
hgcia/color: remove star imports...
r11750 from mercurial.node import bin, short
Yuya Nishihara
templater: remove noop calls of parsestring(s, quoted=False) (API)...
r24987 from mercurial import cmdutil, patch, util, mail
Brendan Cully
Add hgcia to hgext
r7438 import email.Parser
Brodie Rao
cleanup: replace naked excepts with more specific ones
r16688 import socket, xmlrpclib
Brendan Cully
Add hgcia to hgext
r7438 from xml.sax import saxutils
Augie Fackler
extensions: document that `testedwith = 'internal'` is special...
r25186 # Note for extension authors: ONLY specify testedwith = 'internal' for
# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
# be specifying the version(s) of Mercurial they are tested with, or
# leave the attribute unspecified.
Augie Fackler
hgext: mark all first-party extensions as such
r16743 testedwith = 'internal'
Brendan Cully
Add hgcia to hgext
r7438
socket_timeout = 30 # seconds
Brodie Rao
cleanup: replace naked excepts with more specific ones
r16688 if util.safehasattr(socket, 'setdefaulttimeout'):
Brendan Cully
Add hgcia to hgext
r7438 # set a timeout for the socket so you don't have to wait so looooong
# when cia.vc is having problems. requires python >= 2.3:
socket.setdefaulttimeout(socket_timeout)
HGCIA_VERSION = '0.1'
HGCIA_URL = 'http://hg.kublai.com/mercurial/hgcia'
class ciamsg(object):
""" A CIA message """
def __init__(self, cia, ctx):
self.cia = cia
self.ctx = ctx
self.url = self.cia.url
Cédric Krier
hgcia: Handle URL like in notify (issue2406)...
r14314 if self.url:
self.url += self.cia.root
Brendan Cully
Add hgcia to hgext
r7438
def fileelem(self, path, uri, action):
if uri:
uri = ' uri=%s' % saxutils.quoteattr(uri)
return '<file%s action=%s>%s</file>' % (
uri, saxutils.quoteattr(action), saxutils.escape(path))
def fileelems(self):
n = self.ctx.node()
Matt Mackall
misc: replace .parents()[0] with p1()
r13878 f = self.cia.repo.status(self.ctx.p1().node(), n)
Brendan Cully
Add hgcia to hgext
r7438 url = self.url or ''
Cédric Krier
hgcia: Set default value of strip to -1 (issue2891)...
r14850 if url and url[-1] == '/':
url = url[:-1]
Brendan Cully
Add hgcia to hgext
r7438 elems = []
Martin von Zweigbergk
hgcia: access status fields by name rather than index
r22917 for path in f.modified:
Brendan Cully
Add hgcia to hgext
r7438 uri = '%s/diff/%s/%s' % (url, short(n), path)
elems.append(self.fileelem(path, url and uri, 'modify'))
Martin von Zweigbergk
hgcia: access status fields by name rather than index
r22917 for path in f.added:
Brendan Cully
Add hgcia to hgext
r7438 # TODO: copy/rename ?
uri = '%s/file/%s/%s' % (url, short(n), path)
elems.append(self.fileelem(path, url and uri, 'add'))
Martin von Zweigbergk
hgcia: access status fields by name rather than index
r22917 for path in f.removed:
Brendan Cully
Add hgcia to hgext
r7438 elems.append(self.fileelem(path, '', 'remove'))
return '\n'.join(elems)
def sourceelem(self, project, module=None, branch=None):
msg = ['<source>', '<project>%s</project>' % saxutils.escape(project)]
if module:
msg.append('<module>%s</module>' % saxutils.escape(module))
if branch:
msg.append('<branch>%s</branch>' % saxutils.escape(branch))
msg.append('</source>')
return '\n'.join(msg)
def diffstat(self):
Benoit Boissinot
use new style classes
r8778 class patchbuf(object):
Brendan Cully
Add hgcia to hgext
r7438 def __init__(self):
self.lines = []
# diffstat is stupid
self.name = 'cia'
def write(self, data):
Matt Mackall
hgcia: fix diffstat support
r15776 self.lines += data.splitlines(True)
Brendan Cully
Add hgcia to hgext
r7438 def close(self):
pass
n = self.ctx.node()
pbuf = patchbuf()
Benoit Boissinot
patch/diff: move patch.export() to cmdutil.export()...
r10611 cmdutil.export(self.cia.repo, [n], fp=pbuf)
Brendan Cully
Add hgcia to hgext
r7438 return patch.diffstat(pbuf.lines) or ''
def logmsg(self):
Jordi Gutiérrez Hermoso
style: kill ersatz if-else ternary operators...
r24306 if self.cia.diffstat:
diffstat = self.diffstat()
else:
diffstat = ''
Brendan Cully
Add hgcia to hgext
r7438 self.cia.ui.pushbuffer()
self.cia.templater.show(self.ctx, changes=self.ctx.changeset(),
Cédric Krier
hgcia: Handle URL like in notify (issue2406)...
r14314 baseurl=self.cia.ui.config('web', 'baseurl'),
url=self.url, diffstat=diffstat,
webroot=self.cia.root)
Brendan Cully
Add hgcia to hgext
r7438 return self.cia.ui.popbuffer()
def xml(self):
n = short(self.ctx.node())
src = self.sourceelem(self.cia.project, module=self.cia.module,
branch=self.ctx.branch())
# unix timestamp
dt = self.ctx.date()
timestamp = dt[0]
author = saxutils.escape(self.ctx.user())
rev = '%d:%s' % (self.ctx.rev(), n)
log = saxutils.escape(self.logmsg())
Cédric Krier
hgcia: Set default value of strip to -1 (issue2891)...
r14850 url = self.url
if url and url[-1] == '/':
url = url[:-1]
url = url and '<url>%s/rev/%s</url>' % (saxutils.escape(url), n) or ''
Brendan Cully
Add hgcia to hgext
r7438
msg = """
<message>
<generator>
<name>Mercurial (hgcia)</name>
<version>%s</version>
<url>%s</url>
<user>%s</user>
</generator>
%s
<body>
<commit>
<author>%s</author>
<version>%s</version>
<log>%s</log>
%s
<files>%s</files>
</commit>
</body>
<timestamp>%d</timestamp>
</message>
""" % \
(HGCIA_VERSION, saxutils.escape(HGCIA_URL),
saxutils.escape(self.cia.user), src, author, rev, log, url,
self.fileelems(), timestamp)
return msg
class hgcia(object):
""" CIA notification class """
deftemplate = '{desc}'
dstemplate = '{desc}\n-- \n{diffstat}'
def __init__(self, ui, repo):
self.ui = ui
self.repo = repo
self.ciaurl = self.ui.config('cia', 'url', 'http://cia.vc')
self.user = self.ui.config('cia', 'user')
self.project = self.ui.config('cia', 'project')
self.module = self.ui.config('cia', 'module')
self.diffstat = self.ui.configbool('cia', 'diffstat')
self.emailfrom = self.ui.config('email', 'from')
self.dryrun = self.ui.configbool('cia', 'test')
self.url = self.ui.config('web', 'baseurl')
Cédric Krier
hgcia: Set default value of strip to -1 (issue2891)...
r14850 # Default to -1 for backward compatibility
self.stripcount = int(self.ui.config('cia', 'strip', -1))
Cédric Krier
hgcia: Handle URL like in notify (issue2406)...
r14314 self.root = self.strip(self.repo.root)
Brendan Cully
Add hgcia to hgext
r7438
style = self.ui.config('cia', 'style')
template = self.ui.config('cia', 'template')
if not template:
Jordi Gutiérrez Hermoso
style: kill ersatz if-else ternary operators...
r24306 if self.diffstat:
template = self.dstemplate
else:
template = self.deftemplate
Jim Correia
add --git option to commands supporting --patch (log, incoming, history, tip)...
r7762 t = cmdutil.changeset_templater(self.ui, self.repo, False, None,
Matt Mackall
changeset_templater: remove use_template method
r20667 template, style, False)
Brendan Cully
Add hgcia to hgext
r7438 self.templater = t
Cédric Krier
hgcia: Handle URL like in notify (issue2406)...
r14314 def strip(self, path):
'''strip leading slashes from local path, turn into web-safe path.'''
path = util.pconvert(path)
count = self.stripcount
Cédric Krier
hgcia: Set default value of strip to -1 (issue2891)...
r14850 if count < 0:
return ''
Cédric Krier
hgcia: Handle URL like in notify (issue2406)...
r14314 while count > 0:
c = path.find('/')
if c == -1:
break
path = path[c + 1:]
count -= 1
return path
Brendan Cully
Add hgcia to hgext
r7438 def sendrpc(self, msg):
srv = xmlrpclib.Server(self.ciaurl)
Brendan Cully
hgcia: report RPC errors
r10529 res = srv.hub.deliver(msg)
Georg Brandl
hgcia: accept "queued." xmlrpc return as success
r13551 if res is not True and res != 'queued.':
Brendan Cully
hgcia: report RPC errors
r10529 raise util.Abort(_('%s returned an error: %s') %
(self.ciaurl, res))
Brendan Cully
Add hgcia to hgext
r7438
def sendemail(self, address, data):
p = email.Parser.Parser()
msg = p.parsestr(data)
msg['Date'] = util.datestr(format="%a, %d %b %Y %H:%M:%S %1%2")
msg['To'] = address
msg['From'] = self.emailfrom
msg['Subject'] = 'DeliverXML'
msg['Content-type'] = 'text/xml'
Nicolas Dumazet
for calls expecting bool args, pass bool instead of int...
r9136 msgtext = msg.as_string()
Brendan Cully
Add hgcia to hgext
r7438
self.ui.status(_('hgcia: sending update to %s\n') % address)
mail.sendmail(self.ui, util.email(self.emailfrom),
[address], msgtext)
def hook(ui, repo, hooktype, node=None, url=None, **kwargs):
""" send CIA notification """
def sendmsg(cia, ctx):
msg = ciamsg(cia, ctx).xml()
if cia.dryrun:
ui.write(msg)
elif cia.ciaurl.startswith('mailto:'):
if not cia.emailfrom:
raise util.Abort(_('email.from must be defined when '
'sending by email'))
cia.sendemail(cia.ciaurl[7:], msg)
else:
cia.sendrpc(msg)
n = bin(node)
cia = hgcia(ui, repo)
if not cia.user:
Martin Geisler
do not attempt to translate ui.debug output
r9467 ui.debug('cia: no user specified')
Brendan Cully
Add hgcia to hgext
r7438 return
if not cia.project:
Martin Geisler
do not attempt to translate ui.debug output
r9467 ui.debug('cia: no project specified')
Brendan Cully
Add hgcia to hgext
r7438 return
if hooktype == 'changegroup':
start = repo.changelog.rev(n)
end = len(repo.changelog)
for rev in xrange(start, end):
n = repo.changelog.node(rev)
ctx = repo.changectx(n)
sendmsg(cia, ctx)
else:
ctx = repo.changectx(n)
sendmsg(cia, ctx)